@hyperframes/studio 0.7.37 → 0.7.38

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.
Files changed (75) hide show
  1. package/dist/assets/hyperframes-player-BBrKzTGd.js +459 -0
  2. package/dist/assets/index-BLRTwY5l.js +396 -0
  3. package/dist/assets/{index-BXYJbIax.js → index-ClUipc8i.js} +1 -1
  4. package/dist/assets/index-DJaiR8T2.css +1 -0
  5. package/dist/assets/{index-Ct-X2wlf.js → index-Ykq7ihge.js} +1 -1
  6. package/dist/index.d.ts +35 -10
  7. package/dist/index.html +2 -2
  8. package/dist/index.js +5146 -3321
  9. package/dist/index.js.map +1 -1
  10. package/package.json +7 -7
  11. package/src/App.tsx +19 -18
  12. package/src/components/AskAgentModal.tsx +23 -6
  13. package/src/components/LintModal.tsx +40 -10
  14. package/src/components/MediaPreview.tsx +36 -1
  15. package/src/components/SaveQueuePausedBanner.tsx +7 -6
  16. package/src/components/StudioErrorBoundary.tsx +19 -31
  17. package/src/components/StudioFeedbackBar.tsx +11 -2
  18. package/src/components/StudioGlobalDragOverlay.tsx +1 -1
  19. package/src/components/StudioHeader.tsx +184 -106
  20. package/src/components/StudioLeftSidebar.tsx +24 -3
  21. package/src/components/StudioOverlays.tsx +34 -8
  22. package/src/components/StudioRightPanel.tsx +154 -9
  23. package/src/components/StudioSplash.tsx +6 -3
  24. package/src/components/StudioToast.tsx +12 -11
  25. package/src/components/TimelineToolbar.test.tsx +9 -3
  26. package/src/components/TimelineToolbar.tsx +63 -29
  27. package/src/components/editor/PropertyPanel.tsx +18 -17
  28. package/src/components/editor/colorGradingScopePatch.test.ts +74 -0
  29. package/src/components/editor/colorGradingScopePatch.ts +57 -0
  30. package/src/components/editor/manualEditingAvailability.test.ts +0 -12
  31. package/src/components/editor/manualEditingAvailability.ts +0 -6
  32. package/src/components/editor/propertyPanelColorGradingControls.tsx +371 -329
  33. package/src/components/editor/propertyPanelColorGradingSection.tsx +274 -55
  34. package/src/components/editor/propertyPanelColorGradingSlider.tsx +275 -0
  35. package/src/components/editor/propertyPanelHelpers.ts +22 -91
  36. package/src/components/editor/propertyPanelMediaSection.tsx +253 -99
  37. package/src/components/editor/propertyPanelTypes.ts +111 -0
  38. package/src/components/nle/CompositionBreadcrumb.tsx +3 -2
  39. package/src/components/nle/NLELayout.tsx +54 -51
  40. package/src/components/nle/NLEPreview.tsx +41 -5
  41. package/src/components/nle/TimelineResizeDivider.tsx +97 -0
  42. package/src/components/nle/usePreviewBlockDrop.ts +31 -7
  43. package/src/components/renders/RenderQueue.tsx +125 -24
  44. package/src/components/renders/RenderQueueItem.tsx +132 -64
  45. package/src/components/renders/useRenderQueue.ts +136 -24
  46. package/src/components/storyboard/StoryboardFrameFocus.tsx +39 -16
  47. package/src/components/storyboard/StoryboardLoaded.tsx +19 -2
  48. package/src/components/storyboard/StoryboardView.tsx +6 -0
  49. package/src/components/studioColorGradingScope.ts +124 -0
  50. package/src/components/studioMediaJobs.ts +123 -0
  51. package/src/components/ui/Button.tsx +20 -11
  52. package/src/components/ui/HyperframesLoader.tsx +9 -2
  53. package/src/components/ui/SearchInput.tsx +53 -0
  54. package/src/components/ui/Tooltip.tsx +52 -6
  55. package/src/components/ui/VideoFrameThumbnail.tsx +26 -3
  56. package/src/components/ui/useDialogBehavior.ts +83 -0
  57. package/src/contexts/PanelLayoutContext.tsx +3 -0
  58. package/src/contexts/StudioContext.tsx +7 -0
  59. package/src/hooks/useCompositionContentLoader.ts +40 -0
  60. package/src/hooks/useEditorSave.ts +14 -0
  61. package/src/hooks/useFileManager.ts +39 -25
  62. package/src/hooks/useFrameCapture.ts +12 -1
  63. package/src/hooks/usePanelLayout.ts +1 -0
  64. package/src/hooks/usePreviewPersistence.ts +24 -15
  65. package/src/hooks/useStudioContextValue.ts +5 -0
  66. package/src/hooks/useToast.ts +66 -13
  67. package/src/styles/studio.css +61 -0
  68. package/src/utils/sdkResolverShadow.test.ts +53 -3
  69. package/src/utils/sdkResolverShadow.ts +41 -1
  70. package/src/utils/studioPendingEdits.test.ts +43 -0
  71. package/src/utils/studioPendingEdits.ts +45 -0
  72. package/src/utils/studioUiPreferences.ts +4 -0
  73. package/dist/assets/hyperframes-player-BGuumSiM.js +0 -459
  74. package/dist/assets/index-DmkOvZns.css +0 -1
  75. package/dist/assets/index-SYSbQyK4.js +0 -396
@@ -0,0 +1,74 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { patchMediaColorGradingInHtml } from "./colorGradingScopePatch";
3
+
4
+ describe("patchMediaColorGradingInHtml", () => {
5
+ it("adds color grading to video and image tags only", () => {
6
+ const { html, count } = patchMediaColorGradingInHtml(
7
+ `<div><video id="v"></video><img id="i" /><audio id="a"></audio></div>`,
8
+ `{"preset":"natural-lift"}`,
9
+ );
10
+
11
+ expect(count).toBe(2);
12
+ expect(html).toContain(
13
+ `video id="v" data-color-grading="{&quot;preset&quot;:&quot;natural-lift&quot;}"`,
14
+ );
15
+ expect(html).toContain(
16
+ `img id="i" data-color-grading="{&quot;preset&quot;:&quot;natural-lift&quot;}"`,
17
+ );
18
+ expect(html).toContain(`<audio id="a"></audio>`);
19
+ });
20
+
21
+ it("replaces existing color grading without touching other attributes", () => {
22
+ const { html, count } = patchMediaColorGradingInHtml(
23
+ `<video muted data-color-grading='old' playsinline></video>`,
24
+ `{"adjust":{"exposure":0.2}}`,
25
+ );
26
+
27
+ expect(count).toBe(1);
28
+ expect(html).toBe(
29
+ `<video muted data-color-grading="{&quot;adjust&quot;:{&quot;exposure&quot;:0.2}}" playsinline></video>`,
30
+ );
31
+ });
32
+
33
+ it("keeps quoted greater-than characters inside media attributes", () => {
34
+ const { html, count } = patchMediaColorGradingInHtml(
35
+ `<img alt="before > after" src="photo.jpg">`,
36
+ `{"adjust":{"contrast":0.1}}`,
37
+ );
38
+
39
+ expect(count).toBe(1);
40
+ expect(html).toBe(
41
+ `<img alt="before > after" src="photo.jpg" data-color-grading="{&quot;adjust&quot;:{&quot;contrast&quot;:0.1}}">`,
42
+ );
43
+ });
44
+
45
+ it("removes color grading when value is empty", () => {
46
+ const { html, count } = patchMediaColorGradingInHtml(
47
+ `<video data-color-grading="old"></video><img alt="">`,
48
+ null,
49
+ );
50
+
51
+ expect(count).toBe(1);
52
+ expect(html).toBe(`<video></video><img alt="">`);
53
+ });
54
+
55
+ it("does not patch media-looking text inside scripts, styles, or comments", () => {
56
+ const { html, count } = patchMediaColorGradingInHtml(
57
+ [
58
+ `<script>const tpl = '<video id="script-video"></video>';</script>`,
59
+ `<style>.icon::before { content: "<img>"; }</style>`,
60
+ `<!-- <img id="commented"> -->`,
61
+ `<video id="real"></video>`,
62
+ ].join(""),
63
+ `{"preset":"clean-studio"}`,
64
+ );
65
+
66
+ expect(count).toBe(1);
67
+ expect(html).toContain(`<script>const tpl = '<video id="script-video"></video>';</script>`);
68
+ expect(html).toContain(`<style>.icon::before { content: "<img>"; }</style>`);
69
+ expect(html).toContain(`<!-- <img id="commented"> -->`);
70
+ expect(html).toContain(
71
+ `<video id="real" data-color-grading="{&quot;preset&quot;:&quot;clean-studio&quot;}"></video>`,
72
+ );
73
+ });
74
+ });
@@ -0,0 +1,57 @@
1
+ const MEDIA_TAG_RE = /<\s*(video|img)\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi;
2
+ const COLOR_GRADING_ATTR_RE = /\sdata-color-grading=(["'])([\s\S]*?)\1/i;
3
+ const IGNORED_HTML_RANGE_RE = /<!--[\s\S]*?-->|<(script|style)\b[\s\S]*?<\/\1\s*>/gi;
4
+
5
+ interface TextRange {
6
+ start: number;
7
+ end: number;
8
+ }
9
+
10
+ function collectIgnoredRanges(html: string): TextRange[] {
11
+ const ranges: TextRange[] = [];
12
+ let match: RegExpExecArray | null;
13
+ IGNORED_HTML_RANGE_RE.lastIndex = 0;
14
+ while ((match = IGNORED_HTML_RANGE_RE.exec(html)) !== null) {
15
+ ranges.push({ start: match.index, end: match.index + match[0].length });
16
+ }
17
+ return ranges;
18
+ }
19
+
20
+ function isInsideRange(offset: number, ranges: TextRange[]): boolean {
21
+ return ranges.some((range) => offset >= range.start && offset < range.end);
22
+ }
23
+
24
+ function escapeHtmlAttribute(value: string): string {
25
+ return value
26
+ .replace(/&/g, "&amp;")
27
+ .replace(/"/g, "&quot;")
28
+ .replace(/</g, "&lt;")
29
+ .replace(/>/g, "&gt;");
30
+ }
31
+
32
+ function patchMediaTag(tag: string, value: string | null): string {
33
+ if (value === null || value === "") {
34
+ return tag.replace(COLOR_GRADING_ATTR_RE, "");
35
+ }
36
+
37
+ const nextAttr = ` data-color-grading="${escapeHtmlAttribute(value)}"`;
38
+ if (COLOR_GRADING_ATTR_RE.test(tag)) {
39
+ return tag.replace(COLOR_GRADING_ATTR_RE, nextAttr);
40
+ }
41
+ return tag.replace(/\s*\/?>$/, (end) => `${nextAttr}${end}`);
42
+ }
43
+
44
+ export function patchMediaColorGradingInHtml(
45
+ html: string,
46
+ value: string | null,
47
+ ): { html: string; count: number } {
48
+ let count = 0;
49
+ const ignoredRanges = collectIgnoredRanges(html);
50
+ const patched = html.replace(MEDIA_TAG_RE, (tag, _tagName, offset: number) => {
51
+ if (isInsideRange(offset, ignoredRanges)) return tag;
52
+ const next = patchMediaTag(tag, value);
53
+ if (next !== tag) count += 1;
54
+ return next;
55
+ });
56
+ return { html: patched, count };
57
+ }
@@ -24,18 +24,6 @@ describe("manual editing availability", () => {
24
24
  expect(availability.STUDIO_INSPECTOR_PANELS_ENABLED).toBe(true);
25
25
  });
26
26
 
27
- it("keeps color grading off by default", async () => {
28
- const availability = await loadAvailabilityWithEnv({});
29
- expect(availability.STUDIO_COLOR_GRADING_ENABLED).toBe(false);
30
- });
31
-
32
- it("enables color grading with an explicit env flag", async () => {
33
- const availability = await loadAvailabilityWithEnv({
34
- VITE_STUDIO_ENABLE_COLOR_GRADING: "1",
35
- });
36
- expect(availability.STUDIO_COLOR_GRADING_ENABLED).toBe(true);
37
- });
38
-
39
27
  it("disables preview selection when the inspector panel flag is explicitly off", async () => {
40
28
  const availability = await loadAvailabilityWithEnv({
41
29
  VITE_STUDIO_ENABLE_INSPECTOR_PANELS: "0",
@@ -64,12 +64,6 @@ export const STUDIO_GSAP_PANEL_ENABLED = resolveStudioBooleanEnvFlag(
64
64
  true,
65
65
  );
66
66
 
67
- export const STUDIO_COLOR_GRADING_ENABLED = resolveStudioBooleanEnvFlag(
68
- env,
69
- ["VITE_STUDIO_ENABLE_COLOR_GRADING", "VITE_STUDIO_COLOR_GRADING_ENABLED"],
70
- false,
71
- );
72
-
73
67
  export const STUDIO_KEYFRAMES_ENABLED = resolveStudioBooleanEnvFlag(
74
68
  env,
75
69
  ["VITE_STUDIO_ENABLE_KEYFRAMES", "VITE_STUDIO_KEYFRAMES_ENABLED"],