hyperframes 0.8.81 → 0.8.83

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 (61) hide show
  1. package/dist/backgroundChecksWorker.js +890 -0
  2. package/dist/cli.js +4272 -2792
  3. package/dist/commands/layout-audit.browser.js +55 -25
  4. package/dist/fontLocalizeCli.js +714 -344
  5. package/dist/hyperframe-runtime.js +83 -58
  6. package/dist/hyperframe.manifest.json +1 -1
  7. package/dist/hyperframe.runtime.iife.js +83 -58
  8. package/dist/hyperframes-player.global.js +3 -3
  9. package/dist/registry/localSemantic.js +7 -3
  10. package/dist/renderSetupWorker.js +62 -32
  11. package/dist/sherpaWorker.js +179 -0
  12. package/dist/skills/hyperframes/SKILL.md +2 -0
  13. package/dist/skills/hyperframes/references/plugin-installation.md +43 -0
  14. package/dist/skills/hyperframes/references/skill-lifecycle.md +2 -0
  15. package/dist/skills/hyperframes/scripts/plugin-cli.mjs +88 -0
  16. package/dist/skills/hyperframes/scripts/plugin-cli.test.mjs +117 -0
  17. package/dist/skills/hyperframes-cli/SKILL.md +2 -0
  18. package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +1 -0
  19. package/dist/skills/media-use/SKILL.md +2 -0
  20. package/dist/skills/media-use/references/operations.md +7 -5
  21. package/dist/skills/media-use/references/setup-providers.md +9 -9
  22. package/dist/skills/media-use/registry/localSemantic.js +7 -3
  23. package/dist/skills/media-use/scripts/lib/ff-binaries.mjs +37 -0
  24. package/dist/skills/media-use/scripts/lib/probe.mjs +3 -1
  25. package/dist/skills/media-use/scripts/lib/probe.test.mjs +118 -1
  26. package/dist/skills/media-use/scripts/lib/tts-local-provider.mjs +5 -3
  27. package/dist/skills/media-use/scripts/resolve-plugin.test.mjs +62 -0
  28. package/dist/skills/media-use/scripts/resolve.mjs +45 -19
  29. package/dist/skills/media-use/scripts/transcribe.mjs +39 -25
  30. package/dist/skills/media-use/scripts/transcribe.test.mjs +112 -0
  31. package/dist/skills/registry/localSemantic.js +7 -3
  32. package/dist/studio/assets/{hyperframes-player-C68UawR3.js → hyperframes-player-BAerMCex.js} +1 -1
  33. package/dist/studio/assets/{index-CMzPGv9P.js → index-BUhcVhNy.js} +1 -1
  34. package/dist/studio/assets/{index-hNVM9Pd2.js → index-BYhK_KMc.js} +187 -187
  35. package/dist/studio/assets/{index-CS5SImRT.js → index-Iv0HI7eM.js} +1 -1
  36. package/dist/studio/{chunk-I7XNAIOF.js → chunk-3IOCVWB6.js} +6 -97
  37. package/dist/studio/chunk-3IOCVWB6.js.map +1 -0
  38. package/dist/studio/chunk-62DDWOSH.js +189 -0
  39. package/dist/studio/chunk-62DDWOSH.js.map +1 -0
  40. package/dist/studio/chunk-LPZMAGS7.js +1871 -0
  41. package/dist/studio/chunk-LPZMAGS7.js.map +1 -0
  42. package/dist/studio/chunk-QZ6HNNFG.js +934 -0
  43. package/dist/studio/chunk-QZ6HNNFG.js.map +1 -0
  44. package/dist/studio/chunk-S65AQH6M.js +101 -0
  45. package/dist/studio/chunk-S65AQH6M.js.map +1 -0
  46. package/dist/studio/{domEditingLayers-MHFDKAQ7.js → domEditingLayers-ZOOMN7CQ.js} +3 -2
  47. package/dist/studio/index.d.ts +834 -330
  48. package/dist/studio/index.html +1 -1
  49. package/dist/studio/index.js +26378 -28802
  50. package/dist/studio/index.js.map +1 -1
  51. package/dist/studio/player.d.ts +30 -0
  52. package/dist/studio/player.js +10 -0
  53. package/dist/studio/player.js.map +1 -0
  54. package/dist/studio/ui.d.ts +294 -0
  55. package/dist/studio/ui.js +66 -0
  56. package/dist/studio/ui.js.map +1 -0
  57. package/dist/templates/_shared/AGENTS.md +5 -1
  58. package/dist/templates/_shared/CLAUDE.md +5 -1
  59. package/package.json +1 -1
  60. package/dist/studio/chunk-I7XNAIOF.js.map +0 -1
  61. /package/dist/studio/{domEditingLayers-MHFDKAQ7.js.map → domEditingLayers-ZOOMN7CQ.js.map} +0 -0
@@ -1,331 +1,23 @@
1
- import * as react from 'react';
2
- import { ButtonHTMLAttributes, ReactNode, ElementType, ComponentPropsWithoutRef, ReactElement, RefObject, MutableRefObject, DragEventHandler, ComponentProps, RefCallback, MouseEvent, CSSProperties, UIEvent, PointerEvent } from 'react';
1
+ export { Button, ButtonSize, ButtonVariant, ContextMenu, HyperframesLoader, HyperframesLoaderProps, HyperframesLogo, IconButton, Input, InputProps, Menu, MenuItem, MenuItemTone, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, NumberField, NumberFieldProps, Popover, PopupPreviewState, PreviewState, Select, SelectOption, SelectProps, Slider, SliderProps, Tab, TabPanel, Tabs, TabsList, Toggle, ToggleProps, Tooltip, buttonBase, buttonSizes, buttonVariants, cn, fieldBase, fieldText, popupSurface } from './ui.js';
3
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
- import { Tabs as Tabs$1 } from '@base-ui/react/tabs';
5
- import * as node_modules_cn_dist_types from 'node_modules/cn/dist/types';
6
- import { ContextMenu as ContextMenu$1 } from '@base-ui/react/context-menu';
7
- import { Menu as Menu$1 } from '@base-ui/react/menu';
8
- import { Popover as Popover$1 } from '@base-ui/react/popover';
3
+ import * as react from 'react';
4
+ import { RefObject, MutableRefObject, ReactNode, DragEventHandler, ComponentProps, RefCallback, MouseEvent, CSSProperties, UIEvent, PointerEvent } from 'react';
9
5
  import { RuntimeTimelineClipIdentity, HyperframePickerElementInfo } from '@hyperframes/core';
10
- import { GsapAnimation, PropertyGroupName } from '@hyperframes/core/gsap-parser';
6
+ import { GsapAnimation, ParsedGsap, PropertyGroupName } from '@hyperframes/core/gsap-parser';
7
+ export { Player } from './player.js';
8
+ import { Composition } from '@hyperframes/sdk';
11
9
  import { MusicBeatAnalysis } from '@hyperframes/core/beats';
12
10
  import * as zustand from 'zustand';
13
11
  import { StoreApi } from 'zustand';
14
12
  import { GsapAnimation as GsapAnimation$1, ArcPathSegment } from '@hyperframes/parsers/gsap-parser';
13
+ import * as _hyperframes_parsers from '@hyperframes/parsers';
15
14
  import { CanvasResolution } from '@hyperframes/parsers';
16
- import { Composition } from '@hyperframes/sdk';
17
15
  export { SeamTransitionFrameSource, SeamTransitionLoopHandle, SeamTransitionLoopOptions, playSeamTransitionLoop } from '@hyperframes/shader-transitions';
18
-
19
- type ButtonVariant = "primary" | "secondary" | "danger" | "ghost";
20
- type ButtonSize = "sm" | "md" | "lg";
21
- /** Forces one interactive look for a gallery shot. CSS-only; see the header. */
22
- type PreviewState = "hover" | "active" | "focus";
23
- interface ButtonBaseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
24
- variant?: ButtonVariant;
25
- size?: ButtonSize;
26
- "data-preview-state"?: PreviewState;
27
- }
28
- interface ButtonProps extends ButtonBaseProps {
29
- loading?: boolean;
30
- icon?: ReactNode;
31
- }
32
- /**
33
- * Shared by Button and IconButton. `disabled:` keeps pointer events alive so a
34
- * wrapping Tooltip can still explain why the control is disabled.
35
- */
36
- declare const buttonBase: string;
37
- /**
38
- * One entry per variant. The `data-[preview-state=…]` half of each string
39
- * repeats the `hover:` and `active:` half exactly; the test pairs them.
40
- */
41
- declare const buttonVariants: Record<ButtonVariant, string>;
42
- /**
43
- * The three control heights, 24 / 28 / 32 px, from `--spacing-ctl-*`.
44
- * Exported so the Capture download `<a href>` can wear the same recipe as a Button.
45
- */
46
- declare const buttonSizes: Record<ButtonSize, string>;
47
- declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
48
-
49
- declare function HyperframesLogo(): react_jsx_runtime.JSX.Element;
50
-
51
- interface IconButtonProps extends ButtonBaseProps {
52
- icon: ReactNode;
53
- "aria-label": string;
54
- }
55
- declare const IconButton: react.ForwardRefExoticComponent<IconButtonProps & react.RefAttributes<HTMLButtonElement>>;
56
-
57
- /**
58
- * Base UI lets `className` be a function of the part's state. Studio's parts
59
- * merge a string with `cn`, so the string form is the one they accept.
60
- */
61
- type StyledProps$1<T extends ElementType> = Omit<ComponentPropsWithoutRef<T>, "className"> & {
62
- className?: string;
63
- };
64
- /**
65
- * Groups a tab list with its panels. Uncontrolled by default; pass `value` and
66
- * `onValueChange` for a strip whose selection lives in a store.
67
- */
68
- declare function Tabs(props: ComponentPropsWithoutRef<typeof Tabs$1.Root>): react_jsx_runtime.JSX.Element;
69
- /** The strip. Give it an `aria-label`: a tablist with no name is unlabelled. */
70
- declare function TabsList({ className, ...props }: StyledProps$1<typeof Tabs$1.List>): react_jsx_runtime.JSX.Element;
71
- interface TabProps extends StyledProps$1<typeof Tabs$1.Tab> {
72
- value: string;
73
- "data-preview-state"?: PreviewState;
74
- }
75
- /**
76
- * aria-selected drives the selected look (Base UI sets it) so assistive tech
77
- * and sighted users match. data-preview-state is for gallery shots only.
78
- */
79
- declare function Tab({ value, className, ...props }: TabProps): react_jsx_runtime.JSX.Element;
80
- /** The panel for one tab. Base UI wires `aria-labelledby` back to its tab. */
81
- declare function TabPanel({ className, ...props }: StyledProps$1<typeof Tabs$1.Panel>): react_jsx_runtime.JSX.Element;
82
-
83
- interface HyperframesLoaderProps {
84
- /** Status text shown below the mark. */
85
- title: string;
86
- /** Optional secondary detail line. */
87
- detail?: string;
88
- /** Optional monospace third line for IDs, counts, or percentages. */
89
- mono?: string;
90
- /** Pixel size of the mark itself; status text scales independently. */
91
- size?: number;
92
- /** Optional normalized progress value from 0 to 1. */
93
- progress?: number;
94
- }
95
- declare function HyperframesLoader({ title, detail, mono, size, progress, }: HyperframesLoaderProps): react_jsx_runtime.JSX.Element;
96
-
97
- interface TooltipProps {
98
- label: string;
99
- /** A single element, wrapped in a box-less span so a disabled one still gets hover. */
100
- children: ReactElement<{
101
- "aria-describedby"?: string;
102
- }>;
103
- /** Hover delay in ms. */
104
- delay?: number;
105
- side?: "top" | "bottom" | "left" | "right";
106
- }
107
- declare function Tooltip({ label, children, delay, side }: TooltipProps): react_jsx_runtime.JSX.Element;
108
-
109
- /**
110
- * Studio's tailwind-merge config: teaches it the two scales `theme.css`
111
- * invents (`text-step-*`, `ctl`/`ctl-sm`/`ctl-lg`) so overrides replace, not stack.
112
- */
113
- declare const cn: node_modules_cn_dist_types.CnFunction;
114
-
115
- /**
116
- * Base UI lets `className` be a function of the part's state. Studio's parts
117
- * merge a string with `cn`, so the string form is the one they accept.
118
- */
119
- type StyledProps<T extends ElementType> = Omit<ComponentPropsWithoutRef<T>, "className"> & {
120
- className?: string;
121
- };
122
- /** Forces the settled open look for a gallery shot; CSS-only, open state stays controlled. */
123
- type PopupPreviewState = "open";
124
- /** Where the portal puts the popup. `null` keeps it inline, next to its trigger. */
125
- type PortalContainer$1 = ComponentPropsWithoutRef<typeof Menu$1.Portal>["container"];
126
- /**
127
- * Chrome shared by every floating panel (`Popover` too); callers add their own shadow token.
128
- */
129
- declare const popupSurface: string;
130
- type MenuItemTone = "default" | "danger";
131
- interface PositionedProps {
132
- side?: "top" | "bottom" | "left" | "right";
133
- align?: "start" | "center" | "end";
134
- sideOffset?: number;
135
- /** Portal target. Pass the shadow root when the trigger lives in one. */
136
- container?: PortalContainer$1;
137
- /** Names the popup for assistive tech. A menu with no name is unlabelled. */
138
- "aria-label"?: string;
139
- className?: string;
140
- "data-preview-state"?: PopupPreviewState;
141
- }
142
- interface MenuProps extends PositionedProps, Omit<ComponentPropsWithoutRef<typeof Menu$1.Root>, "children"> {
143
- /** A single element. It becomes the trigger; no wrapper is added around it. */
144
- trigger: ReactElement;
145
- /** The items: `MenuItem`, `MenuRadioGroup`, `MenuSeparator`. */
146
- children: ReactNode;
147
- }
148
- /**
149
- * A menu opened by its trigger. Uncontrolled by default; pass `open` and
150
- * `onOpenChange` for a menu whose state lives in a store.
151
- */
152
- declare function Menu({ trigger, children, side, align, sideOffset, container, className, "aria-label": ariaLabel, "data-preview-state": previewState, ...root }: MenuProps): react_jsx_runtime.JSX.Element;
153
- interface ContextMenuProps extends PositionedProps, Omit<ComponentPropsWithoutRef<typeof ContextMenu$1.Root>, "children"> {
154
- /**
155
- * The right-clickable area, as the caller's own element. Its children are
156
- * kept: the trigger renders that element rather than wrapping it.
157
- */
158
- trigger: ReactElement;
159
- children: ReactNode;
160
- }
161
- /** Opened by right click or long press at the pointer, so `side` and `align` are not offered. */
162
- declare function ContextMenu({ trigger, children, container, className, "aria-label": ariaLabel, "data-preview-state": previewState, ...root }: Omit<ContextMenuProps, "side" | "align" | "sideOffset">): react_jsx_runtime.JSX.Element;
163
- /** Keyboard shortcut hint, mono and tabular; exported for hints that are not a plain string. */
164
- declare function MenuShortcut({ className, ...props }: StyledProps<"span">): react_jsx_runtime.JSX.Element;
165
- interface MenuItemProps extends StyledProps<typeof Menu$1.Item> {
166
- /** Rendered as a dim mono hint on the trailing edge. Decorative. */
167
- shortcut?: string;
168
- /** `danger` for a destructive action (Delete, Remove). */
169
- tone?: MenuItemTone;
170
- "data-preview-state"?: "hover";
171
- }
172
- /** One action. `disabled` items are skipped by the arrow keys, not just dimmed. */
173
- declare function MenuItem({ shortcut, tone, className, children, ...props }: MenuItemProps): react_jsx_runtime.JSX.Element;
174
- /** Single-choice group; selection is `aria-checked` on each item, which the dot indicator draws from. */
175
- declare function MenuRadioGroup(props: ComponentPropsWithoutRef<typeof Menu$1.RadioGroup>): react_jsx_runtime.JSX.Element;
176
- interface MenuRadioItemProps extends StyledProps<typeof Menu$1.RadioItem> {
177
- "data-preview-state"?: "hover";
178
- }
179
- /** One choice in a `MenuRadioGroup`. The dot renders only while it is checked. */
180
- declare function MenuRadioItem({ className, children, ...props }: MenuRadioItemProps): react_jsx_runtime.JSX.Element;
181
- /** A hairline between two groups of items. */
182
- declare function MenuSeparator({ className, ...props }: StyledProps<typeof Menu$1.Separator>): react_jsx_runtime.JSX.Element;
183
-
184
- type PortalContainer = ComponentPropsWithoutRef<typeof Popover$1.Portal>["container"];
185
- interface PopoverProps extends Omit<ComponentPropsWithoutRef<typeof Popover$1.Root>, "children"> {
186
- /** A single element. It becomes the trigger; no wrapper is added around it. */
187
- trigger: ReactElement;
188
- /** Arbitrary content. The popover owns none of its keys. */
189
- children: ReactNode;
190
- side?: "top" | "bottom" | "left" | "right";
191
- align?: "start" | "center" | "end";
192
- sideOffset?: number;
193
- /** Portal target. Pass the shadow root when the trigger lives in one. */
194
- container?: PortalContainer;
195
- /** Names the popup for assistive tech. */
196
- "aria-label"?: string;
197
- /**
198
- * What to focus on open. Defaults to Base UI's behaviour (the first tabbable
199
- * element), which is what a rename field wants.
200
- */
201
- initialFocus?: ComponentPropsWithoutRef<typeof Popover$1.Popup>["initialFocus"];
202
- className?: string;
203
- "data-preview-state"?: PopupPreviewState;
204
- }
205
- declare function Popover({ trigger, children, side, align, sideOffset, container, className, initialFocus, "aria-label": ariaLabel, "data-preview-state": previewState, ...root }: PopoverProps): react_jsx_runtime.JSX.Element;
206
-
207
- /**
208
- * Shared field look (also used by NumberField and Select). Each interactive state is written
209
- * twice, real and `data-[preview-state=...]`; `valueControls.test.tsx` asserts the lists match.
210
- */
211
- declare const fieldBase: string;
212
- /** The text itself, inside the box. The box owns the border and the ring. */
213
- declare const fieldText: string;
214
- interface InputProps extends Omit<ComponentPropsWithoutRef<"input">, "value" | "onChange" | "className"> {
215
- /** The committed value. A draft lives inside until Enter or blur. */
216
- value: string;
217
- /** Called with the draft on Enter and on blur, only when it really changed. */
218
- onCommit: (next: string) => void;
219
- /** Called once per committed change, for design-input telemetry. */
220
- onTrack?: () => void;
221
- /** Marks the field invalid: red boundary and `aria-invalid`. */
222
- invalid?: boolean;
223
- className?: string;
224
- "data-preview-state"?: PreviewState;
225
- }
226
- declare function Input({ value, onCommit, onTrack, invalid, disabled, className, "data-preview-state": previewState, ...props }: InputProps): react_jsx_runtime.JSX.Element;
227
-
228
- interface NumberFieldProps {
229
- /** Accessible name. The inspector's row label is the usual one. */
230
- label: string;
231
- /** The committed value. */
232
- value: number;
233
- /** Called when a commit boundary produces a value different from `value`. */
234
- onCommit: (next: number) => void;
235
- /** Called once per committed change, for design-input telemetry. */
236
- onTrack?: () => void;
237
- /** Rendered beside the number: "px", "%", "deg". Never part of the text. */
238
- unit?: string;
239
- min?: number;
240
- max?: number;
241
- step?: number;
242
- disabled?: boolean;
243
- className?: string;
244
- "data-preview-state"?: PreviewState;
245
- }
246
- declare function NumberField({ label, value, onCommit, onTrack, unit, min, max, step, disabled, className, "data-preview-state": previewState, }: NumberFieldProps): react_jsx_runtime.JSX.Element;
247
-
248
- interface SelectOption {
249
- label: string;
250
- value: string;
251
- /** Offered but not choosable; the label stays visible so the reason stays visible too. */
252
- disabled?: boolean;
253
- }
254
- interface SelectProps {
255
- /** Accessible name for the trigger. */
256
- label: string;
257
- value: string;
258
- options: SelectOption[];
259
- /** Called when a different option is chosen. */
260
- onCommit: (next: string) => void;
261
- /** Called once per committed change, for design-input telemetry. */
262
- onTrack?: () => void;
263
- disabled?: boolean;
264
- className?: string;
265
- "data-preview-state"?: PreviewState;
266
- }
267
- declare function Select({ label, value, options, onCommit, onTrack, disabled, className, "data-preview-state": previewState, }: SelectProps): react_jsx_runtime.JSX.Element;
268
-
269
- interface SliderProps {
270
- /** Accessible name for the thumb. The inspector's row label is the usual one. */
271
- label: string;
272
- /** The committed value. */
273
- value: number;
274
- min: number;
275
- max: number;
276
- step?: number;
277
- /** Every intermediate value while dragging or stepping. Not a commit. */
278
- onPreview?: (next: number) => void;
279
- /** Called at a commit boundary when the value really changed. */
280
- onCommit: (next: number) => void;
281
- /** Called once per commit boundary, for design-input telemetry. */
282
- onTrack?: () => void;
283
- disabled?: boolean;
284
- className?: string;
285
- "data-preview-state"?: PreviewState;
286
- }
287
- declare function Slider({ label, value, min, max, step, onPreview, onCommit, onTrack, disabled, className, "data-preview-state": previewState, }: SliderProps): react_jsx_runtime.JSX.Element;
288
-
289
- interface ToggleProps {
290
- /** Accessible name. */
291
- label: string;
292
- checked: boolean;
293
- /** Called on every flip. */
294
- onCommit: (next: boolean) => void;
295
- /** Called once per flip, for design-input telemetry. */
296
- onTrack?: () => void;
297
- disabled?: boolean;
298
- className?: string;
299
- "data-preview-state"?: PreviewState;
300
- }
301
- declare function Toggle({ label, checked, onCommit, onTrack, disabled, className, "data-preview-state": previewState, }: ToggleProps): react_jsx_runtime.JSX.Element;
302
-
303
- interface PlayerProps {
304
- projectId?: string;
305
- directUrl?: string;
306
- onLoad: () => void;
307
- /** Fires once the loaded document is painted and every loader (shader, assets) has cleared. */
308
- onReadyToShowChange?: (ready: boolean) => void;
309
- onPreviewError?: (message: string) => void;
310
- onCompositionLoadingChange?: (loading: boolean) => void;
311
- onPainted?: (details: {
312
- iframe: HTMLIFrameElement;
313
- startedAt: number;
314
- loadId: number;
315
- }) => void;
316
- portrait?: boolean;
317
- style?: React.CSSProperties;
318
- suppressLoadingOverlay?: boolean;
319
- }
320
- /**
321
- * Renders a composition preview using the <hyperframes-player> web component.
322
- *
323
- * The web component handles iframe scaling, dimension detection, and
324
- * ResizeObserver internally. This wrapper bridges its inner iframe to the
325
- * forwarded ref so useTimelinePlayer can access it for clip manifest parsing,
326
- * timeline probing, and DOM inspection.
327
- */
328
- declare const Player: react.ForwardRefExoticComponent<PlayerProps & react.RefAttributes<HTMLIFrameElement>>;
16
+ import '@base-ui/react/tabs';
17
+ import 'node_modules/cn/dist/types';
18
+ import '@base-ui/react/context-menu';
19
+ import '@base-ui/react/menu';
20
+ import '@base-ui/react/popover';
329
21
 
330
22
  interface ShortcutHint {
331
23
  key: string;
@@ -654,8 +346,9 @@ interface TimelineElement {
654
346
  playbackRate?: number;
655
347
  sourceDuration?: number;
656
348
  volume?: number;
657
- /** `data-has-audio="true"` on a video: its sound is mixed, so it takes audio affordances (fades). */
349
+ /** A video with sound to mix (`data-has-audio`, or unmuted without it); `muted` silences it. */
658
350
  hasAudio?: boolean;
351
+ muted?: boolean;
659
352
  /** Clip-edge fades from `data-fade-in` / `data-fade-out`, seconds; absent means none. */
660
353
  fadeIn?: number;
661
354
  fadeOut?: number;
@@ -1080,6 +773,12 @@ interface TimelineRangeSelection {
1080
773
  anchorY: number;
1081
774
  }
1082
775
 
776
+ /** Durable evidence returned by the one Studio DOM persistence actor. */
777
+ interface DomEditPersistOutcome {
778
+ sourceFile: string;
779
+ version: string;
780
+ changed: boolean;
781
+ }
1083
782
  /**
1084
783
  * Durability report for a patch-batches commit. `durable === false` means the
1085
784
  * server could not locate at least one patch target on disk — the preview was
@@ -1094,7 +793,7 @@ interface DomEditPatchBatchesResult {
1094
793
  changed: boolean;
1095
794
  }
1096
795
 
1097
- interface RecordEditInput$1 {
796
+ interface RecordEditInput$4 {
1098
797
  label: string;
1099
798
  coalesceKey?: string;
1100
799
  files: Record<string, {
@@ -1118,7 +817,7 @@ interface UseTimelineEditingOptions {
1118
817
  showToast: (message: string, tone?: "error" | "info") => void;
1119
818
  writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
1120
819
  observeProjectFileVersion?: (path: string, version: string | null) => void;
1121
- recordEdit: (input: RecordEditInput$1) => Promise<void>;
820
+ recordEdit: (input: RecordEditInput$4) => Promise<void>;
1122
821
  reloadPreview: () => void;
1123
822
  previewIframeRef: RefObject<HTMLIFrameElement | null>;
1124
823
  pendingTimelineEditPathRef: MutableRefObject<Set<string>>;
@@ -1142,6 +841,101 @@ type TimelineMoveUpdates = Pick<TimelineElement, "start" | "track"> & {
1142
841
  stackingReorder?: TimelineStackingReorderIntent | null;
1143
842
  };
1144
843
 
844
+ /** Value-only channels a `tl.set(...)` patch may touch. */
845
+ interface SetPatchProps {
846
+ x?: number;
847
+ y?: number;
848
+ rotation?: number;
849
+ rotationX?: number;
850
+ rotationY?: number;
851
+ rotationZ?: number;
852
+ z?: number;
853
+ transformPerspective?: number;
854
+ scaleX?: number;
855
+ scaleY?: number;
856
+ scale?: number;
857
+ opacity?: number;
858
+ }
859
+ /** A single keyframe step's numeric channels (the GSAP array-keyframe form). */
860
+ type KeyframeStep = Record<string, number>;
861
+ type RuntimeTweenChange = {
862
+ kind: "set";
863
+ props: SetPatchProps;
864
+ } | {
865
+ kind: "keyframes";
866
+ keyframes: KeyframeStep[];
867
+ } | {
868
+ kind: "keyframe-rebuild";
869
+ pct: number;
870
+ props: KeyframeStep;
871
+ } | {
872
+ kind: "global-set";
873
+ props: SetPatchProps;
874
+ };
875
+
876
+ interface MutationResult {
877
+ ok: boolean;
878
+ changed?: boolean;
879
+ parsed?: ParsedGsap;
880
+ before?: string;
881
+ after?: string;
882
+ scriptText?: string;
883
+ }
884
+ interface CommitMutationOptions {
885
+ label: string;
886
+ /** Observe the durable writer result without duplicating the request path. */
887
+ onResult?: (result: MutationResult) => void;
888
+ coalesceKey?: string;
889
+ coalesceMs?: number;
890
+ softReload?: boolean;
891
+ skipReload?: boolean;
892
+ /**
893
+ * Write the source but leave the preview alone; the caller renders once when it
894
+ * is done. For a multi-write action like a group drag, rendering after each
895
+ * write shows a source where the members not yet written still hold their old
896
+ * values, so they snap back until their own write lands. This also defers the
897
+ * in-place runtime patch's seek, which re-renders the whole timeline and repaints
898
+ * the queued members the same way. Unlike `skipReload` this changes nothing about
899
+ * error handling — a failed write still throws.
900
+ */
901
+ deferPreviewSync?: boolean;
902
+ /** Shares an in-place patch miss with the final render of one multi-write action. */
903
+ previewFallbackLatch?: {
904
+ pending: boolean;
905
+ };
906
+ beforeReload?: () => void;
907
+ /**
908
+ * Serialize this commit against others sharing the same key. Used to chain
909
+ * per-animationId GSAP meta updates. Every commit independently takes the
910
+ * project/file mutation lock, so this key only adds ordering and can never
911
+ * bypass whole-file serialization.
912
+ */
913
+ serializeKey?: string;
914
+ /**
915
+ * Value-only edit fast path. When present, `runCommit` first tries to patch the
916
+ * one changed tween in the preview's runtime timeline in place
917
+ * (`patchRuntimeTweenInPlace`) — instant, no composition re-run, no iframe
918
+ * remount. On a successful patch the reload is skipped entirely (panels still
919
+ * refresh); when the patch can't be confidently applied it falls back to the
920
+ * existing soft/full reload path. Structural edits omit this and reload as before.
921
+ */
922
+ instantPatch?: {
923
+ selector: string;
924
+ change: RuntimeTweenChange;
925
+ };
926
+ /**
927
+ * The same fast path for a batched commit: one patch per element the batch
928
+ * wrote, applied in order. All of them must land for the reload to be skipped
929
+ * — one that can't be applied leaves the preview half-patched, so the whole
930
+ * batch falls back to the reload. Only the last patch re-renders (see
931
+ * `deferSeek`), so a ten-element batch repaints once.
932
+ */
933
+ instantPatches?: Array<{
934
+ selector: string;
935
+ change: RuntimeTweenChange;
936
+ }>;
937
+ }
938
+
1145
939
  interface TimelineGroupMoveChange {
1146
940
  element: TimelineElement;
1147
941
  start: number;
@@ -1310,18 +1104,24 @@ interface TimelineTheme {
1310
1104
 
1311
1105
  type TimelineEditOverrides = Pick<TimelineEditCallbacks, "onMoveElement" | "onMoveElements" | "onResizeElement" | "onResizeElements" | "onBlockedEditAttempt" | "onSplitElement">;
1312
1106
 
1107
+ /** With both set, a lane move restacks the preview's z-index to match the rows; each overrides Studio's own. */
1108
+ interface TimelineStackingSyncProps {
1109
+ previewIframeRef?: RefObject<HTMLIFrameElement | null>;
1110
+ onZIndexReorder?: TimelineZIndexReorderCommit;
1111
+ }
1112
+
1313
1113
  interface TimelineClipRenderContext {
1314
1114
  priority: "overscan" | "visible" | "interaction";
1315
1115
  rich: boolean;
1316
1116
  }
1317
- interface TimelineProps extends TimelineDropCallbacks, TimelineEditOverrides {
1117
+ interface TimelineProps extends TimelineDropCallbacks, TimelineEditOverrides, TimelineStackingSyncProps {
1318
1118
  /** Project-scoped reset boundary; soft source refreshes retain the same epoch. */
1319
1119
  sessionEpoch?: number;
1320
- /** keepPlaying: true preserves the current play state across the seek. */
1321
1120
  onSeek?: (time: number, options?: {
1322
1121
  keepPlaying?: boolean;
1323
1122
  }) => void;
1324
1123
  onDrillDown?: (element: TimelineElement) => void;
1124
+ /** Picture only: takes no pointer input. Interactive content goes in renderClipOverlay. */
1325
1125
  renderClipContent?: (element: TimelineElement, style: {
1326
1126
  clip: string;
1327
1127
  label: string;
@@ -1347,7 +1147,7 @@ interface TimelineEmptyStateProps {
1347
1147
  }
1348
1148
  declare function TimelineEmptyState({ isDragOver, onFileDrop, onDragOver, onDragLeave, onDrop, }: TimelineEmptyStateProps): react_jsx_runtime.JSX.Element;
1349
1149
 
1350
- interface Rect {
1150
+ interface Rect$1 {
1351
1151
  left: number;
1352
1152
  top: number;
1353
1153
  width: number;
@@ -1694,7 +1494,7 @@ type TimelineCanvasState = Omit<TimelineLaneBaseProps, "setRangeSelection" | "se
1694
1494
  effectiveDuration: number;
1695
1495
  majorTickInterval: number;
1696
1496
  rangeSelection: TimelineRangeSelection | null;
1697
- marqueeRect: Rect | null;
1497
+ marqueeRect: Rect$1 | null;
1698
1498
  resizingClip: ResizingClipState | null;
1699
1499
  isScrubbing: boolean;
1700
1500
  playheadRef: React.RefObject<HTMLDivElement | null>;
@@ -2448,6 +2248,7 @@ interface StudioAppProps {
2448
2248
  }
2449
2249
  declare function StudioApp({ readOnlyPreview, readOnlyPreviewReason }?: StudioAppProps): react_jsx_runtime.JSX.Element;
2450
2250
 
2251
+ type RightPanelTab = "layers" | "design" | "renders" | "block-params" | "slideshow" | "variables";
2451
2252
  interface AgentModalAnchorPoint {
2452
2253
  x: number;
2453
2254
  y: number;
@@ -2648,7 +2449,7 @@ declare function findElementBlock(html: string, elementId: string): {
2648
2449
  isSelfClosing: boolean;
2649
2450
  } | null;
2650
2451
 
2651
- interface RecordEditInput {
2452
+ interface RecordEditInput$3 {
2652
2453
  label: string;
2653
2454
  coalesceKey?: string;
2654
2455
  coalesceMs?: number;
@@ -2694,7 +2495,7 @@ declare function usePersistentEditHistory({ projectId }: UsePersistentEditHistor
2694
2495
  createdAt: number;
2695
2496
  }[];
2696
2497
  };
2697
- recordEdit: ({ label, coalesceKey, coalesceMs, files }: RecordEditInput) => Promise<void>;
2498
+ recordEdit: ({ label, coalesceKey, coalesceMs, files }: RecordEditInput$3) => Promise<void>;
2698
2499
  undo: (callbacks: ApplyCallbacks) => Promise<ApplyResult>;
2699
2500
  redo: (callbacks: ApplyCallbacks) => Promise<ApplyResult>;
2700
2501
  };
@@ -2890,4 +2691,707 @@ declare function TimelineEditProvider({ value, children, }: {
2890
2691
  children: ReactNode;
2891
2692
  }): react_jsx_runtime.JSX.Element;
2892
2693
 
2893
- export { type AgentModalAnchorPoint, type AgentPromptElementInfo, AskAgentModal, type AskAgentModalProps, AudioWaveform, type AudioWaveformProps, type BlockedTimelineEditIntent, Button, type ButtonSize, type ButtonVariant, type CanEditTimelineElement, CompositionBreadcrumb, type CompositionDimensions, type CompositionLevel, CompositionThumbnail, ContextMenu, DEFAULT_SHORTCUT_SECTIONS, type EditHistoryHandle, EditorShell, type EditorShellProps, type ExternalFileChangeBlockedState, type ExternalFileChangeCoordinatorHandle, ExternalFileConflictBanner, type FfmpegStatus, FileTree, GridOverlay, HyperframesLoader, type HyperframesLoaderProps, HyperframesLogo, IconButton, ImageThumbnail, type ImageThumbnailProps, Input, type InputProps, Menu, MenuItem, type MenuItemTone, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, NLEPreview, NumberField, type NumberFieldProps, type PatchOperation, type PersistedRenderSettings, type PickedElement, Player, PlayerControls, type PlayerHandle, type PlayerHandleElement, type PlayerHandleListener, type PlayerHandleTimeListener, Popover, type PopupPreviewState, type DomEditCompositionRect as PreviewCompositionRect, PreviewGuides, PreviewOverlayProvider, type PreviewOverlayProviderProps, type PreviewSnapPreferences, type PreviewState, PropertyPanel, type RenderJob, RenderQueue, type RenderQueueProps, type ResolutionPreset, Select, type SelectOption, type SelectProps, type ShortcutHint, type ShortcutSection, Slider, type SliderProps, SnapToolbar, SourceEditor, type StartRenderOptions, StudioApp, StudioFileConflictError, type StudioPendingEditsDrainResult, Tab, TabPanel, Tabs, TabsList, type ThumbnailPriority, Timeline, TimelineClipMenu, type TimelineClipRenderContext, type TimelineEditCallbacks, type TimelineEditOutcome, type TimelineEditPermission, TimelineEditPopover, TimelineEditProvider, type TimelineElement, TimelineEmptyStatePart, TimelineFrame, TimelineGapMenu, TimelineKeyframeMenu, TimelineLanes, TimelineOverlays, TimelinePane, type TimelinePaneProps, TimelinePlayhead, TimelineProvider, TimelineRazorGuide, TimelineRuler, TimelineShortcutHint, type TimelineTheme, type TimelineTimeRange$1 as TimelineTimeRange, Toggle, type ToggleProps, Tooltip, type UseEditHistoryActionsOptions, type UsePersistentEditHistoryOptions, type UseProjectFileWriterOptions, type UseRenderClipContentOptions, type UseTimelineEditingOptions, VideoThumbnail, applyPatch, buildPickerAgentContextPreview, buildPickerAgentPrompt, buttonBase, buttonSizes, buttonVariants, cn, fieldBase, fieldText, findElementBlock, flushStudioPendingEdits, formatTime, getPersistedRenderSettings, liveTime, mergeStyleIntoTag, parseStyleString, persistRenderSettings, popupSurface, resolveIframe, resolveSourceFile, useEditHistoryActions, useElementPicker, usePersistentEditHistory, usePlayerHandle, usePlayerStore, usePreviewCompositionRect, usePreviewGuidesStore, usePreviewOverlayContext, useProjectFileWriter, useRenderClipContent, useRenderQueue, useTimelineContext, useTimelineEditing, useTimelinePlayer };
2694
+ interface EnableKeyframesSession {
2695
+ domEditSelection: DomEditSelection | null;
2696
+ selectedGsapAnimations: GsapAnimation[];
2697
+ previewIframeRef?: React.RefObject<HTMLIFrameElement | null>;
2698
+ handleGsapAddAnimation: (method: "to" | "from" | "set" | "fromTo") => void;
2699
+ handleGsapConvertToKeyframes: (animId: string, resolvedFromValues?: Record<string, number | string>, duration?: number, commitOverrides?: Partial<CommitMutationOptions>) => void | Promise<void>;
2700
+ handleGsapRemoveKeyframe: (animId: string, pct: number) => void;
2701
+ handleGsapAddKeyframeBatch?: (animId: string, pct: number, properties: Record<string, number | string>, commitOverrides?: Partial<CommitMutationOptions>) => Promise<void>;
2702
+ commitMutation?: (mutation: Record<string, unknown>, options: CommitMutationOptions) => Promise<void>;
2703
+ }
2704
+
2705
+ interface TimelineHistoryButtonsProps {
2706
+ canUndo?: boolean;
2707
+ canRedo?: boolean;
2708
+ undoLabel?: string;
2709
+ redoLabel?: string;
2710
+ onUndo?: () => Promise<void> | void;
2711
+ onRedo?: () => Promise<void> | void;
2712
+ }
2713
+ /** Undo and Redo: a host's props win, else the shell's edit history. */
2714
+ declare function TimelineHistoryButtons(props: TimelineHistoryButtonsProps): react_jsx_runtime.JSX.Element;
2715
+
2716
+ interface DomEditSessionSlice extends EnableKeyframesSession {
2717
+ domEditSelection: DomEditSelection | null;
2718
+ selectedGsapAnimations: GsapAnimation[];
2719
+ }
2720
+ interface TimelineToolbarProps {
2721
+ domEditSession?: DomEditSessionSlice;
2722
+ onSplitElement?: (element: TimelineElement, splitTime: number) => void;
2723
+ history?: TimelineHistoryButtonsProps;
2724
+ showAddBeat?: boolean;
2725
+ }
2726
+ declare function TimelineToolbar({ domEditSession, onSplitElement, history, showAddBeat, }: TimelineToolbarProps): react_jsx_runtime.JSX.Element;
2727
+
2728
+ interface AudioMeterStripProps {
2729
+ /** Pass a stable ref (useRef): a new object each render restarts the meter loop. */
2730
+ previewIframeRef?: RefObject<HTMLIFrameElement | null>;
2731
+ }
2732
+ declare const AudioMeterStrip: react.NamedExoticComponent<AudioMeterStripProps>;
2733
+
2734
+ interface RecordEditInput$2 {
2735
+ label: string;
2736
+ coalesceKey?: string;
2737
+ files: Record<string, {
2738
+ before: string;
2739
+ after: string;
2740
+ }>;
2741
+ }
2742
+ interface UseClipboardOptions {
2743
+ projectId: string | null;
2744
+ activeCompPath: string | null;
2745
+ domEditSelectionRef: React.MutableRefObject<DomEditSelection | null>;
2746
+ showToast: (message: string, tone?: "error" | "info") => void;
2747
+ writeProjectFile: (path: string, content: string) => Promise<void>;
2748
+ recordEdit: (input: RecordEditInput$2) => Promise<void>;
2749
+ reloadPreview: () => void;
2750
+ handleTimelineElementsDelete: (elements: TimelineElement[]) => Promise<void>;
2751
+ handleDomEditElementDelete: (selection: DomEditSelection) => Promise<void>;
2752
+ previewIframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
2753
+ waitForPendingDomEditSaves: () => Promise<void>;
2754
+ }
2755
+ declare function useClipboard({ projectId, activeCompPath, domEditSelectionRef, showToast, writeProjectFile, recordEdit, reloadPreview, handleTimelineElementsDelete, handleDomEditElementDelete, previewIframeRef, waitForPendingDomEditSaves, }: UseClipboardOptions): {
2756
+ handleCopy: () => boolean;
2757
+ handlePaste: () => Promise<void>;
2758
+ handleCut: () => Promise<boolean>;
2759
+ handleDuplicate: () => Promise<boolean>;
2760
+ canPaste: () => boolean;
2761
+ };
2762
+
2763
+ /** The live markup to persist and the session snapshot to restore on failure. */
2764
+ interface InlineTextEditCommit {
2765
+ /** The exact preview node that owned the edit; a reload must not retarget it. */
2766
+ element: HTMLElement;
2767
+ html: string;
2768
+ previousHtml: string;
2769
+ }
2770
+
2771
+ declare const SNAP_THRESHOLD_PX = 6;
2772
+ /** Whether a move of this size has travelled far enough for snapping to apply. */
2773
+ declare function snapEngagedForTravel(dx: number, dy: number): boolean;
2774
+ interface SnapEdge {
2775
+ position: number;
2776
+ source: "grid";
2777
+ id: string;
2778
+ }
2779
+ interface SnapTarget {
2780
+ left: number;
2781
+ top: number;
2782
+ right: number;
2783
+ bottom: number;
2784
+ centerX: number;
2785
+ centerY: number;
2786
+ id: string;
2787
+ }
2788
+ interface SnapGuide {
2789
+ axis: "x" | "y";
2790
+ position: number;
2791
+ /** Extent of the guide line (min of involved elements). */
2792
+ from: number;
2793
+ /** Extent of the guide line (max of involved elements). */
2794
+ to: number;
2795
+ }
2796
+ interface SpacingGuide {
2797
+ axis: "x" | "y";
2798
+ /** Position of the gap (start of gap). */
2799
+ position: number;
2800
+ /** Size of the gap in pixels. */
2801
+ size: number;
2802
+ /** Extent for rendering the indicator. */
2803
+ from: number;
2804
+ /** Extent for rendering the indicator. */
2805
+ to: number;
2806
+ }
2807
+ interface SnapResult {
2808
+ dx: number;
2809
+ dy: number;
2810
+ guides: SnapGuide[];
2811
+ spacingGuides: SpacingGuide[];
2812
+ }
2813
+ interface Rect {
2814
+ left: number;
2815
+ top: number;
2816
+ width: number;
2817
+ height: number;
2818
+ }
2819
+ /**
2820
+ * Convert overlay rects to snap targets with precomputed edges & centers.
2821
+ */
2822
+ declare function extractSnapTargets(entries: Array<{
2823
+ rect: Rect;
2824
+ id: string;
2825
+ }>): SnapTarget[];
2826
+ /**
2827
+ * Create a snap target from the composition/overlay boundary.
2828
+ */
2829
+ declare function buildCompositionSnapTarget(rect: Rect): SnapTarget;
2830
+ /**
2831
+ * Generate grid-line snap edges.
2832
+ * `gridSpacing` is in composition pixels; `scale` converts to overlay pixels.
2833
+ * X edges are vertical grid lines; Y edges are horizontal grid lines.
2834
+ */
2835
+ declare function buildGridSnapEdges(compositionRect: Rect, gridSpacing: number, scale: number): {
2836
+ x: SnapEdge[];
2837
+ y: SnapEdge[];
2838
+ };
2839
+ declare function resolveSnapAdjustment(input: {
2840
+ movingRect: Rect;
2841
+ proposedDx: number;
2842
+ proposedDy: number;
2843
+ targets: SnapTarget[];
2844
+ gridEdges?: {
2845
+ x: SnapEdge[];
2846
+ y: SnapEdge[];
2847
+ };
2848
+ threshold: number;
2849
+ disabled: boolean;
2850
+ /** Set when the gesture has not travelled far enough for snapping yet. */
2851
+ disabledForTravel?: boolean;
2852
+ }): SnapResult;
2853
+ /**
2854
+ * Full-length guide line spanning the composition: a vertical line (axis "x")
2855
+ * runs the composition's height at the snapped x position; a horizontal line
2856
+ * (axis "y") runs the composition's width. `composition` is the composition
2857
+ * rect in overlay space — guide positions are already overlay-space, so the
2858
+ * line must be offset by the composition's left/top (the canvas is usually
2859
+ * letterboxed inside the overlay).
2860
+ */
2861
+ declare function resolveGuideLineRect(guide: SnapGuide, composition: Rect): Rect;
2862
+ declare function resolveEquidistanceGuides(input: {
2863
+ movingRect: Rect;
2864
+ targets: SnapTarget[];
2865
+ threshold: number;
2866
+ }): SpacingGuide[];
2867
+
2868
+ interface SnapContext {
2869
+ targets: SnapTarget[];
2870
+ compositionTarget: SnapTarget | null;
2871
+ gridEdges: {
2872
+ x: SnapEdge[];
2873
+ y: SnapEdge[];
2874
+ } | null;
2875
+ snapEnabled: boolean;
2876
+ }
2877
+ declare function collectSnapContext(input: {
2878
+ overlayEl: HTMLDivElement;
2879
+ iframe: HTMLIFrameElement;
2880
+ excludeElements: Set<HTMLElement>;
2881
+ }): SnapContext;
2882
+
2883
+ interface SnapGuidesState {
2884
+ guides: SnapGuide[];
2885
+ spacingGuides: SpacingGuide[];
2886
+ }
2887
+ interface SnapGuideOverlayProps {
2888
+ snapGuidesRef: RefObject<SnapGuidesState | null>;
2889
+ /** Composition rect in overlay space — guide lines span exactly this rect. */
2890
+ compositionLeft: number;
2891
+ compositionTop: number;
2892
+ compositionWidth: number;
2893
+ compositionHeight: number;
2894
+ }
2895
+ declare const SnapGuideOverlay: react.NamedExoticComponent<SnapGuideOverlayProps>;
2896
+
2897
+ interface ApplyDomSelectionOptions {
2898
+ revealPanel?: boolean;
2899
+ additive?: boolean;
2900
+ preserveGroup?: boolean;
2901
+ announce?: boolean;
2902
+ }
2903
+ interface ResolveDomSelectionOptions {
2904
+ preferClipAncestor?: boolean;
2905
+ skipSourceProbe?: boolean;
2906
+ activeGroupElement?: HTMLElement | null;
2907
+ /** Resolve this node itself instead of applying human group-capture behavior. */
2908
+ exactTarget?: boolean;
2909
+ }
2910
+ interface DomEditTimelineParams {
2911
+ projectId: string | null;
2912
+ activeCompPath: string | null;
2913
+ compIdToSrc: Map<string, string>;
2914
+ captionEditMode: boolean;
2915
+ previewIframeRef: MutableRefObject<HTMLIFrameElement | null>;
2916
+ timelineElements: TimelineElement[];
2917
+ getTimelineSelectionSet: () => ReadonlySet<string>;
2918
+ setSelectedTimelineElementId: (id: string | null, options?: SelectElementOptions) => void;
2919
+ /** Publishes a whole multi-selection to the timeline; the anchor is set separately. */
2920
+ setTimelineSelectionSet: (ids: Set<string>) => void;
2921
+ setRightCollapsed: (collapsed: boolean) => void;
2922
+ setRightPanelTab: (tab: RightPanelTab) => void;
2923
+ }
2924
+
2925
+ interface PreviewMouseDownOptions {
2926
+ preferClipAncestor?: boolean;
2927
+ hoverSelection?: DomEditSelection | null;
2928
+ }
2929
+
2930
+ interface DomEditGroupPathOffsetCommit {
2931
+ selection: DomEditSelection;
2932
+ next: {
2933
+ x: number;
2934
+ y: number;
2935
+ };
2936
+ }
2937
+
2938
+ /**
2939
+ * Why a DOM edit commit did not change the file.
2940
+ *
2941
+ * `runDomEditCommit` resolves on persist failure by design (see its contract
2942
+ * above), so a caller cannot learn whether the write landed by awaiting it — a
2943
+ * failed persist and a successful one are indistinguishable. Capture and apply
2944
+ * bugs still reject. The human path does not need to ask about handled persist
2945
+ * failures, because `onError` already put a toast on screen. A programmatic
2946
+ * caller has no screen, so it has to be told.
2947
+ */
2948
+ type DomEditCommitDeclineReason = "no-project" | "no-selection" | "geometry-property" | "styles-not-editable" | "not-text-editable" | "preview-stale" | "persist-failed";
2949
+ type DomEditCommitOutcome = {
2950
+ ok: true;
2951
+ persistence?: DomEditPersistOutcome;
2952
+ } | {
2953
+ ok: false;
2954
+ reason: DomEditCommitDeclineReason;
2955
+ };
2956
+
2957
+ /**
2958
+ * Which elements a delete acts on.
2959
+ *
2960
+ * Its own module so `useDomEditSession.ts` stays under the studio's 600-line
2961
+ * cap; it reads only its arguments.
2962
+ */
2963
+
2964
+ /** One entry in the studio's edit history, as `useDomEditSession`'s caller
2965
+ * supplies it. */
2966
+ interface RecordEditInput$1 {
2967
+ label: string;
2968
+ coalesceKey?: string;
2969
+ files: Record<string, {
2970
+ before: string;
2971
+ after: string;
2972
+ }>;
2973
+ }
2974
+
2975
+ interface UseDomEditSessionParams extends DomEditTimelineParams {
2976
+ compositionLoading: boolean;
2977
+ showToast: (message: string, tone?: "error" | "info") => void;
2978
+ isRecordingRef?: React.RefObject<boolean>;
2979
+ refreshPreviewDocumentVersion: () => void;
2980
+ queueDomEditSave: <T>(save: () => Promise<T>) => Promise<T>;
2981
+ readProjectFile: (path: string) => Promise<string>;
2982
+ writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
2983
+ updateEditingFileContent: (path: string, content: string) => void;
2984
+ editHistory: {
2985
+ recordEdit: (entry: RecordEditInput$1) => Promise<void>;
2986
+ };
2987
+ fileTree: string[];
2988
+ importedFontAssetsRef: React.MutableRefObject<ImportedFontAsset[]>;
2989
+ projectDir: string | null;
2990
+ projectIdRef: React.MutableRefObject<string | null>;
2991
+ previewIframe: HTMLIFrameElement | null;
2992
+ refreshKey: number;
2993
+ previewDocumentVersion: number;
2994
+ rightPanelTab: RightPanelTab;
2995
+ applyStudioManualEditsToPreviewRef: React.MutableRefObject<(iframe: HTMLIFrameElement) => Promise<void>>;
2996
+ syncPreviewHotkeys: (iframe: HTMLIFrameElement | null) => void;
2997
+ reloadPreview: () => void;
2998
+ setRefreshKey: React.Dispatch<React.SetStateAction<number>>;
2999
+ openSourceForSelection?: (sourceFile: string, target: PatchTarget) => void;
3000
+ sdkSession?: Composition | null;
3001
+ publishSdkSession?: PublishSdkSession;
3002
+ forceReloadSdkSession?: () => void;
3003
+ /** The timeline context menu's delete op — a canvas selection that IS a
3004
+ * timeline row hands off here instead of the REST remove-elements path. */
3005
+ handleTimelineElementsDelete: (elements: TimelineElement[]) => Promise<void>;
3006
+ readOnlyPreview: boolean;
3007
+ }
3008
+ declare function useDomEditSession({ projectId, activeCompPath, compIdToSrc, captionEditMode, compositionLoading, previewIframeRef, timelineElements, getTimelineSelectionSet, setSelectedTimelineElementId, setTimelineSelectionSet, setRightCollapsed, setRightPanelTab, showToast, isRecordingRef, refreshPreviewDocumentVersion, queueDomEditSave, readProjectFile, writeProjectFile, updateEditingFileContent, editHistory, fileTree, importedFontAssetsRef, projectDir, projectIdRef, previewIframe, refreshKey, previewDocumentVersion, rightPanelTab, applyStudioManualEditsToPreviewRef, syncPreviewHotkeys, reloadPreview, setRefreshKey: _setRefreshKey, openSourceForSelection, sdkSession, publishSdkSession, forceReloadSdkSession, handleTimelineElementsDelete, readOnlyPreview, }: UseDomEditSessionParams): {
3009
+ domEditSelection: DomEditSelection | null;
3010
+ domEditGroupSelections: DomEditSelection[];
3011
+ domEditHoverSelection: DomEditSelection | null;
3012
+ activeGroupElement: HTMLElement | null;
3013
+ agentModalOpen: boolean;
3014
+ agentModalAnchorPoint: AgentModalAnchorPoint | null;
3015
+ copiedAgentPrompt: boolean;
3016
+ agentPromptSelectionContext: string | undefined;
3017
+ domEditSelectionRef: react.MutableRefObject<DomEditSelection | null>;
3018
+ handleTimelineElementSelect: (element: TimelineElement | null) => Promise<void>;
3019
+ handlePreviewCanvasMouseDown: (e: React.MouseEvent<HTMLDivElement>, options?: PreviewMouseDownOptions) => Promise<void>;
3020
+ handlePreviewCanvasPointerMove: (e: React.PointerEvent<HTMLDivElement>, options?: {
3021
+ preferClipAncestor?: boolean;
3022
+ }) => Promise<DomEditSelection | null>;
3023
+ handlePreviewCanvasPointerLeave: () => void;
3024
+ applyDomSelection: (selection: DomEditSelection | null, options?: ApplyDomSelectionOptions) => void;
3025
+ clearDomSelection: () => void;
3026
+ refreshDomEditSelectionFromPreview: (selection: DomEditSelection) => Promise<void>;
3027
+ handleDomStyleCommit: (property: string, value: string) => Promise<DomEditCommitOutcome>;
3028
+ handleDomStyleCommitForSelection: (selection: DomEditSelection, property: string, value: string) => Promise<DomEditCommitOutcome>;
3029
+ handleDomAttributeCommit: (attr: string, value: string) => Promise<void>;
3030
+ handleDomAttributeLiveCommit: (attr: string, value: string | null, onSettled?: (ok: boolean) => void, live?: {
3031
+ previewOnly?: boolean;
3032
+ }) => Promise<void>;
3033
+ handleDomAttributeQuietCommit: (attr: string, value: string | null) => Promise<void>;
3034
+ handleDomHtmlAttributeCommit: (attr: string, value: string | null) => Promise<void>;
3035
+ handleDomAttributesCommit: (selection: DomEditSelection, attrs: Record<string, string>) => Promise<void>;
3036
+ handleDomPathOffsetCommit: (selection: DomEditSelection, next: {
3037
+ x: number;
3038
+ y: number;
3039
+ }, modifiers?: {
3040
+ altKey?: boolean;
3041
+ }) => Promise<void>;
3042
+ handleDomGroupPathOffsetCommit: (updates: DomEditGroupPathOffsetCommit[]) => Promise<void>;
3043
+ handleDomZIndexReorderCommit: (entries: Array<{
3044
+ element: HTMLElement;
3045
+ zIndex: number;
3046
+ id?: string;
3047
+ selector?: string;
3048
+ selectorIndex?: number;
3049
+ sourceFile: string;
3050
+ key?: string;
3051
+ }>, gestureCoalesceKey?: string, actionKind?: string) => Promise<void> | Promise<DomEditPatchBatchesResult>;
3052
+ handleDomBoxSizeCommit: (selection: DomEditSelection, next: {
3053
+ width: number;
3054
+ height: number;
3055
+ }, offset?: {
3056
+ x: number;
3057
+ y: number;
3058
+ }, restore?: () => void) => Promise<void>;
3059
+ handleDomRotationCommit: (selection: DomEditSelection, next: {
3060
+ angle: number;
3061
+ }) => Promise<void>;
3062
+ handleDomManualEditsReset: (selection: DomEditSelection) => Promise<void>;
3063
+ handleDomTextCommit: (value: string, fieldKey?: string) => Promise<DomEditCommitOutcome>;
3064
+ handleDomTextCommitForSelection: (selection: DomEditSelection, value: string, fieldKey?: string) => Promise<DomEditCommitOutcome>;
3065
+ handleDomRichTextCommit: ({ element, html, previousHtml }: InlineTextEditCommit) => Promise<void>;
3066
+ handleDomTextFieldStyleCommit: (fieldKey: string, property: string, value: string) => Promise<void>;
3067
+ handleDomAddTextField: (afterFieldKey?: string) => Promise<string | null>;
3068
+ handleDomRemoveTextField: (fieldKey: string) => Promise<void>;
3069
+ getGsapAnimationsForSelection: (selection: DomEditSelection) => _hyperframes_parsers.GsapAnimation[] | Promise<_hyperframes_parsers.GsapAnimation[]>;
3070
+ handleAskAgent: () => void;
3071
+ handleAgentModalSubmit: (userInstruction: string) => Promise<void>;
3072
+ handleBlockedDomMove: (selection: DomEditSelection) => void;
3073
+ handleDomManualDragStart: () => void;
3074
+ handleDomEditElementDelete: (selection: DomEditSelection, options?: {
3075
+ expandGroup?: boolean;
3076
+ }) => Promise<void>;
3077
+ handleGroupSelection: () => void;
3078
+ handleUngroupSelection: () => void;
3079
+ setActiveGroupElement: (el: HTMLElement | null) => void;
3080
+ buildDomSelectionFromTarget: (target: HTMLElement, options?: ResolveDomSelectionOptions) => Promise<DomEditSelection | null>;
3081
+ buildDomSelectionForTimelineElement: (element: TimelineElement) => Promise<DomEditSelection | null>;
3082
+ updateDomEditHoverSelection: (selection: DomEditSelection | null) => void;
3083
+ applyMarqueeSelection: (selections: DomEditSelection[], additive: boolean) => void;
3084
+ resolveImportedFontAsset: (fontFamilyValue: string) => ImportedFontAsset | null;
3085
+ setAgentModalOpen: react.Dispatch<react.SetStateAction<boolean>>;
3086
+ setAgentPromptSelectionContext: react.Dispatch<react.SetStateAction<string | undefined>>;
3087
+ setAgentModalAnchorPoint: react.Dispatch<react.SetStateAction<AgentModalAnchorPoint | null>>;
3088
+ selectedGsapAnimations: _hyperframes_parsers.GsapAnimation[];
3089
+ gsapMultipleTimelines: boolean;
3090
+ gsapUnsupportedTimelinePattern: boolean;
3091
+ handleGsapUpdateProperty: (animId: string, prop: string, value: number | string) => void;
3092
+ handleGsapUpdateMeta: (animId: string, updates: {
3093
+ duration?: number;
3094
+ ease?: string;
3095
+ position?: number;
3096
+ }, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3097
+ handleGsapDeleteAnimation: (animId: string, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3098
+ handleGsapDeleteAllForElement: (targetSelector: string) => void;
3099
+ handleGsapAddAnimation: (method: "to" | "from" | "set" | "fromTo", selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3100
+ handleGsapAddProperty: (animId: string, prop: string) => void;
3101
+ handleGsapRemoveProperty: (animId: string, prop: string) => void;
3102
+ handleGsapUpdateFromProperty: (animId: string, prop: string, value: number | string) => void;
3103
+ handleGsapAddFromProperty: (animId: string, prop: string) => void;
3104
+ handleGsapRemoveFromProperty: (animId: string, prop: string) => void;
3105
+ handleGsapAddKeyframe: (animId: string, percentage: number, property: string, value: number | string, selectionOverride?: DomEditSelection | null) => void;
3106
+ handleGsapAddKeyframeBatch: (animId: string, percentage: number, properties: Record<string, number | string>, commitOverrides?: Partial<CommitMutationOptions>, selectionOverride?: DomEditSelection | null) => Promise<void>;
3107
+ handleGsapRemoveKeyframe: (animId: string, percentage: number, commitOverrides?: Partial<CommitMutationOptions>, selectionOverride?: DomEditSelection | null) => void;
3108
+ handleGsapMoveKeyframeToPlayhead: (animId: string, fromPercentage: number, selectionOverride?: DomEditSelection | null, animationOverride?: _hyperframes_parsers.GsapAnimation) => void;
3109
+ handleGsapMoveKeyframe: (animId: string, fromPercentage: number, toPercentage: number, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3110
+ handleGsapResizeKeyframedTween: (animId: string, position: number, duration: number, pctRemap: Array<{
3111
+ from: number;
3112
+ to: number;
3113
+ }>, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3114
+ handleGsapConvertToKeyframes: (animId: string, resolvedFromValues?: Record<string, number | string>, duration?: number, commitOverrides?: Partial<CommitMutationOptions>, selectionOverride?: DomEditSelection | null) => Promise<void>;
3115
+ handleGsapRemoveAllKeyframes: (animId: string, selectionOverride?: DomEditSelection | null) => Promise<boolean>;
3116
+ handleResetSelectedElementKeyframes: () => boolean;
3117
+ handleUpdateKeyframeEase: (animationId: string, percentage: number, ease: string) => void;
3118
+ handleUpdateSegmentEase: (targets: AnimationKeyframeTarget[], ease: string) => void;
3119
+ handleSetAllKeyframeEases: (animationId: string, ease: string) => void;
3120
+ commitAnimatedProperty: (selection: DomEditSelection, property: string, value: number | string) => Promise<void>;
3121
+ commitAnimatedProperties: (selection: DomEditSelection, properties: Record<string, number | string>) => Promise<void>;
3122
+ handleSetArcPath: (animId: string, config: Parameters<(sel: DomEditSelection, animId: string, config: {
3123
+ enabled: boolean;
3124
+ autoRotate?: boolean | number;
3125
+ segments?: Array<{
3126
+ curviness: number;
3127
+ cp1?: {
3128
+ x: number;
3129
+ y: number;
3130
+ };
3131
+ cp2?: {
3132
+ x: number;
3133
+ y: number;
3134
+ };
3135
+ }>;
3136
+ }) => void>[2]) => void;
3137
+ handleUpdateArcSegment: (animId: string, segmentIndex: number, update: Parameters<(sel: DomEditSelection, animId: string, segmentIndex: number, update: {
3138
+ curviness?: number;
3139
+ cp1?: {
3140
+ x: number;
3141
+ y: number;
3142
+ };
3143
+ cp2?: {
3144
+ x: number;
3145
+ y: number;
3146
+ };
3147
+ }) => void>[3]) => void;
3148
+ handleUnroll: () => void;
3149
+ invalidateGsapCache: () => void;
3150
+ previewIframeRef: react.MutableRefObject<HTMLIFrameElement | null>;
3151
+ commitMutation: (mutation: Record<string, unknown>, options: {
3152
+ label: string;
3153
+ softReload?: boolean;
3154
+ }) => Promise<void>;
3155
+ };
3156
+
3157
+ interface DomEditSaveQueue {
3158
+ enqueue: <T>(save: () => Promise<T>) => Promise<T>;
3159
+ waitForIdle: () => Promise<DomEditSaveDrainResult>;
3160
+ reset: () => void;
3161
+ destroy: () => void;
3162
+ }
3163
+ type DomEditSaveDrainResult = StudioSaveDrainResult;
3164
+
3165
+ /** One file's restore from the edit-history store: before (live) / after (target) bytes. */
3166
+ interface UndoRestoreFile {
3167
+ previous: string;
3168
+ restored: string;
3169
+ }
3170
+
3171
+ /** The restore payload the undo/redo preview-sync consumes (from the history store). */
3172
+ interface HistoryPreviewRestore {
3173
+ paths?: string[];
3174
+ files?: Record<string, UndoRestoreFile>;
3175
+ }
3176
+ interface RecordEditInput {
3177
+ label: string;
3178
+ coalesceKey?: string;
3179
+ files: Record<string, {
3180
+ before: string;
3181
+ after: string;
3182
+ }>;
3183
+ }
3184
+ interface UsePreviewPersistenceParams {
3185
+ showToast: (message: string, tone?: "error" | "info") => void;
3186
+ readOptionalProjectFile: (path: string) => Promise<string>;
3187
+ writeProjectFile: (path: string, content: string) => Promise<void>;
3188
+ recordEdit: (entry: RecordEditInput) => Promise<void>;
3189
+ previewIframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
3190
+ activeCompPathRef: React.MutableRefObject<string | null>;
3191
+ /** Called to reload the preview after undo/redo or external file changes. */
3192
+ reloadPreview: () => void;
3193
+ }
3194
+ declare function usePreviewPersistence({ showToast, readOptionalProjectFile: _readOptionalProjectFile, writeProjectFile: _writeProjectFile, recordEdit: _recordEdit, previewIframeRef, activeCompPathRef, reloadPreview, }: UsePreviewPersistenceParams): {
3195
+ domTextCommitVersionRef: react.RefObject<number>;
3196
+ domEditSaveQueueRef: react.RefObject<DomEditSaveQueue | null>;
3197
+ applyStudioManualEditsToPreviewRef: react.RefObject<(iframe?: HTMLIFrameElement | null) => Promise<void>>;
3198
+ queueDomEditSave: <T>(save: () => Promise<T>) => Promise<T>;
3199
+ drainPendingDomEditSaves: () => Promise<{
3200
+ status: "clean";
3201
+ } | {
3202
+ status: "conflict";
3203
+ error: StudioFileConflictError;
3204
+ } | {
3205
+ status: "failed";
3206
+ error: unknown;
3207
+ }>;
3208
+ waitForPendingDomEditSaves: () => Promise<void>;
3209
+ domEditSaveQueuePaused: string | null;
3210
+ resetDomEditSaveQueueBreaker: () => void;
3211
+ applyCurrentStudioManualEditsToPreview: (iframe?: HTMLIFrameElement | null) => void;
3212
+ applyStudioManualEditsToPreview: (iframe?: HTMLIFrameElement | null) => Promise<void>;
3213
+ syncHistoryPreviewAfterApply: (restore: HistoryPreviewRestore) => Promise<void>;
3214
+ };
3215
+
3216
+ type DomEditValue = ReturnType<typeof useDomEditSession>;
3217
+ interface DomEditSelectionValue extends Pick<DomEditValue, "domEditSelection" | "domEditGroupSelections" | "domEditHoverSelection" | "activeGroupElement" | "domEditSelectionRef" | "selectedGsapAnimations" | "gsapMultipleTimelines" | "gsapUnsupportedTimelinePattern" | "agentModalOpen" | "agentModalAnchorPoint" | "copiedAgentPrompt" | "agentPromptSelectionContext"> {
3218
+ }
3219
+ declare function useDomEditSelectionContext(): DomEditSelectionValue;
3220
+ declare function DomEditProvider({ value: { domEditSelection, domEditGroupSelections, domEditHoverSelection, agentModalOpen, agentModalAnchorPoint, copiedAgentPrompt, agentPromptSelectionContext, domEditSelectionRef, handleTimelineElementSelect, handlePreviewCanvasMouseDown, handlePreviewCanvasPointerMove, handlePreviewCanvasPointerLeave, applyDomSelection, clearDomSelection, refreshDomEditSelectionFromPreview, handleDomStyleCommit, handleDomStyleCommitForSelection, handleDomAttributeCommit, handleDomAttributeLiveCommit, handleDomAttributeQuietCommit, handleDomHtmlAttributeCommit, handleDomAttributesCommit, handleDomPathOffsetCommit, handleDomGroupPathOffsetCommit, handleDomZIndexReorderCommit, handleDomBoxSizeCommit, handleDomRotationCommit, handleDomManualEditsReset, handleDomTextCommit, handleDomTextCommitForSelection, handleDomRichTextCommit, handleDomTextFieldStyleCommit, handleDomAddTextField, handleDomRemoveTextField, getGsapAnimationsForSelection, handleAskAgent, handleAgentModalSubmit, handleBlockedDomMove, handleDomManualDragStart, handleDomEditElementDelete, handleGroupSelection, handleUngroupSelection, setActiveGroupElement, activeGroupElement, buildDomSelectionFromTarget, buildDomSelectionForTimelineElement, updateDomEditHoverSelection, resolveImportedFontAsset, setAgentModalOpen, setAgentPromptSelectionContext, setAgentModalAnchorPoint, selectedGsapAnimations, gsapMultipleTimelines, gsapUnsupportedTimelinePattern, handleGsapUpdateProperty, handleGsapUpdateMeta, handleGsapDeleteAnimation, handleGsapDeleteAllForElement, handleGsapAddAnimation, handleGsapAddProperty, handleGsapRemoveProperty, handleGsapUpdateFromProperty, handleGsapAddFromProperty, handleGsapRemoveFromProperty, handleGsapAddKeyframe, handleGsapAddKeyframeBatch, handleGsapRemoveKeyframe, handleGsapMoveKeyframeToPlayhead, handleGsapMoveKeyframe, handleGsapResizeKeyframedTween, handleGsapConvertToKeyframes, handleGsapRemoveAllKeyframes, handleResetSelectedElementKeyframes, commitAnimatedProperty, commitAnimatedProperties, handleSetArcPath, handleUpdateArcSegment, handleUnroll, invalidateGsapCache, previewIframeRef, commitMutation, applyMarqueeSelection, handleUpdateKeyframeEase, handleUpdateSegmentEase, handleSetAllKeyframeEases, }, children, }: {
3221
+ value: DomEditValue;
3222
+ children: ReactNode;
3223
+ }): react_jsx_runtime.JSX.Element;
3224
+
3225
+ declare function PreviewReadOnlyProvider({ readOnly, reason, children, }: {
3226
+ readOnly: boolean;
3227
+ reason?: string;
3228
+ children: ReactNode;
3229
+ }): react_jsx_runtime.JSX.Element;
3230
+
3231
+ /**
3232
+ * Pure z-order helpers for the canvas right-click context menu.
3233
+ *
3234
+ * Layering strategy: z-index + CSS stacking context (position ≠ static).
3235
+ * All sibling z-index values are read from the live iframe DOM via
3236
+ * element.style.zIndex (inline style, set by the editor) falling back to
3237
+ * the computed value. Treat missing / "auto" as 0 for comparison purposes.
3238
+ *
3239
+ * "Overlapping siblings" = siblings whose bounding rects intersect the
3240
+ * target's bounding rect AND are actually visible at the current frame.
3241
+ * Forward/backward operate within that set; front/back operate across all
3242
+ * siblings (full painting family, visible or not — unchanged semantics).
3243
+ *
3244
+ * ── Visibility ───────────────────────────────────────────────────────────────
3245
+ * In HyperFrames compositions the nearest z-neighbor is often INVISIBLE at the
3246
+ * paused frame: the runtime hides time-inactive clips with inline
3247
+ * `visibility:hidden` / `display:none` (see core runtime
3248
+ * syncTimedElementVisibility), and GSAP timelines park elements at `opacity:0`.
3249
+ * Stepping "forward" over such a sibling looks like a silent no-op. The
3250
+ * forward/backward comparison set therefore keeps only siblings whose
3251
+ * element-level computed style is visible (display ≠ none, visibility ≠
3252
+ * hidden, opacity > 0.01) — all runtime hiding signals are inline styles, so
3253
+ * computed style covers them. Ancestor-chain checks are unnecessary here:
3254
+ * siblings share the target's ancestors. The probe is injectable
3255
+ * (ZOrderResolveOptions.isVisible) so the pure-module tests stay meaningful
3256
+ * without a real style engine, mirroring how tests stub rect reading.
3257
+ *
3258
+ * ── Tie-awareness ────────────────────────────────────────────────────────────
3259
+ * CSS paint order for elements that share a z-index is DOM document order:
3260
+ * the element that comes LATER in the DOM paints ON TOP. The old resolver
3261
+ * compared z-index alone, so a target tied with the element visually below it
3262
+ * (equal z, target later in DOM) had an empty "below" set and silently
3263
+ * no-op'd. This module computes true render order — sort by
3264
+ * (zIndex asc, DOM position asc), bottom→top — moves the target one step (or
3265
+ * to an end) in that order, then realizes the new order back into z values.
3266
+ *
3267
+ * The result is a MULTI-element patch: a single-element patch when a
3268
+ * strictly-between z value can express the new order given DOM-order
3269
+ * tie-breaking, otherwise a minimal renumber of the affected set (emitting
3270
+ * patches only for elements whose z actually changes). z is never negative
3271
+ * (project convention clamps z ≥ 0).
3272
+ */
3273
+ type ZOrderAction = "bring-forward" | "send-backward" | "bring-to-front" | "send-to-back";
3274
+ /** A resolved change: set `element`'s z-index to `zIndex`. */
3275
+ interface ZOrderPatch {
3276
+ element: HTMLElement;
3277
+ zIndex: number;
3278
+ }
3279
+
3280
+ interface DomEditOverlayProps {
3281
+ iframeRef: RefObject<HTMLIFrameElement | null>;
3282
+ activeCompositionPath: string | null;
3283
+ selection: DomEditSelection | null;
3284
+ groupSelections?: DomEditSelection[];
3285
+ hoverSelection: DomEditSelection | null;
3286
+ allowCanvasMovement?: boolean;
3287
+ /** "host": no hover, marquee or box re-select; Enter with nothing focused still opens text. */
3288
+ canvasInput?: "overlay" | "host";
3289
+ onTextEditingChange?: (editing: boolean) => void;
3290
+ /** A click on a single selection's box, in either mode; the event may be the pointerup. */
3291
+ onSelectionBoxClick?: (event: React.MouseEvent<HTMLDivElement>, selection: DomEditSelection) => void;
3292
+ onCanvasMouseDown: (event: React.MouseEvent<HTMLDivElement>, options?: PreviewMouseDownOptions) => void;
3293
+ onCanvasPointerMove: (event: React.PointerEvent<HTMLDivElement>, options?: {
3294
+ preferClipAncestor?: boolean;
3295
+ }) => Promise<DomEditSelection | null>;
3296
+ onCanvasPointerLeave: () => void;
3297
+ onSelectionChange: (selection: DomEditSelection, options?: {
3298
+ revealPanel?: boolean;
3299
+ additive?: boolean;
3300
+ }) => void;
3301
+ onBlockedMove: (selection: DomEditSelection) => void;
3302
+ onManualDragStart?: () => void;
3303
+ onPathOffsetCommit: (selection: DomEditSelection, next: {
3304
+ x: number;
3305
+ y: number;
3306
+ }, modifiers?: {
3307
+ altKey?: boolean;
3308
+ }) => Promise<void> | void;
3309
+ onGroupPathOffsetCommit: (updates: DomEditGroupPathOffsetCommit[]) => Promise<void> | void;
3310
+ onBoxSizeCommit: (selection: DomEditSelection, next: {
3311
+ width: number;
3312
+ height: number;
3313
+ }, offset?: {
3314
+ x: number;
3315
+ y: number;
3316
+ }, restore?: () => void) => Promise<void> | void;
3317
+ onRotationCommit: (selection: DomEditSelection, next: {
3318
+ angle: number;
3319
+ }) => Promise<void> | void;
3320
+ onStyleCommit?: (property: string, value: string) => Promise<unknown> | void;
3321
+ recordingState?: GestureRecordingState;
3322
+ onToggleRecording?: () => void;
3323
+ onMarqueeSelect?: (selections: DomEditSelection[], additive: boolean) => void;
3324
+ /**
3325
+ * Delete the selected canvas element.
3326
+ * Wire to handleDomEditElementDelete from useDomEditActionsContext —
3327
+ * same handler the Delete/Backspace hotkey uses.
3328
+ */
3329
+ onDeleteSelection?: (selection: DomEditSelection) => void;
3330
+ /**
3331
+ * Called with the resolved z-order patch list and the menu action that
3332
+ * produced it (feeds the undo coalesce key). The patch list is tie-aware and
3333
+ * may include sibling elements (see canvasContextMenuZOrder); the live DOM is
3334
+ * NOT yet mutated. Wire to handleDomZIndexReorderCommit from
3335
+ * useDomEditActionsContext. See CanvasContextMenu.tsx module comment.
3336
+ */
3337
+ onApplyZIndex?: (selection: DomEditSelection, patches: ZOrderPatch[], action: ZOrderAction,
3338
+ /** Sibling a forward/backward step moved past (pre-mutation render order);
3339
+ * null for front/back. Feeds the timeline z-mirror's crossedKey. */
3340
+ crossed: HTMLElement | null) => void;
3341
+ }
3342
+ declare const DomEditOverlay: react.NamedExoticComponent<DomEditOverlayProps>;
3343
+
3344
+ type HostInputProps = Pick<ComponentProps<typeof DomEditOverlay>, "canvasInput" | "onSelectionBoxClick">;
3345
+ interface ConnectedDomEditOverlayProps extends HostInputProps {
3346
+ activeCompositionPath: string | null;
3347
+ showHoverSelection: boolean;
3348
+ shouldShowSelectedDomBounds: boolean;
3349
+ isGestureRecording?: boolean;
3350
+ /** True when an in-place text edit opens its caret, false when it ends or unmounts. */
3351
+ onTextEditingChange?: (editing: boolean) => void;
3352
+ }
3353
+ declare function ConnectedDomEditOverlay({ activeCompositionPath, showHoverSelection, shouldShowSelectedDomBounds, isGestureRecording, canvasInput, onTextEditingChange, onSelectionBoxClick, }: ConnectedDomEditOverlayProps): react_jsx_runtime.JSX.Element;
3354
+
3355
+ interface MarqueeGesturesDeps<T = DomEditSelection> {
3356
+ iframeRef: React.RefObject<HTMLIFrameElement | null>;
3357
+ overlayRef: React.RefObject<HTMLDivElement | null>;
3358
+ activeCompositionPathRef: React.RefObject<string | null>;
3359
+ onMarqueeSelectRef: React.RefObject<((selections: T[], additive: boolean) => void) | undefined>;
3360
+ /** Turns the elements a drag touched into picks; without it, Studio's edit selections. */
3361
+ resolveHits?: (elements: HTMLElement[]) => T[] | Promise<T[]>;
3362
+ selectionRef?: React.RefObject<DomEditSelection | null>;
3363
+ /** Studio's pointer handling, for the events that are not part of a marquee. */
3364
+ gestures?: {
3365
+ onPointerMove: (event: React.PointerEvent<HTMLDivElement>) => void;
3366
+ onPointerUp: (event: React.PointerEvent<HTMLDivElement>) => void;
3367
+ clearPointerState: (ref: React.RefObject<DomEditSelection | null>) => void;
3368
+ };
3369
+ }
3370
+ interface MarqueeGestures {
3371
+ marqueeRect: Rect$1 | null;
3372
+ candidateRects: Rect$1[];
3373
+ /** Starts a marquee at this press; the host has decided it landed on empty canvas. */
3374
+ begin: (event: React.PointerEvent<HTMLElement>) => void;
3375
+ /** Drops an active marquee without selecting anything. */
3376
+ cancel: () => void;
3377
+ onPointerMove: (event: React.PointerEvent<HTMLDivElement>) => void;
3378
+ onPointerUp: (event: React.PointerEvent<HTMLDivElement>) => void;
3379
+ onPointerCancel: () => void;
3380
+ }
3381
+ declare function useMarqueeGestures(deps: MarqueeGesturesDeps): MarqueeGestures;
3382
+ declare function useMarqueeGestures<T>(deps: MarqueeGesturesDeps<T> & Required<Pick<MarqueeGesturesDeps<T>, "resolveHits">>): MarqueeGestures;
3383
+
3384
+ interface MarqueeOverlayProps {
3385
+ /** Elements the marquee currently intersects — outlined live before mouse-up. */
3386
+ candidateRects: Rect$1[];
3387
+ /** The marquee drag rectangle itself, or null when not marquee-selecting. */
3388
+ marqueeRect: Rect$1 | null;
3389
+ }
3390
+ /**
3391
+ * The marquee selection visuals: a live "candidate" outline on each element the
3392
+ * box currently touches, plus the dashed drag rectangle. Extracted from
3393
+ * DomEditOverlay to keep that file under the 600-line cap.
3394
+ */
3395
+ declare function MarqueeOverlay({ candidateRects, marqueeRect }: MarqueeOverlayProps): react_jsx_runtime.JSX.Element;
3396
+
3397
+ export { type AgentModalAnchorPoint, type AgentPromptElementInfo, AskAgentModal, type AskAgentModalProps, AudioMeterStrip, type AudioMeterStripProps, AudioWaveform, type AudioWaveformProps, type BlockedTimelineEditIntent, type CanEditTimelineElement, CompositionBreadcrumb, type CompositionDimensions, type CompositionLevel, CompositionThumbnail, ConnectedDomEditOverlay, type ConnectedDomEditOverlayProps, DEFAULT_SHORTCUT_SECTIONS, type DomEditCapabilities, DomEditProvider, type DomEditSelection, type EditHistoryHandle, EditorShell, type EditorShellProps, type ExternalFileChangeBlockedState, type ExternalFileChangeCoordinatorHandle, ExternalFileConflictBanner, type FfmpegStatus, FileTree, GridOverlay, ImageThumbnail, type ImageThumbnailProps, type MarqueeGestures, type MarqueeGesturesDeps, MarqueeOverlay, type MarqueeOverlayProps, type Rect$1 as MarqueeRect, NLEPreview, type PatchOperation, type PersistedRenderSettings, type PickedElement, PlayerControls, type PlayerHandle, type PlayerHandleElement, type PlayerHandleListener, type PlayerHandleTimeListener, type DomEditCompositionRect as PreviewCompositionRect, PreviewGuides, PreviewOverlayProvider, type PreviewOverlayProviderProps, PreviewReadOnlyProvider, type PreviewSnapPreferences, PropertyPanel, type RenderJob, RenderQueue, type RenderQueueProps, type ResolutionPreset, SNAP_THRESHOLD_PX, type ShortcutHint, type ShortcutSection, type SnapContext, type SnapEdge, type SnapGuide, SnapGuideOverlay, type SnapGuideOverlayProps, type SnapGuidesState, type Rect as SnapRect, type SnapResult, type SnapTarget, SnapToolbar, SourceEditor, type SpacingGuide, type StartRenderOptions, StudioApp, StudioFileConflictError, type StudioPendingEditsDrainResult, type ThumbnailPriority, Timeline, TimelineClipMenu, type TimelineClipRenderContext, type TimelineEditCallbacks, type TimelineEditOutcome, type TimelineEditPermission, TimelineEditPopover, TimelineEditProvider, type TimelineElement, TimelineEmptyStatePart, TimelineFrame, TimelineGapMenu, TimelineHistoryButtons, type TimelineHistoryButtonsProps, TimelineKeyframeMenu, TimelineLanes, TimelineOverlays, TimelinePane, type TimelinePaneProps, TimelinePlayhead, TimelineProvider, TimelineRazorGuide, TimelineRuler, TimelineShortcutHint, type TimelineTheme, type TimelineTimeRange$1 as TimelineTimeRange, TimelineToolbar, type TimelineToolbarProps, type TimelineZIndexReorderCommit, type UseClipboardOptions, type UseDomEditSessionParams, type UseEditHistoryActionsOptions, type UsePersistentEditHistoryOptions, type UsePreviewPersistenceParams, type UseProjectFileWriterOptions, type UseRenderClipContentOptions, type UseTimelineEditingOptions, VideoThumbnail, applyPatch, buildCompositionSnapTarget, buildGridSnapEdges, buildPickerAgentContextPreview, buildPickerAgentPrompt, collectSnapContext, extractSnapTargets, findElementBlock, flushStudioPendingEdits, formatTime, getPersistedRenderSettings, liveTime, mergeStyleIntoTag, parseStyleString, persistRenderSettings, resolveEquidistanceGuides, resolveGuideLineRect, resolveIframe, resolveSnapAdjustment, resolveSourceFile, snapEngagedForTravel, useClipboard, useDomEditSelectionContext, useDomEditSession, useEditHistoryActions, useElementPicker, useMarqueeGestures, usePersistentEditHistory, usePlayerHandle, usePlayerStore, usePreviewCompositionRect, usePreviewGuidesStore, usePreviewOverlayContext, usePreviewPersistence, useProjectFileWriter, useRenderClipContent, useRenderQueue, useTimelineContext, useTimelineEditing, useTimelinePlayer };