Close
Simone Seagle

Simone Seagle

Independent Web and Educational Software Developer

Read More

Search

Mouse-over or touch/drag to interact with Le Marin Or, view fullscreen.

About the Art

Georges Valmier was a French painter who was born on April 11, 1885. Valmier painted in many of the most important styles in art history, from impressionism, to cubism, to abstractionism. This piece, Le Marin, was painted in 1929 during his abstractionism phase. "Le Marin" is French for the sailor - and the nautical themes are very obvious with the piece. Interestingly enough, I first found the piece on Wikimedia and they had the title listed incorrectly as "La Marina," which is also very descriptive I guess.

Georges Valmier was suggested to me by @talloggia on Twitter. I love the forms and shapes in his work, and I look forward to animating another of his in the future.

About the Programming

I had been mulling over how to pull this animation off for almost an entire year before I finally got the confidence to animate it as I had imagined. There are two main things going on in here - one, a simple animated tile animation of the waves in the center, and two - the far more complicated mask animation.

The repeating tile animation is extremely simple and is similar to what I did for the Chrysanthemums by a Stream piece. The tricky part was creating a seamless tile in Photoshop. All I do is change the tile offset x velocity in response to the location of the tracking point.

function updateTileSprite(layer){
    var multiplier = 1;
    if (trackLoc.x > 0) {
        // First get the distance from the layer to the tracking point
        var dist = distance(layer.center.x * scale, layer.center.y * scale, trackLoc.x, trackLoc.y);

        // If the distance is less than my predetermined value...
        if (dist < intDist) {
            // Scale the velocity based on the distance
            multiplier = 1 + 3 * (intDist - dist)/intDist;4

            // And then make sure it's moving the direction towards the tracking point
            multiplier *= Math.sign(scale * layer.center.x - trackLoc.x);
        }
    }
    layer.sprite.tilePosition.x += layer.tileVel * multiplier;
}

In order to create the different layers of waving blobs, I had to first do a lot of Photoshop work in separating the layers and the colors. This particular piece was one of the most difficult in that respect. You'll notice if you look in the top left and bottom right corners, features continue from the lower layer to the animated layer. I was pretty pleased at how that turned out.

The shapes are achieved by using generated Bezier curves to animate a mask on a rectangular sprite. I carefully went through and made a note of each crest and trough on the original piece of art and saved them in arrays. The points have an x and y coordinate, an angle with respect to the center of the blob, and an amplitude. I use that information, along with the location of the tracking point (if applicable) to create the control points for the Bezier curves. Here is an example of one of the layer objects with it's collection of curve points.

{
    // the black outline of one blob
    type: 'blob',
    x: 486,
    y: 1109,
    sprite: null,
    curvePoints: [
        {x: 1309, y: 1139, amplitude: 40, angle: 30},
        {x: 1385, y: 1353, amplitude: -60, angle: -30},
        {x: 1136, y: 1357, amplitude: 30, angle: -90},
        {x: 1002, y: 1400, amplitude: -30, angle: -90},
        {x: 869, y: 1363, amplitude: 20, angle: -90},
        {x: 657, y: 1339, amplitude: 20, angle: -90},
        {x: 520, y: 1350, amplitude: -60, angle: -120},
        {x: 524, y: 1220, amplitude: 20, angle: 180},
    ],
    graphicMask: null,
    filename: 'gv-plaster-black.jpg'
}

This is actually kind of tricky, and it might be a good idea for me to write a whole post about animating Bezier curves. I will include a snippet of that code below with some explanation, but it needs more than I think would be appropriate here.

for (var i = 1; i < layer.curvePoints.length; i++) {
    // For each point, draw a bezier curve
    var interactionMultiplier = 1;
    var frequency = 100 - index * 3;
    var angle = layer.curvePoints[i].baseAngle;

    if (trackLoc.x > 0) {
        // Add interactivity here....
    } 

    // We modulate the point with a cosine function and the amplitude that I defined for that point
    var frameMultiplier = 0.5* scale * layer.curvePoints[i].amplitude * (1 + Math.cos((index * 3 + frame)/frequency) );

    // Modulate the point itself
    var pt = {
        x: scale * layer.curvePoints[i].x + frameMultiplier * Math.cos(layer.curvePoints[i].angle),
        y: scale * layer.curvePoints[i].y - frameMultiplier * Math.sin(layer.curvePoints[i].angle)
    };

    // Calculate the control points.  So much trig.
    var amplitudeMult = -1.5 * scale * Math.abs(layer.curvePoints[i].amplitude) * interactionMultiplier;

    // In order for a Bezier curve to appear continuous, you need to have the point and both control points be co-linear.  
    // Sounds like a job for trig!

    // The first control point is attached to the previous point, and the second is attached to this point.
    var cp1 = {x: lastPt.x + amplitudeMult * Math.cos(layer.curvePoints[i-1].angle + Math.PI/2), 
        y: lastPt.y - amplitudeMult * Math.sin(layer.curvePoints[i-1].angle + Math.PI/2)};
    var cp2 = {x: pt.x - amplitudeMult * Math.cos(layer.curvePoints[i].angle + Math.PI/2), 
        y: pt.y + amplitudeMult * Math.sin(layer.curvePoints[i].angle + Math.PI/2)};

    // Finally draw the next part of the curve
    layer.graphicMask.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, pt.x, pt.y);

    lastPt = pt;

}

Working with Bezier curves is really fun, beautiful, and intellectually challenging. I'll talk more about the trig I used above in a separate post, I think.