@scenar/cli 0.9.1 → 0.11.0
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/example-bundle/assets/index-DxmqjG-8.js +388 -0
- package/example-bundle/assets/style-B2sxnVVZ.css +1 -0
- package/example-bundle/embed.js +1 -1
- package/example-bundle/index.html +2 -2
- package/example-bundle/logo.png +0 -0
- package/example-bundle/pack-manifest.json +33 -9
- package/example-bundle/soundtrack/music.mp3 +0 -0
- package/example-bundle/soundtrack/sfx/click.mp3 +0 -0
- package/example-bundle/soundtrack/sfx/keystroke.mp3 +0 -0
- package/package.json +4 -4
- package/src/__tests__/collect-pack-shots.test.ts +27 -1
- package/src/__tests__/elevenlabs-provider.test.ts +187 -0
- package/src/__tests__/embed-snippet.test.ts +5 -0
- package/src/__tests__/find-authored-soundtrack.test.ts +54 -0
- package/src/__tests__/find-authored-title-cards.test.ts +65 -0
- package/src/__tests__/find-authored-viewport.test.ts +58 -0
- package/src/__tests__/load-bundle.test.ts +67 -0
- package/src/__tests__/narrate-command.test.ts +65 -1
- package/src/__tests__/narration-cache.test.ts +134 -0
- package/src/__tests__/pack-bundle-contract.test.ts +2 -0
- package/src/__tests__/pack-generate-embed-entry.test.ts +99 -16
- package/src/__tests__/presenter-command.test.ts +366 -0
- package/src/__tests__/render-command.test.ts +11 -0
- package/src/__tests__/render-generate-entry.test.ts +102 -0
- package/src/__tests__/resolve-pack-viewport.test.ts +46 -0
- package/src/__tests__/resolve-provider.test.ts +32 -3
- package/src/__tests__/scenario-validator.test.ts +174 -0
- package/src/__tests__/stage-assets.test.ts +269 -0
- package/src/commands/narrate.js +1 -1
- package/src/commands/narrate.js.map +1 -1
- package/src/commands/narrate.ts +1 -1
- package/src/commands/pack.d.ts.map +1 -1
- package/src/commands/pack.js +23 -4
- package/src/commands/pack.js.map +1 -1
- package/src/commands/pack.ts +26 -5
- package/src/commands/presenter.d.ts +3 -0
- package/src/commands/presenter.d.ts.map +1 -0
- package/src/commands/presenter.js +89 -0
- package/src/commands/presenter.js.map +1 -0
- package/src/commands/presenter.ts +107 -0
- package/src/commands/render.d.ts.map +1 -1
- package/src/commands/render.js +2 -0
- package/src/commands/render.js.map +1 -1
- package/src/commands/render.ts +6 -0
- package/src/embed/embed-snippet.d.ts +5 -0
- package/src/embed/embed-snippet.d.ts.map +1 -1
- package/src/embed/embed-snippet.js +6 -1
- package/src/embed/embed-snippet.js.map +1 -1
- package/src/embed/embed-snippet.ts +6 -1
- package/src/index.d.ts.map +1 -1
- package/src/index.js +2 -0
- package/src/index.js.map +1 -1
- package/src/index.ts +2 -0
- package/src/narrate/run-narrate.d.ts +15 -1
- package/src/narrate/run-narrate.d.ts.map +1 -1
- package/src/narrate/run-narrate.js +11 -4
- package/src/narrate/run-narrate.js.map +1 -1
- package/src/narrate/run-narrate.ts +15 -6
- package/src/pack/bundle-contract.d.ts +1 -0
- package/src/pack/bundle-contract.d.ts.map +1 -1
- package/src/pack/bundle-contract.js +3 -0
- package/src/pack/bundle-contract.js.map +1 -1
- package/src/pack/bundle-contract.ts +3 -0
- package/src/pack/collect-pack-shots.d.ts +16 -5
- package/src/pack/collect-pack-shots.d.ts.map +1 -1
- package/src/pack/collect-pack-shots.js +13 -4
- package/src/pack/collect-pack-shots.js.map +1 -1
- package/src/pack/collect-pack-shots.ts +35 -8
- package/src/pack/generate-embed-entry.d.ts +7 -0
- package/src/pack/generate-embed-entry.d.ts.map +1 -1
- package/src/pack/generate-embed-entry.js +105 -7
- package/src/pack/generate-embed-entry.js.map +1 -1
- package/src/pack/generate-embed-entry.ts +110 -7
- package/src/pack/run-pack.d.ts +8 -2
- package/src/pack/run-pack.d.ts.map +1 -1
- package/src/pack/run-pack.js +120 -17
- package/src/pack/run-pack.js.map +1 -1
- package/src/pack/run-pack.ts +164 -19
- package/src/pack/viewport.d.ts +17 -0
- package/src/pack/viewport.d.ts.map +1 -1
- package/src/pack/viewport.js +19 -0
- package/src/pack/viewport.js.map +1 -1
- package/src/pack/viewport.ts +29 -0
- package/src/presenter/heygen-client.d.ts +69 -0
- package/src/presenter/heygen-client.d.ts.map +1 -0
- package/src/presenter/heygen-client.js +154 -0
- package/src/presenter/heygen-client.js.map +1 -0
- package/src/presenter/heygen-client.ts +224 -0
- package/src/presenter/run-presenter.d.ts +67 -0
- package/src/presenter/run-presenter.d.ts.map +1 -0
- package/src/presenter/run-presenter.js +348 -0
- package/src/presenter/run-presenter.js.map +1 -0
- package/src/presenter/run-presenter.ts +536 -0
- package/src/render/generate-entry.d.ts +4 -0
- package/src/render/generate-entry.d.ts.map +1 -1
- package/src/render/generate-entry.js +75 -7
- package/src/render/generate-entry.js.map +1 -1
- package/src/render/generate-entry.ts +84 -7
- package/src/render/run-render.d.ts +6 -0
- package/src/render/run-render.d.ts.map +1 -1
- package/src/render/run-render.js +58 -0
- package/src/render/run-render.js.map +1 -1
- package/src/render/run-render.ts +72 -0
- package/src/render/stage-assets.d.ts +44 -0
- package/src/render/stage-assets.d.ts.map +1 -0
- package/src/render/stage-assets.js +91 -0
- package/src/render/stage-assets.js.map +1 -0
- package/src/render/stage-assets.ts +130 -0
- package/src/tts/echogarden.d.ts.map +1 -1
- package/src/tts/echogarden.js +4 -2
- package/src/tts/echogarden.js.map +1 -1
- package/src/tts/echogarden.ts +5 -2
- package/src/tts/edge-tts.d.ts.map +1 -1
- package/src/tts/edge-tts.js +2 -1
- package/src/tts/edge-tts.js.map +1 -1
- package/src/tts/edge-tts.ts +2 -1
- package/src/tts/elevenlabs.d.ts +15 -0
- package/src/tts/elevenlabs.d.ts.map +1 -0
- package/src/tts/elevenlabs.js +73 -0
- package/src/tts/elevenlabs.js.map +1 -0
- package/src/tts/elevenlabs.ts +105 -0
- package/src/tts/openai.d.ts.map +1 -1
- package/src/tts/openai.js +2 -1
- package/src/tts/openai.js.map +1 -1
- package/src/tts/openai.ts +2 -1
- package/src/tts/resolve-provider.d.ts +1 -1
- package/src/tts/resolve-provider.d.ts.map +1 -1
- package/src/tts/resolve-provider.js +10 -3
- package/src/tts/resolve-provider.js.map +1 -1
- package/src/tts/resolve-provider.ts +12 -4
- package/src/tts/types.d.ts +9 -0
- package/src/tts/types.d.ts.map +1 -1
- package/src/tts/types.ts +10 -0
- package/src/util/confirm.d.ts +11 -0
- package/src/util/confirm.d.ts.map +1 -0
- package/src/util/confirm.js +24 -0
- package/src/util/confirm.js.map +1 -0
- package/src/util/confirm.ts +23 -0
- package/src/util/load-bundle.d.ts +17 -1
- package/src/util/load-bundle.d.ts.map +1 -1
- package/src/util/load-bundle.js +19 -11
- package/src/util/load-bundle.js.map +1 -1
- package/src/util/load-bundle.ts +38 -12
- package/src/util/load-ts.d.ts +100 -0
- package/src/util/load-ts.d.ts.map +1 -1
- package/src/util/load-ts.js +176 -0
- package/src/util/load-ts.js.map +1 -1
- package/src/util/load-ts.ts +227 -0
- package/src/util/narration-cache.d.ts +13 -5
- package/src/util/narration-cache.d.ts.map +1 -1
- package/src/util/narration-cache.js +10 -8
- package/src/util/narration-cache.js.map +1 -1
- package/src/util/narration-cache.ts +22 -6
- package/src/util/presenter-cache.d.ts +44 -0
- package/src/util/presenter-cache.d.ts.map +1 -0
- package/src/util/presenter-cache.js +43 -0
- package/src/util/presenter-cache.js.map +1 -0
- package/src/util/presenter-cache.ts +101 -0
- package/src/util/scenario-assets.d.ts +47 -0
- package/src/util/scenario-assets.d.ts.map +1 -0
- package/src/util/scenario-assets.js +71 -0
- package/src/util/scenario-assets.js.map +1 -0
- package/src/util/scenario-assets.ts +111 -0
- package/src/util/soundtrack-assets.d.ts +34 -0
- package/src/util/soundtrack-assets.d.ts.map +1 -0
- package/src/util/soundtrack-assets.js +48 -0
- package/src/util/soundtrack-assets.js.map +1 -0
- package/src/util/soundtrack-assets.ts +69 -0
- package/src/validate/scenario-validator.d.ts.map +1 -1
- package/src/validate/scenario-validator.js +82 -0
- package/src/validate/scenario-validator.js.map +1 -1
- package/src/validate/scenario-validator.ts +110 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/example-bundle/assets/index-DlmG1Uh7.js +0 -388
- package/example-bundle/assets/style-BjquDnTE.css +0 -1
|
@@ -15,6 +15,8 @@ export interface EmbedEntryInput {
|
|
|
15
15
|
scenarioId: string;
|
|
16
16
|
/** Whether the scenario has a narration manifest (+ audio). */
|
|
17
17
|
hasNarration: boolean;
|
|
18
|
+
/** Whether the scenario has a presenter manifest (+ clips). */
|
|
19
|
+
hasPresenter: boolean;
|
|
18
20
|
/** Absolute path to .scenar/providers.tsx, or null if none. */
|
|
19
21
|
providersPath: string | null;
|
|
20
22
|
/** Canonical viewport width in px (children render at this width). */
|
|
@@ -50,6 +52,11 @@ export interface EmbedEntryInput {
|
|
|
50
52
|
* selector). The default is light, so existing embeds are unaffected; a host can
|
|
51
53
|
* theme-sync simply by framing `…/?theme=dark`.
|
|
52
54
|
*
|
|
55
|
+
* Captions (`?captions=1`): same frame-time-preference family as `?theme` —
|
|
56
|
+
* enables the player's step captions (narration text as a subtitle overlay,
|
|
57
|
+
* with a CC toggle in the control bar). Absent means off, preserving prior
|
|
58
|
+
* behavior.
|
|
59
|
+
*
|
|
53
60
|
* Capture (`?shot`): with a `shot` query param present, the entry mounts
|
|
54
61
|
* `ScenarioCaptureMount` instead of the playback tree — the TimeSource-driven
|
|
55
62
|
* catch-up mount behind `scenar shoot` (DD-02). The driver installs on
|
|
@@ -84,7 +91,7 @@ export function generateEmbedEntry(input: EmbedEntryInput): string {
|
|
|
84
91
|
// in-app player wires): step tracking, cursor target, ripple/drag flags, and
|
|
85
92
|
// the viewport transform. Without these, the embed would render content but
|
|
86
93
|
// silently drop every cursor move and mid-step interaction.
|
|
87
|
-
lines.push(`import { useCallback, useRef, useState } from "react";`);
|
|
94
|
+
lines.push(`import { useCallback, useMemo, useRef, useState } from "react";`);
|
|
88
95
|
lines.push(`import { createRoot } from "react-dom/client";`);
|
|
89
96
|
const reactImports = [
|
|
90
97
|
"ScenarioPlayer",
|
|
@@ -95,9 +102,11 @@ export function generateEmbedEntry(input: EmbedEntryInput): string {
|
|
|
95
102
|
"ViewportTransformLayer",
|
|
96
103
|
"VIEWPORT_TRANSFORM_IDENTITY",
|
|
97
104
|
"ScenarioCaptureMount",
|
|
105
|
+
"applyTitleCards",
|
|
98
106
|
];
|
|
99
107
|
if (input.stage) reactImports.push("ScenarioStage");
|
|
100
108
|
if (input.hasNarration) reactImports.push("useNarrationManifest");
|
|
109
|
+
if (input.hasPresenter) reactImports.push("usePresenterManifest");
|
|
101
110
|
lines.push(`import { ${reactImports.join(", ")} } from "@scenar/react";`);
|
|
102
111
|
lines.push(`import "@scenar/react/theme.css";`);
|
|
103
112
|
lines.push(`import "@scenar/react/styles.css";`);
|
|
@@ -128,6 +137,54 @@ export function generateEmbedEntry(input: EmbedEntryInput): string {
|
|
|
128
137
|
lines.push(``);
|
|
129
138
|
lines.push(`const _steps: any = _findSteps(_stepsModule as unknown as Record<string, unknown>);`);
|
|
130
139
|
|
|
140
|
+
// --- Soundtrack resolution (mirror of the CLI's findAuthoredSoundtrack) ---
|
|
141
|
+
// Same runtime-discovery contract as _findSteps: read from the very module
|
|
142
|
+
// the bundle bakes in, so the embed can never disagree with the authored
|
|
143
|
+
// config. Pack copies the referenced assets (music, the built-in SFX set)
|
|
144
|
+
// into the bundle; the sources below point at those copies.
|
|
145
|
+
lines.push(``);
|
|
146
|
+
lines.push(`function _findSoundtrack(mod: Record<string, unknown>): any {`);
|
|
147
|
+
lines.push(` for (const val of Object.values(mod)) {`);
|
|
148
|
+
lines.push(` if (`);
|
|
149
|
+
lines.push(` typeof val === "object" && val !== null && !Array.isArray(val) &&`);
|
|
150
|
+
lines.push(` "soundtrack" in val &&`);
|
|
151
|
+
lines.push(` Array.isArray((val as any).steps) && (val as any).steps.length > 0 &&`);
|
|
152
|
+
lines.push(` typeof (val as any).steps[0] === "object" && (val as any).steps[0] !== null &&`);
|
|
153
|
+
lines.push(` "delayMs" in (val as any).steps[0]`);
|
|
154
|
+
lines.push(` ) return (val as any).soundtrack;`);
|
|
155
|
+
lines.push(` }`);
|
|
156
|
+
lines.push(` return (mod as any)["soundtrack"];`);
|
|
157
|
+
lines.push(`}`);
|
|
158
|
+
lines.push(``);
|
|
159
|
+
lines.push(`const _soundtrack: any = _findSoundtrack(_stepsModule as unknown as Record<string, unknown>);`);
|
|
160
|
+
lines.push(``);
|
|
161
|
+
lines.push(`const _soundtrackSources = {`);
|
|
162
|
+
lines.push(` sfx: { click: "./soundtrack/sfx/click.mp3", keystroke: "./soundtrack/sfx/keystroke.mp3" },`);
|
|
163
|
+
lines.push(`};`);
|
|
164
|
+
|
|
165
|
+
// --- Title cards resolution (mirror of the CLI's findAuthoredTitleCards) ---
|
|
166
|
+
// Same runtime-discovery contract as _findSoundtrack. Applied inside
|
|
167
|
+
// _App (the manifest arrives asynchronously and padding must track it);
|
|
168
|
+
// pack copies the referenced logo into the bundle, so the authored
|
|
169
|
+
// relative src resolves against the embed page. Capture mode (?shot)
|
|
170
|
+
// deliberately stays on the AUTHORED steps: shots live on authored
|
|
171
|
+
// steps and cards declare none.
|
|
172
|
+
lines.push(``);
|
|
173
|
+
lines.push(`function _findTitleCards(mod: Record<string, unknown>): any {`);
|
|
174
|
+
lines.push(` for (const val of Object.values(mod)) {`);
|
|
175
|
+
lines.push(` if (`);
|
|
176
|
+
lines.push(` typeof val === "object" && val !== null && !Array.isArray(val) &&`);
|
|
177
|
+
lines.push(` "titleCards" in val &&`);
|
|
178
|
+
lines.push(` Array.isArray((val as any).steps) && (val as any).steps.length > 0 &&`);
|
|
179
|
+
lines.push(` typeof (val as any).steps[0] === "object" && (val as any).steps[0] !== null &&`);
|
|
180
|
+
lines.push(` "delayMs" in (val as any).steps[0]`);
|
|
181
|
+
lines.push(` ) return (val as any).titleCards;`);
|
|
182
|
+
lines.push(` }`);
|
|
183
|
+
lines.push(` return (mod as any)["titleCards"];`);
|
|
184
|
+
lines.push(`}`);
|
|
185
|
+
lines.push(``);
|
|
186
|
+
lines.push(`const _titleCards: any = _findTitleCards(_stepsModule as unknown as Record<string, unknown>);`);
|
|
187
|
+
|
|
131
188
|
// --- Narration manifest URL resolver (stable module-level reference) ---
|
|
132
189
|
// The manifest is fetched at runtime from its own relative location so that
|
|
133
190
|
// useNarrationManifest resolves each clip src against it (audio lives under
|
|
@@ -137,6 +194,14 @@ export function generateEmbedEntry(input: EmbedEntryInput): string {
|
|
|
137
194
|
lines.push(`const _resolveManifestUrl = () => "./narration/manifest.json";`);
|
|
138
195
|
}
|
|
139
196
|
|
|
197
|
+
// --- Presenter manifest URL resolver (same contract as narration) ---
|
|
198
|
+
// The clips live under ./presenter/; usePresenterManifest resolves each
|
|
199
|
+
// clip's relative src against the manifest's own location.
|
|
200
|
+
if (input.hasPresenter) {
|
|
201
|
+
lines.push(``);
|
|
202
|
+
lines.push(`const _resolvePresenterManifestUrl = () => "./presenter/manifest.json";`);
|
|
203
|
+
}
|
|
204
|
+
|
|
140
205
|
// --- Theme: opt-in dark via ?theme=dark (default light; backward-compatible) ---
|
|
141
206
|
// Read once at module load from the embed's own URL. `theme=dark` adds the
|
|
142
207
|
// `dark` class next to SCENAR_CLASS so the `.scenar.dark` tokens apply; any
|
|
@@ -148,6 +213,20 @@ export function generateEmbedEntry(input: EmbedEntryInput): string {
|
|
|
148
213
|
lines.push(`})();`);
|
|
149
214
|
lines.push(`const _rootClass = _theme === "dark" ? SCENAR_CLASS + " dark" : SCENAR_CLASS;`);
|
|
150
215
|
|
|
216
|
+
// --- Captions: opt-in via ?captions=1 (default off; backward-compatible) ---
|
|
217
|
+
// Same family as ?theme: a frame-time presentation preference the host
|
|
218
|
+
// chooses per embed instance (an iframe host writes no JSX, so the player's
|
|
219
|
+
// `captions` prop is reachable only through the URL). Read once at module
|
|
220
|
+
// load; "1" and "true" both enable, anything else (including absent)
|
|
221
|
+
// preserves prior behavior.
|
|
222
|
+
lines.push(``);
|
|
223
|
+
lines.push(`const _captions = (() => {`);
|
|
224
|
+
lines.push(` try {`);
|
|
225
|
+
lines.push(` const v = new URLSearchParams(window.location.search).get("captions");`);
|
|
226
|
+
lines.push(` return v === "1" || v === "true";`);
|
|
227
|
+
lines.push(` } catch { return false; }`);
|
|
228
|
+
lines.push(`})();`);
|
|
229
|
+
|
|
151
230
|
// --- Capture mode: ?shot (bare = driver only; ?shot=<name> = auto-walk) ---
|
|
152
231
|
// Read the same way as _theme: once, at module load, outside React. A null
|
|
153
232
|
// value (param absent) means normal playback; "" (bare ?shot) means capture
|
|
@@ -192,11 +271,15 @@ export function generateEmbedEntry(input: EmbedEntryInput): string {
|
|
|
192
271
|
// `useStepInteractions` reads the current step's `interactions` and drives the
|
|
193
272
|
// cursor / ripple / drag / viewport state, synced to narration duration.
|
|
194
273
|
const manifestExpr = input.hasNarration ? "_manifest" : "undefined";
|
|
274
|
+
const presenterExpr = input.hasPresenter ? "_presenterManifest" : "undefined";
|
|
195
275
|
lines.push(``);
|
|
196
276
|
lines.push(`function _App() {`);
|
|
197
277
|
if (input.hasNarration) {
|
|
198
278
|
lines.push(` const _manifest = useNarrationManifest(${JSON.stringify(input.scenarioId)}, _resolveManifestUrl);`);
|
|
199
279
|
}
|
|
280
|
+
if (input.hasPresenter) {
|
|
281
|
+
lines.push(` const _presenterManifest = usePresenterManifest(${JSON.stringify(input.scenarioId)}, _resolvePresenterManifestUrl);`);
|
|
282
|
+
}
|
|
200
283
|
lines.push(` const _containerRef = useRef<HTMLDivElement>(null);`);
|
|
201
284
|
lines.push(` const _cameraRef = useRef<HTMLDivElement>(null);`);
|
|
202
285
|
lines.push(` const [_stepIndex, _setStepIndex] = useState(0);`);
|
|
@@ -207,27 +290,44 @@ export function generateEmbedEntry(input: EmbedEntryInput): string {
|
|
|
207
290
|
lines.push(``);
|
|
208
291
|
// Reset the cursor when the step changes so a prior step's target never
|
|
209
292
|
// lingers; the new step's interactions re-set it at their scheduled time.
|
|
210
|
-
|
|
293
|
+
// One handler feeds both step-change callbacks: authored steps deliver
|
|
294
|
+
// data, card steps deliver the card — the wiring needs only the index,
|
|
295
|
+
// and it must track BOTH so card-step interactions (the outro's
|
|
296
|
+
// cursor-clear and viewport-reset housekeeping) reach the scheduler.
|
|
297
|
+
lines.push(` const _handleStepChange = useCallback((_dataOrCard: any, index: number) => {`);
|
|
211
298
|
lines.push(` _setStepIndex(index);`);
|
|
212
299
|
lines.push(` _setCursorTarget(undefined);`);
|
|
213
300
|
lines.push(` }, []);`);
|
|
214
301
|
lines.push(``);
|
|
302
|
+
// Card synthesis: bundle assembly is THE one expansion point. Memoized
|
|
303
|
+
// on the manifests (the only async inputs) so the steps identity stays
|
|
304
|
+
// stable across renders and the interaction scheduler is not re-armed.
|
|
305
|
+
const appliedDeps = [manifestExpr, presenterExpr]
|
|
306
|
+
.filter((expr) => expr !== "undefined")
|
|
307
|
+
.join(", ");
|
|
308
|
+
lines.push(` const _applied = useMemo(`);
|
|
309
|
+
lines.push(` () => applyTitleCards(_steps as any, ${manifestExpr}, _titleCards, ${presenterExpr}),`);
|
|
310
|
+
lines.push(` [${appliedDeps}],`);
|
|
311
|
+
lines.push(` );`);
|
|
312
|
+
lines.push(``);
|
|
215
313
|
lines.push(` useStepInteractions({`);
|
|
216
314
|
lines.push(` stepIndex: _stepIndex,`);
|
|
217
|
-
lines.push(` narrationManifest:
|
|
315
|
+
lines.push(` narrationManifest: _applied.narrationManifest,`);
|
|
218
316
|
lines.push(` containerRef: _containerRef,`);
|
|
219
317
|
lines.push(` cameraRef: _cameraRef,`);
|
|
220
318
|
lines.push(` setCursorTarget: _setCursorTarget,`);
|
|
221
319
|
lines.push(` setShowRipple: _setShowRipple,`);
|
|
222
320
|
lines.push(` setDragging: _setDragging,`);
|
|
223
321
|
lines.push(` setViewportTransform: _setViewport,`);
|
|
224
|
-
lines.push(` steps:
|
|
322
|
+
lines.push(` steps: _applied.steps,`);
|
|
225
323
|
lines.push(` });`);
|
|
226
324
|
lines.push(``);
|
|
227
325
|
lines.push(` const _bundle = {`);
|
|
228
326
|
lines.push(` id: ${JSON.stringify(input.scenarioId)},`);
|
|
229
|
-
lines.push(` steps:
|
|
230
|
-
lines.push(` narrationManifest:
|
|
327
|
+
lines.push(` steps: _applied.steps as any,`);
|
|
328
|
+
lines.push(` narrationManifest: _applied.narrationManifest,`);
|
|
329
|
+
lines.push(` soundtrack: _soundtrack,`);
|
|
330
|
+
lines.push(` presenterManifest: _applied.presenterManifest,`);
|
|
231
331
|
lines.push(` };`);
|
|
232
332
|
const open = input.providersPath ? `<_Providers>` : ``;
|
|
233
333
|
const close = input.providersPath ? `</_Providers>` : ``;
|
|
@@ -242,7 +342,10 @@ export function generateEmbedEntry(input: EmbedEntryInput): string {
|
|
|
242
342
|
: `{(data: any, stepIndex: number) => renderStep(data, stepIndex)}`;
|
|
243
343
|
lines.push(` <DemoViewport containerRef={_containerRef} canonicalWidth={${input.canonicalWidth}} shellHeight={${input.shellHeight}}>`);
|
|
244
344
|
lines.push(` <ViewportTransformLayer transform={_viewport} contentRef={_cameraRef}>`);
|
|
245
|
-
|
|
345
|
+
// embedViewport mirrors DemoViewport's numbers on purpose: the bundle
|
|
346
|
+
// announces the exact canonical size it lays out at, so a host can adopt
|
|
347
|
+
// iframe-as-screen scaling (see @scenar/embed's mount).
|
|
348
|
+
lines.push(` <ScenarioPlayer bundle={_bundle} embed embedViewport={{ widthPx: ${input.canonicalWidth}, heightPx: ${input.shellHeight} }} captions={_captions} soundtrackSources={_soundtrackSources} onStepChange={_handleStepChange} onCardStepChange={_handleStepChange}>`);
|
|
246
349
|
lines.push(` ${stepRender}`);
|
|
247
350
|
lines.push(` </ScenarioPlayer>`);
|
|
248
351
|
lines.push(` <Cursor target={_cursorTarget} containerRef={_cameraRef} showRipple={_showRipple} isDragging={_dragging} />`);
|
package/src/pack/run-pack.d.ts
CHANGED
|
@@ -5,9 +5,14 @@ export interface RunPackOptions {
|
|
|
5
5
|
readonly scenarioDir: string;
|
|
6
6
|
/** Output directory for the bundle (default: ./<scenario-id>-bundle). */
|
|
7
7
|
readonly outDir?: string;
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Canonical viewport width in px. Omitted -> the scenario's own authored
|
|
10
|
+
* viewport (`createScenario({ viewport })` or an exported `viewport`
|
|
11
|
+
* constant) applies; a scenario that authors none falls back to
|
|
12
|
+
* {@link DEFAULT_VIEWPORT}. Explicit flags always win over both.
|
|
13
|
+
*/
|
|
9
14
|
readonly width?: number;
|
|
10
|
-
/** Shell/container height in px
|
|
15
|
+
/** Shell/container height in px. Same resolution chain as `width`. */
|
|
11
16
|
readonly shellHeight?: number;
|
|
12
17
|
/**
|
|
13
18
|
* Float the scenario on a backdrop with a window shadow (screen-recording
|
|
@@ -27,6 +32,7 @@ export interface PackResult {
|
|
|
27
32
|
readonly renderFilePath: string;
|
|
28
33
|
readonly providersPath: string | null;
|
|
29
34
|
readonly hasNarration: boolean;
|
|
35
|
+
readonly hasPresenter: boolean;
|
|
30
36
|
/**
|
|
31
37
|
* The declared shot names recorded in scenario.json (empty = the scenario
|
|
32
38
|
* authoritatively declares none), or undefined when the steps module could
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-pack.d.ts","sourceRoot":"","sources":["../../../src/pack/run-pack.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-pack.d.ts","sourceRoot":"","sources":["../../../src/pack/run-pack.ts"],"names":[],"mappings":"AAeA,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAS5B,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,gDAAgD;IAChD,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C;AAED,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CA8K1E"}
|
package/src/pack/run-pack.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { resolve, join, basename } from "node:path";
|
|
1
|
+
import { resolve, join, basename, dirname } from "node:path";
|
|
2
2
|
import { stat, mkdir, writeFile, rm, readdir, copyFile, access } from "node:fs/promises";
|
|
3
3
|
import { detectRenderExport } from "../render/detect-render-export.js";
|
|
4
4
|
import { resolveProvidersPath } from "../render/resolve-providers.js";
|
|
5
|
+
import { SFX_DEST_PATHS, resolveMusicAsset, resolveSfxAssetPaths, } from "../util/soundtrack-assets.js";
|
|
6
|
+
import { resolveLogoAsset } from "../util/scenario-assets.js";
|
|
5
7
|
import { generateEmbedEntry, generateEmbedHtml } from "./generate-embed-entry.js";
|
|
6
8
|
import { collectPackShots } from "./collect-pack-shots.js";
|
|
7
9
|
import { runViteBuild } from "./build.js";
|
|
8
10
|
import { copyEmbedLoader } from "./embed-loader.js";
|
|
9
11
|
import { buildPackManifest, writePackManifest, writeScenarioJson, verifyManifestFilesExist, } from "./pack-manifest.js";
|
|
10
|
-
import {
|
|
12
|
+
import { resolvePackViewport } from "./viewport.js";
|
|
11
13
|
/**
|
|
12
14
|
* Generator version stamped into scenario.json (kept in sync with the CLI).
|
|
13
15
|
* 0.0.2: scenario.json may carry `shots` (declared shot names, in step order).
|
|
@@ -32,8 +34,6 @@ export async function runPack(options) {
|
|
|
32
34
|
}
|
|
33
35
|
const scenarioId = basename(scenarioDir);
|
|
34
36
|
const outDir = options.outDir ? resolve(options.outDir) : resolve(`./${scenarioId}-bundle`);
|
|
35
|
-
const width = options.width ?? DEFAULT_VIEWPORT.width;
|
|
36
|
-
const shellHeight = options.shellHeight ?? DEFAULT_VIEWPORT.height;
|
|
37
37
|
// The entry must live inside the scenario directory so the bundler's
|
|
38
38
|
// node_modules resolution walks up into the consumer project.
|
|
39
39
|
const tempDir = join(scenarioDir, ".scenar-pack");
|
|
@@ -41,18 +41,34 @@ export async function runPack(options) {
|
|
|
41
41
|
const renderFilePath = await detectRenderExport(scenarioDir);
|
|
42
42
|
const providersPath = await resolveProvidersPath(scenarioDir);
|
|
43
43
|
const hasNarration = await fileExists(join(scenarioDir, "narration", "manifest.json"));
|
|
44
|
+
const hasPresenter = await fileExists(join(scenarioDir, "presenter", "manifest.json"));
|
|
44
45
|
onLog(`Scenario: ${scenarioId}`);
|
|
45
46
|
onLog(`Render: ${renderFilePath}`);
|
|
46
47
|
onLog(`Providers: ${providersPath ?? "none"}`);
|
|
47
48
|
onLog(`Narration: ${hasNarration ? "yes (manifest found)" : "none"}`);
|
|
49
|
+
onLog(`Presenter: ${hasPresenter ? "yes (manifest found)" : "none"}`);
|
|
48
50
|
onLog(`Output: ${outDir}`);
|
|
49
|
-
// 1. Discover the declared shots
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
51
|
+
// 1. Discover the declared shots — and the authored viewport — by
|
|
52
|
+
// SSR-loading the steps module (same Vite resolution as the build
|
|
53
|
+
// below). Before the build on purpose: authoring errors — bad shot
|
|
54
|
+
// names, no steps array — fail fast here, without paying for a
|
|
55
|
+
// bundle. An import failure is tolerated: the shots are then unknown
|
|
56
|
+
// and scenario.json omits the key.
|
|
54
57
|
const collectedShots = await collectPackShots(scenarioDir);
|
|
55
58
|
onLog(`Shots: ${describeCollectedShots(collectedShots)}`);
|
|
59
|
+
// Canonical viewport: explicit options > the scenario's authored
|
|
60
|
+
// viewport > the packer default. Authored viewports used to be silently
|
|
61
|
+
// ignored (the authoring docs demonstrated `createScenario({ viewport })`
|
|
62
|
+
// while pack only ever read its own options); the source is logged so a
|
|
63
|
+
// surprising size is one log line from its explanation.
|
|
64
|
+
const resolvedViewport = resolvePackViewport(options, collectedShots.recorded ? collectedShots.authoredViewport : null);
|
|
65
|
+
const { width, height: shellHeight } = resolvedViewport;
|
|
66
|
+
const viewportSourceLabel = {
|
|
67
|
+
explicit: "explicit",
|
|
68
|
+
authored: "authored by the scenario",
|
|
69
|
+
default: "packer default",
|
|
70
|
+
}[resolvedViewport.source];
|
|
71
|
+
onLog(`Viewport: ${width}x${shellHeight} (${viewportSourceLabel})`);
|
|
56
72
|
// 2. Generate the browser entry + index.html into the temp dir.
|
|
57
73
|
const stage = options.stage ?? false;
|
|
58
74
|
const entrySource = generateEmbedEntry({
|
|
@@ -60,6 +76,7 @@ export async function runPack(options) {
|
|
|
60
76
|
renderFilePath,
|
|
61
77
|
scenarioId,
|
|
62
78
|
hasNarration,
|
|
79
|
+
hasPresenter,
|
|
63
80
|
providersPath,
|
|
64
81
|
canonicalWidth: width,
|
|
65
82
|
shellHeight,
|
|
@@ -77,7 +94,39 @@ export async function runPack(options) {
|
|
|
77
94
|
// ./narration/manifest.json at runtime and resolves each clip's
|
|
78
95
|
// relative src against it, so both must ship in the bundle.
|
|
79
96
|
if (hasNarration) {
|
|
80
|
-
await
|
|
97
|
+
await copyClipTrack(scenarioDir, outDir, "narration", ".mp3");
|
|
98
|
+
}
|
|
99
|
+
// 4a. Copy the presenter manifest + clips — the same runtime contract
|
|
100
|
+
// as narration: the embed fetches ./presenter/manifest.json and
|
|
101
|
+
// resolves each clip's relative src against it. CSP is
|
|
102
|
+
// `media-src 'self'`, so the clips must ship in the bundle.
|
|
103
|
+
if (hasPresenter) {
|
|
104
|
+
await copyClipTrack(scenarioDir, outDir, "presenter", ".mp4");
|
|
105
|
+
}
|
|
106
|
+
// 4b. Copy the soundtrack's assets: the authored music file (at its
|
|
107
|
+
// scenario-relative path, which is what the embed references) and
|
|
108
|
+
// the built-in SFX set from @scenar/react. Discovery rides the same
|
|
109
|
+
// SSR load as the shots; when the module was not loadable, the
|
|
110
|
+
// soundtrack (if any) cannot ship — warn rather than silently
|
|
111
|
+
// packing an embed whose audio 404s.
|
|
112
|
+
if (collectedShots.recorded) {
|
|
113
|
+
if (collectedShots.authoredSoundtrack) {
|
|
114
|
+
const copied = await copySoundtrack(scenarioDir, outDir, collectedShots.authoredSoundtrack);
|
|
115
|
+
if (copied > 0)
|
|
116
|
+
onLog(`Soundtrack: ${copied} audio file(s) copied into the bundle`);
|
|
117
|
+
}
|
|
118
|
+
// 4c. Copy title-card logos at their scenario-relative paths (the
|
|
119
|
+
// card component references them by that same path). Discovery
|
|
120
|
+
// rides the same SSR load as the shots and the soundtrack.
|
|
121
|
+
if (collectedShots.authoredTitleCards) {
|
|
122
|
+
const copied = await copyTitleCardLogos(scenarioDir, outDir, collectedShots.authoredTitleCards);
|
|
123
|
+
if (copied > 0)
|
|
124
|
+
onLog(`Cards: ${copied} logo file(s) copied into the bundle`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
onLog("Warning: steps module not loadable under Node — if this scenario authors a " +
|
|
129
|
+
"soundtrack or title cards, their asset files were NOT copied into the bundle.");
|
|
81
130
|
}
|
|
82
131
|
// 5. Write the required scenario.json descriptor, recording the canonical
|
|
83
132
|
// viewport baked into the bundle so `deploy`/`serve`/`publish` can derive
|
|
@@ -102,6 +151,7 @@ export async function runPack(options) {
|
|
|
102
151
|
renderFilePath,
|
|
103
152
|
providersPath,
|
|
104
153
|
hasNarration,
|
|
154
|
+
hasPresenter,
|
|
105
155
|
shots: collectedShots.recorded ? collectedShots.shots : undefined,
|
|
106
156
|
manifest,
|
|
107
157
|
totalBytes,
|
|
@@ -114,24 +164,77 @@ export async function runPack(options) {
|
|
|
114
164
|
}
|
|
115
165
|
}
|
|
116
166
|
/**
|
|
117
|
-
* Copy
|
|
118
|
-
*
|
|
119
|
-
*
|
|
167
|
+
* Copy one clip track's manifest and media (narration mp3s, presenter
|
|
168
|
+
* mp4s) from <scenarioDir>/<trackDir> into <outDir>/<trackDir>. The
|
|
169
|
+
* manifest is the runtime index the embed fetches; the clips are what it
|
|
170
|
+
* references by relative src. Cache files never ship.
|
|
120
171
|
*/
|
|
121
|
-
async function
|
|
122
|
-
const srcDir = join(scenarioDir,
|
|
123
|
-
const destDir = join(outDir,
|
|
172
|
+
async function copyClipTrack(scenarioDir, outDir, trackDir, extension) {
|
|
173
|
+
const srcDir = join(scenarioDir, trackDir);
|
|
174
|
+
const destDir = join(outDir, trackDir);
|
|
124
175
|
await mkdir(destDir, { recursive: true });
|
|
125
176
|
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
126
177
|
for (const entry of entries) {
|
|
127
178
|
if (!entry.isFile())
|
|
128
179
|
continue;
|
|
129
180
|
const name = entry.name.toLowerCase();
|
|
130
|
-
if (name === "manifest.json" || name.endsWith(
|
|
181
|
+
if (name === "manifest.json" || name.endsWith(extension)) {
|
|
131
182
|
await copyFile(join(srcDir, entry.name), join(destDir, entry.name));
|
|
132
183
|
}
|
|
133
184
|
}
|
|
134
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Copy the soundtrack's audio into the bundle: the authored music file at
|
|
188
|
+
* its scenario-relative path (the embed references it by that same path),
|
|
189
|
+
* and the built-in SFX set from @scenar/react at the shared
|
|
190
|
+
* {@link SFX_DEST_PATHS} locations the generated entry points at. Returns
|
|
191
|
+
* the number of files copied. Remote music URLs copy nothing.
|
|
192
|
+
*/
|
|
193
|
+
async function copySoundtrack(scenarioDir, outDir, soundtrack) {
|
|
194
|
+
let copied = 0;
|
|
195
|
+
if (soundtrack.musicSrc) {
|
|
196
|
+
const music = await resolveMusicAsset(scenarioDir, soundtrack.musicSrc);
|
|
197
|
+
if (music) {
|
|
198
|
+
const dest = join(outDir, music.destRelPath);
|
|
199
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
200
|
+
await copyFile(music.sourcePath, dest);
|
|
201
|
+
copied += 1;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (soundtrack.sfx) {
|
|
205
|
+
const sfxPaths = resolveSfxAssetPaths(scenarioDir);
|
|
206
|
+
for (const sound of ["click", "keystroke"]) {
|
|
207
|
+
const dest = join(outDir, SFX_DEST_PATHS[sound]);
|
|
208
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
209
|
+
await copyFile(sfxPaths[sound], dest);
|
|
210
|
+
copied += 1;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return copied;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Copy title-card logos into the bundle at their scenario-relative paths.
|
|
217
|
+
* A logo shared by intro and outro copies once; remote URLs copy nothing.
|
|
218
|
+
* Returns the number of files copied.
|
|
219
|
+
*/
|
|
220
|
+
async function copyTitleCardLogos(scenarioDir, outDir, titleCards) {
|
|
221
|
+
let copied = 0;
|
|
222
|
+
const copiedPaths = new Set();
|
|
223
|
+
for (const side of ["intro", "outro"]) {
|
|
224
|
+
const logoSrc = titleCards[side]?.logoSrc;
|
|
225
|
+
if (!logoSrc)
|
|
226
|
+
continue;
|
|
227
|
+
const logo = await resolveLogoAsset(scenarioDir, logoSrc, `titleCards.${side}.logoSrc`);
|
|
228
|
+
if (!logo || copiedPaths.has(logo.destRelPath))
|
|
229
|
+
continue;
|
|
230
|
+
const dest = join(outDir, logo.destRelPath);
|
|
231
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
232
|
+
await copyFile(logo.sourcePath, dest);
|
|
233
|
+
copiedPaths.add(logo.destRelPath);
|
|
234
|
+
copied += 1;
|
|
235
|
+
}
|
|
236
|
+
return copied;
|
|
237
|
+
}
|
|
135
238
|
/** One log-friendly line for the shot discovery outcome. */
|
|
136
239
|
function describeCollectedShots(collected) {
|
|
137
240
|
if (!collected.recorded) {
|
package/src/pack/run-pack.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-pack.js","sourceRoot":"","sources":["../../../src/pack/run-pack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"run-pack.js","sourceRoot":"","sources":["../../../src/pack/run-pack.ts"],"names":[],"mappings":"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"}
|