@hyperframes/studio 0.7.71 → 0.7.73

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 (79) hide show
  1. package/dist/assets/{hyperframes-player-C1X90psg.js → hyperframes-player-DGlzhf_s.js} +1 -1
  2. package/dist/assets/index-B37rWXo4.css +1 -0
  3. package/dist/assets/{index-DzxDHPR1.js → index-CbVTOJ-E.js} +1 -1
  4. package/dist/assets/{index-nY4lLBqM.js → index-CcA5WVJv.js} +1 -1
  5. package/dist/assets/index-DXcLI2wu.js +428 -0
  6. package/dist/index.d.ts +8 -0
  7. package/dist/index.html +2 -2
  8. package/dist/index.js +7762 -4261
  9. package/dist/index.js.map +1 -1
  10. package/package.json +7 -7
  11. package/src/App.tsx +4 -4
  12. package/src/components/StudioLeftSidebar.tsx +2 -3
  13. package/src/components/StudioRightPanel.tsx +10 -4
  14. package/src/components/editor/AnimationCard.test.tsx +100 -0
  15. package/src/components/editor/AnimationCard.tsx +5 -2
  16. package/src/components/editor/EaseCurveSection.test.tsx +348 -0
  17. package/src/components/editor/EaseCurveSection.tsx +444 -237
  18. package/src/components/editor/EaseParamFields.test.tsx +188 -0
  19. package/src/components/editor/EaseParamFields.tsx +246 -0
  20. package/src/components/editor/PropertyPanel.test.tsx +9 -7
  21. package/src/components/editor/PropertyPanelFlat.tsx +75 -88
  22. package/src/components/editor/colorGradingFrameAnalysis.test.ts +101 -0
  23. package/src/components/editor/colorGradingFrameAnalysis.ts +203 -0
  24. package/src/components/editor/colorGradingScopePatch.test.ts +3 -3
  25. package/src/components/editor/easeCurveSvg.tsx +65 -0
  26. package/src/components/editor/easePresetLibrary.test.ts +114 -0
  27. package/src/components/editor/easePresetLibrary.ts +49 -0
  28. package/src/components/editor/gsapAnimationConstants.ts +15 -13
  29. package/src/components/editor/propertyPanelColorCurveGraph.tsx +549 -0
  30. package/src/components/editor/propertyPanelColorCurves.test.tsx +158 -0
  31. package/src/components/editor/propertyPanelColorCurves.tsx +185 -0
  32. package/src/components/editor/propertyPanelColorGradingControls.tsx +115 -77
  33. package/src/components/editor/propertyPanelColorScopes.tsx +258 -0
  34. package/src/components/editor/propertyPanelColorSecondary.test.tsx +181 -0
  35. package/src/components/editor/propertyPanelColorSecondary.tsx +448 -0
  36. package/src/components/editor/propertyPanelColorWheels.test.tsx +119 -0
  37. package/src/components/editor/propertyPanelColorWheels.tsx +334 -0
  38. package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +109 -0
  39. package/src/components/editor/propertyPanelFlatColorGradingSection.test.tsx +239 -41
  40. package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +260 -300
  41. package/src/components/editor/propertyPanelFlatEffectControl.tsx +96 -0
  42. package/src/components/editor/propertyPanelFlatEffectSpecs.ts +305 -0
  43. package/src/components/editor/propertyPanelFlatEffectsSection.test.tsx +331 -0
  44. package/src/components/editor/propertyPanelFlatEffectsSection.tsx +503 -0
  45. package/src/components/editor/propertyPanelFlatOverlaysSection.test.tsx +113 -0
  46. package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +108 -0
  47. package/src/components/editor/propertyPanelFlatPrimitives.tsx +2 -0
  48. package/src/components/editor/propertyPanelGradingNumberField.test.tsx +79 -0
  49. package/src/components/editor/propertyPanelGradingNumberField.tsx +116 -0
  50. package/src/components/editor/propertyPanelPresetPreview.ts +36 -0
  51. package/src/components/editor/propertyPanelTypes.ts +13 -0
  52. package/src/components/editor/useColorGradingController.test.ts +331 -10
  53. package/src/components/editor/useColorGradingController.ts +57 -90
  54. package/src/components/editor/useColorGradingPreviews.ts +350 -0
  55. package/src/components/editor/useColorGradingScopes.test.tsx +143 -0
  56. package/src/components/editor/useColorGradingScopes.ts +62 -0
  57. package/src/components/editor/useInspectorGestureTransaction.ts +30 -1
  58. package/src/components/nle/NLEContext.tsx +1 -1
  59. package/src/contexts/PanelLayoutContext.tsx +3 -6
  60. package/src/hooks/useBlockCatalog.ts +31 -13
  61. package/src/hooks/useBlockHandlers.ts +22 -0
  62. package/src/hooks/useGsapScriptCommits.test.tsx +15 -0
  63. package/src/hooks/useGsapScriptCommits.ts +14 -1
  64. package/src/hooks/usePanelLayout.test.ts +68 -1
  65. package/src/hooks/usePanelLayout.ts +72 -34
  66. package/src/icons/SystemIcons.tsx +4 -0
  67. package/src/player/components/PlayerControls.tsx +68 -229
  68. package/src/player/components/ShortcutsPanel.tsx +2 -4
  69. package/src/player/components/SpeedMenu.tsx +1 -2
  70. package/src/telemetry/events.test.ts +9 -0
  71. package/src/telemetry/events.ts +5 -0
  72. package/src/utils/blockInstaller.test.ts +67 -0
  73. package/src/utils/blockInstaller.ts +162 -109
  74. package/src/utils/studioUiPreferences.test.ts +5 -0
  75. package/src/utils/studioUiPreferences.ts +8 -0
  76. package/dist/assets/index-CSCh2Vrp.js +0 -428
  77. package/dist/assets/index-Ceyz8Qt2.css +0 -1
  78. package/src/player/components/PlayerControls.test.ts +0 -20
  79. package/src/player/components/useSeekBarDrag.ts +0 -169
@@ -0,0 +1,96 @@
1
+ import {
2
+ HF_COLOR_GRADING_EFFECT_APPLY_DEFAULTS,
3
+ type HfColorGradingEffectKey,
4
+ type NormalizedHfColorGrading,
5
+ } from "@hyperframes/core/color-grading";
6
+ import { FlatSelectRow } from "./propertyPanelFlatSelectRow";
7
+ import { FlatSlider } from "./propertyPanelFlatPrimitives";
8
+ import { FlatToggle } from "./propertyPanelFlatToggle";
9
+ import {
10
+ DEFAULT_EFFECTS,
11
+ type EffectControl,
12
+ type EffectSpec,
13
+ } from "./propertyPanelFlatEffectSpecs";
14
+
15
+ type CommitEffect = (key: HfColorGradingEffectKey, value: number) => void;
16
+
17
+ function defaultValueFor(control: EffectControl, effect: EffectSpec): number {
18
+ return (
19
+ HF_COLOR_GRADING_EFFECT_APPLY_DEFAULTS[effect.key][control.key] ?? DEFAULT_EFFECTS[control.key]
20
+ );
21
+ }
22
+
23
+ function EffectSliderControl({
24
+ control,
25
+ value,
26
+ defaultValue,
27
+ onCommit,
28
+ }: {
29
+ control: Extract<EffectControl, { kind: "slider" }>;
30
+ value: number;
31
+ defaultValue: number;
32
+ onCommit: CommitEffect;
33
+ }) {
34
+ const scale = control.scale ?? 100;
35
+ const sliderValue = value * scale;
36
+ const displayValue = control.format
37
+ ? control.format(value)
38
+ : `${Number.isInteger(sliderValue) ? sliderValue : sliderValue.toFixed(1)}${control.unit ?? "%"}`;
39
+ return (
40
+ <FlatSlider
41
+ label={control.label}
42
+ value={sliderValue}
43
+ min={control.min ?? 0}
44
+ max={control.max ?? 100}
45
+ step={control.step ?? 1}
46
+ tier={Math.abs(value - defaultValue) > 0.0001 ? "explicitCustom" : "default"}
47
+ displayValue={displayValue}
48
+ onCommit={(next) => onCommit(control.key, next / scale)}
49
+ onReset={() => onCommit(control.key, defaultValue)}
50
+ />
51
+ );
52
+ }
53
+
54
+ export function FlatEffectControl({
55
+ control,
56
+ effect,
57
+ effects,
58
+ onCommit,
59
+ }: {
60
+ control: EffectControl;
61
+ effect: EffectSpec;
62
+ effects: NormalizedHfColorGrading["effects"];
63
+ onCommit: CommitEffect;
64
+ }) {
65
+ const value = effects[control.key];
66
+ const defaultValue = defaultValueFor(control, effect);
67
+ if (control.kind === "toggle") {
68
+ return (
69
+ <FlatToggle
70
+ label={control.label}
71
+ checked={value >= 0.5}
72
+ onChange={(next) => onCommit(control.key, next ? 1 : 0)}
73
+ />
74
+ );
75
+ }
76
+ if (control.kind === "select") {
77
+ return (
78
+ <FlatSelectRow
79
+ label={control.label}
80
+ value={String(Math.round(value))}
81
+ options={control.options}
82
+ tier={value === defaultValue ? "default" : "explicitCustom"}
83
+ onChange={(next) => onCommit(control.key, Number.parseInt(next, 10))}
84
+ onReset={() => onCommit(control.key, defaultValue)}
85
+ />
86
+ );
87
+ }
88
+ return (
89
+ <EffectSliderControl
90
+ control={control}
91
+ value={value}
92
+ defaultValue={defaultValue}
93
+ onCommit={onCommit}
94
+ />
95
+ );
96
+ }
@@ -0,0 +1,305 @@
1
+ import {
2
+ getHfColorGradingCapabilities,
3
+ normalizeHfColorGrading,
4
+ type HfColorGradingActiveEffectKey,
5
+ type HfColorGradingEffectKey,
6
+ type HfColorGradingPresetId,
7
+ } from "@hyperframes/core/color-grading";
8
+
9
+ type SliderControl = {
10
+ kind: "slider";
11
+ key: HfColorGradingEffectKey;
12
+ label: string;
13
+ min?: number;
14
+ max?: number;
15
+ step?: number;
16
+ scale?: number;
17
+ unit?: string;
18
+ format?: (value: number) => string;
19
+ };
20
+
21
+ export type EffectControl =
22
+ | SliderControl
23
+ | { kind: "toggle"; key: HfColorGradingEffectKey; label: string }
24
+ | {
25
+ kind: "select";
26
+ key: HfColorGradingEffectKey;
27
+ label: string;
28
+ options: Array<{ value: string; label: string }>;
29
+ };
30
+
31
+ export type EffectSpec = {
32
+ key: HfColorGradingActiveEffectKey;
33
+ label: string;
34
+ showMaster?: false;
35
+ masterLabel?: string;
36
+ masterFormat?: (value: number) => string;
37
+ max?: number;
38
+ settings?: readonly EffectControl[];
39
+ palette?: "mono" | "art";
40
+ };
41
+
42
+ type EffectGroup = {
43
+ label: string;
44
+ effects: readonly EffectSpec[];
45
+ presets?: readonly HfColorGradingPresetId[];
46
+ };
47
+
48
+ const EFFECT_CONTROL_LIMITS = new Map(
49
+ getHfColorGradingCapabilities().effects.flatMap((effect) =>
50
+ effect.controls.map((control) => [control.key, control] as const),
51
+ ),
52
+ );
53
+
54
+ function controlRange(key: HfColorGradingEffectKey, scale: number) {
55
+ const control = EFFECT_CONTROL_LIMITS.get(key);
56
+ return control ? { min: control.min * scale, max: control.max * scale, scale } : { scale };
57
+ }
58
+
59
+ const percent = (key: HfColorGradingEffectKey, label: string): SliderControl => ({
60
+ kind: "slider",
61
+ key,
62
+ label,
63
+ ...controlRange(key, 100),
64
+ });
65
+
66
+ const degrees = (key: HfColorGradingEffectKey, label: string, max: number): SliderControl => ({
67
+ kind: "slider",
68
+ key,
69
+ label,
70
+ ...controlRange(key, max),
71
+ unit: "deg",
72
+ });
73
+
74
+ function enumOptions(key: HfColorGradingEffectKey, labels: readonly string[]) {
75
+ const control = EFFECT_CONTROL_LIMITS.get(key);
76
+ const first = control?.min ?? 0;
77
+ const count = (control?.max ?? labels.length - 1) - first + 1;
78
+ if (labels.length !== count) throw new Error(`${key} labels do not match Core capabilities`);
79
+ return labels.map((label, index) => ({ value: String(first + index), label }));
80
+ }
81
+
82
+ const ASCII_STYLES = enumOptions("asciiStyle", [
83
+ "Standard",
84
+ "Dense",
85
+ "Minimal",
86
+ "Blocks",
87
+ "Braille",
88
+ "Technical",
89
+ "Matrix",
90
+ "Hatching",
91
+ ]);
92
+
93
+ const SCREEN_SHAPES = enumOptions("monoScreenShape", [
94
+ "Circle",
95
+ "Square",
96
+ "Diamond",
97
+ "Triangle",
98
+ "Line",
99
+ ]);
100
+
101
+ export const EFFECT_GROUPS: readonly EffectGroup[] = [
102
+ {
103
+ label: "Essentials",
104
+ effects: [
105
+ {
106
+ key: "blur",
107
+ label: "Blur",
108
+ masterLabel: "Radius",
109
+ masterFormat: (value) => `${(0.75 + Math.pow(value, 1.35) * 32).toFixed(1)}px`,
110
+ },
111
+ {
112
+ key: "pixelate",
113
+ label: "Pixelate",
114
+ masterLabel: "Cell Size",
115
+ masterFormat: (value) => `${Math.round(1 + value * 47)}px`,
116
+ },
117
+ {
118
+ key: "bloom",
119
+ label: "Bloom",
120
+ masterLabel: "Intensity",
121
+ max: controlRange("bloom", 100).max,
122
+ settings: [
123
+ {
124
+ kind: "slider",
125
+ key: "bloomRadius",
126
+ label: "Radius",
127
+ ...controlRange("bloomRadius", 1),
128
+ unit: "px",
129
+ },
130
+ ],
131
+ },
132
+ ],
133
+ },
134
+ {
135
+ label: "Retro & Glitch",
136
+ presets: ["creator-camcorder", "vhs-playback", "home-movie-8mm"],
137
+ effects: [
138
+ { key: "chromaBleed", label: "Chroma Softening", masterLabel: "Smear" },
139
+ {
140
+ key: "tapeDamage",
141
+ label: "Tape Damage",
142
+ showMaster: false,
143
+ settings: [
144
+ percent("tapeTracking", "Tracking"),
145
+ percent("tapeNoise", "Noise"),
146
+ percent("tapeSpeed", "Speed"),
147
+ ],
148
+ },
149
+ { key: "filmArtifacts", label: "Film Artifacts", masterLabel: "Density" },
150
+ {
151
+ key: "scanlines",
152
+ label: "Scanlines",
153
+ masterLabel: "Opacity",
154
+ settings: [
155
+ {
156
+ ...percent("scanlineCount", "Line Count"),
157
+ format: (value) => `${Math.round(50 + value * 450)}`,
158
+ },
159
+ percent("scanlineSoftness", "Softness"),
160
+ ],
161
+ },
162
+ { key: "crtCurvature", label: "CRT Curvature", masterLabel: "Curvature" },
163
+ {
164
+ key: "chromaticAberration",
165
+ label: "Channel Separation",
166
+ masterLabel: "Separation",
167
+ settings: [degrees("chromaticAngle", "Angle", 360)],
168
+ },
169
+ {
170
+ key: "digitalGlitch",
171
+ label: "Digital Glitch",
172
+ showMaster: false,
173
+ settings: [
174
+ percent("digitalGlitchColorSplit", "Color Split"),
175
+ percent("digitalGlitchLineTear", "Line Tear"),
176
+ percent("digitalGlitchPixelate", "Pixelation"),
177
+ percent("digitalGlitchBlockAmount", "Block Amount"),
178
+ percent("digitalGlitchBlockDisplacement", "Displacement"),
179
+ percent("digitalGlitchBlockOpacity", "Block Opacity"),
180
+ percent("digitalGlitchSpeed", "Speed"),
181
+ ],
182
+ },
183
+ ],
184
+ },
185
+ {
186
+ label: "Print",
187
+ presets: ["editorial-halftone", "two-ink-print"],
188
+ effects: [
189
+ {
190
+ key: "halftone",
191
+ label: "Halftone",
192
+ showMaster: false,
193
+ settings: [percent("halftoneSize", "Dot Size")],
194
+ },
195
+ {
196
+ key: "twoInkPrint",
197
+ label: "Two-Ink Print",
198
+ showMaster: false,
199
+ settings: [percent("twoInkPrintSize", "Dot Size")],
200
+ },
201
+ {
202
+ key: "dither",
203
+ label: "Ordered Dither",
204
+ showMaster: false,
205
+ palette: "mono",
206
+ settings: [
207
+ {
208
+ ...percent("ditherSize", "Point Size"),
209
+ format: (value) => `${(1 + value * 4).toFixed(1)}px`,
210
+ },
211
+ ],
212
+ },
213
+ {
214
+ key: "monoScreen",
215
+ label: "Mono Screen",
216
+ showMaster: false,
217
+ palette: "mono",
218
+ settings: [
219
+ {
220
+ ...percent("monoScreenSize", "Cell Size"),
221
+ format: (value) => `${Math.round(4 + value * 14)}px`,
222
+ },
223
+ degrees("monoScreenAngle", "Angle", 90),
224
+ percent("monoScreenSpread", "Spread"),
225
+ { kind: "select", key: "monoScreenShape", label: "Shape", options: SCREEN_SHAPES },
226
+ { kind: "toggle", key: "monoScreenInvert", label: "Invert" },
227
+ ],
228
+ },
229
+ ],
230
+ },
231
+ {
232
+ label: "Art",
233
+ effects: [
234
+ {
235
+ key: "ascii",
236
+ label: "ASCII",
237
+ showMaster: false,
238
+ palette: "mono",
239
+ settings: [
240
+ {
241
+ ...percent("asciiSize", "Character Size"),
242
+ format: (value) => `${Math.round(4 + value * 76)}px`,
243
+ },
244
+ { kind: "select", key: "asciiStyle", label: "Style", options: ASCII_STYLES },
245
+ { kind: "toggle", key: "asciiInvert", label: "Invert" },
246
+ { kind: "toggle", key: "asciiColor", label: "Use Source Color" },
247
+ percent("asciiRotation", "Edge Rotation"),
248
+ ],
249
+ },
250
+ {
251
+ key: "engraving",
252
+ label: "Engraving",
253
+ showMaster: false,
254
+ palette: "art",
255
+ settings: [
256
+ percent("engravingSpacing", "Spacing"),
257
+ percent("engravingMinThickness", "Min Thickness"),
258
+ percent("engravingMaxThickness", "Max Thickness"),
259
+ degrees("engravingAngle", "Angle", 180),
260
+ percent("engravingContrast", "Contrast"),
261
+ percent("engravingSharpness", "Sharpness"),
262
+ percent("engravingWave", "Wave"),
263
+ percent("engravingWaveFrequency", "Wave Frequency"),
264
+ ],
265
+ },
266
+ {
267
+ key: "crosshatch",
268
+ label: "Crosshatch",
269
+ showMaster: false,
270
+ palette: "art",
271
+ settings: [
272
+ percent("crosshatchSpacing", "Spacing"),
273
+ percent("crosshatchThickness", "Thickness"),
274
+ degrees("crosshatchAngle", "Angle", 180),
275
+ percent("crosshatchContrast", "Contrast"),
276
+ percent("crosshatchEdges", "Edge Detail"),
277
+ percent("crosshatchLineWeight", "Line Variation"),
278
+ percent("crosshatchWave", "Wave"),
279
+ percent("crosshatchWaveFrequency", "Wave Frequency"),
280
+ ],
281
+ },
282
+ {
283
+ key: "kuwahara",
284
+ label: "Kuwahara Paint",
285
+ showMaster: false,
286
+ settings: [
287
+ {
288
+ ...percent("kuwaharaRadius", "Radius"),
289
+ format: (value) => `${Math.round(2 + value * 14)}px`,
290
+ },
291
+ percent("kuwaharaSharpness", "Sharpness"),
292
+ {
293
+ ...percent("kuwaharaSaturation", "Saturation"),
294
+ format: (value) => `${Math.round(value * 200)}%`,
295
+ },
296
+ ],
297
+ },
298
+ ],
299
+ },
300
+ ];
301
+
302
+ export const EFFECT_SPECS = EFFECT_GROUPS.flatMap((group) => group.effects);
303
+ const DEFAULT_GRADING = normalizeHfColorGrading("neutral");
304
+ if (!DEFAULT_GRADING) throw new Error("Missing neutral color grading preset");
305
+ export const DEFAULT_EFFECTS = DEFAULT_GRADING.effects;