@hyperframes/studio 0.8.145 → 0.8.146

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 (102) hide show
  1. package/dist/assets/{hyperframes-player-DZ5JrMDg.js → hyperframes-player-tkxyWf5H.js} +3 -3
  2. package/dist/assets/{index-BqFRhNZa.js → index-BrdqOkqP.js} +1 -1
  3. package/dist/assets/{index-D8W0a0Z9.js → index-Cg48BxAo.js} +135 -135
  4. package/dist/assets/{index-BOs6C0aZ.js → index-Dllxg4aU.js} +1 -1
  5. package/dist/{chunk-EEXSYY5F.js → chunk-C5BDT7NG.js} +0 -1
  6. package/dist/{chunk-TP6D3U37.js → chunk-HZDCMUG4.js} +1 -2
  7. package/dist/{chunk-PZ5AY32C.js → chunk-MLKGABMK.js} +0 -1
  8. package/dist/{chunk-NZPJUZKT.js → chunk-PHGBG7OG.js} +3 -4
  9. package/dist/{chunk-Y2OHHNM2.js → chunk-PVFBY7KR.js} +0 -1
  10. package/dist/{chunk-6JY3MTIX.js → chunk-T43DM7Q6.js} +2 -3
  11. package/dist/{domEditingLayers-PTP2ICGM.js → domEditingLayers-SMVA3FEW.js} +3 -4
  12. package/dist/index.css +0 -1
  13. package/dist/index.html +1 -1
  14. package/dist/index.js +106 -107
  15. package/dist/player.js +4 -5
  16. package/dist/styles/tailwind-preset.js +1 -2
  17. package/dist/ui.js +3 -4
  18. package/package.json +8 -8
  19. package/src/captions/components/CaptionOverlay.tsx +1 -1
  20. package/src/captions/hooks/useCaptionSync.ts +1 -1
  21. package/src/components/LinkedSelectionToggle.tsx +2 -2
  22. package/src/components/LintModal.tsx +1 -5
  23. package/src/components/MediaPreview.tsx +2 -2
  24. package/src/components/ProjectUnreachableBanner.tsx +1 -1
  25. package/src/components/StudioRightPanels.tsx +1 -1
  26. package/src/components/TimelineToolbar.test.tsx +2 -2
  27. package/src/components/TimelineToolbar.tsx +6 -6
  28. package/src/components/editor/AnimationCard.tsx +3 -3
  29. package/src/components/editor/AnimationCardParts.tsx +1 -1
  30. package/src/components/editor/BlockParamsPanel.tsx +3 -3
  31. package/src/components/editor/ComputedTweenNotice.tsx +2 -2
  32. package/src/components/editor/FileTree.tsx +1 -1
  33. package/src/components/editor/GsapAnimationList.tsx +1 -1
  34. package/src/components/editor/GsapAnimationSection.tsx +2 -2
  35. package/src/components/editor/OffCanvasIndicators.tsx +1 -1
  36. package/src/components/editor/PromotableControl.tsx +1 -1
  37. package/src/components/editor/PropertyPanel.tsx +2 -2
  38. package/src/components/editor/SnapToolbar.tsx +2 -2
  39. package/src/components/editor/Transform3DCube.tsx +1 -1
  40. package/src/components/editor/gsapAnimationConstants.ts +2 -2
  41. package/src/components/editor/gsapAnimationHelpers.test.ts +1 -1
  42. package/src/components/editor/gsapAnimationHelpers.ts +1 -1
  43. package/src/components/editor/propertyPanelColorGradingControls.tsx +1 -1
  44. package/src/components/editor/propertyPanelFill.tsx +1 -1
  45. package/src/components/editor/propertyPanelFlatMotionSection.tsx +3 -3
  46. package/src/components/editor/propertyPanelFlatPrimitives.tsx +2 -2
  47. package/src/components/editor/propertyPanelFlatSelectRow.tsx +1 -1
  48. package/src/components/editor/propertyPanelFlatTextSection.tsx +1 -1
  49. package/src/components/editor/propertyPanelFont.tsx +3 -3
  50. package/src/components/editor/propertyPanelFxBandRuler.tsx +2 -2
  51. package/src/components/editor/propertyPanelFxNodeOpenBody.tsx +2 -2
  52. package/src/components/editor/propertyPanelTimingSection.tsx +1 -1
  53. package/src/components/editor/propertyPanelTransformCommit.ts +3 -3
  54. package/src/components/editor/useColorGradingController.ts +1 -1
  55. package/src/components/panels/SlideshowSubPanels.tsx +2 -2
  56. package/src/components/panels/VariablesBindElement.tsx +1 -1
  57. package/src/components/panels/VariablesPanel.tsx +3 -3
  58. package/src/components/renders/RenderQueue.tsx +2 -2
  59. package/src/components/renders/useRenderQueue.ts +3 -3
  60. package/src/components/sidebar/AssetCard.tsx +2 -2
  61. package/src/components/sidebar/AudioRow.tsx +1 -1
  62. package/src/components/sidebar/BlocksTab.tsx +2 -2
  63. package/src/components/sidebar/CompositionsTab.tsx +2 -2
  64. package/src/components/sidebar/PromptPreviewModal.tsx +1 -1
  65. package/src/hooks/timelineAudioGroupCreate.ts +1 -1
  66. package/src/hooks/timelineEditingHelpers.ts +1 -1
  67. package/src/hooks/useBlockHandlers.ts +1 -1
  68. package/src/hooks/useDomEditSession.ts +1 -1
  69. package/src/hooks/useEditorSave.ts +1 -1
  70. package/src/hooks/useFrameCapture.ts +1 -1
  71. package/src/hooks/useGestureCommit.ts +4 -4
  72. package/src/hooks/useGsapScriptCommits.ts +1 -1
  73. package/src/player/components/AudioGainDialog.test.tsx +1 -1
  74. package/src/player/components/AudioGainDialog.tsx +2 -1
  75. package/src/player/components/EditModal.tsx +2 -2
  76. package/src/player/components/KeyframeDiamondContextMenu.tsx +1 -1
  77. package/src/player/components/OutOfSyncBadge.tsx +1 -1
  78. package/src/player/components/Player.tsx +1 -1
  79. package/src/player/components/ShortcutsPanel.tsx +2 -2
  80. package/src/player/components/Timeline.virtualization.test.tsx +1 -1
  81. package/src/player/components/TimelineAutomationLaneSlot.tsx +1 -1
  82. package/src/player/components/TimelineClip.tsx +1 -1
  83. package/src/player/components/TimelineFxButton.tsx +2 -2
  84. package/src/player/components/TimelineTrackHeader.test.tsx +3 -3
  85. package/src/player/components/timelineClipDragCommit.ts +2 -2
  86. package/src/player/components/trackHeaderLabelRows.tsx +1 -1
  87. package/src/player/lib/playbackAdapter.ts +1 -1
  88. package/src/utils/hmrStableContext.ts +1 -1
  89. package/src/utils/razorSplitTransaction.ts +0 -2
  90. package/src/utils/sdkCutover.linkedTiming.test.ts +1 -1
  91. package/dist/chunk-6JY3MTIX.js.map +0 -1
  92. package/dist/chunk-EEXSYY5F.js.map +0 -1
  93. package/dist/chunk-NZPJUZKT.js.map +0 -1
  94. package/dist/chunk-PZ5AY32C.js.map +0 -1
  95. package/dist/chunk-TP6D3U37.js.map +0 -1
  96. package/dist/chunk-Y2OHHNM2.js.map +0 -1
  97. package/dist/domEditingLayers-PTP2ICGM.js.map +0 -1
  98. package/dist/index.css.map +0 -1
  99. package/dist/index.js.map +0 -1
  100. package/dist/player.js.map +0 -1
  101. package/dist/styles/tailwind-preset.js.map +0 -1
  102. package/dist/ui.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HyperframesLogo
3
- } from "./chunk-EEXSYY5F.js";
3
+ } from "./chunk-C5BDT7NG.js";
4
4
  import {
5
5
  DOCK_PANEL_COMPONENT,
6
6
  PANEL_DEFINITIONS,
@@ -47,7 +47,7 @@ import {
47
47
  usePreviewVariablesStore,
48
48
  whenPreviewBooted,
49
49
  writeStudioUiPreferences
50
- } from "./chunk-NZPJUZKT.js";
50
+ } from "./chunk-PHGBG7OG.js";
51
51
  import {
52
52
  Button,
53
53
  ContextMenu,
@@ -79,7 +79,7 @@ import {
79
79
  fieldBase,
80
80
  fieldText,
81
81
  popupSurface
82
- } from "./chunk-Y2OHHNM2.js";
82
+ } from "./chunk-PVFBY7KR.js";
83
83
  import {
84
84
  DOM_EDIT_LAYER_OBSERVER_INIT,
85
85
  buildDefaultDomEditTextField,
@@ -105,7 +105,7 @@ import {
105
105
  resolveAllVisualDomEditTargets,
106
106
  resolveDomEditSelection,
107
107
  serializeDomEditTextFields
108
- } from "./chunk-TP6D3U37.js";
108
+ } from "./chunk-HZDCMUG4.js";
109
109
  import {
110
110
  LAYER_REVEAL_PRIOR_POSITION_ATTR,
111
111
  LAYER_REVEAL_PRIOR_Z_ATTR,
@@ -172,8 +172,8 @@ import {
172
172
  studioApiFetch,
173
173
  toHexColor,
174
174
  wrapTimeline
175
- } from "./chunk-6JY3MTIX.js";
176
- import "./chunk-PZ5AY32C.js";
175
+ } from "./chunk-T43DM7Q6.js";
176
+ import "./chunk-MLKGABMK.js";
177
177
 
178
178
  // src/components/EditorShell.tsx
179
179
  import { memo as memo34, useCallback as useCallback74 } from "react";
@@ -878,7 +878,7 @@ var ShortcutsPanel = memo(function ShortcutsPanel2({
878
878
  )
879
879
  }
880
880
  ) })
881
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-600", children: "\u2014" }) })
881
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-600", children: "Not set" }) })
882
882
  ] }),
883
883
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
884
884
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -908,7 +908,7 @@ var ShortcutsPanel = memo(function ShortcutsPanel2({
908
908
  )
909
909
  }
910
910
  ) })
911
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-600", children: "\u2014" }) })
911
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-600", children: "Not set" }) })
912
912
  ] })
913
913
  ] })
914
914
  ] }),
@@ -1469,7 +1469,7 @@ function createStableContext(name, defaultValue) {
1469
1469
  const store = registry();
1470
1470
  if (store.has(name) && seenNames.get(name) !== defaultValue) {
1471
1471
  console.warn(
1472
- `[hmrStableContext] "${name}" was registered twice with different defaults \u2014 two contexts are sharing one identity. Use module path + export name.`
1472
+ `[hmrStableContext] "${name}" was registered twice with different defaults: two contexts are sharing one identity. Use module path + export name.`
1473
1473
  );
1474
1474
  }
1475
1475
  seenNames.set(name, defaultValue);
@@ -6001,7 +6001,7 @@ var METHOD_LABELS = {
6001
6001
  fromTo: "From \u2192 To"
6002
6002
  };
6003
6003
  var METHOD_TOOLTIPS = {
6004
- set: "Instantly snap to these values \u2014 no transition",
6004
+ set: "Instantly snap to these values, no transition",
6005
6005
  to: "Smoothly animate the element to these target values",
6006
6006
  from: "Element starts at these values and transitions to its normal state",
6007
6007
  fromTo: "Animate from one state to another"
@@ -6071,7 +6071,7 @@ var PROP_TOOLTIPS = {
6071
6071
  rotationY: "Rotate around the vertical Y axis",
6072
6072
  rotationZ: "Rotate around the screen-facing Z axis",
6073
6073
  perspective: "3D depth context for child elements; set it on a parent when rotating children in 3D",
6074
- transformPerspective: "3D depth for THIS element's own X/Y rotation \u2014 lower = stronger perspective (try 600\u20131000)",
6074
+ transformPerspective: "3D depth for THIS element's own X/Y rotation: lower = stronger perspective (try 600 to 1000)",
6075
6075
  transformOrigin: "Pivot point for transforms, for example center center or 50% 50%",
6076
6076
  width: "Element width",
6077
6077
  height: "Element height",
@@ -10139,7 +10139,7 @@ function persistMoveEdits(edits, deps, coalesceKey, operation = "timing") {
10139
10139
  const { updateElement, onMoveElement, onMoveElements } = deps;
10140
10140
  if (!onMoveElements) {
10141
10141
  console.warn(
10142
- onMoveElement ? `[Timeline] persistMoveEdits: only single-clip onMoveElement wired \u2014 this ${edits.length}-clip move degrades to a per-clip persist race (no atomic single-undo)` : `[Timeline] persistMoveEdits: no move persist handler wired \u2014 ${edits.length} edit(s) applied to the store only, not saved`
10142
+ onMoveElement ? `[Timeline] persistMoveEdits: only single-clip onMoveElement wired, so this ${edits.length}-clip move degrades to a per-clip persist race (no atomic single-undo)` : `[Timeline] persistMoveEdits: no move persist handler wired, so ${edits.length} edit(s) applied to the store only, not saved`
10143
10143
  );
10144
10144
  }
10145
10145
  const prev = edits.map((e) => ({
@@ -18889,7 +18889,7 @@ function resolveResizePlaybackStart(original, target, element, updates) {
18889
18889
  function applyTimelineMoveAttributes(original, target, start, duration, track2, audioGroup) {
18890
18890
  if (!Number.isFinite(start) || !Number.isFinite(duration)) {
18891
18891
  console.warn(
18892
- `[Timeline] applyTimelineMoveAttributes: non-finite timing (start=${start}, duration=${duration}) \u2014 patch skipped`
18892
+ `[Timeline] applyTimelineMoveAttributes: non-finite timing (start=${start}, duration=${duration}). Patch skipped`
18893
18893
  );
18894
18894
  return original;
18895
18895
  }
@@ -19399,7 +19399,7 @@ var OutOfSyncBadge = memo12(function OutOfSyncBadge2({ el }) {
19399
19399
  tabIndex: -1,
19400
19400
  "aria-haspopup": "menu",
19401
19401
  "aria-label": `Out of sync with ${partnerName} by ${label} frames`,
19402
- title: `Out of sync with ${partnerName} by ${label} \u2014 click for Move or Slip into Sync`,
19402
+ title: `Out of sync with ${partnerName} by ${label}. Click for Move or Slip into Sync`,
19403
19403
  "data-testid": "out-of-sync-badge",
19404
19404
  className: "absolute bottom-0.5 left-1 z-[12] cursor-pointer rounded-[3px] bg-red-600 px-1 font-mono text-[9px] leading-[14px] text-white tabular-nums",
19405
19405
  onPointerDown: stop,
@@ -19553,7 +19553,7 @@ var TimelineClip = memo13(function TimelineClip2({
19553
19553
  "aria-description": isGestureActor || !capabilities.canMove ? void 0 : "Space picks up. Up and Down choose a new track. Enter drops. Escape cancels.",
19554
19554
  className: clipClassName,
19555
19555
  style,
19556
- title: isComposition ? `${el.compositionSrc} \u2022 Double-click to open` : `${displayLabel} \u2022 ${startLabel}s \u2013 ${endLabel}s`,
19556
+ title: isComposition ? `${el.compositionSrc} \u2022 Double-click to open` : `${displayLabel} \u2022 ${startLabel}s to ${endLabel}s`,
19557
19557
  onPointerEnter: onHoverStart,
19558
19558
  onPointerLeave: onHoverEnd,
19559
19559
  onPointerDown,
@@ -21563,7 +21563,7 @@ function ClipAutomationLanes({
21563
21563
  onSelect: bound.onSelect,
21564
21564
  snapTimes,
21565
21565
  readOnly: bound.readOnly || isCarveLane(lane.target, bound.chain),
21566
- readOnlyNote: isCarveLane(lane.target, bound.chain) ? "Owned by the voiceover carve \u2014 re-derived on every analysis. Change strength in the FX rack, or turn the carve off to edit these by hand." : bound.readOnly ? "Read-only here." : void 0,
21566
+ readOnlyNote: isCarveLane(lane.target, bound.chain) ? "Owned by the voiceover carve and re-derived on every analysis. Change strength in the FX rack, or turn the carve off to edit these by hand." : bound.readOnly ? "Read-only here." : void 0,
21567
21567
  rangeSelection: bound.selection?.target === lane.target ? {
21568
21568
  t0: bound.selection.t0,
21569
21569
  t1: bound.selection.t1,
@@ -22877,7 +22877,7 @@ function TimelineFxButton(props) {
22877
22877
  type: "button",
22878
22878
  tabIndex: -1,
22879
22879
  ref: buttonRef,
22880
- "aria-label": "Effects \u2014 group these clips first",
22880
+ "aria-label": "Effects: group these clips first",
22881
22881
  title: "Group these clips to add effects to all of them",
22882
22882
  className: "flex h-6 items-center justify-center rounded-sm border-0 bg-transparent px-1 text-[10px] font-semibold text-[var(--timeline-text-faint)] hover:text-[var(--timeline-text-soft)]",
22883
22883
  onPointerDown: (event) => event.stopPropagation(),
@@ -22916,7 +22916,7 @@ function TimelineFxButton(props) {
22916
22916
  type: "button",
22917
22917
  tabIndex: -1,
22918
22918
  ref: buttonRef,
22919
- "aria-label": nodeCount > 0 ? `Effects \u2014 ${nodeCount} applied` : "Effects",
22919
+ "aria-label": nodeCount > 0 ? `Effects: ${nodeCount} applied` : "Effects",
22920
22920
  title: "Effects",
22921
22921
  className: `flex h-6 items-center justify-center gap-0.5 rounded border-0 bg-transparent px-1 text-[10px] font-semibold transition-colors ${open || nodeCount > 0 ? "text-[var(--timeline-accent)]" : "text-[var(--timeline-text-faint)] hover:text-[var(--timeline-text-soft)]"}`,
22922
22922
  onPointerDown: (event) => event.stopPropagation(),
@@ -23392,7 +23392,7 @@ function AutomationLaneHeaderRow({
23392
23392
  {
23393
23393
  "data-automation-lane-also": "",
23394
23394
  className: "truncate text-[9px] text-warning-ink",
23395
- title: `${alsoAutomatedBy} is also fading this \u2014 the two multiply.`,
23395
+ title: `${alsoAutomatedBy} is also fading this. The two multiply.`,
23396
23396
  children: [
23397
23397
  alsoAutomatedBy,
23398
23398
  " is also fading this."
@@ -25696,8 +25696,9 @@ function AudioGainDialog({
25696
25696
  }
25697
25697
  ),
25698
25698
  /* @__PURE__ */ jsxs40("div", { className: "mt-3 text-neutral-400", "data-testid": "audio-gain-peak", children: [
25699
- "Peak Amplitude: ",
25700
- peaks === null ? "measuring\u2026" : peakDb === null ? "\u2014" : dbText(peakDb)
25699
+ "Peak Amplitude:",
25700
+ " ",
25701
+ peaks === null ? "measuring\u2026" : peakDb === null ? "Unavailable" : dbText(peakDb)
25701
25702
  ] }),
25702
25703
  outOfRange && /* @__PURE__ */ jsx63("div", { className: "mt-1 text-red-400", children: "Peak targets must be 0 dB or lower." }),
25703
25704
  /* @__PURE__ */ jsxs40("div", { className: "mt-4 flex justify-end gap-2", children: [
@@ -25905,7 +25906,7 @@ function EditPopover({ rangeStart, rangeEnd, anchorX, anchorY, onClose }) {
25905
25906
  /* @__PURE__ */ jsx64("div", { className: "w-1.5 h-1.5 rounded-full bg-studio-accent" }),
25906
25907
  /* @__PURE__ */ jsxs41("span", { className: "text-[11px] font-medium text-neutral-300", children: [
25907
25908
  formatTime(start),
25908
- " \u2014 ",
25909
+ " to ",
25909
25910
  formatTime(end)
25910
25911
  ] })
25911
25912
  ] }),
@@ -25939,7 +25940,7 @@ function EditPopover({ rangeStart, rangeEnd, anchorX, anchorY, onClose }) {
25939
25940
  className: "w-full px-3 py-2 text-xs bg-neutral-800/60 border border-neutral-700/40 rounded-lg text-neutral-200 placeholder:text-neutral-600 resize-none focus:outline-hidden focus:border-studio-accent/40 transition-colors"
25940
25941
  }
25941
25942
  ) }),
25942
- copyError && /* @__PURE__ */ jsx64("p", { className: "px-3 pb-2 text-[10px] text-danger-ink", role: "alert", children: "Copy failed \u2014 check clipboard permissions and try again." }),
25943
+ copyError && /* @__PURE__ */ jsx64("p", { className: "px-3 pb-2 text-[10px] text-danger-ink", role: "alert", children: "Copy failed. Check clipboard permissions and try again." }),
25943
25944
  /* @__PURE__ */ jsxs41("div", { className: "grid grid-cols-2 gap-2 px-3 pb-3", children: [
25944
25945
  /* @__PURE__ */ jsx64(
25945
25946
  "button",
@@ -26054,7 +26055,7 @@ function KeyframeDiamondContextMenu({
26054
26055
  onClick: () => {
26055
26056
  void handleCopyProperties();
26056
26057
  },
26057
- children: copyStatus === "copied" ? "Copied!" : copyStatus === "failed" ? "Copy failed \u2014 check permissions" : "Copy Properties"
26058
+ children: copyStatus === "copied" ? "Copied!" : copyStatus === "failed" ? "Copy failed. Check permissions" : "Copy Properties"
26058
26059
  }
26059
26060
  ),
26060
26061
  onDelete && /* @__PURE__ */ jsx65(
@@ -35858,7 +35859,7 @@ var CaptionOverlay = memo26(function CaptionOverlay2({ iframeRef }) {
35858
35859
  onPointerUp: handlePointerUp,
35859
35860
  onLostPointerCapture: handlePointerUp,
35860
35861
  children: [
35861
- wordBoxes.length === 0 && model && model.segments.size > 0 && /* @__PURE__ */ jsx91("div", { className: "absolute inset-x-0 top-3 flex justify-center pointer-events-none", children: /* @__PURE__ */ jsx91("span", { className: "px-2.5 py-1 rounded-full bg-black/60 border border-neutral-700 text-2xs text-neutral-300", children: "No captions visible at this frame \u2014 scrub to a caption, or select one in the track below" }) }),
35862
+ wordBoxes.length === 0 && model && model.segments.size > 0 && /* @__PURE__ */ jsx91("div", { className: "absolute inset-x-0 top-3 flex justify-center pointer-events-none", children: /* @__PURE__ */ jsx91("span", { className: "px-2.5 py-1 rounded-full bg-black/60 border border-neutral-700 text-2xs text-neutral-300", children: "No captions visible at this frame. Scrub to a caption, or select one in the track below" }) }),
35862
35863
  wordBoxes.map((box) => {
35863
35864
  const isSelected2 = selectedSegmentIds.has(box.segmentId);
35864
35865
  return /* @__PURE__ */ jsx91(
@@ -37509,7 +37510,7 @@ function OffCanvasIndicators({
37509
37510
  const selectOffCanvas = async () => {
37510
37511
  const el = elements.current.get(r.key);
37511
37512
  if (!el) return;
37512
- const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-PTP2ICGM.js");
37513
+ const { resolveDomEditSelection: resolveDomEditSelection2 } = await import("./domEditingLayers-SMVA3FEW.js");
37513
37514
  const acp = activeCompositionPathRef.current ?? "index.html";
37514
37515
  const sel = await resolveDomEditSelection2(el, {
37515
37516
  activeCompositionPath: acp,
@@ -37530,7 +37531,7 @@ function OffCanvasIndicators({
37530
37531
  "aria-label": `Select off-canvas element ${r.key}`,
37531
37532
  className: "pointer-events-auto absolute inset-0 border-2 border-dashed border-studio-accent/10 rounded-md cursor-pointer hover:border-studio-accent hover:bg-studio-accent/10 transition-colors",
37532
37533
  style: clipOutside ? { clipPath: clipOutside } : void 0,
37533
- title: `Off-canvas: ${r.key} \u2014 click to select`,
37534
+ title: `Off-canvas: ${r.key}. Click to select`,
37534
37535
  onClick: handleClick,
37535
37536
  onKeyDown: (e) => {
37536
37537
  if (e.key === "Enter" || e.key === " ") {
@@ -48419,7 +48420,7 @@ var SnapToolbar = memo31(function SnapToolbar2() {
48419
48420
  if (gridPopoverOpen) settleGridSpacing();
48420
48421
  setGridPopoverOpen((v) => !v);
48421
48422
  },
48422
- title: prefs.gridVisible ? "Grid visible (G) \u2014 right-click for spacing options" : "Grid hidden (G) \u2014 right-click for spacing options",
48423
+ title: prefs.gridVisible ? "Grid visible (G). Right-click for spacing options" : "Grid hidden (G). Right-click for spacing options",
48423
48424
  "aria-label": "Toggle grid",
48424
48425
  children: /* @__PURE__ */ jsx109(GridFour, { size: 16, weight: prefs.gridVisible ? "fill" : "regular" })
48425
48426
  }
@@ -54494,7 +54495,7 @@ function createTransformCommitHandlers({
54494
54495
  if (await commitAnimatedTransformValue(
54495
54496
  axis,
54496
54497
  parsed,
54497
- "This element's position can't be edited here yet \u2014 it is driven by its animation"
54498
+ "This element's position can't be edited here yet: its animation drives it"
54498
54499
  ))
54499
54500
  return;
54500
54501
  const plainTranslate = editsPlainCss(element.element, "move");
@@ -54517,7 +54518,7 @@ function createTransformCommitHandlers({
54517
54518
  return;
54518
54519
  }
54519
54520
  if (hasGsapAnimation) {
54520
- showToast?.("This element's size can't be edited here yet \u2014 it is driven by its animation");
54521
+ showToast?.("This element's size can't be edited here yet: its animation drives it");
54521
54522
  return;
54522
54523
  }
54523
54524
  const current = readStudioBoxSize(element.element);
@@ -54536,7 +54537,7 @@ function createTransformCommitHandlers({
54536
54537
  if (await commitAnimatedTransformValue(
54537
54538
  "rotation",
54538
54539
  parsed,
54539
- "This element's rotation can't be edited here yet \u2014 it is driven by its animation"
54540
+ "This element's rotation can't be edited here yet: its animation drives it"
54540
54541
  ))
54541
54542
  return;
54542
54543
  await Promise.resolve(onSetManualRotation(element, { angle: parsed }));
@@ -55533,7 +55534,7 @@ function ColorGradingControls({
55533
55534
  setLutImporting(true);
55534
55535
  setLutImportError(null);
55535
55536
  void actions.importLut(files, onImportAssets, () => track2("button", "Import LUT")).catch(
55536
- () => setLutImportError("LUT import failed \u2014 check the .cube file and try again.")
55537
+ () => setLutImportError("LUT import failed. Check the .cube file and try again.")
55537
55538
  ).finally(() => setLutImporting(false));
55538
55539
  event.currentTarget.value = "";
55539
55540
  }
@@ -56143,7 +56144,7 @@ function useColorGradingController({
56143
56144
  const reverted = confirmedGradingRef.current;
56144
56145
  latestGradingRef.current = reverted;
56145
56146
  setGrading(reverted);
56146
- setRuntimeStatus({ state: "unavailable", message: "Save failed \u2014 reverted" });
56147
+ setRuntimeStatus({ state: "unavailable", message: "Save failed, changes reverted" });
56147
56148
  };
56148
56149
  const result = setAttributeLive(COLOR_GRADING_DATA_KEY, value ?? null, applySettled);
56149
56150
  return trackStudioPendingEdit(
@@ -57301,7 +57302,7 @@ function FontFamilyField({
57301
57302
  setFontNotice("No supported font files were imported.");
57302
57303
  }
57303
57304
  } catch {
57304
- setFontNotice("Font import failed \u2014 the files were not added. Try again.");
57305
+ setFontNotice("Font import failed. The files were not added. Try again.");
57305
57306
  } finally {
57306
57307
  setImportingFonts(false);
57307
57308
  }
@@ -57379,10 +57380,10 @@ function FontFamilyField({
57379
57380
  setQuery("");
57380
57381
  setOpen(false);
57381
57382
  } else {
57382
- setFontNotice(`Couldn't import "${option.family}" \u2014 the font was not applied.`);
57383
+ setFontNotice(`Couldn't import "${option.family}", so the font was not applied.`);
57383
57384
  }
57384
57385
  } catch {
57385
- setFontNotice(`Couldn't import "${option.family}" \u2014 the font was not applied.`);
57386
+ setFontNotice(`Couldn't import "${option.family}", so the font was not applied.`);
57386
57387
  } finally {
57387
57388
  setImportingFonts(false);
57388
57389
  }
@@ -57881,7 +57882,7 @@ function VariablesBindElement({
57881
57882
  String(existingDecl.default),
57882
57883
  ")"
57883
57884
  ] }),
57884
- `, not the element's own \u2014 binding won't change "`,
57885
+ `, not the element's own, so binding won't change "`,
57885
57886
  trimmedId,
57886
57887
  '".'
57887
57888
  ] }),
@@ -58041,7 +58042,7 @@ function PromotableControl({
58041
58042
  useEffect79(() => {
58042
58043
  if (danglingId != null) {
58043
58044
  console.warn(
58044
- `[hyperframes] Control is bound to variable "${danglingId}", but no such declaration exists. The element still carries the binding on disk \u2014 re-declare the variable or unbind the element.`
58045
+ `[hyperframes] Control is bound to variable "${danglingId}", but no such declaration exists. The element still carries the binding on disk. Re-declare the variable or unbind the element.`
58045
58046
  );
58046
58047
  }
58047
58048
  }, [danglingId]);
@@ -58536,7 +58537,7 @@ function ImageFillField({
58536
58537
  commitImage(toProjectRootAssetPath(nextImage), true);
58537
58538
  }
58538
58539
  } catch {
58539
- setUploadError("Upload failed \u2014 check the file and try again.");
58540
+ setUploadError("Upload failed. Check the file and try again.");
58540
58541
  } finally {
58541
58542
  setUploading(false);
58542
58543
  }
@@ -60044,7 +60045,7 @@ function buildTweenSummary(animation2) {
60044
60045
  const label = (PROP_LABELS[p] ?? p).toLowerCase();
60045
60046
  return `${label} ${formatPropValue(p, v)}`;
60046
60047
  });
60047
- const fromText = fromDescs.length > 0 ? fromDescs.join(", ") : "\u2014";
60048
+ const fromText = fromDescs.length > 0 ? fromDescs.join(", ") : "none";
60048
60049
  return `Starting at ${pos}s, over ${dur}s, ${target} animates from [${fromText}] to [${propText}] using a ${ease.toLowerCase()} curve.`;
60049
60050
  }
60050
60051
  return `Starting at ${pos}s, over ${dur}s, animate ${target}'s ${propText} using a ${ease.toLowerCase()} curve.`;
@@ -60187,14 +60188,14 @@ function ComputedTweenNotice({
60187
60188
  const editability = editabilityForProvenance2(provenance);
60188
60189
  if (editability === "direct") return null;
60189
60190
  if (editability === "source") {
60190
- return /* @__PURE__ */ jsx142("div", { className: "rounded-md border border-neutral-800 bg-neutral-900/50 px-2 py-1.5 text-[9px] text-neutral-400", children: "Computed value \u2014 edit it in the Code tab." });
60191
+ return /* @__PURE__ */ jsx142("div", { className: "rounded-md border border-neutral-800 bg-neutral-900/50 px-2 py-1.5 text-[9px] text-neutral-400", children: "Computed value. Edit it in the Code tab." });
60191
60192
  }
60192
60193
  const source = provenance?.fn ? `${provenance.fn}()` : "a loop";
60193
60194
  return /* @__PURE__ */ jsxs104("div", { className: "flex items-center justify-between gap-2 rounded-md border border-neutral-800 bg-neutral-900/50 px-2 py-1.5 text-[9px] text-neutral-400", children: [
60194
60195
  /* @__PURE__ */ jsxs104("span", { children: [
60195
60196
  "Generated by ",
60196
60197
  source,
60197
- " \u2014 not directly editable."
60198
+ ", not directly editable."
60198
60199
  ] }),
60199
60200
  onUnroll && /* @__PURE__ */ jsx142(
60200
60201
  "button",
@@ -60402,7 +60403,7 @@ function PropertyRow({
60402
60403
  onClick: () => onCommit(isVisible ? "hidden" : "visible"),
60403
60404
  className: "shrink-0 rounded-full transition-colors duration-200 relative",
60404
60405
  style: { width: 28, height: 16, background: isVisible ? P.accent : P.borderInput },
60405
- title: isVisible ? "Visible \u2014 click to hide" : "Hidden \u2014 click to show",
60406
+ title: isVisible ? "Visible: click to hide" : "Hidden: click to show",
60406
60407
  children: /* @__PURE__ */ jsx144(
60407
60408
  "span",
60408
60409
  {
@@ -60666,7 +60667,7 @@ var AnimationCard = memo38(function AnimationCard2({
60666
60667
  children: [
60667
60668
  typeof animation2.position === "number" ? `${parseFloat(animation2.position.toFixed(3))}s` : animation2.position,
60668
60669
  " ",
60669
- "\u2013 ",
60670
+ "to ",
60670
60671
  typeof endTime === "number" ? `${parseFloat(endTime.toFixed(3))}s` : endTime
60671
60672
  ]
60672
60673
  }
@@ -60716,7 +60717,7 @@ var AnimationCard = memo38(function AnimationCard2({
60716
60717
  }
60717
60718
  }
60718
60719
  ),
60719
- "Keyframed \u2014 click a segment below to edit its curve"
60720
+ "Keyframed: click a segment below to edit its curve"
60720
60721
  ] }),
60721
60722
  runEase && runEase !== "none" && /* @__PURE__ */ jsxs107("p", { className: "mt-1 text-[9px] text-neutral-500", "data-card-run-ease": true, children: [
60722
60723
  "Run ease: ",
@@ -60733,7 +60734,7 @@ var AnimationCard = memo38(function AnimationCard2({
60733
60734
  setTimeout(() => setCopied(false), 1500);
60734
60735
  },
60735
60736
  className: "shrink-0 rounded-sm px-1.5 py-0.5 text-[9px] font-medium text-neutral-500 transition-colors hover:bg-neutral-800 hover:text-neutral-300",
60736
- title: "Copy description to clipboard \u2014 paste into agent prompts",
60737
+ title: "Copy description for agent prompts",
60737
60738
  children: copied ? "Copied" : "Copy"
60738
60739
  }
60739
60740
  )
@@ -61072,7 +61073,7 @@ function GsapAnimationList({
61072
61073
  }
61073
61074
  }, [focusedHere]);
61074
61075
  return /* @__PURE__ */ jsxs109("div", { className: "space-y-2", children: [
61075
- animations.length === 0 && /* @__PURE__ */ jsx147("p", { className: "text-[11px] leading-4 text-neutral-500", children: "No animations on this element yet \u2014 add an effect below to animate it." }),
61076
+ animations.length === 0 && /* @__PURE__ */ jsx147("p", { className: "text-[11px] leading-4 text-neutral-500", children: "No animations on this element yet. Add an effect below to animate it." }),
61076
61077
  animations.map((animation2, index) => /* @__PURE__ */ createElement2(
61077
61078
  AnimationCard,
61078
61079
  {
@@ -61109,7 +61110,7 @@ var GsapAnimationSection = memo39(function GsapAnimationSection2({
61109
61110
  ...callbacks
61110
61111
  }) {
61111
61112
  return /* @__PURE__ */ jsxs110(Section, { title: "Animation", icon: /* @__PURE__ */ jsx148(Film, { size: 15 }), children: [
61112
- multipleTimelines && /* @__PURE__ */ jsx148("p", { className: "mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink", children: "This file has multiple GSAP timelines. Animation editing is disabled to prevent data loss \u2014 consolidate into a single timeline to enable editing." }),
61113
+ multipleTimelines && /* @__PURE__ */ jsx148("p", { className: "mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink", children: "This file has multiple GSAP timelines. Animation editing is disabled to prevent data loss. Consolidate into a single timeline to enable editing." }),
61113
61114
  unsupportedTimelinePattern && /* @__PURE__ */ jsx148("p", { className: "mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink", children: `This timeline uses a computed key (window.__timelines[variable]) the editor can't resolve statically. Use a string-literal key (window.__timelines["id"]) or a variable declaration (const tl = gsap.timeline()) to enable editing.` }),
61114
61115
  multipleTimelines || unsupportedTimelinePattern ? null : /* @__PURE__ */ jsx148(
61115
61116
  GsapAnimationList,
@@ -61449,7 +61450,7 @@ function Transform3DCube({
61449
61450
  {
61450
61451
  type: "button",
61451
61452
  onClick: onKeyframe,
61452
- title: keyframed ? "3D transform is keyframed \u2014 click a field diamond to add keyframes" : "Keyframe the 3D transform (animate it over time)",
61453
+ title: keyframed ? "3D transform is keyframed. Click a field diamond to add keyframes" : "Keyframe the 3D transform (animate it over time)",
61453
61454
  "aria-label": "Keyframe 3D transform",
61454
61455
  "aria-pressed": keyframed,
61455
61456
  className: `absolute left-1.5 top-1.5 rounded p-0.5 hover:bg-neutral-800 ${keyframed ? "text-accent-ink" : "text-neutral-500 hover:text-neutral-200"}`,
@@ -62169,7 +62170,7 @@ function FlatSelectRow({
62169
62170
  {
62170
62171
  type: "button",
62171
62172
  "data-flat-select-reset": "true",
62172
- title: "Remove \u2014 fall back to default",
62173
+ title: "Remove and fall back to default",
62173
62174
  disabled,
62174
62175
  onClick: () => {
62175
62176
  track2("button", `Reset ${trackName}`);
@@ -62230,7 +62231,7 @@ function FlatRow({
62230
62231
  {
62231
62232
  type: "button",
62232
62233
  "data-flat-row-reset": "true",
62233
- title: "Remove \u2014 fall back to default",
62234
+ title: "Remove and fall back to default",
62234
62235
  onClick: () => {
62235
62236
  track2("button", `Reset ${label}`);
62236
62237
  onReset();
@@ -62557,7 +62558,7 @@ function FlatSlider({
62557
62558
  {
62558
62559
  type: "button",
62559
62560
  "data-flat-slider-reset": "true",
62560
- title: "Remove \u2014 fall back to default",
62561
+ title: "Remove and fall back to default",
62561
62562
  disabled,
62562
62563
  onClick: () => {
62563
62564
  track2("button", `Reset ${label}`);
@@ -62598,7 +62599,7 @@ var ALIGN_OPTIONS = [
62598
62599
  { key: "justify", label: "justify", node: "J" }
62599
62600
  ];
62600
62601
  var CASE_OPTIONS = [
62601
- { key: "none", label: "none", node: "\u2013" },
62602
+ { key: "none", label: "none", node: "None" },
62602
62603
  { key: "uppercase", label: "uppercase", node: "AG" },
62603
62604
  { key: "lowercase", label: "lowercase", node: "ag" },
62604
62605
  { key: "capitalize", label: "capitalize", node: "Ag" }
@@ -63824,7 +63825,7 @@ function TimingSection({
63824
63825
  onCommit: commitDuration
63825
63826
  }
63826
63827
  ) }),
63827
- derived && /* @__PURE__ */ jsx161("p", { className: "mt-2 text-[10px] leading-snug text-neutral-500", children: "Inferred from this element\u2019s animation \u2014 edit to pin an explicit clip range." })
63828
+ derived && /* @__PURE__ */ jsx161("p", { className: "mt-2 text-[10px] leading-snug text-neutral-500", children: "Inferred from this element\u2019s animation. Edit to pin an explicit clip range." })
63828
63829
  ] });
63829
63830
  }
63830
63831
 
@@ -63918,7 +63919,7 @@ function FlatTimingRow({
63918
63919
  cell("Start", formatTimingValue(start), commitStart),
63919
63920
  cell("End", formatTimingValue(end), commitEnd),
63920
63921
  cell("Duration", formatTimingValue(duration), commitDuration),
63921
- derived && /* @__PURE__ */ jsx162("p", { className: "col-span-3 mt-1 text-[10px] leading-snug text-panel-text-3", children: "Inferred from this element's animation \u2014 edit to pin an explicit clip range." })
63922
+ derived && /* @__PURE__ */ jsx162("p", { className: "col-span-3 mt-1 text-[10px] leading-snug text-panel-text-3", children: "Inferred from this element's animation. Edit to pin an explicit clip range." })
63922
63923
  ] });
63923
63924
  }
63924
63925
  function FlatMotionSection({
@@ -63945,7 +63946,7 @@ function FlatMotionSection({
63945
63946
  }
63946
63947
  ),
63947
63948
  showEffects && /* @__PURE__ */ jsxs122(Fragment46, { children: [
63948
- multipleTimelines && /* @__PURE__ */ jsx162("p", { className: "rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink", children: "This file has multiple GSAP timelines. Animation editing is disabled to prevent data loss \u2014 consolidate into a single timeline to enable editing." }),
63949
+ multipleTimelines && /* @__PURE__ */ jsx162("p", { className: "rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink", children: "This file has multiple GSAP timelines. Animation editing is disabled to prevent data loss. Consolidate into a single timeline to enable editing." }),
63949
63950
  unsupportedTimelinePattern && /* @__PURE__ */ jsx162("p", { className: "rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink", children: "This timeline uses a computed key the editor can't resolve statically." }),
63950
63951
  !multipleTimelines && !unsupportedTimelinePattern && /* @__PURE__ */ jsx162(
63951
63952
  GsapAnimationList,
@@ -63964,7 +63965,7 @@ function motionSectionLabel(args) {
63964
63965
  if (args.timingOnly) {
63965
63966
  return {
63966
63967
  title: "Timing",
63967
- summary: `${formatTimingValue(args.start)} \u2013 ${formatTimingValue(args.start + args.duration)}`
63968
+ summary: `${formatTimingValue(args.start)} to ${formatTimingValue(args.start + args.duration)}`
63968
63969
  };
63969
63970
  }
63970
63971
  return {
@@ -64986,7 +64987,7 @@ function FxBandRuler({ band, at }) {
64986
64987
  return /* @__PURE__ */ jsx166(
64987
64988
  "span",
64988
64989
  {
64989
- title: `${range.name} \u2014 ${range.says}`,
64990
+ title: `${range.name}: ${range.says}`,
64990
64991
  className: range.name === here.name ? "hf-fx-ruler-band bg-panel-accent" : reachable ? "hf-fx-ruler-band bg-panel-text-4/50" : "hf-fx-ruler-band bg-panel-text-4/15",
64991
64992
  style: {
64992
64993
  width: `${(positionOf(range.to) - positionOf(range.from)) * 100}%`
@@ -64997,7 +64998,7 @@ function FxBandRuler({ band, at }) {
64997
64998
  }) }),
64998
64999
  /* @__PURE__ */ jsxs126("p", { className: "hf-fx-ruler-label truncate pt-0.5 text-[9px] text-panel-text-2", children: [
64999
65000
  /* @__PURE__ */ jsx166("span", { className: "hf-fx-ruler-name text-panel-text-1", children: here.name }),
65000
- " \u2014 ",
65001
+ ": ",
65001
65002
  here.says
65002
65003
  ] })
65003
65004
  ] });
@@ -65220,12 +65221,12 @@ function FxNodeOpenBody({
65220
65221
  onClick: onToggleDetails,
65221
65222
  children: [
65222
65223
  /* @__PURE__ */ jsx168("span", { "aria-hidden": "true", children: details ? "\u25BE" : "\u25B8" }),
65223
- "Details \u2014 ",
65224
+ "Details: ",
65224
65225
  registryDef.label
65225
65226
  ]
65226
65227
  }
65227
65228
  ) : /* @__PURE__ */ jsxs127("p", { className: "hf-fx-node-mechanism border-t border-panel-border-input px-1.5 pt-1 font-mono text-[9px] uppercase tracking-wide text-panel-text-2", children: [
65228
- "Details \u2014 ",
65229
+ "Details: ",
65229
65230
  registryDef.label
65230
65231
  ] }),
65231
65232
  details || !oneKnob ? /* @__PURE__ */ jsx168(
@@ -71614,12 +71615,12 @@ var PropertyPanel = memo40(function PropertyPanel2(props) {
71614
71615
  const handleCopyElementInfo = () => {
71615
71616
  const text = buildElementInfoText(element, sourceLabel, gsapAnimations, previewIframeRef);
71616
71617
  navigator.clipboard.writeText(text).then(() => {
71617
- showToast(`Copied element info for ${element.label} \u2014 paste into any AI agent`, "info");
71618
+ showToast(`Copied element info for ${element.label}. Paste it into any AI agent`, "info");
71618
71619
  setClipboardCopied(true);
71619
71620
  clearTimeout(clipboardTimerRef.current);
71620
71621
  clipboardTimerRef.current = setTimeout(() => setClipboardCopied(false), 1500);
71621
71622
  }).catch(() => {
71622
- showToast("Couldn't copy to the clipboard \u2014 check browser permissions", "error");
71623
+ showToast("Couldn't copy to the clipboard. Check browser permissions", "error");
71623
71624
  });
71624
71625
  };
71625
71626
  if (STUDIO_FLAT_INSPECTOR_ENABLED) {
@@ -72756,7 +72757,7 @@ var FileTree = memo42(function FileTree2({
72756
72757
  ),
72757
72758
  children.length === 0 && !inlineInput && /* @__PURE__ */ jsxs150("div", { className: "px-3 py-4 text-center text-[11px] text-neutral-600", children: [
72758
72759
  "No files yet",
72759
- hasFileOps ? " \u2014 use + above to create one" : "",
72760
+ hasFileOps ? ". Use + above to create one" : "",
72760
72761
  "."
72761
72762
  ] }),
72762
72763
  children.map(
@@ -73401,7 +73402,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
73401
73402
  try {
73402
73403
  const res = await studioApiFetch(`/api/render/${jobId}/cancel`, { method: "POST" });
73403
73404
  if (!res.ok && res.status !== 404) {
73404
- setActionError("Couldn't cancel on the server \u2014 the render may still be running.");
73405
+ setActionError("Couldn't cancel on the server. The render may still be running.");
73405
73406
  return;
73406
73407
  }
73407
73408
  if (res.ok) {
@@ -73411,7 +73412,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
73411
73412
  }
73412
73413
  }
73413
73414
  } catch {
73414
- setActionError("Couldn't reach the server to cancel \u2014 the render may still be running.");
73415
+ setActionError("Couldn't reach the server to cancel. The render may still be running.");
73415
73416
  }
73416
73417
  },
73417
73418
  [closeActiveEventSource, loadRenders]
@@ -73423,7 +73424,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
73423
73424
  try {
73424
73425
  const res = await studioApiFetch(`/api/render/${jobId}`, { method: "DELETE" });
73425
73426
  if (!res.ok) {
73426
- setActionError("Couldn't delete the render \u2014 it's still on disk.");
73427
+ setActionError("Couldn't delete the render. It's still on disk.");
73427
73428
  return;
73428
73429
  }
73429
73430
  } catch {
@@ -73662,7 +73663,7 @@ ${pathLine}${lines.join("\n\n")}`;
73662
73663
  {
73663
73664
  onClick: handleCopyToAgent,
73664
73665
  className: `px-3 py-1 text-xs font-medium rounded-lg transition-colors active:scale-[0.98] ${copied ? "bg-accent text-on-accent" : copyFailed ? "bg-danger text-on-danger" : "bg-accent hover:bg-accent-hover text-on-accent"}`,
73665
- children: copied ? "Copied!" : copyFailed ? "Copy failed \u2014 check permissions" : "Copy to Agent"
73666
+ children: copied ? "Copied!" : copyFailed ? "Copy failed. Check permissions" : "Copy to Agent"
73666
73667
  }
73667
73668
  ) }),
73668
73669
  /* @__PURE__ */ jsxs151("div", { className: "flex-1 overflow-y-auto px-5 py-3", children: [
@@ -74563,7 +74564,7 @@ function ProjectUnreachableBanner({ projectId }) {
74563
74564
  ]
74564
74565
  }
74565
74566
  )
74566
- ] }) : /* @__PURE__ */ jsx202("span", { children: "Couldn't open this project \u2014 it may have been renamed, moved, or deleted." })
74567
+ ] }) : /* @__PURE__ */ jsx202("span", { children: "Couldn't open this project. It may have been renamed, moved, or deleted." })
74567
74568
  }
74568
74569
  );
74569
74570
  }
@@ -74744,7 +74745,7 @@ function useCaptionSync(projectId) {
74744
74745
  suppressSaveRef.current = true;
74745
74746
  useCaptionStore.getState().setModel({ ...model, segments: newSegments });
74746
74747
  } catch {
74747
- useCaptionStore.getState().setSyncError("caption-overrides.json is corrupt \u2014 earlier caption edits didn't load");
74748
+ useCaptionStore.getState().setSyncError("caption-overrides.json is corrupt, so earlier caption edits didn't load");
74748
74749
  }
74749
74750
  }, []);
74750
74751
  return { save, loadOverrides };
@@ -75203,7 +75204,7 @@ function useEditorSave({
75203
75204
  if (lastFailureToastAtRef.current === null || now2 - lastFailureToastAtRef.current >= FAILURE_BURST_MS) {
75204
75205
  lastFailureToastAtRef.current = now2;
75205
75206
  showToast(
75206
- `Couldn't save ${path} \u2014 your latest edits are NOT persisted. Check the preview server; editing again retries the save.`,
75207
+ `Couldn't save ${path}. Your latest edits are NOT persisted. Check the preview server; editing again retries the save.`,
75207
75208
  "error"
75208
75209
  );
75209
75210
  }
@@ -76321,7 +76322,6 @@ function buildCutTarget(element, target, splitTime) {
76321
76322
  elementDuration: element.duration,
76322
76323
  ...element.playbackStart != null ? { playbackStart: element.playbackStart } : {},
76323
76324
  ...element.playbackRate != null ? { playbackRate: element.playbackRate } : {},
76324
- ...element.kind === "composition" ? { isComposition: true } : {},
76325
76325
  // Pin both halves to the current track: unstamped, the runtime's positional
76326
76326
  // fallback (parseAuthoredTrack) renumbers the new sibling onto a new row.
76327
76327
  track: resolveElementTrack(element)
@@ -78344,7 +78344,7 @@ async function createAudioGroupAndAssignMembers({
78344
78344
  pendingTimelineEditPathRef
78345
78345
  }) {
78346
78346
  if (elements.length < 2) {
78347
- throw new Error(`Cannot group ${elements.length} clip(s) \u2014 a group needs at least two`);
78347
+ throw new Error(`Cannot group ${elements.length} clip(s): a group needs at least two`);
78348
78348
  }
78349
78349
  if (!GROUP_ID_PATTERN.test(groupId)) {
78350
78350
  throw new Error(`Invalid audio group id ${JSON.stringify(groupId)}`);
@@ -83250,7 +83250,7 @@ function showUnchangedMutationFeedback(mutations, result, showToast) {
83250
83250
  async function runMutationRequest(mutations, options, showToast, request2) {
83251
83251
  const unsafeFields = mutations.flatMap((mutation) => findUnsafeMutationValues(mutation));
83252
83252
  if (unsafeFields.length > 0) {
83253
- showToast?.("Couldn't read element layout \u2014 try again at a different playhead time", "error");
83253
+ showToast?.("Couldn't read element layout. Try again at a different playhead time", "error");
83254
83254
  if (options.skipReload) return;
83255
83255
  throw markStudioSaveErrorAlreadyToasted(
83256
83256
  new Error(
@@ -86354,7 +86354,7 @@ function useDomEditSession({
86354
86354
  }
86355
86355
  if (members.some((m) => isAudioDomElement(m.element))) {
86356
86356
  showToast(
86357
- members.every((m) => isAudioDomElement(m.element)) ? "Audio clips group into a bus \u2014 use FX on the track header" : "Can't group audio clips with layout elements",
86357
+ members.every((m) => isAudioDomElement(m.element)) ? "Audio clips group into a bus. Use FX on the track header" : "Can't group audio clips with layout elements",
86358
86358
  "info"
86359
86359
  );
86360
86360
  return;
@@ -87651,7 +87651,7 @@ function useBlockHandlers({
87651
87651
  const runBlockInstall = useCallback152(
87652
87652
  async (blockName, install) => {
87653
87653
  if (installingBlockRef.current) {
87654
- showToast("A block is already installing \u2014 one moment\u2026", "info");
87654
+ showToast("A block is already installing. One moment\u2026", "info");
87655
87655
  return null;
87656
87656
  }
87657
87657
  installingBlockRef.current = true;
@@ -89230,7 +89230,7 @@ function useFrameCapture({
89230
89230
  } catch (fetchErr) {
89231
89231
  clearTimeout(timeout);
89232
89232
  if (fetchErr instanceof DOMException && fetchErr.name === "AbortError") {
89233
- throw new Error("Capture timed out \u2014 the server took too long to respond");
89233
+ throw new Error("Capture timed out: the server took too long to respond");
89234
89234
  }
89235
89235
  throw fetchErr;
89236
89236
  }
@@ -90939,11 +90939,11 @@ function useGestureCommit({
90939
90939
  }
90940
90940
  const duration = frozenSamples.length > 0 ? frozenSamples[frozenSamples.length - 1]?.time ?? 0 : 0;
90941
90941
  if (frozenSamples.length <= 2) {
90942
- showToast("No gesture detected \u2014 move the pointer while recording", "error");
90942
+ showToast("No gesture detected. Move the pointer while recording", "error");
90943
90943
  return;
90944
90944
  }
90945
90945
  if (duration <= 0) {
90946
- showToast("Recording too short \u2014 try again", "error");
90946
+ showToast("Recording too short. Try again", "error");
90947
90947
  return;
90948
90948
  }
90949
90949
  const simplified = simplifyGestureSamples(frozenSamples, duration, (key2) => {
@@ -90958,7 +90958,7 @@ function useGestureCommit({
90958
90958
  }
90959
90959
  const selector = sel.id ? idSelector(sel.id) : sel.selector;
90960
90960
  if (!selector) {
90961
- showToast("Cannot save \u2014 element has no selector", "error");
90961
+ showToast("Cannot save: element has no selector", "error");
90962
90962
  return;
90963
90963
  }
90964
90964
  const writeSelector = writeTargetSelector(sel);
@@ -91126,7 +91126,7 @@ function useGestureCommit({
91126
91126
  }
91127
91127
  const iframe = previewIframeRef.current;
91128
91128
  if (!iframe) {
91129
- showToast("Preview not ready \u2014 try again", "error");
91129
+ showToast("Preview not ready. Try again", "error");
91130
91130
  return;
91131
91131
  }
91132
91132
  const store = usePlayerStore.getState();
@@ -91341,7 +91341,7 @@ function MediaErrorPanel({ name, filePath }) {
91341
91341
  ),
91342
91342
  /* @__PURE__ */ jsx212("span", { className: "text-sm text-neutral-400 font-medium", children: name }),
91343
91343
  /* @__PURE__ */ jsx212("span", { className: "text-[11px] text-neutral-600 font-mono", children: filePath }),
91344
- /* @__PURE__ */ jsx212("span", { className: "text-[10px] text-neutral-500", children: "Couldn't load this file \u2014 it may be missing or corrupt" })
91344
+ /* @__PURE__ */ jsx212("span", { className: "text-[10px] text-neutral-500", children: "Couldn't load this file. It may be missing or corrupt" })
91345
91345
  ] });
91346
91346
  }
91347
91347
  function MediaPreview({ projectId, filePath }) {
@@ -91428,7 +91428,7 @@ function MediaPreview({ projectId, filePath }) {
91428
91428
  ),
91429
91429
  /* @__PURE__ */ jsx212("span", { className: "text-sm text-neutral-400 font-medium", children: name }),
91430
91430
  /* @__PURE__ */ jsx212("span", { className: "text-[11px] text-neutral-600 font-mono", children: filePath }),
91431
- /* @__PURE__ */ jsx212("span", { className: "text-[10px] text-neutral-600", children: "Binary file \u2014 preview not available" })
91431
+ /* @__PURE__ */ jsx212("span", { className: "text-[10px] text-neutral-600", children: "Binary file: preview not available" })
91432
91432
  ] });
91433
91433
  }
91434
91434
 
@@ -91954,7 +91954,7 @@ function AudioRow({
91954
91954
  onPointerUp: handlePointerUp,
91955
91955
  role: "button",
91956
91956
  tabIndex: 0,
91957
- "aria-label": `${name} \u2014 open, drag to timeline, right-click for actions`,
91957
+ "aria-label": `${name}: open, drag to timeline, right-click for actions`,
91958
91958
  onKeyDown: (e) => {
91959
91959
  if (e.target !== e.currentTarget) return;
91960
91960
  if (e.key === "Enter" || e.key === " ") {
@@ -92293,7 +92293,7 @@ function AssetCard({
92293
92293
  draggable: true,
92294
92294
  role: "button",
92295
92295
  tabIndex: 0,
92296
- "aria-label": `${name} \u2014 open, drag to timeline, right-click for actions`,
92296
+ "aria-label": `${name}: open, drag to timeline, right-click for actions`,
92297
92297
  onPointerDown: handlePointerDown,
92298
92298
  onPointerUp: handlePointerUp,
92299
92299
  onKeyDown: (e) => {
@@ -92387,7 +92387,7 @@ function FontRow({
92387
92387
  draggable: true,
92388
92388
  role: "button",
92389
92389
  tabIndex: 0,
92390
- "aria-label": `${name} \u2014 copy path, drag to timeline, right-click for actions`,
92390
+ "aria-label": `${name}: copy path, drag to timeline, right-click for actions`,
92391
92391
  onClick: () => onCopy(asset),
92392
92392
  onKeyDown: (e) => {
92393
92393
  if (e.target !== e.currentTarget) return;
@@ -92888,7 +92888,7 @@ function PromptPreviewModal({
92888
92888
  ref: containerRef,
92889
92889
  role: "dialog",
92890
92890
  "aria-modal": "true",
92891
- "aria-label": `Ask agent \u2014 ${title}`,
92891
+ "aria-label": `Ask agent: ${title}`,
92892
92892
  tabIndex: -1,
92893
92893
  className: "w-[560px] max-h-[80vh] flex flex-col rounded-2xl border border-neutral-800 bg-neutral-950 shadow-2xl outline-hidden",
92894
92894
  onClick: (e) => e.stopPropagation(),
@@ -93079,7 +93079,7 @@ function formatCompositionContext(ctx3) {
93079
93079
  "",
93080
93080
  `Elements visible at ${formatTime(ctx3.currentTime)}:`,
93081
93081
  ...visibleNow.map(
93082
- (el) => `- ${el.label || el.id} (track ${el.track}, ${formatTime(el.start)}\u2013${formatTime(el.start + el.duration)}${el.compositionSrc ? `, src: ${el.compositionSrc}` : ""})`
93082
+ (el) => `- ${el.label || el.id} (track ${el.track}, ${formatTime(el.start)} to ${formatTime(el.start + el.duration)}${el.compositionSrc ? `, src: ${el.compositionSrc}` : ""})`
93083
93083
  )
93084
93084
  );
93085
93085
  }
@@ -93105,7 +93105,7 @@ function buildAgentPrompt(title, name, description, category, blockType, context
93105
93105
  transitions: [
93106
93106
  `Using /hyperframes, add the "${title}" transition (registry: ${name}) between my scenes.`,
93107
93107
  `${description}`,
93108
- `Place this transition at the cut point between the current scene and the next. Set the duration to 0.5\u20131s, position it at the scene boundary on the timeline, and make sure the z-index is above both scenes. Adjust colors to match my palette.`
93108
+ `Place this transition at the cut point between the current scene and the next. Set the duration to 0.5 to 1s, position it at the scene boundary on the timeline, and make sure the z-index is above both scenes. Adjust colors to match my palette.`
93109
93109
  ].join("\n\n"),
93110
93110
  effects: [
93111
93111
  `Using /hyperframes, add the "${title}" effect (registry: ${name}) as an overlay on my composition.`,
@@ -93606,8 +93606,8 @@ function CompCard({
93606
93606
  isRoot && /* @__PURE__ */ jsx222(
93607
93607
  "span",
93608
93608
  {
93609
- "aria-label": "Root composition \u2014 opens automatically on load",
93610
- title: "Root composition \u2014 opens automatically on load",
93609
+ "aria-label": "Root composition: opens automatically on load",
93610
+ title: "Root composition: opens automatically on load",
93611
93611
  className: "flex-shrink-0 rounded-full bg-neutral-700/60 px-1.5 py-px text-[8px] font-bold uppercase tracking-wide text-neutral-300",
93612
93612
  children: "Root"
93613
93613
  }
@@ -95136,7 +95136,7 @@ var BlockParamsPanel = memo54(function BlockParamsPanel2({
95136
95136
  if (matches === 0) {
95137
95137
  setCommitState({
95138
95138
  tone: "error",
95139
- message: `Couldn't find the current value in ${compositionPath} \u2014 it may have been edited by hand.`
95139
+ message: `Couldn't find the current value in ${compositionPath}. It may have been edited by hand.`
95140
95140
  });
95141
95141
  trackBlockParamCommit({ tone: "error", blockName, key: key2 });
95142
95142
  return;
@@ -95144,7 +95144,7 @@ var BlockParamsPanel = memo54(function BlockParamsPanel2({
95144
95144
  if (matches > 1) {
95145
95145
  setCommitState({
95146
95146
  tone: "error",
95147
- message: `"${previous}" appears ${matches}\xD7 in ${compositionPath} \u2014 the panel can't tell which one belongs to this parameter, so it won't risk changing unrelated content. Edit the file directly to disambiguate.`
95147
+ message: `"${previous}" appears ${matches}\xD7 in ${compositionPath}. The panel can't tell which one belongs to this parameter, so it won't risk changing unrelated content. Edit the file directly to disambiguate.`
95148
95148
  });
95149
95149
  trackBlockParamCommit({ tone: "error", blockName, key: key2 });
95150
95150
  return;
@@ -95233,7 +95233,7 @@ var BlockParamsPanel = memo54(function BlockParamsPanel2({
95233
95233
  /* @__PURE__ */ jsxs182("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
95234
95234
  /* @__PURE__ */ jsx230("div", { className: "text-[9px] font-medium text-neutral-500 uppercase tracking-wider", children: "Parameters" }),
95235
95235
  params.length === 0 && /* @__PURE__ */ jsx230("div", { className: "text-[10px] text-neutral-500", children: "This block has no editable parameters." }),
95236
- !fileManager && params.length > 0 && /* @__PURE__ */ jsx230("div", { className: "text-[10px] text-warning-ink", children: "Block params can't be edited here \u2014 no project file access." }),
95236
+ !fileManager && params.length > 0 && /* @__PURE__ */ jsx230("div", { className: "text-[10px] text-warning-ink", children: "Block params can't be edited here: no project file access." }),
95237
95237
  params.map((param) => /* @__PURE__ */ jsx230(
95238
95238
  ParamControl,
95239
95239
  {
@@ -95716,7 +95716,7 @@ function scaleOptionLabel(scale, dims) {
95716
95716
  const resolved2 = resolvedDimensions(scale, dims);
95717
95717
  const base2 = resolved2 ? `${SCALE_LABEL[scale]} \xB7 ${resolved2.width}\xD7${resolved2.height}` : SCALE_LABEL[scale];
95718
95718
  if (dims && !scaleApplies(scale, dims)) {
95719
- return `${base2} \u2014 not an integer scale of ${dims.width}\xD7${dims.height}`;
95719
+ return `${base2} (not an integer scale of ${dims.width}\xD7${dims.height})`;
95720
95720
  }
95721
95721
  return base2;
95722
95722
  }
@@ -95816,7 +95816,7 @@ function FormatInfoTooltip({ format }) {
95816
95816
  /* @__PURE__ */ jsx234("p", { className: "text-step-9 text-text-3 leading-tight", children: info.desc }),
95817
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
95818
  /* @__PURE__ */ jsx234("span", { className: "text-text-3 font-medium", children: FORMAT_INFO[f].label }),
95819
- " \u2014 ",
95819
+ ": ",
95820
95820
  FORMAT_INFO[f].desc
95821
95821
  ] }, f)) })
95822
95822
  ]
@@ -96559,7 +96559,7 @@ function HotspotTool({
96559
96559
  /* @__PURE__ */ jsx236("span", { className: "text-neutral-200 font-mono", children: elementKey3 ?? "none" })
96560
96560
  ] }),
96561
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." }),
96562
+ sequences.length === 0 && /* @__PURE__ */ jsx236("p", { className: "text-[10px] text-neutral-500 italic", children: "Create a branch in the Branches section first. Hotspots jump to a branch." }),
96563
96563
  /* @__PURE__ */ jsx236("label", { className: "text-[11px] text-neutral-400", children: "Hotspot label" }),
96564
96564
  /* @__PURE__ */ jsx236(
96565
96565
  "input",
@@ -96581,7 +96581,7 @@ function HotspotTool({
96581
96581
  onChange: (e) => setTargetSequenceId(e.target.value),
96582
96582
  "aria-label": "Target branch sequence",
96583
96583
  children: [
96584
- /* @__PURE__ */ jsx236("option", { value: "", children: "\u2014 select branch \u2014" }),
96584
+ /* @__PURE__ */ jsx236("option", { value: "", children: "Select branch" }),
96585
96585
  sequences.map((seq) => /* @__PURE__ */ jsx236("option", { value: seq.id, children: seq.label }, seq.id))
96586
96586
  ]
96587
96587
  }
@@ -97828,7 +97828,7 @@ function HandoffFooter({
97828
97828
  ] });
97829
97829
  }
97830
97830
  var EMPTY_STATE = /* @__PURE__ */ jsxs191("p", { className: "text-[10px] leading-relaxed text-neutral-500", children: [
97831
- "No variables declared. Variables make parts of this composition dynamic \u2014 declare them here (or in ",
97831
+ "No variables declared. Variables make parts of this composition dynamic. Declare them here (or in ",
97832
97832
  /* @__PURE__ */ jsx241("code", { className: "font-mono", children: "data-composition-variables" }),
97833
97833
  "), read them with",
97834
97834
  " ",
@@ -98004,7 +98004,7 @@ var VariablesPanel = memo59(function VariablesPanel2({
98004
98004
  const wanted = action.declaration(id).type;
98005
98005
  if (existing && existing.type !== wanted) {
98006
98006
  showToast(
98007
- `"${id}" is already a ${existing.type} variable \u2014 pick another id for this ${wanted} binding`,
98007
+ `"${id}" is already a ${existing.type} variable. Pick another id for this ${wanted} binding`,
98008
98008
  "error"
98009
98009
  );
98010
98010
  return;
@@ -98064,7 +98064,7 @@ var VariablesPanel = memo59(function VariablesPanel2({
98064
98064
  onDeclare: (id) => handleAdd({ id, type: "string", label: id, default: "" })
98065
98065
  }
98066
98066
  ),
98067
- usage?.scanIncomplete && /* @__PURE__ */ jsx241("p", { className: "text-[9px] text-neutral-600", children: "Scripts access variables dynamically \u2014 usage info may be incomplete." }),
98067
+ usage?.scanIncomplete && /* @__PURE__ */ jsx241("p", { className: "text-[9px] text-neutral-600", children: "Scripts access variables dynamically, so usage info may be incomplete." }),
98068
98068
  declarations.length > 0 && /* @__PURE__ */ jsx241(
98069
98069
  HandoffFooter,
98070
98070
  {
@@ -98676,7 +98676,7 @@ var StudioRightPanels = memo60(function StudioRightPanels2({
98676
98676
  );
98677
98677
  const handleHideAllSelected = useCallback188(() => {
98678
98678
  if (!canHideSelections(domEditGroupSelections)) {
98679
- showToast("Audio can't be hidden \u2014 use the group's own controls", "info");
98679
+ showToast("Audio can't be hidden. Use the group's own controls", "info");
98680
98680
  return;
98681
98681
  }
98682
98682
  const { elements } = usePlayerStore.getState();
@@ -99078,7 +99078,7 @@ function LinkedSelectionToggle() {
99078
99078
  /* @__PURE__ */ jsx249(
99079
99079
  Tooltip,
99080
99080
  {
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",
99081
+ label: linkedSelection ? "Linked Selection on: a click selects both halves (\u2325-click for one)" : "Linked Selection off: a click selects one clip",
99082
99082
  children: /* @__PURE__ */ jsx249(
99083
99083
  "button",
99084
99084
  {
@@ -99234,7 +99234,7 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99234
99234
  /* @__PURE__ */ jsx250(
99235
99235
  Tooltip,
99236
99236
  {
99237
- label: rippleEditEnabled ? "Ripple on \u2014 keeps the main track gapless" : "Ripple off \u2014 deleting a main-track clip leaves a gap",
99237
+ label: rippleEditEnabled ? "Ripple on: keeps the main track gapless" : "Ripple off: deleting a main-track clip leaves a gap",
99238
99238
  children: /* @__PURE__ */ jsx250(
99239
99239
  "button",
99240
99240
  {
@@ -99395,12 +99395,12 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99395
99395
  /* @__PURE__ */ jsx250(
99396
99396
  Tooltip,
99397
99397
  {
99398
- label: thumbnailsVisible ? "Hide thumbnails \u2014 labels only" : "Show thumbnails \u2014 posters stay visible; richer previews appear on interaction",
99398
+ label: thumbnailsVisible ? "Hide thumbnails: labels only" : "Show thumbnails: posters stay visible; richer previews appear on interaction",
99399
99399
  children: /* @__PURE__ */ jsx250(
99400
99400
  "button",
99401
99401
  {
99402
99402
  type: "button",
99403
- "aria-label": thumbnailsVisible ? "Hide thumbnails \u2014 labels only" : "Show thumbnails \u2014 posters stay visible; richer previews appear on interaction",
99403
+ "aria-label": thumbnailsVisible ? "Hide thumbnails: labels only" : "Show thumbnails: posters stay visible; richer previews appear on interaction",
99404
99404
  "aria-pressed": thumbnailsVisible,
99405
99405
  onClick: () => setThumbnailMode(thumbnailsVisible ? "hidden" : "adaptive"),
99406
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"}`,
@@ -100949,4 +100949,3 @@ export {
100949
100949
  useTimelinePlayer,
100950
100950
  zoomTimelineToRange
100951
100951
  };
100952
- //# sourceMappingURL=index.js.map