@hyperframes/studio 0.8.47 → 0.8.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/assets/{hyperframes-player-B7fsB8C2.js → hyperframes-player-CtVX6jL_.js} +1 -1
  2. package/dist/assets/{index-ryL7q1QG.js → index-B3-orIjW.js} +1 -1
  3. package/dist/assets/index-B9LfWNyM.css +1 -0
  4. package/dist/assets/index-C9gJKpqQ.js +441 -0
  5. package/dist/assets/{index-B50xQfSG.js → index-D_j-0PD3.js} +1 -1
  6. package/dist/index.d.ts +66 -23
  7. package/dist/index.html +2 -2
  8. package/dist/index.js +1015 -621
  9. package/dist/index.js.map +1 -1
  10. package/package.json +7 -7
  11. package/src/App.tsx +17 -26
  12. package/src/components/AskAgentModal.tsx +9 -7
  13. package/src/components/TimelineToolbar.tsx +26 -1
  14. package/src/components/editor/PropertyPanelFlat.tsx +8 -8
  15. package/src/components/editor/domEditing.ts +7 -1
  16. package/src/components/editor/domEditingAgentPrompt.test.ts +199 -0
  17. package/src/components/editor/domEditingAgentPrompt.ts +136 -34
  18. package/src/components/editor/propertyPanelAutomation.test.ts +82 -1
  19. package/src/components/editor/propertyPanelAutomation.ts +15 -0
  20. package/src/components/editor/propertyPanelFlatMediaSection.test.tsx +35 -0
  21. package/src/components/editor/propertyPanelFlatMediaSection.tsx +23 -9
  22. package/src/components/editor/useVolumeAutomation.test.tsx +81 -10
  23. package/src/components/editor/useVolumeAutomation.ts +23 -2
  24. package/src/components/panels/VariablesPanel.tsx +5 -8
  25. package/src/components/sidebar/CompositionsTab.rootBadge.test.tsx +59 -0
  26. package/src/components/sidebar/CompositionsTab.tsx +15 -0
  27. package/src/components/sidebar/LeftSidebar.masterComposition.test.tsx +47 -0
  28. package/src/components/sidebar/LeftSidebar.tsx +7 -0
  29. package/src/contexts/FileManagerContext.tsx +0 -3
  30. package/src/hooks/appHotkeysDispatch.ts +256 -0
  31. package/src/hooks/domEditDeleteMembers.test.ts +30 -0
  32. package/src/hooks/domEditDeleteMembers.ts +19 -0
  33. package/src/hooks/useActiveComposition.ts +69 -0
  34. package/src/hooks/useAppHotkeys.test.ts +23 -1
  35. package/src/hooks/useAppHotkeys.ts +6 -239
  36. package/src/hooks/useAutoOpenRootComposition.test.tsx +151 -0
  37. package/src/hooks/useAutoOpenRootComposition.ts +33 -0
  38. package/src/hooks/useDomEditCommits.ts +13 -15
  39. package/src/hooks/useDomEditSession.test.tsx +90 -1
  40. package/src/hooks/useDomEditSession.ts +31 -34
  41. package/src/hooks/useDomSelectionTypes.ts +7 -2
  42. package/src/hooks/useElementLifecycleOps.ts +0 -8
  43. package/src/hooks/useFileManager.projectOwnership.test.tsx +0 -1
  44. package/src/hooks/useFileManager.ts +0 -2
  45. package/src/hooks/useFileTree.test.tsx +214 -0
  46. package/src/hooks/useFileTree.ts +66 -24
  47. package/src/hooks/useGroupCommits.test.ts +98 -0
  48. package/src/hooks/useGroupCommits.ts +66 -9
  49. package/src/hooks/useResetSelectionOnProjectSwitch.test.tsx +234 -0
  50. package/src/hooks/useResetSelectionOnProjectSwitch.ts +34 -0
  51. package/src/hooks/useTimelineAssetDropOps.test.tsx +72 -0
  52. package/src/hooks/useTimelineAssetDropOps.ts +20 -16
  53. package/src/hooks/useTimelineDeleteOps.test.tsx +119 -0
  54. package/src/hooks/useTimelineDeleteOps.ts +103 -9
  55. package/src/hooks/useTimelineEditing.ts +1 -0
  56. package/src/hooks/useTimelineGroupEditing.test.tsx +74 -0
  57. package/src/hooks/useTimelineGroupEditing.ts +19 -5
  58. package/src/index.ts +10 -0
  59. package/src/player/components/Timeline.test.ts +0 -4
  60. package/src/player/components/Timeline.tsx +0 -1
  61. package/src/player/components/TimelineAutomationLaneSlot.tsx +4 -2
  62. package/src/player/components/TimelineClipDiamonds.test.tsx +13 -1
  63. package/src/player/components/TimelineDiamondConnectors.test.ts +16 -0
  64. package/src/player/components/TimelineDiamondConnectors.tsx +17 -1
  65. package/src/player/components/TimelinePropertyLanes.test.tsx +1 -1
  66. package/src/player/components/automationLaneData.test.ts +11 -3
  67. package/src/player/components/automationLaneData.ts +5 -4
  68. package/src/player/components/automationLaneGeometry.ts +15 -0
  69. package/src/player/components/timelineDragDrop.test.tsx +21 -4
  70. package/src/player/components/timelineDragDrop.ts +9 -25
  71. package/src/player/components/timelineGapCommit.test.ts +96 -0
  72. package/src/player/components/timelineGapCommit.ts +56 -11
  73. package/src/player/components/timelineGaps.ts +2 -2
  74. package/src/player/components/timelineLayout.test.ts +0 -1
  75. package/src/player/components/timelineLayout.ts +1 -6
  76. package/src/player/components/timelineZones.test.ts +20 -1
  77. package/src/player/components/timelineZones.ts +10 -3
  78. package/src/player/components/useAutomationLaneGestures.ts +2 -10
  79. package/src/player/components/useTimelineTrackLayout.ts +7 -6
  80. package/src/player/hooks/usePlaybackKeyboard.test.ts +34 -0
  81. package/src/player/hooks/usePlaybackKeyboard.ts +13 -0
  82. package/src/player/lib/timelineIframeHelpers.test.ts +22 -0
  83. package/src/player/lib/timelineIframeHelpers.ts +1 -0
  84. package/src/player/store/playerStore.ts +16 -21
  85. package/src/utils/razorSplitTransaction.test.ts +10 -0
  86. package/src/utils/razorSplitTransaction.ts +5 -0
  87. package/src/utils/sdkCutover.test.ts +51 -0
  88. package/src/utils/studioHelpers.test.ts +18 -0
  89. package/src/utils/studioHelpers.ts +41 -5
  90. package/src/utils/studioUiPreferences.test.ts +14 -0
  91. package/src/utils/studioUiPreferences.ts +6 -0
  92. package/src/utils/studioUrlState.ts +15 -7
  93. package/src/utils/timelineInspector.ts +10 -0
  94. package/dist/assets/index-DnRfAiK2.css +0 -1
  95. package/dist/assets/index-j-4hCrZU.js +0 -441
@@ -1 +1 @@
1
- import{g as P}from"./index-j-4hCrZU.js";function j(c,d){for(var s=0;s<d.length;s++){const a=d[s];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in c)){const l=Object.getOwnPropertyDescriptor(a,i);l&&Object.defineProperty(c,i,l.get?l:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}))}var v={},w;function k(){if(w)return v;w=1,Object.defineProperty(v,"__esModule",{value:!0}),v.default=d;var c=window.OfflineAudioContext||window.webkitOfflineAudioContext;function d(e){var r=a(e);return r.start(0),[i,y,O(e.sampleRate),s].reduce(function(t,o){return o(t)},r.buffer.getChannelData(0))}function s(e){return e.sort(function(r,t){return t.count-r.count}).splice(0,5)[0].tempo}function a(e){var r=e.length,t=e.numberOfChannels,o=e.sampleRate,n=new c(t,r,o),u=n.createBufferSource();u.buffer=e;var f=n.createBiquadFilter();return f.type="lowpass",u.connect(f),f.connect(n.destination),u}function i(e){for(var r=[],t=.9,o=.3,n=15;r.length<n&&t>=o;)r=l(e,t),t-=.05;if(r.length<n)throw new Error("Could not find enough samples for a reliable detection.");return r}function l(e,r){for(var t=[],o=0,n=e.length;o<n;o+=1)e[o]>r&&(t.push(o),o+=1e4);return t}function y(e){var r=[];return e.forEach(function(t,o){for(var n=function(x){var g=e[o+x]-t,_=r.some(function(h){if(h.interval===g)return h.count+=1});_||r.push({interval:g,count:1})},u=0;u<10;u+=1)n(u)}),r}function O(e){return function(r){var t=[];return r.forEach(function(o){if(o.interval!==0){for(var n=60/(o.interval/e);n<90;)n*=2;for(;n>180;)n/=2;n=Math.round(n);var u=t.some(function(f){if(f.tempo===n)return f.count+=o.count});u||t.push({tempo:n,count:o.count})}}),t}}return v}var p,b;function q(){return b||(b=1,p=k().default),p}var m=q();const A=P(m),D=j({__proto__:null,default:A},[m]);export{D as i};
1
+ import{g as P}from"./index-C9gJKpqQ.js";function j(c,d){for(var s=0;s<d.length;s++){const a=d[s];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in c)){const l=Object.getOwnPropertyDescriptor(a,i);l&&Object.defineProperty(c,i,l.get?l:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}))}var v={},w;function k(){if(w)return v;w=1,Object.defineProperty(v,"__esModule",{value:!0}),v.default=d;var c=window.OfflineAudioContext||window.webkitOfflineAudioContext;function d(e){var r=a(e);return r.start(0),[i,y,O(e.sampleRate),s].reduce(function(t,o){return o(t)},r.buffer.getChannelData(0))}function s(e){return e.sort(function(r,t){return t.count-r.count}).splice(0,5)[0].tempo}function a(e){var r=e.length,t=e.numberOfChannels,o=e.sampleRate,n=new c(t,r,o),u=n.createBufferSource();u.buffer=e;var f=n.createBiquadFilter();return f.type="lowpass",u.connect(f),f.connect(n.destination),u}function i(e){for(var r=[],t=.9,o=.3,n=15;r.length<n&&t>=o;)r=l(e,t),t-=.05;if(r.length<n)throw new Error("Could not find enough samples for a reliable detection.");return r}function l(e,r){for(var t=[],o=0,n=e.length;o<n;o+=1)e[o]>r&&(t.push(o),o+=1e4);return t}function y(e){var r=[];return e.forEach(function(t,o){for(var n=function(x){var g=e[o+x]-t,_=r.some(function(h){if(h.interval===g)return h.count+=1});_||r.push({interval:g,count:1})},u=0;u<10;u+=1)n(u)}),r}function O(e){return function(r){var t=[];return r.forEach(function(o){if(o.interval!==0){for(var n=60/(o.interval/e);n<90;)n*=2;for(;n>180;)n/=2;n=Math.round(n);var u=t.some(function(f){if(f.tempo===n)return f.count+=o.count});u||t.push({tempo:n,count:o.count})}}),t}}return v}var p,b;function q(){return b||(b=1,p=k().default),p}var m=q();const A=P(m),D=j({__proto__:null,default:A},[m]);export{D as i};
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, RefObject } from 'react';
4
- import { RuntimeTimelineClipIdentity } from '@hyperframes/core';
4
+ import { RuntimeTimelineClipIdentity, HyperframePickerElementInfo } from '@hyperframes/core';
5
5
  import { GsapAnimation, PropertyGroupName } from '@hyperframes/core/gsap-parser';
6
6
  import * as zustand from 'zustand';
7
7
  import { StoreApi } from 'zustand';
@@ -443,14 +443,14 @@ interface PlayerState extends PlayerStoreSlices {
443
443
  /** Timeline magnet toggle — when false, clip drags/trims/drops never snap. */
444
444
  timelineSnapEnabled: boolean;
445
445
  setTimelineSnapEnabled: (enabled: boolean) => void;
446
+ /** Keeps the main track gapless on delete; distinct from the magnet above. */
447
+ rippleEditEnabled: boolean;
448
+ setRippleEditEnabled: (enabled: boolean) => void;
446
449
  /** Transport + ruler readout: timecode ("time") or frame number ("frame"). */
447
450
  timeDisplayMode: TimelineTimeDisplayMode;
448
451
  setTimeDisplayMode: (mode: TimelineTimeDisplayMode) => void;
449
- /**
450
- * Pin the timeline zoom to its current visual scale before a duration-changing
451
- * edit, so a subsequent duration change (which recomputes fit-pps) stops
452
- * rescaling every clip. No-op once already pinned (mode is "manual").
453
- */
452
+ /** Pin the timeline zoom to its current scale before a duration change, so
453
+ * it stops rescaling every clip. No-op once already pinned. */
454
454
  pinTimelineZoom: (currentPixelsPerSecond: number, fitPixelsPerSecond: number) => void;
455
455
  /** The timeline's live pixels-per-second + fit basis, published by <Timeline>. */
456
456
  timelinePps: number;
@@ -482,25 +482,15 @@ interface PlayerState extends PlayerStoreSlices {
482
482
  beginTimelineSession: (projectId: string) => void;
483
483
  /** Clears project data without creating a new hard-project session. */
484
484
  reset: () => void;
485
- /**
486
- * Request a seek from outside the player loop (e.g. Layers panel).
487
- * useTimelinePlayer subscribes and calls adapter.seek() + liveTime.notify().
488
- */
485
+ /** Request a seek from outside the player loop (e.g. Layers panel);
486
+ * useTimelinePlayer subscribes and calls adapter.seek() + liveTime.notify(). */
489
487
  requestedSeekTime: number | null;
490
488
  requestSeek: (time: number) => void;
491
489
  clearSeekRequest: () => void;
492
- /**
493
- * Request the transport start or stop from outside the player loop.
494
- *
495
- * The FX rack auditions a preset by writing it to the running graph, which is
496
- * silent while the transport is paused — so hovering one has to start
497
- * playback, and leaving has to put the playhead back where it was. Hovering is
498
- * not an edit and must not cost the author their place.
499
- *
500
- * A nonce rather than a bare boolean: two hovers in a row both want play, and
501
- * without it the second request is indistinguishable from the first having
502
- * already been served.
503
- */
490
+ /** Request the transport start or stop from outside the player loop: the FX
491
+ * rack starts playback to audition a preset (silent while paused) and
492
+ * restores the playhead on leave, without costing the author their place.
493
+ * A nonce, not a bare boolean, so two hovers in a row both register. */
504
494
  playbackRequest: {
505
495
  playing: boolean;
506
496
  returnTo: number | null;
@@ -675,6 +665,45 @@ interface DomEditSelection extends PatchTarget {
675
665
  gsapAnimations?: GsapAnimation$1[];
676
666
  }
677
667
 
668
+ /**
669
+ * Agent prompt builder for HyperFrames element edit requests.
670
+ */
671
+
672
+ /**
673
+ * The subset of an element selection shared by the Studio DOM editor (`DomEditSelection`) and the
674
+ * runtime picker (`HyperframePickerElementInfo`); a field absent from a caller's type is simply omitted.
675
+ */
676
+ interface AgentPromptElementInfo {
677
+ id: string | null;
678
+ selector?: string | null;
679
+ /** Disambiguates duplicate selectors in `DomEditSelection`. The picker
680
+ * payload has no such concept (one picked node, not a candidate list), so
681
+ * a picker-built prompt always prints index 0 — expected, not a gap. */
682
+ selectorIndex?: number;
683
+ tagName: string;
684
+ label?: string;
685
+ boundingBox: {
686
+ x: number;
687
+ y: number;
688
+ width: number;
689
+ height: number;
690
+ };
691
+ textContent: string | null;
692
+ src?: string | null;
693
+ textFields?: DomEditTextField[];
694
+ inlineStyles?: Record<string, string>;
695
+ computedStyles?: Record<string, string>;
696
+ }
697
+ /**
698
+ * Same convention as `buildElementAgentPrompt`, for a host app embedding only the player: built from
699
+ * the runtime picker's own payload, not `DomEditSelection`. Null selection yields a bare prompt, no guardrails.
700
+ */
701
+ declare function buildPickerAgentPrompt({ selection, userInstruction, }: {
702
+ selection: HyperframePickerElementInfo | null;
703
+ userInstruction?: string;
704
+ }): string;
705
+ declare function buildPickerAgentContextPreview(selection: HyperframePickerElementInfo | null): string;
706
+
678
707
  type BlockedTimelineEditIntent = "move" | "resize-start" | "resize-end";
679
708
 
680
709
  type TimelineMoveOperation = "timing" | "lane-reorder" | "track-insert";
@@ -1216,6 +1245,20 @@ declare const FileTree: react.NamedExoticComponent<FileTreeProps>;
1216
1245
 
1217
1246
  declare function StudioApp(): react_jsx_runtime.JSX.Element;
1218
1247
 
1248
+ interface AgentModalAnchorPoint {
1249
+ x: number;
1250
+ y: number;
1251
+ }
1252
+
1253
+ interface AskAgentModalProps {
1254
+ selectionLabel: string;
1255
+ contextPreview?: string;
1256
+ anchorPoint?: AgentModalAnchorPoint | null;
1257
+ onSubmit: (instruction: string) => void;
1258
+ onClose: () => void;
1259
+ }
1260
+ declare function AskAgentModal({ selectionLabel, contextPreview, anchorPoint, onSubmit, onClose, }: AskAgentModalProps): react_jsx_runtime.JSX.Element;
1261
+
1219
1262
  interface PickedElement {
1220
1263
  id: string | null;
1221
1264
  tagName: string;
@@ -1291,4 +1334,4 @@ declare function findElementBlock(html: string, elementId: string): {
1291
1334
  isSelfClosing: boolean;
1292
1335
  } | null;
1293
1336
 
1294
- export { CompositionBreadcrumb, type CompositionLevel, CompositionThumbnail, EditorShell, FileTree, NLEPreview, type PatchOperation, type PickedElement, Player, PlayerControls, PropertyPanel, SourceEditor, StudioApp, Timeline, type TimelineElement, VideoThumbnail, applyPatch, findElementBlock, formatTime, liveTime, mergeStyleIntoTag, parseStyleString, resolveIframe, resolveSourceFile, useElementPicker, usePlayerStore, useTimelinePlayer };
1337
+ export { type AgentModalAnchorPoint, type AgentPromptElementInfo, AskAgentModal, type AskAgentModalProps, CompositionBreadcrumb, type CompositionLevel, CompositionThumbnail, EditorShell, FileTree, NLEPreview, type PatchOperation, type PickedElement, Player, PlayerControls, PropertyPanel, SourceEditor, StudioApp, Timeline, type TimelineElement, VideoThumbnail, applyPatch, buildPickerAgentContextPreview, buildPickerAgentPrompt, findElementBlock, formatTime, liveTime, mergeStyleIntoTag, parseStyleString, resolveIframe, resolveSourceFile, useElementPicker, usePlayerStore, useTimelinePlayer };
package/dist/index.html CHANGED
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>HyperFrames Studio</title>
8
- <script type="module" crossorigin src="/assets/index-j-4hCrZU.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-DnRfAiK2.css">
8
+ <script type="module" crossorigin src="/assets/index-C9gJKpqQ.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-B9LfWNyM.css">
10
10
  </head>
11
11
  <body>
12
12
  <div data-hf-id="hf-aph5" id="root"></div>