Skip to content
animorio
IT
Back to the library

The wrecking-ball logo

Intro, Physics, SVG, TextGSAPAdvancedCompressed weight: Demo 25 KBGSAP 28 KBFreeDownload the zip

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.

The code

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>

Playground

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

Or ask Claude Code for it

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 site

What it does

On lime-washed paper the logo of a made-up brand, Brawnly, arrives in a jet-black, extra-wide typeface: it is built like a wall, one course of bricks at a time, every piece dropping, squashing and bouncing; at the end the logo settles with a jolt and a little dust. The logo moves aside and a yellow crawler crane drives in from the right: the tracks turn, the exhaust puffs, the wrecking ball dangles under the lattice boom and, when the crane brakes, swings back and forth. In the cabin sits an operator with a yellow helmet, a huge moustache and one hand on the lever. First he gently lets the ball down onto the logo: a knock, the letters tremble, and he shrugs. Then he pulls the lever: the boom dips, the ball swings far back, hangs at the top for a moment and comes down like a true pendulum, faster and faster, until it strikes a letter. The stage shakes, the letter breaks into pieces that fly off spinning, bounce on the ground and come to rest, while thick dust bursts out in clouds; the ball, slowed down, shoves the letter before, which tips over and leans on the next one like a domino. Bouncing back, the ball catches the corner of the following letter, which cracks and is left balancing on one corner. The operator hauls the ball up and cheers with both arms in the air. The logo stays like that for a few seconds: the dust settles slowly, the cracked letter rocks and creaks, the ball sways gently. Then everything goes back together like a film run backwards, the pieces snap into place with an elastic bounce, the crane drives off with a wave and the story starts again. A click restarts it from the beginning. A picture can take the place of the word: the ball smashes one of its corners.

How it works

A scene to size

The 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.

A true pendulum

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 shards

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 domino and the crack

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 and the operator

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.

The film run backwards

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.

Values to change

NameFileDefaultWhat it changes
NAMEscript.js'BRAWNLY'The logo as a word: every letter is a block of the wall that the ball can shatter, shove or crack.
IMAGEscript.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.
HITscript.js4The 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.
SHARDSscript.js9How many pieces the struck letter breaks into.
DUSTscript.js1How much dust: 0 none, 2 twice as much.
BALLscript.js0.9How big the ball is, in letter heights.
SPEEDscript.js1The speed of the whole story: 2 is twice as fast, 0.5 half as fast.
RESTscript.js4How many seconds the logo stays wrecked before it goes back together.
LOOPscript.jstrueWhether the logo goes back together and the story starts again. With false it stays wrecked, the letter rocking and the ball swaying.

Try them in the Playground

When to use it

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.

On phones

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.

With reduced motion

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.

Pitfalls

  • The ball came down on the right letter but grazed another one first, or ended up inside the crane’s boom as it swung back: the tip of the boom, the chain length and the highest swing are found by trying, with the true ink of the letters read on a canvas.
  • On a pendulum with a long chain, after the blow the ball went for the ground before the letter it should shove, and the domino never started: among the possible plans, the one where the slowed ball reaches the letter before is preferred.
  • After the crack the ball, swinging back down, passed through the letters again: the chain is hauled up quickly (power3.out) and the swaying only starts once the ball is high up.
  • A crack hidden with a stroke-dashoffset equal to its length still showed a dot: the round cap of a zero-length dash is drawn. It stays invisible until it cracks.
  • On a canvas the wide face is not asked for in the font shorthand (the width is dropped) but with fontStretch; and if the browser cannot do it, the letters are stretched to the width measured in the page.
  • Letters made of courses of bricks show thin lines between one course and the next (antialiasing): fine while the wall goes up, then the whole letter is shown.
  • getComputedTextLength on SVG text drops trailing spaces: measuring «BRAW » needs xml:space preserve.

Libraries

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.

Testing

Tested on 10 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

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.

All animations