The hands rotate to point at the yellow dot. As each one points more towards the dot, it opens from a fist into a pointing hand. The hand sizes and locations are random: if you re-load the page, you'll get a new assortment of hands. Note that the bigger hands rotate more slowly than the small hands.
To make the source photos, I just started up my webcam one day, and recorded my hand going from a fist to a pointing finger. Then I cut away the background in Photoshop and saved the images. You could easily replace these pictures with any other kind of animation that pleases you.
Arrow[] ArrowList; // list of Arrows color TargetColor = color(255, 255, 0); // target is yellow float TargetX, TargetY; // location of target void setup() { size(600, 500); // make graphics window smooth(); // draw things nicely TargetX = width * random(.2, .8); // start target randomly TargetY = height * random(.2, .8); ArrowList = new Arrow[15]; // create the array of Arrow objects for (int i=0; i<ArrowList.length; i++) { // roll up some random numbers to specify a new arrow float minR = width*.02; float maxR = width*.1; float radius = random(minR, maxR); float changeSpeed = map(radius, minR, maxR, .1, .01); float centerx = random(radius, width-radius); float centery = random(radius, height-radius); float startAngle = random(0, TWO_PI); // make the new arrow ArrowList[i] = new Arrow(centerx, centery, radius, changeSpeed, startAngle); } } void draw() { // Draw the arrows and target. If the target's moving, update the arrows. background(200); for (int i=0; i<ArrowList.length; i++) { ArrowList[i].render(); } drawTarget(); if (mousePressed) updateArrows(); } void drawTarget() { // draw the target circle stroke(0); fill(TargetColor); ellipse(TargetX, TargetY, 40, 40); } void mousePressed() { setTargetXY(); } void mouseDragged() { setTargetXY(); } void setTargetXY() { TargetX = mouseX; TargetY = mouseY; } void updateArrows() { for (int i=0; i<ArrowList.length; i++) { ArrowList[i].update(TargetX, TargetY); } } // A class to hold an arrow object. PImage[] ArrowHands; // images of my hand from fist to pointing boolean GotHands = false; // did we read the hand images yet? class Arrow { PVector center; // center of arrow float radius, angle, changeSpeed; // size, orientation, spin speed color clr; // color at this moment int imageIndex; // where we are in the animation // construct a new Arrow Arrow(float startX, float startY, float startRadius, float startChangeSpeed, float startAngle) { center = new PVector(startX, startY); radius = startRadius; angle = startAngle; changeSpeed = startChangeSpeed; clr = color(255); imageIndex = 0; if (!GotHands) { // read in the hand photos only once GotHands = true; ArrowHands = new PImage[18]; for (int i=0; i<ArrowHands.length; i++) { String name = "arrowHandPix/hand"+nf(i, 2)+".png"; ArrowHands[i] = loadImage(name); } } } void render() { fill(clr); noStroke(); pushMatrix(); translate(center.x, center.y); // move to place arrow on screen scale(radius/120.0); // Picked by eye to make nicely-sized hands rotate(angle); // spin in place to point at the target // photos are 397x191, so this next line centers them image(ArrowHands[imageIndex], -199, -95); popMatrix(); } void update(float goalX, float goalY) { float newAngle = atan2(goalY-center.y, goalX-center.x); // adjust the angles so the arrow turns either clockwise or // counter-clockwise, depending on which way gets to the goal faster while (angle < 0) angle += TWO_PI; while (newAngle < 0) newAngle += TWO_PI; float diffAngle = abs(angle - newAngle); if (diffAngle > PI) { if (newAngle > angle) newAngle -= TWO_PI; else angle -= TWO_PI; } float speed = changeSpeed; speed = constrain(speed, .05, .3); angle = lerp(angle, newAngle, speed); float angleMismatch = abs(angle-newAngle); // how far off are we? angleMismatch = constrain(angleMismatch, 0, 1); // use the angle mismatch to make an index into the image array imageIndex = int(ArrowHands.length * (1-angleMismatch)); imageIndex = constrain(imageIndex, 0, ArrowHands.length-1); } }