Pictogram Motion — our demo

One example among many. Don't reuse its story, arc, shots, props or timings.

Demo: Left Behind 《被落下的傘》 (50.0 s, 1920×1080, 24 fps) · pictogram-motion.mp4 · source in demo/

A yellow umbrella is left on a city bus on a rainy morning. All day in the sun nobody needs it; at the end of the line it joins 312 other lost umbrellas on the depot's shelf. At rush hour the storm comes back, the depot opens every shelf, and 313 umbrellas go back out into the rain. The hero is an object, not a person: the cast is an umbrella, a bus, doors, stop signs, a clock, clouds, sun, moon, lightning, a lost-property sign and footprints, all built from the same round-capped geometry as the grid pattern. English narration (Kokoro bf_emma) with Chinese and English subtitles. Line 4, the street names, the depot and the number 313 are fiction.

Story & structure

Hook: rain, and on the first beat a yellow umbrella snaps open (the only warm colour in a blue world) over a trail of wet footprints. Then the sun comes out, dry footprints step off the bus, the umbrella stays on its rail. Turn: half a beat of silence, thunder, and the umbrella that nobody needed in the sun becomes what the whole city needs. Landing: the shelf of 313 folded umbrellas opens at once and turns into the film's own pattern; the next morning at 07:42 it rains again and the footprints under the yellow umbrella are dry, answering the first shot.

Tell one object's day, not a chain of shape changes (one disc becomes sun, wheel, clock, coin; no subject, no turn) or a countdown of ten city moments (a list again): one object's day needs objects, vehicles, weather, signs and actions for real reasons, and the signature (the pattern) grows from one canopy to a shelf to the whole frame.

Native moves spent: one verb per item (the umbrella opens, furls, turns over, hooks on, drips), chapter = colour (navy rain, teal day, coral depot, ink storm, yellow bloom), long take down a track (the line, one stop per beat), pace ladder (one-second clock cards), count-up slam (313), icon wall (the shelf turns yellow), split screen along a grid line (wet stop / dry shelf), and one of our own: the wall becomes the pattern (313 canopies open into half-discs and the rows shift like the core graphic).

Shots

Film time; 120 BPM, beat 0.5 s, bar 2 s. Every shot starts on a beat or an eighth. HUD on every shot except the end card: LINE 4 and the clock top left, chapter and weather (word + glyph) top right, a 12-tick bar = the 12 stops of Line 4.

# Time Shot Camera / transition Native move / note
1 0.0–2.5 navy rain pattern; drops in the motif cells; the furled umbrella snaps open on 0.5 (the film's one back ease) over wet footprints, furls on 2.0 locked, background scrolls with the walk opening: a single motif becomes the frame
2 2.5–4.0 the same furled umbrella, now inside a bus window; it turns over and hooks onto the rail on 3.0; the bus brakes at stop 4 · ELM ST, bell on 3.5 shape match cut, then pull back 4.1× → 1× along the grid
3 3.88–4.62 rain → sun at the same moment: navy tiles flip to teal, a sun appears, 07:42 → 07:51 11×6 tile flip weather as a chapter change
4 4.5–6.5 doors open; dry bare-foot prints walk out on 5.0, 5.5, 6.0; doors close on 6.0; the umbrella stays locked wide, slight push people only as traces
5 6.5–10.5 iris from the umbrella into the title card: umbrella on its rail over a seat on the stage disc (assembled from sliding bands); LEFT / BEHIND, 被落下的傘, tag LOST ITEM · UMBRELLA, YELLOW on 7.0; a drip on 9.0 and 10.0 iris → locked type as architecture
6 10.5–13.5 ALL DAY 一整天: the bus rides, stop signs 03–08 whip past one per beat rows transition; lateral track, one-screen whip on 11.0–13.0, row parallax long take down a track
7 13.5–16.5 three one-second cards 10:00 / 14:00 / 18:00 in teal, sky, coral: the stage disc is a clock, the sun walks its rim, the umbrella hangs dry beside it falling columns between cards pace ladder
8 16.5–18.5 stop 12 · DEPOT; the sun sinks behind the road, the moon rises push in; then the frame slides up a screen (18.05–18.5)
9 18.5–21.5 LOST & FOUND 失物招領 chapter band; our sign (umbrella + question mark) slams; the umbrella gets a tag No. 313; rows jump a quarter cell on 19.5–20.5 locked chapter card
10 21.5–25.0 quarter-discs open onto our umbrella in its cubby; pull back 4.2× → 0.62× to a shelf of 320 cubbies (313 umbrellas, a few gloves, keys, hats, a scarf); a panel counts 1 → 313, landing on 24.0 quarter transition; long pull back icon wall, count-up slam
11 25.0–28.0 push back in and drift along the shelf; DAY 02 … DAY 09, a sun per day; 26–28 only a clock ticks slow drift the breath; silence before the turn
12 28.0–31.0 thunder: the shelf splits along a zigzag; STORM 暴雨 on ink; lightning on 28.0 and 29.5; rows lurch half a cell on the beats lightning split
13 31.0–34.0 split screen: left, feet waiting at ELM ST in the rain (等車的人); right, the dry shelf (傘是乾的, 313 DRY) halves drop and rise along x = 960 split along a grid line, held 2.5 s
14 34.0–36.5 the depot shutter; the sign turns CLOSED 休息 → TAKE ONE 拿一把 on 34.5; the shutter rolls up a row per eighth (35.0–36.25); half a beat of silence tile flip; locked
15 36.5–40.5 BLOOM: all 313 open in a ripple from ours (≈0.2 s); the colours sweep to yellow row by row; rows shift half a cell on 39.0, 39.5, 40.0 and the wall becomes the pattern slow pull back 1.1× → 0.8× the wall becomes the pattern
16 40.5–44.0 EVERY STOP 每一站: Line 4 as a route; a stream of umbrellas runs from the depot and three open at each stop, one stop per eighth; the 12 HUD ticks light in step quarter transition; pull back from the depot end
17 44.0–46.5 the next morning, 07:42, the first shot again: rain, the yellow umbrella open, puddles everywhere except under it, dry footprints rows transition; slow push ending that echoes
18 46.5–50.0 end card rows transition; pattern rows stop one by one

Narration (English voice, subtitles Chinese over English, one cue per line):

Start Line
0.4 Seven forty-two. Rain on Line Four.
3.9 Then the sun came out, and someone forgot their umbrella.
11.0 It rode the line all day. Nobody needs an umbrella in the sun.
19.6 At the end of the line, it joined three hundred and twelve others.
28.4 Then, at rush hour, the storm came back.
33.9 The depot opened every shelf.
37.4 Three hundred and thirteen umbrellas went back out into the rain.
44.3 Lost on a sunny day. Found on a rainy one.

77 words in 31.5 s of speech (2.44 words/s; per-line Kokoro speed 0.66–0.84). Every line passes asr_check.py (the time is checked as Whisper writes it, "742"). Captions hold at least the line + 0.6 s (shortest 3.24 s); numbers are spelled out for the voice and written as digits in the captions.

Score structure

120 BPM, picture-locked: mix.py places every hit from the page's window.EV (exported to events.json), so cuts, slams, steps and stops land on their frames.

Palette & props

Five hues and a dark neutral, five tones each (G.PAL in engine.js, t0 darkest → t4 lightest; light hues take dark type):

key name t0 t1 t2 base t3 t4 type
navy Rain Navy #13254a #1a3263 #24457d #3b5e95 #5d7cad cream #fbf6ec
teal Tram Teal #00544c #00685d #0b7f70 #2e9686 #5fae9f cream
sky Puddle Sky #4b95c4 #61a5d0 #7ab6da #97c7e3 #b8daeb dark #0f2036
coral Brick Coral #a93726 #c04731 #d75d43 #e2785c #ea957a cream
yellow Signal Yellow #d39400 #e4a608 #f2ba1d #f6c94a #f9d87e dark #231902
ink Storm Ink #0c1018 #131924 #1b2230 #272f41 #374055 cream, accent yellow

The umbrella is Signal Yellow t2 with a t0 gore: the only warm colour until the bloom. Grid cell 180 px (6 rows). The pattern draws from two motif sets: rain (half-discs, fish scales, dot scales, arcs, crescents, raindrop scales, clouds, rain strokes, small umbrellas) and sun (quarter discs, sunsets, sun wheels, fading bars, suns, wheels, wayfinding chevrons, checks). Props: bus (rounded body, five windows with seat backs and a rail, sliding doors, disc wheels), stop signs (route number, bus glyph, street), clock face on the stage disc, cubby shelf, shutter of grooved slats, lost-property sign, route line with stop discs.

Type: Inter Tight 900 titles (150–270 px, −0.02 em), Noto Sans SC 900 second-language line, DM Mono 17–28 px for the HUD, tags and captions.

End card

Navy pattern whose rows stop one by one, the yellow umbrella opening on its stage disc, and the type sliding up from 46.5 s, fully in place from about 47.5 s to 50.0 s: LEFT BEHIND / 被落下的傘, a hairline, PICTOGRAM MOTION 象形運動圖形, and "LemoLab × Claude Opus 5.5". The last narration line runs under it at the bottom until 49.05 s. The sign-off belongs to this library's demo only; a user's film carries no LemoLab credit and no copy of this card.

Build

sh styles/pictogram-motion/demo/build.sh (WORKERS=3 for more render workers, VOICE=1 to regenerate the narration, sh demo/build.sh 28 36 for a span).

Engine reference

engine.js (window.G)

API What it does
G.E.{lin,io,o3,i3,io3,oExp,iExp,ioExp,oBack,o5} easings (input clamped 0..1)
G.clamp, G.lerp, G.inv(a,b,x), G.rng(seed), G.hash(n) maths; inv = progress of x between a and b, used for every timing
G.PAL[key] (t, fg, far), G.CREAM, G.INK, G.UMB, G.mix(a,b,t), G.rgba(hex,a) palette and colour helpers
G.pattern(pk, seed, {spread, density, set}) cached pattern canvas, 3 cells wider than the screen; set = 'rain' or 'sun' motif library
G.drawPattern(ctx, pat, offs(row)→px) draws the pattern with a per-row horizontal offset (wraps, so rows can travel)
G.motif(ctx, kind, x, y, size, [bg, main, sub], rng) one patterned cell (kinds 0–13 geometry, 14–20 pictogram cells)
G.umbrella(ctx, x, y, R, open, rot, canopy, gore, shaft) umbrella; open 0 furled → 1 open; origin = canopy rim centre
G.drop, G.cloud, G.sunIcon, G.moon, G.bolt, G.foot(…, mirror), G.item(ctx, kind, …) weather, footprint and lost-item pictograms
G.disc, G.seg, G.ring, G.poly, G.rrect, G.hair round-capped drawing primitives
G.maskText(ctx, text, x, y, font, col, p, {align, ls}), G.typeText(…) mask slide-up entrance; typewriter

film.js

SHOTS (film seconds and a kind per shot), TRANS (grid transition per shot boundary: rows, cols, slide, split, quarter, flip), EV (sound events). One function per kind (rainOpen, busStop, titleCard, track, ladder, lastStop, lost, wall, storm, split, shutter, bloom, route, echo, endCard); shared pieces textBlock, chip, stopSign, drawBus, drawWall (the shelf, with open, sweep and shift callbacks), hud, subtitles. frame(t) handles the boundary transitions and the custom ones (flip, iris, descent, lightning split); render averages five sub-frames inside the FAST windows.

Minimal example: a new pictogram and a card

// engine.js: a kite, built from the same geometry
G.kite = (ctx, x, y, s, col, line) => {
  G.poly(ctx, [[x, y - s], [x + s * 0.6, y], [x, y + s], [x - s * 0.6, y]], col);
  G.seg(ctx, [x, y + s], [x - s * 0.3, y + s * 2.2], s * 0.06, line);
};
// film.js: a card that uses it, entered with the shared text block
function kiteCard(ctx, t) {
  const P = PAL.sky, lt = t - 50;
  ctx.fillStyle = P.t[2]; ctx.fillRect(0, 0, W, H);
  G.drawPattern(ctx, G.pattern('sky', 7, { spread: 0.42, set: 'sun' }), rowDrift(lt, 1));
  stageDisc(ctx, 1290, 520, 360, P.t[4], lt);
  G.kite(ctx, 1290, 420 + Math.sin(lt * Math.PI) * 20, 140, G.UMB, P.fg);   // tugs on the beat
  textBlock(ctx, lt, 130, 540, { title: 'WIND', px: 230, zh: '起風了', zpx: 70, fg: P.fg });
}

Then add { t0, kind: 'kite' } to SHOTS, a case in drawShot, a transition in TRANS and its sound in EV.