
The flock-of-birds logo
Intro, Physics, SVG, Text
NewFree
A logo preview in three acts: the logo is built like a wall, course by course, then a crane rolls in with a moustached operator in the cabin and a wrecking ball that swings like a true pendulum. First it only taps, then it strikes: one letter shatters, the next one topples like a domino, another one cracks. In the Playground you type your own name or upload your own logo.
A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The wrecking-ball logo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="scena">
<!-- the stage: the script measures it, builds the logo in it and drives the crane -->
<svg class="palco" data-stage role="img" aria-label="BRAWNLY" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- the operator is seen only through the cabin window -->
<clipPath id="op-window">
<rect x="-150" y="-290" width="88" height="110" rx="5" />
</clipPath>
<!-- the counterweight, to keep its warning stripes inside it -->
<clipPath id="weight-clip">
<path d="M120 -86L180 -86Q188 -86 188 -94L188 -164Q188 -172 180 -172L120 -172Z" />
</clipPath>
</defs>
<g data-world>
<g data-scene>
<g data-ground>
<line class="terra" data-floor />
<ellipse class="ombra-palla" data-ball-shadow />
</g>
<g data-haze-back></g>
<!-- the crane: drawn facing left, the point under its tracks is 0 0 -->
<g data-crane>
<ellipse class="gru-ombra" cx="12" cy="2" rx="196" ry="11" />
<!-- the boom, built by the script along its length: it turns on its foot, behind the cabin -->
<g data-boom></g>
<!-- the cable that holds the boom, from the top of the mast to the tip -->
<line class="gru-cavo" data-pendant />
<!-- the mast at the back -->
<path class="asta-bordo" d="M44 -196L76 -322M112 -196L76 -322" />
<path class="asta" d="M44 -196L76 -322M112 -196L76 -322" />
<circle class="perno" cx="76" cy="-322" r="8" />
<!-- the exhaust -->
<rect class="tubo" x="92" y="-238" width="12" height="44" rx="3" />
<rect class="tubo" x="88.5" y="-244" width="19" height="8" rx="2.5" />
<!-- the ring the upper works turn on -->
<rect class="scuro" x="-100" y="-84" width="200" height="20" rx="4" />
<!-- the upper works -->
<path class="gru" d="M-150 -78L128 -78L128 -188Q128 -198 118 -198L-150 -198Z" />
<path class="gru-scuro" d="M-150 -94L128 -94L128 -78L-150 -78Z" />
<path class="gru-linea" d="M-150 -78L128 -78L128 -188Q128 -198 118 -198L-150 -198" />
<path class="gru-lucido" d="M-40 -190L114 -190" />
<path class="gru-righe" d="M8 -172L64 -172M8 -160L64 -160M8 -148L64 -148M8 -136L64 -136" />
<path class="gru-righe" d="M-30 -186L-30 -100M80 -186L80 -100" />
<circle class="rivetto" cx="-20" cy="-176" r="3" />
<circle class="rivetto" cx="-20" cy="-112" r="3" />
<circle class="rivetto" cx="92" cy="-176" r="3" />
<circle class="rivetto" cx="92" cy="-112" r="3" />
<!-- the counterweight, with warning stripes -->
<path class="contrappeso" d="M120 -86L180 -86Q188 -86 188 -94L188 -164Q188 -172 180 -172L120 -172Z" />
<g clip-path="url(#weight-clip)">
<path class="strisce" d="M104 -86L122 -86L150 -172L132 -172ZM140 -86L158 -86L186 -172L168 -172ZM176 -86L194 -86L222 -172L204 -172Z" />
</g>
<path class="contrappeso-bordo" d="M120 -86L180 -86Q188 -86 188 -94L188 -164Q188 -172 180 -172L120 -172Z" />
<!-- the tracks: the treads run, the wheels turn -->
<rect class="cingolo" x="-164" y="-66" width="328" height="66" rx="33" />
<rect class="battistrada" x="-157" y="-59" width="314" height="52" rx="26" data-tread />
<rect class="cingolo-piastra" x="-134" y="-51" width="268" height="36" rx="18" />
<g data-wheel data-cx="-131" data-cy="-33" data-r="22">
<circle class="ruota" r="22" />
<path class="raggi" d="M0 -15L0 15M-13 -7.5L13 7.5M-13 7.5L13 -7.5" />
<circle class="mozzo" r="6" />
</g>
<g data-wheel data-cx="-66" data-cy="-31" data-r="14">
<circle class="ruota" r="14" />
<path class="raggi" d="M0 -9L0 9M-8 -4.5L8 4.5M-8 4.5L8 -4.5" />
<circle class="mozzo" r="4" />
</g>
<g data-wheel data-cx="0" data-cy="-31" data-r="14">
<circle class="ruota" r="14" />
<path class="raggi" d="M0 -9L0 9M-8 -4.5L8 4.5M-8 4.5L8 -4.5" />
<circle class="mozzo" r="4" />
</g>
<g data-wheel data-cx="66" data-cy="-31" data-r="14">
<circle class="ruota" r="14" />
<path class="raggi" d="M0 -9L0 9M-8 -4.5L8 4.5M-8 4.5L8 -4.5" />
<circle class="mozzo" r="4" />
</g>
<g data-wheel data-cx="131" data-cy="-33" data-r="22">
<circle class="ruota" r="22" />
<path class="raggi" d="M0 -15L0 15M-13 -7.5L13 7.5M-13 7.5L13 -7.5" />
<circle class="mozzo" r="6" />
</g>
<!-- the cabin: the inside, the operator, the glass, then the frame with the window cut out -->
<rect class="cabina-dentro" x="-150" y="-290" width="88" height="110" />
<g clip-path="url(#op-window)">
<rect class="sedile" x="-141" y="-270" width="70" height="104" rx="15" />
<rect class="sedile-cuscino" x="-131" y="-262" width="50" height="14" rx="7" />
<!-- the far arm, behind the body -->
<path class="braccio-bordo" data-arm-far-line />
<path class="manica" data-arm-far />
<circle class="mano" r="6.2" data-hand-far />
<g data-op-body>
<path class="camicia" d="M-143 -168L-143 -190Q-143 -208 -122 -210L-90 -210Q-69 -208 -69 -190L-69 -168Z" />
<path class="gilet" d="M-141 -168L-141 -190Q-141 -206 -122 -208L-114 -208L-106 -195L-98 -208L-90 -208Q-71 -206 -71 -190L-71 -168Z" />
<path class="striscia" d="M-141 -191L-71 -191L-71 -185L-141 -185Z" />
<rect class="pelle" x="-112.5" y="-216" width="13" height="12" />
</g>
<!-- the head: it tilts on the neck -->
<g data-op-head>
<circle class="pelle" cx="-128" cy="-232" r="5.5" />
<circle class="pelle" cx="-84" cy="-232" r="5.5" />
<ellipse class="pelle" cx="-106" cy="-233" rx="21.5" ry="23" />
<ellipse class="guance" cx="-121" cy="-224" rx="4.6" ry="3" data-op-blush />
<ellipse class="guance" cx="-91" cy="-224" rx="4.6" ry="3" data-op-blush />
<circle class="occhio" cx="-114" cy="-238" r="6" />
<circle class="occhio" cx="-98" cy="-238" r="6" />
<g data-op-eyes>
<circle class="iride" cx="-115.4" cy="-237.6" r="3.7" />
<circle class="iride" cx="-99.4" cy="-237.6" r="3.7" />
<circle class="pupilla" cx="-115.8" cy="-237.6" r="2" />
<circle class="pupilla" cx="-99.8" cy="-237.6" r="2" />
<circle class="riflesso" cx="-116.8" cy="-239" r="1.1" />
<circle class="riflesso" cx="-100.8" cy="-239" r="1.1" />
</g>
<ellipse class="palpebra" cx="-114" cy="-238" rx="7" ry="7" data-op-lid />
<ellipse class="palpebra" cx="-98" cy="-238" rx="7" ry="7" data-op-lid />
<path class="ciglio" d="M-121 -246.5Q-114 -250 -107.5 -246.5" data-op-brow />
<path class="ciglio" d="M-104.5 -246.5Q-98 -250 -91 -246.5" data-op-brow />
<ellipse class="naso" cx="-106" cy="-229" rx="5.6" ry="4.6" />
<ellipse class="bocca" cx="-106" cy="-213.5" rx="5.5" ry="2.4" data-op-mouth />
<!-- the moustache, big and bushy -->
<path class="baffi" d="M-106 -227C-112 -229.5 -120 -229 -124 -224C-127 -220 -131 -220.5 -134 -223.5C-132 -215.5 -123 -214.5 -117 -217.5C-112 -219.5 -108.5 -220.5 -106 -220.5C-103.5 -220.5 -100 -219.5 -95 -217.5C-89 -214.5 -80 -215.5 -78 -223.5C-81 -220.5 -85 -220 -88 -224C-92 -229 -100 -229.5 -106 -227Z" data-op-stache />
<path class="baffi-righe" d="M-122 -222Q-118 -219.5 -113 -221M-90 -222Q-94 -219.5 -99 -221" />
<!-- the yellow helmet -->
<path class="casco" d="M-130.5 -250C-130.5 -268 -121 -278 -106 -278C-91 -278 -81.5 -268 -81.5 -250Z" />
<path class="casco-cresta" d="M-110 -277.2L-102 -277.2L-102 -250L-110 -250Z" />
<path class="casco-falda" d="M-135 -251.5L-77 -251.5Q-74.5 -248.5 -77.5 -246.5L-134.5 -246.5Q-137.5 -248.5 -135 -251.5Z" />
<path class="casco-lucido" d="M-125 -255Q-123.5 -266 -114 -271.5" />
</g>
<!-- the lever, and the near arm with its hand on it -->
<g data-lever>
<line class="leva" x1="-66" y1="-172" x2="-66" y2="-206" />
<circle class="pomello" cx="-66" cy="-210" r="5.6" />
<circle class="pomello-lucido" cx="-67.8" cy="-211.8" r="1.7" />
</g>
<path class="braccio-bordo" data-arm-near-line />
<path class="manica" data-arm-near />
<circle class="mano" r="6.2" data-hand-near />
</g>
<rect class="vetro" x="-150" y="-290" width="88" height="110" />
<g clip-path="url(#op-window)">
<path class="vetro-riflesso" d="M-128 -292L-112 -292L-150 -230L-150 -256ZM-104 -292L-98 -292L-150 -206L-150 -216Z" />
</g>
<path class="gru" fill-rule="evenodd" d="M-166 -300L-52 -300L-52 -78L-166 -78ZM-150 -290L-62 -290L-62 -180L-150 -180Z" />
<path class="gru-scuro" d="M-166 -100L-52 -100L-52 -78L-166 -78Z" />
<path class="gru-linea" fill-rule="evenodd" d="M-166 -300L-52 -300L-52 -78L-166 -78ZM-150 -290L-62 -290L-62 -180L-150 -180Z" />
<path class="gru-righe" d="M-158 -168L-60 -168M-120 -168L-120 -96" />
<rect class="maniglia" x="-114" y="-142" width="16" height="5" rx="2.5" />
<path class="gru-scuro" d="M-172 -308L-46 -308Q-42 -308 -42 -304L-42 -297L-176 -297L-176 -304Q-176 -308 -172 -308Z" />
<path class="gru-linea" d="M-172 -308L-46 -308Q-42 -308 -42 -304L-42 -297L-176 -297L-176 -304Q-176 -308 -172 -308Z" />
</g>
<g data-logo></g>
<!-- the chain and the ball: the script places them under the tip of the boom -->
<g data-rig>
<g data-chain></g>
<g data-ball>
<g data-ball-spin>
<path class="grillo-bordo" d="M-21 -96L-21 -122Q-21 -142 0 -142Q21 -142 21 -122L21 -96" />
<path class="grillo" d="M-21 -96L-21 -122Q-21 -142 0 -142Q21 -142 21 -122L21 -96" />
<rect class="grillo-piastra" x="-30" y="-110" width="60" height="18" rx="6" />
</g>
<circle class="palla-scura" r="100" />
<circle class="palla" cx="-12" cy="-12" r="85" />
<g data-ball-spin>
<path class="ammaccatura" d="M26 18Q36 25 46 18M-30 46Q-21 52 -12 46M44 -36Q50 -28 58 -32M-52 2Q-46 10 -38 6" />
</g>
<ellipse class="palla-riflesso" cx="-42" cy="-46" rx="25" ry="13" transform="rotate(-40 -42 -46)" />
<circle class="palla-riflesso" cx="-12" cy="-70" r="6.5" />
<circle class="palla-bordo" r="100" />
</g>
</g>
<g data-shards></g>
<g data-dust></g>
<g data-haze></g>
<g data-fx></g>
</g>
</g>
</svg>
<p class="nota">Click or tap to see it again</p>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.
38 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The wrecking-ball logo” from Animorio and fit it into my siteThe logo is set at size 100 inside an SVG group that is then scaled to the window: every measure (ball, crane, chain, dust) is in letter heights. The letters are measured in the page itself with getComputedTextLength, which surely knows the 125 width of the face; the true ink of each letter is read by drawing it on a canvas (fontStretch expanded) and reading its pixels: the outline is for the ball, a grid of points inside it is for the shards.
The ball is the point at the tip of the boom, a length of chain and an angle: its centre sits L·sin θ and L·cos θ away from the tip. Before starting, the script tries angle after angle to find the tip and the chain length for which the first thing the ball touches, coming down from the right, is exactly the chosen letter, on its top corner, without grazing the next one; then where it ends up (the letter before or the ground), and how much the chain must slip so that, bouncing back, it catches the corner of the following letter. The swing follows a cosine, like a pendulum: slow at the top, fast at the bottom.
The struck letter is cut into Voronoi cells around points taken inside its ink: each cell is a polygon, trimmed by a half-plane for every other point, used as the clipPath of a copy of the letter. The flight is worked out only once, frame by frame, with a kick, gravity, spin and bounces on the lowest corner of the turned polygon; the timeline then reads the position at its own time, so it can go forwards and backwards.
The shoved letter turns around its bottom left corner until a point of its outline, turned, falls inside the ink of the letter before (itself tilted a little): there it stops and leans. The crack is a zigzag in the colour of the paper, starting from the corner that was hit and traced with stroke-dashoffset; then the letter tips into the gap left by the other one and rocks on a corner, with two little creaking arcs.
The crane is drawn only once in the page, in pieces and with an outline; the lattice boom is built by the script as long as it needs to be. Place of the crane, angle of the boom, angle and length of the chain, the lever and the operator’s poses live in one object written as attributes at every update: the tracks and the wheels turn by themselves from where the crane is, the operator’s arms are two bones with the elbow bent outwards, from the shoulder to the hand, which sits on the knob of the lever or up high when he cheers.
Everything the blow does to the logo (shards, dust, domino, crack) lives in a separate, paused timeline: the story plays it forward by animating its time, and at the end plays it back with power3.inOut, like a rewound film; then the letters bounce with an elastic and the story starts again from the «arrive» label. If IMAGE holds an address, the logo becomes that picture: a single piece, of which the ball smashes the corner it hits, with an evenodd clipPath for what is left.
| Name | File | Default | What it changes |
|---|---|---|---|
NAME | script.js | 'BRAWNLY' | The logo as a word: every letter is a block of the wall that the ball can shatter, shove or crack. |
IMAGE | script.js | '' | The logo as a picture: the address of a file, or upload it from your computer. If there is one, it takes the place of the word and the ball smashes one of its corners. |
HIT | script.js | 4 | The letter the ball shatters, counting from 0 (spaces do not count). If a taller letter next to it shields it, the ball breaks the one it meets first. |
SHARDS | script.js | 9 | How many pieces the struck letter breaks into. |
DUST | script.js | 1 | How much dust: 0 none, 2 twice as much. |
BALL | script.js | 0.9 | How big the ball is, in letter heights. |
SPEED | script.js | 1 | The speed of the whole story: 2 is twice as fast, 0.5 half as fast. |
REST | script.js | 4 | How many seconds the logo stays wrecked before it goes back together. |
LOOP | script.js | true | Whether the logo goes back together and the story starts again. With false it stays wrecked, the letter rocking and the ball swaying. |
To present a logo in a way nobody forgets: a preview for a client, the opening of a builder’s, a studio’s or a video’s site, a 404 or an «under construction» page with a sense of humour, a social post. It works with a written wordmark and with a picture.
The same story, with the sizes adapted: on a narrow screen the crane is a little bigger and the cabin with the operator and the boom are in view, the back stays past the edge. A tap restarts it.
Nothing moves: the logo fades in, then the crane with the ball hanging, then the wrecked logo fades in (shards on the ground, toppled letter, crack). If the story starts again, the return is a fade too.
GSAP 3.15.0, Archivo (font variabile, larghezza e peso) 5.3.0.
Compressed with gzip, the three demo files weigh 25 KB; the libraries: GSAP 28 KB.
Tested on 10 October 2026
Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.