Twoville Inching Along
Thanks to a snow day yesterday, I can now export animated GIFs from Twoville, my 2D drawing language. Gif.js made this possible. However, Jeremy, I think naming your project with .js
suffix was a big mistake. When one clones the project, one ends up with a directory with a .js
extension, which messes everything up.
Here’s another demo to celebrate:
And here’s the Twoville code that produced this animation:
t.start = 0 t.stop = 40 a = rectangle() b = rectangle() c = rectangle() d = rectangle() a.rgb = [1, 0, 0.5] b.rgb = [1, 0, 0.5] c.rgb = [1, 0, 0.5] d.rgb = [1, 0, 0.5] # Rectangles in the fore position 0 -> t a.size = [200, 100] a.position = [0, 0] b.size = [100, 200] b.position = [200, 0] c.size = [200, 100] c.position = [100, 200] d.size = [100, 200] d.position = [0, 100] # Squares in the middles t -> 10 -> t a.size = [100, 100] a.position = [100, 0] b.size = [100, 100] b.position = [200, 100] c.size = [100, 100] c.position = [100, 200] d.size = [100, 100] d.position = [0, 100] # Rectangles in the aft position t -> 20 -> t a.size = [200, 100] a.position = [100, 0] b.size = [100, 200] b.position = [200, 100] c.size = [200, 100] c.position = [0, 200] d.size = [100, 200] d.position = [0, 0] # Squares in the corners t -> 30 -> t a.size = [100, 100] a.position = [200, 0] b.size = [100, 100] b.position = [200, 200] c.size = [100, 100] c.position = [0, 200] d.size = [100, 100] d.position = [0, 0] # Morphed into successor t -> 40 d.size = [200, 100] d.position = [0, 0] a.size = [100, 200] a.position = [200, 0] b.size = [200, 100] b.position = [100, 200] c.size = [100, 200] c.position = [0, 100]
I spent several hours trying to figure out why my animation was getting clipped to a small square in the top-left corner of the animations. The frames themselves were the right size, but the shapes only appeared when they landed in that small square. The animation showed fine when the SVG element was embedded in the DOM, but I was also rendering it to an image with this code:
var data = new XMLSerializer().serializeToString(svg);
var img = new Image();
var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = URL.createObjectURL(svgBlob);
img.onload = function () {
gif.addFrame(img, {
delay: 10,
copy: true
});
URL.revokeObjectURL(url);
};
img.src = url;
I eventually tried explicitly setting the SVG element’s viewport to match its size in the DOM. I had never explicitly set the viewport dimensions, so I guess the default didn’t do the right thing when rendered to an image? I dunno. Running this code before capturing any frames fixed it:
var box = svg.getBoundingClientRect();
// I don't know why I need to set the viewport explicitly. Setting the size
// of the image isn't sufficient.
svg.setAttribute('width', box.width);
svg.setAttribute('height', box.height);
There have also been a number of significant changes to the codebase that no one but me will ever care about. In particular, I’ve decided to abandon new
and constructor functions in Javascript. It’s much clearer to me what’s going on when I directly write the prototypes as objects.