@hyperframes/studio 0.8.147 → 0.8.148

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.
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ import {
47
47
  usePreviewVariablesStore,
48
48
  whenPreviewBooted,
49
49
  writeStudioUiPreferences
50
- } from "./chunk-PHGBG7OG.js";
50
+ } from "./chunk-4UHZLLQL.js";
51
51
  import {
52
52
  Button,
53
53
  ContextMenu,
@@ -79,7 +79,7 @@ import {
79
79
  fieldBase,
80
80
  fieldText,
81
81
  popupSurface
82
- } from "./chunk-PVFBY7KR.js";
82
+ } from "./chunk-FF5DM7BQ.js";
83
83
  import {
84
84
  DOM_EDIT_LAYER_OBSERVER_INIT,
85
85
  buildDefaultDomEditTextField,
@@ -182,7 +182,7 @@ import { memo as memo34, useCallback as useCallback74 } from "react";
182
182
  import { useCallback as useCallback51, useRef as useRef59, useSyncExternalStore as useSyncExternalStore6 } from "react";
183
183
 
184
184
  // src/player/components/PlayerControls.tsx
185
- import { useRef as useRef3, useEffect as useEffect3, memo as memo4 } from "react";
185
+ import { useRef as useRef3, useEffect as useEffect2, memo as memo4 } from "react";
186
186
  import gsap from "gsap";
187
187
  import { MorphSVGPlugin } from "gsap/MorphSVGPlugin";
188
188
 
@@ -592,7 +592,7 @@ if (typeof window !== "undefined") {
592
592
  }
593
593
 
594
594
  // src/player/components/ShortcutsPanel.tsx
595
- import { useState, useCallback as useCallback2, useEffect as useEffect2, useId, useRef as useRef2, memo } from "react";
595
+ import { useState, useCallback, useRef, memo } from "react";
596
596
 
597
597
  // src/components/timelineToolbarStyles.ts
598
598
  var flatBtn = "flex h-7 w-7 items-center justify-center rounded-md transition-colors";
@@ -600,34 +600,6 @@ var flatIdle = `${flatBtn} text-text-2 hover:bg-hover hover:text-text-0 active:b
600
600
  var flatActive = `${flatBtn} bg-on text-text-0 hover:bg-on-hover active:scale-[0.98]`;
601
601
  var flatDisabled = `${flatBtn} text-text-off cursor-not-allowed`;
602
602
 
603
- // src/hooks/useContextMenuDismiss.ts
604
- import { useCallback, useEffect, useRef } from "react";
605
- function useContextMenuDismiss(onClose) {
606
- const menuRef = useRef(null);
607
- const dismiss = useCallback(
608
- (e) => {
609
- if (e instanceof KeyboardEvent) {
610
- if (e.key === "Escape") onClose();
611
- return;
612
- }
613
- if (menuRef.current?.contains(e.target)) return;
614
- onClose();
615
- },
616
- [onClose]
617
- );
618
- useEffect(() => {
619
- document.addEventListener("pointerdown", dismiss, true);
620
- document.addEventListener("mousedown", dismiss, true);
621
- document.addEventListener("keydown", dismiss);
622
- return () => {
623
- document.removeEventListener("pointerdown", dismiss, true);
624
- document.removeEventListener("mousedown", dismiss, true);
625
- document.removeEventListener("keydown", dismiss);
626
- };
627
- }, [dismiss]);
628
- return menuRef;
629
- }
630
-
631
603
  // src/player/components/studioShortcuts.ts
632
604
  var STUDIO_PLAIN_KEYS = {
633
605
  fullscreen: "f",
@@ -727,6 +699,7 @@ var DEFAULT_SHORTCUT_SECTIONS = [
727
699
 
728
700
  // src/player/components/ShortcutsPanel.tsx
729
701
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
702
+ var STAY_ABOVE = { side: "none", align: "shift", fallbackAxisSide: "none" };
730
703
  var ShortcutsPanel = memo(function ShortcutsPanel2({
731
704
  disabled,
732
705
  duration,
@@ -739,33 +712,21 @@ var ShortcutsPanel = memo(function ShortcutsPanel2({
739
712
  }) {
740
713
  const [showShortcuts, setShowShortcuts] = useState(false);
741
714
  const [jumpFrame, setJumpFrame] = useState("");
742
- const shortcutsPanelId = useId();
743
- const closeShortcuts = useCallback2(() => setShowShortcuts(false), []);
744
- const shortcutsPanelRef = useContextMenuDismiss(closeShortcuts);
745
- const panelBodyRef = useRef2(null);
746
- const triggerRef = useRef2(null);
747
- useEffect2(() => {
748
- if (!showShortcuts) return;
749
- const trigger = triggerRef.current;
750
- panelBodyRef.current?.focus();
751
- return () => {
752
- trigger?.focus();
753
- };
754
- }, [showShortcuts]);
755
- const commitJumpFrame = useCallback2(() => {
715
+ const panelBodyRef = useRef(null);
716
+ const commitJumpFrame = useCallback(() => {
756
717
  if (disabled) return;
757
718
  const frame3 = Number.parseInt(jumpFrame, 10);
758
719
  if (!Number.isFinite(frame3) || duration <= 0) return;
759
720
  onSeek(Math.min(duration, frameToSeconds(Math.max(0, frame3))));
760
721
  }, [disabled, duration, jumpFrame, onSeek]);
761
- const handleJumpSubmit = useCallback2(
722
+ const handleJumpSubmit = useCallback(
762
723
  (e) => {
763
724
  e.preventDefault();
764
725
  commitJumpFrame();
765
726
  },
766
727
  [commitJumpFrame]
767
728
  );
768
- const handleJumpKeyDown = useCallback2(
729
+ const handleJumpKeyDown = useCallback(
769
730
  (e) => {
770
731
  if (e.key !== "Enter") return;
771
732
  e.preventDefault();
@@ -773,157 +734,150 @@ var ShortcutsPanel = memo(function ShortcutsPanel2({
773
734
  },
774
735
  [commitJumpFrame]
775
736
  );
776
- return /* @__PURE__ */ jsxs("div", { ref: shortcutsPanelRef, className: "relative shrink-0", children: [
777
- /* @__PURE__ */ jsx(Tooltip, { label: "Shortcuts and tools", children: /* @__PURE__ */ jsx(
778
- "button",
779
- {
780
- ref: triggerRef,
781
- type: "button",
782
- onClick: () => setShowShortcuts((v) => !v),
783
- className: showShortcuts ? flatActive : flatIdle,
784
- "aria-label": "Shortcuts and tools",
785
- "aria-expanded": showShortcuts,
786
- "aria-controls": shortcutsPanelId,
787
- children: /* @__PURE__ */ jsxs(
788
- "svg",
789
- {
790
- width: "11",
791
- height: "11",
792
- viewBox: "0 0 24 24",
793
- fill: "none",
794
- stroke: "currentColor",
795
- strokeWidth: "1.75",
796
- strokeLinecap: "round",
797
- strokeLinejoin: "round",
798
- "aria-hidden": "true",
799
- children: [
800
- /* @__PURE__ */ jsx("rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }),
801
- /* @__PURE__ */ jsx("path", { d: "M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M10 12h.01M14 12h.01M18 12h.01M8 16h8" })
802
- ]
803
- }
804
- )
805
- }
806
- ) }),
807
- showShortcuts && /* @__PURE__ */ jsxs(
808
- "div",
809
- {
810
- id: shortcutsPanelId,
811
- ref: panelBodyRef,
812
- tabIndex: -1,
813
- role: "dialog",
814
- "aria-label": "Keyboard shortcuts and tools",
815
- className: "absolute bottom-full right-0 mb-2 z-50 rounded-lg border border-border bg-raised shadow-popover min-w-[220px] overflow-y-auto outline-hidden",
816
- style: {
817
- maxHeight: "min(280px, calc(100vh - 80px))"
818
- },
819
- children: [
820
- /* @__PURE__ */ jsxs("div", { className: "px-3 pt-3 pb-2.5", children: [
821
- /* @__PURE__ */ jsx("p", { className: "text-[9px] font-medium text-neutral-500 uppercase tracking-wider mb-1.5", children: "Jump to frame" }),
822
- /* @__PURE__ */ jsxs("form", { onSubmit: handleJumpSubmit, className: "flex items-center gap-1.5", children: [
823
- /* @__PURE__ */ jsx(
824
- "input",
825
- {
826
- value: jumpFrame,
827
- onChange: (e) => setJumpFrame(e.target.value),
828
- disabled,
829
- inputMode: "numeric",
830
- pattern: "[0-9]*",
831
- "aria-label": "Jump to frame",
832
- placeholder: "frame number",
833
- className: "h-6 flex-1 rounded-sm border border-neutral-700 bg-neutral-900 px-2 text-[10px] font-mono tabular-nums text-neutral-200 outline-hidden transition-colors placeholder:text-neutral-600 focus:border-studio-accent/60",
834
- onKeyDown: handleJumpKeyDown,
835
- onBlur: commitJumpFrame
836
- }
837
- ),
838
- /* @__PURE__ */ jsx(Tooltip, { label: "Jump to frame", children: /* @__PURE__ */ jsx(
839
- "button",
840
- {
841
- type: "submit",
842
- disabled,
843
- className: "h-6 px-2 rounded-sm border border-neutral-700 text-[10px] text-neutral-300 transition-colors hover:border-neutral-500 hover:bg-neutral-800 disabled:opacity-40",
844
- children: "Go"
845
- }
846
- ) })
847
- ] })
848
- ] }),
849
- /* @__PURE__ */ jsx("div", { className: "border-t border-border" }),
850
- /* @__PURE__ */ jsxs("div", { className: "px-3 pt-2.5 pb-2", children: [
851
- /* @__PURE__ */ jsx("p", { className: "text-[9px] font-medium text-neutral-500 uppercase tracking-wider mb-1.5", children: "Work area" }),
852
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
853
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
854
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
855
- /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] rounded-sm border border-neutral-700 px-1.5 py-0.5 text-neutral-300 min-w-[20px] text-center bg-hover", children: "I" }),
856
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-400", children: "In-point" })
857
- ] }),
858
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: inPoint !== null ? /* @__PURE__ */ jsxs(Fragment, { children: [
859
- /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] text-neutral-300", children: formatTime(inPoint) }),
860
- /* @__PURE__ */ jsx(Tooltip, { label: "Clear in-point", children: /* @__PURE__ */ jsx(
861
- "button",
862
- {
863
- type: "button",
864
- onClick: () => setInPoint(null),
865
- className: "w-4 h-4 flex items-center justify-center rounded-sm text-neutral-500 hover:text-neutral-200 transition-colors",
866
- "aria-label": "Clear in-point",
867
- children: /* @__PURE__ */ jsx(
868
- "svg",
869
- {
870
- width: "8",
871
- height: "8",
872
- viewBox: "0 0 24 24",
873
- fill: "none",
874
- stroke: "currentColor",
875
- strokeWidth: "2.5",
876
- children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
877
- }
878
- )
879
- }
880
- ) })
881
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-600", children: "Not set" }) })
737
+ return /* @__PURE__ */ jsx(Tooltip, { label: "Shortcuts and tools", children: /* @__PURE__ */ jsx(
738
+ Popover,
739
+ {
740
+ open: showShortcuts,
741
+ onOpenChange: setShowShortcuts,
742
+ side: "top",
743
+ align: "end",
744
+ collisionAvoidance: STAY_ABOVE,
745
+ "aria-label": "Keyboard shortcuts and tools",
746
+ initialFocus: panelBodyRef,
747
+ className: "flex max-h-[min(280px,var(--available-height))] min-w-[220px] flex-col border-border bg-raised p-0",
748
+ trigger: /* @__PURE__ */ jsx(
749
+ "button",
750
+ {
751
+ type: "button",
752
+ className: `${showShortcuts ? flatActive : flatIdle} shrink-0`,
753
+ "aria-label": "Shortcuts and tools",
754
+ children: /* @__PURE__ */ jsxs(
755
+ "svg",
756
+ {
757
+ width: "11",
758
+ height: "11",
759
+ viewBox: "0 0 24 24",
760
+ fill: "none",
761
+ stroke: "currentColor",
762
+ strokeWidth: "1.75",
763
+ strokeLinecap: "round",
764
+ strokeLinejoin: "round",
765
+ "aria-hidden": "true",
766
+ children: [
767
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }),
768
+ /* @__PURE__ */ jsx("path", { d: "M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M10 12h.01M14 12h.01M18 12h.01M8 16h8" })
769
+ ]
770
+ }
771
+ )
772
+ }
773
+ ),
774
+ children: /* @__PURE__ */ jsxs("div", { ref: panelBodyRef, tabIndex: -1, className: "min-h-0 overflow-y-auto outline-hidden", children: [
775
+ /* @__PURE__ */ jsxs("div", { className: "px-3 pt-3 pb-2.5", children: [
776
+ /* @__PURE__ */ jsx("p", { className: "text-[9px] font-medium text-neutral-500 uppercase tracking-wider mb-1.5", children: "Jump to frame" }),
777
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleJumpSubmit, className: "flex items-center gap-1.5", children: [
778
+ /* @__PURE__ */ jsx(
779
+ "input",
780
+ {
781
+ value: jumpFrame,
782
+ onChange: (e) => setJumpFrame(e.target.value),
783
+ disabled,
784
+ inputMode: "numeric",
785
+ pattern: "[0-9]*",
786
+ "aria-label": "Jump to frame",
787
+ placeholder: "frame number",
788
+ className: "h-6 flex-1 rounded-sm border border-neutral-700 bg-neutral-900 px-2 text-[10px] font-mono tabular-nums text-neutral-200 outline-hidden transition-colors placeholder:text-neutral-600 focus:border-studio-accent/60",
789
+ onKeyDown: handleJumpKeyDown,
790
+ onBlur: commitJumpFrame
791
+ }
792
+ ),
793
+ /* @__PURE__ */ jsx(Tooltip, { label: "Jump to frame", children: /* @__PURE__ */ jsx(
794
+ "button",
795
+ {
796
+ type: "submit",
797
+ disabled,
798
+ className: "h-6 px-2 rounded-sm border border-neutral-700 text-[10px] text-neutral-300 transition-colors hover:border-neutral-500 hover:bg-neutral-800 disabled:opacity-40",
799
+ children: "Go"
800
+ }
801
+ ) })
802
+ ] })
803
+ ] }),
804
+ /* @__PURE__ */ jsx("div", { className: "border-t border-border" }),
805
+ /* @__PURE__ */ jsxs("div", { className: "px-3 pt-2.5 pb-2", children: [
806
+ /* @__PURE__ */ jsx("p", { className: "text-[9px] font-medium text-neutral-500 uppercase tracking-wider mb-1.5", children: "Work area" }),
807
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
808
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
809
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
810
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] rounded-sm border border-neutral-700 px-1.5 py-0.5 text-neutral-300 min-w-[20px] text-center bg-hover", children: "I" }),
811
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-400", children: "In-point" })
882
812
  ] }),
883
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
884
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
885
- /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] rounded-sm border border-neutral-700 px-1.5 py-0.5 text-neutral-300 min-w-[20px] text-center bg-hover", children: "O" }),
886
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-400", children: "Out-point" })
887
- ] }),
888
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: outPoint !== null ? /* @__PURE__ */ jsxs(Fragment, { children: [
889
- /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] text-neutral-300", children: formatTime(outPoint) }),
890
- /* @__PURE__ */ jsx(Tooltip, { label: "Clear out-point", children: /* @__PURE__ */ jsx(
891
- "button",
892
- {
893
- type: "button",
894
- onClick: () => setOutPoint(null),
895
- className: "w-4 h-4 flex items-center justify-center rounded-sm text-neutral-500 hover:text-neutral-200 transition-colors",
896
- "aria-label": "Clear out-point",
897
- children: /* @__PURE__ */ jsx(
898
- "svg",
899
- {
900
- width: "8",
901
- height: "8",
902
- viewBox: "0 0 24 24",
903
- fill: "none",
904
- stroke: "currentColor",
905
- strokeWidth: "2.5",
906
- children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
907
- }
908
- )
909
- }
910
- ) })
911
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-600", children: "Not set" }) })
912
- ] })
813
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: inPoint !== null ? /* @__PURE__ */ jsxs(Fragment, { children: [
814
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] text-neutral-300", children: formatTime(inPoint) }),
815
+ /* @__PURE__ */ jsx(Tooltip, { label: "Clear in-point", children: /* @__PURE__ */ jsx(
816
+ "button",
817
+ {
818
+ type: "button",
819
+ onClick: () => setInPoint(null),
820
+ className: "w-4 h-4 flex items-center justify-center rounded-sm text-neutral-500 hover:text-neutral-200 transition-colors",
821
+ "aria-label": "Clear in-point",
822
+ children: /* @__PURE__ */ jsx(
823
+ "svg",
824
+ {
825
+ width: "8",
826
+ height: "8",
827
+ viewBox: "0 0 24 24",
828
+ fill: "none",
829
+ stroke: "currentColor",
830
+ strokeWidth: "2.5",
831
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
832
+ }
833
+ )
834
+ }
835
+ ) })
836
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-600", children: "Not set" }) })
837
+ ] }),
838
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
839
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
840
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] rounded-sm border border-neutral-700 px-1.5 py-0.5 text-neutral-300 min-w-[20px] text-center bg-hover", children: "O" }),
841
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-400", children: "Out-point" })
842
+ ] }),
843
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: outPoint !== null ? /* @__PURE__ */ jsxs(Fragment, { children: [
844
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] text-neutral-300", children: formatTime(outPoint) }),
845
+ /* @__PURE__ */ jsx(Tooltip, { label: "Clear out-point", children: /* @__PURE__ */ jsx(
846
+ "button",
847
+ {
848
+ type: "button",
849
+ onClick: () => setOutPoint(null),
850
+ className: "w-4 h-4 flex items-center justify-center rounded-sm text-neutral-500 hover:text-neutral-200 transition-colors",
851
+ "aria-label": "Clear out-point",
852
+ children: /* @__PURE__ */ jsx(
853
+ "svg",
854
+ {
855
+ width: "8",
856
+ height: "8",
857
+ viewBox: "0 0 24 24",
858
+ fill: "none",
859
+ stroke: "currentColor",
860
+ strokeWidth: "2.5",
861
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
862
+ }
863
+ )
864
+ }
865
+ ) })
866
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-600", children: "Not set" }) })
913
867
  ] })
914
- ] }),
915
- /* @__PURE__ */ jsx("div", { className: "border-t border-border" }),
916
- /* @__PURE__ */ jsx("div", { className: "px-3 pt-2.5 pb-3 flex flex-col gap-3", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs("div", { children: [
917
- /* @__PURE__ */ jsx("p", { className: "text-[9px] font-medium text-neutral-500 uppercase tracking-wider mb-1.5", children: section.title }),
918
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: section.hints.map((hint, hintIndex) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
919
- /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] rounded-sm border border-neutral-700 px-1.5 py-0.5 text-neutral-300 min-w-[36px] text-center bg-hover", children: hint.key }),
920
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-400", children: hint.label })
921
- ] }, hintIndex)) })
922
- ] }, sectionIndex)) })
923
- ]
924
- }
925
- )
926
- ] });
868
+ ] })
869
+ ] }),
870
+ /* @__PURE__ */ jsx("div", { className: "border-t border-border" }),
871
+ /* @__PURE__ */ jsx("div", { className: "px-3 pt-2.5 pb-3 flex flex-col gap-3", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs("div", { children: [
872
+ /* @__PURE__ */ jsx("p", { className: "text-[9px] font-medium text-neutral-500 uppercase tracking-wider mb-1.5", children: section.title }),
873
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: section.hints.map((hint, hintIndex) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
874
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] rounded-sm border border-neutral-700 px-1.5 py-0.5 text-neutral-300 min-w-[36px] text-center bg-hover", children: hint.key }),
875
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-neutral-400", children: hint.label })
876
+ ] }, hintIndex)) })
877
+ ] }, sectionIndex)) })
878
+ ] })
879
+ }
880
+ ) });
927
881
  });
928
882
  function ShortcutsButton({ sections, disabled = false, onSeek }) {
929
883
  const duration = usePlayerStore((s) => s.duration);
@@ -947,6 +901,36 @@ function ShortcutsButton({ sections, disabled = false, onSeek }) {
947
901
 
948
902
  // src/player/components/SpeedMenu.tsx
949
903
  import { useState as useState2, useCallback as useCallback3, memo as memo2 } from "react";
904
+
905
+ // src/hooks/useContextMenuDismiss.ts
906
+ import { useCallback as useCallback2, useEffect, useRef as useRef2 } from "react";
907
+ function useContextMenuDismiss(onClose) {
908
+ const menuRef = useRef2(null);
909
+ const dismiss = useCallback2(
910
+ (e) => {
911
+ if (e instanceof KeyboardEvent) {
912
+ if (e.key === "Escape") onClose();
913
+ return;
914
+ }
915
+ if (menuRef.current?.contains(e.target)) return;
916
+ onClose();
917
+ },
918
+ [onClose]
919
+ );
920
+ useEffect(() => {
921
+ document.addEventListener("pointerdown", dismiss, true);
922
+ document.addEventListener("mousedown", dismiss, true);
923
+ document.addEventListener("keydown", dismiss);
924
+ return () => {
925
+ document.removeEventListener("pointerdown", dismiss, true);
926
+ document.removeEventListener("mousedown", dismiss, true);
927
+ document.removeEventListener("keydown", dismiss);
928
+ };
929
+ }, [dismiss]);
930
+ return menuRef;
931
+ }
932
+
933
+ // src/player/components/SpeedMenu.tsx
950
934
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
951
935
  var SPEED_OPTIONS = [0.25, 0.5, 1, 1.5, 2];
952
936
  var SpeedMenu = memo2(function SpeedMenu2({
@@ -1102,7 +1086,7 @@ var PAUSE_BARS_D = "M56 28H67V71H56Z M73 28H84V71H73Z";
1102
1086
  function PlayPauseMorphIcon({ playing }) {
1103
1087
  const pathRef = useRef3(null);
1104
1088
  const isFirstRun = useRef3(true);
1105
- useEffect3(() => {
1089
+ useEffect2(() => {
1106
1090
  const el = pathRef.current;
1107
1091
  if (!el) return;
1108
1092
  const target = playing ? PAUSE_BARS_D : PLAY_BLADE_D;
@@ -1229,7 +1213,7 @@ var PlayerControls = memo4(function PlayerControls2({
1229
1213
  const durationRef = useRef3(duration);
1230
1214
  durationRef.current = duration;
1231
1215
  const controlsDisabled = disabled || !timelineReady;
1232
- useEffect3(() => {
1216
+ useEffect2(() => {
1233
1217
  if (!timeDisplayRef.current) return;
1234
1218
  const t2 = currentTimeRef.current;
1235
1219
  timeDisplayRef.current.textContent = timeDisplayMode === "frame" ? formatFrameTime(t2, duration) : formatTime(t2);
@@ -1342,7 +1326,7 @@ import {
1342
1326
  import { useRef as useRef25, useMemo as useMemo24, useCallback as useCallback22, useState as useState16 } from "react";
1343
1327
 
1344
1328
  // src/hooks/useMusicBeatAnalysis.ts
1345
- import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4 } from "react";
1329
+ import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef4 } from "react";
1346
1330
 
1347
1331
  // src/utils/timelineInspector.ts
1348
1332
  import { HF_AUDIO_GROUP_TAG } from "@hyperframes/core/audio-groups";
@@ -1857,7 +1841,7 @@ function useMusicBeatAnalysis() {
1857
1841
  isFallbackTrack: resolved2?.isFallback ?? false
1858
1842
  };
1859
1843
  }, [elements]);
1860
- useEffect4(() => {
1844
+ useEffect3(() => {
1861
1845
  if (!musicSrc) {
1862
1846
  setBeatAnalysis(null);
1863
1847
  setBeatEdits(null);
@@ -1903,7 +1887,7 @@ function useMusicBeatAnalysis() {
1903
1887
  cancelled = true;
1904
1888
  };
1905
1889
  }, [musicSrc, isFallbackTrack, setBeatAnalysis, setBeatEdits, resetBeatHistory]);
1906
- useEffect4(() => {
1890
+ useEffect3(() => {
1907
1891
  const beatPath = beatFilePathForSrc(musicSrc);
1908
1892
  if (!musicSrc || !beatPath || !ioRef.current) {
1909
1893
  setBeatPersist(null);
@@ -2013,7 +1997,7 @@ function getRenderedTimelineElement({
2013
1997
  }
2014
1998
 
2015
1999
  // src/player/components/useTimelinePlayhead.ts
2016
- import { useRef as useRef5, useCallback as useCallback4, useEffect as useEffect5, useLayoutEffect } from "react";
2000
+ import { useRef as useRef5, useCallback as useCallback4, useEffect as useEffect4, useLayoutEffect } from "react";
2017
2001
 
2018
2002
  // src/player/components/timelineZoomInput.ts
2019
2003
  import { useSyncExternalStore as useSyncExternalStore2 } from "react";
@@ -3441,7 +3425,7 @@ function useTimelinePlayhead({
3441
3425
  },
3442
3426
  [playheadRef, durationRef, ppsRef, contentOrigin]
3443
3427
  );
3444
- useEffect5(() => {
3428
+ useEffect4(() => {
3445
3429
  syncPlayheadPosition(currentTime);
3446
3430
  }, [currentTime, pps, syncPlayheadPosition, timelineReady, elementsLength]);
3447
3431
  useLayoutEffect(() => {
@@ -3449,7 +3433,7 @@ function useTimelinePlayhead({
3449
3433
  if (!scroll || zoomMode !== "fit") return;
3450
3434
  scroll.scrollLeft = 0;
3451
3435
  }, [zoomMode, pps, scrollRef]);
3452
- useEffect5(() => {
3436
+ useEffect4(() => {
3453
3437
  const scroll = scrollRef.current;
3454
3438
  if (!scroll) {
3455
3439
  previousZoomModeRef.current = zoomMode;
@@ -3561,7 +3545,7 @@ function useTimelinePlayhead({
3561
3545
  },
3562
3546
  [scrollRef, durationRef, fitPpsRef, ppsRef]
3563
3547
  );
3564
- useEffect5(() => {
3548
+ useEffect4(() => {
3565
3549
  const scroll = scrollRef.current;
3566
3550
  if (!scroll) return;
3567
3551
  scroll.addEventListener("wheel", handlePinchWheel, { passive: false, capture: true });
@@ -3602,7 +3586,7 @@ function useTimelineZoom() {
3602
3586
  }
3603
3587
 
3604
3588
  // src/player/components/timelineDragDrop.ts
3605
- import { useCallback as useCallback5, useEffect as useEffect6, useRef as useRef6, useState as useState4 } from "react";
3589
+ import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef6, useState as useState4 } from "react";
3606
3590
 
3607
3591
  // src/utils/timelineAssetDrop.ts
3608
3592
  import { encodeUrlPath } from "@hyperframes/parsers";
@@ -4150,14 +4134,14 @@ function useTimelineAssetDrop({
4150
4134
  sessionEpoch
4151
4135
  ]
4152
4136
  );
4153
- useEffect6(() => {
4137
+ useEffect5(() => {
4154
4138
  window.addEventListener("dragend", clearDropPreview);
4155
4139
  return () => {
4156
4140
  window.removeEventListener("dragend", clearDropPreview);
4157
4141
  clearDropPreview();
4158
4142
  };
4159
4143
  }, [clearDropPreview]);
4160
- useEffect6(() => clearDropPreview(), [clearDropPreview, sessionEpoch]);
4144
+ useEffect5(() => clearDropPreview(), [clearDropPreview, sessionEpoch]);
4161
4145
  return {
4162
4146
  isDragOver,
4163
4147
  dropPreview: dropPreview2,
@@ -4169,7 +4153,7 @@ function useTimelineAssetDrop({
4169
4153
  }
4170
4154
 
4171
4155
  // src/player/components/useTimelineClipDrag.ts
4172
- import { useRef as useRef12, useState as useState8, useCallback as useCallback8, useMemo as useMemo7, useEffect as useEffect11 } from "react";
4156
+ import { useRef as useRef12, useState as useState8, useCallback as useCallback8, useMemo as useMemo7, useEffect as useEffect10 } from "react";
4173
4157
 
4174
4158
  // src/player/components/timelineRulerGeometry.ts
4175
4159
  function getTimelineMajorTickInterval(duration, pixelsPerSecond, frameRate) {
@@ -4812,7 +4796,7 @@ var useLinkedClipPreferences = create2((set) => ({
4812
4796
  var isLinkedSelectionOn = () => useLinkedClipPreferences.getState().linkedSelection;
4813
4797
 
4814
4798
  // src/player/components/timelineReadOnly.ts
4815
- import { createContext as createContext2, useContext as useContext2, useEffect as useEffect7, useEffectEvent } from "react";
4799
+ import { createContext as createContext2, useContext as useContext2, useEffect as useEffect6, useEffectEvent } from "react";
4816
4800
  var TimelineReadOnlyContext = createContext2(null);
4817
4801
  function useTimelineReadOnlyPress() {
4818
4802
  return useContext2(TimelineReadOnlyContext);
@@ -4832,7 +4816,7 @@ function refuseWhenReadOnly(readOnlyPress, callbacks) {
4832
4816
  }
4833
4817
  function useAbandonEditsOnReadOnly(readOnly, abandon) {
4834
4818
  const abandonNow = useEffectEvent(abandon);
4835
- useEffect7(() => {
4819
+ useEffect6(() => {
4836
4820
  if (readOnly) abandonNow();
4837
4821
  }, [readOnly]);
4838
4822
  }
@@ -5373,7 +5357,7 @@ function synthesizeFlatTweenKeyframes(anim) {
5373
5357
  }
5374
5358
 
5375
5359
  // src/player/components/TimelineClipDiamonds.tsx
5376
- import { memo as memo8, useEffect as useEffect10, useRef as useRef10, useState as useState7 } from "react";
5360
+ import { memo as memo8, useEffect as useEffect9, useRef as useRef10, useState as useState7 } from "react";
5377
5361
 
5378
5362
  // src/player/components/BeatStrip.tsx
5379
5363
  import { memo as memo5, useSyncExternalStore as useSyncExternalStore3 } from "react";
@@ -5745,7 +5729,7 @@ function previewClipPct(opts) {
5745
5729
  }
5746
5730
 
5747
5731
  // src/components/editor/EaseCurveSection.tsx
5748
- import { useEffect as useEffect9, useId as useId3, useRef as useRef8, useState as useState6 } from "react";
5732
+ import { useEffect as useEffect8, useId as useId2, useRef as useRef8, useState as useState6 } from "react";
5749
5733
  import { evaluateSpringEase as evaluateSpringEase2, parseSpringBounce as parseSpringBounce3 } from "@hyperframes/core/spring-ease";
5750
5734
  import {
5751
5735
  evaluateWiggleEase as evaluateWiggleEase2,
@@ -6287,7 +6271,7 @@ function EaseModeToggle({
6287
6271
  }
6288
6272
 
6289
6273
  // src/components/editor/EaseParamFields.tsx
6290
- import { useEffect as useEffect8, useId as useId2, useRef as useRef7, useState as useState5 } from "react";
6274
+ import { useEffect as useEffect7, useId, useRef as useRef7, useState as useState5 } from "react";
6291
6275
  import { parseSpringBounce as parseSpringBounce2 } from "@hyperframes/core/spring-ease";
6292
6276
  import {
6293
6277
  parseWiggleEase as parseWiggleEase2
@@ -6316,9 +6300,9 @@ function EaseBezierField({
6316
6300
  }) {
6317
6301
  const text = tuple.join(", ");
6318
6302
  const inputRef = useRef7(null);
6319
- const errorId = useId2();
6303
+ const errorId = useId();
6320
6304
  const [error, setError] = useState5(null);
6321
- useEffect8(() => {
6305
+ useEffect7(() => {
6322
6306
  if (inputRef.current) inputRef.current.value = text;
6323
6307
  setError(null);
6324
6308
  }, [text]);
@@ -6391,7 +6375,7 @@ function NumericCommitInput({
6391
6375
  onCommit
6392
6376
  }) {
6393
6377
  const [draft, setDraft] = useState5(String(value));
6394
- useEffect8(() => setDraft(String(value)), [value]);
6378
+ useEffect7(() => setDraft(String(value)), [value]);
6395
6379
  const commit2 = () => {
6396
6380
  if (draft.trim() === "") {
6397
6381
  setDraft(String(value));
@@ -6524,8 +6508,8 @@ function EaseTypeDropdown({
6524
6508
  const [open, setOpen] = useState6(false);
6525
6509
  const triggerRef = useRef8(null);
6526
6510
  const menuRef = useRef8(null);
6527
- const menuId = useId3();
6528
- useEffect9(() => {
6511
+ const menuId = useId2();
6512
+ useEffect8(() => {
6529
6513
  if (!open) return;
6530
6514
  const menu = menuRef.current;
6531
6515
  const selected = menu?.querySelector('[role="menuitemradio"][aria-checked="true"]') ?? menu?.querySelector('[role="menuitemradio"]');
@@ -6707,7 +6691,7 @@ function EaseCurveSection({
6707
6691
  const [hover, setHover] = useState6(null);
6708
6692
  const draggingRef = useRef8(null);
6709
6693
  const svgRef = useRef8(null);
6710
- useEffect9(() => {
6694
+ useEffect8(() => {
6711
6695
  setDraft(null);
6712
6696
  const inFlight = inFlightEasesRef.current;
6713
6697
  const landed = inFlight.indexOf(ease);
@@ -6719,7 +6703,7 @@ function EaseCurveSection({
6719
6703
  inFlight.splice(0, landed + 1);
6720
6704
  if (inFlight.length === 0) setPendingEase(null);
6721
6705
  }, [ease]);
6722
- useEffect9(() => {
6706
+ useEffect8(() => {
6723
6707
  if (pendingEase === null) return;
6724
6708
  const timer = setTimeout(() => {
6725
6709
  inFlightEasesRef.current.length = 0;
@@ -8001,7 +7985,7 @@ var TimelineDiamondLane = memo8(function TimelineDiamondLane2({
8001
7985
  const readOnlyPress = useTimelineReadOnlyPress();
8002
7986
  const pendingRetimes = readPendingTimelineKeyframeRetimes(rootRef.current);
8003
7987
  const [preview2, setPreview] = useState7(null);
8004
- useEffect10(() => {
7988
+ useEffect9(() => {
8005
7989
  const source = rootRef.current;
8006
7990
  if (!source) return;
8007
7991
  return subscribeTimelineKeyframeRetimePreview(source, (nextPreview) => {
@@ -11144,7 +11128,7 @@ function useTimelineClipDrag({
11144
11128
  lifecycleRef
11145
11129
  })
11146
11130
  );
11147
- useEffect11(() => {
11131
+ useEffect10(() => {
11148
11132
  const movePickup = (drag, step, viewport2) => {
11149
11133
  const audioTracks = getTimelineElementIndexes(elementsRef.current).audioTracks;
11150
11134
  const row = nextKeyboardInsertRow({
@@ -11208,11 +11192,11 @@ function useTimelineClipDrag({
11208
11192
  trackOrderRef,
11209
11193
  trackInsertLayoutRef
11210
11194
  ]);
11211
- useEffect11(() => {
11195
+ useEffect10(() => {
11212
11196
  cancelGestureRef.current();
11213
11197
  }, [sessionEpoch]);
11214
11198
  const previousOrderRef = useRef12(trackOrderRef.current);
11215
- useEffect11(() => {
11199
+ useEffect10(() => {
11216
11200
  const order = trackOrderRef.current;
11217
11201
  const previous = previousOrderRef.current;
11218
11202
  previousOrderRef.current = order;
@@ -11499,7 +11483,7 @@ function useClipContextMenu(onSelectElement, dismissGapMenu, setClipContextMenu)
11499
11483
  }
11500
11484
 
11501
11485
  // src/player/components/useTimelineRangeSelection.ts
11502
- import { useRef as useRef13, useState as useState10, useCallback as useCallback12, useEffect as useEffect12 } from "react";
11486
+ import { useRef as useRef13, useState as useState10, useCallback as useCallback12, useEffect as useEffect11 } from "react";
11503
11487
 
11504
11488
  // src/utils/marqueeGeometry.ts
11505
11489
  function rectsOverlap(a, b) {
@@ -12078,7 +12062,7 @@ function useTimelineRangeSelection({
12078
12062
  },
12079
12063
  [cancelActiveGesture, isGestureSessionCurrent]
12080
12064
  );
12081
- useEffect12(() => {
12065
+ useEffect11(() => {
12082
12066
  const onBandEscape = (e) => {
12083
12067
  if (e.key !== "Escape" || !(marqueeRef.current || isRangeSelecting.current)) return;
12084
12068
  e.preventDefault();
@@ -12102,12 +12086,12 @@ function useTimelineRangeSelection({
12102
12086
  return () => listeners3.abort();
12103
12087
  }, [cancelActiveGesture, isDragging]);
12104
12088
  const previousSessionEpochRef = useRef13(sessionEpoch);
12105
- useEffect12(() => {
12089
+ useEffect11(() => {
12106
12090
  if (previousSessionEpochRef.current === sessionEpoch) return;
12107
12091
  previousSessionEpochRef.current = sessionEpoch;
12108
12092
  cancelActiveGesture(true, false);
12109
12093
  }, [cancelActiveGesture, sessionEpoch]);
12110
- useEffect12(
12094
+ useEffect11(
12111
12095
  () => () => {
12112
12096
  cancelActiveGesture(false, isGestureSessionCurrent());
12113
12097
  },
@@ -12126,14 +12110,14 @@ function useTimelineRangeSelection({
12126
12110
  }
12127
12111
 
12128
12112
  // src/player/components/usePublishRangeSelection.ts
12129
- import { useEffect as useEffect13, useRef as useRef14 } from "react";
12113
+ import { useEffect as useEffect12, useRef as useRef14 } from "react";
12130
12114
  function usePublishRangeSelection(rangeSelection, onRangeSelect) {
12131
12115
  const onRangeSelectRef = useRef14(onRangeSelect);
12132
12116
  const publishedRangeRef = useRef14(null);
12133
- useEffect13(() => {
12117
+ useEffect12(() => {
12134
12118
  onRangeSelectRef.current = onRangeSelect;
12135
12119
  }, [onRangeSelect]);
12136
- useEffect13(() => {
12120
+ useEffect12(() => {
12137
12121
  const range = rangeSelection ? {
12138
12122
  t0: Math.min(rangeSelection.start, rangeSelection.end),
12139
12123
  t1: Math.max(rangeSelection.start, rangeSelection.end)
@@ -12145,7 +12129,7 @@ function usePublishRangeSelection(rangeSelection, onRangeSelect) {
12145
12129
  usePlayerStore.setState({ rangeSelection: range });
12146
12130
  onRangeSelectRef.current?.(range);
12147
12131
  }, [rangeSelection]);
12148
- useEffect13(
12132
+ useEffect12(
12149
12133
  () => () => {
12150
12134
  const current = usePlayerStore.getState().rangeSelection;
12151
12135
  const published = publishedRangeRef.current;
@@ -12157,7 +12141,7 @@ function usePublishRangeSelection(rangeSelection, onRangeSelect) {
12157
12141
  }
12158
12142
 
12159
12143
  // src/player/components/useTimelineSelectionLifecycle.ts
12160
- import { useEffect as useEffect14, useMemo as useMemo9, useRef as useRef15 } from "react";
12144
+ import { useEffect as useEffect13, useMemo as useMemo9, useRef as useRef15 } from "react";
12161
12145
  function useTimelineSelectionLifecycle(elements, selectedElementId, setShowPopover, clearRangeSelection) {
12162
12146
  const selectedElement = useMemo9(
12163
12147
  () => elements.find((element) => getTimelineElementIdentity(element) === selectedElementId) ?? null,
@@ -12166,7 +12150,7 @@ function useTimelineSelectionLifecycle(elements, selectedElementId, setShowPopov
12166
12150
  const selectedElementRef = useRef15(selectedElement);
12167
12151
  selectedElementRef.current = selectedElement;
12168
12152
  const previousSelectedRef = useRef15(selectedElementRef.current);
12169
- useEffect14(() => {
12153
+ useEffect13(() => {
12170
12154
  const previous = previousSelectedRef.current;
12171
12155
  const current = selectedElementRef.current;
12172
12156
  previousSelectedRef.current = current;
@@ -12178,7 +12162,7 @@ function useTimelineSelectionLifecycle(elements, selectedElementId, setShowPopov
12178
12162
  }
12179
12163
 
12180
12164
  // src/player/components/useTrackGapMenu.ts
12181
- import { useCallback as useCallback13, useEffect as useEffect15, useMemo as useMemo10, useState as useState11 } from "react";
12165
+ import { useCallback as useCallback13, useEffect as useEffect14, useMemo as useMemo10, useState as useState11 } from "react";
12182
12166
 
12183
12167
  // src/player/components/timelineGaps.ts
12184
12168
  var TRACK_GAP_EPSILON_S = 1e-3;
@@ -12387,7 +12371,7 @@ function useTrackGapMenu({
12387
12371
  setHoveredGapAction(null);
12388
12372
  setGapContextMenu(null);
12389
12373
  }, []);
12390
- useEffect15(() => {
12374
+ useEffect14(() => {
12391
12375
  if (gapContextMenu && gapContextMenu.sessionEpoch !== sessionEpoch) dismissGapMenu();
12392
12376
  }, [dismissGapMenu, gapContextMenu, sessionEpoch]);
12393
12377
  return {
@@ -13375,7 +13359,7 @@ function useTimelineStackingSync({
13375
13359
  }
13376
13360
 
13377
13361
  // src/player/components/useTimelineGeometry.ts
13378
- import { useEffect as useEffect16, useLayoutEffect as useLayoutEffect2, useRef as useRef18 } from "react";
13362
+ import { useEffect as useEffect15, useLayoutEffect as useLayoutEffect2, useRef as useRef18 } from "react";
13379
13363
  function useTimelineGeometry({
13380
13364
  viewportWidth,
13381
13365
  effectiveDuration,
@@ -13408,7 +13392,7 @@ function useTimelineGeometry({
13408
13392
  const zoomModeRef = useRef18(zoomMode);
13409
13393
  zoomModeRef.current = zoomMode;
13410
13394
  fitPpsRef.current = fitPps;
13411
- useEffect16(() => {
13395
+ useEffect15(() => {
13412
13396
  if (zoomMode !== "manual" || isDragging.current) return;
13413
13397
  const el = scrollRef.current;
13414
13398
  if (!el) return;
@@ -13421,7 +13405,7 @@ function useTimelineGeometry({
13421
13405
  });
13422
13406
  return () => cancelAnimationFrame(raf);
13423
13407
  }, [expandedElements, zoomMode]);
13424
- useEffect16(() => {
13408
+ useEffect15(() => {
13425
13409
  usePlayerStore.getState().setTimelineScale(pps, fitPps);
13426
13410
  }, [pps, fitPps]);
13427
13411
  const hasClips = expandedElements.length > 0;
@@ -13444,7 +13428,7 @@ function useTimelineGeometry({
13444
13428
  }
13445
13429
 
13446
13430
  // src/player/components/useAutoExpandKeyframedClips.ts
13447
- import { useEffect as useEffect17, useRef as useRef19 } from "react";
13431
+ import { useEffect as useEffect16, useRef as useRef19 } from "react";
13448
13432
  function freshLaneClips(gsapAnimations, clips) {
13449
13433
  for (const key2 of clips) {
13450
13434
  if (!gsapAnimations.has(key2)) clips.delete(key2);
@@ -13460,7 +13444,7 @@ function useAutoExpandKeyframedClips(gsapAnimations) {
13460
13444
  const expandClips = usePlayerStore((s) => s.expandClips);
13461
13445
  const projectId = useStudioShellContextOptional()?.projectId ?? null;
13462
13446
  const seen = useRef19({ projectId, source: gsapAnimations, clips: /* @__PURE__ */ new Set() });
13463
- useEffect17(() => {
13447
+ useEffect16(() => {
13464
13448
  if (seen.current.projectId !== projectId) {
13465
13449
  const sourceChanged = seen.current.source !== gsapAnimations;
13466
13450
  seen.current = { projectId, source: gsapAnimations, clips: /* @__PURE__ */ new Set() };
@@ -13498,7 +13482,7 @@ function useTimelineKeyframeData(showKeyframes) {
13498
13482
  }
13499
13483
 
13500
13484
  // src/player/components/useTimelineScrollViewport.ts
13501
- import { useCallback as useCallback17, useEffect as useEffect18, useRef as useRef20, useState as useState12 } from "react";
13485
+ import { useCallback as useCallback17, useEffect as useEffect17, useRef as useRef20, useState as useState12 } from "react";
13502
13486
 
13503
13487
  // src/player/components/timelineRowVirtualizationFlag.ts
13504
13488
  var STUDIO_TIMELINE_ROW_VIRTUALIZATION_ENABLED = import.meta.env?.VITE_STUDIO_TIMELINE_ROW_VIRTUALIZATION_ENABLED !== "0";
@@ -13597,7 +13581,7 @@ function useTimelineScrollViewport(scrollRef, resyncShortcutHintOn) {
13597
13581
  if (viewportRafRef.current) cancelAnimationFrame(viewportRafRef.current);
13598
13582
  if (scrollSettledTimerRef.current) clearTimeout(scrollSettledTimerRef.current);
13599
13583
  });
13600
- useEffect18(() => {
13584
+ useEffect17(() => {
13601
13585
  syncShortcutHintVisibility();
13602
13586
  }, [syncShortcutHintVisibility, ...resyncShortcutHintOn]);
13603
13587
  return { viewport: viewport2, showShortcutHint, setScrollRef, syncScrollViewport };
@@ -14065,7 +14049,7 @@ function useTimelineLaneMoveRefresh() {
14065
14049
  }
14066
14050
 
14067
14051
  // src/player/components/useTimelineFocusCoordinator.ts
14068
- import { useEffect as useEffect19, useLayoutEffect as useLayoutEffect4, useMemo as useMemo20, useRef as useRef23 } from "react";
14052
+ import { useEffect as useEffect18, useLayoutEffect as useLayoutEffect4, useMemo as useMemo20, useRef as useRef23 } from "react";
14069
14053
 
14070
14054
  // src/player/components/timelineRevealScroll.ts
14071
14055
  var REVEAL_SCROLL_PADDING_PX = 12;
@@ -14204,7 +14188,7 @@ function useTimelineFocusCoordinator({
14204
14188
  useLayoutEffect4(() => {
14205
14189
  previousRowsRef.current = logicalRows;
14206
14190
  }, [logicalRows]);
14207
- useEffect19(() => {
14191
+ useEffect18(() => {
14208
14192
  if (!isCurrentRequest(request2, projectId, sessionEpoch)) return;
14209
14193
  if (!resolution) {
14210
14194
  const withinBudget = recordRetryAttempt(
@@ -14337,7 +14321,7 @@ function resolveTimelineFocusIdentity(elements, elementId2) {
14337
14321
  }
14338
14322
 
14339
14323
  // src/player/components/useTimelineVirtualRows.ts
14340
- import { useCallback as useCallback20, useEffect as useEffect20, useMemo as useMemo22 } from "react";
14324
+ import { useCallback as useCallback20, useEffect as useEffect19, useMemo as useMemo22 } from "react";
14341
14325
  import { defaultRangeExtractor, useVirtualizer } from "@tanstack/react-virtual";
14342
14326
  function extractTimelineVirtualRowRange(range, pinnedRowIndexes) {
14343
14327
  const indexes = new Set(defaultRangeExtractor(range));
@@ -14400,14 +14384,14 @@ function useTimelineVirtualRows({
14400
14384
  initialRect: { width: viewport2.clientWidth, height: viewport2.clientHeight },
14401
14385
  initialOffset
14402
14386
  });
14403
- useEffect20(() => {
14387
+ useEffect19(() => {
14404
14388
  if (!enabled || !viewportReady) return;
14405
14389
  virtualizer.measure();
14406
14390
  scrollRef.current?.dispatchEvent(new Event("scroll"));
14407
14391
  }, [enabled, scrollRef, sessionEpoch, viewportReady, virtualizer]);
14408
14392
  const focusedRowIndex = focusedRowKey === void 0 ? -1 : rowGeometry.getRowIndex(focusedRowKey);
14409
14393
  const focusedRowHeight = focusedRowIndex < 0 ? 0 : rowGeometry.getRowHeight(focusedRowIndex);
14410
- useEffect20(() => {
14394
+ useEffect19(() => {
14411
14395
  if (enabled && viewportReady && focusedRowIndex >= 0) {
14412
14396
  virtualizer.resizeItem(focusedRowIndex, focusedRowHeight);
14413
14397
  }
@@ -15488,7 +15472,7 @@ function TimelinePlayheadLayer({
15488
15472
  }
15489
15473
 
15490
15474
  // src/player/components/TimelineLanes.tsx
15491
- import { Fragment as Fragment18, useId as useId4, useMemo as useMemo32, useRef as useRef42 } from "react";
15475
+ import { Fragment as Fragment18, useId as useId3, useMemo as useMemo32, useRef as useRef42 } from "react";
15492
15476
 
15493
15477
  // src/player/components/TimelineLaneClip.tsx
15494
15478
  import { memo as memo14 } from "react";
@@ -15499,7 +15483,7 @@ import { memo as memo13 } from "react";
15499
15483
  // src/player/components/TimelineClipFades.tsx
15500
15484
  import {
15501
15485
  createContext as createContext4,
15502
- useEffect as useEffect21,
15486
+ useEffect as useEffect20,
15503
15487
  useLayoutEffect as useLayoutEffect7,
15504
15488
  useMemo as useMemo25,
15505
15489
  useRef as useRef28,
@@ -15760,7 +15744,7 @@ function TimelineClipFades({
15760
15744
  setDraft({ edge, seconds });
15761
15745
  onSetElementAttributeLive?.(el, attrFor(edge), attrText(seconds));
15762
15746
  };
15763
- useEffect21(() => {
15747
+ useEffect20(() => {
15764
15748
  if (dragging === null) return;
15765
15749
  const cancelOnWindowEscape = (e) => {
15766
15750
  const g = gesture.current;
@@ -15982,7 +15966,7 @@ function FadeHandle({
15982
15966
  }
15983
15967
 
15984
15968
  // src/player/components/AudioWaveform.tsx
15985
- import { memo as memo10, useCallback as useCallback27, useContext as useContext7, useEffect as useEffect22, useMemo as useMemo26, useRef as useRef30, useState as useState19 } from "react";
15969
+ import { memo as memo10, useCallback as useCallback27, useContext as useContext7, useEffect as useEffect21, useMemo as useMemo26, useRef as useRef30, useState as useState19 } from "react";
15986
15970
  import { fadeGain } from "@hyperframes/core/audio-fade";
15987
15971
 
15988
15972
  // src/hooks/useThumbnailLease.ts
@@ -16720,7 +16704,7 @@ var nearScreenListeners = /* @__PURE__ */ new Map();
16720
16704
  var nearScreen = null;
16721
16705
  function useNearScreen(element) {
16722
16706
  const [near4, setNear] = useState19(() => typeof IntersectionObserver === "undefined");
16723
- useEffect22(() => {
16707
+ useEffect21(() => {
16724
16708
  if (!element || typeof IntersectionObserver === "undefined") return;
16725
16709
  nearScreen ??= new IntersectionObserver(
16726
16710
  (entries) => entries.forEach((entry2) => nearScreenListeners.get(entry2.target)?.(entry2.isIntersecting)),
@@ -16793,10 +16777,10 @@ var AudioWaveform = memo10(function AudioWaveform2({
16793
16777
  );
16794
16778
  }, [fades, from, muted, peaks, to, trimEndFraction, trimStartFraction]);
16795
16779
  const near4 = useNearScreen(root);
16796
- useEffect22(() => {
16780
+ useEffect21(() => {
16797
16781
  if (near4) draw();
16798
16782
  }, [draw, near4, strip.width, strip.height]);
16799
- useEffect22(() => {
16783
+ useEffect21(() => {
16800
16784
  const root2 = document.documentElement;
16801
16785
  const observer = new MutationObserver(draw);
16802
16786
  observer.observe(root2, {
@@ -16805,7 +16789,7 @@ var AudioWaveform = memo10(function AudioWaveform2({
16805
16789
  });
16806
16790
  return () => observer.disconnect();
16807
16791
  }, [draw]);
16808
- useEffect22(() => {
16792
+ useEffect21(() => {
16809
16793
  const clip = root?.closest(".timeline-clip");
16810
16794
  if (!(clip instanceof HTMLElement)) return;
16811
16795
  if (muted) clip.setAttribute("data-audio-muted", "true");
@@ -17138,7 +17122,7 @@ function readClipEffects(state) {
17138
17122
  }
17139
17123
 
17140
17124
  // src/player/components/useClipToolState.ts
17141
- import { useEffect as useEffect23, useState as useState20 } from "react";
17125
+ import { useEffect as useEffect22, useState as useState20 } from "react";
17142
17126
  import { HF_AUDIO_AUTOMATION_ATTR } from "@hyperframes/core/audio-automation";
17143
17127
  import { HF_AUDIO_CARVE_ATTR } from "@hyperframes/core/audio-carve";
17144
17128
  import { HF_AUDIO_FX_ATTR } from "@hyperframes/core/audio-fx";
@@ -17161,6 +17145,7 @@ function useOwnPreviewIframe() {
17161
17145
 
17162
17146
  // src/hooks/timelineEditingHelpers.ts
17163
17147
  import { isHtmlElement as isHtmlElement4 } from "@hyperframes/core/runtime/dom-realm";
17148
+ import { applyAuthoredTiming } from "@hyperframes/core/studio-preview-mark";
17164
17149
 
17165
17150
  // src/utils/sourcePatcher.ts
17166
17151
  import {
@@ -18856,7 +18841,7 @@ function patchIframeDomTiming(iframe, element, attrs, activeCompositionPath = nu
18856
18841
  try {
18857
18842
  const el = findTimelineElementInIframe(iframe, element, activeCompositionPath);
18858
18843
  if (!el) return;
18859
- for (const [name, value] of attrs) el.setAttribute(name, value);
18844
+ applyAuthoredTiming(el, attrs);
18860
18845
  } catch {
18861
18846
  }
18862
18847
  }
@@ -19147,7 +19132,7 @@ function useClipToolState(el) {
19147
19132
  const iframe = useLivePreviewIframe();
19148
19133
  const activeCompPath = useStudioShellContextOptional()?.activeCompPath ?? null;
19149
19134
  const [state, setState] = useState20(() => toolStateFromElement(el));
19150
- useEffect23(() => {
19135
+ useEffect22(() => {
19151
19136
  const node = findTimelineElementInIframe(iframe, el, activeCompPath);
19152
19137
  if (!node) {
19153
19138
  setState(toolStateFromElement(el));
@@ -19259,9 +19244,9 @@ import { createPortal } from "react-dom";
19259
19244
  import { formatSyncOffset } from "@hyperframes/core/media-link";
19260
19245
 
19261
19246
  // src/player/components/menuKeyboardNav.ts
19262
- import { useEffect as useEffect24 } from "react";
19247
+ import { useEffect as useEffect23 } from "react";
19263
19248
  function useMenuKeyboardNav(menuRef) {
19264
- useEffect24(() => {
19249
+ useEffect23(() => {
19265
19250
  const menu = menuRef.current;
19266
19251
  if (!menu) return;
19267
19252
  const previouslyFocused = document.activeElement;
@@ -19949,13 +19934,13 @@ function TimelineCompactDiamonds({
19949
19934
  }
19950
19935
 
19951
19936
  // src/player/components/TimelineAutomationLaneSlot.tsx
19952
- import { useEffect as useEffect26, useMemo as useMemo28 } from "react";
19937
+ import { useEffect as useEffect25, useMemo as useMemo28 } from "react";
19953
19938
  import { resolveAutomationRange as resolveAutomationRange3 } from "@hyperframes/core/audio-automation";
19954
19939
 
19955
19940
  // src/player/components/TimelineAutomationLane.tsx
19956
19941
  import {
19957
19942
  useCallback as useCallback33,
19958
- useEffect as useEffect25,
19943
+ useEffect as useEffect24,
19959
19944
  useMemo as useMemo27,
19960
19945
  useRef as useRef35,
19961
19946
  useState as useState27
@@ -21210,7 +21195,7 @@ function TimelineAutomationLane({
21210
21195
  () => draft ? { target, points: draft.points } : stored,
21211
21196
  [draft, target, stored]
21212
21197
  );
21213
- useEffect25(() => {
21198
+ useEffect24(() => {
21214
21199
  setDraft(null);
21215
21200
  }, [target]);
21216
21201
  const h = AUTOMATION_LANE_H;
@@ -21285,7 +21270,7 @@ function TimelineAutomationLane({
21285
21270
  editing
21286
21271
  } = gestures;
21287
21272
  const gestureLive = [dragIndex, curveIndex, segmentDragIndex, edgeDrag].some((g) => g !== null);
21288
- useEffect25(() => {
21273
+ useEffect24(() => {
21289
21274
  if (draft && draft.basedOn !== automation && !gestureLive) setDraft(null);
21290
21275
  }, [automation, draft, gestureLive]);
21291
21276
  const removeAt = useCallback33(
@@ -21535,7 +21520,7 @@ function ClipAutomationLanes({
21535
21520
  [beatTimes, element.start, element.duration]
21536
21521
  );
21537
21522
  const bound = lanes.bind(element, isSelected2);
21538
- useEffect26(() => {
21523
+ useEffect25(() => {
21539
21524
  const target = bound.selection?.target;
21540
21525
  if (target !== void 0 && !bound.lanes.some((lane) => lane.target === target)) {
21541
21526
  bound.onRangeClear();
@@ -21744,7 +21729,7 @@ function useAutomationLanes() {
21744
21729
  }
21745
21730
 
21746
21731
  // src/hooks/useAutomationSelectionKeyboard.ts
21747
- import { useEffect as useEffect27 } from "react";
21732
+ import { useEffect as useEffect26 } from "react";
21748
21733
 
21749
21734
  // src/player/components/automationClipboard.ts
21750
21735
  import {
@@ -22127,7 +22112,7 @@ function handleDelete(e, state, lanes, sel) {
22127
22112
  function useAutomationSelectionKeyboard({
22128
22113
  lanes
22129
22114
  }) {
22130
- useEffect27(() => {
22115
+ useEffect26(() => {
22131
22116
  const handler = (e) => {
22132
22117
  if (isTypingTarget(document.activeElement)) return;
22133
22118
  if (e.defaultPrevented) return;
@@ -22447,7 +22432,7 @@ function carverAgainst(doc, id) {
22447
22432
  }
22448
22433
 
22449
22434
  // src/player/components/TimelineFxButton.tsx
22450
- import { useEffect as useEffect30, useRef as useRef40, useState as useState28 } from "react";
22435
+ import { useEffect as useEffect29, useRef as useRef40, useState as useState28 } from "react";
22451
22436
  import { createPortal as createPortal3 } from "react-dom";
22452
22437
  import {
22453
22438
  enabledAudioFxNodes,
@@ -22455,7 +22440,7 @@ import {
22455
22440
  } from "@hyperframes/core/audio-fx";
22456
22441
 
22457
22442
  // src/components/editor/TimelineFxPopover.tsx
22458
- import { useEffect as useEffect29, useRef as useRef38 } from "react";
22443
+ import { useEffect as useEffect28, useRef as useRef38 } from "react";
22459
22444
  import { applyAudioFxPreset as applyAudioFxPreset2, getAudioFxPreset as getAudioFxPreset3 } from "@hyperframes/core/audio-fx-presets";
22460
22445
 
22461
22446
  // src/components/editor/propertyPanelFxPresetMenu.tsx
@@ -22535,7 +22520,7 @@ function FxPresetMenu({
22535
22520
  }
22536
22521
 
22537
22522
  // src/components/editor/useFxAudition.ts
22538
- import { useCallback as useCallback35, useEffect as useEffect28, useRef as useRef37 } from "react";
22523
+ import { useCallback as useCallback35, useEffect as useEffect27, useRef as useRef37 } from "react";
22539
22524
  function useFxAudition(chain, onChainPreview, onAuditionTransport) {
22540
22525
  const auditionBase = useRef37(null);
22541
22526
  const audition = useCallback35(
@@ -22562,7 +22547,7 @@ function useFxAudition(chain, onChainPreview, onAuditionTransport) {
22562
22547
  previewRef.current = onChainPreview;
22563
22548
  const transportRef = useRef37(onAuditionTransport);
22564
22549
  transportRef.current = onAuditionTransport;
22565
- useEffect28(
22550
+ useEffect27(
22566
22551
  () => () => {
22567
22552
  if (auditionBase.current) {
22568
22553
  transportRef.current?.(false);
@@ -22624,7 +22609,7 @@ function TimelineFxPopover({
22624
22609
  onChainPreview,
22625
22610
  onAuditionTransport
22626
22611
  );
22627
- useEffect29(() => {
22612
+ useEffect28(() => {
22628
22613
  const onPointerDown = (event) => {
22629
22614
  if (rootRef.current && !rootRef.current.contains(event.target)) onClose();
22630
22615
  };
@@ -22772,7 +22757,7 @@ function GroupNameDialog({
22772
22757
  }) {
22773
22758
  const [label, setLabel] = useState28(defaultLabel ?? "Voiceover");
22774
22759
  const inputRef = useRef40(null);
22775
- useEffect30(() => inputRef.current?.select(), []);
22760
+ useEffect29(() => inputRef.current?.select(), []);
22776
22761
  if (refusal2) {
22777
22762
  return /* @__PURE__ */ jsx49(
22778
22763
  "div",
@@ -23953,7 +23938,7 @@ function TimelineGroupHeader({
23953
23938
  import { sampleAutomationLane as sampleAutomationLane7 } from "@hyperframes/core/audio-automation";
23954
23939
 
23955
23940
  // src/hooks/useLivePlayheadTime.ts
23956
- import { useEffect as useEffect31, useRef as useRef41, useState as useState29 } from "react";
23941
+ import { useEffect as useEffect30, useRef as useRef41, useState as useState29 } from "react";
23957
23942
  var THROTTLE_MS = 33;
23958
23943
  function useLivePlayheadTime() {
23959
23944
  const storeTime = usePlayerStore((s) => s.currentTime);
@@ -23961,7 +23946,7 @@ function useLivePlayheadTime() {
23961
23946
  const liveRef = useRef41(storeTime);
23962
23947
  const [, forceRender] = useState29(0);
23963
23948
  if (!isPlaying) liveRef.current = storeTime;
23964
- useEffect31(() => {
23949
+ useEffect30(() => {
23965
23950
  if (!isPlaying) return;
23966
23951
  let timerId = 0;
23967
23952
  const unsubscribe = liveTime.subscribe((t2) => {
@@ -24465,7 +24450,7 @@ function TimelineLanes({
24465
24450
  onRazorSplit,
24466
24451
  onRazorSplitAll
24467
24452
  }) {
24468
- const lanesIdPrefix = `timeline-lanes${useId4().replaceAll(":", "")}`;
24453
+ const lanesIdPrefix = `timeline-lanes${useId3().replaceAll(":", "")}`;
24469
24454
  const expandedClipIds = usePlayerStore((s) => s.expandedClipIds);
24470
24455
  const { collapsedGroupIds, expandedLaneOwnerIds, toggleGroupExpanded, toggleLaneOwnerExpanded } = useTimelineGroupDisclosure();
24471
24456
  const automationLanes = useAutomationLanes();
@@ -25209,7 +25194,7 @@ var TimelineCanvas = memo17(function TimelineCanvas2() {
25209
25194
  });
25210
25195
 
25211
25196
  // src/player/components/AudioGainDialog.tsx
25212
- import { useEffect as useEffect32, useMemo as useMemo33, useState as useState30 } from "react";
25197
+ import { useEffect as useEffect31, useMemo as useMemo33, useState as useState30 } from "react";
25213
25198
  import { createPortal as createPortal4 } from "react-dom";
25214
25199
  import { audioGainToDb as audioGainToDb2 } from "@hyperframes/core/audio-gain";
25215
25200
 
@@ -25551,7 +25536,7 @@ var currentGainDb = (el) => {
25551
25536
  var dbText = (db) => `${db < 0 ? "\u2212" : ""}${Math.abs(db).toFixed(1)} dB`;
25552
25537
  function useSourcePeaks(elements, projectId) {
25553
25538
  const [peaks, setPeaks] = useState30(null);
25554
- useEffect32(() => {
25539
+ useEffect31(() => {
25555
25540
  if (!projectId) return;
25556
25541
  let live = true;
25557
25542
  void Promise.all(elements.map((el) => measureClipSourcePeak(el, projectId))).then((found) => {
@@ -25744,7 +25729,7 @@ function TimelineAudioGainOverlay() {
25744
25729
  }
25745
25730
 
25746
25731
  // src/player/components/TimelineOverlays.tsx
25747
- import { useEffect as useEffect34, useMemo as useMemo35 } from "react";
25732
+ import { useEffect as useEffect33, useMemo as useMemo35 } from "react";
25748
25733
 
25749
25734
  // src/player/components/EditModal.tsx
25750
25735
  import { useState as useState31, useCallback as useCallback36, useMemo as useMemo34, useRef as useRef43 } from "react";
@@ -26099,7 +26084,7 @@ import { memo as memo18, useLayoutEffect as useLayoutEffect9, useState as useSta
26099
26084
  import { createPortal as createPortal6 } from "react-dom";
26100
26085
 
26101
26086
  // src/player/components/clipMenuToolItems.tsx
26102
- import { useEffect as useEffect33, useRef as useRef44, useState as useState33 } from "react";
26087
+ import { useEffect as useEffect32, useRef as useRef44, useState as useState33 } from "react";
26103
26088
  import { HF_AUDIO_FX_ATTR as HF_AUDIO_FX_ATTR4 } from "@hyperframes/core/audio-fx";
26104
26089
  import { HF_COLOR_GRADING_ATTR as HF_COLOR_GRADING_ATTR2 } from "@hyperframes/core/color-grading";
26105
26090
  import { Fragment as Fragment19, jsx as jsx66, jsxs as jsxs43 } from "react/jsx-runtime";
@@ -26136,7 +26121,7 @@ function useHoverPreview(preview2) {
26136
26121
  previewRef.current?.apply(id);
26137
26122
  }, HOVER_PREVIEW_DELAY_MS);
26138
26123
  };
26139
- useEffect33(() => end, []);
26124
+ useEffect32(() => end, []);
26140
26125
  return { start, end, settle };
26141
26126
  }
26142
26127
  function focusSibling(menu, step) {
@@ -27725,7 +27710,7 @@ function TimelineKeyframeMenuOverlay() {
27725
27710
  selectedElementId,
27726
27711
  elements: overlay.elements
27727
27712
  }) : null;
27728
- useEffect34(() => {
27713
+ useEffect33(() => {
27729
27714
  if (kfContextMenu && !element) setKfContextMenu(null);
27730
27715
  }, [element, kfContextMenu, setKfContextMenu]);
27731
27716
  if (!kfContextMenu || !element) return null;
@@ -27793,7 +27778,7 @@ function TimelineClipMenuOverlay() {
27793
27778
  selectedElementId,
27794
27779
  elements: overlay.elements
27795
27780
  }) : null;
27796
- useEffect34(() => {
27781
+ useEffect33(() => {
27797
27782
  if (clipContextMenu && !element) setClipContextMenu(null);
27798
27783
  }, [element, clipContextMenu, setClipContextMenu]);
27799
27784
  const { clipMenuItems } = overlay;
@@ -28614,7 +28599,7 @@ var CompositionThumbnail = memo22(function CompositionThumbnail2({
28614
28599
  });
28615
28600
 
28616
28601
  // src/player/hooks/useTimelinePlayer.ts
28617
- import { useRef as useRef48, useCallback as useCallback41, useEffect as useEffect35 } from "react";
28602
+ import { useRef as useRef48, useCallback as useCallback41, useEffect as useEffect34 } from "react";
28618
28603
 
28619
28604
  // src/player/hooks/usePlaybackKeyboard.ts
28620
28605
  import { useRef as useRef45, useCallback as useCallback37 } from "react";
@@ -32517,13 +32502,13 @@ function useTimelinePlayer({
32517
32502
  shuttleSpeedIndexRef
32518
32503
  ]
32519
32504
  );
32520
- useEffect35(
32505
+ useEffect34(
32521
32506
  () => usePlayerStore.subscribe((state, prev) => {
32522
32507
  if (state.playLocked && !prev.playLocked && state.isPlaying) pause();
32523
32508
  }),
32524
32509
  [pause]
32525
32510
  );
32526
- useEffect35(() => {
32511
+ useEffect34(() => {
32527
32512
  return usePlayerStore.subscribe((state, prev) => {
32528
32513
  if (state.requestedSeekTime !== null && state.requestedSeekTime !== prev.requestedSeekTime) {
32529
32514
  seek(state.requestedSeekTime);
@@ -32540,7 +32525,7 @@ function useTimelinePlayer({
32540
32525
  }
32541
32526
  });
32542
32527
  }, [seek, play, pause]);
32543
- useEffect35(() => subscribePreviewFrame(getAdapter), [getAdapter]);
32528
+ useEffect34(() => subscribePreviewFrame(getAdapter), [getAdapter]);
32544
32529
  const { playbackKeyDownRef, playbackKeyUpRef, attachIframeShortcutListeners, togglePlay } = usePlaybackKeyboard({
32545
32530
  iframeRef,
32546
32531
  shuttleDirectionRef,
@@ -32692,7 +32677,7 @@ function useTimelinePlayer({
32692
32677
  cancelPendingLoad();
32693
32678
  usePlayerStore.getState().reset();
32694
32679
  }, [stopRAFLoop, stopReverseLoop, cancelPendingLoad]);
32695
- useEffect35(() => {
32680
+ useEffect34(() => {
32696
32681
  return usePlayerStore.subscribe((state, prev) => {
32697
32682
  const playbackRateChanged = state.playbackRate !== prev.playbackRate;
32698
32683
  const audioMutedChanged = state.audioMuted !== prev.audioMuted;
@@ -32727,10 +32712,10 @@ function useTimelinePlayer({
32727
32712
  import { useCallback as useCallback44, useMemo as useMemo38 } from "react";
32728
32713
 
32729
32714
  // src/components/nle/NLEContext.tsx
32730
- import { useContext as useContext8, useState as useState38, useCallback as useCallback43, useRef as useRef50, useEffect as useEffect37 } from "react";
32715
+ import { useContext as useContext8, useState as useState38, useCallback as useCallback43, useRef as useRef50, useEffect as useEffect36 } from "react";
32731
32716
 
32732
32717
  // src/components/nle/useCompositionStack.ts
32733
- import { useState as useState37, useCallback as useCallback42, useRef as useRef49, useEffect as useEffect36 } from "react";
32718
+ import { useState as useState37, useCallback as useCallback42, useRef as useRef49, useEffect as useEffect35 } from "react";
32734
32719
  function useCompositionStack({
32735
32720
  projectId,
32736
32721
  activeCompositionPath,
@@ -32801,7 +32786,7 @@ function useCompositionStack({
32801
32786
  // eslint-disable-next-line react-hooks/exhaustive-deps
32802
32787
  [projectId]
32803
32788
  );
32804
- useEffect36(() => {
32789
+ useEffect35(() => {
32805
32790
  const master = {
32806
32791
  id: "master",
32807
32792
  label: "Master",
@@ -32889,13 +32874,13 @@ function NLEProvider({
32889
32874
  onShadowPromoted: () => shadowPromotedRef.current(),
32890
32875
  onPreviewReloadFailed
32891
32876
  });
32892
- useEffect37(() => {
32877
+ useEffect36(() => {
32893
32878
  usePlayerStore.getState().beginTimelineSession(projectId);
32894
32879
  useAssetPreviewStore.getState().clearPreviewAsset();
32895
32880
  }, [projectId]);
32896
32881
  const [previewCompositionSize, setPreviewCompositionSize] = useState38(null);
32897
32882
  const prevRefreshKeyRef = useRef50(refreshKey);
32898
- useEffect37(() => {
32883
+ useEffect36(() => {
32899
32884
  try {
32900
32885
  if (refreshKey === prevRefreshKeyRef.current) return;
32901
32886
  prevRefreshKeyRef.current = refreshKey;
@@ -32957,7 +32942,7 @@ function NLEProvider({
32957
32942
  compIdToSrcRef.current = compIdToSrc;
32958
32943
  const onCompIdToSrcChangeRef = useRef50(onCompIdToSrcChange);
32959
32944
  onCompIdToSrcChangeRef.current = onCompIdToSrcChange;
32960
- useEffect37(() => {
32945
+ useEffect36(() => {
32961
32946
  const controller = new AbortController();
32962
32947
  let current = true;
32963
32948
  const emptyMap = /* @__PURE__ */ new Map();
@@ -32992,7 +32977,7 @@ function NLEProvider({
32992
32977
  controller.abort();
32993
32978
  };
32994
32979
  }, [projectId, setCompIdToSrc]);
32995
- useEffect37(() => {
32980
+ useEffect36(() => {
32996
32981
  if (compIdToSrc.size === 0) return;
32997
32982
  const patchElements2 = (elements) => {
32998
32983
  const map = compIdToSrcRef.current;
@@ -33031,12 +33016,12 @@ function NLEProvider({
33031
33016
  }, []);
33032
33017
  const timelineDisabled = shouldDisableTimelineWhileCompositionLoading(compositionLoading);
33033
33018
  const timelineSessionEpoch = usePlayerStore((state) => state.timelineSessionEpoch);
33034
- useEffect37(() => {
33019
+ useEffect36(() => {
33035
33020
  onCompositionLoadingChange?.(compositionLoading);
33036
33021
  }, [compositionLoading, onCompositionLoadingChange]);
33037
33022
  const onIframeRefStable = useRef50(onIframeRef);
33038
33023
  onIframeRefStable.current = onIframeRef;
33039
- useEffect37(() => {
33024
+ useEffect36(() => {
33040
33025
  onIframeRefStable.current?.(iframeRef.current);
33041
33026
  }, [compositionStack.length, refreshKey, iframeRef]);
33042
33027
  const value = {
@@ -33145,7 +33130,7 @@ function readPreviewCompositionSize(iframe) {
33145
33130
  import {
33146
33131
  memo as memo23,
33147
33132
  useCallback as useCallback48,
33148
- useEffect as useEffect39,
33133
+ useEffect as useEffect38,
33149
33134
  useLayoutEffect as useLayoutEffect10,
33150
33135
  useRef as useRef54,
33151
33136
  useState as useState40
@@ -33283,7 +33268,7 @@ var usePreviewGuidesStore = create8((set, get) => {
33283
33268
  });
33284
33269
 
33285
33270
  // src/components/nle/PreviewZoomOverlay.tsx
33286
- import { useCallback as useCallback45, useEffect as useEffect38, useRef as useRef51 } from "react";
33271
+ import { useCallback as useCallback45, useEffect as useEffect37, useRef as useRef51 } from "react";
33287
33272
  import { Fragment as Fragment24, jsx as jsx80, jsxs as jsxs55 } from "react/jsx-runtime";
33288
33273
  var NAVIGATOR_PX = 112;
33289
33274
  function zoomChipLabel(zoomPercent) {
@@ -33323,7 +33308,7 @@ function usePreviewNavigator(viewportRef, stageSize, zoomRef) {
33323
33308
  },
33324
33309
  [draw, zoomRef]
33325
33310
  );
33326
- useEffect38(() => draw(zoomRef.current), [stageSize, draw, zoomRef]);
33311
+ useEffect37(() => draw(zoomRef.current), [stageSize, draw, zoomRef]);
33327
33312
  return { draw, setRegion };
33328
33313
  }
33329
33314
  function PreviewZoomOverlay({
@@ -33577,11 +33562,11 @@ var NLEPreview = memo23(function NLEPreview2({
33577
33562
  const viewportRef = useRef54(null);
33578
33563
  const stageRef = useRef54(null);
33579
33564
  const previewIframeRef = useRef54(null);
33580
- useEffect39(() => {
33565
+ useEffect38(() => {
33581
33566
  onStageRef?.(stageRef);
33582
33567
  }, [onStageRef]);
33583
33568
  const previousActiveKeyRef = useRef54(activeKey);
33584
- useEffect39(() => {
33569
+ useEffect38(() => {
33585
33570
  if (previousActiveKeyRef.current === activeKey) return;
33586
33571
  previousActiveKeyRef.current = activeKey;
33587
33572
  resetPreviewSlots();
@@ -33597,19 +33582,19 @@ var NLEPreview = memo23(function NLEPreview2({
33597
33582
  const hintHeight = compositionSizeHint?.height;
33598
33583
  const zoomRef = useRef54(DEFAULT_PREVIEW_ZOOM);
33599
33584
  const [settledZoom, setSettledZoom] = useState40(DEFAULT_PREVIEW_ZOOM);
33600
- useEffect39(() => postFrameDisplayScale(previewIframeRef.current), [settledZoom]);
33585
+ useEffect38(() => postFrameDisplayScale(previewIframeRef.current), [settledZoom]);
33601
33586
  const hudRef = useRef54(null);
33602
33587
  const hudTimerRef = useRef54(null);
33603
33588
  const settleTimerRef = useRef54(null);
33604
33589
  const zoomingRef = useRef54(false);
33605
33590
  const dragRef = useRef54(null);
33606
- useEffect39(() => {
33591
+ useEffect38(() => {
33607
33592
  return () => {
33608
33593
  if (settleTimerRef.current) clearTimeout(settleTimerRef.current);
33609
33594
  if (hudTimerRef.current) clearTimeout(hudTimerRef.current);
33610
33595
  };
33611
33596
  }, []);
33612
- useEffect39(() => {
33597
+ useEffect38(() => {
33613
33598
  const viewport2 = viewportRef.current;
33614
33599
  if (!viewport2) return;
33615
33600
  const updateStageSize = () => {
@@ -33638,7 +33623,7 @@ var NLEPreview = memo23(function NLEPreview2({
33638
33623
  (prev) => prev?.width === next?.width && prev?.height === next?.height ? prev : next
33639
33624
  );
33640
33625
  }, []);
33641
- useEffect39(() => {
33626
+ useEffect38(() => {
33642
33627
  onCompositionSizeChangeRef.current?.(compositionSize);
33643
33628
  }, [compositionSize]);
33644
33629
  const setPreviewIframeRef = useCallback48(
@@ -33744,7 +33729,7 @@ var NLEPreview = memo23(function NLEPreview2({
33744
33729
  writeTransform3(zoomRef.current);
33745
33730
  }
33746
33731
  }, [writeTransform3]);
33747
- useEffect39(() => {
33732
+ useEffect38(() => {
33748
33733
  const live = previewSlots.find((slot) => slot.role === "live");
33749
33734
  if (!live || live.gen === liveGenRef.current) return;
33750
33735
  const isPromotion = liveGenRef.current !== null;
@@ -33754,7 +33739,7 @@ var NLEPreview = memo23(function NLEPreview2({
33754
33739
  updateCompositionSizeFromPreview();
33755
33740
  applyInitialZoom();
33756
33741
  }, [previewSlots, iframeRef, updateCompositionSizeFromPreview, applyInitialZoom]);
33757
- useEffect39(() => {
33742
+ useEffect38(() => {
33758
33743
  const viewport2 = viewportRef.current;
33759
33744
  if (!viewport2) return;
33760
33745
  const handleWheel = (event) => {
@@ -33800,7 +33785,7 @@ var NLEPreview = memo23(function NLEPreview2({
33800
33785
  document.addEventListener("wheel", handleWheel, { passive: false, capture: true });
33801
33786
  return () => document.removeEventListener("wheel", handleWheel, { capture: true });
33802
33787
  }, [applyZoom, applyPan]);
33803
- useEffect39(() => {
33788
+ useEffect38(() => {
33804
33789
  const isInsideViewport = (clientX, clientY) => {
33805
33790
  const viewport2 = viewportRef.current;
33806
33791
  if (!viewport2) return null;
@@ -34160,7 +34145,7 @@ function usePreviewBlockDrop({
34160
34145
  }
34161
34146
 
34162
34147
  // src/components/nle/AssetPreviewOverlay.tsx
34163
- import { useEffect as useEffect40, useCallback as useCallback50 } from "react";
34148
+ import { useEffect as useEffect39, useCallback as useCallback50 } from "react";
34164
34149
 
34165
34150
  // src/utils/assetPreviewDismiss.ts
34166
34151
  var TIME_EPSILON_S = 1e-6;
@@ -34239,12 +34224,12 @@ function AssetPreviewOverlay() {
34239
34224
  },
34240
34225
  [clearPreviewAsset]
34241
34226
  );
34242
- useEffect40(() => {
34227
+ useEffect39(() => {
34243
34228
  if (!previewAsset) return;
34244
34229
  window.addEventListener("keydown", handleKeyDown);
34245
34230
  return () => window.removeEventListener("keydown", handleKeyDown);
34246
34231
  }, [previewAsset, handleKeyDown]);
34247
- useEffect40(() => {
34232
+ useEffect39(() => {
34248
34233
  if (!previewAsset) return;
34249
34234
  const opened = usePlayerStore.getState();
34250
34235
  const openedTime = opened.currentTime;
@@ -34505,11 +34490,11 @@ function safeBoxInsetPercent(boxPercent) {
34505
34490
  import { createContext as createContext6, useContext as useContext10, useRef as useRef57, useState as useState43 } from "react";
34506
34491
 
34507
34492
  // src/components/editor/usePreviewCompositionRect.ts
34508
- import { useEffect as useEffect41, useRef as useRef56 } from "react";
34493
+ import { useEffect as useEffect40, useRef as useRef56 } from "react";
34509
34494
  function usePreviewCompositionRect(overlayRef, iframe) {
34510
34495
  const iframeRef = useRef56(iframe);
34511
34496
  iframeRef.current = iframe;
34512
- useEffect41(() => {
34497
+ useEffect40(() => {
34513
34498
  requestOverlayFrames();
34514
34499
  }, [iframe]);
34515
34500
  return useDomEditCompositionRect({ iframeRef, overlayRef });
@@ -34802,7 +34787,7 @@ function PreviewPane({
34802
34787
  import {
34803
34788
  memo as memo25,
34804
34789
  useCallback as useCallback52,
34805
- useEffect as useEffect42,
34790
+ useEffect as useEffect41,
34806
34791
  useMemo as useMemo41,
34807
34792
  useRef as useRef60
34808
34793
  } from "react";
@@ -34983,7 +34968,7 @@ function useMeterLoop(strips2, bars, iframeRef, clip) {
34983
34968
  const previewIframeRef = iframeRef ?? shell?.previewIframeRef;
34984
34969
  const stripsRef = useRef60(strips2);
34985
34970
  stripsRef.current = strips2;
34986
- useEffect42(() => {
34971
+ useEffect41(() => {
34987
34972
  let raf = 0;
34988
34973
  let active = null;
34989
34974
  let last = performance.now();
@@ -35170,7 +35155,7 @@ function MeterStrip({
35170
35155
  useRef60(null),
35171
35156
  useRef60(null)
35172
35157
  ];
35173
- useEffect42(() => {
35158
+ useEffect41(() => {
35174
35159
  register(strip.id, [
35175
35160
  { mask: refs[0].current, peak: refs[1].current },
35176
35161
  { mask: refs[2].current, peak: refs[3].current }
@@ -35361,7 +35346,7 @@ function TimelinePane({
35361
35346
  import { useCallback as useCallback66 } from "react";
35362
35347
 
35363
35348
  // src/captions/components/CaptionOverlay.tsx
35364
- import { memo as memo26, useEffect as useEffect43, useState as useState44, useCallback as useCallback53, useRef as useRef61 } from "react";
35349
+ import { memo as memo26, useEffect as useEffect42, useState as useState44, useCallback as useCallback53, useRef as useRef61 } from "react";
35365
35350
 
35366
35351
  // src/captions/keyboard.ts
35367
35352
  var CAPTION_NUDGE_KEYS = /* @__PURE__ */ new Set(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"]);
@@ -35592,7 +35577,7 @@ var CaptionOverlay = memo26(function CaptionOverlay2({ iframeRef }) {
35592
35577
  modelRef.current = model;
35593
35578
  const cancelDragRef = useRef61(null);
35594
35579
  const interactionRef = useRef61(null);
35595
- useEffect43(() => {
35580
+ useEffect42(() => {
35596
35581
  if (!isEditMode) return;
35597
35582
  const unregisterIframe = registerCaptionIframe(iframeRef);
35598
35583
  let prevBoxes = [];
@@ -35991,7 +35976,7 @@ var CaptionOverlay = memo26(function CaptionOverlay2({ iframeRef }) {
35991
35976
  });
35992
35977
 
35993
35978
  // src/components/editor/DomEditOverlay.tsx
35994
- import { memo as memo29, useEffect as useEffect55, useMemo as useMemo42, useRef as useRef71 } from "react";
35979
+ import { memo as memo29, useEffect as useEffect54, useMemo as useMemo42, useRef as useRef71 } from "react";
35995
35980
 
35996
35981
  // src/utils/previewFeatureUsage.ts
35997
35982
  function trackPreviewFeatureUsed(feature, method) {
@@ -36006,7 +35991,7 @@ function trackPreviewEditResult(feature, method, result) {
36006
35991
  }
36007
35992
 
36008
35993
  // src/components/editor/marqueeCommit.ts
36009
- import { useCallback as useCallback54, useEffect as useEffect44, useRef as useRef62, useState as useState45 } from "react";
35994
+ import { useCallback as useCallback54, useEffect as useEffect43, useRef as useRef62, useState as useState45 } from "react";
36010
35995
 
36011
35996
  // src/utils/studioPreviewHelpers.ts
36012
35997
  var FULL_BLEED_RATIO = 0.95;
@@ -37048,7 +37033,7 @@ function useMarqueeGestures(deps) {
37048
37033
  releaseCapture(marqueeRef.current);
37049
37034
  reset();
37050
37035
  }, [reset]);
37051
- useEffect44(() => {
37036
+ useEffect43(() => {
37052
37037
  const cancelBandBeforeHostEscape = (e) => {
37053
37038
  if (e.key !== "Escape" || !marqueeRef.current) return;
37054
37039
  e.preventDefault();
@@ -37169,13 +37154,13 @@ function MarqueeOverlay({ candidateRects, marqueeRect }) {
37169
37154
  }
37170
37155
 
37171
37156
  // src/components/editor/useZOrderCrossedFlash.tsx
37172
- import { useCallback as useCallback55, useEffect as useEffect45, useRef as useRef63, useState as useState46 } from "react";
37157
+ import { useCallback as useCallback55, useEffect as useEffect44, useRef as useRef63, useState as useState46 } from "react";
37173
37158
  import { jsx as jsx93 } from "react/jsx-runtime";
37174
37159
  var Z_ORDER_CROSSED_FLASH_MS = 600;
37175
37160
  function useZOrderCrossedFlash({ overlayRef, iframeRef }) {
37176
37161
  const [zOrderFlashRect, setZOrderFlashRect] = useState46(null);
37177
37162
  const timeoutRef = useRef63(null);
37178
- useEffect45(
37163
+ useEffect44(
37179
37164
  () => () => {
37180
37165
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
37181
37166
  },
@@ -37213,7 +37198,7 @@ function ZOrderCrossedFlash({ rect }) {
37213
37198
  }
37214
37199
 
37215
37200
  // src/components/editor/useCanvasContextMenuState.ts
37216
- import { useCallback as useCallback56, useEffect as useEffect46, useState as useState47 } from "react";
37201
+ import { useCallback as useCallback56, useEffect as useEffect45, useState as useState47 } from "react";
37217
37202
  function useCanvasContextMenuState({
37218
37203
  selection,
37219
37204
  selectionRef,
@@ -37223,7 +37208,7 @@ function useCanvasContextMenuState({
37223
37208
  }) {
37224
37209
  const [contextMenu, setContextMenu] = useState47(null);
37225
37210
  const closeContextMenu = useCallback56(() => setContextMenu(null), []);
37226
- useEffect46(() => {
37211
+ useEffect45(() => {
37227
37212
  if (!contextMenu) return;
37228
37213
  if (!selection || selection.element !== contextMenu.sel.element) {
37229
37214
  setContextMenu(null);
@@ -40474,7 +40459,7 @@ function createDomEditOverlayGestureHandlers(opts) {
40474
40459
  }
40475
40460
 
40476
40461
  // src/components/editor/useDomEditNudge.ts
40477
- import { useCallback as useCallback57, useEffect as useEffect47, useRef as useRef65 } from "react";
40462
+ import { useCallback as useCallback57, useEffect as useEffect46, useRef as useRef65 } from "react";
40478
40463
 
40479
40464
  // src/components/editor/domEditNudge.ts
40480
40465
  var CANVAS_NUDGE_KEYS = /* @__PURE__ */ new Set(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"]);
@@ -40562,7 +40547,7 @@ function useDomEditNudge(params) {
40562
40547
  };
40563
40548
  const commitSessionRef = useRef65(commitSession);
40564
40549
  commitSessionRef.current = commitSession;
40565
- useEffect47(() => {
40550
+ useEffect46(() => {
40566
40551
  if (params.allowCanvasMovement || !sessionRef.current) return;
40567
40552
  const session = sessionRef.current;
40568
40553
  sessionRef.current = null;
@@ -40623,8 +40608,8 @@ function useDomEditNudge(params) {
40623
40608
  });
40624
40609
  const selectionKey = selectionIdentityKey(params.selection);
40625
40610
  const groupSelectionsKey = groupSelectionsIdentityKey(params.groupSelections);
40626
- useEffect47(() => () => void commitSessionRef.current(), [selectionKey, groupSelectionsKey]);
40627
- useEffect47(() => {
40611
+ useEffect46(() => () => void commitSessionRef.current(), [selectionKey, groupSelectionsKey]);
40612
+ useEffect46(() => {
40628
40613
  const targets = params.groupSelections.length > 1 ? params.groupSelections : params.selection ? [params.selection] : [];
40629
40614
  if (!params.allowCanvasMovement || !canCanvasNudgeTargets(targets)) return;
40630
40615
  return acquireCanvasNudgeKeys();
@@ -40774,7 +40759,7 @@ var SnapGuideOverlay = memo27(function SnapGuideOverlay2({
40774
40759
  });
40775
40760
 
40776
40761
  // src/components/editor/DomEditCropHandles.tsx
40777
- import { useEffect as useEffect49, useRef as useRef67, useState as useState49 } from "react";
40762
+ import { useEffect as useEffect48, useRef as useRef67, useState as useState49 } from "react";
40778
40763
 
40779
40764
  // src/components/editor/cropResize.ts
40780
40765
  var boxOf = (element) => ({
@@ -40862,7 +40847,7 @@ async function writeSizeWithCrop(selection, properties, mutation, commit2, write
40862
40847
  }
40863
40848
 
40864
40849
  // src/components/editor/CropPresetBar.tsx
40865
- import { useEffect as useEffect48 } from "react";
40850
+ import { useEffect as useEffect47 } from "react";
40866
40851
 
40867
40852
  // src/components/editor/cropPresets.ts
40868
40853
  var CROP_ASPECT_PRESETS = [
@@ -40893,7 +40878,7 @@ function CropPresetBar({
40893
40878
  onApply,
40894
40879
  onDone
40895
40880
  }) {
40896
- useEffect48(() => {
40881
+ useEffect47(() => {
40897
40882
  const onKeyDown = (event) => {
40898
40883
  if (event.key === "Escape") onDone();
40899
40884
  };
@@ -41001,7 +40986,7 @@ function DomEditCropHandles({
41001
40986
  const committed = readCropFollowingResize(selection.element) ?? NO_CROP;
41002
40987
  const insets = dragging ? state.insets : committed;
41003
40988
  const hasCrop2 = hasCropInsets(insets);
41004
- useEffect49(() => {
40989
+ useEffect48(() => {
41005
40990
  const el = selection.element;
41006
40991
  if (readElementCropInsets(el) === null) return;
41007
40992
  liftElementCrop(el);
@@ -41685,10 +41670,10 @@ var CanvasContextMenu = memo28(function CanvasContextMenu2({
41685
41670
  });
41686
41671
 
41687
41672
  // src/components/editor/useInlineTextEditing.tsx
41688
- import { useEffect as useEffect53, useRef as useRef69 } from "react";
41673
+ import { useEffect as useEffect52, useRef as useRef69 } from "react";
41689
41674
 
41690
41675
  // src/components/editor/InlineTextCaret.tsx
41691
- import { useEffect as useEffect50, useState as useState50 } from "react";
41676
+ import { useEffect as useEffect49, useState as useState50 } from "react";
41692
41677
  import { createPortal as createPortal9 } from "react-dom";
41693
41678
  import { jsx as jsx101 } from "react/jsx-runtime";
41694
41679
  var CARET_PX = 2;
@@ -41698,7 +41683,7 @@ function InlineTextCaret({
41698
41683
  }) {
41699
41684
  const [placement, setPlacement] = useState50(null);
41700
41685
  const element = session?.element ?? null;
41701
- useEffect50(() => {
41686
+ useEffect49(() => {
41702
41687
  if (!element || !iframe) {
41703
41688
  setPlacement(null);
41704
41689
  return;
@@ -41849,7 +41834,7 @@ function neighbours({ startContainer: at, startOffset: offset }) {
41849
41834
  }
41850
41835
 
41851
41836
  // src/components/editor/InlineTextToolbar.tsx
41852
- import { useCallback as useCallback58, useEffect as useEffect51, useState as useState51 } from "react";
41837
+ import { useCallback as useCallback58, useEffect as useEffect50, useState as useState51 } from "react";
41853
41838
  import { createPortal as createPortal10 } from "react-dom";
41854
41839
 
41855
41840
  // src/components/editor/inlineTextStyleRange.ts
@@ -42239,7 +42224,7 @@ function InlineTextToolbar({
42239
42224
  const refresh2 = useCallback58(() => {
42240
42225
  setPlacement(session && iframe ? placeOverSelection(session.element, iframe) : null);
42241
42226
  }, [session, iframe]);
42242
- useEffect51(() => {
42227
+ useEffect50(() => {
42243
42228
  const doc = session?.element.ownerDocument;
42244
42229
  if (!doc) {
42245
42230
  setPlacement(null);
@@ -42417,7 +42402,7 @@ function isBold(weight) {
42417
42402
  }
42418
42403
 
42419
42404
  // src/hooks/useInlineTextEdit.ts
42420
- import { useCallback as useCallback59, useEffect as useEffect52, useRef as useRef68, useState as useState52 } from "react";
42405
+ import { useCallback as useCallback59, useEffect as useEffect51, useRef as useRef68, useState as useState52 } from "react";
42421
42406
  import { sanitizeRichTextChildren } from "@hyperframes/core/rich-text-sanitize";
42422
42407
  var EDITABLE = "true";
42423
42408
  var EDITING_OUTLINE = "2px solid #3CE6AC";
@@ -42503,10 +42488,10 @@ function useInlineTextEdit({
42503
42488
  if (open.element.isConnected) open.element.innerHTML = open.original;
42504
42489
  teardown();
42505
42490
  }, [teardown]);
42506
- useEffect52(() => {
42491
+ useEffect51(() => {
42507
42492
  if (readOnly && openRef.current) cancel();
42508
42493
  }, [cancel, readOnly]);
42509
- useEffect52(() => {
42494
+ useEffect51(() => {
42510
42495
  const element = session?.element;
42511
42496
  if (!element) return;
42512
42497
  const onKeyDown = (event) => {
@@ -42548,7 +42533,7 @@ function useInlineTextEdit({
42548
42533
  }, [session, commit2]);
42549
42534
  const commitRef = useRef68(commit2);
42550
42535
  commitRef.current = commit2;
42551
- useEffect52(() => () => commitRef.current(), []);
42536
+ useEffect51(() => () => commitRef.current(), []);
42552
42537
  return { session, start, commit: commit2, cancel };
42553
42538
  }
42554
42539
  function placeCaret(element, at) {
@@ -42665,7 +42650,7 @@ function useInlineTextEditing(selectionRef, { enterFromWindow = false } = {}) {
42665
42650
  };
42666
42651
  const handleKeyDownRef = useRef69(handleKeyDown);
42667
42652
  handleKeyDownRef.current = handleKeyDown;
42668
- useEffect53(() => {
42653
+ useEffect52(() => {
42669
42654
  if (!enterFromWindow) return;
42670
42655
  const onKeyDown = (event) => {
42671
42656
  const { body, documentElement } = window.document;
@@ -42709,7 +42694,7 @@ function useInlineTextEditing(selectionRef, { enterFromWindow = false } = {}) {
42709
42694
  }
42710
42695
 
42711
42696
  // src/components/editor/useOffCanvasIndicators.ts
42712
- import { useEffect as useEffect54, useRef as useRef70, useState as useState53 } from "react";
42697
+ import { useEffect as useEffect53, useRef as useRef70, useState as useState53 } from "react";
42713
42698
 
42714
42699
  // src/components/editor/offCanvasIndicatorGeometry.ts
42715
42700
  function rounded(value) {
@@ -42885,7 +42870,7 @@ function useOffCanvasIndicators({
42885
42870
  setRects: setOffCanvasRects
42886
42871
  })
42887
42872
  );
42888
- useEffect54(() => {
42873
+ useEffect53(() => {
42889
42874
  offCanvasDirtyRef.current = true;
42890
42875
  }, [activeCompositionPath]);
42891
42876
  return { offCanvasRects, offCanvasElementsRef };
@@ -42953,7 +42938,7 @@ var DomEditOverlay = memo29(function DomEditOverlay2({
42953
42938
  const inlineText = useInlineTextEditing(selectionRef, { enterFromWindow: hostInput });
42954
42939
  const onTextEditingChangeRef = useRef71(onTextEditingChange);
42955
42940
  onTextEditingChangeRef.current = onTextEditingChange;
42956
- useEffect55(() => {
42941
+ useEffect54(() => {
42957
42942
  if (!inlineText.editing) return;
42958
42943
  onTextEditingChangeRef.current?.(true);
42959
42944
  return () => onTextEditingChangeRef.current?.(false);
@@ -43045,7 +43030,7 @@ var DomEditOverlay = memo29(function DomEditOverlay2({
43045
43030
  onCanvasMouseDown,
43046
43031
  snapGuidesRef
43047
43032
  });
43048
- useEffect55(() => {
43033
+ useEffect54(() => {
43049
43034
  if (readOnly) gestures.clearPointerState(selectionRef, true);
43050
43035
  }, [gestures, readOnly, selectionRef]);
43051
43036
  const cancelGestureRef = useRef71((_dropQueued) => {
@@ -43289,7 +43274,7 @@ import { useCallback as useCallback63, useMemo as useMemo43 } from "react";
43289
43274
  import { useCallback as useCallback61 } from "react";
43290
43275
 
43291
43276
  // src/components/editor/useLayerRevealOverride.ts
43292
- import { useCallback as useCallback60, useEffect as useEffect56, useRef as useRef72 } from "react";
43277
+ import { useCallback as useCallback60, useEffect as useEffect55, useRef as useRef72 } from "react";
43293
43278
  var LAYER_REVEAL_LIFT_Z = "2147483000";
43294
43279
  var LAYER_REVEAL_PENDING_COMMIT_ATTR = "data-hf-studio-reveal-pending-commit";
43295
43280
  var revealCommitSequence = 0;
@@ -43518,13 +43503,13 @@ function useLayerRevealOverride({
43518
43503
  },
43519
43504
  [cancelScheduledReveal, reveal2]
43520
43505
  );
43521
- useEffect56(() => {
43506
+ useEffect55(() => {
43522
43507
  const pending2 = pendingRevealRef.current;
43523
43508
  if (isPlaying || pending2 && pending2.element !== selectedElement) cancelScheduledReveal();
43524
43509
  const base2 = stateRef.current?.base;
43525
43510
  if (isPlaying || base2 && selectedElement !== base2) restoreReveal();
43526
43511
  }, [cancelScheduledReveal, isPlaying, restoreReveal, selectedElement]);
43527
- useEffect56(
43512
+ useEffect55(
43528
43513
  () => () => {
43529
43514
  cancelScheduledReveal();
43530
43515
  restoreReveal();
@@ -45274,7 +45259,7 @@ function ConnectedDomEditOverlay({
45274
45259
 
45275
45260
  // src/components/editor/TopologyLens.tsx
45276
45261
  import {
45277
- useEffect as useEffect57,
45262
+ useEffect as useEffect56,
45278
45263
  useLayoutEffect as useLayoutEffect11,
45279
45264
  useReducer,
45280
45265
  useRef as useRef74,
@@ -46093,8 +46078,8 @@ function useTopologyLensState() {
46093
46078
  lifecycle,
46094
46079
  (initialLifecycle) => reduceTopologyLens({ phase: "hidden" }, { type: "lifecycle", value: initialLifecycle })
46095
46080
  );
46096
- useEffect57(() => dispatch({ type: "lifecycle", value: lifecycle }), [lifecycle]);
46097
- useEffect57(() => {
46081
+ useEffect56(() => dispatch({ type: "lifecycle", value: lifecycle }), [lifecycle]);
46082
+ useEffect56(() => {
46098
46083
  if (state.phase === "hidden") return;
46099
46084
  const delay2 = state.phase === "acquiring" ? ACQUISITION_MS : state.phase === "sealing" ? SEAL_MS : state.terminal ? TERMINAL_RETRACT_MS : null;
46100
46085
  if (delay2 === null) return;
@@ -46140,13 +46125,13 @@ function TopologyLens({ iframeRef, activeCompositionPath }) {
46140
46125
  setMeasured(geometry2 ? { callId, geometry: geometry2 } : null);
46141
46126
  }, [activeCompositionPath, callId, handle, iframeRef, phase]);
46142
46127
  const livePreviewIframe = useLivePreviewIframe();
46143
- useEffect57(() => {
46128
+ useEffect56(() => {
46144
46129
  const iframe = iframeRef.current;
46145
46130
  if (!iframe || !callId) return;
46146
46131
  const dismiss = () => studioEditLifecycle.dismiss(callId);
46147
46132
  return onPreviewContentReplaced(iframe, dismiss);
46148
46133
  }, [callId, iframeRef, livePreviewIframe]);
46149
- useEffect57(() => {
46134
+ useEffect56(() => {
46150
46135
  if (pendingUnmountDismissRef.current !== null) {
46151
46136
  window.clearTimeout(pendingUnmountDismissRef.current);
46152
46137
  pendingUnmountDismissRef.current = null;
@@ -46414,7 +46399,7 @@ function writeKeyframeCache(sourceFile, elementId2, data) {
46414
46399
  }
46415
46400
 
46416
46401
  // src/components/editor/MotionPathOverlay.tsx
46417
- import { memo as memo30, useEffect as useEffect59, useRef as useRef76, useState as useState56 } from "react";
46402
+ import { memo as memo30, useEffect as useEffect58, useRef as useRef76, useState as useState56 } from "react";
46418
46403
 
46419
46404
  // src/hooks/useGsapInteractionFailureTelemetry.ts
46420
46405
  import { useCallback as useCallback64 } from "react";
@@ -47827,7 +47812,7 @@ function elementHome(el) {
47827
47812
  }
47828
47813
 
47829
47814
  // src/components/editor/useMotionPathData.ts
47830
- import { useEffect as useEffect58, useRef as useRef75, useState as useState55 } from "react";
47815
+ import { useEffect as useEffect57, useRef as useRef75, useState as useState55 } from "react";
47831
47816
  import { isHtmlElement as isHtmlElement8 } from "@hyperframes/core/runtime/dom-realm";
47832
47817
  function transformWDivisor(el) {
47833
47818
  const t2 = el.ownerDocument?.defaultView?.getComputedStyle(el).transform;
@@ -47858,7 +47843,7 @@ function useMotionPathData(iframeRef, selector) {
47858
47843
  const [pScale, setPScale] = useState55(1);
47859
47844
  const armed = usePlayerStore((s) => s.motionPathArmed);
47860
47845
  const drawn = geometry !== null || armed;
47861
- useEffect58(() => {
47846
+ useEffect57(() => {
47862
47847
  if (!selector) {
47863
47848
  setRect(null);
47864
47849
  setHome(null);
@@ -47899,7 +47884,7 @@ function useMotionPathData(iframeRef, selector) {
47899
47884
  };
47900
47885
  return subscribeOverlayFrame(tick);
47901
47886
  }, [selector, iframeRef, drawn]);
47902
- useEffect58(() => {
47887
+ useEffect57(() => {
47903
47888
  if (!selector) {
47904
47889
  setGeometry(null);
47905
47890
  return;
@@ -47975,20 +47960,20 @@ var MotionPathOverlay = memo30(function MotionPathOverlay2({
47975
47960
  geometry?.kind ?? "linear",
47976
47961
  selection
47977
47962
  );
47978
- useEffect59(() => () => clearTimeout(parkTimerRef.current), [animId]);
47963
+ useEffect58(() => () => clearTimeout(parkTimerRef.current), [animId]);
47979
47964
  const createMode = geometryResolved && !geometry && Boolean(selection?.element) && !isPlaying;
47980
47965
  const createSelector = createMode ? selectorFor(selection) : null;
47981
47966
  const compW = compositionSize?.width ?? null;
47982
47967
  const livePreviewIframe = useLivePreviewIframe();
47983
47968
  const canCreate = createMode && !!createSelector && hasMotionPathPlugin(livePreviewIframe);
47984
- useEffect59(() => {
47969
+ useEffect58(() => {
47985
47970
  setMotionPathCreateAvailable(Boolean(canCreate));
47986
47971
  return () => setMotionPathCreateAvailable(false);
47987
47972
  }, [canCreate, setMotionPathCreateAvailable]);
47988
- useEffect59(() => {
47973
+ useEffect58(() => {
47989
47974
  if (armed && !canCreate) setMotionPathArmed(false);
47990
47975
  }, [armed, canCreate, setMotionPathArmed]);
47991
- useEffect59(() => {
47976
+ useEffect58(() => {
47992
47977
  if (!armed || !createSelector || !compW) return;
47993
47978
  const surface = iframeRef.current?.ownerDocument?.querySelector(
47994
47979
  "[data-preview-pan-surface]"
@@ -48290,7 +48275,7 @@ var MotionPathOverlay = memo30(function MotionPathOverlay2({
48290
48275
  });
48291
48276
 
48292
48277
  // src/components/editor/SnapToolbar.tsx
48293
- import { memo as memo31, useCallback as useCallback65, useEffect as useEffect60, useRef as useRef77, useState as useState57 } from "react";
48278
+ import { memo as memo31, useCallback as useCallback65, useEffect as useEffect59, useRef as useRef77, useState as useState57 } from "react";
48294
48279
  import { MagnetStraight, GridFour, Path, Ruler, FrameCorners } from "@phosphor-icons/react";
48295
48280
  import { jsx as jsx109, jsxs as jsxs77 } from "react/jsx-runtime";
48296
48281
  var SnapToolbar = memo31(function SnapToolbar2() {
@@ -48311,7 +48296,7 @@ var SnapToolbar = memo31(function SnapToolbar2() {
48311
48296
  if (previous !== null && previous !== currentGridSpacing.current)
48312
48297
  trackPreviewFeatureUsed("grid_spacing", "field");
48313
48298
  }, []);
48314
- useEffect60(() => settleGridSpacing, [settleGridSpacing]);
48299
+ useEffect59(() => settleGridSpacing, [settleGridSpacing]);
48315
48300
  const updatePrefs = useCallback65(
48316
48301
  (patch) => {
48317
48302
  actions.setSnapPrefs(patch);
@@ -48326,7 +48311,7 @@ var SnapToolbar = memo31(function SnapToolbar2() {
48326
48311
  updatePrefs({ gridVisible: !prefs.gridVisible });
48327
48312
  trackPreviewFeatureUsed("grid", "button");
48328
48313
  }, [prefs.gridVisible, updatePrefs]);
48329
- useEffect60(() => {
48314
+ useEffect59(() => {
48330
48315
  const handleKeyDown = (e) => {
48331
48316
  if (e.defaultPrevented) return;
48332
48317
  if (ownsPlainKeys(e.target)) return;
@@ -48345,7 +48330,7 @@ var SnapToolbar = memo31(function SnapToolbar2() {
48345
48330
  document.addEventListener("keydown", handleKeyDown);
48346
48331
  return () => document.removeEventListener("keydown", handleKeyDown);
48347
48332
  }, [prefs.gridVisible, prefs.snapEnabled, updatePrefs]);
48348
- useEffect60(() => {
48333
+ useEffect59(() => {
48349
48334
  if (!gridPopoverOpen) return;
48350
48335
  const handleClickOutside = (e) => {
48351
48336
  const target = e.target;
@@ -48536,7 +48521,7 @@ var GridOverlay = memo32(function GridOverlay2() {
48536
48521
  });
48537
48522
 
48538
48523
  // src/hooks/useCompositionDimensions.ts
48539
- import { useEffect as useEffect61, useState as useState58 } from "react";
48524
+ import { useEffect as useEffect60, useState as useState58 } from "react";
48540
48525
  function readCompositionSizeMessage(data) {
48541
48526
  if (!isStageSizeMessage(data)) return null;
48542
48527
  const message = data;
@@ -48564,7 +48549,7 @@ function useCompositionDimensions(iframeRef) {
48564
48549
  null
48565
48550
  );
48566
48551
  const livePreviewIframe = useLivePreviewIframe();
48567
- useEffect61(() => {
48552
+ useEffect60(() => {
48568
48553
  const dimensions = readPreviewCompositionSize(livePreviewIframe);
48569
48554
  if (!dimensions) return;
48570
48555
  setCompositionDimensions(
@@ -48725,7 +48710,7 @@ function PreviewOverlays({
48725
48710
  import { useCallback as useCallback68, useMemo as useMemo45 } from "react";
48726
48711
 
48727
48712
  // src/hooks/useGsapTweenCache.ts
48728
- import { useEffect as useEffect62, useMemo as useMemo44, useRef as useRef78, useState as useState59, useCallback as useCallback67 } from "react";
48713
+ import { useEffect as useEffect61, useMemo as useMemo44, useRef as useRef78, useState as useState59, useCallback as useCallback67 } from "react";
48729
48714
 
48730
48715
  // src/hooks/gsapRuntimeBridge.ts
48731
48716
  import { isXYPositionWrite, PROPERTY_GROUPS } from "@hyperframes/parsers/gsap-constants";
@@ -49356,7 +49341,7 @@ function useGsapAnimationsForElement(projectId, sourceFile, target, version, ifr
49356
49341
  const domClipChildrenKey = usePlayerStore(
49357
49342
  (s) => s.domClipChildren.map((c) => `${c.id}<${c.hostId}`).join("|")
49358
49343
  );
49359
- useEffect62(() => {
49344
+ useEffect61(() => {
49360
49345
  const targetKey = target?.id ?? target?.selector ?? "";
49361
49346
  const fetchKey = `${projectId}:${sourceFile}:${version}:${targetKey}`;
49362
49347
  if (fetchKey === lastFetchKeyRef.current) return;
@@ -49448,7 +49433,7 @@ function useGsapAnimationsForElement(projectId, sourceFile, target, version, ifr
49448
49433
  return result;
49449
49434
  }, [rawAnimations, allAnimations, iframeRef, targetId]);
49450
49435
  const elementId2 = target?.id ?? null;
49451
- useEffect62(() => {
49436
+ useEffect61(() => {
49452
49437
  if (!elementId2) return;
49453
49438
  const sourceAnimations = animations.filter(
49454
49439
  (animation2) => !isStaticPositionHold(animation2) && (animation2.keyframes || synthesizeFlatTweenKeyframes(animation2))
@@ -49516,7 +49501,7 @@ function usePopulateKeyframeCacheForFile(projectId, sourceFile, version, iframeR
49516
49501
  files: /* @__PURE__ */ new Set()
49517
49502
  });
49518
49503
  const runtimeScanDoneRef = useRef78("");
49519
- useEffect62(() => {
49504
+ useEffect61(() => {
49520
49505
  const dataKey = `kf-cache:${projectId}:${version}:${elementCount}:${domClipChildrenKey}:${compositionSrcKey}`;
49521
49506
  if (!projectId) return;
49522
49507
  const files = Array.from(
@@ -49536,7 +49521,7 @@ function usePopulateKeyframeCacheForFile(projectId, sourceFile, version, iframeR
49536
49521
  });
49537
49522
  }
49538
49523
  }, [projectId, sourceFile, version, elementCount, domClipChildrenKey, compositionSrcKey]);
49539
- useEffect62(() => {
49524
+ useEffect61(() => {
49540
49525
  if (!projectId) return;
49541
49526
  const sf = sourceFile;
49542
49527
  let attempts = 0;
@@ -50042,7 +50027,7 @@ var CaptionTimeline = memo33(function CaptionTimeline2({
50042
50027
  });
50043
50028
 
50044
50029
  // src/hooks/useTimelineSelectionPreviewSync.ts
50045
- import { useEffect as useEffect63, useMemo as useMemo46, useRef as useRef79 } from "react";
50030
+ import { useEffect as useEffect62, useMemo as useMemo46, useRef as useRef79 } from "react";
50046
50031
  var MAX_UNRESOLVED_SYNC_RETRIES = 3;
50047
50032
  function orderSelectedIds(ids, anchor2) {
50048
50033
  const ordered = [...ids];
@@ -50101,7 +50086,7 @@ function useTimelineSelectionPreviewSync({
50101
50086
  const unresolvedAttemptsRef = useRef79({ id: "", count: 0 });
50102
50087
  domEditSelectionRef.current = domEditSelection;
50103
50088
  domEditGroupSelectionsRef.current = domEditGroupSelections;
50104
- useEffect63(() => {
50089
+ useEffect62(() => {
50105
50090
  const previousSelectedKey = lastSyncedSelectedKeyRef.current;
50106
50091
  lastSyncedSelectedKeyRef.current = selectedKey;
50107
50092
  const currentDomEditSelection = domEditSelectionRef.current;
@@ -50178,10 +50163,10 @@ function useTimelineSelectionPreviewSync({
50178
50163
  }
50179
50164
 
50180
50165
  // src/webmcp/StudioAgentTools.tsx
50181
- import { useCallback as useCallback70, useEffect as useEffect65, useMemo as useMemo47 } from "react";
50166
+ import { useCallback as useCallback70, useEffect as useEffect64, useMemo as useMemo47 } from "react";
50182
50167
 
50183
50168
  // src/webmcp/useStudioAgentTools.ts
50184
- import { useEffect as useEffect64, useRef as useRef80 } from "react";
50169
+ import { useEffect as useEffect63, useRef as useRef80 } from "react";
50185
50170
 
50186
50171
  // src/webmcp/types.ts
50187
50172
  function isModelContext(value) {
@@ -51402,7 +51387,7 @@ function readNumberInput(input, key2) {
51402
51387
  function useStudioAgentTools(deps) {
51403
51388
  const depsRef = useRef80(deps);
51404
51389
  depsRef.current = deps;
51405
- useEffect64(() => {
51390
+ useEffect63(() => {
51406
51391
  if (readStudioUiPreferences().agentToolsEnabled === false) {
51407
51392
  log2("skipped", { why: "disabled by preference" });
51408
51393
  return;
@@ -51466,7 +51451,7 @@ function StudioAgentTools() {
51466
51451
  handleGsapDeleteAnimation,
51467
51452
  getGsapAnimationsForSelection
51468
51453
  } = useDomEditActionsContext();
51469
- useEffect65(() => {
51454
+ useEffect64(() => {
51470
51455
  studioEditLifecycle.activateProject(projectId);
51471
51456
  return () => studioEditLifecycle.reset();
51472
51457
  }, [projectId]);
@@ -51587,7 +51572,7 @@ import {
51587
51572
  createContext as createContext7,
51588
51573
  useCallback as useCallback73,
51589
51574
  useContext as useContext11,
51590
- useEffect as useEffect66,
51575
+ useEffect as useEffect65,
51591
51576
  useRef as useRef81,
51592
51577
  useState as useState60
51593
51578
  } from "react";
@@ -52144,7 +52129,7 @@ function Root({
52144
52129
  }, []);
52145
52130
  const disposeRef = useRef81(() => {
52146
52131
  });
52147
- useEffect66(() => () => disposeRef.current(), []);
52132
+ useEffect65(() => () => disposeRef.current(), []);
52148
52133
  const onReady = useCallback73(
52149
52134
  ({ api }) => {
52150
52135
  disposeRef.current();
@@ -52222,7 +52207,7 @@ function Panel({ id, title, children }) {
52222
52207
  const controller = useDockLayoutStore((state) => state.controller);
52223
52208
  const open = useDockLayoutStore((state) => state.openPanels.has(id));
52224
52209
  const label = title ?? PANEL_DEFINITIONS[id].title;
52225
- useEffect66(() => {
52210
+ useEffect65(() => {
52226
52211
  if (open) controller?.setTitle(id, label);
52227
52212
  }, [controller, id, label, open]);
52228
52213
  const definition = PANEL_DEFINITIONS[id];
@@ -52236,7 +52221,7 @@ function WindowMenu() {
52236
52221
  const resetLayout = useDockLayoutStore((state) => state.resetLayout);
52237
52222
  const [open, setOpen] = useState60(false);
52238
52223
  const rootRef = useRef81(null);
52239
- useEffect66(() => {
52224
+ useEffect65(() => {
52240
52225
  if (!open) return;
52241
52226
  const close = (event) => {
52242
52227
  if (!rootRef.current?.contains(event.target)) setOpen(false);
@@ -52751,7 +52736,7 @@ function AudibleVideoClipContent({
52751
52736
  }
52752
52737
 
52753
52738
  // src/player/components/ClipPeakMarks.tsx
52754
- import { useContext as useContext12, useEffect as useEffect67, useState as useState61 } from "react";
52739
+ import { useContext as useContext12, useEffect as useEffect66, useState as useState61 } from "react";
52755
52740
  import { jsx as jsx120, jsxs as jsxs86 } from "react/jsx-runtime";
52756
52741
  var dbText2 = (db) => `${db < 0 ? "\u2212" : "+"}${Math.abs(db).toFixed(1)} dBFS`;
52757
52742
  function ClipPeakMarks({
@@ -52761,7 +52746,7 @@ function ClipPeakMarks({
52761
52746
  children
52762
52747
  }) {
52763
52748
  const [map, setMap] = useState61(null);
52764
- useEffect67(() => {
52749
+ useEffect66(() => {
52765
52750
  if (!peaksUrl) return;
52766
52751
  let live = true;
52767
52752
  void loadPeakMap(peaksUrl).then((loaded) => {
@@ -52774,7 +52759,7 @@ function ClipPeakMarks({
52774
52759
  const { runs, peakDbfs } = map ? clipPeakRuns(map, sourceWindow, gain) : { runs: [], peakDbfs: null };
52775
52760
  const detail = runs.length > 0 && peakDbfs !== null ? `Peaks ${dbText2(peakDbfs)} at this volume; export lowers the whole mix` : null;
52776
52761
  const setDetail = useContext12(ClipPeakDescriptionContext);
52777
- useEffect67(() => {
52762
+ useEffect66(() => {
52778
52763
  setDetail?.(detail);
52779
52764
  return () => setDetail?.(null);
52780
52765
  }, [detail, setDetail]);
@@ -53011,7 +52996,7 @@ function useThumbnailStill(url, projectId, { sessionEpoch = 0, priority = "visib
53011
52996
  }
53012
52997
 
53013
52998
  // src/components/editor/SourceEditor.tsx
53014
- import { useRef as useRef82, useCallback as useCallback76, useEffect as useEffect68, memo as memo36 } from "react";
52999
+ import { useRef as useRef82, useCallback as useCallback76, useEffect as useEffect67, memo as memo36 } from "react";
53015
53000
  import {
53016
53001
  EditorView as EditorView2,
53017
53002
  keymap,
@@ -53208,7 +53193,7 @@ var SourceEditor = memo36(function SourceEditor2({
53208
53193
  },
53209
53194
  [filePath, language, readOnly]
53210
53195
  );
53211
- useEffect68(() => {
53196
+ useEffect67(() => {
53212
53197
  const view = editorRef.current;
53213
53198
  if (!view) return;
53214
53199
  const current = view.state.doc.toString();
@@ -53219,7 +53204,7 @@ var SourceEditor = memo36(function SourceEditor2({
53219
53204
  annotations: [ExternalSync.of(true)]
53220
53205
  });
53221
53206
  }, [content]);
53222
- useEffect68(() => {
53207
+ useEffect67(() => {
53223
53208
  const view = editorRef.current;
53224
53209
  if (!view || revealOffset == null || revealOffset < 0) return;
53225
53210
  const docLen = view.state.doc.length;
@@ -53895,13 +53880,13 @@ function buildElementInfoText(element, sourceLabel, gsapAnimations, previewIfram
53895
53880
  }
53896
53881
 
53897
53882
  // src/components/editor/propertyPanelPrimitives.tsx
53898
- import { useCallback as useCallback79, useEffect as useEffect71, useRef as useRef85, useState as useState64 } from "react";
53883
+ import { useCallback as useCallback79, useEffect as useEffect70, useRef as useRef85, useState as useState64 } from "react";
53899
53884
 
53900
53885
  // src/components/editor/propertyPanelCommitField.tsx
53901
- import { useEffect as useEffect70, useRef as useRef84, useState as useState63 } from "react";
53886
+ import { useEffect as useEffect69, useRef as useRef84, useState as useState63 } from "react";
53902
53887
 
53903
53888
  // src/components/editor/useInspectorGestureTransaction.ts
53904
- import { useCallback as useCallback78, useEffect as useEffect69, useRef as useRef83, useState as useState62 } from "react";
53889
+ import { useCallback as useCallback78, useEffect as useEffect68, useRef as useRef83, useState as useState62 } from "react";
53905
53890
  function isPromiseCommit(result) {
53906
53891
  return Boolean(result && typeof result.then === "function");
53907
53892
  }
@@ -53993,7 +53978,7 @@ function useInspectorGestureTransaction({
53993
53978
  previewRef.current(active.before);
53994
53979
  }
53995
53980
  }, []);
53996
- useEffect69(() => cancel, [cancel]);
53981
+ useEffect68(() => cancel, [cancel]);
53997
53982
  return { begin, preview: preview2, settle, cancel, activeRef };
53998
53983
  }
53999
53984
  function useInspectorGestureDraft({
@@ -54013,7 +53998,7 @@ function useInspectorGestureDraft({
54013
53998
  return onCommit(next);
54014
53999
  }
54015
54000
  });
54016
- useEffect69(() => {
54001
+ useEffect68(() => {
54017
54002
  if (!transaction.activeRef.current) setDraft(sourceValue);
54018
54003
  }, [sourceValue, transaction.activeRef]);
54019
54004
  return { draft, setDraft, transaction };
@@ -54153,11 +54138,11 @@ function CommitField({
54153
54138
  }
54154
54139
  previewNumericKeyStep(event);
54155
54140
  };
54156
- useEffect70(() => {
54141
+ useEffect69(() => {
54157
54142
  if (focusedRef.current && dirtyRef.current) return;
54158
54143
  setDraft(value);
54159
54144
  }, [value]);
54160
- useEffect70(() => {
54145
+ useEffect69(() => {
54161
54146
  const el = inputRef.current;
54162
54147
  if (!el) return;
54163
54148
  const handler = (event) => {
@@ -54308,10 +54293,10 @@ function SliderControl({
54308
54293
  const interactionChangedRef = useRef85(false);
54309
54294
  const valueRef = useRef85(value);
54310
54295
  valueRef.current = value;
54311
- useEffect71(() => {
54296
+ useEffect70(() => {
54312
54297
  setDraft(value);
54313
54298
  }, [value]);
54314
- useEffect71(
54299
+ useEffect70(
54315
54300
  () => () => {
54316
54301
  if (commitTimerRef.current) clearTimeout(commitTimerRef.current);
54317
54302
  },
@@ -54549,7 +54534,7 @@ function createTransformCommitHandlers({
54549
54534
  import { resolveEditingSections } from "@hyperframes/core/editing";
54550
54535
 
54551
54536
  // src/components/editor/propertyPanelMediaSection.tsx
54552
- import { useEffect as useEffect72, useState as useState65 } from "react";
54537
+ import { useEffect as useEffect71, useState as useState65 } from "react";
54553
54538
  import {
54554
54539
  AUDIO_GAIN_FADER_MAX as AUDIO_GAIN_FADER_MAX2,
54555
54540
  AUDIO_GAIN_FADER_MIN as AUDIO_GAIN_FADER_MIN2,
@@ -54659,7 +54644,7 @@ function MediaSection({
54659
54644
  const absoluteSrc = projectDir && projectSrc ? `${projectDir}/${projectSrc}` : srcAttr;
54660
54645
  const canRemoveBackground = Boolean(onRemoveBackground && isVisualMedia && projectSrc);
54661
54646
  const panelTitle = isImage ? "Image" : isVideo ? "Video" : "Audio";
54662
- useEffect72(() => {
54647
+ useEffect71(() => {
54663
54648
  setRemoveProgress(null);
54664
54649
  setCreatePlate(false);
54665
54650
  }, [srcAttr]);
@@ -54954,7 +54939,7 @@ import {
54954
54939
  } from "@hyperframes/core/color-grading";
54955
54940
 
54956
54941
  // src/components/editor/propertyPanelColorGradingSlider.tsx
54957
- import { useCallback as useCallback80, useEffect as useEffect73, useRef as useRef86, useState as useState66 } from "react";
54942
+ import { useCallback as useCallback80, useEffect as useEffect72, useRef as useRef86, useState as useState66 } from "react";
54958
54943
  import { jsx as jsx127, jsxs as jsxs90 } from "react/jsx-runtime";
54959
54944
  var SLIDER_THUMB_SIZE = 10;
54960
54945
  var SLIDER_THUMB_RADIUS = SLIDER_THUMB_SIZE / 2;
@@ -54997,7 +54982,7 @@ function ColorGradingSliderControl({
54997
54982
  const interactionChangedRef = useRef86(false);
54998
54983
  const valueRef = useRef86(value);
54999
54984
  valueRef.current = value;
55000
- useEffect73(
54985
+ useEffect72(
55001
54986
  () => () => {
55002
54987
  if (commitTimerRef.current) clearTimeout(commitTimerRef.current);
55003
54988
  },
@@ -55671,7 +55656,7 @@ function ColorGradingControls({
55671
55656
  }
55672
55657
 
55673
55658
  // src/components/editor/useColorGradingController.ts
55674
- import { useCallback as useCallback82, useEffect as useEffect75, useMemo as useMemo52, useRef as useRef89, useState as useState69 } from "react";
55659
+ import { useCallback as useCallback82, useEffect as useEffect74, useMemo as useMemo52, useRef as useRef89, useState as useState69 } from "react";
55675
55660
  import {
55676
55661
  HF_COLOR_GRADING_ATTR as HF_COLOR_GRADING_ATTR3,
55677
55662
  hasHfColorGradingAuthoredValues,
@@ -55681,7 +55666,7 @@ import {
55681
55666
  } from "@hyperframes/core/color-grading";
55682
55667
 
55683
55668
  // src/components/editor/useColorGradingPreviews.ts
55684
- import { useCallback as useCallback81, useEffect as useEffect74, useRef as useRef88, useState as useState68 } from "react";
55669
+ import { useCallback as useCallback81, useEffect as useEffect73, useRef as useRef88, useState as useState68 } from "react";
55685
55670
  import {
55686
55671
  HF_COLOR_GRADING_ACTIVE_EFFECT_KEYS,
55687
55672
  HF_COLOR_GRADING_EFFECT_APPLY_DEFAULTS,
@@ -55762,7 +55747,7 @@ function useColorGradingPreviews({
55762
55747
  }
55763
55748
  const previews = state.identityKey === identityKey ? state.previews : emptyPreviews();
55764
55749
  const livePreviewIframe = useLivePreviewIframe();
55765
- useEffect74(() => {
55750
+ useEffect73(() => {
55766
55751
  if (!request2) return;
55767
55752
  const { kind } = request2;
55768
55753
  const iframe = previewIframeRef?.current;
@@ -55909,7 +55894,7 @@ function useColorGradingPreviews({
55909
55894
  },
55910
55895
  [gradingRef, postColorGrading, previewIframeRef, stopAnimatedPreview, target]
55911
55896
  );
55912
- useEffect74(() => stopAnimatedPreview, [identityKey, stopAnimatedPreview]);
55897
+ useEffect73(() => stopAnimatedPreview, [identityKey, stopAnimatedPreview]);
55913
55898
  const requestPreviews = useCallback81(
55914
55899
  (kind, effects) => {
55915
55900
  setRequest((current) => ({
@@ -56065,7 +56050,7 @@ function useColorGradingController({
56065
56050
  setRuntimeStatus({ state: "pending", message: "Waiting for runtime" });
56066
56051
  setMediaMetadata(null);
56067
56052
  }
56068
- useEffect75(() => {
56053
+ useEffect74(() => {
56069
56054
  return () => {
56070
56055
  for (const timer of statusTimersRef.current) clearTimeout(timer);
56071
56056
  statusTimersRef.current = [];
@@ -56093,7 +56078,7 @@ function useColorGradingController({
56093
56078
  const refreshRuntimeStatus = useCallback82(() => {
56094
56079
  setRuntimeStatus(readRuntimeColorGradingStatus(previewIframeRef?.current, target));
56095
56080
  }, [previewIframeRef, target]);
56096
- useEffect75(() => {
56081
+ useEffect74(() => {
56097
56082
  setMediaMetadata(null);
56098
56083
  if (!selectedAssetPath) return;
56099
56084
  const cacheKey = mediaMetadataUrl(projectId, selectedAssetPath);
@@ -56129,7 +56114,7 @@ function useColorGradingController({
56129
56114
  (delay2) => window.setTimeout(refreshRuntimeStatus, delay2)
56130
56115
  );
56131
56116
  }, [clearStatusTimers, refreshRuntimeStatus]);
56132
- useEffect75(() => {
56117
+ useEffect74(() => {
56133
56118
  refreshRuntimeStatus();
56134
56119
  }, [refreshRuntimeStatus]);
56135
56120
  const persistColorGradingValue = useCallback82(
@@ -56177,8 +56162,8 @@ function useColorGradingController({
56177
56162
  onSetAttributeLive
56178
56163
  );
56179
56164
  }, [onSetAttributeLive, persistColorGradingValue]);
56180
- useEffect75(() => addStudioPendingEditFlushListener(flushPendingPersist), [flushPendingPersist]);
56181
- useEffect75(() => {
56165
+ useEffect74(() => addStudioPendingEditFlushListener(flushPendingPersist), [flushPendingPersist]);
56166
+ useEffect74(() => {
56182
56167
  return () => {
56183
56168
  clearStatusTimers();
56184
56169
  void flushPendingPersist();
@@ -56215,7 +56200,7 @@ function useColorGradingController({
56215
56200
  [previewIframeRef, target]
56216
56201
  );
56217
56202
  const livePreviewIframe = useLivePreviewIframe();
56218
- useEffect75(() => {
56203
+ useEffect74(() => {
56219
56204
  const iframe = previewIframeRef?.current;
56220
56205
  if (!iframe) return;
56221
56206
  const refreshAndReplay = () => {
@@ -56247,7 +56232,7 @@ function useColorGradingController({
56247
56232
  scheduleRuntimeStatusRefresh,
56248
56233
  livePreviewIframe
56249
56234
  ]);
56250
- useEffect75(
56235
+ useEffect74(
56251
56236
  () => () => {
56252
56237
  postCompare(false);
56253
56238
  },
@@ -56551,10 +56536,10 @@ function ColorGradingSection({
56551
56536
  }
56552
56537
 
56553
56538
  // src/components/editor/propertyPanelSections.tsx
56554
- import { useEffect as useEffect81, useRef as useRef94, useState as useState78 } from "react";
56539
+ import { useEffect as useEffect80, useRef as useRef94, useState as useState78 } from "react";
56555
56540
 
56556
56541
  // src/components/editor/propertyPanelColor.tsx
56557
- import { useCallback as useCallback83, useEffect as useEffect76, useLayoutEffect as useLayoutEffect12, useRef as useRef90, useState as useState70 } from "react";
56542
+ import { useCallback as useCallback83, useEffect as useEffect75, useLayoutEffect as useLayoutEffect12, useRef as useRef90, useState as useState70 } from "react";
56558
56543
  import { createPortal as createPortal12 } from "react-dom";
56559
56544
  import { jsx as jsx130, jsxs as jsxs93 } from "react/jsx-runtime";
56560
56545
  var COLOR_PICKER_SIZE = { width: 292, height: 386 };
@@ -56733,7 +56718,7 @@ function ColorField({
56733
56718
  if (resolved2) persistColorValue(resolved2.value);
56734
56719
  }
56735
56720
  });
56736
- useEffect76(() => {
56721
+ useEffect75(() => {
56737
56722
  const nextColor = colorFromCss(value);
56738
56723
  setDraftColor(nextColor);
56739
56724
  setHexDraft(toHexColor(nextColor).toUpperCase());
@@ -56764,7 +56749,7 @@ function ColorField({
56764
56749
  window.removeEventListener("scroll", handlePositionInvalidated, true);
56765
56750
  };
56766
56751
  }, [open, updatePanelPosition]);
56767
- useEffect76(() => {
56752
+ useEffect75(() => {
56768
56753
  if (!open) return;
56769
56754
  panelRef.current?.focus();
56770
56755
  const restoreTarget = buttonRef.current;
@@ -57061,7 +57046,7 @@ function ColorField({
57061
57046
  }
57062
57047
 
57063
57048
  // src/components/editor/propertyPanelFont.tsx
57064
- import { useEffect as useEffect77, useMemo as useMemo53, useRef as useRef91, useState as useState71, useSyncExternalStore as useSyncExternalStore10 } from "react";
57049
+ import { useEffect as useEffect76, useMemo as useMemo53, useRef as useRef91, useState as useState71, useSyncExternalStore as useSyncExternalStore10 } from "react";
57065
57050
 
57066
57051
  // src/components/editor/fontAssets.ts
57067
57052
  var FONT_EXT_RE = /\.(eot|otf|ttc|ttf|woff2?)$/i;
@@ -57237,7 +57222,7 @@ function FontFamilyField({
57237
57222
  if (nextValue !== value) track2("select", "Font family");
57238
57223
  onCommit(nextValue);
57239
57224
  };
57240
- useEffect77(() => {
57225
+ useEffect76(() => {
57241
57226
  if (!open) return;
57242
57227
  const handlePointerDown = (event) => {
57243
57228
  const target = event.target;
@@ -57247,14 +57232,14 @@ function FontFamilyField({
57247
57232
  document.addEventListener("pointerdown", handlePointerDown);
57248
57233
  return () => document.removeEventListener("pointerdown", handlePointerDown);
57249
57234
  }, [open]);
57250
- useEffect77(() => {
57235
+ useEffect76(() => {
57251
57236
  if (!open) return;
57252
57237
  requestAnimationFrame(() => inputRef.current?.focus());
57253
57238
  }, [open]);
57254
- useEffect77(() => {
57239
+ useEffect76(() => {
57255
57240
  if (open) loadFontLists();
57256
57241
  }, [open]);
57257
- useEffect77(() => {
57242
+ useEffect76(() => {
57258
57243
  if (lists.googleKeys.has(currentFamily.toLowerCase())) {
57259
57244
  loadGoogleFontStylesheet(currentFamily);
57260
57245
  }
@@ -57562,7 +57547,7 @@ function FontFamilyField({
57562
57547
  }
57563
57548
 
57564
57549
  // src/components/editor/PromotableControl.tsx
57565
- import { useEffect as useEffect79 } from "react";
57550
+ import { useEffect as useEffect78 } from "react";
57566
57551
 
57567
57552
  // src/components/panels/VariablesBindElement.tsx
57568
57553
  import { useMemo as useMemo54, useState as useState73 } from "react";
@@ -57958,7 +57943,7 @@ function uniqueId(base2, existing) {
57958
57943
  }
57959
57944
 
57960
57945
  // src/contexts/VariablePromoteContext.tsx
57961
- import { useContext as useContext14, useEffect as useEffect78, useMemo as useMemo55, useState as useState74 } from "react";
57946
+ import { useContext as useContext14, useEffect as useEffect77, useMemo as useMemo55, useState as useState74 } from "react";
57962
57947
  import { jsx as jsx134 } from "react/jsx-runtime";
57963
57948
  var VariablePromoteContext = createStableContext(
57964
57949
  "VariablePromoteContext",
@@ -57977,7 +57962,7 @@ function VariablePromoteProvider({
57977
57962
  children
57978
57963
  }) {
57979
57964
  const [revision, setRevision] = useState74(0);
57980
- useEffect78(() => {
57965
+ useEffect77(() => {
57981
57966
  if (!session) return;
57982
57967
  return session.on("change", () => setRevision((r) => r + 1));
57983
57968
  }, [session]);
@@ -58039,7 +58024,7 @@ function PromotableControl({
58039
58024
  }) {
58040
58025
  const promote = useVariablePromoteChannel(channel);
58041
58026
  const danglingId = enabled && promote && promote.boundId != null && promote.declaration == null ? promote.boundId : null;
58042
- useEffect79(() => {
58027
+ useEffect78(() => {
58043
58028
  if (danglingId != null) {
58044
58029
  console.warn(
58045
58030
  `[hyperframes] Control is bound to variable "${danglingId}", but no such declaration exists. The element still carries the binding on disk. Re-declare the variable or unbind the element.`
@@ -58089,7 +58074,7 @@ function PromotableControl({
58089
58074
  }
58090
58075
 
58091
58076
  // src/components/editor/propertyPanelStyleSections.tsx
58092
- import { useEffect as useEffect80, useRef as useRef93, useState as useState77 } from "react";
58077
+ import { useEffect as useEffect79, useRef as useRef93, useState as useState77 } from "react";
58093
58078
 
58094
58079
  // src/components/editor/gradientValue.ts
58095
58080
  var RADIAL_SIZE_KEYWORDS = [
@@ -59125,10 +59110,10 @@ function StyleSections({
59125
59110
  const lastGradientRef = useRef93(
59126
59111
  backgroundImage.includes("gradient") ? backgroundImage : null
59127
59112
  );
59128
- useEffect80(() => {
59113
+ useEffect79(() => {
59129
59114
  lastGradientRef.current = null;
59130
59115
  }, [element.id, element.selector]);
59131
- useEffect80(() => {
59116
+ useEffect79(() => {
59132
59117
  setPreferredFillMode(fillMode);
59133
59118
  if (backgroundImage.includes("gradient")) {
59134
59119
  lastGradientRef.current = backgroundImage;
@@ -59585,17 +59570,17 @@ function TextAreaField({
59585
59570
  const focusedRef = useRef94(false);
59586
59571
  const valueRef = useRef94(value);
59587
59572
  valueRef.current = value;
59588
- useEffect81(() => {
59573
+ useEffect80(() => {
59589
59574
  if (focusedRef.current) return;
59590
59575
  setDraft(value);
59591
59576
  }, [value]);
59592
- useEffect81(
59577
+ useEffect80(
59593
59578
  () => () => {
59594
59579
  if (commitTimerRef.current) clearTimeout(commitTimerRef.current);
59595
59580
  },
59596
59581
  []
59597
59582
  );
59598
- useEffect81(() => {
59583
+ useEffect80(() => {
59599
59584
  if (!autoFocus) return;
59600
59585
  textareaRef.current?.focus();
59601
59586
  }, [autoFocus]);
@@ -59892,7 +59877,7 @@ function TextSection({
59892
59877
  const [activeTextFieldKey, setActiveTextFieldKey] = useState78(
59893
59878
  element.textFields[0]?.key ?? null
59894
59879
  );
59895
- useEffect81(() => {
59880
+ useEffect80(() => {
59896
59881
  const nextFields = element.textFields;
59897
59882
  setActiveTextFieldKey((current) => {
59898
59883
  if (current && nextFields.some((field) => field.key === current)) return current;
@@ -59994,7 +59979,7 @@ import { useCallback as useCallback87, useState as useState80 } from "react";
59994
59979
  import { useShallow } from "zustand/react/shallow";
59995
59980
 
59996
59981
  // src/components/editor/AnimationCard.tsx
59997
- import { memo as memo38, useCallback as useCallback86, useEffect as useEffect82, useMemo as useMemo57, useRef as useRef95, useState as useState79 } from "react";
59982
+ import { memo as memo38, useCallback as useCallback86, useEffect as useEffect81, useMemo as useMemo57, useRef as useRef95, useState as useState79 } from "react";
59998
59983
  import { SUPPORTED_EASES, SUPPORTED_PROPS } from "@hyperframes/core/gsap-constants";
59999
59984
 
60000
59985
  // src/components/editor/gsapAnimationHelpers.ts
@@ -60541,7 +60526,7 @@ var AnimationCard = memo38(function AnimationCard2({
60541
60526
  const [focusedCollidingAnimationTargets, setFocusedCollidingAnimationTargets] = useState79();
60542
60527
  const cardRef = useRef95(null);
60543
60528
  const pendingAutoScrollRef = useRef95(false);
60544
- useEffect82(() => {
60529
+ useEffect81(() => {
60545
60530
  if (!focusedSegment) return;
60546
60531
  setExpanded(true);
60547
60532
  pendingAutoScrollRef.current = true;
@@ -60549,7 +60534,7 @@ var AnimationCard = memo38(function AnimationCard2({
60549
60534
  setFocusedCollidingAnimationTargets(focusedSegment.collidingAnimationTargets);
60550
60535
  onFocusSegmentConsumed?.();
60551
60536
  }, [focusedSegment, onFocusSegmentConsumed]);
60552
- useEffect82(() => {
60537
+ useEffect81(() => {
60553
60538
  if (!pendingAutoScrollRef.current || expandedKfPct === null) return;
60554
60539
  const segment = cardRef.current?.querySelector(
60555
60540
  `[data-ease-segment-pct="${expandedKfPct}"]`
@@ -61129,7 +61114,7 @@ var GsapAnimationSection = memo39(function GsapAnimationSection2({
61129
61114
  import { useState as useState82 } from "react";
61130
61115
 
61131
61116
  // src/components/editor/Transform3DCube.tsx
61132
- import { useEffect as useEffect83, useRef as useRef96, useState as useState81 } from "react";
61117
+ import { useEffect as useEffect82, useRef as useRef96, useState as useState81 } from "react";
61133
61118
 
61134
61119
  // src/components/editor/transform3dProjection.ts
61135
61120
  var DEG = Math.PI / 180;
@@ -61252,7 +61237,7 @@ function Transform3DCube({
61252
61237
  const lens = perspective > 0 ? perspective : defaultPerspective;
61253
61238
  const depthRef = useRef96({ z, onDepthDraft, onDepthCommit, lens });
61254
61239
  depthRef.current = { z, onDepthDraft, onDepthCommit, lens };
61255
- useEffect83(() => {
61240
+ useEffect82(() => {
61256
61241
  const el = svgRef.current;
61257
61242
  if (!el) return;
61258
61243
  let pending2 = null;
@@ -61773,7 +61758,7 @@ function PropertyPanel3dTransform({
61773
61758
  }
61774
61759
 
61775
61760
  // src/components/editor/PropertyPanelFlat.tsx
61776
- import { useEffect as useEffect103, useMemo as useMemo64, useRef as useRef112, useState as useState104 } from "react";
61761
+ import { useEffect as useEffect102, useMemo as useMemo64, useRef as useRef112, useState as useState104 } from "react";
61777
61762
  import { useShallow as useShallow2 } from "zustand/react/shallow";
61778
61763
 
61779
61764
  // src/components/editor/audioFxSummary.ts
@@ -62006,10 +61991,10 @@ function PropertyPanelFlatFooter({
62006
61991
  }
62007
61992
 
62008
61993
  // src/components/editor/propertyPanelFlatPrimitives.tsx
62009
- import { useEffect as useEffect85, useRef as useRef98, useState as useState84 } from "react";
61994
+ import { useEffect as useEffect84, useRef as useRef98, useState as useState84 } from "react";
62010
61995
 
62011
61996
  // src/components/editor/propertyPanelFlatSliderReadout.tsx
62012
- import { useEffect as useEffect84, useRef as useRef97, useState as useState83 } from "react";
61997
+ import { useEffect as useEffect83, useRef as useRef97, useState as useState83 } from "react";
62013
61998
  import { jsx as jsx153 } from "react/jsx-runtime";
62014
61999
  function FlatSliderReadout({
62015
62000
  label,
@@ -62024,7 +62009,7 @@ function FlatSliderReadout({
62024
62009
  const [invalid, setInvalid] = useState83(false);
62025
62010
  const inputRef = useRef97(null);
62026
62011
  const editable = Boolean(onCommitText) && !disabled;
62027
- useEffect84(() => {
62012
+ useEffect83(() => {
62028
62013
  if (!editing) return;
62029
62014
  inputRef.current?.focus();
62030
62015
  inputRef.current?.select();
@@ -62380,12 +62365,12 @@ function FlatSlider({
62380
62365
  const explicitReleaseRef = useRef98(false);
62381
62366
  const dragStartValueRef = useRef98(value);
62382
62367
  const activePointerIdRef = useRef98(null);
62383
- useEffect85(() => {
62368
+ useEffect84(() => {
62384
62369
  if (draggingRef.current) return;
62385
62370
  setDraft(value);
62386
62371
  lastCommittedRef.current = value;
62387
62372
  }, [value]);
62388
- useEffect85(
62373
+ useEffect84(
62389
62374
  () => () => {
62390
62375
  if (commitTimerRef.current) {
62391
62376
  clearTimeout(commitTimerRef.current);
@@ -62590,7 +62575,7 @@ function isSelectionHidden(fromTimeline, element) {
62590
62575
  }
62591
62576
 
62592
62577
  // src/components/editor/propertyPanelFlatTextSection.tsx
62593
- import { useEffect as useEffect86, useState as useState85 } from "react";
62578
+ import { useEffect as useEffect85, useState as useState85 } from "react";
62594
62579
  import { Fragment as Fragment42, jsx as jsx157, jsxs as jsxs117 } from "react/jsx-runtime";
62595
62580
  var ALIGN_OPTIONS = [
62596
62581
  { key: "left", label: "left", node: "L" },
@@ -62803,7 +62788,7 @@ function FlatTextSection({
62803
62788
  element.textFields[0]?.key ?? null
62804
62789
  );
62805
62790
  const [autoFocusFieldKey, setAutoFocusFieldKey] = useState85(null);
62806
- useEffect86(() => {
62791
+ useEffect85(() => {
62807
62792
  const nextFields = element.textFields;
62808
62793
  setActiveFieldKey((current) => {
62809
62794
  if (current && nextFields.some((field) => field.key === current)) return current;
@@ -62955,7 +62940,7 @@ function FlatTextLayerList({
62955
62940
  }
62956
62941
 
62957
62942
  // src/components/editor/propertyPanelFlatStyleSections.tsx
62958
- import { useEffect as useEffect87, useState as useState86 } from "react";
62943
+ import { useEffect as useEffect86, useState as useState86 } from "react";
62959
62944
 
62960
62945
  // src/components/editor/propertyPanelFlatStyleHelpers.ts
62961
62946
  var STROKE_STYLE_OPTIONS = [
@@ -63081,7 +63066,7 @@ function FlatFillFields({
63081
63066
  }
63082
63067
  const [preferredFillMode, setPreferredFillMode] = useState86(fillMode);
63083
63068
  const imageUrl = extractBackgroundImageUrl(backgroundImage);
63084
- useEffect87(() => {
63069
+ useEffect86(() => {
63085
63070
  setPreferredFillMode(fillMode);
63086
63071
  }, [fillMode, element.id, element.selector, backgroundImage]);
63087
63072
  const handleFillModeChange = (nextMode) => {
@@ -63995,7 +63980,7 @@ import {
63995
63980
  } from "@hyperframes/core/audio-automation";
63996
63981
 
63997
63982
  // src/components/editor/propertyPanelFxSection.tsx
63998
- import { useCallback as useCallback90, useEffect as useEffect90, useMemo as useMemo59, useRef as useRef100, useState as useState90 } from "react";
63983
+ import { useCallback as useCallback90, useEffect as useEffect89, useMemo as useMemo59, useRef as useRef100, useState as useState90 } from "react";
63999
63984
 
64000
63985
  // src/components/editor/audioFxRevealTarget.ts
64001
63986
  import { parseAutomationTarget as parseAutomationTarget2 } from "@hyperframes/core/audio-automation";
@@ -64075,7 +64060,7 @@ import { DEFAULT_CARVE as DEFAULT_CARVE2 } from "@hyperframes/core/audio-carve";
64075
64060
  import { fxAutomationTarget as fxAutomationTarget3 } from "@hyperframes/core/audio-automation";
64076
64061
 
64077
64062
  // src/components/editor/propertyPanelFxControls.tsx
64078
- import { useCallback as useCallback88, useEffect as useEffect88, useRef as useRef99, useState as useState87 } from "react";
64063
+ import { useCallback as useCallback88, useEffect as useEffect87, useRef as useRef99, useState as useState87 } from "react";
64079
64064
  import { jsx as jsx163, jsxs as jsxs123 } from "react/jsx-runtime";
64080
64065
  function toSlider(p, value) {
64081
64066
  if (p.scale !== "log" || p.min <= 0) return value;
@@ -64128,10 +64113,10 @@ function FxParamRow({
64128
64113
  const [pending2, setPending] = useState87(null);
64129
64114
  const [typing, setTyping] = useState87(null);
64130
64115
  const edited = useRef99(false);
64131
- useEffect88(() => {
64116
+ useEffect87(() => {
64132
64117
  if (!dragging) setLocal(value);
64133
64118
  }, [value, dragging]);
64134
- useEffect88(() => {
64119
+ useEffect87(() => {
64135
64120
  setPending(null);
64136
64121
  }, [value]);
64137
64122
  const handleNumber = useCallback88(
@@ -64795,7 +64780,7 @@ function CarveAnalysis({
64795
64780
  }
64796
64781
 
64797
64782
  // src/components/editor/propertyPanelFxEqModule.tsx
64798
- import { useCallback as useCallback89, useEffect as useEffect89, useState as useState88 } from "react";
64783
+ import { useCallback as useCallback89, useEffect as useEffect88, useState as useState88 } from "react";
64799
64784
  import {
64800
64785
  audioEqSummary,
64801
64786
  HF_AUDIO_EQ_RANGE_DB
@@ -64817,7 +64802,7 @@ function Fader2({
64817
64802
  }) {
64818
64803
  const [local, setLocal] = useState88(band.gain);
64819
64804
  const [dragging, setDragging] = useState88(false);
64820
- useEffect89(() => {
64805
+ useEffect88(() => {
64821
64806
  if (!dragging) setLocal(band.gain);
64822
64807
  }, [band.gain, dragging]);
64823
64808
  const value = dragging ? local : band.gain;
@@ -66111,7 +66096,7 @@ function FxSection({
66111
66096
  }
66112
66097
  setPendingReveal(where && revealTarget ? { nonce: revealNonce, target: revealTarget } : null);
66113
66098
  }
66114
- useEffect90(() => {
66099
+ useEffect89(() => {
66115
66100
  const target = pendingReveal?.target;
66116
66101
  if (target && scrollRevealedRowIntoView(rootRef.current, target, chain)) {
66117
66102
  setPendingReveal(null);
@@ -66308,7 +66293,7 @@ function FxSection({
66308
66293
  }
66309
66294
 
66310
66295
  // src/components/editor/useFxChainObserved.ts
66311
- import { useEffect as useEffect91, useRef as useRef101 } from "react";
66296
+ import { useEffect as useEffect90, useRef as useRef101 } from "react";
66312
66297
  import { classifyAudioName as classifyAudioName3 } from "@hyperframes/core/audio-carve";
66313
66298
  function useFxChainObserved(element, chain, carve, automation, onSetAttributeQuietRaw) {
66314
66299
  const lastShape = useRef101(null);
@@ -66317,7 +66302,7 @@ function useFxChainObserved(element, chain, carve, automation, onSetAttributeQui
66317
66302
  panelEdits.current += 1;
66318
66303
  return onSetAttributeQuietRaw(attr, value);
66319
66304
  };
66320
- useEffect91(() => {
66305
+ useEffect90(() => {
66321
66306
  const shape = JSON.stringify([
66322
66307
  chain.nodes.map((n) => `${n.type}:${n.fromPreset ?? ""}:${n.fromCarve ? 1 : 0}`),
66323
66308
  carve?.enabled ?? false,
@@ -66345,7 +66330,7 @@ function useFxChainObserved(element, chain, carve, automation, onSetAttributeQui
66345
66330
  }
66346
66331
 
66347
66332
  // src/components/editor/useFxCarve.ts
66348
- import { useEffect as useEffect92, useRef as useRef102 } from "react";
66333
+ import { useEffect as useEffect91, useRef as useRef102 } from "react";
66349
66334
  import {
66350
66335
  HF_AUDIO_FX_ATTR as HF_AUDIO_FX_ATTR9,
66351
66336
  serializeAudioFxChain as serializeAudioFxChain6
@@ -66456,13 +66441,13 @@ function useFxCarve(element, chain, carve, automation, onSetAttributeQuiet, writ
66456
66441
  setAnalysing(false);
66457
66442
  }
66458
66443
  };
66459
- useEffect92(() => {
66444
+ useEffect91(() => {
66460
66445
  if (carvedAgainstBy || !carve?.enabled) return;
66461
66446
  if (survivingSources.length === carve.sources.length) return;
66462
66447
  void setCarve({ ...carve, sources: survivingSources });
66463
66448
  }, [carve, carvedAgainstBy, survivingSources.join(" ")]);
66464
66449
  const candidateIds = autoSourceIds.join("\0");
66465
- useEffect92(() => {
66450
+ useEffect91(() => {
66466
66451
  if (carvedAgainstBy || !autoBed || autoSourceIds.length <= 1) return;
66467
66452
  if (autoCarveInFlight.current) return;
66468
66453
  const all = autoSourceIds;
@@ -66472,7 +66457,7 @@ function useFxCarve(element, chain, carve, automation, onSetAttributeQuiet, writ
66472
66457
  }
66473
66458
  if (carve.enabled && carve.sources.length === 0) setCarveAuto({ ...carve, sources: all });
66474
66459
  }, [carve, carvedAgainstBy, autoBed, candidateIds]);
66475
- useEffect92(() => {
66460
+ useEffect91(() => {
66476
66461
  if (carvedAgainstBy || !autoBed || autoSourceIds.length !== 1) return;
66477
66462
  if (autoCarveInFlight.current) return;
66478
66463
  const only = autoSourceIds[0];
@@ -66861,14 +66846,14 @@ function useVolumeAutomation(element, currentTime, onSetAttributeQuiet, linkedSp
66861
66846
  }
66862
66847
 
66863
66848
  // src/components/editor/useAudioFxRevealSection.ts
66864
- import { useEffect as useEffect93, useState as useState93 } from "react";
66849
+ import { useEffect as useEffect92, useState as useState93 } from "react";
66865
66850
  function useAudioFxRevealSection(input) {
66866
66851
  const revealedAudioFxTarget = usePlayerStore((s) => s.revealedAudioFxTarget);
66867
66852
  const timelineProjectId = usePlayerStore((s) => s.timelineProjectId);
66868
66853
  const timelineSessionEpoch = usePlayerStore((s) => s.timelineSessionEpoch);
66869
66854
  const clearRevealedAudioFxTarget = usePlayerStore((s) => s.clearRevealedAudioFxTarget);
66870
66855
  const [consumed, setConsumed] = useState93(null);
66871
- useEffect93(() => {
66856
+ useEffect92(() => {
66872
66857
  if (consumed === null) return;
66873
66858
  return () => clearRevealedAudioFxTarget(consumed);
66874
66859
  }, [consumed, clearRevealedAudioFxTarget]);
@@ -66883,7 +66868,7 @@ function useAudioFxRevealSection(input) {
66883
66868
  }
66884
66869
 
66885
66870
  // src/components/editor/propertyPanelFlatMediaSection.tsx
66886
- import { useEffect as useEffect94, useState as useState94 } from "react";
66871
+ import { useEffect as useEffect93, useState as useState94 } from "react";
66887
66872
 
66888
66873
  // src/components/editor/propertyPanelFlatToggle.tsx
66889
66874
  import { jsx as jsx175, jsxs as jsxs133 } from "react/jsx-runtime";
@@ -67049,7 +67034,7 @@ function FlatMediaSection({
67049
67034
  const projectSrc = srcAttr && !/^(?:https?:|data:|blob:)/i.test(srcAttr) ? authoredSrcPath(srcAttr.startsWith("./") ? srcAttr.slice(2) : srcAttr) : "";
67050
67035
  const absoluteSrc = projectDir && projectSrc ? `${projectDir}/${projectSrc}` : srcAttr;
67051
67036
  const canRemoveBackground = Boolean(onRemoveBackground && isVisualMedia && projectSrc);
67052
- useEffect94(() => {
67037
+ useEffect93(() => {
67053
67038
  setRemoveProgress(null);
67054
67039
  setCreatePlate(false);
67055
67040
  }, [srcAttr]);
@@ -67385,7 +67370,7 @@ function createGsapLivePreview(iframeRef) {
67385
67370
  }
67386
67371
 
67387
67372
  // src/components/editor/propertyPanelFlatColorGradingSection.tsx
67388
- import { useEffect as useEffect100, useMemo as useMemo62, useRef as useRef111, useState as useState100 } from "react";
67373
+ import { useEffect as useEffect99, useMemo as useMemo62, useRef as useRef111, useState as useState100 } from "react";
67389
67374
  import {
67390
67375
  HF_COLOR_GRADING_GRADE_PRESETS,
67391
67376
  normalizeHfColorGrading as normalizeHfColorGrading6,
@@ -67843,7 +67828,7 @@ function formatPointValue(value, tab, axis) {
67843
67828
  }
67844
67829
 
67845
67830
  // src/components/editor/propertyPanelGradingNumberField.tsx
67846
- import { useEffect as useEffect95, useRef as useRef105, useState as useState95 } from "react";
67831
+ import { useEffect as useEffect94, useRef as useRef105, useState as useState95 } from "react";
67847
67832
  import { jsx as jsx178, jsxs as jsxs136 } from "react/jsx-runtime";
67848
67833
  function GradingNumberField({
67849
67834
  label,
@@ -67866,7 +67851,7 @@ function GradingNumberField({
67866
67851
  const cancelBlurRef = useRef105(false);
67867
67852
  const baselineRef = useRef105(value);
67868
67853
  const dirtyRef = useRef105(false);
67869
- useEffect95(() => {
67854
+ useEffect94(() => {
67870
67855
  if (!focusedRef.current) setDraft(formatValue2(value));
67871
67856
  }, [formatValue2, value]);
67872
67857
  const settle = () => {
@@ -68095,10 +68080,10 @@ function ColorCurves({
68095
68080
  }
68096
68081
 
68097
68082
  // src/components/editor/propertyPanelColorScopes.tsx
68098
- import { useEffect as useEffect97, useRef as useRef107, useState as useState98 } from "react";
68083
+ import { useEffect as useEffect96, useRef as useRef107, useState as useState98 } from "react";
68099
68084
 
68100
68085
  // src/components/editor/useColorGradingScopes.ts
68101
- import { useEffect as useEffect96, useRef as useRef106, useState as useState97 } from "react";
68086
+ import { useEffect as useEffect95, useRef as useRef106, useState as useState97 } from "react";
68102
68087
 
68103
68088
  // src/components/editor/colorGradingFrameAnalysis.ts
68104
68089
  import {
@@ -68260,7 +68245,7 @@ function useColorGradingScopes({
68260
68245
  const [refreshVersion, setRefreshVersion] = useState97(0);
68261
68246
  const captureRef = useRef106(captureFrame);
68262
68247
  captureRef.current = captureFrame;
68263
- useEffect96(() => {
68248
+ useEffect95(() => {
68264
68249
  if (!open) {
68265
68250
  setAnalysis(null);
68266
68251
  setStatus("idle");
@@ -68442,7 +68427,7 @@ function PropertyPanelColorScopes({
68442
68427
  captureFrame,
68443
68428
  refreshKey
68444
68429
  });
68445
- useEffect97(() => {
68430
+ useEffect96(() => {
68446
68431
  const canvas = canvasRef.current;
68447
68432
  if (!canvas) return;
68448
68433
  if (analysis) {
@@ -68506,7 +68491,7 @@ function PropertyPanelColorScopes({
68506
68491
  }
68507
68492
 
68508
68493
  // src/components/editor/propertyPanelColorSecondary.tsx
68509
- import { useEffect as useEffect98, useRef as useRef108, useState as useState99 } from "react";
68494
+ import { useEffect as useEffect97, useRef as useRef108, useState as useState99 } from "react";
68510
68495
  import {
68511
68496
  getHfColorGradingCapabilities,
68512
68497
  normalizeHfColorGrading as normalizeHfColorGrading5
@@ -68559,7 +68544,7 @@ function PropertyPanelColorSecondary({
68559
68544
  const matteCanvasRef = useRef108(null);
68560
68545
  const activeIndex = Math.min(selectedIndex, Math.max(0, secondaries.length - 1));
68561
68546
  const selected = secondaries[activeIndex];
68562
- useEffect98(() => {
68547
+ useEffect97(() => {
68563
68548
  const canvas = matteCanvasRef.current;
68564
68549
  if (!showMatte || !canvas || !sampleFrame || !samplePixels || !selected) return;
68565
68550
  const context = canvas.getContext("2d");
@@ -69225,7 +69210,7 @@ function ColorWheels({
69225
69210
  }
69226
69211
 
69227
69212
  // src/components/editor/propertyPanelFlatColorGradingAccessory.tsx
69228
- import { useEffect as useEffect99, useRef as useRef110 } from "react";
69213
+ import { useEffect as useEffect98, useRef as useRef110 } from "react";
69229
69214
  import { isHfColorGradingActive as isHfColorGradingActive3 } from "@hyperframes/core/color-grading";
69230
69215
  import { jsx as jsx183, jsxs as jsxs141 } from "react/jsx-runtime";
69231
69216
  var STATUS_DOT_CLASS = {
@@ -69242,7 +69227,7 @@ function FlatColorGradingAccessory({
69242
69227
  const { grading, compareEnabled, runtimeStatus, commitCompare, resetGrading } = state;
69243
69228
  const gradingActive = isHfColorGradingActive3(grading);
69244
69229
  const releaseRef = useRef110(null);
69245
- useEffect99(
69230
+ useEffect98(
69246
69231
  () => () => {
69247
69232
  releaseRef.current?.();
69248
69233
  releaseRef.current = null;
@@ -69425,7 +69410,7 @@ function FlatColorGradingSection({
69425
69410
  );
69426
69411
  const actions = createColorGradingActions(grading, onCommitColorGrading);
69427
69412
  const scopesRefreshKey = useMemo62(() => serializeHfColorGrading2(grading), [grading]);
69428
- useEffect100(() => {
69413
+ useEffect99(() => {
69429
69414
  if (presetPreviews.status === "idle") onRequestPresetPreviews();
69430
69415
  }, [onRequestPresetPreviews, presetPreviews.status]);
69431
69416
  const resolvePreset = (presetId) => {
@@ -69436,7 +69421,7 @@ function FlatColorGradingSection({
69436
69421
  palette: grading.palette
69437
69422
  } : grading;
69438
69423
  };
69439
- useEffect100(() => () => onPreviewColorGrading(null), [onPreviewColorGrading]);
69424
+ useEffect99(() => () => onPreviewColorGrading(null), [onPreviewColorGrading]);
69440
69425
  const renderDetailSlider = (key2) => {
69441
69426
  const spec = detailByKey(key2);
69442
69427
  const value = grading.details[key2];
@@ -69784,7 +69769,7 @@ function FlatColorGradingSection({
69784
69769
  }
69785
69770
 
69786
69771
  // src/components/editor/propertyPanelFlatEffectsSection.tsx
69787
- import { useEffect as useEffect101, useState as useState101 } from "react";
69772
+ import { useEffect as useEffect100, useState as useState101 } from "react";
69788
69773
  import {
69789
69774
  HF_COLOR_GRADING_EFFECT_APPLY_DEFAULTS as HF_COLOR_GRADING_EFFECT_APPLY_DEFAULTS3,
69790
69775
  HF_COLOR_GRADING_EFFECT_PRESETS,
@@ -70166,7 +70151,7 @@ function FlatEffectsSection({
70166
70151
  activeEffects[0]?.key ?? null
70167
70152
  );
70168
70153
  const selectedEffect = activeEffects.find((effect) => effect.key === selectedKey) ?? activeEffects[0] ?? null;
70169
- useEffect101(() => {
70154
+ useEffect100(() => {
70170
70155
  if (!catalogOpen) return;
70171
70156
  const group = EFFECT_GROUPS.find((candidate) => candidate.label === catalogGroup);
70172
70157
  if (!group) return;
@@ -70187,7 +70172,7 @@ function FlatEffectsSection({
70187
70172
  previews.images,
70188
70173
  previews.status
70189
70174
  ]);
70190
- useEffect101(() => () => onPreviewColorGrading(null), [onPreviewColorGrading]);
70175
+ useEffect100(() => () => onPreviewColorGrading(null), [onPreviewColorGrading]);
70191
70176
  const commitEffects = (effects) => {
70192
70177
  onCommitColorGrading({
70193
70178
  ...grading,
@@ -70554,7 +70539,7 @@ function FlatEffectsSection({
70554
70539
  import { useState as useState103 } from "react";
70555
70540
 
70556
70541
  // src/hooks/useBlockCatalog.ts
70557
- import { useState as useState102, useEffect as useEffect102, useMemo as useMemo63 } from "react";
70542
+ import { useState as useState102, useEffect as useEffect101, useMemo as useMemo63 } from "react";
70558
70543
 
70559
70544
  // src/utils/blockCategories.ts
70560
70545
  import {
@@ -70634,7 +70619,7 @@ function useBlockCatalog() {
70634
70619
  const [error, setError] = useState102(null);
70635
70620
  const [search, setSearch] = useState102("");
70636
70621
  const [category, setCategory] = useState102(null);
70637
- useEffect102(() => {
70622
+ useEffect101(() => {
70638
70623
  if (catalogCache) return;
70639
70624
  let cancelled = false;
70640
70625
  (async () => {
@@ -70915,7 +70900,7 @@ function PropertyPanelFlat({
70915
70900
  const [justToggledIds, setJustToggledIds] = useState104([]);
70916
70901
  const justToggledTimeoutRef = useRef112(null);
70917
70902
  const panelBodyRef = useRef112(null);
70918
- useEffect103(() => {
70903
+ useEffect102(() => {
70919
70904
  return () => {
70920
70905
  if (justToggledTimeoutRef.current) clearTimeout(justToggledTimeoutRef.current);
70921
70906
  };
@@ -71930,7 +71915,7 @@ import { memo as memo42, useState as useState107, useCallback as useCallback92,
71930
71915
  import { Plus as Plus2, FolderSimplePlus as FolderSimplePlus2 } from "@phosphor-icons/react";
71931
71916
 
71932
71917
  // src/components/editor/FileTreeNodes.tsx
71933
- import { memo as memo41, useState as useState106, useCallback as useCallback91, useMemo as useMemo66, useRef as useRef114, useEffect as useEffect104 } from "react";
71918
+ import { memo as memo41, useState as useState106, useCallback as useCallback91, useMemo as useMemo66, useRef as useRef114, useEffect as useEffect103 } from "react";
71934
71919
  import {
71935
71920
  PencilSimple,
71936
71921
  Copy,
@@ -72067,7 +72052,7 @@ function ContextMenu2({
72067
72052
  }) {
72068
72053
  const menuRef = useRef114(null);
72069
72054
  const restoreFocusRef = useRef114(null);
72070
- useEffect104(() => {
72055
+ useEffect103(() => {
72071
72056
  restoreFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
72072
72057
  const firstItem = menuRef.current?.querySelector("button");
72073
72058
  if (firstItem instanceof HTMLElement) firstItem.focus();
@@ -72233,7 +72218,7 @@ function InlineInput({
72233
72218
  if (name.includes("..")) return "Name can't contain ..";
72234
72219
  return null;
72235
72220
  };
72236
- useEffect104(() => {
72221
+ useEffect103(() => {
72237
72222
  const el = inputRef.current;
72238
72223
  if (!el) return;
72239
72224
  el.focus();
@@ -72310,7 +72295,7 @@ function DeleteConfirm({
72310
72295
  onCancel
72311
72296
  }) {
72312
72297
  const ref = useRef114(null);
72313
- useEffect104(() => {
72298
+ useEffect103(() => {
72314
72299
  const handleEscape = (e) => {
72315
72300
  if (e.key === "Escape") onCancel();
72316
72301
  };
@@ -72907,11 +72892,11 @@ function useToolbarSession(session) {
72907
72892
  }
72908
72893
 
72909
72894
  // src/hooks/useRightPanelIntents.ts
72910
- import { useCallback as useCallback93, useEffect as useEffect105, useRef as useRef117 } from "react";
72895
+ import { useCallback as useCallback93, useEffect as useEffect104, useRef as useRef117 } from "react";
72911
72896
  function useSlideshowDockPanel(isSlideshowComposition) {
72912
72897
  const controller = useDockLayoutStore((state) => state.controller);
72913
72898
  const wasSlideshow = useRef117(false);
72914
- useEffect105(() => {
72899
+ useEffect104(() => {
72915
72900
  if (!controller) return;
72916
72901
  const inDock = useDockLayoutStore.getState().openPanels.has("slideshow");
72917
72902
  if (isSlideshowComposition && !inDock) controller.open("slideshow");
@@ -72924,7 +72909,7 @@ function useBlockParamsDismissal({
72924
72909
  onDismiss
72925
72910
  }) {
72926
72911
  const designVisible = useDockLayoutStore((state) => state.visiblePanels.has("design"));
72927
- useEffect105(() => {
72912
+ useEffect104(() => {
72928
72913
  if (hasBlockParams && !designVisible) onDismiss();
72929
72914
  }, [hasBlockParams, designVisible, onDismiss]);
72930
72915
  }
@@ -72942,7 +72927,7 @@ function useCaptionDesignFocus(captionEditMode) {
72942
72927
  const rightShown = useDockLayoutStore(
72943
72928
  (state) => visiblePanelInZone("right", state.lastActive, state.visiblePanels) !== null
72944
72929
  );
72945
- useEffect105(() => {
72930
+ useEffect104(() => {
72946
72931
  if (captionEditMode && rightShown && !designVisible) {
72947
72932
  useDockLayoutStore.getState().activatePanel("design");
72948
72933
  }
@@ -72955,7 +72940,7 @@ function useRightPanelIntent() {
72955
72940
  }
72956
72941
 
72957
72942
  // src/components/renders/useRenderQueue.ts
72958
- import { useState as useState109, useEffect as useEffect107, useCallback as useCallback95, useRef as useRef119, useMemo as useMemo69 } from "react";
72943
+ import { useState as useState109, useEffect as useEffect106, useCallback as useCallback95, useRef as useRef119, useMemo as useMemo69 } from "react";
72959
72944
 
72960
72945
  // src/components/renders/serverError.ts
72961
72946
  async function readServerError(res) {
@@ -72973,7 +72958,7 @@ async function readServerError(res) {
72973
72958
  }
72974
72959
 
72975
72960
  // src/components/renders/useFfmpegStatus.ts
72976
- import { useCallback as useCallback94, useEffect as useEffect106, useRef as useRef118, useState as useState108 } from "react";
72961
+ import { useCallback as useCallback94, useEffect as useEffect105, useRef as useRef118, useState as useState108 } from "react";
72977
72962
  function ffmpegInstallMessage(status) {
72978
72963
  const title = status?.title ?? "FFmpeg not found";
72979
72964
  const remedy = status?.command ?? status?.hint;
@@ -73005,7 +72990,7 @@ function useFfmpegStatus() {
73005
72990
  const [status, setStatus] = useState108(cached4);
73006
72991
  const [checking, setChecking] = useState108(cached4 === null);
73007
72992
  const mounted = useRef118(true);
73008
- useEffect106(() => {
72993
+ useEffect105(() => {
73009
72994
  mounted.current = true;
73010
72995
  return () => {
73011
72996
  mounted.current = false;
@@ -73019,7 +73004,7 @@ function useFfmpegStatus() {
73019
73004
  setStatus(next);
73020
73005
  setChecking(false);
73021
73006
  }, []);
73022
- useEffect106(() => {
73007
+ useEffect105(() => {
73023
73008
  if (cached4 !== null) return;
73024
73009
  void run();
73025
73010
  }, [run]);
@@ -73247,7 +73232,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
73247
73232
  setLoadError("Couldn't load render history. Is the studio server running?");
73248
73233
  }
73249
73234
  }, [projectId]);
73250
- useEffect107(() => {
73235
+ useEffect106(() => {
73251
73236
  loadRenders();
73252
73237
  }, [loadRenders]);
73253
73238
  const startRender = useCallback95(
@@ -73447,7 +73432,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
73447
73432
  });
73448
73433
  }, [projectId]);
73449
73434
  const dismissActionError = useCallback95(() => setActionError(null), []);
73450
- useEffect107(() => {
73435
+ useEffect106(() => {
73451
73436
  for (const job of jobs) {
73452
73437
  if (job.status === "rendering" || job.status === "cancelled") continue;
73453
73438
  const settings = sessionJobs.current.get(job.id);
@@ -73472,7 +73457,7 @@ function useRenderQueue(projectId, activeCompPathRef) {
73472
73457
  });
73473
73458
  }
73474
73459
  }, [jobs]);
73475
- useEffect107(() => {
73460
+ useEffect106(() => {
73476
73461
  return () => {
73477
73462
  eventSourceRef.current?.close();
73478
73463
  eventSourceRef.current = null;
@@ -73525,7 +73510,7 @@ import { useRef as useRef121, useState as useState110 } from "react";
73525
73510
  import { XIcon, WarningIcon, CheckCircleIcon, CaretRightIcon } from "@phosphor-icons/react";
73526
73511
 
73527
73512
  // src/components/ui/useDialogBehavior.ts
73528
- import { useEffect as useEffect108, useCallback as useCallback96, useRef as useRef120 } from "react";
73513
+ import { useEffect as useEffect107, useCallback as useCallback96, useRef as useRef120 } from "react";
73529
73514
  var FOCUSABLE = 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, [contenteditable="true"], [tabindex]:not([tabindex="-1"])';
73530
73515
  function useDialogBehavior({
73531
73516
  open,
@@ -73543,7 +73528,7 @@ function useDialogBehavior({
73543
73528
  if (guard && !guard()) return;
73544
73529
  onCloseRef.current();
73545
73530
  }, []);
73546
- useEffect108(() => {
73531
+ useEffect107(() => {
73547
73532
  if (!open) return;
73548
73533
  const previouslyFocused = document.activeElement;
73549
73534
  restoreRef.current = previouslyFocused instanceof HTMLElement ? previouslyFocused : null;
@@ -73883,7 +73868,7 @@ function toastSurface(isError) {
73883
73868
  }
73884
73869
 
73885
73870
  // src/components/feedback/StudioFeedbackCard.tsx
73886
- import { memo as memo43, useState as useState112, useCallback as useCallback97, useRef as useRef123, useEffect as useEffect109 } from "react";
73871
+ import { memo as memo43, useState as useState112, useCallback as useCallback97, useRef as useRef123, useEffect as useEffect108 } from "react";
73887
73872
 
73888
73873
  // src/components/feedback/projectProvenance.ts
73889
73874
  var CONFIG_FILE = "hyperframes.json";
@@ -74003,7 +73988,7 @@ var StudioFeedbackCard = memo43(function StudioFeedbackCard2() {
74003
73988
  },
74004
73989
  [clearTimer]
74005
73990
  );
74006
- useEffect109(
73991
+ useEffect108(
74007
73992
  () => subscribeToFeedbackRequests((next) => {
74008
73993
  setRequest(next);
74009
73994
  setRating(null);
@@ -74015,12 +74000,12 @@ var StudioFeedbackCard = memo43(function StudioFeedbackCard2() {
74015
74000
  }),
74016
74001
  []
74017
74002
  );
74018
- useEffect109(() => {
74003
+ useEffect108(() => {
74019
74004
  if (!request2 || step === "thanks" || rating !== null || comment !== "") return;
74020
74005
  timerRef.current = setTimeout(() => close("timeout"), AUTO_DISMISS_MS);
74021
74006
  return clearTimer;
74022
74007
  }, [request2, step, rating, comment, close, clearTimer]);
74023
- useEffect109(() => {
74008
+ useEffect108(() => {
74024
74009
  if (step === "comment") inputRef.current?.focus();
74025
74010
  }, [step]);
74026
74011
  const submit = useCallback97(
@@ -74520,11 +74505,11 @@ function ExternalFileConflictBanner({
74520
74505
  }
74521
74506
 
74522
74507
  // src/components/ProjectUnreachableBanner.tsx
74523
- import { useEffect as useEffect110, useState as useState114 } from "react";
74508
+ import { useEffect as useEffect109, useState as useState114 } from "react";
74524
74509
  import { Fragment as Fragment57, jsx as jsx202, jsxs as jsxs158 } from "react/jsx-runtime";
74525
74510
  function ProjectUnreachableBanner({ projectId }) {
74526
74511
  const [served, setServed] = useState114(null);
74527
- useEffect110(() => {
74512
+ useEffect109(() => {
74528
74513
  let cancelled = false;
74529
74514
  studioApiFetch("/api/projects").then((res) => res.ok ? res.json() : { projects: [] }).then((data) => {
74530
74515
  if (!cancelled) setServed(data.projects ?? []);
@@ -74752,7 +74737,7 @@ function useCaptionSync(projectId) {
74752
74737
  }
74753
74738
 
74754
74739
  // src/hooks/usePersistentEditHistory.ts
74755
- import { useCallback as useCallback99, useEffect as useEffect111, useMemo as useMemo70, useRef as useRef126, useState as useState115 } from "react";
74740
+ import { useCallback as useCallback99, useEffect as useEffect110, useMemo as useMemo70, useRef as useRef126, useState as useState115 } from "react";
74756
74741
  var EMPTY3 = { entries: [], back: null, forward: null };
74757
74742
  var OWN_ENTRIES_KEPT = 100;
74758
74743
  function createOwnHistory() {
@@ -74898,14 +74883,14 @@ function usePersistentEditHistory({ projectId }) {
74898
74883
  setView(next);
74899
74884
  own.offered(seen, next);
74900
74885
  }, [projectId, own]);
74901
- useEffect111(() => {
74886
+ useEffect110(() => {
74902
74887
  setView(EMPTY3);
74903
74888
  setLoaded(false);
74904
74889
  heldClaimRef.current = null;
74905
74890
  own.clear();
74906
74891
  void refresh2().finally(() => setLoaded(true));
74907
74892
  }, [refresh2, own]);
74908
- useEffect111(() => {
74893
+ useEffect110(() => {
74909
74894
  setStudioPendingEditClaimClock(own.claimCount);
74910
74895
  return () => setStudioPendingEditClaimClock(null);
74911
74896
  }, [own]);
@@ -75015,7 +75000,7 @@ function usePersistentEditHistory({ projectId }) {
75015
75000
  }
75016
75001
 
75017
75002
  // src/hooks/usePanelLayout.ts
75018
- import { useCallback as useCallback100, useEffect as useEffect112, useRef as useRef127 } from "react";
75003
+ import { useCallback as useCallback100, useEffect as useEffect111, useRef as useRef127 } from "react";
75019
75004
  function panelForTab(tab) {
75020
75005
  return tab === "block-params" ? "design" : tab;
75021
75006
  }
@@ -75027,7 +75012,7 @@ function usePanelLayout(initialState2) {
75027
75012
  const lastActive = useDockLayoutStore((state) => state.lastActive);
75028
75013
  const visiblePanels = useDockLayoutStore((state) => state.visiblePanels);
75029
75014
  const initialRef = useRef127(initialState2);
75030
- useEffect112(() => {
75015
+ useEffect111(() => {
75031
75016
  if (!controller) return;
75032
75017
  const { rightCollapsed: rightCollapsed2, rightPanelTab: rightPanelTab2 } = initialRef.current ?? {};
75033
75018
  initialRef.current = void 0;
@@ -75074,7 +75059,7 @@ function usePanelLayout(initialState2) {
75074
75059
  import { useState as useState117, useCallback as useCallback104, useRef as useRef130 } from "react";
75075
75060
 
75076
75061
  // src/hooks/useFileTree.ts
75077
- import { useState as useState116, useCallback as useCallback101, useEffect as useEffect113, useMemo as useMemo71, useRef as useRef128 } from "react";
75062
+ import { useState as useState116, useCallback as useCallback101, useEffect as useEffect112, useMemo as useMemo71, useRef as useRef128 } from "react";
75078
75063
  import { encodeUrlPath as encodeUrlPath4 } from "@hyperframes/parsers";
75079
75064
  var EMPTY_FILE_LIST = [];
75080
75065
  function useFileTree({ projectId, projectIdRef }) {
@@ -75084,7 +75069,7 @@ function useFileTree({ projectId, projectIdRef }) {
75084
75069
  const compositionPaths = current?.compositionPaths ?? EMPTY_FILE_LIST;
75085
75070
  const projectDir = current?.projectDir ?? null;
75086
75071
  const fileTreeLoaded = current?.loaded ?? false;
75087
- useEffect113(() => {
75072
+ useEffect112(() => {
75088
75073
  if (!projectId) return;
75089
75074
  let cancelled = false;
75090
75075
  setFetched({ projectId, loaded: false, fileTree: [], compositionPaths: [], projectDir: null });
@@ -76279,7 +76264,7 @@ function usePreviewPersistence({
76279
76264
  }
76280
76265
 
76281
76266
  // src/hooks/usePreviewDocumentVersion.ts
76282
- import { useCallback as useCallback106, useEffect as useEffect114, useRef as useRef132, useState as useState119 } from "react";
76267
+ import { useCallback as useCallback106, useEffect as useEffect113, useRef as useRef132, useState as useState119 } from "react";
76283
76268
  function usePreviewDocumentVersion() {
76284
76269
  const [previewDocumentVersion, setPreviewDocumentVersion] = useState119(0);
76285
76270
  const refreshTimersRef = useRef132([]);
@@ -76292,7 +76277,7 @@ function usePreviewDocumentVersion() {
76292
76277
  window.setTimeout(() => setPreviewDocumentVersion((v) => v + 1), 300)
76293
76278
  );
76294
76279
  }, []);
76295
- useEffect114(
76280
+ useEffect113(
76296
76281
  () => () => {
76297
76282
  for (const id of refreshTimersRef.current) clearTimeout(id);
76298
76283
  },
@@ -79350,7 +79335,7 @@ function useTimelineMoveEditsHandler(handleTimelineGroupMove) {
79350
79335
  import { useCallback as useCallback148 } from "react";
79351
79336
 
79352
79337
  // src/hooks/useAskAgentModal.ts
79353
- import { useState as useState121, useCallback as useCallback124, useRef as useRef141, useEffect as useEffect115 } from "react";
79338
+ import { useState as useState121, useCallback as useCallback124, useRef as useRef141, useEffect as useEffect114 } from "react";
79354
79339
  function useAskAgentModal({
79355
79340
  activeCompPath,
79356
79341
  projectDir,
@@ -79432,13 +79417,13 @@ function useAskAgentModal({
79432
79417
  showToast
79433
79418
  ]
79434
79419
  );
79435
- useEffect115(() => {
79420
+ useEffect114(() => {
79436
79421
  setAgentPromptTagSnippet(void 0);
79437
79422
  setAgentPromptSelectionContext(void 0);
79438
79423
  setAgentModalAnchorPoint(null);
79439
79424
  setCopiedAgentPrompt(false);
79440
79425
  }, [domEditSelection]);
79441
- useEffect115(
79426
+ useEffect114(
79442
79427
  () => () => {
79443
79428
  if (copiedAgentTimerRef.current) clearTimeout(copiedAgentTimerRef.current);
79444
79429
  },
@@ -79462,7 +79447,7 @@ function useAskAgentModal({
79462
79447
  }
79463
79448
 
79464
79449
  // src/hooks/useDomSelection.ts
79465
- import { useState as useState122, useCallback as useCallback125, useRef as useRef142, useEffect as useEffect117 } from "react";
79450
+ import { useState as useState122, useCallback as useCallback125, useRef as useRef142, useEffect as useEffect116 } from "react";
79466
79451
 
79467
79452
  // src/utils/domEditHelpers.ts
79468
79453
  function domEditSelectionsTargetSame(a, b) {
@@ -79498,7 +79483,7 @@ function seedDomEditGroupWithSelection(group, selection) {
79498
79483
  }
79499
79484
 
79500
79485
  // src/hooks/useStudioTestHooks.ts
79501
- import { useEffect as useEffect116 } from "react";
79486
+ import { useEffect as useEffect115 } from "react";
79502
79487
 
79503
79488
  // src/player/lib/timelinePerformanceDiagnostics.ts
79504
79489
  function readNonNegativeNumber(value) {
@@ -79581,7 +79566,7 @@ function useStudioTestHooks({
79581
79566
  buildDomSelectionFromTarget,
79582
79567
  applyDomSelection
79583
79568
  }) {
79584
- useEffect116(() => {
79569
+ useEffect115(() => {
79585
79570
  if (!STUDIO_TEST_HOOKS_ENABLED || typeof window === "undefined") return;
79586
79571
  const api = {
79587
79572
  runtimeMode: STUDIO_RUNTIME_MODE,
@@ -79964,13 +79949,13 @@ function useDomSelection({
79964
79949
  },
79965
79950
  [activeCompPath, announceTimelineSelection2, buildDomSelectionFromTarget, previewIframeRef]
79966
79951
  );
79967
- useEffect117(() => {
79952
+ useEffect116(() => {
79968
79953
  refreshDomEditGroupSelectionsFromPreviewRef.current = refreshDomEditGroupSelectionsFromPreview;
79969
79954
  }, [refreshDomEditGroupSelectionsFromPreview]);
79970
- useEffect117(() => {
79955
+ useEffect116(() => {
79971
79956
  updateDomEditHoverSelection(null);
79972
79957
  }, [activeCompPath, projectId, previewIframe, refreshKey, updateDomEditHoverSelection]);
79973
- useEffect117(() => {
79958
+ useEffect116(() => {
79974
79959
  const previous = compositionIdentityRef.current;
79975
79960
  if (previous.activeCompPath === activeCompPath && previous.projectId === projectId) return;
79976
79961
  compositionIdentityRef.current = { activeCompPath, projectId };
@@ -79978,7 +79963,7 @@ function useDomSelection({
79978
79963
  setActiveGroupElementState(null);
79979
79964
  applyDomSelection(null, { revealPanel: false });
79980
79965
  }, [activeCompPath, projectId, applyDomSelection]);
79981
- useEffect117(() => {
79966
+ useEffect116(() => {
79982
79967
  if (!domEditHoverSelection) return;
79983
79968
  const shouldClear = captionEditMode || domEditSelectionsTargetSame(domEditHoverSelection, domEditSelection) || domEditSelectionInGroup(domEditGroupSelections, domEditHoverSelection) || !domEditHoverSelection.element.isConnected;
79984
79969
  if (shouldClear) updateDomEditHoverSelection(null);
@@ -79989,7 +79974,7 @@ function useDomSelection({
79989
79974
  domEditGroupSelections,
79990
79975
  updateDomEditHoverSelection
79991
79976
  ]);
79992
- useEffect117(() => {
79977
+ useEffect116(() => {
79993
79978
  if (!captionEditMode) return;
79994
79979
  applyDomSelection(null, { revealPanel: false });
79995
79980
  }, [applyDomSelection, captionEditMode]);
@@ -82947,7 +82932,7 @@ function useGsapKeyframeOps({
82947
82932
  }
82948
82933
 
82949
82934
  // src/hooks/useGsapPropertyDebounce.ts
82950
- import { useCallback as useCallback137, useEffect as useEffect118, useRef as useRef147 } from "react";
82935
+ import { useCallback as useCallback137, useEffect as useEffect117, useRef as useRef147 } from "react";
82951
82936
  import { parseGsapScriptAcorn as parseGsapScriptAcorn2 } from "@hyperframes/core/gsap-parser-acorn";
82952
82937
  var DEBOUNCE_MS = 150;
82953
82938
  function mergeTweenProperties(sdkSession, animationId, edited, kind) {
@@ -83017,7 +83002,7 @@ function useGsapPropertyDebounce(commitMutationSafely, sdk) {
83017
83002
  },
83018
83003
  [flushPendingPropertyEdit]
83019
83004
  );
83020
- useEffect118(() => {
83005
+ useEffect117(() => {
83021
83006
  return () => {
83022
83007
  if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
83023
83008
  void flushPendingPropertyEdit();
@@ -83584,10 +83569,10 @@ function useGsapScriptCommits({ projectIdRef, activeCompPath, previewIframeRef,
83584
83569
  }
83585
83570
 
83586
83571
  // src/hooks/useDomEditWiring.ts
83587
- import { useCallback as useCallback142, useEffect as useEffect120, useRef as useRef151 } from "react";
83572
+ import { useCallback as useCallback142, useEffect as useEffect119, useRef as useRef151 } from "react";
83588
83573
 
83589
83574
  // src/hooks/useDomEditPreviewSync.ts
83590
- import { useEffect as useEffect119, useRef as useRef149 } from "react";
83575
+ import { useEffect as useEffect118, useRef as useRef149 } from "react";
83591
83576
  function useDomEditPreviewSync({
83592
83577
  previewIframe,
83593
83578
  activeCompPath,
@@ -83604,7 +83589,7 @@ function useDomEditPreviewSync({
83604
83589
  openSourceForSelection,
83605
83590
  gsapCacheVersion
83606
83591
  }) {
83607
- useEffect119(() => {
83592
+ useEffect118(() => {
83608
83593
  if (!previewIframe) return;
83609
83594
  const syncSelectionFromDocument = async () => {
83610
83595
  if (captionEditMode) return;
@@ -83666,7 +83651,7 @@ function useDomEditPreviewSync({
83666
83651
  ]);
83667
83652
  const openSourceRef = useRef149(openSourceForSelection);
83668
83653
  openSourceRef.current = openSourceForSelection;
83669
- useEffect119(
83654
+ useEffect118(
83670
83655
  // fallow-ignore-next-line complexity
83671
83656
  () => {
83672
83657
  if (!domEditSelection || !openSourceRef.current) return;
@@ -84085,7 +84070,7 @@ function useDomEditWiring(params) {
84085
84070
  },
84086
84071
  [openSourceForSelection]
84087
84072
  );
84088
- useEffect120(() => {
84073
+ useEffect119(() => {
84089
84074
  if (!domEditSelection?.id) return;
84090
84075
  const { selectedElementId, elements, setSelectedElementId } = usePlayerStore.getState();
84091
84076
  const matchKey = elements.find(
@@ -84095,7 +84080,7 @@ function useDomEditWiring(params) {
84095
84080
  if (key2 && key2 !== selectedElementId) setSelectedElementId(key2);
84096
84081
  }, [domEditSelection?.id]);
84097
84082
  const prevRefreshKeyRef = useRef151(refreshKey);
84098
- useEffect120(() => {
84083
+ useEffect119(() => {
84099
84084
  if (refreshKey !== prevRefreshKeyRef.current) {
84100
84085
  prevRefreshKeyRef.current = refreshKey;
84101
84086
  bumpGsapCache();
@@ -85713,7 +85698,7 @@ function useGsapAwareEditing({
85713
85698
  }
85714
85699
 
85715
85700
  // src/hooks/useStudioSelectionPublisher.ts
85716
- import { useEffect as useEffect121, useRef as useRef152 } from "react";
85701
+ import { useEffect as useEffect120, useRef as useRef152 } from "react";
85717
85702
 
85718
85703
  // src/utils/studioSelectionSnapshot.ts
85719
85704
  function round34(value) {
@@ -85806,7 +85791,7 @@ function useStudioSelectionPublisher({
85806
85791
  }) {
85807
85792
  const lastSelectionRefreshKeyRef = useRef152(refreshKey);
85808
85793
  const pendingSelectionRefreshKeyRef = useRef152(null);
85809
- useEffect121(() => {
85794
+ useEffect120(() => {
85810
85795
  if (!projectId) return;
85811
85796
  const selection = domEditSelection?.element.isConnected ? buildStudioSelectionSnapshot({
85812
85797
  projectId,
@@ -85817,13 +85802,13 @@ function useStudioSelectionPublisher({
85817
85802
  void putSelection(projectId, selection, controller.signal).catch(reportSelectionPublishError);
85818
85803
  return () => controller.abort();
85819
85804
  }, [domEditSelection, projectId]);
85820
- useEffect121(() => {
85805
+ useEffect120(() => {
85821
85806
  if (!projectId) return;
85822
85807
  return () => {
85823
85808
  void putSelection(projectId, null).catch(reportSelectionPublishError);
85824
85809
  };
85825
85810
  }, [projectId]);
85826
- useEffect121(() => {
85811
+ useEffect120(() => {
85827
85812
  if (lastSelectionRefreshKeyRef.current === refreshKey) return;
85828
85813
  lastSelectionRefreshKeyRef.current = refreshKey;
85829
85814
  pendingSelectionRefreshKeyRef.current = domEditSelectionRef.current ? refreshKey : null;
@@ -85832,7 +85817,7 @@ function useStudioSelectionPublisher({
85832
85817
  void putSelection(projectId, null, controller.signal).catch(reportSelectionPublishError);
85833
85818
  return () => controller.abort();
85834
85819
  }, [domEditSelectionRef, projectId, refreshKey]);
85835
- useEffect121(() => {
85820
+ useEffect120(() => {
85836
85821
  if (pendingSelectionRefreshKeyRef.current === null) return;
85837
85822
  pendingSelectionRefreshKeyRef.current = null;
85838
85823
  const selection = domEditSelectionRef.current;
@@ -85905,7 +85890,7 @@ function useKeyframeEaseCommits({
85905
85890
  }
85906
85891
 
85907
85892
  // src/hooks/useCommitPreflightCapabilities.ts
85908
- import { useEffect as useEffect122, useMemo as useMemo74, useRef as useRef153, useState as useState123 } from "react";
85893
+ import { useEffect as useEffect121, useMemo as useMemo74, useRef as useRef153, useState as useState123 } from "react";
85909
85894
  function runCommitPreflights(selection, fileAnimations, iframe, group) {
85910
85895
  const target = { id: selection.id ?? null, selector: selection.selector ?? null };
85911
85896
  const animations = getAnimationsForElement(fileAnimations, target, selection.element);
@@ -85967,7 +85952,7 @@ function useCommitPreflightCapabilities({
85967
85952
  }) {
85968
85953
  const parsesRef = useRef153(/* @__PURE__ */ new Map());
85969
85954
  const [parseTick, setParseTick] = useState123(0);
85970
- useEffect122(() => {
85955
+ useEffect121(() => {
85971
85956
  if (!enabled || !projectId) return;
85972
85957
  const targets = selection ? [selection, ...groupSelections] : groupSelections;
85973
85958
  for (const file of new Set(targets.map(gsapSourceFileForSelection))) {
@@ -86024,13 +86009,13 @@ function timelineElementsForDelete(members, elements) {
86024
86009
  }
86025
86010
 
86026
86011
  // src/hooks/useLivePreviewIframe.ts
86027
- import { useEffect as useEffect123, useRef as useRef154, useState as useState124 } from "react";
86012
+ import { useEffect as useEffect122, useRef as useRef154, useState as useState124 } from "react";
86028
86013
  function useLivePreviewIframe2(host) {
86029
86014
  const [promoted, setPromoted] = useState124();
86030
86015
  const live = host && promoted?.host === host ? promoted.live : host;
86031
86016
  const liveRef = useRef154(live);
86032
86017
  liveRef.current = live;
86033
- useEffect123(() => {
86018
+ useEffect122(() => {
86034
86019
  if (!host) return;
86035
86020
  return onPreviewPromoted(host.ownerDocument, ({ retired, live: next }) => {
86036
86021
  if (retired === liveRef.current) setPromoted({ host, live: next });
@@ -86580,23 +86565,23 @@ function useDomEditSession({
86580
86565
  }
86581
86566
 
86582
86567
  // src/hooks/useSdkSelectionSync.ts
86583
- import { useEffect as useEffect124 } from "react";
86568
+ import { useEffect as useEffect123 } from "react";
86584
86569
  function toHfIds(group, primary) {
86585
86570
  const source = group.length > 0 ? group : primary ? [primary] : [];
86586
86571
  return source.flatMap((s) => s.hfId ? [s.hfId] : []);
86587
86572
  }
86588
86573
  function useSdkSelectionSync(session, domEditSelection, domEditGroupSelections) {
86589
- useEffect124(() => {
86574
+ useEffect123(() => {
86590
86575
  if (!session) return;
86591
86576
  session.setSelection(toHfIds(domEditGroupSelections, domEditSelection));
86592
86577
  }, [session, domEditSelection, domEditGroupSelections]);
86593
86578
  }
86594
86579
 
86595
86580
  // src/hooks/useStudioSdkSessions.ts
86596
- import { useEffect as useEffect126 } from "react";
86581
+ import { useEffect as useEffect125 } from "react";
86597
86582
 
86598
86583
  // src/hooks/useSdkSession.ts
86599
- import { useState as useState125, useEffect as useEffect125, useCallback as useCallback149, useRef as useRef155 } from "react";
86584
+ import { useState as useState125, useEffect as useEffect124, useCallback as useCallback149, useRef as useRef155 } from "react";
86600
86585
  import { openComposition as openComposition3 } from "@hyperframes/sdk";
86601
86586
 
86602
86587
  // src/hooks/externalFileReloadBus.ts
@@ -86720,7 +86705,7 @@ function useSdkSession(projectId, activeCompPath, fileTree = [], fileTreeLoaded
86720
86705
  const [unreachableProject, setUnreachableProject] = useState125(null);
86721
86706
  const [compositionMissing, setCompositionMissing] = useState125(false);
86722
86707
  const refreshedAbsentPathsRef = useRef155(/* @__PURE__ */ new Set());
86723
- useEffect125(() => {
86708
+ useEffect124(() => {
86724
86709
  refreshedAbsentPathsRef.current.clear();
86725
86710
  }, [projectId]);
86726
86711
  function handleReadFailure(read2, forProjectId, forPath) {
@@ -86733,7 +86718,7 @@ function useSdkSession(projectId, activeCompPath, fileTree = [], fileTreeLoaded
86733
86718
  refreshedAbsentPathsRef.current.add(key2);
86734
86719
  onAbsentRead?.(forPath);
86735
86720
  }
86736
- useEffect125(
86721
+ useEffect124(
86737
86722
  () => addExternalFileReloadListener((changedPath) => {
86738
86723
  if (changedPath === "." || changedPath === activeCompPathRef.current) {
86739
86724
  setReloadToken((token) => token + 1);
@@ -86741,7 +86726,7 @@ function useSdkSession(projectId, activeCompPath, fileTree = [], fileTreeLoaded
86741
86726
  }),
86742
86727
  []
86743
86728
  );
86744
- useEffect125(() => {
86729
+ useEffect124(() => {
86745
86730
  const generation = ++generationRef.current;
86746
86731
  let cancelled = false;
86747
86732
  const previous = ownedSessionRef.current;
@@ -86849,7 +86834,7 @@ function useStudioSdkSessions(projectId, activeCompPath, masterCompPath, fileTre
86849
86834
  refreshFileTree
86850
86835
  );
86851
86836
  const editFlowSdkSession = activeCompPath ? sdkHandle.session : null;
86852
- useEffect126(() => {
86837
+ useEffect125(() => {
86853
86838
  usePreviewVariablesStore.getState().setValues(null);
86854
86839
  }, [projectId, activeCompPath]);
86855
86840
  return { sdkHandle: useStableHandlers(sdkHandle, projectId), editFlowSdkSession };
@@ -86957,7 +86942,7 @@ async function deleteExternalConflictSnapshot(projectId, filePath) {
86957
86942
  }
86958
86943
 
86959
86944
  // src/hooks/useExternalFileChangeCoordinator.ts
86960
- import { useCallback as useCallback150, useEffect as useEffect127, useRef as useRef156, useState as useState126 } from "react";
86945
+ import { useCallback as useCallback150, useEffect as useEffect126, useRef as useRef156, useState as useState126 } from "react";
86961
86946
  function testHotAdapter() {
86962
86947
  const value = globalThis.__HF_STUDIO_HOT_TEST_ADAPTER__;
86963
86948
  if (!value || typeof value !== "object") return null;
@@ -87028,22 +87013,22 @@ function useExternalFileChangeCoordinator({
87028
87013
  blockedRef.current = current;
87029
87014
  setBlockedState(current);
87030
87015
  }, []);
87031
- useEffect127(() => {
87016
+ useEffect126(() => {
87032
87017
  mountedRef.current = true;
87033
87018
  return () => {
87034
87019
  mountedRef.current = false;
87035
87020
  generationRef.current += 1;
87036
87021
  };
87037
87022
  }, []);
87038
- useEffect127(() => {
87023
+ useEffect126(() => {
87039
87024
  pendingPayloadRef.current = null;
87040
87025
  }, [projectId]);
87041
- useEffect127(() => {
87026
+ useEffect126(() => {
87042
87027
  generationRef.current += 1;
87043
87028
  setBlocked(null);
87044
87029
  lastEventIdentityRef.current = null;
87045
87030
  }, [projectId, activeCompPath, setBlocked]);
87046
- useEffect127(() => {
87031
+ useEffect126(() => {
87047
87032
  if (!projectId || !recoveryFilePath || !loadConflictSnapshot) return;
87048
87033
  const generation = ++generationRef.current;
87049
87034
  let cancelled = false;
@@ -87268,7 +87253,7 @@ function useExternalFileChangeCoordinator({
87268
87253
  );
87269
87254
  const processChangeRef = useRef156(processChange);
87270
87255
  processChangeRef.current = processChange;
87271
- useEffect127(() => {
87256
+ useEffect126(() => {
87272
87257
  const handler = (delivery) => processChangeRef.current(decodeFileChange(delivery));
87273
87258
  const adapter = testHotAdapter();
87274
87259
  if (adapter) {
@@ -87763,7 +87748,7 @@ function useBlockHandlers({
87763
87748
  }
87764
87749
 
87765
87750
  // src/hooks/useAppHotkeys.ts
87766
- import { useCallback as useCallback154, useEffect as useEffect128, useRef as useRef158 } from "react";
87751
+ import { useCallback as useCallback154, useEffect as useEffect127, useRef as useRef158 } from "react";
87767
87752
 
87768
87753
  // src/hooks/appHotkeysDispatch.ts
87769
87754
  function handleUndoRedoKey(event, onUndo, onRedo) {
@@ -88186,7 +88171,7 @@ function useAppHotkeys({
88186
88171
  }
88187
88172
  dispatchPlainKey(event, key2, cb);
88188
88173
  }, []);
88189
- useEffect128(() => {
88174
+ useEffect127(() => {
88190
88175
  window.addEventListener("keydown", handleAppKeyDown, true);
88191
88176
  return () => window.removeEventListener("keydown", handleAppKeyDown, true);
88192
88177
  }, [handleAppKeyDown]);
@@ -88202,7 +88187,7 @@ function useAppHotkeys({
88202
88187
  },
88203
88188
  [handleAppKeyDown]
88204
88189
  );
88205
- useEffect128(
88190
+ useEffect127(
88206
88191
  () => () => {
88207
88192
  previewHistoryCleanupRef.current?.();
88208
88193
  previewHistoryCleanupRef.current = null;
@@ -88729,7 +88714,7 @@ function useClipboard({
88729
88714
  }
88730
88715
 
88731
88716
  // src/hooks/useCaptionDetection.ts
88732
- import { useEffect as useEffect129, useRef as useRef160 } from "react";
88717
+ import { useEffect as useEffect128, useRef as useRef160 } from "react";
88733
88718
 
88734
88719
  // src/captions/types.ts
88735
88720
  var DEFAULT_STYLE = {
@@ -88983,7 +88968,7 @@ function useCaptionDetection({
88983
88968
  }) {
88984
88969
  const livePreviewIframe = useLivePreviewIframe();
88985
88970
  const prevCompPathRef = useRef160(activeCompPath);
88986
- useEffect129(() => {
88971
+ useEffect128(() => {
88987
88972
  if (prevCompPathRef.current !== activeCompPath) {
88988
88973
  prevCompPathRef.current = activeCompPath;
88989
88974
  const store = useCaptionStore.getState();
@@ -88993,7 +88978,7 @@ function useCaptionDetection({
88993
88978
  }
88994
88979
  }
88995
88980
  }, [activeCompPath]);
88996
- useEffect129(() => {
88981
+ useEffect128(() => {
88997
88982
  if (!projectId) return;
88998
88983
  let activating = false;
88999
88984
  const tryActivateCaptions = () => {
@@ -89075,7 +89060,7 @@ function useCaptionDetection({
89075
89060
  window.removeEventListener("message", handleMessage);
89076
89061
  };
89077
89062
  }, [activeCompPath, projectId, compIdToSrc, captionSync, previewIframeRef, livePreviewIframe]);
89078
- useEffect129(() => {
89063
+ useEffect128(() => {
89079
89064
  if (captionEditMode) {
89080
89065
  setRightCollapsed(!captionHasSelection);
89081
89066
  }
@@ -89083,7 +89068,7 @@ function useCaptionDetection({
89083
89068
  }
89084
89069
 
89085
89070
  // src/hooks/useConsoleErrorCapture.ts
89086
- import { useCallback as useCallback156, useEffect as useEffect130, useRef as useRef161, useState as useState128 } from "react";
89071
+ import { useCallback as useCallback156, useEffect as useEffect129, useRef as useRef161, useState as useState128 } from "react";
89087
89072
  import { STUDIO_PREVIEW_ERRORS } from "@hyperframes/core/studio-preview-mark";
89088
89073
  function useConsoleErrorCapture(previewIframe) {
89089
89074
  const [consoleErrors, setConsoleErrors] = useState128(null);
@@ -89092,7 +89077,7 @@ function useConsoleErrorCapture(previewIframe) {
89092
89077
  consoleErrorsRef.current = [];
89093
89078
  setConsoleErrors(null);
89094
89079
  }, []);
89095
- useEffect130(() => {
89080
+ useEffect129(() => {
89096
89081
  resetErrors();
89097
89082
  if (!previewIframe) return;
89098
89083
  let patchedWin = null;
@@ -89263,7 +89248,7 @@ function useFrameCapture({
89263
89248
  }
89264
89249
 
89265
89250
  // src/hooks/useLintModal.ts
89266
- import { useState as useState130, useCallback as useCallback158, useEffect as useEffect131, useRef as useRef163, useMemo as useMemo78 } from "react";
89251
+ import { useState as useState130, useCallback as useCallback158, useEffect as useEffect130, useRef as useRef163, useMemo as useMemo78 } from "react";
89267
89252
  function parseFinding(f) {
89268
89253
  return {
89269
89254
  severity: f.severity === "error" ? "error" : "warning",
@@ -89306,7 +89291,7 @@ function useLintModal(projectId, refreshKey) {
89306
89291
  }
89307
89292
  }, [projectId]);
89308
89293
  const prevProjectIdRef = useRef163(projectId);
89309
- useEffect131(() => {
89294
+ useEffect130(() => {
89310
89295
  if (projectId !== prevProjectIdRef.current) {
89311
89296
  autoLintRanRef.current = false;
89312
89297
  prevProjectIdRef.current = projectId;
@@ -89315,7 +89300,7 @@ function useLintModal(projectId, refreshKey) {
89315
89300
  autoLintRanRef.current = true;
89316
89301
  void runBackgroundLint();
89317
89302
  }, [projectId, runBackgroundLint]);
89318
- useEffect131(() => {
89303
+ useEffect130(() => {
89319
89304
  if (!projectId || !refreshKey) return;
89320
89305
  const timer = setTimeout(() => void runBackgroundLint(), 1e3);
89321
89306
  return () => clearTimeout(timer);
@@ -89341,7 +89326,7 @@ function useLintModal(projectId, refreshKey) {
89341
89326
  const badgeFindings = lintModal ?? backgroundFindings;
89342
89327
  const lintFindingCount = badgeFindings.length;
89343
89328
  const hasLintError = badgeFindings.some((f) => f.severity === "error");
89344
- useEffect131(() => {
89329
+ useEffect130(() => {
89345
89330
  usePlayerStore.getState().setLintFindingsByElement(findingsByElement);
89346
89331
  }, [findingsByElement]);
89347
89332
  return {
@@ -89416,7 +89401,7 @@ function useToast() {
89416
89401
  }
89417
89402
 
89418
89403
  // src/hooks/useStudioUrlState.ts
89419
- import { useCallback as useCallback160, useEffect as useEffect132, useRef as useRef165, useState as useState132 } from "react";
89404
+ import { useCallback as useCallback160, useEffect as useEffect131, useRef as useRef165, useState as useState132 } from "react";
89420
89405
 
89421
89406
  // src/utils/studioUrlState.ts
89422
89407
  var VALID_TABS = ["layers", "design", "renders", "slideshow", "variables"];
@@ -89720,7 +89705,7 @@ function useStudioUrlState({
89720
89705
  previewIframeRef
89721
89706
  ]
89722
89707
  );
89723
- useEffect132(() => {
89708
+ useEffect131(() => {
89724
89709
  if (!projectId || hydratedSeekRef.current || compositionLoading) return;
89725
89710
  const nextTime = duration > 0 ? clampNumber(initialState2.currentTime ?? 0, 0, duration) : Math.max(0, initialState2.currentTime ?? 0);
89726
89711
  usePlayerStore.getState().requestSeek(nextTime);
@@ -89728,7 +89713,7 @@ function useStudioUrlState({
89728
89713
  hydratedSeekRef.current = true;
89729
89714
  }, [projectId, compositionLoading, duration, initialState2.currentTime]);
89730
89715
  const selectionHydrationTime = selectionHydrated ? 0 : currentTime;
89731
- useEffect132(() => {
89716
+ useEffect131(() => {
89732
89717
  if (!projectId || hydratedSelectionRef.current || compositionLoading) return;
89733
89718
  if (!hydratedSeekRef.current) return;
89734
89719
  const targetTime = initialState2.currentTime;
@@ -89755,7 +89740,7 @@ function useStudioUrlState({
89755
89740
  projectId,
89756
89741
  refreshKey
89757
89742
  ]);
89758
- useEffect132(() => {
89743
+ useEffect131(() => {
89759
89744
  if (hydratedInitialTimeRef.current) return;
89760
89745
  const targetTime = stableTimeRef.current;
89761
89746
  if (targetTime == null) {
@@ -89765,7 +89750,7 @@ function useStudioUrlState({
89765
89750
  if (Math.abs(currentTime - targetTime) > 0.05) return;
89766
89751
  hydratedInitialTimeRef.current = true;
89767
89752
  }, [currentTime]);
89768
- useEffect132(() => {
89753
+ useEffect131(() => {
89769
89754
  if (!activeCompPathHydrated) return;
89770
89755
  if (!hydratedSeekRef.current) return;
89771
89756
  if (!hydratedInitialTimeRef.current) return;
@@ -89776,12 +89761,12 @@ function useStudioUrlState({
89776
89761
  }, 200);
89777
89762
  return () => window.clearTimeout(handle);
89778
89763
  }, [activeCompPathHydrated, buildUrlState, currentTime, duration, isPlaying, projectId]);
89779
- useEffect132(() => {
89764
+ useEffect131(() => {
89780
89765
  if (!activeCompPathHydrated) return;
89781
89766
  if (!projectId) return;
89782
89767
  replaceHash(buildStudioHash(projectId, buildUrlState()));
89783
89768
  }, [activeCompPathHydrated, buildUrlState, projectId]);
89784
- useEffect132(() => {
89769
+ useEffect131(() => {
89785
89770
  if (!projectId) return;
89786
89771
  const onHashChange = () => {
89787
89772
  if (parseProjectIdFromHash(window.location.hash) !== projectId) return;
@@ -89928,7 +89913,7 @@ function InspectorIcon({ size = 16 }) {
89928
89913
  }
89929
89914
 
89930
89915
  // src/components/OpenInDesktopButton.tsx
89931
- import { useEffect as useEffect133, useRef as useRef166, useState as useState133 } from "react";
89916
+ import { useEffect as useEffect132, useRef as useRef166, useState as useState133 } from "react";
89932
89917
 
89933
89918
  // src/components/FrameyGlyph.tsx
89934
89919
  import { jsx as jsx206, jsxs as jsxs161 } from "react/jsx-runtime";
@@ -89991,7 +89976,7 @@ var GAZE = 2.2;
89991
89976
  var OPENING_MS = 1600;
89992
89977
  function useDesktopRoute() {
89993
89978
  const [route, setRoute] = useState133(null);
89994
- useEffect133(() => {
89979
+ useEffect132(() => {
89995
89980
  let live = true;
89996
89981
  studioApiFetch(ROUTE).then((res) => res.ok ? res.json() : null).then((body) => {
89997
89982
  if (!live || body?.available !== true) return;
@@ -90007,7 +89992,7 @@ function useDesktopRoute() {
90007
89992
  return route;
90008
89993
  }
90009
89994
  function useGaze(anchor2, eye) {
90010
- useEffect133(() => {
89995
+ useEffect132(() => {
90011
89996
  let frame3 = 0;
90012
89997
  const look = (event) => {
90013
89998
  cancelAnimationFrame(frame3);
@@ -90358,10 +90343,10 @@ var StudioHeader = memo45(function StudioHeader2({
90358
90343
  });
90359
90344
 
90360
90345
  // src/hooks/useGestureCommit.ts
90361
- import { useState as useState135, useCallback as useCallback163, useRef as useRef168, useEffect as useEffect135 } from "react";
90346
+ import { useState as useState135, useCallback as useCallback163, useRef as useRef168, useEffect as useEffect134 } from "react";
90362
90347
 
90363
90348
  // src/hooks/useGestureRecording.ts
90364
- import { useCallback as useCallback162, useEffect as useEffect134, useRef as useRef167, useState as useState134 } from "react";
90349
+ import { useCallback as useCallback162, useEffect as useEffect133, useRef as useRef167, useState as useState134 } from "react";
90365
90350
  function readBasePosition(element, iframeEl) {
90366
90351
  let baseOpacity = 1;
90367
90352
  let baseScale = 1;
@@ -90509,7 +90494,7 @@ function useGestureRecording() {
90509
90494
  const refs = useRef167(createRecordingRefs());
90510
90495
  const samplesRef = useRef167(refs.current.samples);
90511
90496
  const trailRef = useRef167(refs.current.trail);
90512
- useEffect134(() => {
90497
+ useEffect133(() => {
90513
90498
  const r = refs.current;
90514
90499
  return () => {
90515
90500
  isRecordingRef.current = false;
@@ -90900,7 +90885,7 @@ function useGestureCommit({
90900
90885
  const commitInFlightRef = useRef168(false);
90901
90886
  const capturedSelectionRef = useRef168(null);
90902
90887
  const capturedAnimationsRef = useRef168([]);
90903
- useEffect135(() => () => clearInterval(recordingAutoStopRef.current), []);
90888
+ useEffect134(() => () => clearInterval(recordingAutoStopRef.current), []);
90904
90889
  const cancelRecording = useCallback163(() => {
90905
90890
  clearInterval(recordingAutoStopRef.current);
90906
90891
  gestureRecording.stopRecording();
@@ -90910,7 +90895,7 @@ function useGestureCommit({
90910
90895
  capturedSelectionRef.current = null;
90911
90896
  setGestureState("idle");
90912
90897
  }, [gestureRecording, isGestureRecordingRef]);
90913
- useEffect135(() => {
90898
+ useEffect134(() => {
90914
90899
  if (readOnlyPreview && gestureStateRef.current === "recording") cancelRecording();
90915
90900
  }, [cancelRecording, readOnlyPreview]);
90916
90901
  const stopAndCommitRecording = useCallback163(async () => {
@@ -91433,7 +91418,7 @@ function MediaPreview({ projectId, filePath }) {
91433
91418
  }
91434
91419
 
91435
91420
  // src/components/sidebar/AssetsTab.tsx
91436
- import { memo as memo47, useState as useState142, useCallback as useCallback167, useRef as useRef173, useMemo as useMemo84, useEffect as useEffect141 } from "react";
91421
+ import { memo as memo47, useState as useState142, useCallback as useCallback167, useRef as useRef173, useMemo as useMemo84, useEffect as useEffect140 } from "react";
91437
91422
 
91438
91423
  // src/components/ui/SearchInput.tsx
91439
91424
  import { jsx as jsx213, jsxs as jsxs167 } from "react/jsx-runtime";
@@ -91544,11 +91529,11 @@ var CATEGORY_LABELS = {
91544
91529
  var FILTER_ORDER = ["audio", "images", "video", "fonts"];
91545
91530
 
91546
91531
  // src/components/sidebar/AudioRow.tsx
91547
- import { useState as useState138, useRef as useRef171, useEffect as useEffect137, useCallback as useCallback165 } from "react";
91532
+ import { useState as useState138, useRef as useRef171, useEffect as useEffect136, useCallback as useCallback165 } from "react";
91548
91533
  import { classifyWebAudioMediaRoute } from "@hyperframes/core/runtime/web-audio-route";
91549
91534
 
91550
91535
  // src/components/sidebar/AssetContextMenu.tsx
91551
- import { useCallback as useCallback164, useEffect as useEffect136, useLayoutEffect as useLayoutEffect14, useRef as useRef170, useState as useState137 } from "react";
91536
+ import { useCallback as useCallback164, useEffect as useEffect135, useLayoutEffect as useLayoutEffect14, useRef as useRef170, useState as useState137 } from "react";
91552
91537
  import { Fragment as Fragment59, jsx as jsx214, jsxs as jsxs168 } from "react/jsx-runtime";
91553
91538
  function isValidAssetName(name) {
91554
91539
  return name.length > 0 && !/[/\\]/.test(name) && !name.includes("..");
@@ -91578,7 +91563,7 @@ function ContextMenu3({
91578
91563
  y: Math.min(y, window.innerHeight - rect.height - margin)
91579
91564
  });
91580
91565
  }, [x, y, mode]);
91581
- useEffect136(() => {
91566
+ useEffect135(() => {
91582
91567
  const onKeyDown = (e) => {
91583
91568
  if (e.key === "Escape") {
91584
91569
  e.stopPropagation();
@@ -91603,7 +91588,7 @@ function ContextMenu3({
91603
91588
  document.addEventListener("keydown", onKeyDown, true);
91604
91589
  return () => document.removeEventListener("keydown", onKeyDown, true);
91605
91590
  }, [mode, onClose]);
91606
- useEffect136(() => {
91591
+ useEffect135(() => {
91607
91592
  if (mode === "menu") {
91608
91593
  menuRef.current?.querySelector('[role="menuitem"]')?.focus();
91609
91594
  }
@@ -91870,7 +91855,7 @@ function AudioRow({
91870
91855
  },
91871
91856
  [activateRow]
91872
91857
  );
91873
- useEffect137(() => {
91858
+ useEffect136(() => {
91874
91859
  return () => {
91875
91860
  cancelAnimationFrame(animRef.current);
91876
91861
  audioRef.current?.pause();
@@ -91878,7 +91863,7 @@ function AudioRow({
91878
91863
  if (stopCurrentPreview === stopPlayback) stopCurrentPreview = null;
91879
91864
  };
91880
91865
  }, [stopPlayback]);
91881
- useEffect137(() => {
91866
+ useEffect136(() => {
91882
91867
  if (playing) {
91883
91868
  const barCount = 24;
91884
91869
  const loop = () => {
@@ -92045,7 +92030,7 @@ function AudioRow({
92045
92030
  }
92046
92031
 
92047
92032
  // src/components/sidebar/GlobalAssetsView.tsx
92048
- import { useEffect as useEffect138, useMemo as useMemo83, useState as useState139 } from "react";
92033
+ import { useEffect as useEffect137, useMemo as useMemo83, useState as useState139 } from "react";
92049
92034
  import { jsx as jsx216, jsxs as jsxs170 } from "react/jsx-runtime";
92050
92035
  function globalAssetRows(records, query = "") {
92051
92036
  const q = query.trim().toLowerCase();
@@ -92061,7 +92046,7 @@ function globalAssetRows(records, query = "") {
92061
92046
  }
92062
92047
  function GlobalAssetsView({ searchQuery }) {
92063
92048
  const [records, setRecords] = useState139(null);
92064
- useEffect138(() => {
92049
+ useEffect137(() => {
92065
92050
  let cancelled = false;
92066
92051
  studioApiFetch("/api/assets/global").then((r) => r.ok ? r.json() : { assets: [] }).then((d) => {
92067
92052
  if (!cancelled) setRecords(Array.isArray(d.assets) ? d.assets : []);
@@ -92104,10 +92089,10 @@ function GlobalAssetsView({ searchQuery }) {
92104
92089
  }
92105
92090
 
92106
92091
  // src/components/sidebar/AssetCard.tsx
92107
- import { useState as useState141, useEffect as useEffect140, useRef as useRef172, useCallback as useCallback166 } from "react";
92092
+ import { useState as useState141, useEffect as useEffect139, useRef as useRef172, useCallback as useCallback166 } from "react";
92108
92093
 
92109
92094
  // src/components/ui/VideoFrameThumbnail.tsx
92110
- import { useState as useState140, useEffect as useEffect139 } from "react";
92095
+ import { useState as useState140, useEffect as useEffect138 } from "react";
92111
92096
  import { jsx as jsx217 } from "react/jsx-runtime";
92112
92097
  function VideoFrameThumbnail({
92113
92098
  src,
@@ -92115,7 +92100,7 @@ function VideoFrameThumbnail({
92115
92100
  }) {
92116
92101
  const [frame3, setFrame] = useState140(null);
92117
92102
  const [failed2, setFailed] = useState140(false);
92118
- useEffect139(() => {
92103
+ useEffect138(() => {
92119
92104
  setFailed(false);
92120
92105
  const video = document.createElement("video");
92121
92106
  video.crossOrigin = "anonymous";
@@ -92182,7 +92167,7 @@ function openAssetContextMenu(e, setContextMenu) {
92182
92167
  }
92183
92168
  function useProbedDuration(src, skip) {
92184
92169
  const [duration, setDuration] = useState141(void 0);
92185
- useEffect140(() => {
92170
+ useEffect139(() => {
92186
92171
  if (skip) return;
92187
92172
  let cancelled = false;
92188
92173
  let retryTimer;
@@ -92581,7 +92566,7 @@ var AssetsTab = memo47(function AssetsTab2({
92581
92566
  const [manifest, setManifest] = useState142(/* @__PURE__ */ new Map());
92582
92567
  const manifest404Ref = useRef173(/* @__PURE__ */ new Set());
92583
92568
  const assetsKey = assets.join("|");
92584
- useEffect141(() => {
92569
+ useEffect140(() => {
92585
92570
  if (manifest404Ref.current.has(projectId)) return;
92586
92571
  let cancelled = false;
92587
92572
  studioApiFetch(buildProjectApiPath(projectId, `/preview/.media/manifest.jsonl`)).then((r) => {
@@ -92838,11 +92823,11 @@ var AssetsTab = memo47(function AssetsTab2({
92838
92823
  });
92839
92824
 
92840
92825
  // src/components/sidebar/BlocksTab.tsx
92841
- import { memo as memo48, useState as useState144, useCallback as useCallback169, useRef as useRef175, useEffect as useEffect143 } from "react";
92826
+ import { memo as memo48, useState as useState144, useCallback as useCallback169, useRef as useRef175, useEffect as useEffect142 } from "react";
92842
92827
  import { createPortal as createPortal13 } from "react-dom";
92843
92828
 
92844
92829
  // src/components/sidebar/PromptPreviewModal.tsx
92845
- import { useState as useState143, useCallback as useCallback168, useEffect as useEffect142, useRef as useRef174 } from "react";
92830
+ import { useState as useState143, useCallback as useCallback168, useEffect as useEffect141, useRef as useRef174 } from "react";
92846
92831
  import { jsx as jsx220, jsxs as jsxs173 } from "react/jsx-runtime";
92847
92832
  function PromptPreviewModal({
92848
92833
  title,
@@ -92862,7 +92847,7 @@ function PromptPreviewModal({
92862
92847
  containerRef,
92863
92848
  canClose: () => valueRef.current === prompt
92864
92849
  });
92865
- useEffect142(() => {
92850
+ useEffect141(() => {
92866
92851
  requestAnimationFrame(() => {
92867
92852
  setEntered(true);
92868
92853
  textareaRef.current?.focus();
@@ -93168,7 +93153,7 @@ function BlockCard({
93168
93153
  setHovered(false);
93169
93154
  onPreview?.(null);
93170
93155
  }, [onPreview]);
93171
- useEffect143(() => {
93156
+ useEffect142(() => {
93172
93157
  return () => {
93173
93158
  if (hoverTimer.current) clearTimeout(hoverTimer.current);
93174
93159
  };
@@ -93329,7 +93314,7 @@ function BlockCard({
93329
93314
  }
93330
93315
 
93331
93316
  // src/components/sidebar/CompositionsTab.tsx
93332
- import { memo as memo49, useCallback as useCallback170, useEffect as useEffect144, useLayoutEffect as useLayoutEffect15, useMemo as useMemo85, useRef as useRef176, useState as useState145 } from "react";
93317
+ import { memo as memo49, useCallback as useCallback170, useEffect as useEffect143, useLayoutEffect as useLayoutEffect15, useMemo as useMemo85, useRef as useRef176, useState as useState145 } from "react";
93333
93318
  import { jsx as jsx222, jsxs as jsxs175 } from "react/jsx-runtime";
93334
93319
  var DEFAULT_PREVIEW_STAGE = { width: 1920, height: 1080 };
93335
93320
  var CARD_W = 80;
@@ -93408,7 +93393,7 @@ function useLastFrame(request2, snapshot3) {
93408
93393
  function useNearViewport() {
93409
93394
  const [element, setElement] = useState145(null);
93410
93395
  const [near4, setNear] = useState145(false);
93411
- useEffect144(() => {
93396
+ useEffect143(() => {
93412
93397
  if (!element || near4) return;
93413
93398
  if (typeof IntersectionObserver === "undefined") return setNear(true);
93414
93399
  const observer = new IntersectionObserver(
@@ -93489,13 +93474,13 @@ function CompCard({
93489
93474
  });
93490
93475
  const thumbnailOffsetX = (CARD_W - stageSize.width * previewScale) / 2;
93491
93476
  const thumbnailOffsetY = (CARD_H - stageSize.height * previewScale) / 2;
93492
- useEffect144(() => {
93477
+ useEffect143(() => {
93493
93478
  if (hovered) requestIframePlaybackSync(true);
93494
93479
  }, [hovered, requestIframePlaybackSync]);
93495
- useEffect144(() => {
93480
+ useEffect143(() => {
93496
93481
  if (livePreviewLoaded) postFrameDisplayScale(iframeRef.current);
93497
93482
  }, [livePreviewLoaded, previewScale]);
93498
- useEffect144(() => {
93483
+ useEffect143(() => {
93499
93484
  if (!hovered) return;
93500
93485
  const onRuntimeReady = (event) => {
93501
93486
  const frame3 = iframeRef.current;
@@ -93506,7 +93491,7 @@ function CompCard({
93506
93491
  window.addEventListener("message", onRuntimeReady);
93507
93492
  return () => window.removeEventListener("message", onRuntimeReady);
93508
93493
  }, [hovered]);
93509
- useEffect144(() => {
93494
+ useEffect143(() => {
93510
93495
  return () => {
93511
93496
  if (hoverTimer.current) clearTimeout(hoverTimer.current);
93512
93497
  if (syncTimer.current) clearTimeout(syncTimer.current);
@@ -93948,7 +93933,7 @@ function CodeBody({
93948
93933
  import { memo as memo60, useCallback as useCallback188 } from "react";
93949
93934
 
93950
93935
  // src/components/editor/LayersPanel.tsx
93951
- import { memo as memo51, useState as useState147, useCallback as useCallback173, useEffect as useEffect145, useRef as useRef178 } from "react";
93936
+ import { memo as memo51, useState as useState147, useCallback as useCallback173, useEffect as useEffect144, useRef as useRef178 } from "react";
93952
93937
 
93953
93938
  // src/components/editor/layerKind.ts
93954
93939
  function isCompositionHost(el) {
@@ -94267,10 +94252,10 @@ var LayersPanel = memo51(function LayersPanel2({ host }) {
94267
94252
  );
94268
94253
  setLayers(sortLayersByZIndex(items));
94269
94254
  }, [previewIframeRef, activeCompPath, isMasterView, activeGroupElement, setActiveGroupElement]);
94270
- useEffect145(() => {
94255
+ useEffect144(() => {
94271
94256
  collectLayers();
94272
94257
  }, [collectLayers, refreshKey, zEditVersion, livePreviewIframe]);
94273
- useEffect145(() => {
94258
+ useEffect144(() => {
94274
94259
  const iframe = previewIframeRef.current;
94275
94260
  if (!iframe) return;
94276
94261
  const handleLoad = () => {
@@ -94279,13 +94264,13 @@ var LayersPanel = memo51(function LayersPanel2({ host }) {
94279
94264
  };
94280
94265
  return onPreviewContentReplaced(iframe, handleLoad);
94281
94266
  }, [previewIframeRef, livePreviewIframe, collectLayers]);
94282
- useEffect145(() => {
94267
+ useEffect144(() => {
94283
94268
  if (!compositionLoading) {
94284
94269
  const timer = setTimeout(collectLayers, 100);
94285
94270
  return () => clearTimeout(timer);
94286
94271
  }
94287
94272
  }, [compositionLoading, collectLayers]);
94288
- useEffect145(() => {
94273
+ useEffect144(() => {
94289
94274
  const throttle = createRafThrottle(collectLayers, 100);
94290
94275
  const unsubscribe = liveTime.subscribe(throttle.invoke);
94291
94276
  return () => {
@@ -94578,7 +94563,7 @@ import { memo as memo53, useCallback as useCallback175, useState as useState149
94578
94563
  import { memo as memo52, useCallback as useCallback174 } from "react";
94579
94564
 
94580
94565
  // src/captions/components/shared.tsx
94581
- import { useEffect as useEffect146, useRef as useRef179, useState as useState148 } from "react";
94566
+ import { useEffect as useEffect145, useRef as useRef179, useState as useState148 } from "react";
94582
94567
  import { jsx as jsx227, jsxs as jsxs179 } from "react/jsx-runtime";
94583
94568
  var inputCls = "w-full bg-neutral-900 border border-neutral-800 rounded-sm px-1.5 py-0.5 text-2xs text-neutral-200 font-mono outline-hidden focus:border-studio-accent disabled:opacity-40 disabled:cursor-not-allowed";
94584
94569
  function Section2({ label, children }) {
@@ -94605,7 +94590,7 @@ function NumberField2({
94605
94590
  }) {
94606
94591
  const [draft, setDraft] = useState148(null);
94607
94592
  const focusedRef = useRef179(false);
94608
- useEffect146(() => {
94593
+ useEffect145(() => {
94609
94594
  if (!focusedRef.current) setDraft(null);
94610
94595
  }, [value]);
94611
94596
  const display2 = draft !== null ? draft : mixed ? "" : String(value ?? 0);
@@ -95097,7 +95082,7 @@ var CaptionPropertyPanel = memo53(function CaptionPropertyPanel2({
95097
95082
  });
95098
95083
 
95099
95084
  // src/components/editor/BlockParamsPanel.tsx
95100
- import { memo as memo54, useCallback as useCallback176, useEffect as useEffect147, useRef as useRef180, useState as useState150 } from "react";
95085
+ import { memo as memo54, useCallback as useCallback176, useEffect as useEffect146, useRef as useRef180, useState as useState150 } from "react";
95101
95086
  import { jsx as jsx230, jsxs as jsxs182 } from "react/jsx-runtime";
95102
95087
  var BlockParamsPanel = memo54(function BlockParamsPanel2({
95103
95088
  blockName,
@@ -95199,7 +95184,7 @@ var BlockParamsPanel = memo54(function BlockParamsPanel2({
95199
95184
  }
95200
95185
  commitTimersRef.current.clear();
95201
95186
  };
95202
- useEffect147(() => () => flushRef.current(), []);
95187
+ useEffect146(() => () => flushRef.current(), []);
95203
95188
  return /* @__PURE__ */ jsxs182("div", { className: "flex flex-col h-full", children: [
95204
95189
  /* @__PURE__ */ jsxs182("div", { className: "flex items-center justify-between px-3 py-2 border-b border-neutral-800", children: [
95205
95190
  /* @__PURE__ */ jsx230("div", { className: "text-[11px] font-semibold text-neutral-200 truncate", children: blockTitle }),
@@ -95331,7 +95316,7 @@ function ParamControl({
95331
95316
  import { memo as memo58 } from "react";
95332
95317
 
95333
95318
  // src/components/renders/RenderQueue.tsx
95334
- import { memo as memo57, useState as useState153, useRef as useRef182, useEffect as useEffect149, useLayoutEffect as useLayoutEffect16, useId as useId5 } from "react";
95319
+ import { memo as memo57, useState as useState153, useRef as useRef182, useEffect as useEffect148, useLayoutEffect as useLayoutEffect16, useId as useId4 } from "react";
95335
95320
  import { createPortal as createPortal14 } from "react-dom";
95336
95321
  import { CANVAS_DIMENSIONS } from "@hyperframes/parsers";
95337
95322
 
@@ -95562,7 +95547,7 @@ var RenderQueueItem = memo55(function RenderQueueItem2({
95562
95547
  });
95563
95548
 
95564
95549
  // src/components/renders/FfmpegRequiredNotice.tsx
95565
- import { memo as memo56, useEffect as useEffect148, useRef as useRef181, useState as useState152 } from "react";
95550
+ import { memo as memo56, useEffect as useEffect147, useRef as useRef181, useState as useState152 } from "react";
95566
95551
  import { jsx as jsx232, jsxs as jsxs184 } from "react/jsx-runtime";
95567
95552
  var DOWNLOAD_URL = "https://ffmpeg.org/download.html";
95568
95553
  var CUE_MS = 1600;
@@ -95576,16 +95561,16 @@ var FfmpegRequiredNotice = memo56(function FfmpegRequiredNotice2({
95576
95561
  const [recheckFailed, setRecheckFailed] = useState152(false);
95577
95562
  const wasChecking = useRef181(false);
95578
95563
  const cueTimer = useRef181(void 0);
95579
- useEffect148(() => {
95564
+ useEffect147(() => {
95580
95565
  if (wasChecking.current && !checking) setRecheckFailed(true);
95581
95566
  wasChecking.current = checking;
95582
95567
  }, [checking]);
95583
- useEffect148(() => {
95568
+ useEffect147(() => {
95584
95569
  if (!recheckFailed) return;
95585
95570
  cueTimer.current = setTimeout(() => setRecheckFailed(false), CUE_MS);
95586
95571
  return () => clearTimeout(cueTimer.current);
95587
95572
  }, [recheckFailed]);
95588
- useEffect148(() => () => clearTimeout(cueTimer.current), []);
95573
+ useEffect147(() => () => clearTimeout(cueTimer.current), []);
95589
95574
  const copy = async (command) => {
95590
95575
  const ok = await copyTextToClipboard(command);
95591
95576
  if (!ok) return;
@@ -95737,7 +95722,7 @@ function FormatInfoTooltip({ format }) {
95737
95722
  const [position, setPosition] = useState153(null);
95738
95723
  const triggerRef = useRef182(null);
95739
95724
  const timeoutRef = useRef182(void 0);
95740
- const panelId = useId5();
95725
+ const panelId = useId4();
95741
95726
  const show = () => {
95742
95727
  clearTimeout(timeoutRef.current);
95743
95728
  setOpen(true);
@@ -95745,7 +95730,7 @@ function FormatInfoTooltip({ format }) {
95745
95730
  const hide = () => {
95746
95731
  timeoutRef.current = setTimeout(() => setOpen(false), 120);
95747
95732
  };
95748
- useEffect149(() => () => clearTimeout(timeoutRef.current), []);
95733
+ useEffect148(() => () => clearTimeout(timeoutRef.current), []);
95749
95734
  useLayoutEffect16(() => {
95750
95735
  if (!open) return;
95751
95736
  const el = triggerRef.current;
@@ -95759,7 +95744,7 @@ function FormatInfoTooltip({ format }) {
95759
95744
  )
95760
95745
  );
95761
95746
  }, [open]);
95762
- useEffect149(() => {
95747
+ useEffect148(() => {
95763
95748
  if (!open) return;
95764
95749
  const onKeyDown = (e) => {
95765
95750
  if (e.key === "Escape") setOpen(false);
@@ -95999,7 +95984,7 @@ var RenderQueue = memo57(function RenderQueue2({
95999
95984
  onRecheckFfmpeg
96000
95985
  }) {
96001
95986
  const listRef = useRef182(null);
96002
- useEffect149(() => {
95987
+ useEffect148(() => {
96003
95988
  if (listRef.current) {
96004
95989
  listRef.current.scrollTo({ top: listRef.current.scrollHeight, behavior: "smooth" });
96005
95990
  }
@@ -96154,11 +96139,11 @@ var RenderQueuePanel = memo58(function RenderQueuePanel2() {
96154
96139
  });
96155
96140
 
96156
96141
  // src/components/panels/SlideshowPanel.tsx
96157
- import { useState as useState155, useEffect as useEffect150, useCallback as useCallback179, useRef as useRef183 } from "react";
96142
+ import { useState as useState155, useEffect as useEffect149, useCallback as useCallback179, useRef as useRef183 } from "react";
96158
96143
  import { parseSlideshowManifest } from "@hyperframes/core/slideshow";
96159
96144
 
96160
96145
  // src/components/panels/SlideshowSubPanels.tsx
96161
- import { useState as useState154, useCallback as useCallback178, useId as useId6 } from "react";
96146
+ import { useState as useState154, useCallback as useCallback178, useId as useId5 } from "react";
96162
96147
  import { jsx as jsx236, jsxs as jsxs187 } from "react/jsx-runtime";
96163
96148
  function SectionHeader({
96164
96149
  children,
@@ -96345,7 +96330,7 @@ function BranchTree({
96345
96330
  onSelectBranchSlide
96346
96331
  }) {
96347
96332
  const [newLabel, setNewLabel] = useState154("");
96348
- const inputId = useId6();
96333
+ const inputId = useId5();
96349
96334
  const handleCreate = useCallback178(() => {
96350
96335
  const label = newLabel.trim();
96351
96336
  if (!label) return;
@@ -96850,7 +96835,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
96850
96835
  const { domEditSelection } = useDomEditSelectionContext();
96851
96836
  const manifestRef = useRef183(manifest);
96852
96837
  const notesCtrlRef = useRef183(makeSlideshowNotesController());
96853
- useEffect150(() => {
96838
+ useEffect149(() => {
96854
96839
  if (!compHtml) {
96855
96840
  notesCtrlRef.current.flush();
96856
96841
  setManifest({ slides: [] });
@@ -96912,7 +96897,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
96912
96897
  },
96913
96898
  [onPersistNotes]
96914
96899
  );
96915
- useEffect150(() => {
96900
+ useEffect149(() => {
96916
96901
  const ctrl = notesCtrlRef.current;
96917
96902
  return () => {
96918
96903
  ctrl.flush();
@@ -97171,7 +97156,7 @@ function SlideshowPanel({ scenes, onPersist, onPersistNotes }) {
97171
97156
  }
97172
97157
 
97173
97158
  // src/components/panels/VariablesPanel.tsx
97174
- import { memo as memo59, useCallback as useCallback183, useEffect as useEffect152, useMemo as useMemo86, useState as useState159 } from "react";
97159
+ import { memo as memo59, useCallback as useCallback183, useEffect as useEffect151, useMemo as useMemo86, useState as useState159 } from "react";
97175
97160
 
97176
97161
  // src/hooks/useVariablesPersist.ts
97177
97162
  import { useCallback as useCallback180 } from "react";
@@ -97222,7 +97207,7 @@ function useVariablesPersist({
97222
97207
  import { useCallback as useCallback182, useState as useState158 } from "react";
97223
97208
 
97224
97209
  // src/hooks/useProjectCompositionVariables.ts
97225
- import { useCallback as useCallback181, useEffect as useEffect151, useState as useState156 } from "react";
97210
+ import { useCallback as useCallback181, useEffect as useEffect150, useState as useState156 } from "react";
97226
97211
  import { openComposition as openComposition4 } from "@hyperframes/sdk";
97227
97212
  async function readGroup(path, readProjectFile) {
97228
97213
  let content;
@@ -97246,7 +97231,7 @@ async function readGroup(path, readProjectFile) {
97246
97231
  }
97247
97232
  function useProjectCompositionVariables(compositionPaths, excludePath, readProjectFile, refreshKey) {
97248
97233
  const [groups, setGroups] = useState156([]);
97249
- useEffect151(() => {
97234
+ useEffect150(() => {
97250
97235
  let cancelled = false;
97251
97236
  const htmlFiles = compositionPaths.filter((p) => p !== excludePath);
97252
97237
  void (async () => {
@@ -97852,7 +97837,7 @@ var VariablesPanel = memo59(function VariablesPanel2({
97852
97837
  const previewValues = usePreviewVariablesStore((s) => s.values);
97853
97838
  const setPreviewValues = usePreviewVariablesStore((s) => s.setValues);
97854
97839
  const [revision, setRevision] = useState159(0);
97855
- useEffect152(() => {
97840
+ useEffect151(() => {
97856
97841
  if (!sdkSession) return;
97857
97842
  return sdkSession.on("change", () => setRevision((r) => r + 1));
97858
97843
  }, [sdkSession]);
@@ -98266,7 +98251,7 @@ function DesignPanelPromoteProvider({
98266
98251
  }
98267
98252
 
98268
98253
  // src/hooks/useRemoveBackground.ts
98269
- import { useCallback as useCallback186, useEffect as useEffect153, useRef as useRef184 } from "react";
98254
+ import { useCallback as useCallback186, useEffect as useEffect152, useRef as useRef184 } from "react";
98270
98255
 
98271
98256
  // src/components/studioMediaJobs.ts
98272
98257
  var MEDIA_JOB_RECONNECT_TIMEOUT_MS = 15e3;
@@ -98373,7 +98358,7 @@ function waitForMediaJob(jobId, onProgress, signal) {
98373
98358
  // src/hooks/useRemoveBackground.ts
98374
98359
  function useRemoveBackground(projectId, refreshFileTree, showToast) {
98375
98360
  const abortRef = useRef184(null);
98376
- useEffect153(
98361
+ useEffect152(
98377
98362
  () => () => {
98378
98363
  abortRef.current?.abort();
98379
98364
  },
@@ -98830,7 +98815,7 @@ function useStudioSidePanels(left, right, projectId) {
98830
98815
  }
98831
98816
 
98832
98817
  // src/components/TimelineToolbar.tsx
98833
- import { memo as memo61, useEffect as useEffect155, useRef as useRef185 } from "react";
98818
+ import { memo as memo61, useEffect as useEffect154, useRef as useRef185 } from "react";
98834
98819
  import {
98835
98820
  ArrowsOutLineHorizontal,
98836
98821
  Image as Image3,
@@ -98840,7 +98825,7 @@ import {
98840
98825
  } from "@phosphor-icons/react";
98841
98826
 
98842
98827
  // src/hooks/useKeyframeKeyboard.ts
98843
- import { useEffect as useEffect154, useCallback as useCallback189 } from "react";
98828
+ import { useEffect as useEffect153, useCallback as useCallback189 } from "react";
98844
98829
  function useKeyframeKeyboard({ enabled, onAddKeyframe }) {
98845
98830
  const handler = useCallback189(
98846
98831
  (e) => {
@@ -98854,7 +98839,7 @@ function useKeyframeKeyboard({ enabled, onAddKeyframe }) {
98854
98839
  },
98855
98840
  [enabled, onAddKeyframe]
98856
98841
  );
98857
- useEffect154(() => {
98842
+ useEffect153(() => {
98858
98843
  if (!enabled) return;
98859
98844
  window.addEventListener("keydown", handler, { capture: true });
98860
98845
  return () => window.removeEventListener("keydown", handler, { capture: true });
@@ -99200,10 +99185,10 @@ var TimelineToolbar = memo61(function TimelineToolbar2({
99200
99185
  enabled: showKeyframes && Boolean(onToggleKeyframe),
99201
99186
  onAddKeyframe: onToggleKeyframe
99202
99187
  });
99203
- useEffect155(() => {
99188
+ useEffect154(() => {
99204
99189
  if (!showKeyframes) setAutoKeyframeEnabled(false);
99205
99190
  }, [showKeyframes, setAutoKeyframeEnabled]);
99206
- useEffect155(() => {
99191
+ useEffect154(() => {
99207
99192
  const onKeyDown = (e) => {
99208
99193
  if (e.key !== "n" && e.key !== "N") return;
99209
99194
  if (e.metaKey || e.ctrlKey || e.altKey) return;
@@ -99484,7 +99469,7 @@ function StudioSplash({ waiting }) {
99484
99469
  }
99485
99470
 
99486
99471
  // src/hooks/useServerConnection.ts
99487
- import { useEffect as useEffect156, useState as useState161 } from "react";
99472
+ import { useEffect as useEffect155, useState as useState161 } from "react";
99488
99473
  async function resolveHashProject(id) {
99489
99474
  try {
99490
99475
  const res = await studioApiFetch(`/api/projects/${encodeURIComponent(id)}`);
@@ -99558,7 +99543,7 @@ function useServerConnection() {
99558
99543
  if (retryTimer !== null) clearTimeout(retryTimer);
99559
99544
  };
99560
99545
  });
99561
- useEffect156(() => {
99546
+ useEffect155(() => {
99562
99547
  const onHashChange = () => {
99563
99548
  const next = parseProjectIdFromHash(window.location.hash);
99564
99549
  if (!next || next === projectId) return;
@@ -99584,9 +99569,9 @@ function useServerConnection() {
99584
99569
  }
99585
99570
 
99586
99571
  // src/hooks/useStudioSessionStart.ts
99587
- import { useEffect as useEffect157 } from "react";
99572
+ import { useEffect as useEffect156 } from "react";
99588
99573
  function useStudioSessionStart(projectId, resolving, waitingForServer) {
99589
- useEffect157(() => {
99574
+ useEffect156(() => {
99590
99575
  if (resolving || waitingForServer || hasFiredSessionStart()) return;
99591
99576
  markSessionStartFired();
99592
99577
  trackStudioSessionStart({ has_project: projectId != null });
@@ -99613,7 +99598,7 @@ function useTimelineAddAtPlayhead(addAsset, addComposition, projectId) {
99613
99598
  import { useState as useState162 } from "react";
99614
99599
 
99615
99600
  // src/hooks/useHydrateActiveCompPathFromUrl.ts
99616
- import { useEffect as useEffect158 } from "react";
99601
+ import { useEffect as useEffect157 } from "react";
99617
99602
  function useHydrateActiveCompPathFromUrl({
99618
99603
  hydrated,
99619
99604
  fileTreeLoaded,
@@ -99622,7 +99607,7 @@ function useHydrateActiveCompPathFromUrl({
99622
99607
  setActiveCompPath,
99623
99608
  setHydrated
99624
99609
  }) {
99625
- useEffect158(() => {
99610
+ useEffect157(() => {
99626
99611
  if (hydrated) return;
99627
99612
  if (!fileTreeLoaded) return;
99628
99613
  const nextCompPath = normalizeStudioCompositionPath(
@@ -99635,7 +99620,7 @@ function useHydrateActiveCompPathFromUrl({
99635
99620
  }
99636
99621
 
99637
99622
  // src/hooks/useAutoOpenRootComposition.ts
99638
- import { useEffect as useEffect159, useRef as useRef186 } from "react";
99623
+ import { useEffect as useEffect158, useRef as useRef186 } from "react";
99639
99624
  function useAutoOpenRootComposition({
99640
99625
  projectId,
99641
99626
  activeCompPath,
@@ -99644,7 +99629,7 @@ function useAutoOpenRootComposition({
99644
99629
  onSelectComposition
99645
99630
  }) {
99646
99631
  const settledForProjectRef = useRef186(void 0);
99647
- useEffect159(() => {
99632
+ useEffect158(() => {
99648
99633
  if (settledForProjectRef.current === projectId) return;
99649
99634
  if (!activeCompPathHydrated) return;
99650
99635
  if (activeCompPath !== null) {