Skip to content
animorio
IT
All components

The sync sprout

Loading, Physics, TransitionsCanvas, GSAPAdvancedCompressed weight: Demo 17 KBGSAP 28 KBFreeDownload the zip

The note sync of an app as a seedling growing in a small clay pot: the shoot comes out of the seed bent in a hook, the stem climbs towards the light and branches, every leaf unrolls from a fold and the whole plant sways on springs. The plant is the progress bar; at the end a flower opens on the bud. If the connection drops the plant wilts a little until Retry straightens it, and every sync grows a different plant from a new seed.

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, viewport-fit=cover">
  <title>The sync sprout</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the sync of a notes app, shown as a seedling in a small clay pot. Pressed, the seed in the soil shivers while
         the app looks for changes, then it splits and a shoot comes up in a hook, opens its two seed leaves and
         climbs: the stem branches, every leaf unrolls from a fold, the whole plant sways on springs. The plant is the
         progress. When every note is in, the bud on top opens into a flower; if the connection drops the plant wilts
         until Retry. Every sync grows a slightly different plant from a new seed. The plant and the pot are drawn by
         script.js on the canvas; the words and the button are HTML -->
    <section class="sprout" aria-labelledby="sprout-title" data-sprout>
      <div class="sprout__scene" role="progressbar" aria-labelledby="sprout-title" aria-valuemin="0" aria-valuemax="100"
           aria-valuenow="0" aria-valuetext="Not syncing" data-scene>
        <canvas class="sprout__paint" aria-hidden="true" data-paint></canvas>
      </div>
      <div class="sprout__foot">
        <div class="sprout__words">
          <h2 class="sprout__title" id="sprout-title"><span class="sprout__swap" data-title>Notes</span></h2>
          <p class="sprout__meta"><span class="sprout__swap" data-meta>Last synced 2 hours ago</span></p>
        </div>
        <button class="sprout__btn" type="button" data-action data-autoclic><span class="sprout__label" data-label>Sync now</span></button>
      </div>
      <p class="sr" role="status" aria-live="polite" data-live></p>
    </section>
  </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 sync sprout” from Animorio and fit it into my site

What it does

On a white background, alone in the middle, a clay pot lit from the left, with dark soil and a seed half buried in it; below, Notes and Last synced 2 hours ago, and on the right the very dark green Sync now button. Pressed, the seed shivers while the app looks for changes (Looking for changes…); then the notes start to arrive and the plant grows with them. The shoot comes up bent in a hook with the seed coat still on its tip, straightens with a little bounce, opens its two round seed leaves and the coat drops onto the soil with a bounce. The stem climbs joint after joint, leans towards the light and zigzags a little away from every leaf; side shoots branch off the joints; every leaf is born shut like a book and rolled at the tip, grows, opens and turns from the pale green of a new leaf to a full green, with its midrib and side veins. The stem thickens as the plant grows and every piece sways a little in the breeze; at every batch of notes that arrives the parts that are growing give a small start. Below, the line says the percentage and how many notes have arrived (37% · 312 of 846); the button becomes Pause, pale and outlined. Towards the end a bud forms on top; when every note is in the stem gives a nod, the bud opens into a yellow flower with the petals spreading one after another on an elastic, and the title becomes All notes synced with a tick that draws itself. Sync again closes the flower, the plant goes back into the soil, a new seed drops into the pot with a few bounces and the sync starts over: the plant that grows is a different one. One time in two, in the demo, the connection drops halfway: the plant stops growing and wilts a little, the stem bends, the leaves hang, fold up a little and turn dull, the title says Connection lost in red and the button becomes Retry. Retry brings the connection back: the plant straightens at once with a bounce and grows on from where it stopped. The pointer passing through the leaves stirs them, and a tap pushes them away from the finger.

How it works

A plant from a number

The seed is a number feeding a pseudo random generator (mulberry32): from it comes the skeleton of the plant, once per sync. The stem is a row of segments from joint to joint; the first three are the hypocotyl that comes up in a hook, then every joint has a leaf, alternately right and left, and with some probability a side shoot of two or three segments with its own leaves. The bend of every segment turns its angle a little towards the window (phototropism) and adds a small zigzag away from the leaf. Every piece knows when it starts to grow and how long it takes, in units of progress: everything is done before 95%, and the last stretch goes into the bud.

Growing with the parameter

Every frame the skeleton is laid out for the progress shown, joint by joint from the soil up: every segment is as long as its growth, its angle is added to the one of the segment below, the branches start from their joint. The thickness is worked out from the tip: thin at the top, 0.048 pixels wider for every pixel of stem above, with a cap that grows with the plant. Before it starts the plant is laid out fully grown and scaled uniformly so that the flower and the leaves fit the box, whatever seed comes up. The progress follows the data on a critically damped spring that never goes back.

Ribbon stems and book leaves

The joints of a branch go through a Catmull-Rom curve; along the curve a tapering ribbon (the edges either side of the normal, the tip rounded) makes the stem, with two narrower ribbons on top moved towards the light and the shade. A leaf is a midrib that curves (downwards with its weight, towards the stem while it is young) and two halves that close like the pages of a book: the width you see is the real one times the cosine of the fold. The half facing up catches the light, the other stays in shade, and on top come the side veins curving out towards the margin, a darker edge and a soft shadow.

Everything on springs

Every segment and every leaf has an extra angle on a damped spring (26% of critical damping, worked out in steps of 1/240 of a second): the breeze is a target that sways on two sines, the wilting is a target that bends the segments towards the side of the light and the leaves downwards, and the pointer gives every piece near it the turn of its push (the cross product of the piece and the pointer’s velocity). When the wilting target goes back to zero quickly, the springs overshoot and the plant straightens with a bounce.

The seed and the flower

The seed coat stays on the tips of the seed leaves until they open, then it falls with its own gravity and bounces on the soil. The flower is drawn in simple three dimensions: an axis tilted towards the viewer, every petal a direction that opens out from the axis by an angle going from shut to open on an elastic staggered petal by petal; the petals are projected onto the plane, sorted from the furthest and lit by their normal. Sync again winds the progress back to zero and drops a new seed in with a bounce.

For those who cannot see it and those who want no motion

The drawing is a role=progressbar with aria-valuenow and an aria-valuetext in notes, the section has aria-busy while it works and an aria-live line says when the sync starts, stops, loses the connection and ends. The button changes its word (Sync now, Pause, Resume, Retry, Sync again) and the pill takes the new width with a little bounce; a click from a script, the library preview’s, never pauses. When nothing moves the canvas is not redrawn.

Values to change

NameFileDefaultWhat it changes
NOTESscript.js846How many notes the app syncs.
SECONDSscript.js5.5How long a sync takes in the demo, in seconds (a real one follows its notes).
FAIL_EVERYscript.js2In the demo, one sync in how many loses the connection (0 never).
FAIL_ATscript.js0.56How far the sync that loses the connection gets, from 0 to 1.
SEEDscript.js11The first plant’s seed; every sync after it grows from a new one.
NODESscript.js8How many joints the main stem grows.
BRANCHINGscript.js0.5How likely a joint is to grow a side shoot, from 0 to 1.
LIGHTscript.js0.6How hard the plant leans towards the light, from 0 to 1.
PETALSscript.js5The petals of the flower.
SWAYscript.js1How much the breeze moves it: 0 still, 1 a little, 2 a lot.
DROOPscript.js1How far it wilts when the connection drops: 0 not at all, 1.5 a lot.
FOLLOWscript.js0.4How long the plant takes to catch up with the notes, in seconds.

Try them in the Playground

When to use it

For a wait of a few seconds that has an outcome, in an app with a gentle tone: syncing notes, a journal, a backup, importing a library. The plant says «it is growing, all is well» better than a bar, and the wilting reads without words; for a one second load or a technical app something drier is better.

On phones

The component takes the screen’s width less 32 pixels (358 on a 390 screen) and stays 290 tall; the plant is scaled to fit the box and the canvas paints at the screen’s real density, up to twice. With a finger, a tap pushes the nearby leaves away and a sideways drag stirs them; scrolling up and down stays with the page. The button squashes and springs back, and its words widen on the width axis only under the mouse.

With reduced motion

No breeze, springs, shivers, starts or bounces: the plant still grows, because it is what says how far along things are, but every piece is already in place; the coat is on the soil at once, the wilting and the straightening are immediate, the flower opens at once, and Sync again moves to the new plant with a fade. The new words fade in and the tick is not drawn.

Pitfalls

  • The first plant was a narrow stick in the middle of a wide box: the scale that fits it in the box depended on the height only, and a long stem with small leaves squeezed it. A shorter stem, bigger leaves and branches, and the scale worked out on height and width together.
  • The seed coat, falling, ended up on the rim of the pot and looked as if it lay on the clay: the seed is ten pixels wide and the soil seen from above is an ellipse a few pixels tall. It now bounces only on the back of the soil, and when it stops it turns flat with a little back.out instead of standing on its edge.
  • With the connection dropped the wilting hardly showed: the leaves’ springs were pulled down by 0.75 radians and the plant just looked still. The leaves now hang further, fold up a little, curve under their weight and turn dull, and the stem bends towards the light.
  • The flower, which is the reward at the end, was about twenty pixels wide and got lost on top of the plant: the petals are now nearly twice as long, with a bigger heart.
  • With the wilting doubled the plant curled into a hook and looked dead rather than tired: in the Playground the slider stops at 1.5.

Libraries

GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 17 KB; the libraries: GSAP 28 KB.

Testing

Tested on 8 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 components