@velumo/cli 0.1.0-beta.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.
Files changed (38) hide show
  1. package/dist/browser-overview.d.ts +72 -0
  2. package/dist/browser-overview.d.ts.map +1 -0
  3. package/dist/browser-overview.js +431 -0
  4. package/dist/browser-overview.js.map +1 -0
  5. package/dist/browser-presenter.d.ts +63 -0
  6. package/dist/browser-presenter.d.ts.map +1 -0
  7. package/dist/browser-presenter.js +304 -0
  8. package/dist/browser-presenter.js.map +1 -0
  9. package/dist/browser-runtime.d.ts +43 -0
  10. package/dist/browser-runtime.d.ts.map +1 -0
  11. package/dist/browser-runtime.js +293 -0
  12. package/dist/browser-runtime.js.map +1 -0
  13. package/dist/browser-spatial.d.ts +42 -0
  14. package/dist/browser-spatial.d.ts.map +1 -0
  15. package/dist/browser-spatial.js +207 -0
  16. package/dist/browser-spatial.js.map +1 -0
  17. package/dist/browser-sync.d.ts +37 -0
  18. package/dist/browser-sync.d.ts.map +1 -0
  19. package/dist/browser-sync.js +77 -0
  20. package/dist/browser-sync.js.map +1 -0
  21. package/dist/browser-timer.d.ts +9 -0
  22. package/dist/browser-timer.d.ts.map +1 -0
  23. package/dist/browser-timer.js +13 -0
  24. package/dist/browser-timer.js.map +1 -0
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +902 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/tsconfig.tsbuildinfo +1 -0
  30. package/package.json +42 -0
  31. package/src/browser-overview.ts +641 -0
  32. package/src/browser-presenter.ts +602 -0
  33. package/src/browser-runtime.ts +493 -0
  34. package/src/browser-spatial.ts +292 -0
  35. package/src/browser-sync.ts +151 -0
  36. package/src/browser-timer.ts +24 -0
  37. package/src/index.ts +1273 -0
  38. package/tsconfig.json +16 -0
@@ -0,0 +1,304 @@
1
+ import { createSpeakerNotesModel, RuntimeController, } from "@velumo/runtime";
2
+ import { DomRenderer } from "@velumo/renderer-dom";
3
+ import { createPresenterSync, } from "./browser-sync.js";
4
+ import { createPresenterTimer } from "./browser-timer.js";
5
+ export async function mountVelumoPresenterView(options) {
6
+ if (options.root === null || options.root === undefined) {
7
+ throw new Error("Velumo presenter root element not found");
8
+ }
9
+ const root = options.root;
10
+ try {
11
+ const response = (await fetch(options.manifestUrl));
12
+ if (!response.ok) {
13
+ throw new Error(`manifest request failed with status ${response.status}`);
14
+ }
15
+ const manifest = await response.json();
16
+ const timer = options.timer ?? createPresenterTimer();
17
+ const notes = createSpeakerNotesModel(manifest);
18
+ let state = options.initialState ?? new RuntimeController(manifest).getState();
19
+ let sync;
20
+ let commandPublisher;
21
+ let currentHandles = [];
22
+ function render() {
23
+ for (const h of currentHandles)
24
+ h.dispose();
25
+ currentHandles = [];
26
+ renderPresenter(root, {
27
+ commandPublisher,
28
+ manifest,
29
+ notes,
30
+ state,
31
+ statusText: sync === undefined ? "Local disconnected" : "Connected",
32
+ timer,
33
+ mountThumbnail: options.mountThumbnail,
34
+ handles: currentHandles,
35
+ });
36
+ }
37
+ // The clock ticks every second, but the elapsed time is the only thing
38
+ // that changes between ticks. Refresh just that text node in place rather
39
+ // than calling render(): a full render() rebuilds the whole tree, including
40
+ // the two slide-preview DomRenderers, which restarts their one-shot entry
41
+ // animations every second (and leaks a renderer per tick). Full render()
42
+ // stays driven by mount and state changes (navigation/sync), where a single
43
+ // preview rebuild — and one entry-animation replay — is correct.
44
+ function updateTimerDisplay() {
45
+ const display = root.querySelector("[data-velumo-presenter-timer]");
46
+ if (display !== null) {
47
+ display.textContent = `Elapsed ${formatElapsed(timer.elapsedMs())}`;
48
+ }
49
+ }
50
+ const connection = createPresenterSyncConnection(options.sync, (nextState) => {
51
+ state = nextState;
52
+ render();
53
+ });
54
+ sync = connection.sync;
55
+ commandPublisher = connection.commandPublisher;
56
+ render();
57
+ const stopTimerUpdates = startTimerUpdates(options, updateTimerDisplay);
58
+ return {
59
+ dispose() {
60
+ stopTimerUpdates?.();
61
+ sync?.dispose();
62
+ for (const h of currentHandles)
63
+ h.dispose();
64
+ currentHandles = [];
65
+ },
66
+ manifest,
67
+ sync,
68
+ timer,
69
+ };
70
+ }
71
+ catch (error) {
72
+ renderPresenterError(root, error);
73
+ return undefined;
74
+ }
75
+ }
76
+ function renderPresenter(root, options) {
77
+ root.setAttribute("data-velumo-presenter", "mounted");
78
+ root.replaceChildren(presenterHeader(root.ownerDocument, options), presenterSlidePanel(root, options), presenterNotesPanel(root.ownerDocument, options), presenterControls(root.ownerDocument, options));
79
+ }
80
+ function presenterHeader(document, options) {
81
+ const header = createElement(document, "header");
82
+ header.setAttribute("data-velumo-presenter-header", "true");
83
+ const title = textElement(document, "h1", "Presenter View");
84
+ const deck = textElement(document, "p", options.manifest.deck.title);
85
+ const status = textElement(document, "p", options.statusText);
86
+ const timer = textElement(document, "p", `Elapsed ${formatElapsed(options.timer.elapsedMs())}`);
87
+ timer.setAttribute("data-velumo-presenter-timer", "true");
88
+ header.append(title, deck, status, timer);
89
+ return header;
90
+ }
91
+ function presenterSlidePanel(root, options) {
92
+ const panel = createElement(root.ownerDocument, "section");
93
+ panel.setAttribute("data-velumo-presenter-slides", "true");
94
+ panel.append(previewSection(root, "Current", options.manifest, options.state.slideId, {
95
+ "data-velumo-presenter-current": "true",
96
+ }, options.mountThumbnail, options.handles), nextPreviewSection(root, options));
97
+ return panel;
98
+ }
99
+ function nextPreviewSection(root, options) {
100
+ const nextSlide = options.manifest.slides[options.state.slideIndex + 1];
101
+ if (nextSlide === undefined) {
102
+ const section = createElement(root.ownerDocument, "section");
103
+ section.setAttribute("data-velumo-presenter-next", "true");
104
+ section.append(textElement(root.ownerDocument, "h2", "Next"));
105
+ section.append(textElement(root.ownerDocument, "p", "No next slide"));
106
+ return section;
107
+ }
108
+ return previewSection(root, "Next", options.manifest, nextSlide.id, {
109
+ "data-velumo-presenter-next": "true",
110
+ }, options.mountThumbnail, options.handles);
111
+ }
112
+ function previewSection(root, label, manifest, slideId, attributes, mountThumbnail, handles) {
113
+ const section = createElement(root.ownerDocument, "section");
114
+ for (const [name, value] of Object.entries(attributes)) {
115
+ section.setAttribute(name, value);
116
+ }
117
+ section.append(textElement(root.ownerDocument, "h2", label));
118
+ const slide = slideById(manifest, slideId);
119
+ if (slide !== undefined) {
120
+ section.append(textElement(root.ownerDocument, "p", slideSummary(slide)));
121
+ }
122
+ const previewRoot = createElement(root.ownerDocument, "div");
123
+ previewRoot.setAttribute("data-velumo-presenter-preview", "true");
124
+ if (mountThumbnail !== undefined) {
125
+ const handle = mountThumbnail({ root: previewRoot, manifest, slideId });
126
+ handles?.push(handle);
127
+ }
128
+ else {
129
+ new DomRenderer({
130
+ root: previewRoot,
131
+ manifest,
132
+ runtime: new RuntimeController(manifest, { initialSlideId: slideId }),
133
+ }).mount();
134
+ }
135
+ section.append(previewRoot);
136
+ return section;
137
+ }
138
+ function presenterNotesPanel(document, options) {
139
+ const section = createElement(document, "section");
140
+ section.setAttribute("data-velumo-presenter-notes", "true");
141
+ section.append(textElement(document, "h2", "Notes"));
142
+ const entry = options.notes.getForState(options.state);
143
+ if (!entry.hasNotes) {
144
+ section.append(textElement(document, "p", "No notes"));
145
+ return section;
146
+ }
147
+ for (const block of entry.blocks) {
148
+ section.append(renderNoteBlock(document, block));
149
+ }
150
+ return section;
151
+ }
152
+ function renderNoteBlock(document, block) {
153
+ switch (block.type) {
154
+ case "heading":
155
+ return textElement(document, `h${block.level + 1}`, block.text);
156
+ case "list": {
157
+ const list = createElement(document, "ul");
158
+ for (const item of block.items) {
159
+ list.append(textElement(document, "li", item));
160
+ }
161
+ return list;
162
+ }
163
+ case "code":
164
+ return textElement(document, "pre", block.text);
165
+ case "paragraph":
166
+ return textElement(document, "p", block.text);
167
+ }
168
+ }
169
+ function presenterControls(document, options) {
170
+ const section = createElement(document, "section");
171
+ section.setAttribute("data-velumo-presenter-controls", "true");
172
+ section.append(commandButton(document, "Previous", "data-velumo-presenter-previous-button", "previous", options), commandButton(document, "Next", "data-velumo-presenter-next-button", "next", options), commandButton(document, "Reset timer", "data-velumo-presenter-reset-button", "resetTimer", options));
173
+ return section;
174
+ }
175
+ function commandButton(document, label, attributeName, command, options) {
176
+ const button = createElement(document, "button");
177
+ button.setAttribute(attributeName, "true");
178
+ button.textContent = label;
179
+ button.addEventListener?.("click", () => {
180
+ if (command === "resetTimer") {
181
+ options.timer.reset();
182
+ }
183
+ options.commandPublisher?.publishCommand(command);
184
+ });
185
+ return button;
186
+ }
187
+ function renderPresenterError(root, error) {
188
+ const section = createElement(root.ownerDocument, "section");
189
+ section.setAttribute("data-velumo-presenter-error", "mount");
190
+ section.append(textElement(root.ownerDocument, "h1", "Presenter mount error"));
191
+ section.append(textElement(root.ownerDocument, "p", error instanceof Error ? error.message : "Unknown presenter error"));
192
+ root.replaceChildren(section);
193
+ }
194
+ function slideById(manifest, slideId) {
195
+ return manifest.slides.find((slide) => slide.id === slideId);
196
+ }
197
+ function slideSummary(slide) {
198
+ const contentLayer = slide.layers?.find((layer) => typeof layer.content === "string");
199
+ const content = typeof contentLayer?.content === "string" ? contentLayer.content : slide.id;
200
+ const firstLine = content
201
+ .split(/\n/)
202
+ .map((line) => line.replace(/^#+\s*/, "").trim())
203
+ .find((line) => line.length > 0);
204
+ return firstLine ?? slide.id;
205
+ }
206
+ function textElement(document, tagName, text) {
207
+ const element = createElement(document, tagName);
208
+ element.textContent = text;
209
+ return element;
210
+ }
211
+ function createElement(document, tagName) {
212
+ return document.createElement(tagName);
213
+ }
214
+ function formatElapsed(elapsedMs) {
215
+ const totalSeconds = Math.floor(elapsedMs / 1000);
216
+ const minutes = Math.floor(totalSeconds / 60);
217
+ const seconds = totalSeconds % 60;
218
+ return `${minutes}:${seconds.toString().padStart(2, "0")}`;
219
+ }
220
+ function isCommandPublisher(sync) {
221
+ return (sync !== false &&
222
+ sync !== undefined &&
223
+ "publishCommand" in sync &&
224
+ typeof sync.publishCommand === "function");
225
+ }
226
+ function isInjectedSync(sync) {
227
+ return (sync !== false &&
228
+ sync !== undefined &&
229
+ "channel" in sync &&
230
+ "instanceId" in sync);
231
+ }
232
+ function createPresenterSyncConnection(syncOption, onState) {
233
+ if (syncOption === false) {
234
+ return {};
235
+ }
236
+ if (isInjectedSync(syncOption)) {
237
+ return connectPresenterSync(syncOption, onState);
238
+ }
239
+ if (isCommandPublisher(syncOption)) {
240
+ return { commandPublisher: syncOption };
241
+ }
242
+ const injectedSync = createDefaultSync();
243
+ if (injectedSync === undefined) {
244
+ return {};
245
+ }
246
+ return connectPresenterSync(injectedSync, onState);
247
+ }
248
+ function connectPresenterSync(injectedSync, onState) {
249
+ const sync = createPresenterSync({
250
+ channel: injectedSync.channel,
251
+ instanceId: injectedSync.instanceId,
252
+ role: "presenter",
253
+ onState,
254
+ });
255
+ return { commandPublisher: sync, sync };
256
+ }
257
+ function startTimerUpdates(options, onTick) {
258
+ const scheduler = options.timerScheduler ?? defaultTimerScheduler();
259
+ if (scheduler === undefined) {
260
+ return undefined;
261
+ }
262
+ const intervalId = scheduler.setInterval(onTick, options.timerIntervalMs ?? 1000);
263
+ intervalId.unref?.();
264
+ return () => scheduler.clearInterval?.(intervalId);
265
+ }
266
+ function defaultTimerScheduler() {
267
+ const setIntervalRef = globalThis.setInterval;
268
+ const clearIntervalRef = globalThis.clearInterval;
269
+ if (setIntervalRef === undefined || clearIntervalRef === undefined) {
270
+ return undefined;
271
+ }
272
+ return {
273
+ setInterval(handler, ms) {
274
+ return setIntervalRef(handler, ms);
275
+ },
276
+ clearInterval(id) {
277
+ clearIntervalRef(id);
278
+ },
279
+ };
280
+ }
281
+ function createDefaultSync() {
282
+ const channel = createDefaultChannel();
283
+ return channel === undefined
284
+ ? undefined
285
+ : {
286
+ channel,
287
+ instanceId: createInstanceId(),
288
+ };
289
+ }
290
+ function createDefaultChannel() {
291
+ const BroadcastChannelCtor = globalThis
292
+ .BroadcastChannel;
293
+ if (BroadcastChannelCtor === undefined) {
294
+ return undefined;
295
+ }
296
+ const channel = new BroadcastChannelCtor("velumo-presenter");
297
+ channel.unref?.();
298
+ return channel;
299
+ }
300
+ function createInstanceId() {
301
+ return (globalThis.crypto?.randomUUID?.() ??
302
+ `presenter-${Math.random().toString(36).slice(2)}`);
303
+ }
304
+ //# sourceMappingURL=browser-presenter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-presenter.js","sourceRoot":"","sources":["../src/browser-presenter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { RuntimeController, type VelumoPlugin, type RuntimeControllerOptions, type RuntimeRegistry } from "@velumo/runtime";
2
+ import { DomRenderer, type DomRendererOptions } from "@velumo/renderer-dom";
3
+ import type { Manifest } from "@velumo/core";
4
+ import { type PresenterSyncChannel } from "./browser-sync.js";
5
+ type BrowserRoot = DomRendererOptions["root"];
6
+ type BrowserRenderer = Pick<DomRenderer, "mount"> & Partial<Pick<DomRenderer, "render" | "getRoot">>;
7
+ type RuntimeFactory = (manifest: Manifest, options?: RuntimeControllerOptions) => RuntimeController;
8
+ type RendererFactory = (options: DomRendererOptions) => BrowserRenderer;
9
+ interface BrowserKeyboardEvent {
10
+ readonly key: string;
11
+ readonly target: unknown;
12
+ preventDefault(): void;
13
+ }
14
+ interface BrowserWindowLike {
15
+ readonly BroadcastChannel?: new (name: string) => PresenterSyncChannel;
16
+ readonly crypto?: {
17
+ randomUUID?(): string;
18
+ };
19
+ readonly location: {
20
+ hash: string;
21
+ };
22
+ addEventListener(type: "keydown", handler: (event: BrowserKeyboardEvent) => void): void;
23
+ removeEventListener(type: "keydown", handler: (event: BrowserKeyboardEvent) => void): void;
24
+ }
25
+ export interface BrowserRuntimeMountOptions {
26
+ readonly root: BrowserRoot | null | undefined;
27
+ readonly manifestUrl: string;
28
+ readonly keyboard?: boolean;
29
+ readonly urlState?: boolean;
30
+ readonly window?: BrowserWindowLike;
31
+ readonly createRuntime?: RuntimeFactory;
32
+ readonly createRenderer?: RendererFactory;
33
+ readonly plugins?: readonly VelumoPlugin<unknown, unknown, unknown>[];
34
+ }
35
+ export interface BrowserRuntimeMountResult {
36
+ readonly manifest: Manifest;
37
+ readonly runtime: RuntimeController;
38
+ readonly renderer: BrowserRenderer;
39
+ readonly registry?: RuntimeRegistry<unknown, unknown, unknown>;
40
+ }
41
+ export declare function mountVelumoBrowserRuntime(options: BrowserRuntimeMountOptions): Promise<BrowserRuntimeMountResult | undefined>;
42
+ export {};
43
+ //# sourceMappingURL=browser-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-runtime.d.ts","sourceRoot":"","sources":["../src/browser-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,iBAAiB,EAEjB,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,WAAW,EAEX,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAkB3B,KAAK,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC9C,KAAK,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC;AACnD,KAAK,cAAc,GAAG,CACpB,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,wBAAwB,KAC/B,iBAAiB,CAAC;AACvB,KAAK,eAAe,GAAG,CAAC,OAAO,EAAE,kBAAkB,KAAK,eAAe,CAAC;AAExE,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,cAAc,IAAI,IAAI,CAAC;CACxB;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,KAAK,IAAI,EAAE,MAAM,KAAK,oBAAoB,CAAC;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,UAAU,CAAC,IAAI,MAAM,CAAA;KAAE,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,gBAAgB,CACd,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAC7C,IAAI,CAAC;IACR,mBAAmB,CACjB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAC7C,IAAI,CAAC;CACT;AAMD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;CACvE;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;CAChE;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC,CA8HhD"}
@@ -0,0 +1,293 @@
1
+ import { createRuntimeRegistry, installPlugins, parseRuntimeHash, RuntimeController, serializeRuntimeHash, } from "@velumo/runtime";
2
+ import { DomRenderer, mountSlideThumbnail, } from "@velumo/renderer-dom";
3
+ import { createPresenterSync, } from "./browser-sync.js";
4
+ import { setupOverviewMode, } from "./browser-overview.js";
5
+ import { createSpatialSession, } from "./browser-spatial.js";
6
+ export async function mountVelumoBrowserRuntime(options) {
7
+ if (options.root === null || options.root === undefined) {
8
+ throw new Error("Velumo root element not found");
9
+ }
10
+ const root = options.root;
11
+ try {
12
+ const response = (await fetch(options.manifestUrl));
13
+ if (!response.ok) {
14
+ throw new Error(`manifest request failed with status ${response.status}`);
15
+ }
16
+ const manifest = await response.json();
17
+ const browserWindow = options.window ?? getGlobalWindow();
18
+ const runtimeOptions = options.urlState === false || browserWindow === undefined
19
+ ? {}
20
+ : parseRuntimeHash(browserWindow.location.hash);
21
+ const runtime = options.createRuntime?.(manifest, runtimeOptions) ??
22
+ new RuntimeController(manifest, runtimeOptions);
23
+ // Ward 033 contract alignment: install plugins (if provided) into a fresh
24
+ // runtime registry, then thread the registry into the DOM renderer so its
25
+ // custom-layer-renderer dispatch can resolve fx:* / custom layer types
26
+ // against the plugin-registered renderers. Type-erased handoff at this
27
+ // boundary: RuntimeRegistry<unknown,unknown,unknown> is structurally
28
+ // satisfied by DomRendererOptions["registry"].
29
+ const installedPlugins = options.plugins ?? [];
30
+ const registry = installedPlugins.length > 0
31
+ ? createRuntimeRegistry()
32
+ : undefined;
33
+ if (registry !== undefined) {
34
+ installPlugins({ registry, manifest, plugins: installedPlugins });
35
+ }
36
+ const rendererOptions = {
37
+ root,
38
+ manifest,
39
+ runtime,
40
+ registry: registry,
41
+ };
42
+ const renderer = options.createRenderer?.(rendererOptions) ??
43
+ new DomRenderer(rendererOptions);
44
+ renderer.mount();
45
+ const urlState = options.urlState !== false;
46
+ setupBrowserControls({
47
+ keyboard: options.keyboard !== false,
48
+ urlState,
49
+ window: browserWindow,
50
+ manifest,
51
+ runtime,
52
+ renderer,
53
+ });
54
+ armSpatialForCurrentSlide({
55
+ urlState,
56
+ window: browserWindow,
57
+ manifest,
58
+ runtime,
59
+ renderer,
60
+ }, "forward");
61
+ setupPresenterAudienceSync({
62
+ urlState,
63
+ window: browserWindow,
64
+ manifest,
65
+ runtime,
66
+ renderer,
67
+ });
68
+ if (browserWindow !== undefined) {
69
+ setupOverviewMode({
70
+ root: root,
71
+ runtime,
72
+ manifest,
73
+ window: browserWindow,
74
+ // Thread the plugin registry into overview thumbnails so plugin-
75
+ // registered layer renderers (e.g. fx:*) render real content, not
76
+ // fallback layer-type text.
77
+ mountThumbnail: ((opts) => mountSlideThumbnail({
78
+ root: opts.root,
79
+ manifest: opts.manifest,
80
+ slideId: opts.slideId,
81
+ registry: registry,
82
+ })),
83
+ onAfterJump: () => {
84
+ renderer.render?.();
85
+ armSpatialForCurrentSlide({
86
+ urlState,
87
+ window: browserWindow,
88
+ manifest,
89
+ runtime,
90
+ renderer,
91
+ }, "forward");
92
+ if (urlState) {
93
+ browserWindow.location.hash = serializeRuntimeHash(runtime.getState());
94
+ }
95
+ },
96
+ });
97
+ }
98
+ return { manifest, runtime, renderer, registry };
99
+ }
100
+ catch (error) {
101
+ renderMountError(root, error);
102
+ return undefined;
103
+ }
104
+ }
105
+ function renderMountError(root, error) {
106
+ const container = root.ownerDocument.createElement("section");
107
+ container.setAttribute("data-velumo-error", "mount");
108
+ const title = root.ownerDocument.createElement("h1");
109
+ title.textContent = "Velumo mount error";
110
+ const message = root.ownerDocument.createElement("p");
111
+ message.textContent =
112
+ error instanceof Error ? error.message : "Unknown browser runtime error";
113
+ container.append(title, message);
114
+ root.replaceChildren(container);
115
+ root.setAttribute("data-velumo-error", "mount");
116
+ }
117
+ function getGlobalWindow() {
118
+ return globalThis.window;
119
+ }
120
+ let activeSpatialSession;
121
+ function currentSlideEntry(options) {
122
+ const state = options.runtime.getState();
123
+ return (options.manifest.slides.find((slide) => slide.id === state.slideId) ??
124
+ options.manifest.slides[0]);
125
+ }
126
+ function armSpatialForCurrentSlide(options, direction) {
127
+ activeSpatialSession?.dispose();
128
+ activeSpatialSession = undefined;
129
+ if (options.window === undefined) {
130
+ return;
131
+ }
132
+ const root = options.renderer.getRoot?.();
133
+ if (root === undefined) {
134
+ return;
135
+ }
136
+ activeSpatialSession = createSpatialSession({
137
+ root: root,
138
+ slide: currentSlideEntry(options),
139
+ window: options.window,
140
+ direction,
141
+ });
142
+ }
143
+ function setupBrowserControls(options) {
144
+ if (!options.keyboard || options.window === undefined) {
145
+ return;
146
+ }
147
+ const browserWindow = options.window;
148
+ browserWindow.addEventListener("keydown", (event) => {
149
+ if (isEditableTarget(event.target)) {
150
+ return;
151
+ }
152
+ const result = navigateWithKey(event.key, options);
153
+ if (result === undefined) {
154
+ return;
155
+ }
156
+ event.preventDefault();
157
+ if (result === "spatial") {
158
+ updateBrowserHash(options);
159
+ return;
160
+ }
161
+ if (result === "runtime-forward") {
162
+ applyRuntimeChange(options, "forward");
163
+ return;
164
+ }
165
+ if (result === "runtime-backward") {
166
+ applyRuntimeChange(options, "backward");
167
+ }
168
+ // "none" → preventDefault already called; nothing else
169
+ });
170
+ }
171
+ function setupPresenterAudienceSync(options) {
172
+ if (options.window === undefined) {
173
+ return;
174
+ }
175
+ const channel = createPresenterChannel(options.window);
176
+ if (channel === undefined) {
177
+ return;
178
+ }
179
+ const sync = createPresenterSync({
180
+ channel,
181
+ instanceId: createPresenterInstanceId(options.window),
182
+ role: "audience",
183
+ onCommand(command) {
184
+ applyPresenterCommand(command, options);
185
+ },
186
+ });
187
+ sync.publishState(options.runtime.getState());
188
+ options.runtime.on("state:change", (event) => {
189
+ sync.publishState(event.state);
190
+ });
191
+ }
192
+ function applyPresenterCommand(command, options) {
193
+ const changed = runPresenterCommand(command, options.runtime);
194
+ if (!changed) {
195
+ return;
196
+ }
197
+ applyRuntimeChange(options, command === "previous" ? "backward" : "forward");
198
+ }
199
+ function applyRuntimeChange(options, direction) {
200
+ activeSpatialSession?.dispose();
201
+ activeSpatialSession = undefined;
202
+ options.renderer.render?.();
203
+ updateBrowserHash(options);
204
+ armSpatialForCurrentSlide(options, direction);
205
+ }
206
+ function updateBrowserHash(options) {
207
+ if (options.urlState && options.window !== undefined) {
208
+ options.window.location.hash = serializeRuntimeHash(options.runtime.getState());
209
+ }
210
+ }
211
+ function runPresenterCommand(command, runtime) {
212
+ switch (command) {
213
+ case "next":
214
+ return runtime.next();
215
+ case "previous":
216
+ return runtime.previous();
217
+ case "resetTimer":
218
+ return false;
219
+ }
220
+ }
221
+ function createPresenterChannel(browserWindow) {
222
+ const BroadcastChannelCtor = browserWindow.BroadcastChannel ??
223
+ globalThis.BroadcastChannel;
224
+ if (BroadcastChannelCtor === undefined) {
225
+ return undefined;
226
+ }
227
+ const channel = new BroadcastChannelCtor("velumo-presenter");
228
+ channel.unref?.();
229
+ return channel;
230
+ }
231
+ function createPresenterInstanceId(browserWindow) {
232
+ return (browserWindow.crypto?.randomUUID?.() ??
233
+ `audience-${Math.random().toString(36).slice(2)}`);
234
+ }
235
+ function navigateWithKey(key, options) {
236
+ switch (key) {
237
+ case " ":
238
+ case "Space":
239
+ case "Spacebar":
240
+ case "ArrowRight":
241
+ case "PageDown":
242
+ case "Enter": {
243
+ if (activeSpatialSession !== undefined &&
244
+ activeSpatialSession.advance()) {
245
+ return "spatial";
246
+ }
247
+ return options.runtime.next() ? "runtime-forward" : "none";
248
+ }
249
+ case "ArrowLeft":
250
+ case "PageUp":
251
+ case "Backspace": {
252
+ if (activeSpatialSession !== undefined && activeSpatialSession.back()) {
253
+ return "spatial";
254
+ }
255
+ return options.runtime.previous() ? "runtime-backward" : "none";
256
+ }
257
+ case "Home": {
258
+ const firstSlide = options.manifest.slides[0];
259
+ if (firstSlide === undefined) {
260
+ return "none";
261
+ }
262
+ return options.runtime.jumpToSlide(firstSlide.id)
263
+ ? "runtime-forward"
264
+ : "none";
265
+ }
266
+ case "End": {
267
+ const lastSlide = options.manifest.slides.at(-1);
268
+ if (lastSlide === undefined) {
269
+ return "none";
270
+ }
271
+ return options.runtime.jumpToSlide(lastSlide.id)
272
+ ? "runtime-forward"
273
+ : "none";
274
+ }
275
+ default:
276
+ return undefined;
277
+ }
278
+ }
279
+ function isEditableTarget(target) {
280
+ if (target === null || typeof target !== "object") {
281
+ return false;
282
+ }
283
+ const candidate = target;
284
+ if (candidate.isContentEditable === true) {
285
+ return true;
286
+ }
287
+ const tagName = candidate.tagName?.toLowerCase();
288
+ return (tagName === "input" ||
289
+ tagName === "textarea" ||
290
+ tagName === "select" ||
291
+ tagName === "button");
292
+ }
293
+ //# sourceMappingURL=browser-runtime.js.map