@hyperframes/studio 0.8.185 → 0.8.186

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/index.html CHANGED
@@ -14,7 +14,7 @@
14
14
  document.documentElement.dataset.theme = "paper";
15
15
  }
16
16
  </script>
17
- <script type="module" crossorigin src="/assets/index-C_6rTpaB.js"></script>
17
+ <script type="module" crossorigin src="/assets/index-Dn5FAk2e.js"></script>
18
18
  <link rel="stylesheet" crossorigin href="/assets/index-CESvLzz0.css">
19
19
  </head>
20
20
  <body>
package/dist/index.js CHANGED
@@ -72983,6 +72983,7 @@ function useRightPanelIntent() {
72983
72983
  }
72984
72984
 
72985
72985
  // src/components/renders/useRenderQueue.ts
72986
+ import { htmlInCanvasForm } from "@hyperframes/core/html-in-canvas";
72986
72987
  import { useState as useState109, useEffect as useEffect106, useCallback as useCallback95, useRef as useRef119, useMemo as useMemo69 } from "react";
72987
72988
 
72988
72989
  // src/components/renders/serverError.ts
@@ -73206,6 +73207,9 @@ function markFeedbackDismissed() {
73206
73207
  }
73207
73208
 
73208
73209
  // src/components/renders/useRenderQueue.ts
73210
+ function canPreviewMotionBlur() {
73211
+ return typeof document !== "undefined" && htmlInCanvasForm() !== null;
73212
+ }
73209
73213
  function hiddenIdsKey(projectId) {
73210
73214
  return `hf-studio-hidden-renders:${projectId}`;
73211
73215
  }
@@ -73320,7 +73324,8 @@ function useRenderQueue(projectId, activeCompPathRef) {
73320
73324
  const body = {
73321
73325
  fps,
73322
73326
  quality,
73323
- format
73327
+ format,
73328
+ previewMotionBlur: canPreviewMotionBlur()
73324
73329
  };
73325
73330
  if (browserTelemetryAllowed()) {
73326
73331
  body.telemetryDistinctId = getAnonymousId();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/studio",
3
- "version": "0.8.185",
3
+ "version": "0.8.186",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -59,12 +59,12 @@
59
59
  "dockview-react": "8.3.1",
60
60
  "gsap": "^3.13.0",
61
61
  "mediabunny": "^1.45.3",
62
- "@hyperframes/core": "0.8.185",
63
- "@hyperframes/parsers": "0.8.185",
64
- "@hyperframes/shader-transitions": "0.8.185",
65
- "@hyperframes/player": "0.8.185",
66
- "@hyperframes/studio-server": "0.8.185",
67
- "@hyperframes/sdk": "0.8.185"
62
+ "@hyperframes/core": "0.8.186",
63
+ "@hyperframes/player": "0.8.186",
64
+ "@hyperframes/shader-transitions": "0.8.186",
65
+ "@hyperframes/studio-server": "0.8.186",
66
+ "@hyperframes/sdk": "0.8.186",
67
+ "@hyperframes/parsers": "0.8.186"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@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.185"
84
+ "@hyperframes/producer": "0.8.186"
85
85
  },
86
86
  "peerDependencies": {
87
87
  "react": "19",
@@ -1,3 +1,4 @@
1
+ import { htmlInCanvasForm } from "@hyperframes/core/html-in-canvas";
1
2
  import { buildProjectApiPath } from "../../utils/projectRouting";
2
3
  import { useState, useEffect, useCallback, useRef, useMemo } from "react";
3
4
  import type { CanvasResolution } from "@hyperframes/parsers";
@@ -10,6 +11,11 @@ import { ffmpegInstallMessage, useFfmpegStatus } from "./useFfmpegStatus";
10
11
  import { requestStudioFeedback, type FeedbackContext } from "../feedback/feedbackTrigger";
11
12
  import { studioApiFetch } from "../../utils/studioApiFetch";
12
13
 
14
+ // WYSIWYG: the preview iframe runs in this browser, so a render blurs only if this one can.
15
+ function canPreviewMotionBlur(): boolean {
16
+ return typeof document !== "undefined" && htmlInCanvasForm() !== null;
17
+ }
18
+
13
19
  export interface RenderJob {
14
20
  id: string;
15
21
  status: "rendering" | "complete" | "failed" | "cancelled";
@@ -238,10 +244,12 @@ export function useRenderQueue(
238
244
  gpu?: boolean;
239
245
  telemetryDistinctId?: string;
240
246
  telemetryOptOut?: boolean;
247
+ previewMotionBlur: boolean;
241
248
  } = {
242
249
  fps,
243
250
  quality,
244
251
  format,
252
+ previewMotionBlur: canPreviewMotionBlur(),
245
253
  };
246
254
  // The id is MINTED by getAnonymousId(), so calling it unconditionally
247
255
  // created a telemetry identity for a profile that had opted out — and
@@ -0,0 +1,61 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ // WYSIWYG: a render only blurs what the Studio preview could show, and only the browser knows
4
+ // whether it has html-in-canvas. The request body is how it tells the server.
5
+
6
+ import { afterEach, describe, expect, it, vi } from "vitest";
7
+ import { startRenderAndReadBody, type MountedQueue } from "./renderQueueTestHarness";
8
+
9
+ vi.mock("../../telemetry/events", () => ({ trackStudioRenderStart: vi.fn() }));
10
+
11
+ const { useRenderQueue } = await import("./useRenderQueue");
12
+
13
+ let queue: MountedQueue | null = null;
14
+
15
+ async function startRenderBody(): Promise<Record<string, unknown>> {
16
+ const started = await startRenderAndReadBody(useRenderQueue, {
17
+ opts: { fps: 30, quality: "standard", format: "mp4" },
18
+ });
19
+ queue = started.queue;
20
+ return started.body;
21
+ }
22
+
23
+ function stubHtmlInCanvas(members: string[]): void {
24
+ vi.stubGlobal(
25
+ "CanvasRenderingContext2D",
26
+ class {
27
+ drawElementImage(): void {}
28
+ },
29
+ );
30
+ const proto = HTMLCanvasElement.prototype as unknown as Record<string, unknown>;
31
+ for (const name of ["requestPaint", ...members]) proto[name] = () => {};
32
+ }
33
+
34
+ afterEach(() => {
35
+ queue?.unmount();
36
+ queue = null;
37
+ document.body.innerHTML = "";
38
+ for (const name of ["requestPaint", "layoutSubtree", "updateElementGeometry"]) {
39
+ delete (HTMLCanvasElement.prototype as unknown as Record<string, unknown>)[name];
40
+ }
41
+ vi.unstubAllGlobals();
42
+ });
43
+
44
+ describe("render request previewMotionBlur", () => {
45
+ it("is false in a browser without html-in-canvas", async () => {
46
+ expect((await startRenderBody())["previewMotionBlur"]).toBe(false);
47
+ });
48
+
49
+ it.each([
50
+ ["the layoutsubtree form", "layoutSubtree"],
51
+ ["the content=drawable form", "updateElementGeometry"],
52
+ ])("is true in a browser with html-in-canvas in %s", async (_name, member) => {
53
+ stubHtmlInCanvas([member]);
54
+ expect((await startRenderBody())["previewMotionBlur"]).toBe(true);
55
+ });
56
+
57
+ it("is false when html-in-canvas has neither known form", async () => {
58
+ stubHtmlInCanvas([]);
59
+ expect((await startRenderBody())["previewMotionBlur"]).toBe(false);
60
+ });
61
+ });