@hyperframes/studio 0.8.92 → 0.8.93
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-DKJPDHUp.js → hyperframes-player-CkV9KK6A.js} +3 -3
- package/dist/assets/{index-DpzpqJ_j.js → index-BlLFipOk.js} +1 -1
- package/dist/assets/{index-C5_j5-3u.js → index-CYk0NwSv.js} +137 -137
- package/dist/assets/{index-CHZ4kFWm.js → index-V3fzEfOD.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/index.js +14 -4
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/player/hooks/useTimelinePlayer.seek.test.ts +29 -1
- package/src/player/hooks/useTimelinePlayer.ts +6 -0
- package/src/player/hooks/useTimelinePlayerLoop.ts +6 -2
- package/src/player/lib/playbackTypes.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.93",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
"dockview-react": "8.3.1",
|
|
61
61
|
"gsap": "^3.13.0",
|
|
62
62
|
"mediabunny": "^1.45.3",
|
|
63
|
-
"@hyperframes/core": "0.8.
|
|
64
|
-
"@hyperframes/
|
|
65
|
-
"@hyperframes/
|
|
66
|
-
"@hyperframes/
|
|
67
|
-
"@hyperframes/player": "0.8.
|
|
68
|
-
"@hyperframes/
|
|
63
|
+
"@hyperframes/core": "0.8.93",
|
|
64
|
+
"@hyperframes/shader-transitions": "0.8.93",
|
|
65
|
+
"@hyperframes/studio-server": "0.8.93",
|
|
66
|
+
"@hyperframes/parsers": "0.8.93",
|
|
67
|
+
"@hyperframes/player": "0.8.93",
|
|
68
|
+
"@hyperframes/sdk": "0.8.93"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@tailwindcss/vite": "^4.3.3",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"vite": "^6.4.2",
|
|
82
82
|
"vitest": "^4.1.11",
|
|
83
83
|
"zustand": "^5.0.0",
|
|
84
|
-
"@hyperframes/producer": "0.8.
|
|
84
|
+
"@hyperframes/producer": "0.8.93"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"react": "19",
|
|
@@ -353,7 +353,11 @@ describe("useTimelinePlayer seek keepPlaying option (#834)", () => {
|
|
|
353
353
|
describe("useTimelinePlayer RAF loop wrap-around", () => {
|
|
354
354
|
type SeekCall = { time: number; options?: { keepPlaying?: boolean } };
|
|
355
355
|
|
|
356
|
-
function attachInstrumentedAdapter(
|
|
356
|
+
function attachInstrumentedAdapter(
|
|
357
|
+
api: ReturnType<typeof useTimelinePlayer>,
|
|
358
|
+
duration = 30,
|
|
359
|
+
hooks: object = {},
|
|
360
|
+
) {
|
|
357
361
|
let currentTime = 0;
|
|
358
362
|
let playing = false;
|
|
359
363
|
const seekCalls: SeekCall[] = [];
|
|
@@ -377,6 +381,7 @@ describe("useTimelinePlayer RAF loop wrap-around", () => {
|
|
|
377
381
|
};
|
|
378
382
|
attachIframeWindow(api, {
|
|
379
383
|
__player: adapter,
|
|
384
|
+
__hf: hooks,
|
|
380
385
|
postMessage: () => {},
|
|
381
386
|
scrollTo: () => {},
|
|
382
387
|
addEventListener: () => {},
|
|
@@ -446,6 +451,29 @@ describe("useTimelinePlayer RAF loop wrap-around", () => {
|
|
|
446
451
|
}
|
|
447
452
|
});
|
|
448
453
|
|
|
454
|
+
it("tells the preview where the loop wraps to while it plays, and that it stopped looping", () => {
|
|
455
|
+
const raf = installRafCapture();
|
|
456
|
+
try {
|
|
457
|
+
const { api, root } = renderTimelinePlayerHarness();
|
|
458
|
+
const setLoopStart = vi.fn();
|
|
459
|
+
const { adapter } = attachInstrumentedAdapter(api, 30, { setLoopStart });
|
|
460
|
+
act(() => {
|
|
461
|
+
usePlayerStore.getState().setInPoint(2);
|
|
462
|
+
usePlayerStore.getState().setOutPoint(5);
|
|
463
|
+
api.play();
|
|
464
|
+
});
|
|
465
|
+
adapter.setTime(3);
|
|
466
|
+
act(() => void raf.flushOne());
|
|
467
|
+
expect(setLoopStart).toHaveBeenLastCalledWith(2);
|
|
468
|
+
act(() => usePlayerStore.getState().setLoopEnabled(false));
|
|
469
|
+
act(() => void raf.flushOne());
|
|
470
|
+
expect(setLoopStart).toHaveBeenLastCalledWith(null);
|
|
471
|
+
unmountWithAct(root);
|
|
472
|
+
} finally {
|
|
473
|
+
raf.restore();
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
|
|
449
477
|
it("does not seek and pauses cleanly when forward playback reaches the end without loop", () => {
|
|
450
478
|
const raf = installRafCapture();
|
|
451
479
|
try {
|
|
@@ -152,12 +152,18 @@ export function useTimelinePlayer({
|
|
|
152
152
|
[],
|
|
153
153
|
);
|
|
154
154
|
|
|
155
|
+
const setLoopStart = useCallback((seconds: number | null) => {
|
|
156
|
+
try {
|
|
157
|
+
(iframeRef.current?.contentWindow as IframeWindow | null)?.__hf?.setLoopStart?.(seconds);
|
|
158
|
+
} catch {}
|
|
159
|
+
}, []);
|
|
155
160
|
const { startRAFLoop, stopRAFLoop, stopReverseLoop } = useTimelinePlayerLoop({
|
|
156
161
|
rafRef,
|
|
157
162
|
reverseRafRef,
|
|
158
163
|
getAdapter,
|
|
159
164
|
setCurrentTime,
|
|
160
165
|
setIsPlaying,
|
|
166
|
+
setLoopStart,
|
|
161
167
|
});
|
|
162
168
|
|
|
163
169
|
const applyPlaybackRate = useCallback((rate: number) => {
|
|
@@ -22,6 +22,7 @@ interface UseTimelinePlayerLoopParams {
|
|
|
22
22
|
getAdapter: () => PlaybackAdapter | null;
|
|
23
23
|
setCurrentTime: (v: number) => void;
|
|
24
24
|
setIsPlaying: (v: boolean) => void;
|
|
25
|
+
setLoopStart: (seconds: number | null) => void;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
interface UseTimelinePlayerLoopResult {
|
|
@@ -36,6 +37,7 @@ export function useTimelinePlayerLoop({
|
|
|
36
37
|
getAdapter,
|
|
37
38
|
setCurrentTime,
|
|
38
39
|
setIsPlaying,
|
|
40
|
+
setLoopStart,
|
|
39
41
|
}: UseTimelinePlayerLoopParams): UseTimelinePlayerLoopResult {
|
|
40
42
|
const stopReverseLoop = useCallback(() => {
|
|
41
43
|
cancelAnimationFrame(reverseRafRef.current);
|
|
@@ -55,8 +57,10 @@ export function useTimelinePlayerLoop({
|
|
|
55
57
|
const rawLoopStart = inPoint !== null ? inPoint : 0;
|
|
56
58
|
const loopEnd = rawLoopStart < rawLoopEnd ? rawLoopEnd : dur;
|
|
57
59
|
const loopStart = rawLoopStart < rawLoopEnd ? rawLoopStart : 0;
|
|
60
|
+
const looping = usePlayerStore.getState().loopEnabled && dur > 0;
|
|
61
|
+
setLoopStart(looping ? loopStart : null);
|
|
58
62
|
if (time >= loopEnd) {
|
|
59
|
-
if (
|
|
63
|
+
if (looping) {
|
|
60
64
|
// keepPlaying skips the adapter's implicit pause; play() below is then a no-op.
|
|
61
65
|
adapter.seek(loopStart, { keepPlaying: true });
|
|
62
66
|
liveTime.notify(loopStart);
|
|
@@ -75,7 +79,7 @@ export function useTimelinePlayerLoop({
|
|
|
75
79
|
rafRef.current = requestAnimationFrame(tick);
|
|
76
80
|
};
|
|
77
81
|
rafRef.current = requestAnimationFrame(tick);
|
|
78
|
-
}, [rafRef, getAdapter, setCurrentTime, setIsPlaying]);
|
|
82
|
+
}, [rafRef, getAdapter, setCurrentTime, setIsPlaying, setLoopStart]);
|
|
79
83
|
|
|
80
84
|
const stopRAFLoop = useCallback(() => {
|
|
81
85
|
cancelAnimationFrame(rafRef.current);
|