Timing — flow, named phases & clocks
By default, verbs play one after another. Three wrappers change that — they turn “then, then, then” into “together” or “cascading”.
| wrapper | plays its steps… | use for |
|---|---|---|
| (nothing) | one after another | the normal flow |
par { … } | all at the same instant | reveal a group at once |
seq { … } | one after another (explicit) | grouping inside a par |
stagger(d) { … } | each one d seconds after the last | cascades / waves |
step("name") { … } | all at once, with a named exported start | change one reactive world across representations |
show(a); show(b); // a, THEN b
par { show(a); show(b); } // a and b together
stagger(0.1) { show(a); show(b); show(c); } // a, then b 0.1s later, then c…
Put a for loop inside one and it just works — the loop expands first, so all
its statements land in the wrapper:
par { for i in 0..6 { show(a{i}); } } // whole row at once
stagger(0.1) { for i in 0..6 { show(b{i}); } } // whole row cascading
// the same reveal, three ways: sequence, together, cascade.
title("Timing"); canvas("16:9");
text(t, (cx, 110), "seq · par · stagger"); color(t, cyan); size(t, 30); hidden(t);
for i in 0..6 { dot(a{i}, (220 + i*160, 300), 16); color(a{i}, cyan); hidden(a{i}); }
for i in 0..6 { dot(b{i}, (220 + i*160, 470), 16); color(b{i}, magenta); hidden(b{i}); }
show(t, 0.5);
// top row, all at the same instant
par { for i in 0..6 { show(a{i}); } }
wait(0.5);
// bottom row, cascading 0.1s apart
stagger(0.1) { for i in 0..6 { show(b{i}); } }
wait(1.0);
▶ See it play:
Beats & sections
Two more timing words structure a longer video:
wait(1.2); // hold — nothing moves for 1.2s
section("Part Two"); // a titled marker (jump to it in preview with keys 1–9;
// also exported for lining up narration)
mark("beat-3"); // a named timestamp for your editor
wait is your friend for pacing — a beat of stillness after something lands
reads far better than rushing to the next move.
Named reactive steps
Use step when a beat represents the world’s next conceptual state, not
just anonymous timing. Its children start together like par; its duration is
the longest child; anything not mentioned remains exactly as it was. The unique
name is written to markers.json and becomes a first-class editing boundary:
manic stages FILE.manic lists durations, --stage NAME previews or records
one stage, and --from-stage / --to-stage export an inclusive arc.
step("explain") {
rewrite(work, `f'(x)=2x`, 0.9, smooth);
to(tangent, x, 2.5, 2.0, smooth);
to(slopeValue, x, 2.5, 2.0, smooth);
say(caption, "Every representation changes together.");
}
Steps are top-level and names must be non-empty and unique. Put seq { … }
inside a step when a small part needs ordered choreography.
An authored wait after a step remains part of that stage until the next step
begins. This lets a stage-only export keep the reading hold after its motion.
See Story stages for the live navigator and publishing
workflow.
Generic Timing v2 — one clock for any scene
Use a generic timing controller when several parts of a scene must share one exact schedule. It is format-neutral: the same controller can coordinate a physics simulation, geometry proof, chart, caption sequence, or ordinary shapes.
Think of it as four small pieces:
| piece | responsibility |
|---|---|
timing | declares the phase names, durations, exact total, and optional clock position |
timerstyle | changes only the visible clock; it never changes scene timing |
timed | runs the clock and schedules the complete phase contract |
during | contains the ordinary animation actions for one named phase |
The phase declaration is the source of truth. The clock is only one visual view of that choreography.
Quick reference
| form | use |
|---|---|
timing(clock,"intro=1 demo=6 result=2") | declare named phases |
timing(clock,(1160,80),"...") | declare phases and set the initial clock position |
timing(clock,"duration=6") | shorthand for one phase named main |
timerstyle(clock,"...") | change appearance without changing timing |
timerstyle(clock,(1160,80),"...") | restyle and reposition the clock |
timed(clock) { ... } | play the complete phase schedule and clock |
during("phase") { ... } | author one phase inside timed |
run(clock) | play the clock alone |
countdown(id,[at],[seconds],["style"]) | independent countdown without named phases |
Core pattern, after defining the referenced entities and simulation:
timing(clock, (1160,80), "intro=1 demo=6 result=2");
timerstyle(clock, "look=ring number=inside color=cyan");
timed(clock) {
during("intro") { show(title, 0.6); }
during("demo") { par { run(sim, 6); draw(sim.path, 6); } }
during("result") { show(answer, 0.6); }
}
Use countdown when you only need an independent visual countdown. Use
timing when named phases must govern other animation.
Compose inside phases
Each during block accepts the usual timeline language. In particular, use
par for actions that must occupy the same phase together:
timing(clock, "setup=1 experiment=6 result=2");
timed(clock) {
during("setup") { show(title, 0.6); }
during("experiment") {
par {
run(pendulum, 6);
draw(pendulum.path, 6);
karaoke(caption, 0.35);
}
}
during("result") {
par {
show(formula, 0.6);
show(explanation, 0.6);
}
wait(1.4);
}
}
Rules that prevent drift
- Give a generic controller a fresh id. Do not reuse an entity, quiz, simulation, or group id.
- Put constructors and style modifiers outside
timed/during; put timeline actions such asshow,draw,run,wait,par, andseqinside. - A short phase block is padded automatically. A block that exceeds its phase is an error.
- A phase may have at most one
duringblock. Combine related work inside it withparorseq. - An omitted phase is valid and becomes a blank hold.
- Phase blocks may appear in any source order: they are placed at the absolute
offsets declared by
timing. timed(clock)already runs the clock. Do not also callrun(clock)inside it.run(clock)is timer-only playback.run(clock, dur)is rejected because the phase declaration already owns the duration.
Choose the clock’s look
The clock uses native manic shapes, so it stays sharp at any output size and can be targeted like the rest of the scene. No SVG workflow is required.
| look | best fit |
|---|---|
ring | neutral default; compact and familiar |
bar | long processes or wide layouts |
segments | energetic stages and presentations |
ticks | precise, technical, or measurement-led scenes |
number | minimal layouts where the value is enough |
pulse | short, urgent moments; use sparingly |
none | keep exact phase choreography without showing a clock |
The main controls are:
number=inside|outside|noneanddirection=fill|drainsize=small|medium|large|0.5..2.0andthickness=0.4..3.0color,track,label, andfont=mono|displayfinish=fade|hold|flash|pulsefor the completion cue
Start with the default ring, then change the look only when it supports the
scene’s meaning. For legibility, keep strong contrast between color and
track, and avoid combining a busy clock with dense content in the same corner.
Advanced styling can target the stable tags clock.timer,
clock.timer.track, clock.timer.progress, clock.timer.value,
clock.timer.label, and clock.timer.effects (replace clock with the
controller id).
Generic controller or Creator quiz?
The same visual clock system serves two different timing contracts:
timing(fresh_id, "phase=seconds ...")creates a generic controller used bytimedandduring.timing(quiz_id, "calm ask=... think=... reveal=...")configures a Creator quiz and is played withrun(quiz_id).
Do not wrap a quiz in timed; the quiz runner already owns its ask, options,
think, reveal, hold, and stagger phases.
Common fixes
| message or symptom | fix |
|---|---|
| controller id is already in use | choose a fresh id for generic timing |
| a phase overruns | shorten its sequence, compose simultaneous work with par, or increase the declared phase |
| unknown phase | match the name in during to the timing declaration |
| duplicate phase block | combine the work into one during block |
| competing duration | remove the duration argument from run(clock, dur) |
| timer appears twice | remove run(clock) from inside timed(clock) |
Complete non-quiz example using a pendulum, caption, formula, and segmented clock:
// Generic Timing v2 — one named clock coordinates a non-quiz physics scene.
// `timed` runs the visual timer and places every `during` block at the exact
// offset declared by `timing`; short blocks are padded, overruns are errors.
title("Generic Timing v2 — Pendulum");
canvas("16:9");
template("mono");
watermark(manicMark, (w*0.955-100, h*0.045+24), "Made With Manic");
text(head, (315, 72), "ONE CLOCK. EVERY BEAT.");
size(head, 30); bold(head); color(head, fg); hidden(head);
text(sub, (315, 112), "Generic Timing v2 — not a quiz");
size(sub, 18); color(sub, dim); hidden(sub);
pendulum(p, (640, 245), 1.5, 42, 140, 0.03);
untraced(p.path);
equation(law, (640, 602), `T\approx2\pi\sqrt{L/g}`, 54);
color(law, gold); hidden(law);
text(note, (640, 655), "The scene and clock share the same named phases.");
size(note, 21); color(note, dim); hidden(note);
text(done, (640, 680), "INTRO → EXPERIMENT → INSIGHT → OUTRO");
size(done, 18); color(done, cyan); hidden(done);
// A fresh id creates a format-neutral timing controller. Its phases total
// 10.4 seconds; no duplicate duration is passed to `timed` or `run`.
timing(showclock, (970, 86), "intro=1.2 experiment=6 insight=2 outro=1.2");
timerstyle(showclock,
"look=segments number=outside direction=drain size=small thickness=1.15 color=cyan track=dim label=MASTER_CLOCK font=display finish=pulse");
timed(showclock) {
during("intro") {
par { show(head, 0.7); show(sub, 0.7); }
}
during("experiment") {
par { run(p, 6); draw(p.path, 6); }
}
during("insight") {
par { show(law, 0.6); show(note, 0.6); }
pulse(p.bob, 0.7);
}
during("outro") {
show(done, 0.6);
}
}
Next: the palette, glow, and easings → Colour & style.