@hyperframes/studio 0.8.144 → 0.8.145

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 (40) hide show
  1. package/dist/assets/{hyperframes-player-Bw_jIaSX.js → hyperframes-player-DZ5JrMDg.js} +1 -1
  2. package/dist/assets/{index-DyH9dT7b.js → index-BOs6C0aZ.js} +1 -1
  3. package/dist/assets/{index-Cj7W_c7p.js → index-BqFRhNZa.js} +1 -1
  4. package/dist/assets/{index-BVM9NuWl.js → index-D8W0a0Z9.js} +131 -131
  5. package/dist/{chunk-3GHTHPZD.js → chunk-6JY3MTIX.js} +101 -2
  6. package/dist/chunk-6JY3MTIX.js.map +1 -0
  7. package/dist/{chunk-G3EDKRZH.js → chunk-NZPJUZKT.js} +99 -3
  8. package/dist/chunk-NZPJUZKT.js.map +1 -0
  9. package/dist/{chunk-PEAKCOUW.js → chunk-TP6D3U37.js} +3 -100
  10. package/dist/chunk-TP6D3U37.js.map +1 -0
  11. package/dist/{domEditingLayers-PYST4G45.js → domEditingLayers-PTP2ICGM.js} +3 -3
  12. package/dist/index.d.ts +8 -5
  13. package/dist/index.html +1 -1
  14. package/dist/index.js +410 -429
  15. package/dist/index.js.map +1 -1
  16. package/dist/player.js +2 -2
  17. package/package.json +8 -8
  18. package/src/components/StudioLeftPanels.tsx +2 -2
  19. package/src/components/editor/LayersPanel.test.ts +4 -4
  20. package/src/components/editor/LayersPanel.tsx +2 -2
  21. package/src/components/editor/TopologyLens.test.tsx +5 -4
  22. package/src/components/renders/GpuEncodingToggle.tsx +28 -0
  23. package/src/components/renders/RenderQueue.test.tsx +20 -2
  24. package/src/components/renders/RenderQueue.tsx +13 -1
  25. package/src/components/renders/RenderQueuePanel.tsx +2 -1
  26. package/src/components/renders/renderSettings.ts +5 -2
  27. package/src/components/renders/useRenderQueue.ts +3 -0
  28. package/src/components/renders/useRenderQueueComposition.test.tsx +12 -0
  29. package/src/hooks/useConsoleErrorCapture.test.tsx +21 -2
  30. package/src/hooks/useConsoleErrorCapture.ts +3 -2
  31. package/src/index.ts +1 -0
  32. package/src/player/components/Player.test.ts +44 -0
  33. package/src/player/components/Player.tsx +11 -0
  34. package/src/player/lib/playbackTypes.ts +1 -0
  35. package/src/player/sceneSwap.test.ts +27 -1
  36. package/src/player/sceneSwap.ts +16 -2
  37. package/dist/chunk-3GHTHPZD.js.map +0 -1
  38. package/dist/chunk-G3EDKRZH.js.map +0 -1
  39. package/dist/chunk-PEAKCOUW.js.map +0 -1
  40. /package/dist/{domEditingLayers-PYST4G45.js.map → domEditingLayers-PTP2ICGM.js.map} +0 -0
package/dist/index.js CHANGED
@@ -7,6 +7,8 @@ import {
7
7
  PANEL_IDS,
8
8
  Player,
9
9
  STUDIO_PREVIEW_FPS,
10
+ announcePreviewDocumentLoaded,
11
+ announcePreviewPromoted,
10
12
  applyPreviewVariablesToUrl,
11
13
  clampTimelineZoomPercent,
12
14
  clampToDuration,
@@ -26,10 +28,15 @@ import {
26
28
  isPreviewBooted,
27
29
  isRevealedAudioFxRequestCurrent,
28
30
  liveTime,
31
+ markScenesStale,
32
+ onPreviewContentReplaced,
33
+ onPreviewDocumentLoaded,
34
+ onPreviewPromoted,
29
35
  panelsInZone,
30
36
  parseDockLayout,
31
37
  patchElements,
32
38
  readStudioUiPreferences,
39
+ sceneSwapFor,
33
40
  secondsToFrame,
34
41
  stepFrameTime,
35
42
  thumbnailRevisionOf,
@@ -40,7 +47,7 @@ import {
40
47
  usePreviewVariablesStore,
41
48
  whenPreviewBooted,
42
49
  writeStudioUiPreferences
43
- } from "./chunk-G3EDKRZH.js";
50
+ } from "./chunk-NZPJUZKT.js";
44
51
  import {
45
52
  Button,
46
53
  ContextMenu,
@@ -75,10 +82,6 @@ import {
75
82
  } from "./chunk-Y2OHHNM2.js";
76
83
  import {
77
84
  DOM_EDIT_LAYER_OBSERVER_INIT,
78
- STUDIO_FLAT_INSPECTOR_ENABLED,
79
- STUDIO_SDK_CUTOVER_ENABLED,
80
- STUDIO_SDK_CUTOVER_FAMILIES,
81
- STUDIO_SDK_RESOLVER_SHADOW_ENABLED,
82
85
  buildDefaultDomEditTextField,
83
86
  buildDomEditPatchTarget,
84
87
  buildDomEditRichTextPatchOperation,
@@ -96,19 +99,20 @@ import {
96
99
  getDomEditTargetKey,
97
100
  getDomLayerPatchTarget,
98
101
  isElementComputedVisible,
99
- isSdkFamilyEnabled,
100
102
  isTextEditableSelection,
101
103
  liveLayerElement,
102
- manualEditingAvailability_exports,
103
104
  readHfId,
104
105
  resolveAllVisualDomEditTargets,
105
106
  resolveDomEditSelection,
106
- serializeDomEditTextFields,
107
- studioApiFetch
108
- } from "./chunk-PEAKCOUW.js";
107
+ serializeDomEditTextFields
108
+ } from "./chunk-TP6D3U37.js";
109
109
  import {
110
110
  LAYER_REVEAL_PRIOR_POSITION_ATTR,
111
111
  LAYER_REVEAL_PRIOR_Z_ATTR,
112
+ STUDIO_FLAT_INSPECTOR_ENABLED,
113
+ STUDIO_SDK_CUTOVER_ENABLED,
114
+ STUDIO_SDK_CUTOVER_FAMILIES,
115
+ STUDIO_SDK_RESOLVER_SHADOW_ENABLED,
112
116
  applyMediaMetadataFromElement,
113
117
  buildProjectApiPath,
114
118
  buildProjectHash,
@@ -136,8 +140,10 @@ import {
136
140
  isAudibleVideoNode,
137
141
  isElementVisibleThroughAncestors,
138
142
  isHtmlElement,
143
+ isSdkFamilyEnabled,
139
144
  isTimelineIgnoredElement,
140
145
  isVideoAudible,
146
+ manualEditingAvailability_exports,
141
147
  normalizeTimelineCompositionSource,
142
148
  parseCssColor,
143
149
  parseProjectHashRoute,
@@ -163,9 +169,10 @@ import {
163
169
  sameTimelineText,
164
170
  setCompositionSourceMap,
165
171
  splitTimelineElementKey,
172
+ studioApiFetch,
166
173
  toHexColor,
167
174
  wrapTimeline
168
- } from "./chunk-3GHTHPZD.js";
175
+ } from "./chunk-6JY3MTIX.js";
169
176
  import "./chunk-PZ5AY32C.js";
170
177
 
171
178
  // src/components/EditorShell.tsx
@@ -31514,79 +31521,6 @@ function isPreviewChanging() {
31514
31521
  return changing() && !givenUp;
31515
31522
  }
31516
31523
 
31517
- // src/player/sceneSwap.ts
31518
- var SCENES_SWAPPED = "hf-scenes-swapped";
31519
- var SCENE_SWAP_MS = 5e3;
31520
- function onPreviewContentReplaced(iframe, onReplaced) {
31521
- iframe.addEventListener("load", onReplaced);
31522
- iframe.addEventListener(SCENES_SWAPPED, onReplaced);
31523
- return () => {
31524
- iframe.removeEventListener("load", onReplaced);
31525
- iframe.removeEventListener(SCENES_SWAPPED, onReplaced);
31526
- };
31527
- }
31528
- var PREVIEW_PROMOTED = "hf-preview-promoted";
31529
- function announcePreviewPromoted(promotion) {
31530
- promotion.live.ownerDocument.dispatchEvent(
31531
- new CustomEvent(PREVIEW_PROMOTED, { detail: promotion })
31532
- );
31533
- }
31534
- function onPreviewPromoted(doc, listener2) {
31535
- const handle = (event) => listener2(event.detail);
31536
- doc.addEventListener(PREVIEW_PROMOTED, handle);
31537
- return () => doc.removeEventListener(PREVIEW_PROMOTED, handle);
31538
- }
31539
- function markScenesStale(iframe, files) {
31540
- const doc = iframe?.contentDocument;
31541
- const meta = doc?.querySelector('meta[name="hf-scene-parts"]');
31542
- if (!doc || !meta) return;
31543
- let parts;
31544
- try {
31545
- parts = JSON.parse(meta.content);
31546
- } catch {
31547
- return;
31548
- }
31549
- for (const file of files) {
31550
- const hosts = doc.querySelectorAll(`[data-composition-file="${CSS.escape(file)}"]`);
31551
- if (hosts.length === 0 && file.endsWith(".html")) parts.shared = "";
31552
- for (const host of hosts) {
31553
- const scene = host.closest("[data-hf-scene]")?.getAttribute("data-hf-scene");
31554
- if (scene && scene in parts.scenes) parts.scenes[scene] = "";
31555
- }
31556
- }
31557
- meta.content = JSON.stringify(parts);
31558
- }
31559
- function sceneSwapFor(iframe) {
31560
- const win = iframe.contentWindow;
31561
- const swap = win?.__hfSwapScenes;
31562
- if (typeof swap !== "function") return null;
31563
- return async (url, isCurrent, cancel) => {
31564
- if (cancel?.aborted) throw cancel.reason;
31565
- const deadline = new AbortController();
31566
- const timer = setTimeout(
31567
- () => deadline.abort(new Error("the preview took too long to swap")),
31568
- SCENE_SWAP_MS
31569
- );
31570
- cancel?.addEventListener("abort", () => deadline.abort(cancel.reason), { once: true });
31571
- const swapping = (async () => {
31572
- const response = await studioApiFetch(url, { signal: deadline.signal });
31573
- if (!response.ok) throw new Error(`preview request failed with ${response.status}`);
31574
- const html2 = await response.text();
31575
- if (!isCurrent()) throw new Error("superseded by a newer reload");
31576
- await swap.call(win, html2, deadline.signal);
31577
- })();
31578
- const expired = new Promise(
31579
- (_resolve, reject) => deadline.signal.addEventListener("abort", () => reject(deadline.signal.reason))
31580
- );
31581
- try {
31582
- await Promise.race([swapping, expired]);
31583
- } finally {
31584
- clearTimeout(timer);
31585
- }
31586
- iframe.dispatchEvent(new Event(SCENES_SWAPPED));
31587
- };
31588
- }
31589
-
31590
31524
  // src/player/hooks/useShadowPreviewReload.ts
31591
31525
  var SHADOW_READY_TIMEOUT_MS = 15e3;
31592
31526
  var SHADOW_READY_BUDGETS = 3;
@@ -37575,7 +37509,7 @@ function OffCanvasIndicators({
37575
37509
  const selectOffCanvas = async () => {
37576
37510
  const el = elements.current.get(r.key);
37577
37511
  if (!el) return;
37578
- const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-PYST4G45.js");
37512
+ const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-PTP2ICGM.js");
37579
37513
  const acp = activeCompositionPathRef.current ?? "index.html";
37580
37514
  const sel = await resolveDomEditSelection2(el, {
37581
37515
  activeCompositionPath: acp,
@@ -73366,6 +73300,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
73366
73300
  }
73367
73301
  if (resolution && resolution !== "auto") body.resolution = resolution;
73368
73302
  if (composition) body.composition = composition;
73303
+ if (opts.gpu) body.gpu = true;
73369
73304
  if (opts.variables && Object.keys(opts.variables).length > 0) {
73370
73305
  body.variables = opts.variables;
73371
73306
  }
@@ -89207,9 +89142,9 @@ function useConsoleErrorCapture(previewIframe) {
89207
89142
  }
89208
89143
  };
89209
89144
  attachErrorCapture();
89210
- previewIframe.addEventListener("load", attachErrorCapture);
89145
+ const stopLoaded = onPreviewDocumentLoaded(previewIframe, attachErrorCapture);
89211
89146
  return () => {
89212
- previewIframe.removeEventListener("load", attachErrorCapture);
89147
+ stopLoaded();
89213
89148
  detachErrorCapture();
89214
89149
  };
89215
89150
  }, [previewIframe, resetErrors]);
@@ -93848,16 +93783,17 @@ function getPersistedRenderSettings() {
93848
93783
  return {
93849
93784
  format: ["mp4", "webm", "mov"].includes(parsed.format) ? parsed.format : "mp4",
93850
93785
  quality: ["draft", "standard", "high"].includes(parsed.quality) ? parsed.quality : "standard",
93851
- fps: [24, 30, 60].includes(parsed.fps) ? parsed.fps : 30
93786
+ fps: [24, 30, 60].includes(parsed.fps) ? parsed.fps : 30,
93787
+ gpu: parsed.gpu === true
93852
93788
  };
93853
93789
  }
93854
93790
  } catch {
93855
93791
  }
93856
- return { format: "mp4", quality: "standard", fps: 30 };
93792
+ return { format: "mp4", quality: "standard", fps: 30, gpu: false };
93857
93793
  }
93858
- function persistRenderSettings(format, quality, fps) {
93794
+ function persistRenderSettings(format, quality, fps, gpu = getPersistedRenderSettings().gpu) {
93859
93795
  try {
93860
- localStorage.setItem(RENDER_SETTINGS_KEY, JSON.stringify({ format, quality, fps }));
93796
+ localStorage.setItem(RENDER_SETTINGS_KEY, JSON.stringify({ format, quality, fps, gpu }));
93861
93797
  } catch {
93862
93798
  }
93863
93799
  }
@@ -93906,8 +93842,8 @@ var StudioLeftPanels = memo50(function StudioLeftPanels2({
93906
93842
  return;
93907
93843
  }
93908
93844
  await waitForPendingDomEditSaves();
93909
- const { format, quality, fps } = getPersistedRenderSettings();
93910
- await renderQueue.startRender({ composition: comp, format, quality, fps });
93845
+ const { format, quality, fps, gpu } = getPersistedRenderSettings();
93846
+ await renderQueue.startRender({ composition: comp, format, quality, fps, gpu });
93911
93847
  },
93912
93848
  [renderQueue, waitForPendingDomEditSaves]
93913
93849
  );
@@ -95713,8 +95649,38 @@ var FfmpegRequiredNotice = memo56(function FfmpegRequiredNotice2({
95713
95649
  );
95714
95650
  });
95715
95651
 
95716
- // src/components/renders/RenderQueue.tsx
95652
+ // src/components/renders/GpuEncodingToggle.tsx
95717
95653
  import { jsx as jsx233, jsxs as jsxs185 } from "react/jsx-runtime";
95654
+ function GpuEncodingToggle({
95655
+ format,
95656
+ checked,
95657
+ disabled,
95658
+ onToggle
95659
+ }) {
95660
+ if (format !== "mp4") return null;
95661
+ return /* @__PURE__ */ jsxs185(
95662
+ "label",
95663
+ {
95664
+ className: `flex items-center gap-2 text-step-10 text-text-4 ${disabled ? "opacity-40 cursor-not-allowed" : "cursor-pointer"}`,
95665
+ children: [
95666
+ /* @__PURE__ */ jsx233(
95667
+ "input",
95668
+ {
95669
+ type: "checkbox",
95670
+ checked,
95671
+ disabled,
95672
+ onChange: onToggle,
95673
+ className: "accent-studio-accent"
95674
+ }
95675
+ ),
95676
+ /* @__PURE__ */ jsx233("span", { children: "Use GPU encoding" })
95677
+ ]
95678
+ }
95679
+ );
95680
+ }
95681
+
95682
+ // src/components/renders/RenderQueue.tsx
95683
+ import { jsx as jsx234, jsxs as jsxs186 } from "react/jsx-runtime";
95718
95684
  var SCALE_OPTION_ORDER = ["auto", "1080p", "4k"];
95719
95685
  var SCALE_LABEL = {
95720
95686
  auto: "Auto",
@@ -95802,8 +95768,8 @@ function FormatInfoTooltip({ format }) {
95802
95768
  return () => document.removeEventListener("keydown", onKeyDown);
95803
95769
  }, [open]);
95804
95770
  const info = FORMAT_INFO[format];
95805
- return /* @__PURE__ */ jsxs185("div", { ref: triggerRef, className: "relative", onPointerEnter: show, onPointerLeave: hide, children: [
95806
- /* @__PURE__ */ jsx233(
95771
+ return /* @__PURE__ */ jsxs186("div", { ref: triggerRef, className: "relative", onPointerEnter: show, onPointerLeave: hide, children: [
95772
+ /* @__PURE__ */ jsx234(
95807
95773
  "button",
95808
95774
  {
95809
95775
  type: "button",
@@ -95814,7 +95780,7 @@ function FormatInfoTooltip({ format }) {
95814
95780
  onBlur: hide,
95815
95781
  onClick: () => setOpen((prev) => !prev),
95816
95782
  className: "flex items-center justify-center p-0.5 -m-0.5 rounded-sm text-text-5 hover:text-text-3 transition-colors cursor-help outline-hidden focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-accent",
95817
- children: /* @__PURE__ */ jsxs185(
95783
+ children: /* @__PURE__ */ jsxs186(
95818
95784
  "svg",
95819
95785
  {
95820
95786
  width: "12",
@@ -95827,16 +95793,16 @@ function FormatInfoTooltip({ format }) {
95827
95793
  strokeLinejoin: "round",
95828
95794
  "aria-hidden": "true",
95829
95795
  children: [
95830
- /* @__PURE__ */ jsx233("circle", { cx: "12", cy: "12", r: "10" }),
95831
- /* @__PURE__ */ jsx233("path", { d: "M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3" }),
95832
- /* @__PURE__ */ jsx233("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
95796
+ /* @__PURE__ */ jsx234("circle", { cx: "12", cy: "12", r: "10" }),
95797
+ /* @__PURE__ */ jsx234("path", { d: "M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3" }),
95798
+ /* @__PURE__ */ jsx234("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
95833
95799
  ]
95834
95800
  }
95835
95801
  )
95836
95802
  }
95837
95803
  ),
95838
95804
  open && createPortal14(
95839
- /* @__PURE__ */ jsxs185(
95805
+ /* @__PURE__ */ jsxs186(
95840
95806
  "div",
95841
95807
  {
95842
95808
  id: panelId,
@@ -95846,10 +95812,10 @@ function FormatInfoTooltip({ format }) {
95846
95812
  className: "fixed w-52 p-2 rounded-sm bg-input border border-border-input shadow-menu z-200",
95847
95813
  style: { left: position?.left ?? -9999, top: position?.top ?? -9999 },
95848
95814
  children: [
95849
- /* @__PURE__ */ jsx233("p", { className: "text-step-10 font-semibold text-text-1 mb-0.5", children: info.label }),
95850
- /* @__PURE__ */ jsx233("p", { className: "text-step-9 text-text-3 leading-tight", children: info.desc }),
95851
- /* @__PURE__ */ jsx233("div", { className: "mt-1.5 pt-1.5 border-t border-border", children: ["mp4", "mov", "webm"].filter((f) => f !== format).map((f) => /* @__PURE__ */ jsxs185("p", { className: "text-step-9 text-text-4 leading-relaxed", children: [
95852
- /* @__PURE__ */ jsx233("span", { className: "text-text-3 font-medium", children: FORMAT_INFO[f].label }),
95815
+ /* @__PURE__ */ jsx234("p", { className: "text-step-10 font-semibold text-text-1 mb-0.5", children: info.label }),
95816
+ /* @__PURE__ */ jsx234("p", { className: "text-step-9 text-text-3 leading-tight", children: info.desc }),
95817
+ /* @__PURE__ */ jsx234("div", { className: "mt-1.5 pt-1.5 border-t border-border", children: ["mp4", "mov", "webm"].filter((f) => f !== format).map((f) => /* @__PURE__ */ jsxs186("p", { className: "text-step-9 text-text-4 leading-relaxed", children: [
95818
+ /* @__PURE__ */ jsx234("span", { className: "text-text-3 font-medium", children: FORMAT_INFO[f].label }),
95853
95819
  " \u2014 ",
95854
95820
  FORMAT_INFO[f].desc
95855
95821
  ] }, f)) })
@@ -95893,10 +95859,11 @@ function FormatExportButton({
95893
95859
  const [quality, setQuality] = useState153(persisted.quality);
95894
95860
  const [resolution, setResolution] = useState153("auto");
95895
95861
  const [fps, setFps] = useState153(persisted.fps);
95862
+ const [gpu, setGpu] = useState153(persisted.gpu);
95896
95863
  const missingFfmpeg = ffmpeg && !ffmpeg.ok ? ffmpeg : null;
95897
95864
  const showQuality = format !== "mov";
95898
- return /* @__PURE__ */ jsxs185("div", { className: "flex flex-col gap-3", children: [
95899
- missingFfmpeg && /* @__PURE__ */ jsx233(
95865
+ return /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-3", children: [
95866
+ missingFfmpeg && /* @__PURE__ */ jsx234(
95900
95867
  FfmpegRequiredNotice,
95901
95868
  {
95902
95869
  status: missingFfmpeg,
@@ -95904,13 +95871,13 @@ function FormatExportButton({
95904
95871
  onRecheck: onRecheckFfmpeg
95905
95872
  }
95906
95873
  ),
95907
- /* @__PURE__ */ jsxs185("div", { className: "grid grid-cols-2 gap-2", children: [
95908
- /* @__PURE__ */ jsxs185("div", { className: "flex flex-col gap-1", children: [
95909
- /* @__PURE__ */ jsxs185("div", { className: "flex items-center gap-1", children: [
95910
- /* @__PURE__ */ jsx233("span", { className: "text-step-10 text-text-4", children: "Format" }),
95911
- /* @__PURE__ */ jsx233(FormatInfoTooltip, { format })
95874
+ /* @__PURE__ */ jsxs186("div", { className: "grid grid-cols-2 gap-2", children: [
95875
+ /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-1", children: [
95876
+ /* @__PURE__ */ jsxs186("div", { className: "flex items-center gap-1", children: [
95877
+ /* @__PURE__ */ jsx234("span", { className: "text-step-10 text-text-4", children: "Format" }),
95878
+ /* @__PURE__ */ jsx234(FormatInfoTooltip, { format })
95912
95879
  ] }),
95913
- /* @__PURE__ */ jsx233(
95880
+ /* @__PURE__ */ jsx234(
95914
95881
  Select,
95915
95882
  {
95916
95883
  label: "Format",
@@ -95925,9 +95892,9 @@ function FormatExportButton({
95925
95892
  }
95926
95893
  )
95927
95894
  ] }),
95928
- /* @__PURE__ */ jsxs185("div", { className: "flex flex-col gap-1", children: [
95929
- /* @__PURE__ */ jsx233("span", { className: "text-step-10 text-text-4", children: "Resolution" }),
95930
- /* @__PURE__ */ jsx233(
95895
+ /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-1", children: [
95896
+ /* @__PURE__ */ jsx234("span", { className: "text-step-10 text-text-4", children: "Resolution" }),
95897
+ /* @__PURE__ */ jsx234(
95931
95898
  Select,
95932
95899
  {
95933
95900
  label: "Resolution",
@@ -95942,9 +95909,9 @@ function FormatExportButton({
95942
95909
  }
95943
95910
  )
95944
95911
  ] }),
95945
- /* @__PURE__ */ jsxs185("div", { className: "flex flex-col gap-1", children: [
95946
- /* @__PURE__ */ jsx233("span", { className: "text-step-10 text-text-4", children: "Frame rate" }),
95947
- /* @__PURE__ */ jsx233(
95912
+ /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-1", children: [
95913
+ /* @__PURE__ */ jsx234("span", { className: "text-step-10 text-text-4", children: "Frame rate" }),
95914
+ /* @__PURE__ */ jsx234(
95948
95915
  Select,
95949
95916
  {
95950
95917
  label: "Frame rate",
@@ -95959,9 +95926,9 @@ function FormatExportButton({
95959
95926
  }
95960
95927
  )
95961
95928
  ] }),
95962
- showQuality && /* @__PURE__ */ jsxs185("div", { className: "flex flex-col gap-1", children: [
95963
- /* @__PURE__ */ jsx233("span", { className: "text-step-10 text-text-4", children: "Quality" }),
95964
- /* @__PURE__ */ jsx233(
95929
+ showQuality && /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-1", children: [
95930
+ /* @__PURE__ */ jsx234("span", { className: "text-step-10 text-text-4", children: "Quality" }),
95931
+ /* @__PURE__ */ jsx234(
95965
95932
  Select,
95966
95933
  {
95967
95934
  label: "Quality",
@@ -95977,7 +95944,19 @@ function FormatExportButton({
95977
95944
  )
95978
95945
  ] })
95979
95946
  ] }),
95980
- /* @__PURE__ */ jsx233(
95947
+ /* @__PURE__ */ jsx234(
95948
+ GpuEncodingToggle,
95949
+ {
95950
+ format,
95951
+ checked: gpu,
95952
+ disabled: isRendering,
95953
+ onToggle: () => {
95954
+ setGpu(!gpu);
95955
+ persistRenderSettings(format, quality, fps, !gpu);
95956
+ }
95957
+ }
95958
+ ),
95959
+ /* @__PURE__ */ jsx234(
95981
95960
  Button,
95982
95961
  {
95983
95962
  variant: "primary",
@@ -95990,13 +95969,13 @@ function FormatExportButton({
95990
95969
  if (isRendering || missingFfmpeg) return;
95991
95970
  const outputResolution = resolveResolution(resolution, compositionDimensions);
95992
95971
  trackStudioEvent("render_start", { format, quality, resolution: outputResolution, fps });
95993
- void onStartRender(format, quality, outputResolution, fps);
95972
+ void onStartRender(format, quality, outputResolution, fps, gpu);
95994
95973
  },
95995
95974
  className: "w-full",
95996
95975
  children: isRendering ? "Rendering\u2026" : "Export"
95997
95976
  }
95998
95977
  ),
95999
- lastRenderDurationMs !== void 0 && !isRendering && /* @__PURE__ */ jsxs185("p", { className: "text-step-9 text-text-5 text-center -mt-1.5", children: [
95978
+ lastRenderDurationMs !== void 0 && !isRendering && /* @__PURE__ */ jsxs186("p", { className: "text-step-9 text-text-5 text-center -mt-1.5", children: [
96000
95979
  "Last render took ",
96001
95980
  formatEta(lastRenderDurationMs)
96002
95981
  ] })
@@ -96027,8 +96006,8 @@ var RenderQueue = memo57(function RenderQueue2({
96027
96006
  }, [jobs.length]);
96028
96007
  const completedCount = jobs.filter((j) => j.status !== "rendering").length;
96029
96008
  const lastRenderDurationMs = [...jobs].reverse().find((j) => j.status === "complete" && j.durationMs !== void 0)?.durationMs;
96030
- return /* @__PURE__ */ jsxs185("div", { className: "flex flex-col h-full", children: [
96031
- /* @__PURE__ */ jsx233("div", { className: "px-3 py-3 border-b border-border shrink-0", children: /* @__PURE__ */ jsx233(
96009
+ return /* @__PURE__ */ jsxs186("div", { className: "flex flex-col h-full", children: [
96010
+ /* @__PURE__ */ jsx234("div", { className: "px-3 py-3 border-b border-border shrink-0", children: /* @__PURE__ */ jsx234(
96032
96011
  FormatExportButton,
96033
96012
  {
96034
96013
  onStartRender,
@@ -96040,21 +96019,21 @@ var RenderQueue = memo57(function RenderQueue2({
96040
96019
  onRecheckFfmpeg
96041
96020
  }
96042
96021
  ) }),
96043
- actionError && /* @__PURE__ */ jsxs185(
96022
+ actionError && /* @__PURE__ */ jsxs186(
96044
96023
  "div",
96045
96024
  {
96046
96025
  role: "alert",
96047
96026
  className: "flex items-start justify-between gap-2 px-3 py-2 border-b border-border bg-danger/10",
96048
96027
  children: [
96049
- /* @__PURE__ */ jsx233("span", { className: "text-step-10 text-danger-ink", children: actionError }),
96050
- onDismissActionError && /* @__PURE__ */ jsx233(
96028
+ /* @__PURE__ */ jsx234("span", { className: "text-step-10 text-danger-ink", children: actionError }),
96029
+ onDismissActionError && /* @__PURE__ */ jsx234(
96051
96030
  IconButton,
96052
96031
  {
96053
96032
  size: "sm",
96054
96033
  onClick: onDismissActionError,
96055
96034
  "aria-label": "Dismiss error",
96056
96035
  className: "shrink-0",
96057
- icon: /* @__PURE__ */ jsx233(
96036
+ icon: /* @__PURE__ */ jsx234(
96058
96037
  "svg",
96059
96038
  {
96060
96039
  width: "10",
@@ -96065,7 +96044,7 @@ var RenderQueue = memo57(function RenderQueue2({
96065
96044
  strokeWidth: "2",
96066
96045
  strokeLinecap: "round",
96067
96046
  "aria-hidden": "true",
96068
- children: /* @__PURE__ */ jsx233("path", { d: "M18 6L6 18M6 6l12 12" })
96047
+ children: /* @__PURE__ */ jsx234("path", { d: "M18 6L6 18M6 6l12 12" })
96069
96048
  }
96070
96049
  )
96071
96050
  }
@@ -96073,11 +96052,11 @@ var RenderQueue = memo57(function RenderQueue2({
96073
96052
  ]
96074
96053
  }
96075
96054
  ),
96076
- /* @__PURE__ */ jsx233("div", { ref: listRef, className: "flex-1 overflow-y-auto", children: loadError && jobs.length === 0 ? /* @__PURE__ */ jsxs185("div", { className: "flex flex-col items-center justify-center h-full px-4 gap-2", role: "alert", children: [
96077
- /* @__PURE__ */ jsx233("p", { className: "text-step-10 text-danger-ink text-center", children: loadError }),
96078
- onRetryLoad && /* @__PURE__ */ jsx233(Button, { size: "sm", variant: "secondary", onClick: onRetryLoad, children: "Retry" })
96079
- ] }) : jobs.length === 0 ? /* @__PURE__ */ jsxs185("div", { className: "flex flex-col items-center justify-center h-full px-4 gap-2", children: [
96080
- /* @__PURE__ */ jsxs185(
96055
+ /* @__PURE__ */ jsx234("div", { ref: listRef, className: "flex-1 overflow-y-auto", children: loadError && jobs.length === 0 ? /* @__PURE__ */ jsxs186("div", { className: "flex flex-col items-center justify-center h-full px-4 gap-2", role: "alert", children: [
96056
+ /* @__PURE__ */ jsx234("p", { className: "text-step-10 text-danger-ink text-center", children: loadError }),
96057
+ onRetryLoad && /* @__PURE__ */ jsx234(Button, { size: "sm", variant: "secondary", onClick: onRetryLoad, children: "Retry" })
96058
+ ] }) : jobs.length === 0 ? /* @__PURE__ */ jsxs186("div", { className: "flex flex-col items-center justify-center h-full px-4 gap-2", children: [
96059
+ /* @__PURE__ */ jsxs186(
96081
96060
  "svg",
96082
96061
  {
96083
96062
  width: "20",
@@ -96088,7 +96067,7 @@ var RenderQueue = memo57(function RenderQueue2({
96088
96067
  strokeWidth: "1.5",
96089
96068
  className: "text-text-5",
96090
96069
  children: [
96091
- /* @__PURE__ */ jsx233(
96070
+ /* @__PURE__ */ jsx234(
96092
96071
  "rect",
96093
96072
  {
96094
96073
  x: "2",
@@ -96101,7 +96080,7 @@ var RenderQueue = memo57(function RenderQueue2({
96101
96080
  strokeLinejoin: "round"
96102
96081
  }
96103
96082
  ),
96104
- /* @__PURE__ */ jsx233(
96083
+ /* @__PURE__ */ jsx234(
96105
96084
  "path",
96106
96085
  {
96107
96086
  d: "M7 2v20M17 2v20M2 12h20M2 7h5M2 17h5M17 17h5M17 7h5",
@@ -96112,17 +96091,17 @@ var RenderQueue = memo57(function RenderQueue2({
96112
96091
  ]
96113
96092
  }
96114
96093
  ),
96115
- /* @__PURE__ */ jsx233("p", { className: "text-step-10 text-text-5 text-center", children: "No renders yet" })
96116
- ] }) : /* @__PURE__ */ jsxs185("div", { children: [
96117
- completedCount > 0 && /* @__PURE__ */ jsxs185("div", { className: "flex items-center justify-between px-3 py-1.5 border-b border-border", children: [
96118
- /* @__PURE__ */ jsxs185("span", { className: "text-step-10 text-text-4", children: [
96094
+ /* @__PURE__ */ jsx234("p", { className: "text-step-10 text-text-5 text-center", children: "No renders yet" })
96095
+ ] }) : /* @__PURE__ */ jsxs186("div", { children: [
96096
+ completedCount > 0 && /* @__PURE__ */ jsxs186("div", { className: "flex items-center justify-between px-3 py-1.5 border-b border-border", children: [
96097
+ /* @__PURE__ */ jsxs186("span", { className: "text-step-10 text-text-4", children: [
96119
96098
  jobs.length,
96120
96099
  " render",
96121
96100
  jobs.length === 1 ? "" : "s"
96122
96101
  ] }),
96123
- /* @__PURE__ */ jsx233(Tooltip, { label: "Hide finished renders from this list (files stay on disk)", children: /* @__PURE__ */ jsx233(Button, { size: "sm", variant: "ghost", onClick: onClearCompleted, children: "Hide finished" }) })
96102
+ /* @__PURE__ */ jsx234(Tooltip, { label: "Hide finished renders from this list (files stay on disk)", children: /* @__PURE__ */ jsx234(Button, { size: "sm", variant: "ghost", onClick: onClearCompleted, children: "Hide finished" }) })
96124
96103
  ] }),
96125
- jobs.map((job) => /* @__PURE__ */ jsx233(
96104
+ jobs.map((job) => /* @__PURE__ */ jsx234(
96126
96105
  RenderQueueItem,
96127
96106
  {
96128
96107
  job,
@@ -96137,10 +96116,10 @@ var RenderQueue = memo57(function RenderQueue2({
96137
96116
  });
96138
96117
 
96139
96118
  // src/components/renders/RenderQueuePanel.tsx
96140
- import { jsx as jsx234 } from "react/jsx-runtime";
96119
+ import { jsx as jsx235 } from "react/jsx-runtime";
96141
96120
  var RenderQueuePanel = memo58(function RenderQueuePanel2() {
96142
96121
  const { projectId, compositionDimensions, waitForPendingDomEditSaves, renderQueue } = useStudioShellContext();
96143
- return /* @__PURE__ */ jsx234(
96122
+ return /* @__PURE__ */ jsx235(
96144
96123
  RenderQueue,
96145
96124
  {
96146
96125
  jobs: renderQueue.jobs,
@@ -96155,13 +96134,14 @@ var RenderQueuePanel = memo58(function RenderQueuePanel2() {
96155
96134
  ffmpeg: renderQueue.ffmpeg,
96156
96135
  ffmpegChecking: renderQueue.ffmpegChecking,
96157
96136
  onRecheckFfmpeg: renderQueue.recheckFfmpeg,
96158
- onStartRender: async (format, quality, resolution, fps) => {
96137
+ onStartRender: async (format, quality, resolution, fps, gpu) => {
96159
96138
  await waitForPendingDomEditSaves();
96160
96139
  await renderQueue.startRender({
96161
96140
  fps,
96162
96141
  quality,
96163
96142
  format,
96164
96143
  resolution,
96144
+ gpu,
96165
96145
  // Render what the user is previewing: active variable overrides
96166
96146
  // from the Variables panel ride along (undefined = defaults).
96167
96147
  variables: usePreviewVariablesStore.getState().values ?? void 0
@@ -96179,13 +96159,13 @@ import { parseSlideshowManifest } from "@hyperframes/core/slideshow";
96179
96159
 
96180
96160
  // src/components/panels/SlideshowSubPanels.tsx
96181
96161
  import { useState as useState154, useCallback as useCallback178, useId as useId6 } from "react";
96182
- import { jsx as jsx235, jsxs as jsxs186 } from "react/jsx-runtime";
96162
+ import { jsx as jsx236, jsxs as jsxs187 } from "react/jsx-runtime";
96183
96163
  function SectionHeader({
96184
96164
  children,
96185
96165
  expanded,
96186
96166
  onToggle
96187
96167
  }) {
96188
- return /* @__PURE__ */ jsxs186(
96168
+ return /* @__PURE__ */ jsxs187(
96189
96169
  "button",
96190
96170
  {
96191
96171
  type: "button",
@@ -96193,8 +96173,8 @@ function SectionHeader({
96193
96173
  onClick: onToggle,
96194
96174
  "aria-expanded": expanded,
96195
96175
  children: [
96196
- /* @__PURE__ */ jsx235("span", { children }),
96197
- /* @__PURE__ */ jsx235("span", { className: "text-[10px] text-neutral-600", children: expanded ? "\u25B2" : "\u25BC" })
96176
+ /* @__PURE__ */ jsx236("span", { children }),
96177
+ /* @__PURE__ */ jsx236("span", { className: "text-[10px] text-neutral-600", children: expanded ? "\u25B2" : "\u25BC" })
96198
96178
  ]
96199
96179
  }
96200
96180
  );
@@ -96212,12 +96192,12 @@ function SlideList({
96212
96192
  const orderedSlideScenes = slides.map((sl) => sceneById.get(sl.sceneId)).filter((s) => s !== void 0);
96213
96193
  const nonSlideScenes = scenes.filter((sc) => !slideIds.has(sc.id));
96214
96194
  const rows = [...orderedSlideScenes, ...nonSlideScenes];
96215
- return /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-px", children: [
96195
+ return /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-px", children: [
96216
96196
  rows.map((scene) => {
96217
96197
  const isSlide = slideIds.has(scene.id);
96218
96198
  const isSelected2 = selectedSceneId === scene.id;
96219
96199
  const slideIndex = slides.findIndex((s) => s.sceneId === scene.id);
96220
- return /* @__PURE__ */ jsxs186(
96200
+ return /* @__PURE__ */ jsxs187(
96221
96201
  "div",
96222
96202
  {
96223
96203
  role: "button",
@@ -96232,7 +96212,7 @@ function SlideList({
96232
96212
  }
96233
96213
  },
96234
96214
  children: [
96235
- /* @__PURE__ */ jsx235(
96215
+ /* @__PURE__ */ jsx236(
96236
96216
  "input",
96237
96217
  {
96238
96218
  type: "checkbox",
@@ -96243,9 +96223,9 @@ function SlideList({
96243
96223
  className: "accent-studio-accent shrink-0"
96244
96224
  }
96245
96225
  ),
96246
- /* @__PURE__ */ jsx235("span", { className: "flex-1 truncate", children: scene.label || scene.id }),
96247
- isSlide && /* @__PURE__ */ jsxs186("span", { className: "flex gap-0.5 shrink-0", children: [
96248
- /* @__PURE__ */ jsx235(
96226
+ /* @__PURE__ */ jsx236("span", { className: "flex-1 truncate", children: scene.label || scene.id }),
96227
+ isSlide && /* @__PURE__ */ jsxs187("span", { className: "flex gap-0.5 shrink-0", children: [
96228
+ /* @__PURE__ */ jsx236(
96249
96229
  "button",
96250
96230
  {
96251
96231
  type: "button",
@@ -96260,7 +96240,7 @@ function SlideList({
96260
96240
  children: "\u25B2"
96261
96241
  }
96262
96242
  ),
96263
- /* @__PURE__ */ jsx235(
96243
+ /* @__PURE__ */ jsx236(
96264
96244
  "button",
96265
96245
  {
96266
96246
  type: "button",
@@ -96281,7 +96261,7 @@ function SlideList({
96281
96261
  scene.id
96282
96262
  );
96283
96263
  }),
96284
- scenes.length === 0 && /* @__PURE__ */ jsx235("p", { className: "px-3 py-2 text-[11px] text-neutral-500 italic", children: "No scenes found" })
96264
+ scenes.length === 0 && /* @__PURE__ */ jsx236("p", { className: "px-3 py-2 text-[11px] text-neutral-500 italic", children: "No scenes found" })
96285
96265
  ] });
96286
96266
  }
96287
96267
  function SlideInspector({
@@ -96293,14 +96273,14 @@ function SlideInspector({
96293
96273
  onRemoveFragment
96294
96274
  }) {
96295
96275
  const fragments = slide?.fragments ?? [];
96296
- return /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-3 px-3 py-2", children: [
96297
- /* @__PURE__ */ jsxs186("p", { className: "text-[10px] text-neutral-500 font-medium uppercase tracking-wide truncate", children: [
96276
+ return /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-3 px-3 py-2", children: [
96277
+ /* @__PURE__ */ jsxs187("p", { className: "text-[10px] text-neutral-500 font-medium uppercase tracking-wide truncate", children: [
96298
96278
  "Scene: ",
96299
96279
  sceneId
96300
96280
  ] }),
96301
- /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-1", children: [
96302
- /* @__PURE__ */ jsx235("label", { className: "text-[11px] text-neutral-400", children: "Notes" }),
96303
- /* @__PURE__ */ jsx235(
96281
+ /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-1", children: [
96282
+ /* @__PURE__ */ jsx236("label", { className: "text-[11px] text-neutral-400", children: "Notes" }),
96283
+ /* @__PURE__ */ jsx236(
96304
96284
  "textarea",
96305
96285
  {
96306
96286
  className: "bg-neutral-800 border border-neutral-700 rounded-sm px-2 py-1.5 text-[11px] text-text-0 resize-none placeholder-neutral-600 focus:border-studio-accent/60 focus:outline-hidden",
@@ -96311,10 +96291,10 @@ function SlideInspector({
96311
96291
  }
96312
96292
  )
96313
96293
  ] }),
96314
- /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-1.5", children: [
96315
- /* @__PURE__ */ jsxs186("div", { className: "flex items-center justify-between", children: [
96316
- /* @__PURE__ */ jsx235("span", { className: "text-[11px] text-neutral-400", children: "Fragment hold-points" }),
96317
- /* @__PURE__ */ jsxs186(
96294
+ /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-1.5", children: [
96295
+ /* @__PURE__ */ jsxs187("div", { className: "flex items-center justify-between", children: [
96296
+ /* @__PURE__ */ jsx236("span", { className: "text-[11px] text-neutral-400", children: "Fragment hold-points" }),
96297
+ /* @__PURE__ */ jsxs187(
96318
96298
  "button",
96319
96299
  {
96320
96300
  type: "button",
@@ -96329,14 +96309,14 @@ function SlideInspector({
96329
96309
  }
96330
96310
  )
96331
96311
  ] }),
96332
- fragments.length > 0 ? /* @__PURE__ */ jsx235("div", { className: "flex flex-wrap gap-1", children: fragments.map((t2, i) => /* @__PURE__ */ jsxs186(
96312
+ fragments.length > 0 ? /* @__PURE__ */ jsx236("div", { className: "flex flex-wrap gap-1", children: fragments.map((t2, i) => /* @__PURE__ */ jsxs187(
96333
96313
  "span",
96334
96314
  {
96335
96315
  className: "inline-flex items-center gap-1 bg-neutral-700 rounded-sm px-1.5 py-0.5 text-[10px] text-neutral-200",
96336
96316
  children: [
96337
96317
  t2.toFixed(2),
96338
96318
  "s",
96339
- /* @__PURE__ */ jsx235(
96319
+ /* @__PURE__ */ jsx236(
96340
96320
  "button",
96341
96321
  {
96342
96322
  type: "button",
@@ -96349,7 +96329,7 @@ function SlideInspector({
96349
96329
  ]
96350
96330
  },
96351
96331
  `frag-${i}`
96352
- )) }) : /* @__PURE__ */ jsx235("p", { className: "text-[10px] text-neutral-600 italic", children: "No hold-points yet" })
96332
+ )) }) : /* @__PURE__ */ jsx236("p", { className: "text-[10px] text-neutral-600 italic", children: "No hold-points yet" })
96353
96333
  ] })
96354
96334
  ] });
96355
96335
  }
@@ -96372,9 +96352,9 @@ function BranchTree({
96372
96352
  onCreateSequence(label);
96373
96353
  setNewLabel("");
96374
96354
  }, [newLabel, onCreateSequence]);
96375
- return /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-3 px-3 py-2", children: [
96376
- /* @__PURE__ */ jsxs186("div", { className: "flex gap-1.5", children: [
96377
- /* @__PURE__ */ jsx235(
96355
+ return /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-3 px-3 py-2", children: [
96356
+ /* @__PURE__ */ jsxs187("div", { className: "flex gap-1.5", children: [
96357
+ /* @__PURE__ */ jsx236(
96378
96358
  "input",
96379
96359
  {
96380
96360
  id: inputId,
@@ -96389,7 +96369,7 @@ function BranchTree({
96389
96369
  "aria-label": "New branch sequence name"
96390
96370
  }
96391
96371
  ),
96392
- /* @__PURE__ */ jsx235(
96372
+ /* @__PURE__ */ jsx236(
96393
96373
  "button",
96394
96374
  {
96395
96375
  type: "button",
@@ -96399,7 +96379,7 @@ function BranchTree({
96399
96379
  }
96400
96380
  )
96401
96381
  ] }),
96402
- sequences.length === 0 ? /* @__PURE__ */ jsx235("p", { className: "text-[10px] text-neutral-600 italic", children: "No branches yet" }) : /* @__PURE__ */ jsx235("div", { className: "flex flex-col gap-3", children: sequences.map((seq) => /* @__PURE__ */ jsx235(
96382
+ sequences.length === 0 ? /* @__PURE__ */ jsx236("p", { className: "text-[10px] text-neutral-600 italic", children: "No branches yet" }) : /* @__PURE__ */ jsx236("div", { className: "flex flex-col gap-3", children: sequences.map((seq) => /* @__PURE__ */ jsx236(
96403
96383
  BranchItem,
96404
96384
  {
96405
96385
  seq,
@@ -96433,9 +96413,9 @@ function BranchItem({
96433
96413
  if (label && label !== seq.label) onRename(seq.id, label);
96434
96414
  setEditing(false);
96435
96415
  }, [draft, onRename, seq.id, seq.label]);
96436
- return /* @__PURE__ */ jsxs186("div", { className: "border border-neutral-700/60 rounded-sm p-2 flex flex-col gap-2", children: [
96437
- /* @__PURE__ */ jsxs186("div", { className: "flex items-center gap-1", children: [
96438
- editing ? /* @__PURE__ */ jsx235(
96416
+ return /* @__PURE__ */ jsxs187("div", { className: "border border-neutral-700/60 rounded-sm p-2 flex flex-col gap-2", children: [
96417
+ /* @__PURE__ */ jsxs187("div", { className: "flex items-center gap-1", children: [
96418
+ editing ? /* @__PURE__ */ jsx236(
96439
96419
  "input",
96440
96420
  {
96441
96421
  className: "flex-1 bg-neutral-800 border border-neutral-600 rounded-sm px-1.5 py-0.5 text-[11px] text-text-0 focus:border-studio-accent/60 focus:outline-hidden",
@@ -96449,7 +96429,7 @@ function BranchItem({
96449
96429
  },
96450
96430
  "aria-label": `Rename branch ${seq.label}`
96451
96431
  }
96452
- ) : /* @__PURE__ */ jsx235(
96432
+ ) : /* @__PURE__ */ jsx236(
96453
96433
  "span",
96454
96434
  {
96455
96435
  role: "button",
@@ -96466,7 +96446,7 @@ function BranchItem({
96466
96446
  children: seq.label
96467
96447
  }
96468
96448
  ),
96469
- /* @__PURE__ */ jsx235(
96449
+ /* @__PURE__ */ jsx236(
96470
96450
  "button",
96471
96451
  {
96472
96452
  type: "button",
@@ -96477,16 +96457,16 @@ function BranchItem({
96477
96457
  }
96478
96458
  )
96479
96459
  ] }),
96480
- confirmingDelete && /* @__PURE__ */ jsxs186("div", { className: "px-2 py-1.5 bg-danger/15 border-l-2 border-red-500 flex flex-col gap-1 rounded-xs", children: [
96481
- /* @__PURE__ */ jsxs186("span", { className: "text-[10px] text-danger-ink", children: [
96460
+ confirmingDelete && /* @__PURE__ */ jsxs187("div", { className: "px-2 py-1.5 bg-danger/15 border-l-2 border-red-500 flex flex-col gap-1 rounded-xs", children: [
96461
+ /* @__PURE__ */ jsxs187("span", { className: "text-[10px] text-danger-ink", children: [
96482
96462
  "Delete branch \u201C",
96483
96463
  seq.label,
96484
96464
  "\u201D",
96485
96465
  seq.slides.length > 0 ? ` and its ${seq.slides.length} slide${seq.slides.length === 1 ? "" : "s"}` : "",
96486
96466
  "? Hotspots pointing to it will no longer resolve."
96487
96467
  ] }),
96488
- /* @__PURE__ */ jsxs186("div", { className: "flex items-center justify-end gap-1", children: [
96489
- /* @__PURE__ */ jsx235(
96468
+ /* @__PURE__ */ jsxs187("div", { className: "flex items-center justify-end gap-1", children: [
96469
+ /* @__PURE__ */ jsx236(
96490
96470
  "button",
96491
96471
  {
96492
96472
  type: "button",
@@ -96498,7 +96478,7 @@ function BranchItem({
96498
96478
  children: "Delete"
96499
96479
  }
96500
96480
  ),
96501
- /* @__PURE__ */ jsx235(
96481
+ /* @__PURE__ */ jsx236(
96502
96482
  "button",
96503
96483
  {
96504
96484
  type: "button",
@@ -96509,16 +96489,16 @@ function BranchItem({
96509
96489
  )
96510
96490
  ] })
96511
96491
  ] }),
96512
- /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-px pl-2", children: [
96492
+ /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-px pl-2", children: [
96513
96493
  scenes.map((scene) => {
96514
96494
  const assigned = seq.slides.some((s) => s.sceneId === scene.id);
96515
96495
  const isSelected2 = selectedSequenceId === seq.id && selectedSceneId === scene.id;
96516
- return /* @__PURE__ */ jsxs186(
96496
+ return /* @__PURE__ */ jsxs187(
96517
96497
  "div",
96518
96498
  {
96519
96499
  className: "flex items-center gap-1.5 py-0.5 text-[11px] text-neutral-400",
96520
96500
  children: [
96521
- /* @__PURE__ */ jsx235(
96501
+ /* @__PURE__ */ jsx236(
96522
96502
  "input",
96523
96503
  {
96524
96504
  type: "checkbox",
@@ -96528,7 +96508,7 @@ function BranchItem({
96528
96508
  className: "accent-studio-accent shrink-0"
96529
96509
  }
96530
96510
  ),
96531
- assigned ? /* @__PURE__ */ jsx235(
96511
+ assigned ? /* @__PURE__ */ jsx236(
96532
96512
  "button",
96533
96513
  {
96534
96514
  type: "button",
@@ -96537,13 +96517,13 @@ function BranchItem({
96537
96517
  onClick: () => onSelectBranchSlide(seq.id, scene.id),
96538
96518
  children: scene.label || scene.id
96539
96519
  }
96540
- ) : /* @__PURE__ */ jsx235("span", { className: "flex-1 truncate", children: scene.label || scene.id })
96520
+ ) : /* @__PURE__ */ jsx236("span", { className: "flex-1 truncate", children: scene.label || scene.id })
96541
96521
  ]
96542
96522
  },
96543
96523
  scene.id
96544
96524
  );
96545
96525
  }),
96546
- scenes.length === 0 && /* @__PURE__ */ jsx235("p", { className: "text-[10px] text-neutral-600 italic", children: "No scenes" })
96526
+ scenes.length === 0 && /* @__PURE__ */ jsx236("p", { className: "text-[10px] text-neutral-600 italic", children: "No scenes" })
96547
96527
  ] })
96548
96528
  ] });
96549
96529
  }
@@ -96569,19 +96549,19 @@ function HotspotTool({
96569
96549
  setHotspotLabel("");
96570
96550
  }, [selectedSceneId, targetSequenceId, elementKey3, hotspotLabel, onAddHotspot]);
96571
96551
  if (!selectedSceneId) {
96572
- return /* @__PURE__ */ jsx235("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx235("p", { className: "text-[11px] text-neutral-500 italic", children: "Select a scene in the Slides list" }) });
96552
+ return /* @__PURE__ */ jsx236("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx236("p", { className: "text-[11px] text-neutral-500 italic", children: "Select a scene in the Slides list" }) });
96573
96553
  }
96574
- return /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-3 px-3 py-2", children: [
96575
- /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-1.5", children: [
96576
- /* @__PURE__ */ jsxs186("p", { className: "text-[11px] text-neutral-400", children: [
96554
+ return /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-3 px-3 py-2", children: [
96555
+ /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-1.5", children: [
96556
+ /* @__PURE__ */ jsxs187("p", { className: "text-[11px] text-neutral-400", children: [
96577
96557
  "Selected element:",
96578
96558
  " ",
96579
- /* @__PURE__ */ jsx235("span", { className: "text-neutral-200 font-mono", children: elementKey3 ?? "none" })
96559
+ /* @__PURE__ */ jsx236("span", { className: "text-neutral-200 font-mono", children: elementKey3 ?? "none" })
96580
96560
  ] }),
96581
- !elementKey3 && /* @__PURE__ */ jsx235("p", { className: "text-[10px] text-neutral-500 italic", children: "Click an element on the canvas to choose the hotspot target." }),
96582
- sequences.length === 0 && /* @__PURE__ */ jsx235("p", { className: "text-[10px] text-neutral-500 italic", children: "Create a branch in the Branches section first \u2014 hotspots jump to a branch." }),
96583
- /* @__PURE__ */ jsx235("label", { className: "text-[11px] text-neutral-400", children: "Hotspot label" }),
96584
- /* @__PURE__ */ jsx235(
96561
+ !elementKey3 && /* @__PURE__ */ jsx236("p", { className: "text-[10px] text-neutral-500 italic", children: "Click an element on the canvas to choose the hotspot target." }),
96562
+ sequences.length === 0 && /* @__PURE__ */ jsx236("p", { className: "text-[10px] text-neutral-500 italic", children: "Create a branch in the Branches section first \u2014 hotspots jump to a branch." }),
96563
+ /* @__PURE__ */ jsx236("label", { className: "text-[11px] text-neutral-400", children: "Hotspot label" }),
96564
+ /* @__PURE__ */ jsx236(
96585
96565
  "input",
96586
96566
  {
96587
96567
  type: "text",
@@ -96592,8 +96572,8 @@ function HotspotTool({
96592
96572
  "aria-label": "Hotspot label"
96593
96573
  }
96594
96574
  ),
96595
- /* @__PURE__ */ jsx235("label", { className: "text-[11px] text-neutral-400", children: "Target branch" }),
96596
- /* @__PURE__ */ jsxs186(
96575
+ /* @__PURE__ */ jsx236("label", { className: "text-[11px] text-neutral-400", children: "Target branch" }),
96576
+ /* @__PURE__ */ jsxs187(
96597
96577
  "select",
96598
96578
  {
96599
96579
  className: "bg-neutral-800 border border-neutral-700 rounded-sm px-2 py-1 text-[11px] text-text-0 focus:border-studio-accent/60 focus:outline-hidden",
@@ -96601,12 +96581,12 @@ function HotspotTool({
96601
96581
  onChange: (e) => setTargetSequenceId(e.target.value),
96602
96582
  "aria-label": "Target branch sequence",
96603
96583
  children: [
96604
- /* @__PURE__ */ jsx235("option", { value: "", children: "\u2014 select branch \u2014" }),
96605
- sequences.map((seq) => /* @__PURE__ */ jsx235("option", { value: seq.id, children: seq.label }, seq.id))
96584
+ /* @__PURE__ */ jsx236("option", { value: "", children: "\u2014 select branch \u2014" }),
96585
+ sequences.map((seq) => /* @__PURE__ */ jsx236("option", { value: seq.id, children: seq.label }, seq.id))
96606
96586
  ]
96607
96587
  }
96608
96588
  ),
96609
- /* @__PURE__ */ jsx235(
96589
+ /* @__PURE__ */ jsx236(
96610
96590
  "button",
96611
96591
  {
96612
96592
  type: "button",
@@ -96618,21 +96598,21 @@ function HotspotTool({
96618
96598
  }
96619
96599
  )
96620
96600
  ] }),
96621
- hotspots.length > 0 && /* @__PURE__ */ jsxs186("div", { className: "flex flex-col gap-1.5", children: [
96622
- /* @__PURE__ */ jsx235("p", { className: "text-[11px] text-neutral-400 font-medium", children: "Hotspots on this slide" }),
96601
+ hotspots.length > 0 && /* @__PURE__ */ jsxs187("div", { className: "flex flex-col gap-1.5", children: [
96602
+ /* @__PURE__ */ jsx236("p", { className: "text-[11px] text-neutral-400 font-medium", children: "Hotspots on this slide" }),
96623
96603
  hotspots.map((h) => {
96624
96604
  const seqLabel = sequences.find((s) => s.id === h.target)?.label ?? h.target;
96625
- return /* @__PURE__ */ jsxs186(
96605
+ return /* @__PURE__ */ jsxs187(
96626
96606
  "div",
96627
96607
  {
96628
96608
  className: "flex items-center gap-2 bg-neutral-800 rounded-sm px-2 py-1",
96629
96609
  children: [
96630
- /* @__PURE__ */ jsxs186("span", { className: "flex-1 text-[11px] text-neutral-200 truncate", children: [
96610
+ /* @__PURE__ */ jsxs187("span", { className: "flex-1 text-[11px] text-neutral-200 truncate", children: [
96631
96611
  h.label,
96632
96612
  " \u2192 ",
96633
- /* @__PURE__ */ jsx235("span", { className: "text-neutral-400", children: seqLabel })
96613
+ /* @__PURE__ */ jsx236("span", { className: "text-neutral-400", children: seqLabel })
96634
96614
  ] }),
96635
- /* @__PURE__ */ jsx235(
96615
+ /* @__PURE__ */ jsx236(
96636
96616
  "button",
96637
96617
  {
96638
96618
  type: "button",
@@ -96782,7 +96762,7 @@ function removeHotspot(manifest, sceneId, hotspotId, sequenceId) {
96782
96762
  }
96783
96763
 
96784
96764
  // src/components/panels/SlideshowPanel.tsx
96785
- import { Fragment as Fragment65, jsx as jsx236, jsxs as jsxs187 } from "react/jsx-runtime";
96765
+ import { Fragment as Fragment65, jsx as jsx237, jsxs as jsxs188 } from "react/jsx-runtime";
96786
96766
  function safeParseManifest(html2) {
96787
96767
  try {
96788
96768
  return parseSlideshowManifest(html2) ?? { slides: [] };
@@ -97050,7 +97030,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97050
97030
  },
97051
97031
  [selectedSequenceId, applyManifest]
97052
97032
  );
97053
- return /* @__PURE__ */ jsxs187(
97033
+ return /* @__PURE__ */ jsxs188(
97054
97034
  "div",
97055
97035
  {
97056
97036
  className: "flex flex-col h-full overflow-y-auto text-text-0",
@@ -97061,14 +97041,14 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97061
97041
  handleUndo();
97062
97042
  },
97063
97043
  children: [
97064
- persistError && /* @__PURE__ */ jsxs187(
97044
+ persistError && /* @__PURE__ */ jsxs188(
97065
97045
  "div",
97066
97046
  {
97067
97047
  role: "alert",
97068
97048
  className: "flex items-center justify-between gap-2 px-3 py-2 bg-danger/15 border-b border-red-500/40",
97069
97049
  children: [
97070
- /* @__PURE__ */ jsx236("span", { className: "text-[11px] text-danger-ink", children: "Changes not saved" }),
97071
- /* @__PURE__ */ jsx236(
97050
+ /* @__PURE__ */ jsx237("span", { className: "text-[11px] text-danger-ink", children: "Changes not saved" }),
97051
+ /* @__PURE__ */ jsx237(
97072
97052
  "button",
97073
97053
  {
97074
97054
  type: "button",
@@ -97081,7 +97061,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97081
97061
  ]
97082
97062
  }
97083
97063
  ),
97084
- undoDepth > 0 && /* @__PURE__ */ jsx236("div", { className: "flex items-center justify-end px-3 py-1 border-b border-neutral-800/60", children: /* @__PURE__ */ jsxs187(
97064
+ undoDepth > 0 && /* @__PURE__ */ jsx237("div", { className: "flex items-center justify-end px-3 py-1 border-b border-neutral-800/60", children: /* @__PURE__ */ jsxs188(
97085
97065
  "button",
97086
97066
  {
97087
97067
  type: "button",
@@ -97095,7 +97075,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97095
97075
  ]
97096
97076
  }
97097
97077
  ) }),
97098
- /* @__PURE__ */ jsxs187(
97078
+ /* @__PURE__ */ jsxs188(
97099
97079
  SectionHeader,
97100
97080
  {
97101
97081
  expanded: expandedSections.has("slides"),
@@ -97107,7 +97087,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97107
97087
  ]
97108
97088
  }
97109
97089
  ),
97110
- expandedSections.has("slides") && /* @__PURE__ */ jsx236("div", { className: "py-1", children: /* @__PURE__ */ jsx236(
97090
+ expandedSections.has("slides") && /* @__PURE__ */ jsx237("div", { className: "py-1", children: /* @__PURE__ */ jsx237(
97111
97091
  SlideList,
97112
97092
  {
97113
97093
  scenes,
@@ -97121,7 +97101,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97121
97101
  onReorder: handleReorder
97122
97102
  }
97123
97103
  ) }),
97124
- /* @__PURE__ */ jsx236(
97104
+ /* @__PURE__ */ jsx237(
97125
97105
  SectionHeader,
97126
97106
  {
97127
97107
  expanded: expandedSections.has("inspector"),
@@ -97129,7 +97109,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97129
97109
  children: "Slide Inspector"
97130
97110
  }
97131
97111
  ),
97132
- expandedSections.has("inspector") && /* @__PURE__ */ jsx236(Fragment65, { children: selectedSceneId ? /* @__PURE__ */ jsx236(
97112
+ expandedSections.has("inspector") && /* @__PURE__ */ jsx237(Fragment65, { children: selectedSceneId ? /* @__PURE__ */ jsx237(
97133
97113
  SlideInspector,
97134
97114
  {
97135
97115
  sceneId: selectedSceneId,
@@ -97139,8 +97119,8 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97139
97119
  onMarkFragment: handleMarkFragment,
97140
97120
  onRemoveFragment: handleRemoveFragment
97141
97121
  }
97142
- ) : /* @__PURE__ */ jsx236("p", { className: "px-3 py-2 text-[11px] text-neutral-500 italic", children: "Select a scene above to inspect" }) }),
97143
- /* @__PURE__ */ jsxs187(
97122
+ ) : /* @__PURE__ */ jsx237("p", { className: "px-3 py-2 text-[11px] text-neutral-500 italic", children: "Select a scene above to inspect" }) }),
97123
+ /* @__PURE__ */ jsxs188(
97144
97124
  SectionHeader,
97145
97125
  {
97146
97126
  expanded: expandedSections.has("branches"),
@@ -97152,7 +97132,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97152
97132
  ]
97153
97133
  }
97154
97134
  ),
97155
- expandedSections.has("branches") && /* @__PURE__ */ jsx236(
97135
+ expandedSections.has("branches") && /* @__PURE__ */ jsx237(
97156
97136
  BranchTree,
97157
97137
  {
97158
97138
  sequences,
@@ -97166,7 +97146,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97166
97146
  onSelectBranchSlide: handleSelectBranchSlide
97167
97147
  }
97168
97148
  ),
97169
- /* @__PURE__ */ jsx236(
97149
+ /* @__PURE__ */ jsx237(
97170
97150
  SectionHeader,
97171
97151
  {
97172
97152
  expanded: expandedSections.has("hotspot"),
@@ -97174,7 +97154,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97174
97154
  children: "Hotspot Tool"
97175
97155
  }
97176
97156
  ),
97177
- expandedSections.has("hotspot") && /* @__PURE__ */ jsx236(
97157
+ expandedSections.has("hotspot") && /* @__PURE__ */ jsx237(
97178
97158
  HotspotTool,
97179
97159
  {
97180
97160
  selectedSceneId,
@@ -97316,7 +97296,7 @@ function useEditVariablesInFile(deps) {
97316
97296
 
97317
97297
  // src/components/panels/VariablesDeclarationForm.tsx
97318
97298
  import { useState as useState157 } from "react";
97319
- import { jsx as jsx237, jsxs as jsxs188 } from "react/jsx-runtime";
97299
+ import { jsx as jsx238, jsxs as jsxs189 } from "react/jsx-runtime";
97320
97300
  var VARIABLE_TYPES = [
97321
97301
  "string",
97322
97302
  "number",
@@ -97418,8 +97398,8 @@ function declarationFromDraft(draft) {
97418
97398
  }
97419
97399
  }
97420
97400
  function Field({ label, children }) {
97421
- return /* @__PURE__ */ jsxs188("div", { className: "space-y-1", children: [
97422
- /* @__PURE__ */ jsx237("label", { className: "text-[9px] font-medium text-neutral-500", children: label }),
97401
+ return /* @__PURE__ */ jsxs189("div", { className: "space-y-1", children: [
97402
+ /* @__PURE__ */ jsx238("label", { className: "text-[9px] font-medium text-neutral-500", children: label }),
97423
97403
  children
97424
97404
  ] });
97425
97405
  }
@@ -97428,20 +97408,20 @@ function DefaultField({
97428
97408
  onChange
97429
97409
  }) {
97430
97410
  if (draft.type === "boolean") {
97431
- return /* @__PURE__ */ jsxs188(
97411
+ return /* @__PURE__ */ jsxs189(
97432
97412
  "select",
97433
97413
  {
97434
97414
  value: draft.defaultRaw === "true" ? "true" : "false",
97435
97415
  onChange: (e) => onChange(e.target.value),
97436
97416
  className: VARIABLES_INPUT_CLASS,
97437
97417
  children: [
97438
- /* @__PURE__ */ jsx237("option", { value: "false", children: "false" }),
97439
- /* @__PURE__ */ jsx237("option", { value: "true", children: "true" })
97418
+ /* @__PURE__ */ jsx238("option", { value: "false", children: "false" }),
97419
+ /* @__PURE__ */ jsx238("option", { value: "true", children: "true" })
97440
97420
  ]
97441
97421
  }
97442
97422
  );
97443
97423
  }
97444
- return /* @__PURE__ */ jsx237(
97424
+ return /* @__PURE__ */ jsx238(
97445
97425
  "input",
97446
97426
  {
97447
97427
  type: "text",
@@ -97470,9 +97450,9 @@ function DeclarationForm({
97470
97450
  setError(null);
97471
97451
  onSubmit(result);
97472
97452
  };
97473
- return /* @__PURE__ */ jsxs188("div", { className: "space-y-2 rounded-lg border border-neutral-800 bg-neutral-900/60 p-2", children: [
97474
- /* @__PURE__ */ jsxs188("div", { className: "grid grid-cols-2 gap-2", children: [
97475
- /* @__PURE__ */ jsx237(Field, { label: "ID", children: /* @__PURE__ */ jsx237(
97453
+ return /* @__PURE__ */ jsxs189("div", { className: "space-y-2 rounded-lg border border-neutral-800 bg-neutral-900/60 p-2", children: [
97454
+ /* @__PURE__ */ jsxs189("div", { className: "grid grid-cols-2 gap-2", children: [
97455
+ /* @__PURE__ */ jsx238(Field, { label: "ID", children: /* @__PURE__ */ jsx238(
97476
97456
  "input",
97477
97457
  {
97478
97458
  type: "text",
@@ -97483,7 +97463,7 @@ function DeclarationForm({
97483
97463
  className: `${VARIABLES_INPUT_CLASS} font-mono disabled:opacity-50`
97484
97464
  }
97485
97465
  ) }),
97486
- /* @__PURE__ */ jsx237(Field, { label: "Label", children: /* @__PURE__ */ jsx237(
97466
+ /* @__PURE__ */ jsx238(Field, { label: "Label", children: /* @__PURE__ */ jsx238(
97487
97467
  "input",
97488
97468
  {
97489
97469
  type: "text",
@@ -97494,8 +97474,8 @@ function DeclarationForm({
97494
97474
  }
97495
97475
  ) })
97496
97476
  ] }),
97497
- /* @__PURE__ */ jsxs188("div", { className: "grid grid-cols-2 gap-2", children: [
97498
- /* @__PURE__ */ jsx237(Field, { label: "Type", children: /* @__PURE__ */ jsx237(
97477
+ /* @__PURE__ */ jsxs189("div", { className: "grid grid-cols-2 gap-2", children: [
97478
+ /* @__PURE__ */ jsx238(Field, { label: "Type", children: /* @__PURE__ */ jsx238(
97499
97479
  "select",
97500
97480
  {
97501
97481
  value: draft.type,
@@ -97504,12 +97484,12 @@ function DeclarationForm({
97504
97484
  if (type) set({ type });
97505
97485
  },
97506
97486
  className: VARIABLES_INPUT_CLASS,
97507
- children: VARIABLE_TYPES.map((t2) => /* @__PURE__ */ jsx237("option", { value: t2, children: t2 }, t2))
97487
+ children: VARIABLE_TYPES.map((t2) => /* @__PURE__ */ jsx238("option", { value: t2, children: t2 }, t2))
97508
97488
  }
97509
97489
  ) }),
97510
- /* @__PURE__ */ jsx237(Field, { label: "Default", children: /* @__PURE__ */ jsx237(DefaultField, { draft, onChange: (defaultRaw) => set({ defaultRaw }) }) })
97490
+ /* @__PURE__ */ jsx238(Field, { label: "Default", children: /* @__PURE__ */ jsx238(DefaultField, { draft, onChange: (defaultRaw) => set({ defaultRaw }) }) })
97511
97491
  ] }),
97512
- draft.type === "number" && /* @__PURE__ */ jsx237("div", { className: "grid grid-cols-3 gap-2", children: ["min", "max", "step"].map((key2) => /* @__PURE__ */ jsx237(Field, { label: key2, children: /* @__PURE__ */ jsx237(
97492
+ draft.type === "number" && /* @__PURE__ */ jsx238("div", { className: "grid grid-cols-3 gap-2", children: ["min", "max", "step"].map((key2) => /* @__PURE__ */ jsx238(Field, { label: key2, children: /* @__PURE__ */ jsx238(
97513
97493
  "input",
97514
97494
  {
97515
97495
  type: "text",
@@ -97518,7 +97498,7 @@ function DeclarationForm({
97518
97498
  className: `${VARIABLES_INPUT_CLASS} tabular-nums`
97519
97499
  }
97520
97500
  ) }, key2)) }),
97521
- draft.type === "enum" && /* @__PURE__ */ jsx237(Field, { label: "Options (one per line, value:Label)", children: /* @__PURE__ */ jsx237(
97501
+ draft.type === "enum" && /* @__PURE__ */ jsx238(Field, { label: "Options (one per line, value:Label)", children: /* @__PURE__ */ jsx238(
97522
97502
  "textarea",
97523
97503
  {
97524
97504
  value: draft.optionsRaw,
@@ -97527,7 +97507,7 @@ function DeclarationForm({
97527
97507
  className: `${VARIABLES_INPUT_CLASS} resize-y font-mono`
97528
97508
  }
97529
97509
  ) }),
97530
- /* @__PURE__ */ jsx237(Field, { label: "Description (optional)", children: /* @__PURE__ */ jsx237(
97510
+ /* @__PURE__ */ jsx238(Field, { label: "Description (optional)", children: /* @__PURE__ */ jsx238(
97531
97511
  "input",
97532
97512
  {
97533
97513
  type: "text",
@@ -97536,9 +97516,9 @@ function DeclarationForm({
97536
97516
  className: VARIABLES_INPUT_CLASS
97537
97517
  }
97538
97518
  ) }),
97539
- error && /* @__PURE__ */ jsx237("p", { className: "text-[10px] text-danger-ink", children: error }),
97540
- /* @__PURE__ */ jsxs188("div", { className: "flex items-center justify-end gap-2 pt-1", children: [
97541
- /* @__PURE__ */ jsx237(
97519
+ error && /* @__PURE__ */ jsx238("p", { className: "text-[10px] text-danger-ink", children: error }),
97520
+ /* @__PURE__ */ jsxs189("div", { className: "flex items-center justify-end gap-2 pt-1", children: [
97521
+ /* @__PURE__ */ jsx238(
97542
97522
  "button",
97543
97523
  {
97544
97524
  type: "button",
@@ -97547,7 +97527,7 @@ function DeclarationForm({
97547
97527
  children: "Cancel"
97548
97528
  }
97549
97529
  ),
97550
- /* @__PURE__ */ jsx237(
97530
+ /* @__PURE__ */ jsx238(
97551
97531
  "button",
97552
97532
  {
97553
97533
  type: "button",
@@ -97561,14 +97541,14 @@ function DeclarationForm({
97561
97541
  }
97562
97542
 
97563
97543
  // src/components/panels/VariablesRowAction.tsx
97564
- import { jsx as jsx238 } from "react/jsx-runtime";
97544
+ import { jsx as jsx239 } from "react/jsx-runtime";
97565
97545
  function RowAction({
97566
97546
  label,
97567
97547
  title,
97568
97548
  danger,
97569
97549
  onClick
97570
97550
  }) {
97571
- return /* @__PURE__ */ jsx238(
97551
+ return /* @__PURE__ */ jsx239(
97572
97552
  "button",
97573
97553
  {
97574
97554
  type: "button",
@@ -97581,7 +97561,7 @@ function RowAction({
97581
97561
  }
97582
97562
 
97583
97563
  // src/components/panels/VariablesOtherCompositions.tsx
97584
- import { jsx as jsx239, jsxs as jsxs189 } from "react/jsx-runtime";
97564
+ import { jsx as jsx240, jsxs as jsxs190 } from "react/jsx-runtime";
97585
97565
  function CompositionSection({
97586
97566
  group,
97587
97567
  editingKey,
@@ -97589,8 +97569,8 @@ function CompositionSection({
97589
97569
  onSave,
97590
97570
  onRemove
97591
97571
  }) {
97592
- return /* @__PURE__ */ jsxs189("div", { className: "space-y-1.5", children: [
97593
- /* @__PURE__ */ jsx239(
97572
+ return /* @__PURE__ */ jsxs190("div", { className: "space-y-1.5", children: [
97573
+ /* @__PURE__ */ jsx240(
97594
97574
  "p",
97595
97575
  {
97596
97576
  className: "truncate text-[9px] font-medium uppercase tracking-wider text-neutral-500",
@@ -97601,12 +97581,12 @@ function CompositionSection({
97601
97581
  group.variables.map((decl) => {
97602
97582
  const key2 = `${group.path}::${decl.id}`;
97603
97583
  const editing = editingKey === key2;
97604
- return /* @__PURE__ */ jsxs189("div", { className: "space-y-1.5 rounded-lg border border-neutral-800/70 p-2", children: [
97605
- /* @__PURE__ */ jsxs189("div", { className: "flex items-center gap-1.5", children: [
97606
- /* @__PURE__ */ jsx239("span", { className: "truncate text-[10px] font-medium text-neutral-300", children: decl.label }),
97607
- /* @__PURE__ */ jsx239("span", { className: "rounded-sm bg-neutral-800 px-1 py-px font-mono text-[8px] text-neutral-500", children: decl.type }),
97608
- /* @__PURE__ */ jsxs189("span", { className: "ml-auto flex items-center gap-1", children: [
97609
- /* @__PURE__ */ jsx239(
97584
+ return /* @__PURE__ */ jsxs190("div", { className: "space-y-1.5 rounded-lg border border-neutral-800/70 p-2", children: [
97585
+ /* @__PURE__ */ jsxs190("div", { className: "flex items-center gap-1.5", children: [
97586
+ /* @__PURE__ */ jsx240("span", { className: "truncate text-[10px] font-medium text-neutral-300", children: decl.label }),
97587
+ /* @__PURE__ */ jsx240("span", { className: "rounded-sm bg-neutral-800 px-1 py-px font-mono text-[8px] text-neutral-500", children: decl.type }),
97588
+ /* @__PURE__ */ jsxs190("span", { className: "ml-auto flex items-center gap-1", children: [
97589
+ /* @__PURE__ */ jsx240(
97610
97590
  RowAction,
97611
97591
  {
97612
97592
  label: "Edit",
@@ -97614,7 +97594,7 @@ function CompositionSection({
97614
97594
  onClick: () => onToggleEdit(editing ? null : key2)
97615
97595
  }
97616
97596
  ),
97617
- /* @__PURE__ */ jsx239(
97597
+ /* @__PURE__ */ jsx240(
97618
97598
  RowAction,
97619
97599
  {
97620
97600
  label: "\u2715",
@@ -97625,8 +97605,8 @@ function CompositionSection({
97625
97605
  )
97626
97606
  ] })
97627
97607
  ] }),
97628
- decl.description && /* @__PURE__ */ jsx239("p", { className: "text-[9px] text-neutral-500", children: decl.description }),
97629
- editing && /* @__PURE__ */ jsx239(
97608
+ decl.description && /* @__PURE__ */ jsx240("p", { className: "text-[9px] text-neutral-500", children: decl.description }),
97609
+ editing && /* @__PURE__ */ jsx240(
97630
97610
  DeclarationForm,
97631
97611
  {
97632
97612
  initial: draftFromDeclaration(decl),
@@ -97684,9 +97664,9 @@ function VariablesOtherCompositions({
97684
97664
  [editInFile]
97685
97665
  );
97686
97666
  if (groups.length === 0) return null;
97687
- return /* @__PURE__ */ jsxs189("div", { className: "space-y-3 border-t border-neutral-800 pt-3", children: [
97688
- /* @__PURE__ */ jsx239("p", { className: "text-[9px] font-medium uppercase tracking-wider text-neutral-600", children: "Other compositions" }),
97689
- groups.map((group) => /* @__PURE__ */ jsx239(
97667
+ return /* @__PURE__ */ jsxs190("div", { className: "space-y-3 border-t border-neutral-800 pt-3", children: [
97668
+ /* @__PURE__ */ jsx240("p", { className: "text-[9px] font-medium uppercase tracking-wider text-neutral-600", children: "Other compositions" }),
97669
+ groups.map((group) => /* @__PURE__ */ jsx240(
97690
97670
  CompositionSection,
97691
97671
  {
97692
97672
  group,
@@ -97702,7 +97682,7 @@ function VariablesOtherCompositions({
97702
97682
 
97703
97683
  // src/components/panels/VariablesPanel.tsx
97704
97684
  import { isScalarVariableValue as isScalar } from "@hyperframes/core/variables";
97705
- import { jsx as jsx240, jsxs as jsxs190 } from "react/jsx-runtime";
97685
+ import { jsx as jsx241, jsxs as jsxs191 } from "react/jsx-runtime";
97706
97686
  function shellSingleQuote(value) {
97707
97687
  return `'${value.replace(/'/g, `'\\''`)}'`;
97708
97688
  }
@@ -97718,7 +97698,7 @@ function formatIssue(issue) {
97718
97698
  }
97719
97699
  function ValidationStrip({ issues }) {
97720
97700
  if (issues.length === 0) return null;
97721
- return /* @__PURE__ */ jsx240("div", { className: "space-y-1 rounded-lg border border-danger/40 bg-danger/15 p-2", children: issues.map((issue) => /* @__PURE__ */ jsx240("p", { className: "text-[10px] text-danger-ink", children: formatIssue(issue) }, `${issue.kind}:${issue.variableId}`)) });
97701
+ return /* @__PURE__ */ jsx241("div", { className: "space-y-1 rounded-lg border border-danger/40 bg-danger/15 p-2", children: issues.map((issue) => /* @__PURE__ */ jsx241("p", { className: "text-[10px] text-danger-ink", children: formatIssue(issue) }, `${issue.kind}:${issue.variableId}`)) });
97722
97702
  }
97723
97703
  function VariableRow({
97724
97704
  decl,
@@ -97732,11 +97712,11 @@ function VariableRow({
97732
97712
  onSaveEdit,
97733
97713
  onRemove
97734
97714
  }) {
97735
- return /* @__PURE__ */ jsxs190("div", { className: "space-y-1.5 rounded-lg border border-neutral-800/70 p-2", children: [
97736
- /* @__PURE__ */ jsxs190("div", { className: "flex items-center gap-1.5", children: [
97737
- /* @__PURE__ */ jsx240("span", { className: "truncate text-[10px] font-medium text-neutral-300", children: decl.label }),
97738
- /* @__PURE__ */ jsx240("span", { className: "rounded-sm bg-neutral-800 px-1 py-px font-mono text-[8px] text-neutral-500", children: decl.type }),
97739
- unused && /* @__PURE__ */ jsx240(
97715
+ return /* @__PURE__ */ jsxs191("div", { className: "space-y-1.5 rounded-lg border border-neutral-800/70 p-2", children: [
97716
+ /* @__PURE__ */ jsxs191("div", { className: "flex items-center gap-1.5", children: [
97717
+ /* @__PURE__ */ jsx241("span", { className: "truncate text-[10px] font-medium text-neutral-300", children: decl.label }),
97718
+ /* @__PURE__ */ jsx241("span", { className: "rounded-sm bg-neutral-800 px-1 py-px font-mono text-[8px] text-neutral-500", children: decl.type }),
97719
+ unused && /* @__PURE__ */ jsx241(
97740
97720
  "span",
97741
97721
  {
97742
97722
  className: "rounded-sm bg-amber-500/15 px-1 py-px text-[8px] text-warning-ink",
@@ -97744,9 +97724,9 @@ function VariableRow({
97744
97724
  children: "unused"
97745
97725
  }
97746
97726
  ),
97747
- overridden && /* @__PURE__ */ jsx240("span", { className: "h-1.5 w-1.5 rounded-full bg-studio-accent" }),
97748
- /* @__PURE__ */ jsxs190("span", { className: "ml-auto flex items-center gap-1", children: [
97749
- overridden && isScalar(value) && /* @__PURE__ */ jsx240(
97727
+ overridden && /* @__PURE__ */ jsx241("span", { className: "h-1.5 w-1.5 rounded-full bg-studio-accent" }),
97728
+ /* @__PURE__ */ jsxs191("span", { className: "ml-auto flex items-center gap-1", children: [
97729
+ overridden && isScalar(value) && /* @__PURE__ */ jsx241(
97750
97730
  RowAction,
97751
97731
  {
97752
97732
  label: "Set default",
@@ -97754,12 +97734,12 @@ function VariableRow({
97754
97734
  onClick: () => onSetDefault(value)
97755
97735
  }
97756
97736
  ),
97757
- /* @__PURE__ */ jsx240(RowAction, { label: "Edit", title: "Edit declaration", onClick: onToggleEdit }),
97758
- /* @__PURE__ */ jsx240(RowAction, { label: "\u2715", title: "Remove declaration", danger: true, onClick: onRemove })
97737
+ /* @__PURE__ */ jsx241(RowAction, { label: "Edit", title: "Edit declaration", onClick: onToggleEdit }),
97738
+ /* @__PURE__ */ jsx241(RowAction, { label: "\u2715", title: "Remove declaration", danger: true, onClick: onRemove })
97759
97739
  ] })
97760
97740
  ] }),
97761
- decl.description && /* @__PURE__ */ jsx240("p", { className: "text-[9px] text-neutral-500", children: decl.description }),
97762
- editing ? /* @__PURE__ */ jsx240(
97741
+ decl.description && /* @__PURE__ */ jsx241("p", { className: "text-[9px] text-neutral-500", children: decl.description }),
97742
+ editing ? /* @__PURE__ */ jsx241(
97763
97743
  DeclarationForm,
97764
97744
  {
97765
97745
  initial: draftFromDeclaration(decl),
@@ -97767,7 +97747,7 @@ function VariableRow({
97767
97747
  onSubmit: (edited) => onSaveEdit(mergeDeclarationEdit(decl, edited)),
97768
97748
  onCancel: onToggleEdit
97769
97749
  }
97770
- ) : /* @__PURE__ */ jsx240(PreviewValueControl, { decl, value, onCommit: onCommitPreview })
97750
+ ) : /* @__PURE__ */ jsx241(PreviewValueControl, { decl, value, onCommit: onCommitPreview })
97771
97751
  ] });
97772
97752
  }
97773
97753
  function UndeclaredReads({
@@ -97775,11 +97755,11 @@ function UndeclaredReads({
97775
97755
  onDeclare
97776
97756
  }) {
97777
97757
  if (!usage || usage.undeclaredReads.length === 0) return null;
97778
- return /* @__PURE__ */ jsxs190("div", { className: "space-y-1 rounded-lg border border-neutral-800/70 bg-neutral-900/40 p-2", children: [
97779
- /* @__PURE__ */ jsx240("p", { className: "text-[9px] font-medium uppercase tracking-wider text-neutral-500", children: "Read by scripts, not declared" }),
97780
- usage.undeclaredReads.map((id) => /* @__PURE__ */ jsxs190("div", { className: "flex items-center gap-2", children: [
97781
- /* @__PURE__ */ jsx240("code", { className: "font-mono text-[10px] text-neutral-400", children: id }),
97782
- /* @__PURE__ */ jsx240(
97758
+ return /* @__PURE__ */ jsxs191("div", { className: "space-y-1 rounded-lg border border-neutral-800/70 bg-neutral-900/40 p-2", children: [
97759
+ /* @__PURE__ */ jsx241("p", { className: "text-[9px] font-medium uppercase tracking-wider text-neutral-500", children: "Read by scripts, not declared" }),
97760
+ usage.undeclaredReads.map((id) => /* @__PURE__ */ jsxs191("div", { className: "flex items-center gap-2", children: [
97761
+ /* @__PURE__ */ jsx241("code", { className: "font-mono text-[10px] text-neutral-400", children: id }),
97762
+ /* @__PURE__ */ jsx241(
97783
97763
  RowAction,
97784
97764
  {
97785
97765
  label: "Declare",
@@ -97795,10 +97775,10 @@ function PreviewModeHeader({
97795
97775
  onReset
97796
97776
  }) {
97797
97777
  const hasOverrides = overrideCount > 0;
97798
- return /* @__PURE__ */ jsxs190("div", { className: "flex items-center justify-between border-b border-neutral-800 px-3 py-2", children: [
97799
- /* @__PURE__ */ jsxs190("div", { className: "flex items-center gap-2", children: [
97800
- /* @__PURE__ */ jsx240("span", { className: "text-[11px] font-semibold text-neutral-200", children: "Variables" }),
97801
- /* @__PURE__ */ jsx240(
97778
+ return /* @__PURE__ */ jsxs191("div", { className: "flex items-center justify-between border-b border-neutral-800 px-3 py-2", children: [
97779
+ /* @__PURE__ */ jsxs191("div", { className: "flex items-center gap-2", children: [
97780
+ /* @__PURE__ */ jsx241("span", { className: "text-[11px] font-semibold text-neutral-200", children: "Variables" }),
97781
+ /* @__PURE__ */ jsx241(
97802
97782
  "span",
97803
97783
  {
97804
97784
  className: `rounded-full px-2 py-0.5 text-[9px] font-medium ${hasOverrides ? "bg-studio-accent/20 text-accent-ink" : "bg-neutral-800 text-neutral-500"}`,
@@ -97806,7 +97786,7 @@ function PreviewModeHeader({
97806
97786
  }
97807
97787
  )
97808
97788
  ] }),
97809
- hasOverrides && /* @__PURE__ */ jsx240(
97789
+ hasOverrides && /* @__PURE__ */ jsx241(
97810
97790
  "button",
97811
97791
  {
97812
97792
  type: "button",
@@ -97824,11 +97804,11 @@ function HandoffFooter({
97824
97804
  }) {
97825
97805
  const json = JSON.stringify(effectiveValues);
97826
97806
  const command = `npx hyperframes render ${shellSingleQuote(compPath)} --variables ${shellSingleQuote(json)}`;
97827
- return /* @__PURE__ */ jsxs190("div", { className: "space-y-1.5 rounded-lg border border-neutral-800/70 bg-neutral-900/40 p-2", children: [
97828
- /* @__PURE__ */ jsx240("p", { className: "text-[9px] font-medium uppercase tracking-wider text-neutral-500", children: "Use this template" }),
97829
- /* @__PURE__ */ jsx240("code", { className: "block truncate font-mono text-[9px] text-neutral-500", title: command, children: command }),
97830
- /* @__PURE__ */ jsxs190("div", { className: "flex items-center gap-2", children: [
97831
- /* @__PURE__ */ jsx240(
97807
+ return /* @__PURE__ */ jsxs191("div", { className: "space-y-1.5 rounded-lg border border-neutral-800/70 bg-neutral-900/40 p-2", children: [
97808
+ /* @__PURE__ */ jsx241("p", { className: "text-[9px] font-medium uppercase tracking-wider text-neutral-500", children: "Use this template" }),
97809
+ /* @__PURE__ */ jsx241("code", { className: "block truncate font-mono text-[9px] text-neutral-500", title: command, children: command }),
97810
+ /* @__PURE__ */ jsxs191("div", { className: "flex items-center gap-2", children: [
97811
+ /* @__PURE__ */ jsx241(
97832
97812
  RowAction,
97833
97813
  {
97834
97814
  label: "Copy render command",
@@ -97836,7 +97816,7 @@ function HandoffFooter({
97836
97816
  onClick: () => onCopy(command, "Render command")
97837
97817
  }
97838
97818
  ),
97839
- /* @__PURE__ */ jsx240(
97819
+ /* @__PURE__ */ jsx241(
97840
97820
  RowAction,
97841
97821
  {
97842
97822
  label: "Copy values JSON",
@@ -97847,15 +97827,15 @@ function HandoffFooter({
97847
97827
  ] })
97848
97828
  ] });
97849
97829
  }
97850
- var EMPTY_STATE = /* @__PURE__ */ jsxs190("p", { className: "text-[10px] leading-relaxed text-neutral-500", children: [
97830
+ var EMPTY_STATE = /* @__PURE__ */ jsxs191("p", { className: "text-[10px] leading-relaxed text-neutral-500", children: [
97851
97831
  "No variables declared. Variables make parts of this composition dynamic \u2014 declare them here (or in ",
97852
- /* @__PURE__ */ jsx240("code", { className: "font-mono", children: "data-composition-variables" }),
97832
+ /* @__PURE__ */ jsx241("code", { className: "font-mono", children: "data-composition-variables" }),
97853
97833
  "), read them with",
97854
97834
  " ",
97855
- /* @__PURE__ */ jsx240("code", { className: "font-mono", children: "getVariables()" }),
97835
+ /* @__PURE__ */ jsx241("code", { className: "font-mono", children: "getVariables()" }),
97856
97836
  ", and pass values at render time with",
97857
97837
  " ",
97858
- /* @__PURE__ */ jsx240("code", { className: "font-mono", children: "--variables" }),
97838
+ /* @__PURE__ */ jsx241("code", { className: "font-mono", children: "--variables" }),
97859
97839
  "."
97860
97840
  ] });
97861
97841
  var VariablesPanel = memo59(function VariablesPanel2({
@@ -98039,18 +98019,18 @@ var VariablesPanel = memo59(function VariablesPanel2({
98039
98019
  );
98040
98020
  const bindableSelection = domEditSelection?.hfId && domEditSelection.sourceFile === (activeCompPath ?? "index.html") ? domEditSelection : null;
98041
98021
  if (!sdkSession) {
98042
- return /* @__PURE__ */ jsx240("div", { className: "flex h-full items-center justify-center px-6 text-center", children: /* @__PURE__ */ jsx240("p", { className: "text-xs text-neutral-500", children: "Open a composition to manage its variables." }) });
98022
+ return /* @__PURE__ */ jsx241("div", { className: "flex h-full items-center justify-center px-6 text-center", children: /* @__PURE__ */ jsx241("p", { className: "text-xs text-neutral-500", children: "Open a composition to manage its variables." }) });
98043
98023
  }
98044
- return /* @__PURE__ */ jsxs190("div", { className: "flex h-full flex-col", children: [
98045
- /* @__PURE__ */ jsx240(
98024
+ return /* @__PURE__ */ jsxs191("div", { className: "flex h-full flex-col", children: [
98025
+ /* @__PURE__ */ jsx241(
98046
98026
  PreviewModeHeader,
98047
98027
  {
98048
98028
  overrideCount: previewValues ? Object.keys(previewValues).length : 0,
98049
98029
  onReset: resetPreview
98050
98030
  }
98051
98031
  ),
98052
- /* @__PURE__ */ jsxs190("div", { className: "flex-1 space-y-3 overflow-y-auto p-3", children: [
98053
- bindableSelection && /* @__PURE__ */ jsx240(
98032
+ /* @__PURE__ */ jsxs191("div", { className: "flex-1 space-y-3 overflow-y-auto p-3", children: [
98033
+ bindableSelection && /* @__PURE__ */ jsx241(
98054
98034
  VariablesBindElement,
98055
98035
  {
98056
98036
  selection: bindableSelection,
@@ -98059,9 +98039,9 @@ var VariablesPanel = memo59(function VariablesPanel2({
98059
98039
  },
98060
98040
  bindableSelection.hfId
98061
98041
  ),
98062
- /* @__PURE__ */ jsx240(ValidationStrip, { issues }),
98042
+ /* @__PURE__ */ jsx241(ValidationStrip, { issues }),
98063
98043
  declarations.length === 0 && !addOpen && EMPTY_STATE,
98064
- declarations.map((decl) => /* @__PURE__ */ jsx240(
98044
+ declarations.map((decl) => /* @__PURE__ */ jsx241(
98065
98045
  VariableRow,
98066
98046
  {
98067
98047
  decl,
@@ -98077,15 +98057,15 @@ var VariablesPanel = memo59(function VariablesPanel2({
98077
98057
  },
98078
98058
  decl.id
98079
98059
  )),
98080
- /* @__PURE__ */ jsx240(
98060
+ /* @__PURE__ */ jsx241(
98081
98061
  UndeclaredReads,
98082
98062
  {
98083
98063
  usage,
98084
98064
  onDeclare: (id) => handleAdd({ id, type: "string", label: id, default: "" })
98085
98065
  }
98086
98066
  ),
98087
- usage?.scanIncomplete && /* @__PURE__ */ jsx240("p", { className: "text-[9px] text-neutral-600", children: "Scripts access variables dynamically \u2014 usage info may be incomplete." }),
98088
- declarations.length > 0 && /* @__PURE__ */ jsx240(
98067
+ usage?.scanIncomplete && /* @__PURE__ */ jsx241("p", { className: "text-[9px] text-neutral-600", children: "Scripts access variables dynamically \u2014 usage info may be incomplete." }),
98068
+ declarations.length > 0 && /* @__PURE__ */ jsx241(
98089
98069
  HandoffFooter,
98090
98070
  {
98091
98071
  effectiveValues,
@@ -98093,7 +98073,7 @@ var VariablesPanel = memo59(function VariablesPanel2({
98093
98073
  onCopy: copyToClipboard
98094
98074
  }
98095
98075
  ),
98096
- addOpen ? /* @__PURE__ */ jsx240(
98076
+ addOpen ? /* @__PURE__ */ jsx241(
98097
98077
  DeclarationForm,
98098
98078
  {
98099
98079
  initial: EMPTY_DRAFT,
@@ -98101,7 +98081,7 @@ var VariablesPanel = memo59(function VariablesPanel2({
98101
98081
  onSubmit: handleAdd,
98102
98082
  onCancel: () => setAddOpen(false)
98103
98083
  }
98104
- ) : /* @__PURE__ */ jsx240(
98084
+ ) : /* @__PURE__ */ jsx241(
98105
98085
  "button",
98106
98086
  {
98107
98087
  type: "button",
@@ -98110,7 +98090,7 @@ var VariablesPanel = memo59(function VariablesPanel2({
98110
98090
  children: "+ Add variable"
98111
98091
  }
98112
98092
  ),
98113
- /* @__PURE__ */ jsx240(
98093
+ /* @__PURE__ */ jsx241(
98114
98094
  VariablesOtherCompositions,
98115
98095
  {
98116
98096
  compositionPaths: compositions,
@@ -98243,7 +98223,7 @@ function useSlideshowTabState(params) {
98243
98223
 
98244
98224
  // src/components/DesignPanelPromoteProvider.tsx
98245
98225
  import { useCallback as useCallback185 } from "react";
98246
- import { jsx as jsx241 } from "react/jsx-runtime";
98226
+ import { jsx as jsx242 } from "react/jsx-runtime";
98247
98227
  function DesignPanelPromoteProvider({
98248
98228
  selection,
98249
98229
  projectId,
@@ -98273,7 +98253,7 @@ function DesignPanelPromoteProvider({
98273
98253
  (error) => showToast(getStudioSaveErrorMessage(error), "error"),
98274
98254
  [showToast]
98275
98255
  );
98276
- return /* @__PURE__ */ jsx241(
98256
+ return /* @__PURE__ */ jsx242(
98277
98257
  VariablePromoteProvider,
98278
98258
  {
98279
98259
  session: handle.session,
@@ -98578,7 +98558,7 @@ function useApplyColorGradingScope(recordEdit, reloadPreview) {
98578
98558
  }
98579
98559
 
98580
98560
  // src/components/StudioRightPanels.tsx
98581
- import { Fragment as Fragment66, jsx as jsx242, jsxs as jsxs191 } from "react/jsx-runtime";
98561
+ import { Fragment as Fragment66, jsx as jsx243, jsxs as jsxs192 } from "react/jsx-runtime";
98582
98562
  var seekToTime = (t2) => usePlayerStore.getState().requestSeek(t2);
98583
98563
  var StudioRightPanels = memo60(function StudioRightPanels2({
98584
98564
  activeBlockParams,
@@ -98707,7 +98687,7 @@ var StudioRightPanels = memo60(function StudioRightPanels2({
98707
98687
  (animId, duration) => handleGsapConvertToKeyframes(animId, void 0, duration),
98708
98688
  [handleGsapConvertToKeyframes]
98709
98689
  );
98710
- const propertyPanel = /* @__PURE__ */ jsx242(
98690
+ const propertyPanel = /* @__PURE__ */ jsx243(
98711
98691
  DesignPanelPromoteProvider,
98712
98692
  {
98713
98693
  selection: domEditGroupSelections.length > 1 ? null : domEditSelection,
@@ -98719,7 +98699,7 @@ var StudioRightPanels = memo60(function StudioRightPanels2({
98719
98699
  recordEdit,
98720
98700
  reloadPreview,
98721
98701
  forceReloadSharedSdkSession: forceReloadSdkSession,
98722
- children: /* @__PURE__ */ jsx242(
98702
+ children: /* @__PURE__ */ jsx243(
98723
98703
  PropertyPanel,
98724
98704
  {
98725
98705
  projectId,
@@ -98790,9 +98770,9 @@ var StudioRightPanels = memo60(function StudioRightPanels2({
98790
98770
  );
98791
98771
  let designBody = propertyPanel;
98792
98772
  if (captionEditMode) {
98793
- designBody = /* @__PURE__ */ jsx242(CaptionPropertyPanel, { iframeRef: previewIframeRef });
98773
+ designBody = /* @__PURE__ */ jsx243(CaptionPropertyPanel, { iframeRef: previewIframeRef });
98794
98774
  } else if (activeBlockParams) {
98795
- designBody = /* @__PURE__ */ jsx242(
98775
+ designBody = /* @__PURE__ */ jsx243(
98796
98776
  BlockParamsPanel,
98797
98777
  {
98798
98778
  blockName: activeBlockParams.blockName,
@@ -98804,18 +98784,18 @@ var StudioRightPanels = memo60(function StudioRightPanels2({
98804
98784
  }
98805
98785
  );
98806
98786
  }
98807
- return /* @__PURE__ */ jsxs191(Fragment66, { children: [
98808
- /* @__PURE__ */ jsx242(Dock.Panel, { id: "design", children: designBody }),
98809
- /* @__PURE__ */ jsx242(Dock.Panel, { id: "layers", children: /* @__PURE__ */ jsx242(LayersPanel, {}) }),
98810
- /* @__PURE__ */ jsx242(
98787
+ return /* @__PURE__ */ jsxs192(Fragment66, { children: [
98788
+ /* @__PURE__ */ jsx243(Dock.Panel, { id: "design", children: designBody }),
98789
+ /* @__PURE__ */ jsx243(Dock.Panel, { id: "layers", children: /* @__PURE__ */ jsx243(LayersPanel, {}) }),
98790
+ /* @__PURE__ */ jsx243(
98811
98791
  Dock.Panel,
98812
98792
  {
98813
98793
  id: "renders",
98814
98794
  title: renderJobs.length > 0 ? `Renders (${renderJobs.length})` : void 0,
98815
- children: /* @__PURE__ */ jsx242(RenderQueuePanel, {})
98795
+ children: /* @__PURE__ */ jsx243(RenderQueuePanel, {})
98816
98796
  }
98817
98797
  ),
98818
- /* @__PURE__ */ jsx242(Dock.Panel, { id: "variables", children: /* @__PURE__ */ jsx242(
98798
+ /* @__PURE__ */ jsx243(Dock.Panel, { id: "variables", children: /* @__PURE__ */ jsx243(
98819
98799
  VariablesPanel,
98820
98800
  {
98821
98801
  sdkSession,
@@ -98824,7 +98804,7 @@ var StudioRightPanels = memo60(function StudioRightPanels2({
98824
98804
  recordEdit
98825
98805
  }
98826
98806
  ) }),
98827
- /* @__PURE__ */ jsx242(Dock.Panel, { id: "slideshow", children: /* @__PURE__ */ jsx242(
98807
+ /* @__PURE__ */ jsx243(Dock.Panel, { id: "slideshow", children: /* @__PURE__ */ jsx243(
98828
98808
  SlideshowPanel,
98829
98809
  {
98830
98810
  scenes: slideshowScenes,
@@ -98836,14 +98816,14 @@ var StudioRightPanels = memo60(function StudioRightPanels2({
98836
98816
  });
98837
98817
 
98838
98818
  // src/hooks/useStudioSidePanels.tsx
98839
- import { Fragment as Fragment67, jsx as jsx243, jsxs as jsxs192 } from "react/jsx-runtime";
98819
+ import { Fragment as Fragment67, jsx as jsx244, jsxs as jsxs193 } from "react/jsx-runtime";
98840
98820
  function useStudioSidePanels(left, right, projectId) {
98841
98821
  const stableLeft = useStableHandlers(left, projectId);
98842
98822
  const stableRight = useStableHandlers(right, projectId);
98843
98823
  return useMemo88(
98844
- () => /* @__PURE__ */ jsxs192(Fragment67, { children: [
98845
- /* @__PURE__ */ jsx243(StudioLeftPanels, { ...stableLeft }),
98846
- /* @__PURE__ */ jsx243(StudioRightPanels, { ...stableRight })
98824
+ () => /* @__PURE__ */ jsxs193(Fragment67, { children: [
98825
+ /* @__PURE__ */ jsx244(StudioLeftPanels, { ...stableLeft }),
98826
+ /* @__PURE__ */ jsx244(StudioRightPanels, { ...stableRight })
98847
98827
  ] }),
98848
98828
  [stableLeft, stableRight]
98849
98829
  );
@@ -98882,9 +98862,9 @@ function useKeyframeKeyboard({ enabled, onAddKeyframe }) {
98882
98862
  }
98883
98863
 
98884
98864
  // src/components/icons/AudioMetersIcon.tsx
98885
- import { jsx as jsx244 } from "react/jsx-runtime";
98865
+ import { jsx as jsx245 } from "react/jsx-runtime";
98886
98866
  function AudioMetersIcon({ size = 16 }) {
98887
- return /* @__PURE__ */ jsx244(
98867
+ return /* @__PURE__ */ jsx245(
98888
98868
  "svg",
98889
98869
  {
98890
98870
  width: size,
@@ -98895,15 +98875,15 @@ function AudioMetersIcon({ size = 16 }) {
98895
98875
  strokeWidth: 1.5,
98896
98876
  strokeLinecap: "round",
98897
98877
  "aria-hidden": "true",
98898
- children: /* @__PURE__ */ jsx244("path", { d: "M2.5 13h2m-2-3h2M7 13h2m-2-3h2m-2-3h2m-2-3h2M11.5 13h2m-2-3h2m-2-3h2" })
98878
+ children: /* @__PURE__ */ jsx245("path", { d: "M2.5 13h2m-2-3h2M7 13h2m-2-3h2m-2-3h2m-2-3h2M11.5 13h2m-2-3h2m-2-3h2" })
98899
98879
  }
98900
98880
  );
98901
98881
  }
98902
98882
 
98903
98883
  // src/components/icons/RippleEditIcon.tsx
98904
- import { jsx as jsx245, jsxs as jsxs193 } from "react/jsx-runtime";
98884
+ import { jsx as jsx246, jsxs as jsxs194 } from "react/jsx-runtime";
98905
98885
  function RippleEditIcon({ size = 16 }) {
98906
- return /* @__PURE__ */ jsxs193(
98886
+ return /* @__PURE__ */ jsxs194(
98907
98887
  "svg",
98908
98888
  {
98909
98889
  width: size,
@@ -98916,20 +98896,20 @@ function RippleEditIcon({ size = 16 }) {
98916
98896
  strokeLinejoin: "round",
98917
98897
  "aria-hidden": "true",
98918
98898
  children: [
98919
- /* @__PURE__ */ jsx245("rect", { x: "1.5", y: "8", width: "4", height: "5", rx: "0.5" }),
98920
- /* @__PURE__ */ jsx245("rect", { x: "10.5", y: "8", width: "4", height: "5", rx: "0.5" }),
98921
- /* @__PURE__ */ jsx245("path", { d: "M13 4H6m2-2L6 4l2 2" })
98899
+ /* @__PURE__ */ jsx246("rect", { x: "1.5", y: "8", width: "4", height: "5", rx: "0.5" }),
98900
+ /* @__PURE__ */ jsx246("rect", { x: "10.5", y: "8", width: "4", height: "5", rx: "0.5" }),
98901
+ /* @__PURE__ */ jsx246("path", { d: "M13 4H6m2-2L6 4l2 2" })
98922
98902
  ]
98923
98903
  }
98924
98904
  );
98925
98905
  }
98926
98906
 
98927
98907
  // src/components/TimelineHistoryButtons.tsx
98928
- import { Fragment as Fragment68, jsx as jsx246, jsxs as jsxs194 } from "react/jsx-runtime";
98908
+ import { Fragment as Fragment68, jsx as jsx247, jsxs as jsxs195 } from "react/jsx-runtime";
98929
98909
  function HistoryButton({ action, can, label, onClick }) {
98930
98910
  const Icon = action === "undo" ? RotateCcw : RotateCw;
98931
98911
  const enabled = Boolean(onClick) && can;
98932
- return /* @__PURE__ */ jsx246(Tooltip, { label: historyTooltipLabel(action, label), children: /* @__PURE__ */ jsx246(
98912
+ return /* @__PURE__ */ jsx247(Tooltip, { label: historyTooltipLabel(action, label), children: /* @__PURE__ */ jsx247(
98933
98913
  "button",
98934
98914
  {
98935
98915
  type: "button",
@@ -98940,7 +98920,7 @@ function HistoryButton({ action, can, label, onClick }) {
98940
98920
  trackStudioEvent("toolbar_action", { action });
98941
98921
  void onClick?.();
98942
98922
  },
98943
- children: /* @__PURE__ */ jsx246(Icon, { size: 16 })
98923
+ children: /* @__PURE__ */ jsx247(Icon, { size: 16 })
98944
98924
  }
98945
98925
  ) });
98946
98926
  }
@@ -98948,8 +98928,8 @@ function TimelineHistoryButtons(props) {
98948
98928
  const shell = useStudioShellContextOptional();
98949
98929
  const onUndo = props.onUndo ?? shell?.handleUndo;
98950
98930
  const onRedo = props.onRedo ?? shell?.handleRedo;
98951
- return /* @__PURE__ */ jsxs194(Fragment68, { children: [
98952
- /* @__PURE__ */ jsx246(
98931
+ return /* @__PURE__ */ jsxs195(Fragment68, { children: [
98932
+ /* @__PURE__ */ jsx247(
98953
98933
  HistoryButton,
98954
98934
  {
98955
98935
  action: "undo",
@@ -98958,7 +98938,7 @@ function TimelineHistoryButtons(props) {
98958
98938
  onClick: onUndo
98959
98939
  }
98960
98940
  ),
98961
- /* @__PURE__ */ jsx246(
98941
+ /* @__PURE__ */ jsx247(
98962
98942
  HistoryButton,
98963
98943
  {
98964
98944
  action: "redo",
@@ -98972,9 +98952,9 @@ function TimelineHistoryButtons(props) {
98972
98952
 
98973
98953
  // src/components/TimelineToolPicker.tsx
98974
98954
  import { ArrowLineLeft, ArrowLineRight, CaretDown } from "@phosphor-icons/react";
98975
- import { jsx as jsx247, jsxs as jsxs195 } from "react/jsx-runtime";
98955
+ import { jsx as jsx248, jsxs as jsxs196 } from "react/jsx-runtime";
98976
98956
  function SelectIcon() {
98977
- return /* @__PURE__ */ jsx247("svg", { width: "16", height: "16", viewBox: "0 0 12 12", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx247("path", { d: "M2 0.5L10 6L6.5 6.5L8.5 11L6.5 11.5L4.5 7L2 9Z" }) });
98957
+ return /* @__PURE__ */ jsx248("svg", { width: "16", height: "16", viewBox: "0 0 12 12", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx248("path", { d: "M2 0.5L10 6L6.5 6.5L8.5 11L6.5 11.5L4.5 7L2 9Z" }) });
98978
98958
  }
98979
98959
  function TimelineToolPicker({ showSelectAroundPlayhead = true }) {
98980
98960
  const activeTool = usePlayerStore((s) => s.activeTool);
@@ -98983,14 +98963,14 @@ function TimelineToolPicker({ showSelectAroundPlayhead = true }) {
98983
98963
  {
98984
98964
  label: "Select",
98985
98965
  shortcut: "V",
98986
- icon: /* @__PURE__ */ jsx247(SelectIcon, {}),
98966
+ icon: /* @__PURE__ */ jsx248(SelectIcon, {}),
98987
98967
  active: activeTool === "select",
98988
98968
  run: () => store().setActiveTool("select")
98989
98969
  },
98990
98970
  {
98991
98971
  label: "Split",
98992
98972
  shortcut: "B",
98993
- icon: /* @__PURE__ */ jsx247(Scissors, { size: 16 }),
98973
+ icon: /* @__PURE__ */ jsx248(Scissors, { size: 16 }),
98994
98974
  active: activeTool === "razor",
98995
98975
  run: () => store().setActiveTool("razor")
98996
98976
  }
@@ -99000,25 +98980,25 @@ function TimelineToolPicker({ showSelectAroundPlayhead = true }) {
99000
98980
  {
99001
98981
  label: "Select leftward",
99002
98982
  shortcut: "[",
99003
- icon: /* @__PURE__ */ jsx247(ArrowLineLeft, { size: 16, "aria-hidden": "true" }),
98983
+ icon: /* @__PURE__ */ jsx248(ArrowLineLeft, { size: 16, "aria-hidden": "true" }),
99004
98984
  active: false,
99005
98985
  run: () => store().selectLeftward()
99006
98986
  },
99007
98987
  {
99008
98988
  label: "Select rightward",
99009
98989
  shortcut: "]",
99010
- icon: /* @__PURE__ */ jsx247(ArrowLineRight, { size: 16, "aria-hidden": "true" }),
98990
+ icon: /* @__PURE__ */ jsx248(ArrowLineRight, { size: 16, "aria-hidden": "true" }),
99011
98991
  active: false,
99012
98992
  run: () => store().selectRightward()
99013
98993
  }
99014
98994
  );
99015
98995
  }
99016
98996
  const current = rows.find((row) => row.active) ?? rows[0];
99017
- return /* @__PURE__ */ jsx247(
98997
+ return /* @__PURE__ */ jsx248(
99018
98998
  Menu,
99019
98999
  {
99020
99000
  "aria-label": "Timeline tools",
99021
- trigger: /* @__PURE__ */ jsxs195(
99001
+ trigger: /* @__PURE__ */ jsxs196(
99022
99002
  "button",
99023
99003
  {
99024
99004
  type: "button",
@@ -99026,18 +99006,18 @@ function TimelineToolPicker({ showSelectAroundPlayhead = true }) {
99026
99006
  className: cn(flatIdle, "gap-0.5"),
99027
99007
  children: [
99028
99008
  current.icon,
99029
- /* @__PURE__ */ jsx247(CaretDown, { size: 10, weight: "bold", "aria-hidden": "true" })
99009
+ /* @__PURE__ */ jsx248(CaretDown, { size: 10, weight: "bold", "aria-hidden": "true" })
99030
99010
  ]
99031
99011
  }
99032
99012
  ),
99033
- children: rows.map((row) => /* @__PURE__ */ jsx247(
99013
+ children: rows.map((row) => /* @__PURE__ */ jsx248(
99034
99014
  MenuItem,
99035
99015
  {
99036
99016
  shortcut: row.shortcut,
99037
99017
  onClick: row.run,
99038
99018
  "data-active": row.active || void 0,
99039
99019
  className: row.active ? "bg-press text-text-0" : void 0,
99040
- children: /* @__PURE__ */ jsxs195("span", { className: "flex items-center gap-2", children: [
99020
+ children: /* @__PURE__ */ jsxs196("span", { className: "flex items-center gap-2", children: [
99041
99021
  row.icon,
99042
99022
  row.label
99043
99023
  ] })
@@ -99052,14 +99032,14 @@ function TimelineToolPicker({ showSelectAroundPlayhead = true }) {
99052
99032
  import { useCallback as useCallback190, useState as useState160 } from "react";
99053
99033
  import { createPortal as createPortal15 } from "react-dom";
99054
99034
  import { LinkSimple } from "@phosphor-icons/react";
99055
- import { Fragment as Fragment69, jsx as jsx248, jsxs as jsxs196 } from "react/jsx-runtime";
99035
+ import { Fragment as Fragment69, jsx as jsx249, jsxs as jsxs197 } from "react/jsx-runtime";
99056
99036
  function SyncIndicatorMenu({ x, y, onClose }) {
99057
99037
  const menuRef = useContextMenuDismiss(onClose);
99058
99038
  useMenuKeyboardNav(menuRef);
99059
99039
  const visible = useLinkedClipPreferences((s) => s.syncIndicatorsVisible);
99060
99040
  const setVisible = useLinkedClipPreferences((s) => s.setSyncIndicatorsVisible);
99061
99041
  return createPortal15(
99062
- /* @__PURE__ */ jsx248(
99042
+ /* @__PURE__ */ jsx249(
99063
99043
  "div",
99064
99044
  {
99065
99045
  ref: menuRef,
@@ -99067,7 +99047,7 @@ function SyncIndicatorMenu({ x, y, onClose }) {
99067
99047
  "aria-label": "Linked clips",
99068
99048
  className: `${menuClasses.panel} fixed z-200 min-w-[200px]`,
99069
99049
  style: { left: x, top: y },
99070
- children: /* @__PURE__ */ jsxs196(
99050
+ children: /* @__PURE__ */ jsxs197(
99071
99051
  "button",
99072
99052
  {
99073
99053
  type: "button",
@@ -99079,7 +99059,7 @@ function SyncIndicatorMenu({ x, y, onClose }) {
99079
99059
  onClose();
99080
99060
  },
99081
99061
  children: [
99082
- /* @__PURE__ */ jsx248("span", { className: "w-3 text-studio-accent", children: visible ? "\u2713" : "" }),
99062
+ /* @__PURE__ */ jsx249("span", { className: "w-3 text-studio-accent", children: visible ? "\u2713" : "" }),
99083
99063
  "Show out-of-sync indicators"
99084
99064
  ]
99085
99065
  }
@@ -99094,12 +99074,12 @@ function LinkedSelectionToggle() {
99094
99074
  const setLinkedSelection = useLinkedClipPreferences((s) => s.setLinkedSelection);
99095
99075
  const [menuAt, setMenuAt] = useState160(null);
99096
99076
  const closeMenu = useCallback190(() => setMenuAt(null), []);
99097
- return /* @__PURE__ */ jsxs196(Fragment69, { children: [
99098
- /* @__PURE__ */ jsx248(
99077
+ return /* @__PURE__ */ jsxs197(Fragment69, { children: [
99078
+ /* @__PURE__ */ jsx249(
99099
99079
  Tooltip,
99100
99080
  {
99101
99081
  label: linkedSelection ? "Linked Selection on \u2014 a click selects both halves (\u2325-click for one)" : "Linked Selection off \u2014 a click selects one clip",
99102
- children: /* @__PURE__ */ jsx248(
99082
+ children: /* @__PURE__ */ jsx249(
99103
99083
  "button",
99104
99084
  {
99105
99085
  type: "button",
@@ -99111,17 +99091,17 @@ function LinkedSelectionToggle() {
99111
99091
  "aria-label": "Linked Selection",
99112
99092
  "aria-pressed": linkedSelection,
99113
99093
  className: linkedSelection ? flatActive : flatIdle,
99114
- children: /* @__PURE__ */ jsx248(LinkSimple, { size: 16, weight: "bold", "aria-hidden": "true" })
99094
+ children: /* @__PURE__ */ jsx249(LinkSimple, { size: 16, weight: "bold", "aria-hidden": "true" })
99115
99095
  }
99116
99096
  )
99117
99097
  }
99118
99098
  ),
99119
- menuAt && /* @__PURE__ */ jsx248(SyncIndicatorMenu, { x: menuAt.x, y: menuAt.y, onClose: closeMenu })
99099
+ menuAt && /* @__PURE__ */ jsx249(SyncIndicatorMenu, { x: menuAt.x, y: menuAt.y, onClose: closeMenu })
99120
99100
  ] });
99121
99101
  }
99122
99102
 
99123
99103
  // src/components/TimelineToolbar.tsx
99124
- import { Fragment as Fragment70, jsx as jsx249, jsxs as jsxs197 } from "react/jsx-runtime";
99104
+ import { Fragment as Fragment70, jsx as jsx250, jsxs as jsxs198 } from "react/jsx-runtime";
99125
99105
  var NO_KEYFRAME_TOGGLE = {
99126
99106
  state: "none",
99127
99107
  isMotionPath: false,
@@ -99234,13 +99214,13 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99234
99214
  window.addEventListener("keydown", onKeyDown);
99235
99215
  return () => window.removeEventListener("keydown", onKeyDown);
99236
99216
  }, []);
99237
- return /* @__PURE__ */ jsx249("div", { className: "border-b border-neutral-800/60", children: /* @__PURE__ */ jsxs197("div", { className: "flex items-center justify-between px-2 py-0.5", children: [
99238
- /* @__PURE__ */ jsxs197("div", { className: "flex items-center gap-0.5", children: [
99239
- showHistory && /* @__PURE__ */ jsx249(TimelineHistoryButtons, { ...history2 }),
99240
- /* @__PURE__ */ jsx249(TimelineToolPicker, { showSelectAroundPlayhead }),
99241
- /* @__PURE__ */ jsx249("div", { "aria-hidden": "true", className: "mx-1 h-4 w-px bg-neutral-800" }),
99242
- /* @__PURE__ */ jsx249(LinkedSelectionToggle, {}),
99243
- /* @__PURE__ */ jsx249(Tooltip, { label: timelineSnapEnabled ? "Snapping on (N)" : "Snapping off (N)", children: /* @__PURE__ */ jsx249(
99217
+ return /* @__PURE__ */ jsx250("div", { className: "border-b border-neutral-800/60", children: /* @__PURE__ */ jsxs198("div", { className: "flex items-center justify-between px-2 py-0.5", children: [
99218
+ /* @__PURE__ */ jsxs198("div", { className: "flex items-center gap-0.5", children: [
99219
+ showHistory && /* @__PURE__ */ jsx250(TimelineHistoryButtons, { ...history2 }),
99220
+ /* @__PURE__ */ jsx250(TimelineToolPicker, { showSelectAroundPlayhead }),
99221
+ /* @__PURE__ */ jsx250("div", { "aria-hidden": "true", className: "mx-1 h-4 w-px bg-neutral-800" }),
99222
+ /* @__PURE__ */ jsx250(LinkedSelectionToggle, {}),
99223
+ /* @__PURE__ */ jsx250(Tooltip, { label: timelineSnapEnabled ? "Snapping on (N)" : "Snapping off (N)", children: /* @__PURE__ */ jsx250(
99244
99224
  "button",
99245
99225
  {
99246
99226
  type: "button",
@@ -99248,14 +99228,14 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99248
99228
  "aria-label": "Toggle timeline snapping",
99249
99229
  "aria-pressed": timelineSnapEnabled,
99250
99230
  className: timelineSnapEnabled ? flatActive : flatIdle,
99251
- children: /* @__PURE__ */ jsx249(Magnet, { size: 16, weight: "bold", "aria-hidden": "true" })
99231
+ children: /* @__PURE__ */ jsx250(Magnet, { size: 16, weight: "bold", "aria-hidden": "true" })
99252
99232
  }
99253
99233
  ) }),
99254
- /* @__PURE__ */ jsx249(
99234
+ /* @__PURE__ */ jsx250(
99255
99235
  Tooltip,
99256
99236
  {
99257
99237
  label: rippleEditEnabled ? "Ripple on \u2014 keeps the main track gapless" : "Ripple off \u2014 deleting a main-track clip leaves a gap",
99258
- children: /* @__PURE__ */ jsx249(
99238
+ children: /* @__PURE__ */ jsx250(
99259
99239
  "button",
99260
99240
  {
99261
99241
  type: "button",
@@ -99263,12 +99243,12 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99263
99243
  "aria-label": "Toggle ripple edit",
99264
99244
  "aria-pressed": rippleEditEnabled,
99265
99245
  className: rippleEditEnabled ? flatActive : flatIdle,
99266
- children: /* @__PURE__ */ jsx249(RippleEditIcon, { size: 16 })
99246
+ children: /* @__PURE__ */ jsx250(RippleEditIcon, { size: 16 })
99267
99247
  }
99268
99248
  )
99269
99249
  }
99270
99250
  ),
99271
- projectHasAudio && /* @__PURE__ */ jsx249(Tooltip, { label: audioMetersVisible ? "Hide audio meters" : "Show audio meters", children: /* @__PURE__ */ jsx249(
99251
+ projectHasAudio && /* @__PURE__ */ jsx250(Tooltip, { label: audioMetersVisible ? "Hide audio meters" : "Show audio meters", children: /* @__PURE__ */ jsx250(
99272
99252
  "button",
99273
99253
  {
99274
99254
  type: "button",
@@ -99276,15 +99256,15 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99276
99256
  "aria-label": "Toggle audio meters",
99277
99257
  "aria-pressed": audioMetersVisible,
99278
99258
  className: audioMetersVisible ? flatActive : flatIdle,
99279
- children: /* @__PURE__ */ jsx249(AudioMetersIcon, { size: 16 })
99259
+ children: /* @__PURE__ */ jsx250(AudioMetersIcon, { size: 16 })
99280
99260
  }
99281
99261
  ) }),
99282
- showKeyframes && /* @__PURE__ */ jsxs197(Fragment70, { children: [
99283
- /* @__PURE__ */ jsx249(
99262
+ showKeyframes && /* @__PURE__ */ jsxs198(Fragment70, { children: [
99263
+ /* @__PURE__ */ jsx250(
99284
99264
  Tooltip,
99285
99265
  {
99286
99266
  label: keyframePathEndpoint ? "Motion path endpoints cannot be removed" : !onToggleKeyframe ? "Select an animated element to add keyframes" : keyframeIsMotionPath ? keyframeWillExtend ? "Extend motion path to playhead (K)" : keyframeState === "active" ? "Remove waypoint from motion path (K)" : "Add waypoint to motion path (K)" : keyframeState === "active" ? "Remove keyframe at playhead (K)" : keyframeState === "inactive" ? keyframeWillExtend ? "Add keyframe at playhead, extends animation (K)" : "Add keyframe at playhead (K)" : "Add keyframe (K)",
99287
- children: /* @__PURE__ */ jsx249(
99267
+ children: /* @__PURE__ */ jsx250(
99288
99268
  "button",
99289
99269
  {
99290
99270
  type: "button",
@@ -99292,7 +99272,7 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99292
99272
  onClick: onToggleKeyframe,
99293
99273
  "aria-label": keyframePathEndpoint ? "Motion path endpoint" : keyframeIsMotionPath ? keyframeState === "active" ? "Remove motion path waypoint" : keyframeWillExtend ? "Extend motion path to playhead" : "Add motion path waypoint" : keyframeState === "active" ? "Remove keyframe at playhead" : "Add keyframe at playhead",
99294
99274
  className: !onToggleKeyframe ? flatDisabled : `${flatBtn} active:scale-[0.98] hover:bg-hover ${keyframeState === "active" ? "text-accent-ink" : keyframeState === "inactive" ? "text-neutral-400 hover:text-accent-ink" : "text-neutral-600 hover:text-neutral-400"}`,
99295
- children: /* @__PURE__ */ jsx249("svg", { width: "16", height: "16", viewBox: "0 0 10 10", fill: "currentColor", children: keyframeState === "active" ? /* @__PURE__ */ jsx249("path", { d: "M5 0.5L9.5 5L5 9.5L0.5 5Z" }) : /* @__PURE__ */ jsx249(
99275
+ children: /* @__PURE__ */ jsx250("svg", { width: "16", height: "16", viewBox: "0 0 10 10", fill: "currentColor", children: keyframeState === "active" ? /* @__PURE__ */ jsx250("path", { d: "M5 0.5L9.5 5L5 9.5L0.5 5Z" }) : /* @__PURE__ */ jsx250(
99296
99276
  "path",
99297
99277
  {
99298
99278
  d: "M5 1.2L8.8 5L5 8.8L1.2 5Z",
@@ -99305,11 +99285,11 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99305
99285
  )
99306
99286
  }
99307
99287
  ),
99308
- /* @__PURE__ */ jsx249(
99288
+ /* @__PURE__ */ jsx250(
99309
99289
  Tooltip,
99310
99290
  {
99311
99291
  label: autoKeyframeEnabled ? "Auto-record manual edits as keyframes (click to turn off)" : "Manual edits will not be recorded as keyframes (click to turn on)",
99312
- children: /* @__PURE__ */ jsx249(
99292
+ children: /* @__PURE__ */ jsx250(
99313
99293
  "button",
99314
99294
  {
99315
99295
  type: "button",
@@ -99317,9 +99297,9 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99317
99297
  "aria-label": "Auto-record manual edits as keyframes",
99318
99298
  "aria-pressed": autoKeyframeEnabled,
99319
99299
  className: `${flatBtn} active:scale-[0.98] hover:bg-hover ${autoKeyframeEnabled ? "text-danger-ink" : "text-neutral-600 hover:text-neutral-400"}`,
99320
- children: /* @__PURE__ */ jsxs197("svg", { width: "16", height: "16", viewBox: "0 0 10 10", fill: "none", children: [
99321
- /* @__PURE__ */ jsx249("path", { d: "M5 0.7L9.3 5L5 9.3L0.7 5Z", stroke: "currentColor", strokeWidth: "1" }),
99322
- /* @__PURE__ */ jsx249(
99300
+ children: /* @__PURE__ */ jsxs198("svg", { width: "16", height: "16", viewBox: "0 0 10 10", fill: "none", children: [
99301
+ /* @__PURE__ */ jsx250("path", { d: "M5 0.7L9.3 5L5 9.3L0.7 5Z", stroke: "currentColor", strokeWidth: "1" }),
99302
+ /* @__PURE__ */ jsx250(
99323
99303
  "circle",
99324
99304
  {
99325
99305
  cx: "5",
@@ -99340,11 +99320,11 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99340
99320
  const el = selectedElementId ? elements.find((e) => (e.key ?? e.id) === selectedElementId) : null;
99341
99321
  const splittable = el != null && canSplitElement(el);
99342
99322
  const canSplit = splittable && currentTime > el.start && currentTime < el.start + el.duration;
99343
- return /* @__PURE__ */ jsx249(
99323
+ return /* @__PURE__ */ jsx250(
99344
99324
  Tooltip,
99345
99325
  {
99346
99326
  label: canSplit ? `Split at playhead (${splitShortcut})` : splittable ? "Move the playhead inside the clip to split" : "Select a clip to split",
99347
- children: /* @__PURE__ */ jsx249(
99327
+ children: /* @__PURE__ */ jsx250(
99348
99328
  "button",
99349
99329
  {
99350
99330
  type: "button",
@@ -99354,7 +99334,7 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99354
99334
  if (canSplit && el) onSplitElement(el, currentTime);
99355
99335
  },
99356
99336
  className: canSplit ? flatIdle : flatDisabled,
99357
- children: /* @__PURE__ */ jsxs197(
99337
+ children: /* @__PURE__ */ jsxs198(
99358
99338
  "svg",
99359
99339
  {
99360
99340
  width: "16",
@@ -99367,8 +99347,8 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99367
99347
  strokeLinejoin: "round",
99368
99348
  "aria-hidden": "true",
99369
99349
  children: [
99370
- /* @__PURE__ */ jsx249("path", { d: "M5 3 L7 3 L7 13 L5 13" }),
99371
- /* @__PURE__ */ jsx249("path", { d: "M11 3 L9 3 L9 13 L11 13" })
99350
+ /* @__PURE__ */ jsx250("path", { d: "M5 3 L7 3 L7 13 L5 13" }),
99351
+ /* @__PURE__ */ jsx250("path", { d: "M11 3 L9 3 L9 13 L11 13" })
99372
99352
  ]
99373
99353
  }
99374
99354
  )
@@ -99380,11 +99360,11 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99380
99360
  (() => {
99381
99361
  if (!showAddBeat) return null;
99382
99362
  const canAdd = beatAnalysisReady && canAddBeatAt(currentTime);
99383
- return /* @__PURE__ */ jsx249(
99363
+ return /* @__PURE__ */ jsx250(
99384
99364
  Tooltip,
99385
99365
  {
99386
99366
  label: !beatAnalysisReady ? "Add a music track with beat analysis to place beats" : canAdd ? "Add beat at playhead" : "A beat already exists at the playhead",
99387
- children: /* @__PURE__ */ jsx249(
99367
+ children: /* @__PURE__ */ jsx250(
99388
99368
  "button",
99389
99369
  {
99390
99370
  type: "button",
@@ -99394,7 +99374,7 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99394
99374
  if (canAdd) addBeatAtCompositionTime(currentTime);
99395
99375
  },
99396
99376
  className: canAdd ? `${flatBtn} text-text-2 hover:bg-hover hover:text-accent-ink active:scale-[0.98]` : flatDisabled,
99397
- children: /* @__PURE__ */ jsx249("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx249(
99377
+ children: /* @__PURE__ */ jsx250("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx250(
99398
99378
  "path",
99399
99379
  {
99400
99380
  d: "M21 10C21 12.2091 16.9706 14 12 14M21 10C21 7.79086 16.9706 6 12 6C7.02944 6 3 7.79086 3 10M21 10V16C21 18.2091 16.9706 20 12 20M12 14C7.02944 14 3 12.2091 3 10M12 14V20M3 10V16C3 18.2091 7.02944 20 12 20M7 19.3264V13.3264M17 19.3264V13.3264M12 10L20 4",
@@ -99410,13 +99390,13 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99410
99390
  );
99411
99391
  })()
99412
99392
  ] }),
99413
- /* @__PURE__ */ jsxs197("div", { className: "flex items-center gap-0.5", children: [
99393
+ /* @__PURE__ */ jsxs198("div", { className: "flex items-center gap-0.5", children: [
99414
99394
  rightActions,
99415
- /* @__PURE__ */ jsx249(
99395
+ /* @__PURE__ */ jsx250(
99416
99396
  Tooltip,
99417
99397
  {
99418
99398
  label: thumbnailsVisible ? "Hide thumbnails \u2014 labels only" : "Show thumbnails \u2014 posters stay visible; richer previews appear on interaction",
99419
- children: /* @__PURE__ */ jsx249(
99399
+ children: /* @__PURE__ */ jsx250(
99420
99400
  "button",
99421
99401
  {
99422
99402
  type: "button",
@@ -99424,12 +99404,12 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99424
99404
  "aria-pressed": thumbnailsVisible,
99425
99405
  onClick: () => setThumbnailMode(thumbnailsVisible ? "hidden" : "adaptive"),
99426
99406
  className: `h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${thumbnailsVisible ? "bg-studio-accent/10 text-accent-ink" : "text-neutral-400 hover:bg-hover hover:text-neutral-200"}`,
99427
- children: /* @__PURE__ */ jsx249(Image3, { size: 16, "aria-hidden": "true" })
99407
+ children: /* @__PURE__ */ jsx250(Image3, { size: 16, "aria-hidden": "true" })
99428
99408
  }
99429
99409
  )
99430
99410
  }
99431
99411
  ),
99432
- /* @__PURE__ */ jsx249(Tooltip, { label: "Fit timeline to width", children: /* @__PURE__ */ jsx249(
99412
+ /* @__PURE__ */ jsx250(Tooltip, { label: "Fit timeline to width", children: /* @__PURE__ */ jsx250(
99433
99413
  "button",
99434
99414
  {
99435
99415
  type: "button",
@@ -99437,20 +99417,20 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99437
99417
  "aria-label": "Fit timeline to width",
99438
99418
  "aria-pressed": zoomMode === "fit",
99439
99419
  className: `h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${zoomMode === "fit" ? "bg-studio-accent/10 text-accent-ink" : "text-neutral-400 hover:bg-hover hover:text-neutral-200"}`,
99440
- children: /* @__PURE__ */ jsx249(ArrowsOutLineHorizontal, { size: 16, "aria-hidden": "true" })
99420
+ children: /* @__PURE__ */ jsx250(ArrowsOutLineHorizontal, { size: 16, "aria-hidden": "true" })
99441
99421
  }
99442
99422
  ) }),
99443
- /* @__PURE__ */ jsx249(Tooltip, { label: "Zoom out", children: /* @__PURE__ */ jsx249(
99423
+ /* @__PURE__ */ jsx250(Tooltip, { label: "Zoom out", children: /* @__PURE__ */ jsx250(
99444
99424
  "button",
99445
99425
  {
99446
99426
  type: "button",
99447
99427
  "aria-label": "Zoom out",
99448
99428
  onClick: () => zoomTimelineStep("out"),
99449
99429
  className: flatIdle,
99450
- children: /* @__PURE__ */ jsx249(MagnifyingGlassMinus, { size: 16, "aria-hidden": "true" })
99430
+ children: /* @__PURE__ */ jsx250(MagnifyingGlassMinus, { size: 16, "aria-hidden": "true" })
99451
99431
  }
99452
99432
  ) }),
99453
- /* @__PURE__ */ jsx249(
99433
+ /* @__PURE__ */ jsx250(
99454
99434
  "input",
99455
99435
  {
99456
99436
  type: "range",
@@ -99465,17 +99445,17 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99465
99445
  className: "mx-1 h-6 w-[96px] cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-[2px] [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-neutral-700 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[10px] [&::-webkit-slider-thumb]:h-[10px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-text-0 [&::-webkit-slider-thumb]:-mt-1 [&::-webkit-slider-thumb]:shadow-[0_0_0_2px_#0a0a0a,0_1px_3px_rgba(0,0,0,0.5)] [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb:active]:cursor-grabbing"
99466
99446
  }
99467
99447
  ),
99468
- /* @__PURE__ */ jsx249(Tooltip, { label: "Zoom in", children: /* @__PURE__ */ jsx249(
99448
+ /* @__PURE__ */ jsx250(Tooltip, { label: "Zoom in", children: /* @__PURE__ */ jsx250(
99469
99449
  "button",
99470
99450
  {
99471
99451
  type: "button",
99472
99452
  "aria-label": "Zoom in",
99473
99453
  onClick: () => zoomTimelineStep("in"),
99474
99454
  className: flatIdle,
99475
- children: /* @__PURE__ */ jsx249(MagnifyingGlassPlus, { size: 16, "aria-hidden": "true" })
99455
+ children: /* @__PURE__ */ jsx250(MagnifyingGlassPlus, { size: 16, "aria-hidden": "true" })
99476
99456
  }
99477
99457
  ) }),
99478
- /* @__PURE__ */ jsx249(
99458
+ /* @__PURE__ */ jsx250(
99479
99459
  "span",
99480
99460
  {
99481
99461
  className: "ml-1 w-[38px] text-right font-mono text-[11px] tabular-nums text-neutral-500 select-none",
@@ -99488,18 +99468,18 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99488
99468
  });
99489
99469
 
99490
99470
  // src/components/StudioSplash.tsx
99491
- import { jsx as jsx250, jsxs as jsxs198 } from "react/jsx-runtime";
99471
+ import { jsx as jsx251, jsxs as jsxs199 } from "react/jsx-runtime";
99492
99472
  function StudioSplash({ waiting }) {
99493
- return /* @__PURE__ */ jsx250("div", { className: "h-full w-full bg-neutral-950 flex items-center justify-center", children: waiting ? /* @__PURE__ */ jsxs198("div", { className: "flex flex-col items-center gap-3 text-center px-6", role: "status", children: [
99494
- /* @__PURE__ */ jsx250("div", { className: "w-4 h-4 rounded-full border-2 border-neutral-700 border-t-neutral-500 animate-spin motion-reduce:animate-none" }),
99495
- /* @__PURE__ */ jsxs198("p", { className: "text-xs text-neutral-600", children: [
99473
+ return /* @__PURE__ */ jsx251("div", { className: "h-full w-full bg-neutral-950 flex items-center justify-center", children: waiting ? /* @__PURE__ */ jsxs199("div", { className: "flex flex-col items-center gap-3 text-center px-6", role: "status", children: [
99474
+ /* @__PURE__ */ jsx251("div", { className: "w-4 h-4 rounded-full border-2 border-neutral-700 border-t-neutral-500 animate-spin motion-reduce:animate-none" }),
99475
+ /* @__PURE__ */ jsxs199("p", { className: "text-xs text-neutral-600", children: [
99496
99476
  "Waiting for preview server\u2026 run",
99497
99477
  " ",
99498
- /* @__PURE__ */ jsx250("code", { className: "text-neutral-500 font-mono", children: "npm run dev" })
99478
+ /* @__PURE__ */ jsx251("code", { className: "text-neutral-500 font-mono", children: "npm run dev" })
99499
99479
  ] })
99500
- ] }) : /* @__PURE__ */ jsxs198("div", { className: "flex flex-col items-center gap-3 text-center px-6", role: "status", children: [
99501
- /* @__PURE__ */ jsx250("div", { className: "w-4 h-4 rounded-full bg-studio-accent animate-pulse motion-reduce:animate-none" }),
99502
- /* @__PURE__ */ jsx250("p", { className: "text-xs text-neutral-600", children: "Connecting to project\u2026" })
99480
+ ] }) : /* @__PURE__ */ jsxs199("div", { className: "flex flex-col items-center gap-3 text-center px-6", role: "status", children: [
99481
+ /* @__PURE__ */ jsx251("div", { className: "w-4 h-4 rounded-full bg-studio-accent animate-pulse motion-reduce:animate-none" }),
99482
+ /* @__PURE__ */ jsx251("p", { className: "text-xs text-neutral-600", children: "Connecting to project\u2026" })
99503
99483
  ] }) });
99504
99484
  }
99505
99485
 
@@ -99769,7 +99749,7 @@ function useActiveComposition({
99769
99749
  }
99770
99750
 
99771
99751
  // src/App.tsx
99772
- import { jsx as jsx251, jsxs as jsxs199 } from "react/jsx-runtime";
99752
+ import { jsx as jsx252, jsxs as jsxs200 } from "react/jsx-runtime";
99773
99753
  var getTimelineSelectionSet = () => usePlayerStore.getState().selectedElementIds;
99774
99754
  function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
99775
99755
  const { projectId, resolving, waitingForServer } = useServerConnection();
@@ -100140,7 +100120,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
100140
100120
  refreshPreviewDocumentVersion
100141
100121
  });
100142
100122
  const timelineToolbar = useMemo89(
100143
- () => /* @__PURE__ */ jsx251(
100123
+ () => /* @__PURE__ */ jsx252(
100144
100124
  TimelineToolbar,
100145
100125
  {
100146
100126
  domEditSession: toolbarSession,
@@ -100188,15 +100168,15 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
100188
100168
  projectId
100189
100169
  );
100190
100170
  if (resolving || waitingForServer || !projectId)
100191
- return /* @__PURE__ */ jsx251(StudioSplash, { waiting: waitingForServer });
100192
- return /* @__PURE__ */ jsx251(StudioShellProvider, { value: studioCtxValue, children: /* @__PURE__ */ jsx251(StudioPlaybackProvider, { value: studioCtxValue, children: /* @__PURE__ */ jsx251(PanelLayoutProvider, { value: layout, children: /* @__PURE__ */ jsx251(FileManagerProvider, { value: fileManager, children: /* @__PURE__ */ jsx251(DomEditProvider, { value: domEditSession, children: /* @__PURE__ */ jsxs199(
100171
+ return /* @__PURE__ */ jsx252(StudioSplash, { waiting: waitingForServer });
100172
+ return /* @__PURE__ */ jsx252(StudioShellProvider, { value: studioCtxValue, children: /* @__PURE__ */ jsx252(StudioPlaybackProvider, { value: studioCtxValue, children: /* @__PURE__ */ jsx252(PanelLayoutProvider, { value: layout, children: /* @__PURE__ */ jsx252(FileManagerProvider, { value: fileManager, children: /* @__PURE__ */ jsx252(DomEditProvider, { value: domEditSession, children: /* @__PURE__ */ jsxs200(
100193
100173
  "div",
100194
100174
  {
100195
100175
  className: "flex flex-col h-full w-full bg-neutral-950 relative",
100196
100176
  onDragOver: fileDrop.onDragOver,
100197
100177
  onDrop: fileDrop.onDrop,
100198
100178
  children: [
100199
- /* @__PURE__ */ jsx251(
100179
+ /* @__PURE__ */ jsx252(
100200
100180
  StudioHeader,
100201
100181
  {
100202
100182
  captureFrameHref: frameCapture.captureFrameHref,
@@ -100209,17 +100189,17 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
100209
100189
  onExport: handleExport
100210
100190
  }
100211
100191
  ),
100212
- previewPersistence.domEditSaveQueuePaused && !externalFileChanges.blocked && /* @__PURE__ */ jsx251(
100192
+ previewPersistence.domEditSaveQueuePaused && !externalFileChanges.blocked && /* @__PURE__ */ jsx252(
100213
100193
  SaveQueuePausedBanner,
100214
100194
  {
100215
100195
  message: previewPersistence.domEditSaveQueuePaused,
100216
100196
  onRetry: previewPersistence.resetDomEditSaveQueueBreaker
100217
100197
  }
100218
100198
  ),
100219
- /* @__PURE__ */ jsx251(ExternalFileConflictBanner, { coordinator: externalFileChanges }),
100220
- sdkHandle.unreachableProject && /* @__PURE__ */ jsx251(ProjectUnreachableBanner, { projectId: sdkHandle.unreachableProject }),
100221
- sdkHandle.compositionMissing && activeCompPath && /* @__PURE__ */ jsx251(CompositionMissingBanner, { path: activeCompPath }),
100222
- /* @__PURE__ */ jsx251(
100199
+ /* @__PURE__ */ jsx252(ExternalFileConflictBanner, { coordinator: externalFileChanges }),
100200
+ sdkHandle.unreachableProject && /* @__PURE__ */ jsx252(ProjectUnreachableBanner, { projectId: sdkHandle.unreachableProject }),
100201
+ sdkHandle.compositionMissing && activeCompPath && /* @__PURE__ */ jsx252(CompositionMissingBanner, { path: activeCompPath }),
100202
+ /* @__PURE__ */ jsx252(
100223
100203
  EditorShell,
100224
100204
  {
100225
100205
  readOnlyPreview,
@@ -100263,7 +100243,7 @@ function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason } = {}) {
100263
100243
  gestureOverlay
100264
100244
  }
100265
100245
  ),
100266
- /* @__PURE__ */ jsx251(
100246
+ /* @__PURE__ */ jsx252(
100267
100247
  StudioOverlays,
100268
100248
  {
100269
100249
  projectId,
@@ -100898,6 +100878,7 @@ export {
100898
100878
  Toggle,
100899
100879
  Tooltip,
100900
100880
  VideoThumbnail,
100881
+ announcePreviewDocumentLoaded,
100901
100882
  applyPatch,
100902
100883
  buildCompositionSnapTarget,
100903
100884
  buildGridSnapEdges,