@hyperframes/studio 0.8.85 → 0.8.87

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 (95) hide show
  1. package/dist/assets/hyperframes-player-CtNVImMi.js +473 -0
  2. package/dist/assets/{index-Bus1BKtk.js → index-B_MF86RE.js} +1 -1
  3. package/dist/assets/{index-CZxhjQpw.js → index-DJ-Ol7YS.js} +1 -1
  4. package/dist/assets/{index-ClLdmgua.js → index-DZKcDAtf.js} +203 -203
  5. package/dist/assets/{index-mzZCha_N.css → index-Dx79V1Se.css} +1 -1
  6. package/dist/{chunk-7VDQIGOU.js → chunk-7PLTC6SV.js} +8 -2
  7. package/dist/chunk-7PLTC6SV.js.map +1 -0
  8. package/dist/{chunk-3IOCVWB6.js → chunk-PQFEGZWM.js} +3 -1
  9. package/dist/chunk-PQFEGZWM.js.map +1 -0
  10. package/dist/{domEditingLayers-ZOOMN7CQ.js → domEditingLayers-3BAP6NNO.js} +2 -2
  11. package/dist/index.d.ts +207 -161
  12. package/dist/index.html +2 -2
  13. package/dist/index.js +2084 -1705
  14. package/dist/index.js.map +1 -1
  15. package/dist/player.js +1 -1
  16. package/dist/styles.css +1 -1
  17. package/package.json +8 -8
  18. package/src/components/TimelineToolbar.test.tsx +53 -2
  19. package/src/components/TimelineToolbar.tsx +119 -101
  20. package/src/components/editor/DomEditOverlay.tsx +1 -2
  21. package/src/components/editor/DomEditOverlayHover.test.tsx +5 -0
  22. package/src/components/editor/DomEditSelectionChrome.test.tsx +0 -3
  23. package/src/components/editor/DomEditSelectionChrome.tsx +3 -13
  24. package/src/components/editor/LayersPanel.test.ts +14 -0
  25. package/src/components/editor/LayersPanel.tsx +2 -2
  26. package/src/components/editor/TopologyLens.tsx +2 -2
  27. package/src/components/editor/commitPreflightHandles.test.tsx +466 -0
  28. package/src/components/editor/domEditOverlayGestures.ts +0 -1
  29. package/src/components/editor/domEditOverlayStartGesture.ts +10 -1
  30. package/src/components/editor/domEditing.test.ts +29 -0
  31. package/src/components/editor/domEditingDom.ts +1 -0
  32. package/src/components/editor/domEditingTypes.ts +1 -0
  33. package/src/components/editor/marqueeCommit.test.tsx +84 -0
  34. package/src/components/editor/marqueeCommit.ts +13 -1
  35. package/src/components/editor/useColorGradingController.test.ts +24 -0
  36. package/src/components/editor/useColorGradingController.ts +3 -2
  37. package/src/components/editor/useDomEditOverlayGestures.ts +20 -5
  38. package/src/components/nle/useCompositionStack.test.tsx +179 -0
  39. package/src/components/nle/useCompositionStack.ts +26 -20
  40. package/src/hooks/domStyleCommit.ts +129 -0
  41. package/src/hooks/gsapEditOutcome.ts +2 -2
  42. package/src/hooks/gsapElementMatch.ts +38 -0
  43. package/src/hooks/gsapResizeIntercept.ts +10 -31
  44. package/src/hooks/gsapResizePreflight.ts +56 -0
  45. package/src/hooks/gsapRuntimeBridge.ts +66 -26
  46. package/src/hooks/keyframeCacheAstLoad.ts +4 -1
  47. package/src/hooks/useCommitPreflightCapabilities.ts +147 -0
  48. package/src/hooks/useDomEditCommits.ts +17 -182
  49. package/src/hooks/useDomEditPersist.ts +225 -0
  50. package/src/hooks/useDomEditPreviewSync.test.ts +58 -0
  51. package/src/hooks/useDomEditPreviewSync.ts +2 -4
  52. package/src/hooks/useDomEditSession.test.tsx +51 -1
  53. package/src/hooks/useDomEditSession.ts +11 -2
  54. package/src/hooks/useDomEditTextCommits.ts +15 -99
  55. package/src/hooks/useDomStyleCommit.test.tsx +155 -0
  56. package/src/hooks/useDomStyleCommit.ts +74 -0
  57. package/src/hooks/useGsapAnimationFetchFallback.test.ts +12 -0
  58. package/src/hooks/useGsapAnimationFetchFallback.ts +8 -2
  59. package/src/hooks/useGsapAwareEditing.test.tsx +4 -0
  60. package/src/hooks/useGsapAwareEditing.ts +1 -1
  61. package/src/hooks/useGsapTweenCache.ts +2 -48
  62. package/src/index.ts +10 -1
  63. package/src/player/components/Timeline.audioEffects.test.tsx +80 -0
  64. package/src/player/components/Timeline.bandEscape.test.tsx +75 -0
  65. package/src/player/components/Timeline.playheadRemount.test.tsx +41 -0
  66. package/src/player/components/Timeline.test.ts +32 -19
  67. package/src/player/components/TimelineGroupHeader.tsx +21 -10
  68. package/src/player/components/TimelineGroupLaneLabels.tsx +7 -2
  69. package/src/player/components/TimelineGroupRow.test.tsx +24 -33
  70. package/src/player/components/TimelineGroupRow.tsx +4 -1
  71. package/src/player/components/TimelineLanes.tsx +5 -5
  72. package/src/player/components/TimelineTrackHeader.test.tsx +27 -0
  73. package/src/player/components/TimelineTrackHeader.tsx +6 -3
  74. package/src/player/components/TimelineTypes.ts +1 -0
  75. package/src/player/components/timelineLaneProps.ts +1 -0
  76. package/src/player/components/timelineLayout.ts +16 -23
  77. package/src/player/components/timelineMountTestEnv.ts +29 -0
  78. package/src/player/components/useTimelineGeometry.test.tsx +105 -0
  79. package/src/player/components/useTimelineGeometry.ts +18 -10
  80. package/src/player/components/useTimelineLabelColumn.ts +18 -0
  81. package/src/player/components/useTimelineLaneRowIndexes.ts +6 -1
  82. package/src/player/components/useTimelinePlayhead.ts +1 -1
  83. package/src/player/components/useTimelineProviderState.tsx +6 -12
  84. package/src/player/components/useTimelineRangeSelection.ts +13 -12
  85. package/src/player/hooks/useShadowPreviewReload.ts +2 -0
  86. package/src/player/hooks/useTimelinePlayer.shadowReload.test.ts +191 -0
  87. package/src/player/hooks/useTimelinePlayer.ts +29 -7
  88. package/src/player/lib/runtimeProtocol.test.ts +1 -0
  89. package/src/player/sceneSwap.test.ts +95 -0
  90. package/src/player/sceneSwap.ts +53 -0
  91. package/src/player/store/liveTime.ts +6 -1
  92. package/dist/assets/hyperframes-player-BK18SggX.js +0 -464
  93. package/dist/chunk-3IOCVWB6.js.map +0 -1
  94. package/dist/chunk-7VDQIGOU.js.map +0 -1
  95. /package/dist/{domEditingLayers-ZOOMN7CQ.js.map → domEditingLayers-3BAP6NNO.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -418,6 +418,7 @@ interface SubCompositionHostState {
418
418
  type TimeListener = (time: number) => void;
419
419
  declare const liveTime: {
420
420
  notify: (time: number) => void;
421
+ latest: () => number;
421
422
  subscribe: (listener: TimeListener) => () => boolean;
422
423
  };
423
424
 
@@ -651,6 +652,7 @@ interface DomEditCapabilities {
651
652
  canApplyManualSize: boolean;
652
653
  canApplyManualRotation: boolean;
653
654
  reasonIfDisabled?: string;
655
+ commitCheckPending?: boolean;
654
656
  }
655
657
  interface DomEditTextField {
656
658
  key: string;
@@ -689,6 +691,20 @@ interface DomEditSelection extends PatchTarget {
689
691
  capabilities: DomEditCapabilities;
690
692
  gsapAnimations?: GsapAnimation$1[];
691
693
  }
694
+ interface DomEditContextOptions {
695
+ activeCompositionPath: string | null;
696
+ isMasterView: boolean;
697
+ preferClipAncestor?: boolean;
698
+ /** The group wrapper the user has drilled into (null = top level). Selection
699
+ * resolution treats groups as a unit unless drilled into one. */
700
+ activeGroupElement?: HTMLElement | null;
701
+ }
702
+
703
+ declare function resolveDomEditSelection(startEl: HTMLElement | null, options: DomEditContextOptions & {
704
+ projectId?: string | null;
705
+ skipSourceProbe?: boolean;
706
+ exactTarget?: boolean;
707
+ }): Promise<DomEditSelection | null>;
692
708
 
693
709
  /**
694
710
  * Agent prompt builder for HyperFrames element edit requests.
@@ -793,7 +809,7 @@ interface DomEditPatchBatchesResult {
793
809
  changed: boolean;
794
810
  }
795
811
 
796
- interface RecordEditInput$4 {
812
+ interface RecordEditInput$5 {
797
813
  label: string;
798
814
  coalesceKey?: string;
799
815
  files: Record<string, {
@@ -817,7 +833,7 @@ interface UseTimelineEditingOptions {
817
833
  showToast: (message: string, tone?: "error" | "info") => void;
818
834
  writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
819
835
  observeProjectFileVersion?: (path: string, version: string | null) => void;
820
- recordEdit: (input: RecordEditInput$4) => Promise<void>;
836
+ recordEdit: (input: RecordEditInput$5) => Promise<void>;
821
837
  reloadPreview: () => void;
822
838
  previewIframeRef: RefObject<HTMLIFrameElement | null>;
823
839
  pendingTimelineEditPathRef: MutableRefObject<Set<string>>;
@@ -1136,6 +1152,7 @@ interface TimelineProps extends TimelineDropCallbacks, TimelineEditOverrides, Ti
1136
1152
  onDuplicateClip?: () => Promise<boolean>;
1137
1153
  canPasteClip?: () => boolean;
1138
1154
  theme?: Partial<TimelineTheme>;
1155
+ showAudioEffects?: boolean;
1139
1156
  }
1140
1157
 
1141
1158
  interface TimelineEmptyStateProps {
@@ -1389,6 +1406,7 @@ interface TimelineLaneBaseProps {
1389
1406
  contentGutter: number;
1390
1407
  trackContentWidth: number;
1391
1408
  theme: TimelineTheme;
1409
+ showAudioEffects?: boolean;
1392
1410
  displayTrackOrder: number[];
1393
1411
  rowHeights: readonly number[];
1394
1412
  rowGeometry: TimelineRowGeometry;
@@ -2469,7 +2487,7 @@ declare function findElementBlock(html: string, elementId: string): {
2469
2487
  isSelfClosing: boolean;
2470
2488
  } | null;
2471
2489
 
2472
- interface RecordEditInput$3 {
2490
+ interface RecordEditInput$4 {
2473
2491
  label: string;
2474
2492
  coalesceKey?: string;
2475
2493
  coalesceMs?: number;
@@ -2515,7 +2533,7 @@ declare function usePersistentEditHistory({ projectId }: UsePersistentEditHistor
2515
2533
  createdAt: number;
2516
2534
  }[];
2517
2535
  };
2518
- recordEdit: ({ label, coalesceKey, coalesceMs, files }: RecordEditInput$3) => Promise<void>;
2536
+ recordEdit: ({ label, coalesceKey, coalesceMs, files }: RecordEditInput$4) => Promise<void>;
2519
2537
  undo: (callbacks: ApplyCallbacks) => Promise<ApplyResult>;
2520
2538
  redo: (callbacks: ApplyCallbacks) => Promise<ApplyResult>;
2521
2539
  };
@@ -2742,8 +2760,10 @@ interface TimelineToolbarProps {
2742
2760
  onSplitElement?: (element: TimelineElement, splitTime: number) => void;
2743
2761
  history?: TimelineHistoryButtonsProps;
2744
2762
  showAddBeat?: boolean;
2763
+ /** Hides Add keyframe and auto-record, and turns off auto-record and the K shortcut with them. */
2764
+ showKeyframes?: boolean;
2745
2765
  }
2746
- declare function TimelineToolbar({ domEditSession, onSplitElement, history, showAddBeat, }: TimelineToolbarProps): react_jsx_runtime.JSX.Element;
2766
+ declare function TimelineToolbar({ domEditSession, onSplitElement, history, showAddBeat, showKeyframes, }: TimelineToolbarProps): react_jsx_runtime.JSX.Element;
2747
2767
 
2748
2768
  interface AudioMeterStripProps {
2749
2769
  /** Pass a stable ref (useRef): a new object each render restarts the meter loop. */
@@ -2751,7 +2771,7 @@ interface AudioMeterStripProps {
2751
2771
  }
2752
2772
  declare const AudioMeterStrip: react.NamedExoticComponent<AudioMeterStripProps>;
2753
2773
 
2754
- interface RecordEditInput$2 {
2774
+ interface RecordEditInput$3 {
2755
2775
  label: string;
2756
2776
  coalesceKey?: string;
2757
2777
  files: Record<string, {
@@ -2765,7 +2785,7 @@ interface UseClipboardOptions {
2765
2785
  domEditSelectionRef: React.MutableRefObject<DomEditSelection | null>;
2766
2786
  showToast: (message: string, tone?: "error" | "info") => void;
2767
2787
  writeProjectFile: (path: string, content: string) => Promise<void>;
2768
- recordEdit: (input: RecordEditInput$2) => Promise<void>;
2788
+ recordEdit: (input: RecordEditInput$3) => Promise<void>;
2769
2789
  reloadPreview: () => void;
2770
2790
  handleTimelineElementsDelete: (elements: TimelineElement[]) => Promise<void>;
2771
2791
  handleDomEditElementDelete: (selection: DomEditSelection) => Promise<void>;
@@ -2788,131 +2808,24 @@ interface InlineTextEditCommit {
2788
2808
  previousHtml: string;
2789
2809
  }
2790
2810
 
2791
- declare const SNAP_THRESHOLD_PX = 6;
2792
- /** Whether a move of this size has travelled far enough for snapping to apply. */
2793
- declare function snapEngagedForTravel(dx: number, dy: number): boolean;
2794
- interface SnapEdge {
2795
- position: number;
2796
- source: "grid";
2797
- id: string;
2798
- }
2799
- interface SnapTarget {
2800
- left: number;
2801
- top: number;
2802
- right: number;
2803
- bottom: number;
2804
- centerX: number;
2805
- centerY: number;
2806
- id: string;
2807
- }
2808
- interface SnapGuide {
2809
- axis: "x" | "y";
2810
- position: number;
2811
- /** Extent of the guide line (min of involved elements). */
2812
- from: number;
2813
- /** Extent of the guide line (max of involved elements). */
2814
- to: number;
2815
- }
2816
- interface SpacingGuide {
2817
- axis: "x" | "y";
2818
- /** Position of the gap (start of gap). */
2819
- position: number;
2820
- /** Size of the gap in pixels. */
2821
- size: number;
2822
- /** Extent for rendering the indicator. */
2823
- from: number;
2824
- /** Extent for rendering the indicator. */
2825
- to: number;
2826
- }
2827
- interface SnapResult {
2828
- dx: number;
2829
- dy: number;
2830
- guides: SnapGuide[];
2831
- spacingGuides: SpacingGuide[];
2832
- }
2833
- interface Rect {
2834
- left: number;
2835
- top: number;
2836
- width: number;
2837
- height: number;
2838
- }
2839
2811
  /**
2840
- * Convert overlay rects to snap targets with precomputed edges & centers.
2841
- */
2842
- declare function extractSnapTargets(entries: Array<{
2843
- rect: Rect;
2844
- id: string;
2845
- }>): SnapTarget[];
2846
- /**
2847
- * Create a snap target from the composition/overlay boundary.
2848
- */
2849
- declare function buildCompositionSnapTarget(rect: Rect): SnapTarget;
2850
- /**
2851
- * Generate grid-line snap edges.
2852
- * `gridSpacing` is in composition pixels; `scale` converts to overlay pixels.
2853
- * X edges are vertical grid lines; Y edges are horizontal grid lines.
2812
+ * Why a DOM edit commit did not change the file.
2813
+ *
2814
+ * `runDomEditCommit` resolves on persist failure by design (see its contract
2815
+ * above), so a caller cannot learn whether the write landed by awaiting it — a
2816
+ * failed persist and a successful one are indistinguishable. Capture and apply
2817
+ * bugs still reject. The human path does not need to ask about handled persist
2818
+ * failures, because `onError` already put a toast on screen. A programmatic
2819
+ * caller has no screen, so it has to be told.
2854
2820
  */
2855
- declare function buildGridSnapEdges(compositionRect: Rect, gridSpacing: number, scale: number): {
2856
- x: SnapEdge[];
2857
- y: SnapEdge[];
2821
+ type DomEditCommitDeclineReason = "no-project" | "no-selection" | "geometry-property" | "styles-not-editable" | "not-text-editable" | "preview-stale" | "persist-failed";
2822
+ type DomEditCommitOutcome = {
2823
+ ok: true;
2824
+ persistence?: DomEditPersistOutcome;
2825
+ } | {
2826
+ ok: false;
2827
+ reason: DomEditCommitDeclineReason;
2858
2828
  };
2859
- declare function resolveSnapAdjustment(input: {
2860
- movingRect: Rect;
2861
- proposedDx: number;
2862
- proposedDy: number;
2863
- targets: SnapTarget[];
2864
- gridEdges?: {
2865
- x: SnapEdge[];
2866
- y: SnapEdge[];
2867
- };
2868
- threshold: number;
2869
- disabled: boolean;
2870
- /** Set when the gesture has not travelled far enough for snapping yet. */
2871
- disabledForTravel?: boolean;
2872
- }): SnapResult;
2873
- /**
2874
- * Full-length guide line spanning the composition: a vertical line (axis "x")
2875
- * runs the composition's height at the snapped x position; a horizontal line
2876
- * (axis "y") runs the composition's width. `composition` is the composition
2877
- * rect in overlay space — guide positions are already overlay-space, so the
2878
- * line must be offset by the composition's left/top (the canvas is usually
2879
- * letterboxed inside the overlay).
2880
- */
2881
- declare function resolveGuideLineRect(guide: SnapGuide, composition: Rect): Rect;
2882
- declare function resolveEquidistanceGuides(input: {
2883
- movingRect: Rect;
2884
- targets: SnapTarget[];
2885
- threshold: number;
2886
- }): SpacingGuide[];
2887
-
2888
- interface SnapContext {
2889
- targets: SnapTarget[];
2890
- compositionTarget: SnapTarget | null;
2891
- gridEdges: {
2892
- x: SnapEdge[];
2893
- y: SnapEdge[];
2894
- } | null;
2895
- snapEnabled: boolean;
2896
- }
2897
- declare function collectSnapContext(input: {
2898
- overlayEl: HTMLDivElement;
2899
- iframe: HTMLIFrameElement;
2900
- excludeElements: Set<HTMLElement>;
2901
- }): SnapContext;
2902
-
2903
- interface SnapGuidesState {
2904
- guides: SnapGuide[];
2905
- spacingGuides: SpacingGuide[];
2906
- }
2907
- interface SnapGuideOverlayProps {
2908
- snapGuidesRef: RefObject<SnapGuidesState | null>;
2909
- /** Composition rect in overlay space — guide lines span exactly this rect. */
2910
- compositionLeft: number;
2911
- compositionTop: number;
2912
- compositionWidth: number;
2913
- compositionHeight: number;
2914
- }
2915
- declare const SnapGuideOverlay: react.NamedExoticComponent<SnapGuideOverlayProps>;
2916
2829
 
2917
2830
  interface ApplyDomSelectionOptions {
2918
2831
  revealPanel?: boolean;
@@ -2947,33 +2860,6 @@ interface PreviewMouseDownOptions {
2947
2860
  hoverSelection?: DomEditSelection | null;
2948
2861
  }
2949
2862
 
2950
- interface DomEditGroupPathOffsetCommit {
2951
- selection: DomEditSelection;
2952
- next: {
2953
- x: number;
2954
- y: number;
2955
- };
2956
- }
2957
-
2958
- /**
2959
- * Why a DOM edit commit did not change the file.
2960
- *
2961
- * `runDomEditCommit` resolves on persist failure by design (see its contract
2962
- * above), so a caller cannot learn whether the write landed by awaiting it — a
2963
- * failed persist and a successful one are indistinguishable. Capture and apply
2964
- * bugs still reject. The human path does not need to ask about handled persist
2965
- * failures, because `onError` already put a toast on screen. A programmatic
2966
- * caller has no screen, so it has to be told.
2967
- */
2968
- type DomEditCommitDeclineReason = "no-project" | "no-selection" | "geometry-property" | "styles-not-editable" | "not-text-editable" | "preview-stale" | "persist-failed";
2969
- type DomEditCommitOutcome = {
2970
- ok: true;
2971
- persistence?: DomEditPersistOutcome;
2972
- } | {
2973
- ok: false;
2974
- reason: DomEditCommitDeclineReason;
2975
- };
2976
-
2977
2863
  /**
2978
2864
  * Which elements a delete acts on.
2979
2865
  *
@@ -2983,7 +2869,7 @@ type DomEditCommitOutcome = {
2983
2869
 
2984
2870
  /** One entry in the studio's edit history, as `useDomEditSession`'s caller
2985
2871
  * supplies it. */
2986
- interface RecordEditInput$1 {
2872
+ interface RecordEditInput$2 {
2987
2873
  label: string;
2988
2874
  coalesceKey?: string;
2989
2875
  files: Record<string, {
@@ -3002,7 +2888,7 @@ interface UseDomEditSessionParams extends DomEditTimelineParams {
3002
2888
  writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
3003
2889
  updateEditingFileContent: (path: string, content: string) => void;
3004
2890
  editHistory: {
3005
- recordEdit: (entry: RecordEditInput$1) => Promise<void>;
2891
+ recordEdit: (entry: RecordEditInput$2) => Promise<void>;
3006
2892
  };
3007
2893
  fileTree: string[];
3008
2894
  importedFontAssetsRef: React.MutableRefObject<ImportedFontAsset[]>;
@@ -3193,7 +3079,7 @@ interface HistoryPreviewRestore {
3193
3079
  paths?: string[];
3194
3080
  files?: Record<string, UndoRestoreFile>;
3195
3081
  }
3196
- interface RecordEditInput {
3082
+ interface RecordEditInput$1 {
3197
3083
  label: string;
3198
3084
  coalesceKey?: string;
3199
3085
  files: Record<string, {
@@ -3205,7 +3091,7 @@ interface UsePreviewPersistenceParams {
3205
3091
  showToast: (message: string, tone?: "error" | "info") => void;
3206
3092
  readOptionalProjectFile: (path: string) => Promise<string>;
3207
3093
  writeProjectFile: (path: string, content: string) => Promise<void>;
3208
- recordEdit: (entry: RecordEditInput) => Promise<void>;
3094
+ recordEdit: (entry: RecordEditInput$1) => Promise<void>;
3209
3095
  previewIframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
3210
3096
  activeCompPathRef: React.MutableRefObject<string | null>;
3211
3097
  /** Called to reload the preview after undo/redo or external file changes. */
@@ -3248,6 +3134,140 @@ declare function PreviewReadOnlyProvider({ readOnly, reason, children, }: {
3248
3134
  children: ReactNode;
3249
3135
  }): react_jsx_runtime.JSX.Element;
3250
3136
 
3137
+ declare const SNAP_THRESHOLD_PX = 6;
3138
+ /** Whether a move of this size has travelled far enough for snapping to apply. */
3139
+ declare function snapEngagedForTravel(dx: number, dy: number): boolean;
3140
+ interface SnapEdge {
3141
+ position: number;
3142
+ source: "grid";
3143
+ id: string;
3144
+ }
3145
+ interface SnapTarget {
3146
+ left: number;
3147
+ top: number;
3148
+ right: number;
3149
+ bottom: number;
3150
+ centerX: number;
3151
+ centerY: number;
3152
+ id: string;
3153
+ }
3154
+ interface SnapGuide {
3155
+ axis: "x" | "y";
3156
+ position: number;
3157
+ /** Extent of the guide line (min of involved elements). */
3158
+ from: number;
3159
+ /** Extent of the guide line (max of involved elements). */
3160
+ to: number;
3161
+ }
3162
+ interface SpacingGuide {
3163
+ axis: "x" | "y";
3164
+ /** Position of the gap (start of gap). */
3165
+ position: number;
3166
+ /** Size of the gap in pixels. */
3167
+ size: number;
3168
+ /** Extent for rendering the indicator. */
3169
+ from: number;
3170
+ /** Extent for rendering the indicator. */
3171
+ to: number;
3172
+ }
3173
+ interface SnapResult {
3174
+ dx: number;
3175
+ dy: number;
3176
+ guides: SnapGuide[];
3177
+ spacingGuides: SpacingGuide[];
3178
+ }
3179
+ interface Rect {
3180
+ left: number;
3181
+ top: number;
3182
+ width: number;
3183
+ height: number;
3184
+ }
3185
+ /**
3186
+ * Convert overlay rects to snap targets with precomputed edges & centers.
3187
+ */
3188
+ declare function extractSnapTargets(entries: Array<{
3189
+ rect: Rect;
3190
+ id: string;
3191
+ }>): SnapTarget[];
3192
+ /**
3193
+ * Create a snap target from the composition/overlay boundary.
3194
+ */
3195
+ declare function buildCompositionSnapTarget(rect: Rect): SnapTarget;
3196
+ /**
3197
+ * Generate grid-line snap edges.
3198
+ * `gridSpacing` is in composition pixels; `scale` converts to overlay pixels.
3199
+ * X edges are vertical grid lines; Y edges are horizontal grid lines.
3200
+ */
3201
+ declare function buildGridSnapEdges(compositionRect: Rect, gridSpacing: number, scale: number): {
3202
+ x: SnapEdge[];
3203
+ y: SnapEdge[];
3204
+ };
3205
+ declare function resolveSnapAdjustment(input: {
3206
+ movingRect: Rect;
3207
+ proposedDx: number;
3208
+ proposedDy: number;
3209
+ targets: SnapTarget[];
3210
+ gridEdges?: {
3211
+ x: SnapEdge[];
3212
+ y: SnapEdge[];
3213
+ };
3214
+ threshold: number;
3215
+ disabled: boolean;
3216
+ /** Set when the gesture has not travelled far enough for snapping yet. */
3217
+ disabledForTravel?: boolean;
3218
+ }): SnapResult;
3219
+ /**
3220
+ * Full-length guide line spanning the composition: a vertical line (axis "x")
3221
+ * runs the composition's height at the snapped x position; a horizontal line
3222
+ * (axis "y") runs the composition's width. `composition` is the composition
3223
+ * rect in overlay space — guide positions are already overlay-space, so the
3224
+ * line must be offset by the composition's left/top (the canvas is usually
3225
+ * letterboxed inside the overlay).
3226
+ */
3227
+ declare function resolveGuideLineRect(guide: SnapGuide, composition: Rect): Rect;
3228
+ declare function resolveEquidistanceGuides(input: {
3229
+ movingRect: Rect;
3230
+ targets: SnapTarget[];
3231
+ threshold: number;
3232
+ }): SpacingGuide[];
3233
+
3234
+ interface SnapContext {
3235
+ targets: SnapTarget[];
3236
+ compositionTarget: SnapTarget | null;
3237
+ gridEdges: {
3238
+ x: SnapEdge[];
3239
+ y: SnapEdge[];
3240
+ } | null;
3241
+ snapEnabled: boolean;
3242
+ }
3243
+ declare function collectSnapContext(input: {
3244
+ overlayEl: HTMLDivElement;
3245
+ iframe: HTMLIFrameElement;
3246
+ excludeElements: Set<HTMLElement>;
3247
+ }): SnapContext;
3248
+
3249
+ interface SnapGuidesState {
3250
+ guides: SnapGuide[];
3251
+ spacingGuides: SpacingGuide[];
3252
+ }
3253
+ interface SnapGuideOverlayProps {
3254
+ snapGuidesRef: RefObject<SnapGuidesState | null>;
3255
+ /** Composition rect in overlay space — guide lines span exactly this rect. */
3256
+ compositionLeft: number;
3257
+ compositionTop: number;
3258
+ compositionWidth: number;
3259
+ compositionHeight: number;
3260
+ }
3261
+ declare const SnapGuideOverlay: react.NamedExoticComponent<SnapGuideOverlayProps>;
3262
+
3263
+ interface DomEditGroupPathOffsetCommit {
3264
+ selection: DomEditSelection;
3265
+ next: {
3266
+ x: number;
3267
+ y: number;
3268
+ };
3269
+ }
3270
+
3251
3271
  /**
3252
3272
  * Pure z-order helpers for the canvas right-click context menu.
3253
3273
  *
@@ -3372,6 +3392,32 @@ interface ConnectedDomEditOverlayProps extends HostInputProps {
3372
3392
  }
3373
3393
  declare function ConnectedDomEditOverlay({ activeCompositionPath, showHoverSelection, shouldShowSelectedDomBounds, isGestureRecording, canvasInput, onTextEditingChange, onSelectionBoxClick, }: ConnectedDomEditOverlayProps): react_jsx_runtime.JSX.Element;
3374
3394
 
3395
+ interface RecordEditInput {
3396
+ label: string;
3397
+ coalesceKey?: string;
3398
+ coalesceMs?: number;
3399
+ files: Record<string, {
3400
+ before: string;
3401
+ after: string;
3402
+ }>;
3403
+ }
3404
+
3405
+ interface UseDomStyleCommitOptions {
3406
+ projectId: string | null;
3407
+ /** The preview the host already runs: the style applies there live, and it reseeks after a save. */
3408
+ iframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
3409
+ /** The same function objects the host gives the timeline, so there is one writer and one undo list. */
3410
+ writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
3411
+ recordEdit: (entry: RecordEditInput) => Promise<void>;
3412
+ activeCompPath?: string | null;
3413
+ showToast?: (message: string, tone?: "error" | "info") => void;
3414
+ }
3415
+ /** Saves style edits on a selection through Studio's own style commit, for a host without the editor. */
3416
+ declare function useDomStyleCommit({ projectId, iframeRef, writeProjectFile, recordEdit, activeCompPath, showToast, }: UseDomStyleCommitOptions): {
3417
+ commitStyle: (selection: DomEditSelection, styles: Record<string, string>) => Promise<DomEditCommitOutcome>;
3418
+ waitForPendingSaves: () => Promise<DomEditSaveDrainResult>;
3419
+ };
3420
+
3375
3421
  interface MarqueeGesturesDeps<T = DomEditSelection> {
3376
3422
  iframeRef: React.RefObject<HTMLIFrameElement | null>;
3377
3423
  overlayRef: React.RefObject<HTMLDivElement | null>;
@@ -3414,4 +3460,4 @@ interface MarqueeOverlayProps {
3414
3460
  */
3415
3461
  declare function MarqueeOverlay({ candidateRects, marqueeRect }: MarqueeOverlayProps): react_jsx_runtime.JSX.Element;
3416
3462
 
3417
- 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, useCompositionStack, useDomEditSelectionContext, useDomEditSession, useEditHistoryActions, useElementPicker, useMarqueeGestures, usePersistentEditHistory, usePlayerHandle, usePlayerStore, usePreviewCompositionRect, usePreviewGuidesStore, usePreviewOverlayContext, usePreviewPersistence, useProjectFileWriter, useRenderClipContent, useRenderQueue, useTimelineContext, useTimelineEditing, useTimelinePlayer };
3463
+ 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, type DomEditCommitDeclineReason, type DomEditCommitOutcome, type DomEditGroupPathOffsetCommit, DomEditOverlay, type DomEditOverlayProps, 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 UseDomStyleCommitOptions, 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, resolveDomEditSelection, resolveEquidistanceGuides, resolveGuideLineRect, resolveIframe, resolveSnapAdjustment, resolveSourceFile, snapEngagedForTravel, useClipboard, useCompositionStack, useDomEditSelectionContext, useDomEditSession, useDomStyleCommit, useEditHistoryActions, useElementPicker, useMarqueeGestures, usePersistentEditHistory, usePlayerHandle, usePlayerStore, usePreviewCompositionRect, usePreviewGuidesStore, usePreviewOverlayContext, usePreviewPersistence, useProjectFileWriter, useRenderClipContent, useRenderQueue, useTimelineContext, useTimelineEditing, useTimelinePlayer };
package/dist/index.html CHANGED
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>HyperFrames Studio</title>
8
- <script type="module" crossorigin src="/assets/index-ClLdmgua.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-mzZCha_N.css">
8
+ <script type="module" crossorigin src="/assets/index-DZKcDAtf.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-Dx79V1Se.css">
10
10
  </head>
11
11
  <body>
12
12
  <div data-hf-id="hf-aph5" id="root"></div>