@hyperframes/studio 0.6.112 → 0.6.114
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/assets/{hyperframes-player-BRjQ5a5_.js → hyperframes-player-C1qkW56w.js} +1 -1
- package/dist/assets/{index-C7VLzTP-.js → index-BR5v5xu2.js} +1 -1
- package/dist/assets/index-DApfviyW.js +269 -0
- package/dist/assets/index-DS7Kfzvb.css +1 -0
- package/dist/assets/{index-kfy9U4bN.js → index-DSLrl2tB.js} +24 -24
- package/dist/index.html +2 -2
- package/package.json +5 -5
- package/src/App.tsx +4 -0
- package/src/components/StudioRightPanel.tsx +98 -4
- package/src/components/panels/SlideshowPanel.test.ts +520 -0
- package/src/components/panels/SlideshowPanel.tsx +484 -0
- package/src/components/panels/SlideshowSubPanels.tsx +536 -0
- package/src/components/panels/slideshowPanelHelpers.ts +232 -0
- package/src/hooks/useGsapAnimationOps.ts +96 -0
- package/src/hooks/useSlideshowPersist.ts +68 -0
- package/src/utils/sdkCutover.ts +83 -2
- package/src/utils/setSlideshowManifest.test.ts +146 -0
- package/src/utils/setSlideshowManifest.ts +102 -0
- package/src/utils/studioHelpers.ts +2 -1
- package/dist/assets/index-C9b6Siu5.js +0 -370
- package/dist/assets/index-DP8pPIk2.css +0 -1
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-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DApfviyW.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DS7Kfzvb.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.114",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"dompurify": "^3.2.4",
|
|
37
37
|
"marked": "^14.1.4",
|
|
38
38
|
"mediabunny": "^1.45.3",
|
|
39
|
-
"@hyperframes/
|
|
40
|
-
"@hyperframes/player": "0.6.
|
|
41
|
-
"@hyperframes/
|
|
39
|
+
"@hyperframes/core": "0.6.114",
|
|
40
|
+
"@hyperframes/player": "0.6.114",
|
|
41
|
+
"@hyperframes/sdk": "0.6.114"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/react": "19",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"vite": "^6.4.2",
|
|
53
53
|
"vitest": "^3.2.4",
|
|
54
54
|
"zustand": "^5.0.0",
|
|
55
|
-
"@hyperframes/producer": "0.6.
|
|
55
|
+
"@hyperframes/producer": "0.6.114"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"react": "19",
|
package/src/App.tsx
CHANGED
|
@@ -566,6 +566,10 @@ export function StudioApp() {
|
|
|
566
566
|
onToggleRecording={
|
|
567
567
|
STUDIO_KEYFRAMES_ENABLED ? handleToggleRecording : undefined
|
|
568
568
|
}
|
|
569
|
+
sdkSession={sdkHandle.session}
|
|
570
|
+
reloadPreview={reloadPreview}
|
|
571
|
+
domEditSaveTimestampRef={domEditSaveTimestampRef}
|
|
572
|
+
recordEdit={editHistory.recordEdit}
|
|
569
573
|
/>
|
|
570
574
|
)}
|
|
571
575
|
</div>
|
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useMemo,
|
|
4
|
+
useRef,
|
|
5
|
+
useState,
|
|
6
|
+
type MutableRefObject,
|
|
7
|
+
type PointerEvent as ReactPointerEvent,
|
|
8
|
+
} from "react";
|
|
2
9
|
import { Tooltip } from "./ui";
|
|
3
10
|
import { PropertyPanel } from "./editor/PropertyPanel";
|
|
4
11
|
import { LayersPanel } from "./editor/LayersPanel";
|
|
5
12
|
import { CaptionPropertyPanel } from "../captions/components/CaptionPropertyPanel";
|
|
6
13
|
import { BlockParamsPanel } from "./editor/BlockParamsPanel";
|
|
7
14
|
import { RenderQueue } from "./renders/RenderQueue";
|
|
15
|
+
import { SlideshowPanel } from "./panels/SlideshowPanel";
|
|
16
|
+
import type { SceneInfo } from "./panels/SlideshowPanel";
|
|
8
17
|
import type { RenderJob } from "./renders/useRenderQueue";
|
|
9
18
|
import type { BlockParam } from "@hyperframes/core/registry";
|
|
19
|
+
import type { IframeWindow } from "../player/lib/playbackTypes";
|
|
10
20
|
import { STUDIO_INSPECTOR_PANELS_ENABLED } from "./editor/manualEditingAvailability";
|
|
21
|
+
import type { Composition } from "@hyperframes/sdk";
|
|
22
|
+
import type { EditHistoryKind } from "../utils/editHistory";
|
|
23
|
+
import { useSlideshowPersist } from "../hooks/useSlideshowPersist";
|
|
11
24
|
|
|
12
25
|
import { useStudioPlaybackContext, useStudioShellContext } from "../contexts/StudioContext";
|
|
13
26
|
import { usePanelLayoutContext } from "../contexts/PanelLayoutContext";
|
|
@@ -30,6 +43,15 @@ export interface StudioRightPanelProps {
|
|
|
30
43
|
recordingState?: "idle" | "recording" | "preview";
|
|
31
44
|
recordingDuration?: number;
|
|
32
45
|
onToggleRecording?: () => void;
|
|
46
|
+
/** Dependencies for the Slideshow persist callback, threaded from App.tsx. */
|
|
47
|
+
sdkSession: Composition | null;
|
|
48
|
+
reloadPreview: () => void;
|
|
49
|
+
domEditSaveTimestampRef: MutableRefObject<number>;
|
|
50
|
+
recordEdit: (entry: {
|
|
51
|
+
label: string;
|
|
52
|
+
kind: EditHistoryKind;
|
|
53
|
+
files: Record<string, { before: string; after: string }>;
|
|
54
|
+
}) => Promise<void>;
|
|
33
55
|
}
|
|
34
56
|
|
|
35
57
|
// fallow-ignore-next-line complexity
|
|
@@ -40,6 +62,10 @@ export function StudioRightPanel({
|
|
|
40
62
|
recordingState,
|
|
41
63
|
recordingDuration,
|
|
42
64
|
onToggleRecording,
|
|
65
|
+
sdkSession,
|
|
66
|
+
reloadPreview,
|
|
67
|
+
domEditSaveTimestampRef,
|
|
68
|
+
recordEdit,
|
|
43
69
|
}: StudioRightPanelProps) {
|
|
44
70
|
const {
|
|
45
71
|
rightWidth,
|
|
@@ -60,7 +86,7 @@ export function StudioRightPanel({
|
|
|
60
86
|
waitForPendingDomEditSaves,
|
|
61
87
|
renderQueue,
|
|
62
88
|
} = useStudioShellContext();
|
|
63
|
-
const { captionEditMode } = useStudioPlaybackContext();
|
|
89
|
+
const { captionEditMode, refreshKey } = useStudioPlaybackContext();
|
|
64
90
|
|
|
65
91
|
const {
|
|
66
92
|
domEditSelection,
|
|
@@ -100,8 +126,40 @@ export function StudioRightPanel({
|
|
|
100
126
|
handleGsapConvertToKeyframes,
|
|
101
127
|
} = useDomEditContext();
|
|
102
128
|
|
|
103
|
-
const {
|
|
104
|
-
|
|
129
|
+
const {
|
|
130
|
+
assets,
|
|
131
|
+
fontAssets,
|
|
132
|
+
projectDir,
|
|
133
|
+
handleImportFiles,
|
|
134
|
+
handleImportFonts,
|
|
135
|
+
readProjectFile,
|
|
136
|
+
writeProjectFile,
|
|
137
|
+
} = useFileManagerContext();
|
|
138
|
+
|
|
139
|
+
// Discrete ops (toggle, reorder, add/delete, hotspot): persist immediately,
|
|
140
|
+
// no coalescing — each is a distinct user action that deserves its own undo entry.
|
|
141
|
+
const onPersistSlideshow = useSlideshowPersist({
|
|
142
|
+
sdkSession,
|
|
143
|
+
activeCompPath,
|
|
144
|
+
readProjectFile,
|
|
145
|
+
writeProjectFile,
|
|
146
|
+
recordEdit,
|
|
147
|
+
reloadPreview,
|
|
148
|
+
domEditSaveTimestampRef,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Notes path: persists are debounced in SlideshowPanel; coalesceKey ensures
|
|
152
|
+
// rapid writes collapse into a single undo entry via the save-queue infra.
|
|
153
|
+
const onPersistSlideshowNotes = useSlideshowPersist({
|
|
154
|
+
sdkSession,
|
|
155
|
+
activeCompPath,
|
|
156
|
+
readProjectFile,
|
|
157
|
+
writeProjectFile,
|
|
158
|
+
recordEdit,
|
|
159
|
+
reloadPreview,
|
|
160
|
+
domEditSaveTimestampRef,
|
|
161
|
+
coalesceKey: activeCompPath ? `slideshow-notes:${activeCompPath}` : "slideshow-notes",
|
|
162
|
+
});
|
|
105
163
|
|
|
106
164
|
const [layersPanePercent, setLayersPanePercent] = useState(40);
|
|
107
165
|
const splitContainerRef = useRef<HTMLDivElement>(null);
|
|
@@ -113,6 +171,23 @@ export function StudioRightPanel({
|
|
|
113
171
|
|
|
114
172
|
const renderJobs = renderQueue.jobs as RenderJob[];
|
|
115
173
|
const inspectorTabActive = rightPanelTab === "design" || rightPanelTab === "layers";
|
|
174
|
+
|
|
175
|
+
// Derive scene list from the live clip manifest in the preview iframe.
|
|
176
|
+
// fallow-ignore-next-line complexity
|
|
177
|
+
const slideshowScenes = useMemo<SceneInfo[]>(() => {
|
|
178
|
+
try {
|
|
179
|
+
const win = previewIframeRef.current?.contentWindow as IframeWindow | null;
|
|
180
|
+
return (win?.__clipManifest?.scenes ?? []).map((s) => ({
|
|
181
|
+
id: s.id,
|
|
182
|
+
label: s.label,
|
|
183
|
+
start: s.start,
|
|
184
|
+
duration: s.duration,
|
|
185
|
+
}));
|
|
186
|
+
} catch {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
190
|
+
}, [previewIframeRef, rightPanelTab, refreshKey]);
|
|
116
191
|
const designPaneOpen = inspectorTabActive && rightInspectorPanes.design && designPanelActive;
|
|
117
192
|
const layersPaneOpen =
|
|
118
193
|
inspectorTabActive && rightInspectorPanes.layers && STUDIO_INSPECTOR_PANELS_ENABLED;
|
|
@@ -291,6 +366,19 @@ export function StudioRightPanel({
|
|
|
291
366
|
{renderJobs.length > 0 ? `Renders (${renderJobs.length})` : "Renders"}
|
|
292
367
|
</button>
|
|
293
368
|
</Tooltip>
|
|
369
|
+
<Tooltip label="Slideshow branching editor" side="bottom">
|
|
370
|
+
<button
|
|
371
|
+
type="button"
|
|
372
|
+
onClick={() => setRightPanelTab("slideshow")}
|
|
373
|
+
className={`h-8 rounded-xl px-3 text-[11px] font-medium transition-colors ${
|
|
374
|
+
rightPanelTab === "slideshow"
|
|
375
|
+
? "bg-neutral-800 text-white"
|
|
376
|
+
: "text-neutral-500 hover:bg-neutral-800/70 hover:text-neutral-200"
|
|
377
|
+
}`}
|
|
378
|
+
>
|
|
379
|
+
Slideshow
|
|
380
|
+
</button>
|
|
381
|
+
</Tooltip>
|
|
294
382
|
</div>
|
|
295
383
|
<div className="min-h-0 flex-1">
|
|
296
384
|
{rightPanelTab === "block-params" && activeBlockParams ? (
|
|
@@ -301,6 +389,12 @@ export function StudioRightPanel({
|
|
|
301
389
|
compositionPath={activeBlockParams.compositionPath}
|
|
302
390
|
onClose={onCloseBlockParams ?? (() => {})}
|
|
303
391
|
/>
|
|
392
|
+
) : rightPanelTab === "slideshow" ? (
|
|
393
|
+
<SlideshowPanel
|
|
394
|
+
scenes={slideshowScenes}
|
|
395
|
+
onPersist={onPersistSlideshow}
|
|
396
|
+
onPersistNotes={onPersistSlideshowNotes}
|
|
397
|
+
/>
|
|
304
398
|
) : layersPaneOpen && designPaneOpen ? (
|
|
305
399
|
<div ref={splitContainerRef} className="flex h-full min-h-0 flex-col">
|
|
306
400
|
<div
|