retiam 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +3 -3
- package/agent/AGENTS.md +67 -0
- package/agent/CLAUDE.md +2 -0
- package/agent/skill/SKILL.md +111 -0
- package/agent/skill/examples/AreaLesson.ts +48 -0
- package/agent/skill/examples/ExplainMotion.ts +32 -0
- package/agent/skill/examples/NarratedMotion.ts +42 -0
- package/agent/skill/examples/SecantToTangent.ts +142 -0
- package/agent/skill/references/api.md +109 -0
- package/agent/skill/references/explainers.md +121 -0
- package/agent/skill/references/quality.md +148 -0
- package/agent/skill/references/styles.md +58 -0
- package/agent/skill/references/tts.md +72 -0
- package/agent/templates/explainer/lesson.json +25 -0
- package/agent/templates/explainer/review.json +6 -0
- package/agent/templates/explainer/styles.json +92 -0
- package/bin/agent-kit.js +26 -0
- package/bin/cli.js +24 -4
- package/bin/context.js +57 -0
- package/bin/init.js +71 -12
- package/bin/lesson-project.js +30 -0
- package/bin/lesson.js +168 -0
- package/bin/lint.js +6 -6
- package/bin/snapshot-runtime.js +185 -0
- package/bin/snapshot.js +32 -225
- package/dist/THIRD_PARTY_NOTICES.md +3 -3
- package/dist/UTIF-BrQ3Ng5l.min.js +1 -0
- package/dist/{UTIF-2Ear_0Uo.js → UTIF-CN0-pEnd.js} +1 -1
- package/dist/decompress-D7LzbvPD.min.js +15 -0
- package/dist/index-3sAseSJQ.min.js +10472 -0
- package/dist/{index-B2sJBy4c.js → index-yQIdejOj.js} +15 -13
- package/dist/libs/explainer/example.d.ts +3 -0
- package/dist/libs/explainer/index.d.ts +5 -0
- package/dist/libs/explainer/index.js +134 -0
- package/dist/libs/explainer/plan.d.ts +12 -0
- package/dist/libs/explainer/plan.js +197 -0
- package/dist/libs/explainer/runtime.d.ts +24 -0
- package/dist/libs/explainer/styles.d.ts +3 -0
- package/dist/libs/explainer/types.d.ts +119 -0
- package/dist/libs/explainer/visuals.d.ts +18 -0
- package/dist/libs/tts/index.js +386 -1009
- package/dist/libs/vite/index.d.ts +28 -0
- package/dist/libs/vite/index.js +158 -0
- package/dist/{main-D_G4uIju.js → main-BTk_9jtl.js} +1 -1
- package/dist/main-lQwYAed8.min.js +5939 -0
- package/dist/msEdgeV2-BLEnvPJa.js +641 -0
- package/dist/opentype.module-B-1cYAb-.min.js +1 -0
- package/dist/retiam.es.js +1 -1
- package/dist/retiam.es.min.js +1 -0
- package/dist/src/engine/animation/Animation.d.ts +1 -0
- package/package.json +12 -6
- package/readme.md +14 -7
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Explainer production with Retiam
|
|
2
|
+
|
|
3
|
+
Use this for educational animations. Ordinary title animations and other short
|
|
4
|
+
edits do not need a lesson plan. An AI coding harness authors the subject model,
|
|
5
|
+
script and TypeScript scenes; the CLI supplies deterministic production tools.
|
|
6
|
+
No particular AI provider or additional agent service is required.
|
|
7
|
+
|
|
8
|
+
## Start from the learner's question
|
|
9
|
+
|
|
10
|
+
Read `lesson/lesson.json` and the existing source. Establish the topic, audience,
|
|
11
|
+
prerequisites, learning objective, duration constraints and requested style from
|
|
12
|
+
the prompt. Infer routine choices; ask only about consequential missing context.
|
|
13
|
+
The supplied area lesson is a working API reference, not the requested subject.
|
|
14
|
+
Replace its model and beats when the user asks for another topic.
|
|
15
|
+
|
|
16
|
+
Research claims that need verification. Record source IDs, titles, links or
|
|
17
|
+
notes in `sources`, and connect factual claims to those IDs. Explicitly mark an
|
|
18
|
+
illustrative model. A numeric simulation may be correct for its assumptions yet
|
|
19
|
+
misrepresent the real system; explain assumptions and avoid false causality.
|
|
20
|
+
|
|
21
|
+
Plan a visible construction and the narration together. Useful beats include a
|
|
22
|
+
question, a prediction, a counterexample, a mechanism, a generalization, an
|
|
23
|
+
application and a resolved takeaway. Choose the sequence for the subject rather
|
|
24
|
+
than forcing every topic into the same chapter count. Each beat records `goal`,
|
|
25
|
+
`visibleChange` and `focus`. Text such as “explain the process” is not a visible
|
|
26
|
+
change; “a molecule passes through the membrane while concentration decreases” is.
|
|
27
|
+
|
|
28
|
+
## Select the visual mechanism
|
|
29
|
+
|
|
30
|
+
- Algorithms: derive graph, table, queue and code updates from one execution trace.
|
|
31
|
+
Check a result against an independent reference. Use native `Code` and
|
|
32
|
+
`retiam/graphs`; introduce auxiliary representations only when they help.
|
|
33
|
+
- Mathematics: vary a parameter, deform geometry, decompose areas, or connect a
|
|
34
|
+
construction to `Tex`. Transfer identity and color into the notation.
|
|
35
|
+
- Physics: use `retiam/physics` when rigid-body dynamics explain the phenomenon;
|
|
36
|
+
mathematical fields or a deterministic analytic model may be more appropriate.
|
|
37
|
+
- Biology and other processes: author an accurate conceptual model and use
|
|
38
|
+
local interactions, flows and scale changes. Use vectors, shapes or labeled
|
|
39
|
+
assets; a process illustration need not pretend to be a physical simulation.
|
|
40
|
+
- History, economics and data: anchor timelines, maps, comparisons and charts to
|
|
41
|
+
sources. Reveal changes and relationships without animating an unsupported
|
|
42
|
+
causal claim.
|
|
43
|
+
|
|
44
|
+
Use the matching native sublibrary for supported features. Do not import every
|
|
45
|
+
library just to exercise the engine. Novel subjects still need original scenes.
|
|
46
|
+
|
|
47
|
+
## Write for a curious teacher
|
|
48
|
+
|
|
49
|
+
Keep formal definitions and conditions exact. Around them, invite the learner to
|
|
50
|
+
predict, give space to think, and explain why an observed event matters. Vary the
|
|
51
|
+
rhythm: not every sentence needs a question. Avoid forced jokes and filler.
|
|
52
|
+
|
|
53
|
+
For example: “A currently says four. What if we go through B?” Then a real pause
|
|
54
|
+
while the route lights up. “Two, plus one… three. That's better. Let's remember it.”
|
|
55
|
+
Do not expose the candidate or subtitle answer during that prediction pause.
|
|
56
|
+
|
|
57
|
+
Keep performance notes out of spoken text. A narration segment has an `id`,
|
|
58
|
+
`text`, and optional `pauseAfterMs`. Segments need not correspond one-to-one to
|
|
59
|
+
visual actions. Split at purposeful thinking pauses, retaining coherent speech
|
|
60
|
+
between them. The built-in voice remains the default. Change a provider only when
|
|
61
|
+
requested; additional providers may normalize recordings into `PreparedSpeech`.
|
|
62
|
+
Include narration in an explainer unless the user requests a silent treatment.
|
|
63
|
+
The sample's disabled narration is an offline-preview convenience, not a reason
|
|
64
|
+
to omit the requested video's spoken explanation.
|
|
65
|
+
|
|
66
|
+
## Public workflow
|
|
67
|
+
|
|
68
|
+
The core authoring types and runtime are exported by `retiam/explainer`. Pure
|
|
69
|
+
validation, compilation and style resolution also import in Node through
|
|
70
|
+
`retiam/explainer/plan`. Find declarations with `retiam context --json`.
|
|
71
|
+
|
|
72
|
+
1. Edit the lesson and write a subject model under `src/`. Persist the requested
|
|
73
|
+
profile in `style`. `retiam lesson style excalidraw` selects the whiteboard look;
|
|
74
|
+
custom style objects extend a preset. Read [styles.md](styles.md) for the look.
|
|
75
|
+
2. Run `npm run lesson:check`. It checks schema/source references and any prepared
|
|
76
|
+
audio. Its `requiredReview` remains a separate obligation, not a quality score.
|
|
77
|
+
3. For narration set `narration.enabled` to true, then run
|
|
78
|
+
`npm run lesson:prepare`. First-time native synthesis needs network access;
|
|
79
|
+
subsequent calls use the native cache. It writes `lesson/prepared.json` and
|
|
80
|
+
public audio files. Keep them for reproducible export. Silent preview timings
|
|
81
|
+
are explicitly marked `estimated` and are not locked speech timings.
|
|
82
|
+
4. Import the lesson and optional prepared manifest into the scene. Use
|
|
83
|
+
`prepareLesson(this, plan, {prepared})`, then `await lesson.run(handlers)`.
|
|
84
|
+
All handlers are built before playback. Put mutations in animations or `b.at()`;
|
|
85
|
+
do not mutate shared objects directly while constructing later beat handlers.
|
|
86
|
+
5. Bind timing to `b.cue('name')` and `b.durationMs`. A cue identifies a segment
|
|
87
|
+
and optionally a spoken phrase; repeated phrases require `occurrence`.
|
|
88
|
+
Missing, ambiguous or stale cues fail visibly instead of drifting silently.
|
|
89
|
+
Check timing with `npm run lesson:timeline`.
|
|
90
|
+
6. Type-check and lint, then capture setup, prediction, reveal, transition and
|
|
91
|
+
conclusion frames. `lesson check --json` lists useful sample times. Open the
|
|
92
|
+
PNGs and watch representative short clips for pacing. Fix observed issues.
|
|
93
|
+
7. Render with the normal Retiam renderer and export captions with
|
|
94
|
+
`npm run lesson:captions`. Inspect final video/audio streams, listen to speech,
|
|
95
|
+
check synchronization and pauses, and update `lesson/review.json` with concrete
|
|
96
|
+
evidence. Report any unavailable checks honestly.
|
|
97
|
+
|
|
98
|
+
The runtime preloads audio, compiles one frame-aligned clock, and schedules all
|
|
99
|
+
clips and visual beat groups on that clock. Native speech and imported assets
|
|
100
|
+
share `durationMs`, word timestamps and a URL in `PreparedSpeech`. Caption cues
|
|
101
|
+
are grouped within speech segments so they cannot bridge a thinking pause.
|
|
102
|
+
|
|
103
|
+
## Small executable reference
|
|
104
|
+
|
|
105
|
+
Copy `../examples/AreaLesson.ts` from the skill directory into `src/scenes/` to
|
|
106
|
+
run it. `npx create-retiam my-video --template explainer` opens this construction
|
|
107
|
+
with the lesson JSON editable outside the scene. The sample is silent by default
|
|
108
|
+
so a fresh preview works offline; enable native narration when needed.
|
|
109
|
+
|
|
110
|
+
`styleGeometry`, `drawGeometry`, `transferValue` and `emphasize` supply reusable
|
|
111
|
+
motion behaviors. Use public Retiam entities for the rest of the construction.
|
|
112
|
+
A style profile does not automatically make a static scene explanatory.
|
|
113
|
+
|
|
114
|
+
## Review evidence
|
|
115
|
+
|
|
116
|
+
In `lesson/review.json`, keep automatic command results separate from observed
|
|
117
|
+
facts. Record a frame/clip path, the beat reviewed, what was observed and whether
|
|
118
|
+
it was fixed. Inspect overlaps, readable label sizes, stable identity, meaningful
|
|
119
|
+
motion, prediction/reveal order, and a conclusion with time to read. Check claims
|
|
120
|
+
against sources and domain calculations against independent results. A passing
|
|
121
|
+
plan check cannot establish factual or pedagogical correctness.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# 3Blue1Brown-inspired visual explanations
|
|
2
|
+
|
|
3
|
+
The default direction is a 3Blue1Brown-inspired mathematical explainer, built
|
|
4
|
+
with Retiam. Teach through visual intuition and evolving constructions. Match
|
|
5
|
+
the user's subject, audience, duration, and aspect ratio; an explicitly different
|
|
6
|
+
style or palette overrides this default.
|
|
7
|
+
|
|
8
|
+
## Default visual and narrative direction
|
|
9
|
+
|
|
10
|
+
- **Start with a question worth seeing answered.** Give the viewer a concrete
|
|
11
|
+
example to predict or inspect. Build intuition before naming the general rule.
|
|
12
|
+
- **Make the mathematical objects the main actors.** Let a graph, geometry,
|
|
13
|
+
field, system, or construction occupy the stage. Develop it through the
|
|
14
|
+
explanation, with enough spatial continuity to follow what changed and why.
|
|
15
|
+
- **Use a clean dark canvas.** Favor black or deep charcoal, crisp geometry,
|
|
16
|
+
white mathematical typography, and a few clear accents. Blue and warm yellow
|
|
17
|
+
are useful starting accents; assign colors by mathematical role and preserve
|
|
18
|
+
those roles between diagrams, symbols, and transitions. Keep grids subdued.
|
|
19
|
+
- **Let notation grow from the construction.** Introduce a formula when the
|
|
20
|
+
diagram has established its meaning. Place corresponding terms and objects
|
|
21
|
+
in the same colors. Transform relevant terms deliberately, exposing the
|
|
22
|
+
reasoning instead of replacing complete screens of equations.
|
|
23
|
+
- **Choreograph discoveries.** Use smooth drawing, motion, decomposition,
|
|
24
|
+
regrouping, comparison, and parameter sweeps. Focus the camera or emphasize
|
|
25
|
+
an object when a detail becomes important. Leave time for the viewer to make
|
|
26
|
+
an inference before stating it, then test or generalize the insight.
|
|
27
|
+
- **Narrate as an explanation.** When using narration, generate it through
|
|
28
|
+
`retiam/tts`. Use conversational questions and precise language, synchronize
|
|
29
|
+
speech with visible events, and allow meaningful silent pauses. Keep requested
|
|
30
|
+
subtitles unobtrusive so they leave room for the mathematical construction.
|
|
31
|
+
|
|
32
|
+
The goal is a clear, satisfying visual argument. Choose 2D or 3D according to
|
|
33
|
+
the concept. Use a slide, dashboard, or another aesthetic when requested.
|
|
34
|
+
|
|
35
|
+
## Plan events the viewer can see
|
|
36
|
+
|
|
37
|
+
For each substantial beat, identify:
|
|
38
|
+
|
|
39
|
+
| Decision | Useful answer |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| What must become clear? | A relationship, cause, comparison, or mechanism |
|
|
42
|
+
| What visibly changes? | A path, configuration, parameter, grouping, or viewpoint |
|
|
43
|
+
| What carries continuity? | The same point, node, symbol, shape, or color meaning |
|
|
44
|
+
| Where should the eye go? | One object or relationship at a time |
|
|
45
|
+
| What warrants a pause? | A meaningful comparison or resolved result |
|
|
46
|
+
|
|
47
|
+
Write an action such as “the second point travels along the curve while the
|
|
48
|
+
secant rotates and the gap collapses.” “Explain the derivative” or “show the next
|
|
49
|
+
heading” does not specify a visual event. Derive the number and length of beats
|
|
50
|
+
from the explanation; do not impose the same five scenes on every subject.
|
|
51
|
+
|
|
52
|
+
Prefer an evolving construction: establish the objects, expose a contrast or
|
|
53
|
+
problem, show the mechanism changing the state, then resolve and generalize.
|
|
54
|
+
Preserve enough context that the viewer can understand each transformation.
|
|
55
|
+
|
|
56
|
+
## Choreograph meaning
|
|
57
|
+
|
|
58
|
+
- **Carry the idea in geometry.** Trace an actual route, move a point along its
|
|
59
|
+
function, deform the existing object, reveal how pieces assemble, or run the
|
|
60
|
+
simulation. Text describes a result after the viewer has seen its cause.
|
|
61
|
+
- **Preserve identity.** Move or transform the same object between states. Keep
|
|
62
|
+
variable colors consistent between diagrams and formulas. Use matching-symbol
|
|
63
|
+
transforms for a meaningful equation change when appropriate.
|
|
64
|
+
When unrelated symbols should disappear, use `morphUnmatched: false` rather
|
|
65
|
+
than deforming every leftover glyph into a new one.
|
|
66
|
+
- **Direct attention.** Establish context, emphasize the current relationship,
|
|
67
|
+
and widen the view for the result. Zoom or pan only when a close relationship,
|
|
68
|
+
changing frontier, or new scale benefits from it. A well-composed static shot
|
|
69
|
+
can support excellent motion; constant camera movement can obscure it.
|
|
70
|
+
- **Use a few distinct motion functions.** Drawing reveals structure; travel
|
|
71
|
+
shows flow; a morph preserves correspondence; a brief pulse marks a state
|
|
72
|
+
change; a hold gives time to infer. Choose the functions the concept needs.
|
|
73
|
+
- **Coordinate timing.** Related changes should happen together. Give an action
|
|
74
|
+
an appropriate acceleration, settle, and readable pause. Use `Concurrent`
|
|
75
|
+
with an explicit group duration so its defaults do not retime the children.
|
|
76
|
+
Use linear progress for uniform physical/data sweeps and eased motion for
|
|
77
|
+
entrances or changes that should settle; follow the actual simulated model.
|
|
78
|
+
- **Keep labels local and short.** Anchor a cost near the affected node or a
|
|
79
|
+
quantity beside its geometric span. Prefer a few precise words to paragraphs.
|
|
80
|
+
Use `Tex` for formulas and meaningful term matching, not plain text equations.
|
|
81
|
+
- **Let narration explain why.** Align each utterance with the event it explains.
|
|
82
|
+
If requested, use `retiam/tts` and its prepared audio duration. Repeatedly
|
|
83
|
+
replacing paragraphs beside an otherwise idle diagram is not enough motion.
|
|
84
|
+
|
|
85
|
+
Choose colors for hierarchy and meaning, with enough contrast for the output.
|
|
86
|
+
Keep guides quieter than active geometry and leave negative space. The default
|
|
87
|
+
dark palette supports the construction; glow, 3D, and sound effects need an
|
|
88
|
+
explanatory purpose.
|
|
89
|
+
|
|
90
|
+
## Presentation patterns to revise
|
|
91
|
+
|
|
92
|
+
For an animation brief, revise these patterns unless they serve a specific need:
|
|
93
|
+
|
|
94
|
+
- A permanent title/header, large body panel, footer, chapter number, and page
|
|
95
|
+
counter framing every beat in the same layout.
|
|
96
|
+
- A diagram occupying one corner while most of the frame is explanatory text.
|
|
97
|
+
- An entire screen fading away, followed by a new heading and another fade-in.
|
|
98
|
+
- A long voiceover over a static scene with only a progress bar or decorative glow.
|
|
99
|
+
- Identical reveal timing for every beat, or unrelated objects appearing at once.
|
|
100
|
+
- An algorithm shown mainly as table rows changing while its mechanism stays idle.
|
|
101
|
+
|
|
102
|
+
For example, a Dijkstra explanation can begin with a question about competing
|
|
103
|
+
routes in the graph. Let the viewer predict a winner, then show why counting
|
|
104
|
+
roads can fail when their costs differ. Make the reason for finalizing the
|
|
105
|
+
cheapest unsettled cost visible using the nonnegative-edge assumption.
|
|
106
|
+
Trace the inspected edge, show the candidate cost beside the affected node, and
|
|
107
|
+
visibly retain or reject that route. Move attention with the active frontier,
|
|
108
|
+
keep cost and settled-state meanings consistent, then dim explored clutter and
|
|
109
|
+
trace the winning path. Use a priority queue or table when explaining that
|
|
110
|
+
structure, rather than reserving half the canvas for one throughout the video.
|
|
111
|
+
Follow actual weighted relaxation order; decorative propagation must not imply
|
|
112
|
+
an incorrect algorithm.
|
|
113
|
+
|
|
114
|
+
## Working reference
|
|
115
|
+
|
|
116
|
+
[SecantToTangent.ts](../examples/SecantToTangent.ts) is a silent visual reference:
|
|
117
|
+
|
|
118
|
+
| Time | Visible event | Purpose |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| 0–3.1 s | Draw the curve, mark two points, introduce the secant and its gap | Establish the construction |
|
|
121
|
+
| 3.1–6.3 s | Move the second point along the curve; the line rotates and the gap shrinks | Show what determines the secant slope |
|
|
122
|
+
| 6.3–11.1 s | Bring attention closer and continue the convergence | Make the limiting relationship visible |
|
|
123
|
+
| 11.1–13.1 s | Resolve the tangent and transform the equation | Connect geometry to notation |
|
|
124
|
+
| 13.1–19.5 s | Move the tangent point across both sides of the curve, updating the slope | Generalize beyond one frozen example |
|
|
125
|
+
| 19.5–21.5 s | Hold the resolved construction | Allow the takeaway to register |
|
|
126
|
+
|
|
127
|
+
The smaller `ExplainMotion.ts` and `NarratedMotion.ts` examples isolate API and
|
|
128
|
+
speech mechanics. They are not visual templates for finished explainers.
|
|
129
|
+
|
|
130
|
+
## Review the rendered evidence
|
|
131
|
+
|
|
132
|
+
Capture the setup, the middle of the main mechanism, a transition, and the resolved
|
|
133
|
+
state at the intended aspect ratio. Open the PNGs and watch playback.
|
|
134
|
+
|
|
135
|
+
- Is the mathematical/data relationship correct throughout the motion?
|
|
136
|
+
- Does the construction establish intuition before introducing the general rule?
|
|
137
|
+
- Do corresponding geometric objects and mathematical terms keep their color meaning?
|
|
138
|
+
- Is the focal object clear, with readable labels and no accidental overlap or clipping?
|
|
139
|
+
- Does the main action demonstrate the idea without requiring every caption?
|
|
140
|
+
- Can the viewer follow the same object through transitions and reframing?
|
|
141
|
+
- Do motion and pauses feel purposeful when watched at normal speed?
|
|
142
|
+
- Does the conclusion remain visible long enough to read?
|
|
143
|
+
|
|
144
|
+
Compare the middle of adjacent beats. If only the heading or paragraph changes,
|
|
145
|
+
redesign the visible action. A deliberate reading hold or final rest is useful;
|
|
146
|
+
idle slides throughout an explanation need revision. Record concrete observed
|
|
147
|
+
issues and fix them. Lint and type checks cannot judge aesthetic quality or
|
|
148
|
+
explanatory correctness, and static screenshots cannot establish pacing.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Visual style profiles
|
|
2
|
+
|
|
3
|
+
Teaching goals and visual style are independent. Read the user's prompt first.
|
|
4
|
+
An explicit requested style overrides `lesson/lesson.json`; save that choice so
|
|
5
|
+
future revisions remain consistent. Keep the same mathematical/content model and
|
|
6
|
+
narration cues when restyling. Preserve explicit brand, aspect and accessibility
|
|
7
|
+
constraints. `retiam lesson styles --json` gives actual tokens for this version.
|
|
8
|
+
|
|
9
|
+
## mathematical — default, matching the Dijkstra video
|
|
10
|
+
|
|
11
|
+
Use navy `#0A1020`, light text, vivid blue and gold, with mint, coral, violet and
|
|
12
|
+
teal available as stable object identities. Color carries meaning across the
|
|
13
|
+
construction, labels, formulas and data transfers. Do not turn the palette into
|
|
14
|
+
random per-frame decoration. Let lines trace real paths, values travel between
|
|
15
|
+
representations, replacements settle smoothly and discarded candidates fade.
|
|
16
|
+
Ask a question, allow a thinking pause, then reveal its answer through geometry.
|
|
17
|
+
Use native `Tex` and syntax-highlighted `Code` where they explain the subject.
|
|
18
|
+
Introduce tables and queues as teaching objects only when relevant. Maintain
|
|
19
|
+
spatial continuity through derivations and applications; conclude with the idea
|
|
20
|
+
that the evolving construction has established.
|
|
21
|
+
|
|
22
|
+
## excalidraw — hand-drawn whiteboard
|
|
23
|
+
|
|
24
|
+
Use warm paper, dark ink, blue and amber markers. The profile selects Retiam's
|
|
25
|
+
bundled `excalifont` for vector labels. Use native `toExcalidraw` through
|
|
26
|
+
`styleGeometry`, and `drawGeometry` for progressive sketch drawing. Use seeded,
|
|
27
|
+
restrained roughness, intentional arrows and light hatching. Keep mathematical
|
|
28
|
+
symbols readable in `Tex`. A question, sketched experiment and resolving annotation
|
|
29
|
+
can share one evolving board. Use dark paper as a custom override if requested.
|
|
30
|
+
Do not apply roughness to every text glyph or continuously jitter all labels.
|
|
31
|
+
|
|
32
|
+
## minimal — clear vector construction
|
|
33
|
+
|
|
34
|
+
Use a light canvas, precise outlines, generous negative space and a small number
|
|
35
|
+
of semantic colors. Motion should isolate a relation: align, compare, decompose,
|
|
36
|
+
transfer or resolve. Keep labels local and avoid filling the quiet space with
|
|
37
|
+
paragraphs. Minimal graphics can still carry a lively teacher's narration.
|
|
38
|
+
|
|
39
|
+
## cinematic — deliberate depth and staging
|
|
40
|
+
|
|
41
|
+
Use a dark canvas, violet/teal accents, slower establishing moves and a strong
|
|
42
|
+
focus for the current event. Use depth or 3D when it explains a spatial relation;
|
|
43
|
+
2D with deliberate staging is also valid. Lighting and highlights support the
|
|
44
|
+
mechanism. Keep labels and formulas clear as the camera moves, and let the
|
|
45
|
+
resolved state rest. Motion quality does not require constant camera movement.
|
|
46
|
+
|
|
47
|
+
## Custom override
|
|
48
|
+
|
|
49
|
+
A prompt can describe a new palette or reference look. Preserve the selected
|
|
50
|
+
profile's useful behavior while overriding tokens in JSON, for example:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{"style":{"extends":"excalidraw","name":"Night chalkboard","background":"#122322","ink":"#F4F2DD","primary":"#7DE1C4","secondary":"#F1CC75","muted":"#94AAA5","accents":["#7DE1C4","#F1CC75"]}}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`resolveStyle` validates the tokens. Fonts must be bundled aliases or available
|
|
57
|
+
user-supplied font assets. Profile changes affect only entities using the profile;
|
|
58
|
+
agent-authored custom colors/materials must be reviewed during a restyle.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Native Retiam narration
|
|
2
|
+
|
|
3
|
+
Generate speech for Retiam scenes through `retiam/tts`. It supplies synthesis,
|
|
4
|
+
timing, subtitle synchronization, and playback through the scene's voiceover bus.
|
|
5
|
+
The built-in provider uses Microsoft Edge neural speech over the network. It
|
|
6
|
+
does not require installing Python TTS packages.
|
|
7
|
+
|
|
8
|
+
Use [NarratedMotion.ts](../examples/NarratedMotion.ts) as the executable recipe.
|
|
9
|
+
Copy it into `src/scenes/` to preview or render it. Adapt the text, voice, and
|
|
10
|
+
motion to the brief. Use a different speech generator only if the user requests
|
|
11
|
+
one; diagnose failures in this path instead of silently replacing it.
|
|
12
|
+
|
|
13
|
+
## Browser and renderer setup
|
|
14
|
+
|
|
15
|
+
New projects enable the native proxy in their Vite configuration. For an existing
|
|
16
|
+
project using an engine release that provides `retiam/vite`, preserve its other
|
|
17
|
+
plugins and add:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { defineConfig } from 'vite';
|
|
21
|
+
import { msEdgeTTSPlugin } from 'retiam/vite';
|
|
22
|
+
|
|
23
|
+
export default defineConfig({ plugins: [msEdgeTTSPlugin()] });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This is a **server-side** import. Scene code imports speech APIs from `retiam/tts`.
|
|
27
|
+
The middleware serves `/api/tts/msedge/synthesize` in Vite development and preview
|
|
28
|
+
servers, including the Vite server started by Retiam's render/snapshot commands.
|
|
29
|
+
A static production host needs an equivalent server endpoint or pre-generated
|
|
30
|
+
audio; bundling the page alone does not host speech synthesis.
|
|
31
|
+
|
|
32
|
+
## Timeline recipe
|
|
33
|
+
|
|
34
|
+
- Use `Speak` as an animation for simultaneous narration and motion. Set `entity`
|
|
35
|
+
to an entity already added to the scene so speech uses that scene's audio bus.
|
|
36
|
+
Call `prepareAudio()` first; its result sets the animation's exact duration.
|
|
37
|
+
- Register the **synthesis promise** in `this.composer.pendingTasks` before
|
|
38
|
+
awaiting it. Headless tools can then wait for network speech generation without
|
|
39
|
+
advancing the scene past the narration. Do not register `this.play(...)` or
|
|
40
|
+
`speak(...)` promises there: they need timeline updates and would deadlock.
|
|
41
|
+
- Set accompanying motion duration from the prepared `Speak.duration`. Avoid
|
|
42
|
+
guessing speech duration from word counts. Also pass that duration explicitly
|
|
43
|
+
to `Concurrent` so the group's defaults do not rescale the prepared narration.
|
|
44
|
+
- For sequential narration, `await speak(this, text, options)` synthesizes,
|
|
45
|
+
plays, synchronizes optional subtitles, and waits for the utterance duration.
|
|
46
|
+
Pre-synthesize that text with `TTS.synthesize(text, options)` and register only
|
|
47
|
+
its synthesis promise before headless rendering; the default provider caches
|
|
48
|
+
the result in memory.
|
|
49
|
+
- `TTS.speak(...)` is a different, lower-level client facade. Its playback result
|
|
50
|
+
does not itself provide the scene's `wait(...)` pacing.
|
|
51
|
+
- Add `new Subtitles({ fontSize, bottomOffset, maxWidth, ... })` to the scene, and
|
|
52
|
+
pass it as `subtitles`. Keep the caption area within the shot. Caption timing
|
|
53
|
+
uses the generated audio metadata.
|
|
54
|
+
- `voice` is a voice ID such as `en-US-JennyNeural`; `speed` is a multiplier
|
|
55
|
+
such as `1.0`, `pitch` accepts values such as `'+0Hz'`, and playback `volume`
|
|
56
|
+
is 0–1. Follow installed types for more options.
|
|
57
|
+
|
|
58
|
+
## Diagnose native TTS failures
|
|
59
|
+
|
|
60
|
+
1. A missing `retiam/vite` import means the installed engine predates this setup
|
|
61
|
+
or its build is incomplete. Check `retiam context --json` and the installed
|
|
62
|
+
package version before changing providers.
|
|
63
|
+
2. HTTP 404 at `/api/tts/msedge/synthesize` means the middleware is absent or the
|
|
64
|
+
configured endpoint differs. Fix the Vite configuration and restart the server.
|
|
65
|
+
3. HTTP 502 means the proxy ran but synthesis failed. Read the server error;
|
|
66
|
+
check network access and the requested voice. Do not present silent audio as
|
|
67
|
+
a successful narration render.
|
|
68
|
+
4. Browser autoplay may require a click or keypress to unlock audio in Studio.
|
|
69
|
+
The headless CLI supplies its autoplay flag.
|
|
70
|
+
5. For exported video, verify an audio stream exists and listen to the result.
|
|
71
|
+
Snapshots verify visuals only. Speech generation requires network access on a
|
|
72
|
+
cache miss; the middleware caches audio in `node_modules/.cache/msedge-tts`.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"title": "Why does area grow so fast?",
|
|
4
|
+
"topic": "How a square's area changes when its side length doubles",
|
|
5
|
+
"audience": "Curious beginners",
|
|
6
|
+
"objective": "See why doubling both side lengths produces four unit squares.",
|
|
7
|
+
"style": "mathematical",
|
|
8
|
+
"narration": {"enabled": false, "provider": "msedge", "voice": "en-US-AndrewNeural", "speed": 1, "pitch": "+0Hz", "volume": 1},
|
|
9
|
+
"sources": [],
|
|
10
|
+
"claims": [{"id":"area-model","text":"A square of side two can be partitioned into four squares of side one.","sourceIds":[],"illustrative":true}],
|
|
11
|
+
"beats": [
|
|
12
|
+
{"id":"predict","goal":"Invite a prediction before exposing the area.","visibleChange":"Draw one unit square and mark its side length.","focus":"The original square","minDurationMs":4500,
|
|
13
|
+
"narration":[{"id":"question","text":"Here is one unit square. If we double its side length, what happens to its area?","pauseAfterMs":900}],
|
|
14
|
+
"cues":[{"id":"show","segment":"question"}]},
|
|
15
|
+
{"id":"grow","goal":"Separate a change in side length from a change in area.","visibleChange":"Expand the outline while retaining the original square.","focus":"Both sides grow","minDurationMs":5000,
|
|
16
|
+
"narration":[{"id":"expand","text":"Let's double both sides. The original square still fits in the corner. How much new space have we made?","pauseAfterMs":700}],
|
|
17
|
+
"cues":[{"id":"expand","segment":"expand"}]},
|
|
18
|
+
{"id":"count","goal":"Discover the four equal areas through decomposition.","visibleChange":"Reveal the three additional unit squares in sequence.","focus":"Four equal pieces","minDurationMs":5000,
|
|
19
|
+
"narration":[{"id":"reveal","text":"One here, another above, and one more in the corner. Together with our original square, that makes four."}],
|
|
20
|
+
"cues":[{"id":"reveal","segment":"reveal"}]},
|
|
21
|
+
{"id":"connect","goal":"Connect the construction to the general area relationship.","visibleChange":"Keep all four pieces visible and reveal the equation below them.","focus":"Side length and area","minDurationMs":4500,
|
|
22
|
+
"narration":[{"id":"insight","text":"Two times the side length gives four times the area. That's the square in side squared: two growing directions, multiplied together."}],
|
|
23
|
+
"cues":[{"id":"equation","segment":"insight"}]}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"automated": {},
|
|
3
|
+
"observations": [],
|
|
4
|
+
"requiredReview": ["Check factual claims and illustrative model assumptions.","Inspect the beginning, prediction pause, main mechanism, transition and conclusion.","Watch a short preview at normal speed to assess pacing and attention.","Verify the final audio track, captions and video dimensions."],
|
|
5
|
+
"status": "not-reviewed"
|
|
6
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mathematical": {
|
|
3
|
+
"name": "Dijkstra-style mathematical explainer",
|
|
4
|
+
"background": "#0A1020",
|
|
5
|
+
"ink": "#ECF0F5",
|
|
6
|
+
"muted": "#74869C",
|
|
7
|
+
"primary": "#6CD5FF",
|
|
8
|
+
"secondary": "#F7CF73",
|
|
9
|
+
"font": "roboto",
|
|
10
|
+
"strokeWidth": 0.035,
|
|
11
|
+
"rough": false,
|
|
12
|
+
"roughness": 0,
|
|
13
|
+
"fillStyle": "solid",
|
|
14
|
+
"motion": {
|
|
15
|
+
"drawMs": 1200,
|
|
16
|
+
"moveMs": 1400,
|
|
17
|
+
"holdMs": 700
|
|
18
|
+
},
|
|
19
|
+
"accents": [
|
|
20
|
+
"#65F0C4",
|
|
21
|
+
"#FF879F",
|
|
22
|
+
"#BA98FF",
|
|
23
|
+
"#55DDE0"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"excalidraw": {
|
|
27
|
+
"name": "Excalidraw whiteboard",
|
|
28
|
+
"background": "#FFFDF7",
|
|
29
|
+
"ink": "#263238",
|
|
30
|
+
"muted": "#7B858C",
|
|
31
|
+
"primary": "#1971C2",
|
|
32
|
+
"secondary": "#D46B08",
|
|
33
|
+
"font": "excalifont",
|
|
34
|
+
"strokeWidth": 0.04,
|
|
35
|
+
"rough": true,
|
|
36
|
+
"roughness": 0.7,
|
|
37
|
+
"fillStyle": "hachure",
|
|
38
|
+
"motion": {
|
|
39
|
+
"drawMs": 1600,
|
|
40
|
+
"moveMs": 1500,
|
|
41
|
+
"holdMs": 900
|
|
42
|
+
},
|
|
43
|
+
"accents": [
|
|
44
|
+
"#1971C2",
|
|
45
|
+
"#D46B08"
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
"minimal": {
|
|
49
|
+
"name": "Minimal vector",
|
|
50
|
+
"background": "#F8FAFC",
|
|
51
|
+
"ink": "#17212B",
|
|
52
|
+
"muted": "#68788A",
|
|
53
|
+
"primary": "#2563EB",
|
|
54
|
+
"secondary": "#C2410C",
|
|
55
|
+
"font": "roboto",
|
|
56
|
+
"strokeWidth": 0.025,
|
|
57
|
+
"rough": false,
|
|
58
|
+
"roughness": 0,
|
|
59
|
+
"fillStyle": "solid",
|
|
60
|
+
"motion": {
|
|
61
|
+
"drawMs": 900,
|
|
62
|
+
"moveMs": 1100,
|
|
63
|
+
"holdMs": 650
|
|
64
|
+
},
|
|
65
|
+
"accents": [
|
|
66
|
+
"#2563EB",
|
|
67
|
+
"#C2410C"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"cinematic": {
|
|
71
|
+
"name": "Cinematic diagrams",
|
|
72
|
+
"background": "#080B18",
|
|
73
|
+
"ink": "#F4F1FF",
|
|
74
|
+
"muted": "#8290AA",
|
|
75
|
+
"primary": "#B79AFF",
|
|
76
|
+
"secondary": "#58E0CE",
|
|
77
|
+
"font": "roboto",
|
|
78
|
+
"strokeWidth": 0.04,
|
|
79
|
+
"rough": false,
|
|
80
|
+
"roughness": 0,
|
|
81
|
+
"fillStyle": "solid",
|
|
82
|
+
"motion": {
|
|
83
|
+
"drawMs": 1500,
|
|
84
|
+
"moveMs": 2000,
|
|
85
|
+
"holdMs": 1000
|
|
86
|
+
},
|
|
87
|
+
"accents": [
|
|
88
|
+
"#B79AFF",
|
|
89
|
+
"#58E0CE"
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
}
|
package/bin/agent-kit.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import {copyLessonKit} from './lesson-project.js';
|
|
5
|
+
|
|
6
|
+
export const agentKitRoot = fileURLToPath(new URL('../agent/', import.meta.url));
|
|
7
|
+
|
|
8
|
+
/** Used only while creating an empty project or preparing a fresh template. */
|
|
9
|
+
export function copyAgentKit(directory, options = {}) {
|
|
10
|
+
const files = [];
|
|
11
|
+
for (const name of ['AGENTS.md', 'CLAUDE.md']) {
|
|
12
|
+
fs.copyFileSync(path.join(agentKitRoot, name), path.join(directory, name));
|
|
13
|
+
files.push(name);
|
|
14
|
+
}
|
|
15
|
+
const destination = path.join(directory, '.agents/skills/retiam');
|
|
16
|
+
fs.cpSync(path.join(agentKitRoot, 'skill'), destination, { recursive: true });
|
|
17
|
+
function collect(folder) {
|
|
18
|
+
for (const entry of fs.readdirSync(folder, { withFileTypes: true })) {
|
|
19
|
+
const location = path.join(folder, entry.name);
|
|
20
|
+
if (entry.isDirectory()) collect(location);
|
|
21
|
+
else files.push(path.relative(directory, location).split(path.sep).join('/'));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
collect(destination);
|
|
25
|
+
return [...files,...copyLessonKit(directory,options)];
|
|
26
|
+
}
|
package/bin/cli.js
CHANGED
|
@@ -20,13 +20,17 @@ const exportScript = path.join(__dirname, 'export.js');
|
|
|
20
20
|
const lintScript = path.join(__dirname, 'lint.js');
|
|
21
21
|
const snapshotScript = path.join(__dirname, 'snapshot.js');
|
|
22
22
|
const initScript = path.join(__dirname, 'init.js');
|
|
23
|
+
const contextScript = path.join(__dirname, 'context.js');
|
|
24
|
+
const lessonScript = path.join(__dirname, 'lesson.js');
|
|
23
25
|
|
|
24
26
|
function runScript(scriptPath, scriptArgs) {
|
|
25
27
|
if (scriptPath === renderScript || scriptPath === snapshotScript) {
|
|
26
28
|
try {
|
|
27
29
|
createRequire(import.meta.url).resolve('puppeteer');
|
|
28
30
|
} catch {
|
|
29
|
-
|
|
31
|
+
const message = 'Retiam installation is incomplete: its required Puppeteer dependency is missing. Reinstall Retiam in your project with: npm install retiam';
|
|
32
|
+
if (scriptPath === snapshotScript && scriptArgs.includes('--json')) console.log(JSON.stringify({ status: 'error', message }));
|
|
33
|
+
console.error(message);
|
|
30
34
|
process.exit(1);
|
|
31
35
|
}
|
|
32
36
|
}
|
|
@@ -48,6 +52,8 @@ Usage:
|
|
|
48
52
|
npx retiam help <command> (detailed help for a single command)
|
|
49
53
|
|
|
50
54
|
Commands Overview:
|
|
55
|
+
lesson Teaching plans, styles, native narration, cue timelines, and captions
|
|
56
|
+
context Locate version-matched agent guidance, examples, and API declarations
|
|
51
57
|
init, create Initialize a complete Retiam WebGPU animation skeleton project
|
|
52
58
|
lint Statically analyze scenes for runtime hazards and async timing bugs
|
|
53
59
|
snapshot Capture multi-timestamp visual PNG keyframes via headless WebGPU
|
|
@@ -85,7 +91,7 @@ Commands Overview:
|
|
|
85
91
|
|
|
86
92
|
================================================================================
|
|
87
93
|
2. SNAPSHOT (npx retiam snapshot <file> [options])
|
|
88
|
-
|
|
94
|
+
Run the named scene directly and capture PNGs at fixed-step timeline seconds.
|
|
89
95
|
|
|
90
96
|
Arguments:
|
|
91
97
|
<file> Target scene TypeScript file (e.g. MyScene.ts)
|
|
@@ -95,6 +101,8 @@ Commands Overview:
|
|
|
95
101
|
-w, --width <px> Snapshot width in pixels (default: 1280)
|
|
96
102
|
-h, --height <px> Snapshot height in pixels (default: 720)
|
|
97
103
|
-o, --out <dir> Output directory for images (default: ./outputs/snapshot)
|
|
104
|
+
--fps <num> Timeline step rate (default: 60)
|
|
105
|
+
--timeout <ms> Browser operation timeout (default: 120000)
|
|
98
106
|
--json Output structured JSON for agents & CI automation
|
|
99
107
|
--help Show snapshot-specific help
|
|
100
108
|
|
|
@@ -113,6 +121,8 @@ Commands Overview:
|
|
|
113
121
|
Options:
|
|
114
122
|
-n, --name <name> Project name for package.json (default: directory name)
|
|
115
123
|
--title <text> Hero text for starter Hello World scene (default: Hello World)
|
|
124
|
+
--template <name> basic (default) or explainer worked construction
|
|
125
|
+
--style <name> mathematical (Dijkstra default), excalidraw, minimal, cinematic
|
|
116
126
|
--pm <manager> Package manager: npm, pnpm, yarn, bun (default: auto or npm)
|
|
117
127
|
-f, --force Overwrite destination directory if files already exist
|
|
118
128
|
-y, --yes Skip interactive prompts and use defaults
|
|
@@ -167,7 +177,13 @@ Commands Overview:
|
|
|
167
177
|
`);
|
|
168
178
|
}
|
|
169
179
|
|
|
170
|
-
if (command === '
|
|
180
|
+
if (command === 'lesson') {
|
|
181
|
+
runScript(lessonScript, args.slice(1));
|
|
182
|
+
}
|
|
183
|
+
else if (command === 'context') {
|
|
184
|
+
runScript(contextScript, args.slice(1));
|
|
185
|
+
}
|
|
186
|
+
else if (command === 'lint') {
|
|
171
187
|
// Usage: npx retiam lint src/MyScene.ts [--json]
|
|
172
188
|
runScript(lintScript, args.slice(1));
|
|
173
189
|
}
|
|
@@ -189,7 +205,11 @@ else if (command === 'render') {
|
|
|
189
205
|
}
|
|
190
206
|
else if (command === 'help') {
|
|
191
207
|
const sub = args[1];
|
|
192
|
-
if (sub === '
|
|
208
|
+
if (sub === 'lesson') {
|
|
209
|
+
runScript(lessonScript, ['--help']);
|
|
210
|
+
} else if (sub === 'context') {
|
|
211
|
+
runScript(contextScript, ['--help']);
|
|
212
|
+
} else if (sub === 'lint') {
|
|
193
213
|
runScript(lintScript, ['--help']);
|
|
194
214
|
} else if (sub === 'snapshot') {
|
|
195
215
|
runScript(snapshotScript, ['--help']);
|