2 years ago I developed something similar (in a team, closed code).
The first thing to note is that something like this is already solved by google docs. We read every blog post and article about how they did it and applied that to an multiuser SVG like simple editor. So here is what I remember:
The breakdown to simple commands is the right way to go.
As you wrote, with them you can recreate your images very detailed. You can even answer exactly what an image looked at every requested timestamp.
Example commands might be
- change color
- change color again
- draw a line from .. to ..
- draw a line from .. to ..
- draw a line from .. to ..
- draw a line from .. to ..
- smooth that line
- change color
- change Stroke
- delete those lines and draw them again ;-)
Back to the goolge docs example, they save and broadcast every single character change (and more).
Yes this is a very clear and testable approach, but asking for performance requires another logic Layer.
It is necessary to add a routine that simplifies these commands to an compressed version (see below)
The moment a user requests an image, your system looks for the latest compressed image and adds the single commands not included in your compress routine.
The compress routine:
Do a video recording of the creation of an dummy image (similar to what you expect from you users) in your favorite vector editor, you will note that about 60% to 80% percent of the commands are useless to the end result.
The targeted compress routine may have these three steps:
Most of the time you will see yourself in the recording repositioning points, handles or moving the objects, change the color again and again setting and undoing other parameters like stroke thickness. Even deleting an redoing of elements. The routine needs to optimize these commands to draw the end result directly. I'm sure, this will reduce your command list down to 10%-50% depending of the type of image you are looking for.
compressing commands. A Path in the example above is drawn in line segments, it needs to. You usually don't know on the first onMouseDown that it will end in a path with 100 segments and 200 Handles. But still like the other users to show the creation process. Add a command to your program that is able to draw complex things like a path. You won't need it in the user drawing process. This command can be used for faster recreation of complete shapes. A path with 100 points and 200 Handles can now be drawn in one command. Before that you had a list of at least 300 commands.
Reorder commands. Two path elements drawn by two users at the same time isn't easy to compress. A simple solution is to sort commands by element. The process might take 3 minutes to create each shape. An animation would require the real command order to see each shpae develop at the same time, but the end result doesn't care. Each shape can be much easier compressed if ordered by element.
sorry for the long post, hope it helps