@hyperframes/studio 0.7.81 → 0.7.82
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-B32VouCm.js → hyperframes-player-HOyDfIO9.js} +1 -1
- package/dist/assets/{index-DCTAKfpa.js → index-C0c6LmEC.js} +1 -1
- package/dist/assets/{index-B5u2_pSh.js → index-DlPIfJDz.js} +101 -101
- package/dist/assets/{index-HeUw0EKI.js → index-fH499K3b.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/index.js +4 -10
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/components/renders/RenderQueue.test.tsx +62 -0
- package/src/components/renders/RenderQueue.tsx +6 -15
- package/src/components/renders/useRenderQueue.ts +5 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.82",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"gsap": "^3.13.0",
|
|
47
47
|
"marked": "^14.1.4",
|
|
48
48
|
"mediabunny": "^1.45.3",
|
|
49
|
-
"@hyperframes/core": "0.7.
|
|
50
|
-
"@hyperframes/parsers": "0.7.
|
|
51
|
-
"@hyperframes/
|
|
52
|
-
"@hyperframes/
|
|
53
|
-
"@hyperframes/studio-server": "0.7.
|
|
49
|
+
"@hyperframes/core": "0.7.82",
|
|
50
|
+
"@hyperframes/parsers": "0.7.82",
|
|
51
|
+
"@hyperframes/player": "0.7.82",
|
|
52
|
+
"@hyperframes/sdk": "0.7.82",
|
|
53
|
+
"@hyperframes/studio-server": "0.7.82"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/react": "19",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"vite": "^6.4.2",
|
|
66
66
|
"vitest": "^3.2.4",
|
|
67
67
|
"zustand": "^5.0.0",
|
|
68
|
-
"@hyperframes/producer": "0.7.
|
|
68
|
+
"@hyperframes/producer": "0.7.82"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"react": "19",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
|
|
3
|
+
import { act } from "react";
|
|
4
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { RenderQueue } from "./RenderQueue";
|
|
7
|
+
|
|
8
|
+
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });
|
|
9
|
+
|
|
10
|
+
let root: Root | null = null;
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
if (root) act(() => root?.unmount());
|
|
14
|
+
root = null;
|
|
15
|
+
document.body.innerHTML = "";
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
function mountRenderQueue(onStartRender: ReturnType<typeof vi.fn>) {
|
|
19
|
+
const host = document.createElement("div");
|
|
20
|
+
document.body.append(host);
|
|
21
|
+
root = createRoot(host);
|
|
22
|
+
act(() => {
|
|
23
|
+
root?.render(
|
|
24
|
+
<RenderQueue
|
|
25
|
+
jobs={[]}
|
|
26
|
+
projectId="demo"
|
|
27
|
+
onDelete={vi.fn()}
|
|
28
|
+
onClearCompleted={vi.fn()}
|
|
29
|
+
onStartRender={onStartRender}
|
|
30
|
+
isRendering={false}
|
|
31
|
+
compositionDimensions={{ width: 1920, height: 1080 }}
|
|
32
|
+
/>,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
return host;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe("RenderQueue resolution submission", () => {
|
|
39
|
+
it("submits the canonical landscape 4K preset selected by the user", () => {
|
|
40
|
+
const onStartRender = vi.fn();
|
|
41
|
+
const host = mountRenderQueue(onStartRender);
|
|
42
|
+
const resolutionSelect = [...host.querySelectorAll("select")].find((select) =>
|
|
43
|
+
[...select.options].some((option) => option.textContent?.startsWith("4K")),
|
|
44
|
+
);
|
|
45
|
+
if (!resolutionSelect) throw new Error("resolution selector did not render");
|
|
46
|
+
|
|
47
|
+
act(() => {
|
|
48
|
+
resolutionSelect.value = "4k";
|
|
49
|
+
resolutionSelect.dispatchEvent(new Event("change", { bubbles: true }));
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const exportButton = [...host.querySelectorAll("button")].find(
|
|
53
|
+
(button) => button.textContent === "Export",
|
|
54
|
+
);
|
|
55
|
+
if (!exportButton) throw new Error("export button did not render");
|
|
56
|
+
act(() => {
|
|
57
|
+
exportButton.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(onStartRender).toHaveBeenCalledWith("mp4", "standard", "landscape-4k", 30);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { memo, useState, useRef, useEffect, useId } from "react";
|
|
2
|
+
import { CANVAS_DIMENSIONS } from "@hyperframes/parsers";
|
|
2
3
|
import { RenderQueueItem } from "./RenderQueueItem";
|
|
3
4
|
import { Button } from "../ui/Button";
|
|
4
5
|
import type { RenderJob, ResolutionPreset } from "./useRenderQueue";
|
|
@@ -53,17 +54,6 @@ const SCALE_LABEL: Record<RenderScale, string> = {
|
|
|
53
54
|
"4k": "4K",
|
|
54
55
|
};
|
|
55
56
|
|
|
56
|
-
// Mirrors `CANVAS_DIMENSIONS` in @hyperframes/core. Studio can't import from
|
|
57
|
-
// the core barrel (it transitively pulls in node:fs) and the values are stable.
|
|
58
|
-
const CANVAS_DIMENSIONS: Record<ResolutionPreset, CompositionDimensions> = {
|
|
59
|
-
landscape: { width: 1920, height: 1080 },
|
|
60
|
-
portrait: { width: 1080, height: 1920 },
|
|
61
|
-
"landscape-4k": { width: 3840, height: 2160 },
|
|
62
|
-
"portrait-4k": { width: 2160, height: 3840 },
|
|
63
|
-
square: { width: 1080, height: 1080 },
|
|
64
|
-
"square-4k": { width: 2160, height: 2160 },
|
|
65
|
-
};
|
|
66
|
-
|
|
67
57
|
type CompAspect = "landscape" | "portrait" | "square";
|
|
68
58
|
|
|
69
59
|
function compAspect(dims: CompositionDimensions | null | undefined): CompAspect {
|
|
@@ -254,7 +244,7 @@ function FormatExportButton({
|
|
|
254
244
|
const persisted = getPersistedRenderSettings();
|
|
255
245
|
const [format, setFormat] = useState<"mp4" | "webm" | "mov">(persisted.format);
|
|
256
246
|
const [quality, setQuality] = useState<"draft" | "standard" | "high">(persisted.quality);
|
|
257
|
-
const [resolution, setResolution] = useState<
|
|
247
|
+
const [resolution, setResolution] = useState<RenderScale>("auto");
|
|
258
248
|
const [fps, setFps] = useState<24 | 30 | 60>(persisted.fps);
|
|
259
249
|
|
|
260
250
|
// MOV (ProRes) is a fixed-quality codec — quality selector has no effect.
|
|
@@ -290,7 +280,7 @@ function FormatExportButton({
|
|
|
290
280
|
<span className="text-[10px] text-panel-text-4">Resolution</span>
|
|
291
281
|
<select
|
|
292
282
|
value={resolution}
|
|
293
|
-
onChange={(e) => setResolution(e.target.value as
|
|
283
|
+
onChange={(e) => setResolution(e.target.value as RenderScale)}
|
|
294
284
|
disabled={isRendering}
|
|
295
285
|
className={selectCls}
|
|
296
286
|
>
|
|
@@ -352,8 +342,9 @@ function FormatExportButton({
|
|
|
352
342
|
// loading already disables the button; this guard also stops a
|
|
353
343
|
// double-click in the same frame from enqueueing two renders.
|
|
354
344
|
if (isRendering) return;
|
|
355
|
-
|
|
356
|
-
|
|
345
|
+
const outputResolution = resolveResolution(resolution, compositionDimensions);
|
|
346
|
+
trackStudioEvent("render_start", { format, quality, resolution: outputResolution, fps });
|
|
347
|
+
void onStartRender(format, quality, outputResolution, fps);
|
|
357
348
|
}}
|
|
358
349
|
className="w-full text-[11px] font-semibold"
|
|
359
350
|
>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
|
|
2
|
+
import type { CanvasResolution } from "@hyperframes/parsers";
|
|
2
3
|
import { trackStudioRenderStart } from "../../telemetry/events";
|
|
3
4
|
import { getAnonymousId } from "../../telemetry/config";
|
|
4
5
|
import { generateId } from "../../utils/generateId";
|
|
@@ -14,17 +15,10 @@ export interface RenderJob {
|
|
|
14
15
|
durationMs?: number;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
export type ResolutionPreset =
|
|
22
|
-
| "landscape"
|
|
23
|
-
| "portrait"
|
|
24
|
-
| "landscape-4k"
|
|
25
|
-
| "portrait-4k"
|
|
26
|
-
| "square"
|
|
27
|
-
| "square-4k";
|
|
18
|
+
// The CLI consumes this same source through @hyperframes/core's re-export.
|
|
19
|
+
// Importing from the browser-safe parsers package avoids the core barrel's
|
|
20
|
+
// Node-only transitive modules without duplicating the preset union in Studio.
|
|
21
|
+
export type ResolutionPreset = CanvasResolution;
|
|
28
22
|
|
|
29
23
|
export interface StartRenderOptions {
|
|
30
24
|
fps?: number;
|