Skip to content

Commit 6e0f4ad

Browse files
committed
fix(studio,producer): post-merge regressions and open issues
- fix gsapDragCommit.test.ts import for commitGsapPositionFromDrag - add generateId() helper with insecure-context fallback (fixes #1637) - enable STUDIO_KEYFRAMES_ENABLED by default - prevent clock duration from shrinking during playback (fixes #1636) - add maxRetries to rmSync cleanup calls to handle ENOTEMPTY race (fixes #1644)
1 parent 4db708e commit 6e0f4ad

12 files changed

Lines changed: 31 additions & 18 deletions

File tree

packages/core/src/runtime/init.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,15 +2259,14 @@ export function initSandboxRuntimeModular(): void {
22592259
bindMediaMetadataListeners();
22602260
}
22612261

2262-
// Keep clock duration in sync with the resolved timeline duration.
2263-
// Catches async timeline rebinds that happen outside the 60-tick
2264-
// branch (metadata hydration, deferred setTimeout). Note: this reads
2265-
// the DOM each tick (duration floors query authored windows + the
2266-
// root's declared data-duration), which also keeps live edits to
2267-
// data-duration in the studio reflected without a rebind.
2262+
// Sync clock duration with the resolved timeline each tick (catches async
2263+
// rebinds, live data-duration edits). Never shrink while playing — transient
2264+
// short reads cause reachedEnd() → playhead jumps to end (#1636).
22682265
if (state.capturedTimeline) {
22692266
const dur = getSafeTimelineDurationSeconds(state.capturedTimeline, 0);
2270-
if (dur > 0) clock.setDuration(dur);
2267+
if (dur > 0 && (!clock.isPlaying() || dur >= clock.getDuration())) {
2268+
clock.setDuration(dur);
2269+
}
22712270
}
22722271

22732272
// Audio-master clock: three tiers of timing precision.

packages/producer/src/services/distributed/renderChunk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ export async function renderChunk(
707707
// Clean up only after the hash + perf sidecar landed. Any failure above
708708
// leaves the framesDir in place for inspection.
709709
try {
710-
rmSync(workDir, { recursive: true, force: true });
710+
rmSync(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
711711
} catch (err) {
712712
log.warn("[renderChunk] failed to remove work dir", {
713713
workDir,

packages/producer/src/services/render/cleanup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export async function cleanupRenderResources(input: {
6565
// `force: true` swallows ENOENT, so no need to existsSync first.
6666
await safeCleanup(
6767
`remove workDir (${label})`,
68-
() => rmSync(workDir, { recursive: true, force: true }),
68+
() => rmSync(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }),
6969
log,
7070
);
7171
}

packages/producer/src/services/renderOrchestrator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1699,7 +1699,7 @@ export async function executeRenderJob(
16991699
await safeCleanup(
17001700
"remove workDir",
17011701
() => {
1702-
rmSync(workDir, { recursive: true, force: true });
1702+
rmSync(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
17031703
},
17041704
log,
17051705
);

packages/studio/src/components/editor/manualEditingAvailability.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export const STUDIO_COLOR_GRADING_ENABLED = resolveStudioBooleanEnvFlag(
7373
export const STUDIO_KEYFRAMES_ENABLED = resolveStudioBooleanEnvFlag(
7474
env,
7575
["VITE_STUDIO_ENABLE_KEYFRAMES", "VITE_STUDIO_KEYFRAMES_ENABLED"],
76-
false,
76+
true,
7777
);
7878

7979
export const STUDIO_RAZOR_TOOL_ENABLED = resolveStudioBooleanEnvFlag(

packages/studio/src/components/panels/SlideshowPanel.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type { SlideshowManifest, SlideHotspot } from "@hyperframes/core/slidesho
2020
import { usePlayerStore } from "../../player";
2121
import { useDomEditSelectionContext } from "../../contexts/DomEditContext";
2222
import { useFileManagerContext } from "../../contexts/FileManagerContext";
23+
import { generateId } from "../../utils/generateId";
2324
import {
2425
SectionHeader,
2526
SlideList,
@@ -325,7 +326,7 @@ export function SlideshowPanel({ scenes, onPersist, onPersistNotes }: SlideshowP
325326

326327
const handleCreateSequence = useCallback(
327328
(label: string) => {
328-
const id = `seq-${crypto.randomUUID()}`;
329+
const id = `seq-${generateId()}`;
329330
applyManifest(createSequence(manifestRef.current, id, label)).catch(() => {});
330331
},
331332
[applyManifest],

packages/studio/src/components/panels/SlideshowSubPanels.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useState, useCallback, useId } from "react";
77
import type { SlideRef, SlideHotspot, SlideSequence } from "@hyperframes/core/slideshow";
88
import type { DomEditSelection } from "../editor/domEditing";
99
import type { SceneInfo } from "./slideshowPanelHelpers";
10+
import { generateId } from "../../utils/generateId";
1011

1112
// ── Section header (accordion toggle) ────────────────────────────────────
1213

@@ -425,7 +426,7 @@ export function HotspotTool({
425426
// fallow-ignore-next-line complexity
426427
const handleMakeHotspot = useCallback(() => {
427428
if (!selectedSceneId || !targetSequenceId || !elementKey) return;
428-
const id = `hotspot-${elementKey}-${crypto.randomUUID()}`;
429+
const id = `hotspot-${elementKey}-${generateId()}`;
429430
const label = hotspotLabel.trim() || elementKey;
430431
onAddHotspot(selectedSceneId, { id, label, target: targetSequenceId });
431432
setHotspotLabel("");

packages/studio/src/components/renders/useRenderQueue.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
22
import { trackStudioRenderStart } from "../../telemetry/events";
33
import { getAnonymousId } from "../../telemetry/config";
4+
import { generateId } from "../../utils/generateId";
45

56
export interface RenderJob {
67
id: string;
@@ -131,7 +132,7 @@ export function useRenderQueue(projectId: string | null) {
131132
});
132133
} catch {
133134
const failedJob: RenderJob = {
134-
id: crypto.randomUUID(),
135+
id: generateId(),
135136
status: "failed",
136137
progress: 0,
137138
error: "Could not reach render server. Use `hyperframes render` from the CLI instead.",
@@ -143,7 +144,7 @@ export function useRenderQueue(projectId: string | null) {
143144
}
144145
if (!res.ok) {
145146
const failedJob: RenderJob = {
146-
id: crypto.randomUUID(),
147+
id: generateId(),
147148
status: "failed",
148149
progress: 0,
149150
error: `Server error (${res.status}). Check the terminal for details.`,

packages/studio/src/hooks/gsapDragCommit.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe, expect, it, beforeEach } from "vitest";
22
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
33
import type { DomEditSelection } from "../components/editor/domEditingTypes";
4+
import { commitGsapPositionFromDrag } from "./gsapDragPositionCommit";
45
import {
56
commitStaticGsapPosition,
67
commitStaticGsapRotation,

packages/studio/src/telemetry/config.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// localStorage.setItem('hyperframes-studio:telemetryDisabled','1')
66
// ---------------------------------------------------------------------------
77

8+
import { generateId } from "../utils/generateId";
9+
810
const ANON_ID_KEY = "hyperframes-studio:anonymousId";
911
const OPT_OUT_KEY = "hyperframes-studio:telemetryDisabled";
1012
const NOTICE_KEY = "hyperframes-studio:telemetryNoticeShown";
@@ -18,8 +20,7 @@ function safeLocalStorage(): Storage | null {
1820
}
1921

2022
function newAnonymousId(): string {
21-
if (typeof crypto !== "undefined" && "randomUUID" in crypto) return crypto.randomUUID();
22-
return `anon-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
23+
return generateId();
2324
}
2425

2526
export function getAnonymousId(): string {

0 commit comments

Comments
 (0)