motiscope

example · animated svg

Ambient geometric loop

Fifteen tiles that spin, scroll and ripple on one shared beat. Recreated from a 2.28 second screen recording: same shapes, same motion, new palette.

loopgrid eased ticksanimated SVG 14 KBno JS
Everything below is shown, not claimed. The unedited analysis is in report.md, the build script is generate.py, and the output rendering at the top of this page is the actual ambient-loop.svg — not a video of it.

The recreation, live

rendering in your browser right now · 14 KB of vector · zero JavaScript

A 5x3 grid of Bauhaus-style tiles: discs rotate, triangles scroll, rings ripple outward and squares rock, all snapping on a 0.75-second beat.
ambient-loop.svg · scale it, view-source it, drop it in a page · honours prefers-reduced-motion

Original vs recreation

one clip, phase-aligned, so the beats land together

Left: the original ambient loop recording. Right: the recreation, playing the same beats with a different palette.
Left: the original.  Right: recreated with motiscope.

Original animation from SVGator’s website-animation examples — all credit to the original creator. Captured as a screen recording; nothing was traced or copied.

What the numbers measured

a still frame shows every shape and no timing — this is the part you cannot eyeball

Grid5 × 3 tiles of 267 px, inset at (18, 9) — the artwork is not flush to the frame. Found from the strongest vertical/horizontal edges. The first guess (flush 277 px tiles) was wrong, and made neighbouring tiles bleed into each other.
Beat0.75 s. Burst peaks at 0.317 / 1.067 / 1.817 s, agreeing to ±0.02 s across three independent tiles.
CharacterShort eased ticks, then a hold — not constant velocity.
EasingPeak angular speed is ~3.6× the mean — too sharp for a stock ease-in-out. cubic-bezier(.83,0,.17,1).
CadenceMost tiles tick every beat; the half-plane, pie wedge and L-morph tick every second beat.
Stagger~41 ms top-to-bottom, applied as a per-row animation-delay.
Loop3.0 s = 4 beats — the ripple needs four beats to cycle its four colours.
The recording is not a full cycle. Frame 0 and the last frame differ by 25.5 against a 0.78 neighbour baseline, so the clip is a window onto a longer loop. The 3.0 s loop length is inferred from the beat and the four-colour ripple — it is the one timing number here that was reasoned, not measured.

The frames motiscope actually used

all 38 curated keyframes, in order, unedited

Contact sheet of the 38 curated keyframes motiscope extracted from the recording, in timeline order.
chosen by the motion signal, not sampled evenly · every timestamp and reason is listed in report.md

These are the only thing that costs image tokens (~300–400 each). The dense motion-energy curve that produced the timing above is pure arithmetic — effectively free. The numbers tell you when; these frames tell you what.

The numbers disagreed with the summary — and the numbers won

why motiscope hands perception to the model instead of guessing

motiscope’s whole-frame readout says dominant easing: linear. That is the average across fifteen tiles moving out of phase. Per tile, the angular velocity decelerates to near zero and ramps again: a hard ease-in-out. Taking the one-line summary at face value would have produced a lifeless, constant-speed grid. The report gives you the timing; you read the frames and the per-segment curve.

Verified, not asserted

the recreation was rendered back to video and re-measured with the same code

source     r1c2 burst peaks=[0.317, 1.067, 1.817]  intervals=[0.75, 0.75]
recreation r1c2 burst peaks=[0.433, 1.183, 1.933]  intervals=[0.75, 0.75]

Same beat. The 0.116 s offset is phase — the recording starts mid-loop — and the side-by-side above is shifted by exactly that much so the two play in step.

The fifteen tiles

every tile a different motif, all on one clock

col 0col 1col 2col 3col 4
row 0rocking square + ripple targethalf-disc rotating in a circleL collapses / square bloomspac-man, −90° per beattriangle conveyor, scrolls up
row 1rotating half-planerocking square + circledome conveyor, scrolls downpie wedge, +180° per 2 beatsquarter-disc scaling
row 2circle + rotating half + ringfour triangles pulsingexpanding ripple ringsfour corner discs → 4-point starrocking square

The ripple is four discs growing 0→1 across the loop, phase-offset by one beat each, over a background whose colour steps in lock-step with whichever disc has just wrapped — so the wrap is invisible and the colours appear to march outward forever.

Only the palette changed

the timing transfers; the artwork doesn’t have to

SourceHere
#FCFCFC white#FBF8F1 paper
#295EEF blue#17A2A2 teal
#2F386F navy#37244F plum
#E6C0E2 lilac#BFDCC6 sage
#FBEDAE cream#FBE3B8 sand
#FBD346 yellow#F5B335 amber
#F946A8 pink#F2584B coral

What we guessed

honest examples teach more than perfect ones

Two bugs this build surfaced

both from one root cause, and one of them only hurt the users who could least afford it

An element with a positive animation-delay renders un-transformed until its animation starts.

Reproduce it

the whole chain, from clip to SVG

motiscope analyze ambient_loop.mov --preset detailed   # -> report.md + curated frames
python3 generate.py > ambient-loop.svg                 # the build script, verbatim