@clipkit/editor 1.0.0

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 (248) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +51 -0
  3. package/dist/Editor.d.ts +3 -0
  4. package/dist/Editor.d.ts.map +1 -0
  5. package/dist/Editor.js +73 -0
  6. package/dist/Editor.js.map +1 -0
  7. package/dist/ExportDialog.d.ts +12 -0
  8. package/dist/ExportDialog.d.ts.map +1 -0
  9. package/dist/ExportDialog.js +30 -0
  10. package/dist/ExportDialog.js.map +1 -0
  11. package/dist/MotionPathOverlay.d.ts +5 -0
  12. package/dist/MotionPathOverlay.d.ts.map +1 -0
  13. package/dist/MotionPathOverlay.js +156 -0
  14. package/dist/MotionPathOverlay.js.map +1 -0
  15. package/dist/PerfHud.d.ts +2 -0
  16. package/dist/PerfHud.d.ts.map +1 -0
  17. package/dist/PerfHud.js +85 -0
  18. package/dist/PerfHud.js.map +1 -0
  19. package/dist/Stage.d.ts +2 -0
  20. package/dist/Stage.d.ts.map +1 -0
  21. package/dist/Stage.js +406 -0
  22. package/dist/Stage.js.map +1 -0
  23. package/dist/StageOverlay.d.ts +7 -0
  24. package/dist/StageOverlay.d.ts.map +1 -0
  25. package/dist/StageOverlay.js +508 -0
  26. package/dist/StageOverlay.js.map +1 -0
  27. package/dist/commands.d.ts +18 -0
  28. package/dist/commands.d.ts.map +1 -0
  29. package/dist/commands.js +103 -0
  30. package/dist/commands.js.map +1 -0
  31. package/dist/configuration.d.ts +9 -0
  32. package/dist/configuration.d.ts.map +1 -0
  33. package/dist/configuration.js +21 -0
  34. package/dist/configuration.js.map +1 -0
  35. package/dist/controls/AnimationsStack.d.ts +8 -0
  36. package/dist/controls/AnimationsStack.d.ts.map +1 -0
  37. package/dist/controls/AnimationsStack.js +188 -0
  38. package/dist/controls/AnimationsStack.js.map +1 -0
  39. package/dist/controls/CameraControl.d.ts +19 -0
  40. package/dist/controls/CameraControl.d.ts.map +1 -0
  41. package/dist/controls/CameraControl.js +47 -0
  42. package/dist/controls/CameraControl.js.map +1 -0
  43. package/dist/controls/CaptionLengthControl.d.ts +5 -0
  44. package/dist/controls/CaptionLengthControl.d.ts.map +1 -0
  45. package/dist/controls/CaptionLengthControl.js +11 -0
  46. package/dist/controls/CaptionLengthControl.js.map +1 -0
  47. package/dist/controls/CaptionTranscribe.d.ts +2 -0
  48. package/dist/controls/CaptionTranscribe.d.ts.map +1 -0
  49. package/dist/controls/CaptionTranscribe.js +95 -0
  50. package/dist/controls/CaptionTranscribe.js.map +1 -0
  51. package/dist/controls/ColorPicker.d.ts +17 -0
  52. package/dist/controls/ColorPicker.d.ts.map +1 -0
  53. package/dist/controls/ColorPicker.js +354 -0
  54. package/dist/controls/ColorPicker.js.map +1 -0
  55. package/dist/controls/ControlRenderer.d.ts +20 -0
  56. package/dist/controls/ControlRenderer.d.ts.map +1 -0
  57. package/dist/controls/ControlRenderer.js +106 -0
  58. package/dist/controls/ControlRenderer.js.map +1 -0
  59. package/dist/controls/CropControl.d.ts +2 -0
  60. package/dist/controls/CropControl.d.ts.map +1 -0
  61. package/dist/controls/CropControl.js +177 -0
  62. package/dist/controls/CropControl.js.map +1 -0
  63. package/dist/controls/EffectsStack.d.ts +8 -0
  64. package/dist/controls/EffectsStack.d.ts.map +1 -0
  65. package/dist/controls/EffectsStack.js +89 -0
  66. package/dist/controls/EffectsStack.js.map +1 -0
  67. package/dist/controls/GradeControl.d.ts +2 -0
  68. package/dist/controls/GradeControl.d.ts.map +1 -0
  69. package/dist/controls/GradeControl.js +120 -0
  70. package/dist/controls/GradeControl.js.map +1 -0
  71. package/dist/controls/KeyframeDiamond.d.ts +11 -0
  72. package/dist/controls/KeyframeDiamond.d.ts.map +1 -0
  73. package/dist/controls/KeyframeDiamond.js +87 -0
  74. package/dist/controls/KeyframeDiamond.js.map +1 -0
  75. package/dist/controls/LightingControls.d.ts +24 -0
  76. package/dist/controls/LightingControls.d.ts.map +1 -0
  77. package/dist/controls/LightingControls.js +108 -0
  78. package/dist/controls/LightingControls.js.map +1 -0
  79. package/dist/controls/ShapePresetControl.d.ts +4 -0
  80. package/dist/controls/ShapePresetControl.d.ts.map +1 -0
  81. package/dist/controls/ShapePresetControl.js +30 -0
  82. package/dist/controls/ShapePresetControl.js.map +1 -0
  83. package/dist/controls/ValueField.d.ts +10 -0
  84. package/dist/controls/ValueField.d.ts.map +1 -0
  85. package/dist/controls/ValueField.js +158 -0
  86. package/dist/controls/ValueField.js.map +1 -0
  87. package/dist/controls/VolumeControl.d.ts +10 -0
  88. package/dist/controls/VolumeControl.d.ts.map +1 -0
  89. package/dist/controls/VolumeControl.js +75 -0
  90. package/dist/controls/VolumeControl.js.map +1 -0
  91. package/dist/controls/compound.d.ts +46 -0
  92. package/dist/controls/compound.d.ts.map +1 -0
  93. package/dist/controls/compound.js +160 -0
  94. package/dist/controls/compound.js.map +1 -0
  95. package/dist/controls/layout.d.ts +38 -0
  96. package/dist/controls/layout.d.ts.map +1 -0
  97. package/dist/controls/layout.js +162 -0
  98. package/dist/controls/layout.js.map +1 -0
  99. package/dist/controls/primitives.d.ts +83 -0
  100. package/dist/controls/primitives.d.ts.map +1 -0
  101. package/dist/controls/primitives.js +194 -0
  102. package/dist/controls/primitives.js.map +1 -0
  103. package/dist/controls/transcribe.worker.d.ts +2 -0
  104. package/dist/controls/transcribe.worker.d.ts.map +1 -0
  105. package/dist/controls/transcribe.worker.js +22 -0
  106. package/dist/controls/transcribe.worker.js.map +1 -0
  107. package/dist/frame/AddElementBar.d.ts +2 -0
  108. package/dist/frame/AddElementBar.d.ts.map +1 -0
  109. package/dist/frame/AddElementBar.js +103 -0
  110. package/dist/frame/AddElementBar.js.map +1 -0
  111. package/dist/frame/Breadcrumbs.d.ts +2 -0
  112. package/dist/frame/Breadcrumbs.d.ts.map +1 -0
  113. package/dist/frame/Breadcrumbs.js +32 -0
  114. package/dist/frame/Breadcrumbs.js.map +1 -0
  115. package/dist/frame/GroupFlash.d.ts +2 -0
  116. package/dist/frame/GroupFlash.d.ts.map +1 -0
  117. package/dist/frame/GroupFlash.js +65 -0
  118. package/dist/frame/GroupFlash.js.map +1 -0
  119. package/dist/frame/Resizable.d.ts +12 -0
  120. package/dist/frame/Resizable.d.ts.map +1 -0
  121. package/dist/frame/Resizable.js +37 -0
  122. package/dist/frame/Resizable.js.map +1 -0
  123. package/dist/frame/Section.d.ts +23 -0
  124. package/dist/frame/Section.d.ts.map +1 -0
  125. package/dist/frame/Section.js +23 -0
  126. package/dist/frame/Section.js.map +1 -0
  127. package/dist/frame/ZoomControl.d.ts +9 -0
  128. package/dist/frame/ZoomControl.d.ts.map +1 -0
  129. package/dist/frame/ZoomControl.js +15 -0
  130. package/dist/frame/ZoomControl.js.map +1 -0
  131. package/dist/index.d.ts +9 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +13 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/lib/camera-gizmo.d.ts +15 -0
  136. package/dist/lib/camera-gizmo.d.ts.map +1 -0
  137. package/dist/lib/camera-gizmo.js +57 -0
  138. package/dist/lib/camera-gizmo.js.map +1 -0
  139. package/dist/lib/camera-tool.d.ts +43 -0
  140. package/dist/lib/camera-tool.d.ts.map +1 -0
  141. package/dist/lib/camera-tool.js +80 -0
  142. package/dist/lib/camera-tool.js.map +1 -0
  143. package/dist/lib/caption-segments.d.ts +17 -0
  144. package/dist/lib/caption-segments.d.ts.map +1 -0
  145. package/dist/lib/caption-segments.js +50 -0
  146. package/dist/lib/caption-segments.js.map +1 -0
  147. package/dist/lib/group.d.ts +12 -0
  148. package/dist/lib/group.d.ts.map +1 -0
  149. package/dist/lib/group.js +61 -0
  150. package/dist/lib/group.js.map +1 -0
  151. package/dist/lib/keyframes.d.ts +29 -0
  152. package/dist/lib/keyframes.d.ts.map +1 -0
  153. package/dist/lib/keyframes.js +92 -0
  154. package/dist/lib/keyframes.js.map +1 -0
  155. package/dist/lib/sfx-preview.d.ts +18 -0
  156. package/dist/lib/sfx-preview.d.ts.map +1 -0
  157. package/dist/lib/sfx-preview.js +74 -0
  158. package/dist/lib/sfx-preview.js.map +1 -0
  159. package/dist/lib/shape-presets.d.ts +35 -0
  160. package/dist/lib/shape-presets.d.ts.map +1 -0
  161. package/dist/lib/shape-presets.js +81 -0
  162. package/dist/lib/shape-presets.js.map +1 -0
  163. package/dist/lib/ungroup.d.ts +12 -0
  164. package/dist/lib/ungroup.d.ts.map +1 -0
  165. package/dist/lib/ungroup.js +40 -0
  166. package/dist/lib/ungroup.js.map +1 -0
  167. package/dist/lib/utils.d.ts +3 -0
  168. package/dist/lib/utils.d.ts.map +1 -0
  169. package/dist/lib/utils.js +9 -0
  170. package/dist/lib/utils.js.map +1 -0
  171. package/dist/panels/AssetsPanel.d.ts +2 -0
  172. package/dist/panels/AssetsPanel.d.ts.map +1 -0
  173. package/dist/panels/AssetsPanel.js +108 -0
  174. package/dist/panels/AssetsPanel.js.map +1 -0
  175. package/dist/panels/InspectorPanel.d.ts +2 -0
  176. package/dist/panels/InspectorPanel.d.ts.map +1 -0
  177. package/dist/panels/InspectorPanel.js +286 -0
  178. package/dist/panels/InspectorPanel.js.map +1 -0
  179. package/dist/panels/InterpolationPanel.d.ts +2 -0
  180. package/dist/panels/InterpolationPanel.d.ts.map +1 -0
  181. package/dist/panels/InterpolationPanel.js +226 -0
  182. package/dist/panels/InterpolationPanel.js.map +1 -0
  183. package/dist/panels/LayersTree.d.ts +4 -0
  184. package/dist/panels/LayersTree.d.ts.map +1 -0
  185. package/dist/panels/LayersTree.js +137 -0
  186. package/dist/panels/LayersTree.js.map +1 -0
  187. package/dist/panels/LeftRail.d.ts +6 -0
  188. package/dist/panels/LeftRail.d.ts.map +1 -0
  189. package/dist/panels/LeftRail.js +35 -0
  190. package/dist/panels/LeftRail.js.map +1 -0
  191. package/dist/panels/SourcePanel.d.ts +2 -0
  192. package/dist/panels/SourcePanel.d.ts.map +1 -0
  193. package/dist/panels/SourcePanel.js +470 -0
  194. package/dist/panels/SourcePanel.js.map +1 -0
  195. package/dist/panels/TimelinePanel.d.ts +11 -0
  196. package/dist/panels/TimelinePanel.d.ts.map +1 -0
  197. package/dist/panels/TimelinePanel.js +98 -0
  198. package/dist/panels/TimelinePanel.js.map +1 -0
  199. package/dist/panels/assets/SfxBrowser.d.ts +2 -0
  200. package/dist/panels/assets/SfxBrowser.d.ts.map +1 -0
  201. package/dist/panels/assets/SfxBrowser.js +49 -0
  202. package/dist/panels/assets/SfxBrowser.js.map +1 -0
  203. package/dist/panels/assets/use-assets.d.ts +11 -0
  204. package/dist/panels/assets/use-assets.d.ts.map +1 -0
  205. package/dist/panels/assets/use-assets.js +84 -0
  206. package/dist/panels/assets/use-assets.js.map +1 -0
  207. package/dist/panels/assets/use-sfx.d.ts +6 -0
  208. package/dist/panels/assets/use-sfx.d.ts.map +1 -0
  209. package/dist/panels/assets/use-sfx.js +47 -0
  210. package/dist/panels/assets/use-sfx.js.map +1 -0
  211. package/dist/panels/timeline/CanvasTimeline.d.ts +7 -0
  212. package/dist/panels/timeline/CanvasTimeline.d.ts.map +1 -0
  213. package/dist/panels/timeline/CanvasTimeline.js +1536 -0
  214. package/dist/panels/timeline/CanvasTimeline.js.map +1 -0
  215. package/dist/panels/timeline/Clip.d.ts +37 -0
  216. package/dist/panels/timeline/Clip.d.ts.map +1 -0
  217. package/dist/panels/timeline/Clip.js +176 -0
  218. package/dist/panels/timeline/Clip.js.map +1 -0
  219. package/dist/panels/timeline/CurveEditor.d.ts +2 -0
  220. package/dist/panels/timeline/CurveEditor.d.ts.map +1 -0
  221. package/dist/panels/timeline/CurveEditor.js +233 -0
  222. package/dist/panels/timeline/CurveEditor.js.map +1 -0
  223. package/dist/panels/timeline/MixerRail.d.ts +7 -0
  224. package/dist/panels/timeline/MixerRail.d.ts.map +1 -0
  225. package/dist/panels/timeline/MixerRail.js +295 -0
  226. package/dist/panels/timeline/MixerRail.js.map +1 -0
  227. package/dist/panels/timeline/Waveform.d.ts +11 -0
  228. package/dist/panels/timeline/Waveform.d.ts.map +1 -0
  229. package/dist/panels/timeline/Waveform.js +63 -0
  230. package/dist/panels/timeline/Waveform.js.map +1 -0
  231. package/dist/panels/timeline/clip-style.d.ts +10 -0
  232. package/dist/panels/timeline/clip-style.d.ts.map +1 -0
  233. package/dist/panels/timeline/clip-style.js +20 -0
  234. package/dist/panels/timeline/clip-style.js.map +1 -0
  235. package/dist/panels/timeline/filmstrip.d.ts +7 -0
  236. package/dist/panels/timeline/filmstrip.d.ts.map +1 -0
  237. package/dist/panels/timeline/filmstrip.js +135 -0
  238. package/dist/panels/timeline/filmstrip.js.map +1 -0
  239. package/dist/panels/timeline/timeline-layout.d.ts +65 -0
  240. package/dist/panels/timeline/timeline-layout.d.ts.map +1 -0
  241. package/dist/panels/timeline/timeline-layout.js +118 -0
  242. package/dist/panels/timeline/timeline-layout.js.map +1 -0
  243. package/dist/types.d.ts +68 -0
  244. package/dist/types.d.ts.map +1 -0
  245. package/dist/types.js +3 -0
  246. package/dist/types.js.map +1 -0
  247. package/package.json +56 -0
  248. package/src/styles.css +185 -0
@@ -0,0 +1,177 @@
1
+ // CropControl — the inspector's "Crop" widget for image + video. Label-left
2
+ // rows (matching the panel rhythm): a "Crop" summary row with a swatch that
3
+ // opens a FLY-OUT (modeled on the color picker) showing the media with a
4
+ // draggable / resizable crop frame, plus "Offset" and "Size" rows holding the
5
+ // numeric crop fields. Self-managed: reads the selected element + patches it
6
+ // directly (like GradeControl / ShapePresetControl).
7
+ //
8
+ // Writes the protocol crop_x / crop_y / crop_width / crop_height fields
9
+ // (normalized 0..1, origin top-left). The runtime applies the crop as a source
10
+ // sub-rectangle BEFORE `fit` (§5.3); identity (0,0,1,1) is a no-op.
11
+ 'use client';
12
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
13
+ import { useEffect, useRef, useState } from 'react';
14
+ import { useEditor, useEditorStore } from '@clipkit/editor-core';
15
+ import { NumberControl } from './primitives.js';
16
+ import { FieldRow } from '../frame/Section.js';
17
+ const MIN = 0.02; // smallest crop edge, so the frame never collapses to a line
18
+ function num(v, d) {
19
+ return typeof v === 'number' && Number.isFinite(v) ? v : d;
20
+ }
21
+ const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
22
+ export function CropControl() {
23
+ const selId = useEditorStore((s) => s.selection[0]);
24
+ const el = useEditorStore((s) => s.source.elements.find((e) => e.id === selId));
25
+ const { updateElement, moveElements, pushHistory } = useEditor();
26
+ const [open, setOpen] = useState(false);
27
+ const btnRef = useRef(null);
28
+ if (!el || !selId || (el.type !== 'image' && el.type !== 'video'))
29
+ return null;
30
+ const rect = {
31
+ x: num(el.crop_x, 0),
32
+ y: num(el.crop_y, 0),
33
+ width: num(el.crop_width, 1),
34
+ height: num(el.crop_height, 1),
35
+ };
36
+ const cropped = rect.x !== 0 || rect.y !== 0 || rect.width !== 1 || rect.height !== 1;
37
+ const src = typeof el.source === 'string' ? el.source : null;
38
+ const isVideo = el.type === 'video';
39
+ // live=true → skip-history scrub write; live=false → committed edit.
40
+ const patch = (r, live) => {
41
+ const p = { crop_x: r.x, crop_y: r.y, crop_width: r.width, crop_height: r.height };
42
+ if (live)
43
+ moveElements([{ id: selId, patch: p }], { skipHistory: true });
44
+ else
45
+ updateElement(selId, p);
46
+ };
47
+ const reset = () => updateElement(selId, {
48
+ crop_x: undefined, crop_y: undefined, crop_width: undefined, crop_height: undefined,
49
+ });
50
+ // One numeric field (stored 0..1, shown as a percentage). Editing one edge
51
+ // clamps it against the opposite so the rect stays valid.
52
+ const field = (key, glyph) => {
53
+ const set = (pct, live) => {
54
+ const v = clamp(pct / 100, 0, 1);
55
+ const next = { ...rect };
56
+ if (key === 'x')
57
+ next.x = clamp(v, 0, 1 - rect.width);
58
+ else if (key === 'y')
59
+ next.y = clamp(v, 0, 1 - rect.height);
60
+ else if (key === 'width')
61
+ next.width = clamp(v, MIN, 1 - rect.x);
62
+ else
63
+ next.height = clamp(v, MIN, 1 - rect.y);
64
+ patch(next, live);
65
+ };
66
+ return (_jsx(NumberControl, { value: Math.round(rect[key] * 100), min: 0, max: 100, step: 1, suffix: "%", prefix: glyph, fluid: true, onChange: set, onScrubStart: pushHistory }));
67
+ };
68
+ return (_jsxs(_Fragment, { children: [_jsxs(FieldRow, { label: "Crop", children: [_jsx("button", { ref: btnRef, type: "button", "aria-expanded": open, title: "Edit crop frame", onClick: () => setOpen((o) => !o), className: "relative w-[18px] h-[18px] rounded border border-border overflow-hidden cursor-pointer shrink-0 bg-black/40", children: _jsx(CropThumb, { src: src, isVideo: isVideo, rect: rect }) }), _jsx("button", { type: "button", onClick: () => setOpen((o) => !o), className: "h-6 flex-1 min-w-0 truncate bg-field hover:bg-field-hover rounded-md px-1.5 text-[11px] text-left text-foreground/90 outline-none transition-colors", children: cropped ? 'Cropped' : 'Edit frame' }), cropped && (_jsx("button", { type: "button", onClick: reset, title: "Remove crop", className: "h-6 px-1.5 rounded-md text-[10px] text-muted-foreground hover:text-foreground hover:bg-field transition-colors shrink-0", children: "Reset" }))] }), _jsx(FieldRow, { label: "Offset", children: _jsxs("div", { className: "flex-1 grid grid-cols-2 gap-2 min-w-0", children: [field('x', 'X'), field('y', 'Y')] }) }), _jsx(FieldRow, { label: "Size", children: _jsxs("div", { className: "flex-1 grid grid-cols-2 gap-2 min-w-0", children: [field('width', 'W'), field('height', 'H')] }) }), open && btnRef.current && (_jsx(CropPopover, { anchor: btnRef.current, src: src, isVideo: isVideo, rect: rect, onChange: patch, onStart: pushHistory, onClose: () => setOpen(false) }))] }));
69
+ }
70
+ // The fly-out — the media at its natural aspect with a draggable / resizable
71
+ // crop frame. Outside the frame is dimmed; the body moves, the four edge
72
+ // handles resize. Handles live in a NON-clipped layer so they read on the
73
+ // frame border even when the crop is flush with the media edge.
74
+ function CropPopover({ anchor, src, isVideo, rect, onChange, onStart, onClose, }) {
75
+ const ref = useRef(null);
76
+ const boxRef = useRef(null);
77
+ const [aspect, setAspect] = useState(16 / 9);
78
+ useEffect(() => {
79
+ const onDoc = (e) => {
80
+ const t = e.target;
81
+ if (ref.current && !ref.current.contains(t) && !anchor.contains(t))
82
+ onClose();
83
+ };
84
+ const onKey = (e) => { if (e.key === 'Escape')
85
+ onClose(); };
86
+ window.addEventListener('mousedown', onDoc);
87
+ window.addEventListener('keydown', onKey);
88
+ return () => {
89
+ window.removeEventListener('mousedown', onDoc);
90
+ window.removeEventListener('keydown', onKey);
91
+ };
92
+ }, [anchor, onClose]);
93
+ // Open to the LEFT of the inspector (panel sits on the right edge).
94
+ const r = anchor.getBoundingClientRect();
95
+ const WIDTH = 260;
96
+ const left = Math.max(8, r.left - WIDTH - 8);
97
+ const top = Math.max(8, Math.min(r.top, window.innerHeight - 320));
98
+ const startDrag = (mode) => (e) => {
99
+ e.preventDefault();
100
+ e.stopPropagation();
101
+ const box = boxRef.current;
102
+ if (!box)
103
+ return;
104
+ const b = box.getBoundingClientRect();
105
+ const sx = e.clientX, sy = e.clientY;
106
+ const s = { ...rect };
107
+ onStart();
108
+ const onMove = (ev) => {
109
+ const dx = (ev.clientX - sx) / b.width;
110
+ const dy = (ev.clientY - sy) / b.height;
111
+ let next;
112
+ if (mode === 'move') {
113
+ next = {
114
+ x: clamp(s.x + dx, 0, 1 - s.width),
115
+ y: clamp(s.y + dy, 0, 1 - s.height),
116
+ width: s.width,
117
+ height: s.height,
118
+ };
119
+ }
120
+ else {
121
+ let l = s.x, t = s.y, rr = s.x + s.width, bb = s.y + s.height;
122
+ if (mode === 'w')
123
+ l = clamp(s.x + dx, 0, rr - MIN);
124
+ else if (mode === 'e')
125
+ rr = clamp(s.x + s.width + dx, l + MIN, 1);
126
+ else if (mode === 'n')
127
+ t = clamp(s.y + dy, 0, bb - MIN);
128
+ else
129
+ bb = clamp(s.y + s.height + dy, t + MIN, 1);
130
+ next = { x: l, y: t, width: rr - l, height: bb - t };
131
+ }
132
+ onChange(next, true);
133
+ };
134
+ const onUp = () => {
135
+ window.removeEventListener('pointermove', onMove);
136
+ window.removeEventListener('pointerup', onUp);
137
+ };
138
+ window.addEventListener('pointermove', onMove);
139
+ window.addEventListener('pointerup', onUp);
140
+ };
141
+ const pctRect = {
142
+ left: `${rect.x * 100}%`,
143
+ top: `${rect.y * 100}%`,
144
+ width: `${rect.width * 100}%`,
145
+ height: `${rect.height * 100}%`,
146
+ };
147
+ // Edge handles — white bars centered on each edge midpoint, with a dark ring
148
+ // so they read on any image. -translate centers them ON the border.
149
+ const handle = 'absolute bg-white border border-black/50 rounded-sm shadow-[0_0_0_1px_rgba(0,0,0,0.35)] -translate-x-1/2 -translate-y-1/2';
150
+ // Rendered INLINE (not portaled) — same as the color picker — so theme tokens
151
+ // resolve and `fixed` still escapes the inspector's scroll clip.
152
+ return (_jsxs("div", { ref: ref, className: "fixed z-50 rounded-lg border bg-popover shadow-2xl p-2 flex flex-col gap-2 select-none", style: { left, top, width: WIDTH, borderColor: 'var(--color-popover-border)' }, role: "dialog", "aria-label": "Crop", children: [_jsxs("div", { ref: boxRef, className: "relative w-full rounded-md bg-[repeating-conic-gradient(#2a2a2a_0%_25%,#1d1d1d_0%_50%)] bg-[length:16px_16px] touch-none", style: { aspectRatio: String(aspect) }, children: [_jsxs("div", { className: "absolute inset-0 overflow-hidden rounded-md", children: [src && !isVideo && (
153
+ // eslint-disable-next-line @next/next/no-img-element
154
+ _jsx("img", { src: src, alt: "", draggable: false, onLoad: (e) => {
155
+ const im = e.currentTarget;
156
+ if (im.naturalWidth > 0 && im.naturalHeight > 0)
157
+ setAspect(im.naturalWidth / im.naturalHeight);
158
+ }, className: "absolute inset-0 w-full h-full object-fill pointer-events-none" })), src && isVideo && (_jsx("video", { src: src, muted: true, playsInline: true, preload: "metadata", onLoadedMetadata: (e) => {
159
+ const v = e.currentTarget;
160
+ if (v.videoWidth > 0 && v.videoHeight > 0)
161
+ setAspect(v.videoWidth / v.videoHeight);
162
+ }, className: "absolute inset-0 w-full h-full object-fill pointer-events-none" })), _jsx("div", { className: "absolute inset-x-0 top-0 bg-black/55 pointer-events-none", style: { height: pctRect.top } }), _jsx("div", { className: "absolute inset-x-0 bottom-0 bg-black/55 pointer-events-none", style: { top: `${(rect.y + rect.height) * 100}%` } }), _jsx("div", { className: "absolute bg-black/55 pointer-events-none", style: { left: 0, width: pctRect.left, top: pctRect.top, height: pctRect.height } }), _jsx("div", { className: "absolute bg-black/55 pointer-events-none", style: { right: 0, left: `${(rect.x + rect.width) * 100}%`, top: pctRect.top, height: pctRect.height } })] }), _jsxs("div", { className: "absolute border-2 border-white shadow-[0_0_0_1px_rgba(0,0,0,0.5)] cursor-move", style: pctRect, onPointerDown: startDrag('move'), children: [_jsxs("div", { className: "absolute inset-0 pointer-events-none", children: [_jsx("div", { className: "absolute top-1/3 inset-x-0 border-t border-white/25" }), _jsx("div", { className: "absolute top-2/3 inset-x-0 border-t border-white/25" }), _jsx("div", { className: "absolute left-1/3 inset-y-0 border-l border-white/25" }), _jsx("div", { className: "absolute left-2/3 inset-y-0 border-l border-white/25" })] }), _jsx("div", { className: `${handle} w-4 h-2 left-1/2 top-0 cursor-ns-resize`, onPointerDown: startDrag('n') }), _jsx("div", { className: `${handle} w-4 h-2 left-1/2 top-full cursor-ns-resize`, onPointerDown: startDrag('s') }), _jsx("div", { className: `${handle} w-2 h-4 left-0 top-1/2 cursor-ew-resize`, onPointerDown: startDrag('w') }), _jsx("div", { className: `${handle} w-2 h-4 left-full top-1/2 cursor-ew-resize`, onPointerDown: startDrag('e') })] })] }), _jsxs("div", { className: "flex items-center justify-between text-[10px] text-muted-foreground tabular-nums", children: [_jsxs("span", { children: [Math.round(rect.width * 100), "% \u00D7 ", Math.round(rect.height * 100), "%"] }), _jsx("button", { type: "button", onClick: () => onChange({ x: 0, y: 0, width: 1, height: 1 }, false), className: "hover:text-foreground transition-colors", children: "Reset" })] })] }));
163
+ }
164
+ // The 18px panel swatch — the media with the crop region punched out of a dim
165
+ // overlay, so the row previews what's kept at a glance.
166
+ function CropThumb({ src, isVideo, rect }) {
167
+ const frame = {
168
+ left: `${rect.x * 100}%`,
169
+ top: `${rect.y * 100}%`,
170
+ width: `${rect.width * 100}%`,
171
+ height: `${rect.height * 100}%`,
172
+ };
173
+ return (_jsxs(_Fragment, { children: [src && !isVideo && (
174
+ // eslint-disable-next-line @next/next/no-img-element
175
+ _jsx("img", { src: src, alt: "", draggable: false, className: "absolute inset-0 w-full h-full object-cover opacity-50" })), src && isVideo && (_jsx("video", { src: src, muted: true, playsInline: true, preload: "metadata", className: "absolute inset-0 w-full h-full object-cover opacity-50" })), _jsx("span", { className: "absolute border border-white/80 box-border", style: frame })] }));
176
+ }
177
+ //# sourceMappingURL=CropControl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CropControl.js","sourceRoot":"","sources":["../../src/controls/CropControl.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Effect } from '@clipkit/protocol';
2
+ export declare function EffectsStackControl({ value, onChange, onScrubStart, onScrubEnd, }: {
3
+ value: Effect[] | undefined;
4
+ onChange: (next: Effect[] | undefined, live: boolean) => void;
5
+ onScrubStart?: () => void;
6
+ onScrubEnd?: () => void;
7
+ }): import("react").JSX.Element;
8
+ //# sourceMappingURL=EffectsStack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EffectsStack.d.ts","sourceRoot":"","sources":["../../src/controls/EffectsStack.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AA6ChD,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,UAAU,GACX,EAAE;IACD,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB,+BA+IA"}
@@ -0,0 +1,89 @@
1
+ // Effects stack — the design-refs "FX rows" pattern: colored type
2
+ // chip, expand to params, × to remove, reorder, + to add. Params
3
+ // render FROM the registry's effect scopes through the one
4
+ // ControlRenderer mapping (D2) — adding an effect type to the
5
+ // protocol makes it appear here with zero UI work.
6
+ 'use client';
7
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
+ import { useState } from 'react';
9
+ import { cn } from '../lib/utils.js';
10
+ import { useConfiguration } from '../configuration.js';
11
+ import { ControlRenderer } from './ControlRenderer.js';
12
+ /** Display defaults mirroring PROTOCOL §4.7 — shown when a param is
13
+ * unauthored so the knob reads the value the runtime will use. */
14
+ const PARAM_DEFAULTS = {
15
+ pixelate: { cell_size: 8 },
16
+ dither: { levels: 4 },
17
+ halftone: { cell_size: 8, angle: 45 },
18
+ ascii: { cell_size: 12 },
19
+ glow: { radius: 20, intensity: 1, color: '#FFFFFF' },
20
+ drop_shadow: { offset_x: 0, offset_y: 12, blur: 18, color: '#000000', opacity: 0.6 },
21
+ stroke: { width: 4, color: '#FFFFFF' },
22
+ chroma_key: { color: '#00FF00', tolerance: 0.18, softness: 0.1, spill: 0.5 },
23
+ luma_key: { threshold: 0.5, softness: 0.1, invert: false },
24
+ levels: { in_black: 0, in_white: 1, gamma: 1, out_black: 0, out_white: 1 },
25
+ lut: { intensity: 1 },
26
+ fractal_noise: { scale: 100, evolution: 0, offset_x: 0, offset_y: 0, octaves: 4, seed: 0 },
27
+ turbulent_displace: { amount: 16, scale: 120, evolution: 0, octaves: 2, seed: 0 },
28
+ glass: {
29
+ blur_radius: 12, refraction: 16, edge_width: 32, edge_highlight: 0.35,
30
+ shadow: 0, dispersion: 0, backdrop_saturation: 1, mode: 'pill',
31
+ },
32
+ };
33
+ /** Chip hues per effect family (stylize / layer style / key / color / generate). */
34
+ const CHIP_CLS = {
35
+ pixelate: 'bg-violet-500/20 text-violet-300',
36
+ dither: 'bg-violet-500/20 text-violet-300',
37
+ halftone: 'bg-violet-500/20 text-violet-300',
38
+ ascii: 'bg-violet-500/20 text-violet-300',
39
+ glow: 'bg-amber-500/20 text-amber-300',
40
+ drop_shadow: 'bg-amber-500/20 text-amber-300',
41
+ stroke: 'bg-amber-500/20 text-amber-300',
42
+ chroma_key: 'bg-emerald-500/20 text-emerald-300',
43
+ luma_key: 'bg-emerald-500/20 text-emerald-300',
44
+ levels: 'bg-sky-500/20 text-sky-300',
45
+ lut: 'bg-sky-500/20 text-sky-300',
46
+ fractal_noise: 'bg-rose-500/20 text-rose-300',
47
+ turbulent_displace: 'bg-rose-500/20 text-rose-300',
48
+ glass: 'bg-cyan-500/20 text-cyan-300',
49
+ };
50
+ export function EffectsStackControl({ value, onChange, onScrubStart, onScrubEnd, }) {
51
+ const { registry } = useConfiguration();
52
+ const [expanded, setExpanded] = useState(null);
53
+ const [adding, setAdding] = useState(false);
54
+ const effects = value ?? [];
55
+ const types = Object.keys(registry.effects);
56
+ const commit = (next, live = false) => onChange(next.length > 0 ? next : undefined, live);
57
+ const setEffect = (i, patch, live) => commit(effects.map((fx, j) => (j === i ? { ...fx, ...patch } : fx)), live);
58
+ const move = (i, dir) => {
59
+ const j = i + dir;
60
+ if (j < 0 || j >= effects.length)
61
+ return;
62
+ const next = [...effects];
63
+ [next[i], next[j]] = [next[j], next[i]];
64
+ commit(next);
65
+ setExpanded(null);
66
+ };
67
+ return (_jsxs("div", { className: "flex flex-col gap-0.5 w-full", children: [effects.map((fx, i) => {
68
+ const scope = registry.effects[fx.type];
69
+ const open = expanded === i;
70
+ return (_jsxs("div", { className: "border border-border/60 rounded", children: [_jsxs("div", { className: "flex items-center gap-1 h-7 px-1", children: [_jsxs("button", { type: "button", className: "flex items-center gap-1.5 flex-1 min-w-0 text-left", onClick: () => setExpanded(open ? null : i), "aria-expanded": open, children: [_jsx("svg", { width: "6", height: "6", viewBox: "0 0 8 8", "aria-hidden": "true", className: cn('text-muted-foreground shrink-0 transition-transform', open && 'rotate-90'), children: _jsx("path", { d: "M2 1 L6 4 L2 7 Z", fill: "currentColor" }) }), _jsx("span", { className: cn('px-1.5 py-px rounded text-[10px] font-medium truncate', CHIP_CLS[fx.type] ?? 'bg-card text-muted-foreground'), children: fx.type })] }), _jsx("button", { type: "button", className: "w-4 h-4 grid place-items-center text-muted-foreground/50 hover:text-foreground text-[9px] disabled:opacity-20", disabled: i === 0, onClick: () => move(i, -1), "aria-label": "Move up", children: "\u25B2" }), _jsx("button", { type: "button", className: "w-4 h-4 grid place-items-center text-muted-foreground/50 hover:text-foreground text-[9px] disabled:opacity-20", disabled: i === effects.length - 1, onClick: () => move(i, 1), "aria-label": "Move down", children: "\u25BC" }), _jsx("button", { type: "button", className: "w-4 h-4 grid place-items-center text-muted-foreground/50 hover:text-foreground text-[11px]", onClick: () => {
71
+ commit(effects.filter((_, j) => j !== i));
72
+ setExpanded(null);
73
+ }, "aria-label": "Remove effect", children: "\u00D7" })] }), open && scope && (_jsx("div", { className: "px-2 pb-2 flex flex-col", children: scope.fields.map((spec) => {
74
+ const raw = fx[spec.path];
75
+ const shown = raw ?? PARAM_DEFAULTS[fx.type]?.[spec.path];
76
+ return (
77
+ // Same row system as the inspector: 32px pitch,
78
+ // fixed label column, fluid well.
79
+ _jsxs("div", { className: "flex items-center gap-2 h-8", children: [_jsx("span", { className: "w-16 shrink-0 text-[10px] text-muted-foreground truncate", children: spec.label }), _jsx("div", { className: "flex-1 min-w-0 flex items-center gap-2", children: _jsx(ControlRenderer, { spec: spec, value: shown, fluid: true, trailing: spec.animatable ? (_jsx("span", { className: Array.isArray(raw) ? 'text-primary text-[9px]' : 'text-muted-foreground/40 text-[9px]', title: Array.isArray(raw) ? 'Animated' : 'Animatable', children: Array.isArray(raw) ? '◆' : '◇' })) : undefined, onChange: (v, live) => setEffect(i, { [spec.path]: v }, live), onScrubStart: onScrubStart, onScrubEnd: onScrubEnd }) })] }, spec.path));
80
+ }) }))] }, i));
81
+ }), adding ? (_jsxs("select", { autoFocus: true, className: "h-6 bg-field hover:bg-field-hover rounded-md px-1 text-[11px] text-foreground outline-none cursor-pointer transition-colors", defaultValue: "", onBlur: () => setAdding(false), onChange: (e) => {
82
+ if (e.target.value) {
83
+ commit([...effects, { type: e.target.value }]);
84
+ setExpanded(effects.length);
85
+ }
86
+ setAdding(false);
87
+ }, children: [_jsx("option", { value: "", disabled: true, children: "Add effect\u2026" }), types.map((t) => (_jsx("option", { value: t, children: t }, t)))] })) : (_jsx("button", { type: "button", className: "self-start h-5 px-1.5 rounded text-[10px] text-muted-foreground hover:text-foreground hover:bg-card transition", onClick: () => setAdding(true), children: "+ Effect" }))] }));
88
+ }
89
+ //# sourceMappingURL=EffectsStack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EffectsStack.js","sourceRoot":"","sources":["../../src/controls/EffectsStack.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function GradeControl(): import("react").JSX.Element | null;
2
+ //# sourceMappingURL=GradeControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GradeControl.d.ts","sourceRoot":"","sources":["../../src/controls/GradeControl.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,YAAY,uCAgD3B"}
@@ -0,0 +1,120 @@
1
+ // GradeControl — the inspector's "Color" widget. A compact summary row in the
2
+ // panel; clicking opens a FLY-OUT (like the color picker) with the grading
3
+ // controls so the narrow inspector stays scannable. Self-managed (reads the
4
+ // selected element + patches it directly, like ShapePresetControl).
5
+ //
6
+ // v1 writes the existing base filter fields (brightness / contrast / saturation
7
+ // / hue_rotate) — zero protocol change. Looks are named presets that expand to
8
+ // those same fields. (Tone via `levels` and LUT looks come next; true
9
+ // temperature/tint needs a protocol field and is intentionally absent.)
10
+ 'use client';
11
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
12
+ import { useEffect, useRef, useState } from 'react';
13
+ import { useEditor, useEditorStore } from '@clipkit/editor-core';
14
+ // Named looks — expand to base filters (no new fields). "Original" resets.
15
+ const LOOKS = [
16
+ { id: 'original', label: 'Original', f: {} },
17
+ { id: 'punch', label: 'Punch', f: { contrast: 1.18, saturation: 1.25 } },
18
+ { id: 'vivid', label: 'Vivid', f: { brightness: 1.03, contrast: 1.1, saturation: 1.4 } },
19
+ { id: 'faded', label: 'Faded', f: { brightness: 1.05, contrast: 0.85, saturation: 0.8 } },
20
+ { id: 'bw', label: 'B&W', f: { saturation: 0, contrast: 1.1 } },
21
+ { id: 'noir', label: 'Noir', f: { saturation: 0, contrast: 1.35, brightness: 0.95 } },
22
+ ];
23
+ const FIELDS = [
24
+ { key: 'brightness', label: 'Brightness', min: 0, max: 2, def: 1, unit: '%' },
25
+ { key: 'contrast', label: 'Contrast', min: 0, max: 2, def: 1, unit: '%' },
26
+ { key: 'saturation', label: 'Saturation', min: 0, max: 2, def: 1, unit: '%' },
27
+ { key: 'hue_rotate', label: 'Hue', min: -180, max: 180, def: 0, unit: '°' },
28
+ ];
29
+ function num(v, d) {
30
+ return typeof v === 'number' && Number.isFinite(v) ? v : d;
31
+ }
32
+ export function GradeControl() {
33
+ const selId = useEditorStore((s) => s.selection[0]);
34
+ const el = useEditorStore((s) => s.source.elements.find((e) => e.id === selId));
35
+ const [open, setOpen] = useState(false);
36
+ const btnRef = useRef(null);
37
+ if (!el || !selId)
38
+ return null;
39
+ const f = {
40
+ brightness: num(el.brightness, 1),
41
+ contrast: num(el.contrast, 1),
42
+ saturation: num(el.saturation, 1),
43
+ hue_rotate: num(el.hue_rotate, 0),
44
+ };
45
+ const adjusted = f.brightness !== 1 || f.contrast !== 1 || f.saturation !== 1 || f.hue_rotate !== 0;
46
+ // Preview on the element's own image when it is one; gradient reference otherwise.
47
+ const src = el.source;
48
+ const previewSrc = el.type === 'image' && typeof src === 'string' ? src : null;
49
+ // Same shape as the color input (ColorControl): an 18px swatch + a field.
50
+ return (_jsxs("div", { className: "flex items-center gap-1 w-full min-w-0", children: [_jsx("button", { ref: btnRef, type: "button", "aria-expanded": open, title: "Color grade", onClick: () => setOpen((o) => !o), className: "relative w-[18px] h-[18px] rounded border border-border overflow-hidden cursor-pointer shrink-0", children: _jsx(GradeSwatch, { f: f }) }), _jsx("button", { type: "button", onClick: () => setOpen((o) => !o), className: "h-6 flex-1 min-w-0 truncate bg-field hover:bg-field-hover rounded-md px-1.5 text-[11px] text-left text-foreground/90 outline-none transition-colors", children: adjusted ? 'Adjusted' : 'Default' }), open && btnRef.current && (_jsx(GradePopover, { selId: selId, anchor: btnRef.current, f: f, previewSrc: previewSrc, onClose: () => setOpen(false) }))] }));
51
+ }
52
+ function GradePopover({ selId, anchor, f, previewSrc, onClose, }) {
53
+ const { updateElement, moveElements, pushHistory } = useEditor();
54
+ const ref = useRef(null);
55
+ useEffect(() => {
56
+ const onDoc = (e) => {
57
+ const t = e.target;
58
+ if (ref.current && !ref.current.contains(t) && !anchor.contains(t))
59
+ onClose();
60
+ };
61
+ const onKey = (e) => { if (e.key === 'Escape')
62
+ onClose(); };
63
+ window.addEventListener('mousedown', onDoc);
64
+ window.addEventListener('keydown', onKey);
65
+ return () => {
66
+ window.removeEventListener('mousedown', onDoc);
67
+ window.removeEventListener('keydown', onKey);
68
+ };
69
+ }, [anchor, onClose]);
70
+ // Open to the LEFT of the inspector (panel sits on the right edge).
71
+ const r = anchor.getBoundingClientRect();
72
+ const WIDTH = 252;
73
+ const left = Math.max(8, r.left - WIDTH - 8);
74
+ const top = Math.max(8, Math.min(r.top, window.innerHeight - 300));
75
+ const patch = (p, live) => {
76
+ if (live)
77
+ moveElements([{ id: selId, patch: p }], { skipHistory: true });
78
+ else
79
+ updateElement(selId, p);
80
+ };
81
+ const neutral = { brightness: undefined, contrast: undefined, saturation: undefined, hue_rotate: undefined };
82
+ const applyLook = (lf) => updateElement(selId, { ...neutral, ...lf });
83
+ // Rendered INLINE (not portaled) — same as the color picker — so the editor's
84
+ // theme tokens resolve and `fixed` still escapes the inspector's scroll clip.
85
+ return (_jsxs("div", { ref: ref, className: "fixed z-50 rounded-lg border bg-popover shadow-2xl p-2 flex flex-col gap-2.5 select-none", style: { left, top, width: WIDTH, borderColor: 'var(--color-popover-border)' }, children: [_jsxs("div", { children: [_jsx("div", { className: "text-[9px] uppercase tracking-wide text-muted-foreground mb-1.5", children: "Looks" }), _jsx("div", { className: "grid grid-cols-3 gap-1", children: LOOKS.map((l) => (_jsxs("button", { type: "button", onClick: () => applyLook(l.f), className: "h-10 rounded border border-border overflow-hidden relative hover:border-primary/60 transition-colors", title: l.label, children: [_jsx(Preview, { src: previewSrc, f: lookFilters(l.f) }), _jsx("span", { className: "absolute inset-x-0 bottom-0 text-[8px] text-center bg-background/70 text-foreground/80 leading-[11px]", children: l.label })] }, l.id))) })] }), _jsx("div", { className: "border-t border-border/50 pt-2 flex flex-col gap-1.5", children: FIELDS.map((fld) => (_jsx(Slider, { label: fld.label, value: f[fld.key], min: fld.min, max: fld.max, step: fld.unit === '°' ? 1 : 0.01, unit: fld.unit, onStart: pushHistory, onLive: (v) => patch({ [fld.key]: v }, true), onReset: () => patch({ [fld.key]: undefined }, false) }, fld.key))) }), _jsx("button", { type: "button", onClick: () => updateElement(selId, neutral), className: "text-[10px] text-muted-foreground hover:text-foreground transition-colors self-end", children: "Reset all" })] }));
86
+ }
87
+ function Slider({ label, value, min, max, step, unit, onStart, onLive, onReset, }) {
88
+ const display = unit === '°' ? `${Math.round(value)}°` : `${Math.round(value * 100)}%`;
89
+ return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "w-[68px] text-[10px] text-muted-foreground shrink-0", children: label }), _jsx("input", { type: "range", min: min, max: max, step: step, value: value, onPointerDown: onStart, onChange: (e) => onLive(parseFloat(e.target.value)), className: "flex-1 h-1 accent-primary cursor-pointer" }), _jsx("button", { type: "button", onDoubleClick: onReset, title: "Double-click to reset", className: "w-9 text-right text-[10px] tabular-nums text-foreground/80", children: display })] }));
90
+ }
91
+ // CSS filters are 1:1 with the protocol's brightness/contrast/saturation/
92
+ // hue_rotate, so this preview is ACCURATE to what the runtime renders.
93
+ function cssFilter(f) {
94
+ return `brightness(${f.brightness}) contrast(${f.contrast}) saturate(${f.saturation}) hue-rotate(${f.hue_rotate}deg)`;
95
+ }
96
+ // Reference used when the element has no image of its own — a spread of hues +
97
+ // tones so a look's character (warmth, punch, desaturation) reads clearly.
98
+ const REFERENCE = 'linear-gradient(135deg, #102a43 0%, #2b6cb0 24%, #e0a23a 48%, #c05621 66%, #2f855a 84%, #e9e9e9 100%)';
99
+ // Panel swatch: a neutral warm tonal ramp (one hue family — not a rainbow),
100
+ // split before | after so the grade's shift reads. Neutral grade ⇒ the halves
101
+ // match ⇒ no visible split (an honest "Default" state).
102
+ const SWATCH_BASE = 'linear-gradient(180deg, #3f3933 0%, #cdc3b3 100%)';
103
+ function GradeSwatch({ f }) {
104
+ return (_jsxs(_Fragment, { children: [_jsx("span", { className: "absolute inset-y-0 left-0 w-1/2", style: { background: SWATCH_BASE } }), _jsx("span", { className: "absolute inset-y-0 right-0 w-1/2", style: { background: SWATCH_BASE, filter: cssFilter(f) } })] }));
105
+ }
106
+ /** A live preview of the grade, filling its (relative) container: the element's
107
+ * own image when it has one, else the reference gradient. */
108
+ function Preview({ src, f }) {
109
+ const filter = cssFilter(f);
110
+ return src ? (_jsx("img", { src: src, alt: "", className: "absolute inset-0 w-full h-full object-cover", style: { filter } })) : (_jsx("span", { className: "absolute inset-0", style: { background: REFERENCE, filter } }));
111
+ }
112
+ function lookFilters(f) {
113
+ return {
114
+ brightness: f.brightness ?? 1,
115
+ contrast: f.contrast ?? 1,
116
+ saturation: f.saturation ?? 1,
117
+ hue_rotate: f.hue_rotate ?? 0,
118
+ };
119
+ }
120
+ //# sourceMappingURL=GradeControl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GradeControl.js","sourceRoot":"","sources":["../../src/controls/GradeControl.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare function KeyframeDiamond({ elementId, property, animated, current, percentDefault, }: {
2
+ elementId: string;
3
+ property: string;
4
+ /** Has a keyframe_animations entry (the editor's animation surface). */
5
+ animated: boolean;
6
+ /** The field's current value — seeds the first keyframe. */
7
+ current: unknown;
8
+ /** Unauthored percent fields read 100, not 0. */
9
+ percentDefault?: boolean;
10
+ }): import("react").JSX.Element;
11
+ //# sourceMappingURL=KeyframeDiamond.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeyframeDiamond.d.ts","sourceRoot":"","sources":["../../src/controls/KeyframeDiamond.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,cAAc,GACf,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,QAAQ,EAAE,OAAO,CAAC;IAClB,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,iDAAiD;IACjD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,+BA0FA"}
@@ -0,0 +1,87 @@
1
+ // The ◇/◆ keyframe diamond (re-ruled by Ian 2026-06-11): a true
2
+ // keyframe toggle, AE-style, reading state from the document + the
3
+ // playhead:
4
+ //
5
+ // muted outline — property has NO keyframes; click starts an
6
+ // animation with one keyframe at the playhead
7
+ // BLUE outline — keyframes exist, playhead is between them;
8
+ // click adds another at the playhead (value
9
+ // sampled from the curve via normative applyEasing)
10
+ // BLUE fill — playhead is ON a keyframe; click removes it
11
+ // (removing the last drops the whole entry)
12
+ //
13
+ // Shared toggle logic with the timeline lane rows (lib/keyframes.ts).
14
+ // The playhead subscription is a derived boolean — the button only
15
+ // re-renders when on/off-keyframe actually flips.
16
+ 'use client';
17
+ import { jsx as _jsx } from "react/jsx-runtime";
18
+ import { elementTime, useEditor, useEditorContext, useEditorStore, } from '@clipkit/editor-core';
19
+ import { cn } from '../lib/utils.js';
20
+ import { findElementById as findById, isOnKeyframe, toggleKeyframeAt, } from '../lib/keyframes.js';
21
+ export function KeyframeDiamond({ elementId, property, animated, current, percentDefault, }) {
22
+ const { store } = useEditorContext();
23
+ const actions = useEditor();
24
+ // Derived boolean — re-renders only when the playhead crosses a
25
+ // keyframe boundary, not on every tick.
26
+ const onKf = useEditorStore((s) => {
27
+ if (!animated)
28
+ return false;
29
+ const el = findById(s.source.elements, elementId);
30
+ const anim = el?.keyframe_animations?.find((a) => a.property === property);
31
+ if (!el || !anim)
32
+ return false;
33
+ // Same clamp as the click handler: a playhead before the element
34
+ // maps to its first frame.
35
+ return isOnKeyframe(anim, Math.max(0, s.playback.time - elementTime(el)));
36
+ });
37
+ // In-field keyframes (volume: Keyframe[]) — authored outside the
38
+ // editor; shown filled but edited via the Source pane, not here.
39
+ const inField = Array.isArray(current);
40
+ const onClick = () => {
41
+ const st = store.getState();
42
+ const el = findById(st.source.elements, elementId);
43
+ if (!el?.id)
44
+ return;
45
+ const local = Math.max(0, Math.round((st.playback.time - elementTime(el)) * 1000) / 1000);
46
+ const anims = el.keyframe_animations ?? [];
47
+ const ai = anims.findIndex((a) => a.property === property);
48
+ if (ai < 0) {
49
+ // First keyframe — start the animation, seeded with the field's
50
+ // current value.
51
+ const seed = typeof current === 'number' || typeof current === 'string'
52
+ ? current
53
+ : percentDefault
54
+ ? 100
55
+ : 0;
56
+ actions.updateElement(elementId, {
57
+ keyframe_animations: [
58
+ ...anims,
59
+ { property, keyframes: [{ time: local, value: seed }] },
60
+ ],
61
+ });
62
+ return;
63
+ }
64
+ actions.updateElement(elementId, {
65
+ keyframe_animations: toggleKeyframeAt(anims, ai, local),
66
+ });
67
+ };
68
+ const title = inField
69
+ ? 'Keyframed in the document (edit via the Source pane)'
70
+ : onKf
71
+ ? 'Remove keyframe at current time'
72
+ : 'Add keyframe at current time';
73
+ return (_jsx("button", { type: "button", className: "w-5 h-5 grid place-items-center group shrink-0 disabled:cursor-default", title: title, "aria-label": title, disabled: inField, onClick: onClick, children: _jsx("span", { className: cn('w-1.5 h-1.5 rotate-45 transition-colors border', inField
74
+ ? 'bg-primary border-primary'
75
+ : onKf
76
+ ? '' // blue fill via style
77
+ : animated
78
+ ? 'bg-transparent' // blue stroke via style
79
+ : 'bg-transparent border-muted-foreground/60 group-hover:border-foreground'), style: inField
80
+ ? undefined
81
+ : onKf
82
+ ? { background: 'var(--color-playhead)', borderColor: 'var(--color-playhead)' }
83
+ : animated
84
+ ? { borderColor: 'var(--color-playhead)' }
85
+ : undefined }) }));
86
+ }
87
+ //# sourceMappingURL=KeyframeDiamond.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeyframeDiamond.js","sourceRoot":"","sources":["../../src/controls/KeyframeDiamond.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { Bloom, Environment, Light, Material } from '@clipkit/protocol';
2
+ export declare function MaterialControl({ value, onChange, onScrubStart, onScrubEnd, }: {
3
+ value: Material | undefined;
4
+ onChange: (next: Material | undefined, live: boolean) => void;
5
+ onScrubStart?: () => void;
6
+ onScrubEnd?: () => void;
7
+ }): import("react").JSX.Element;
8
+ export declare function LightsControl({ value, onChange, onScrubStart, onScrubEnd, }: {
9
+ value: Light[] | undefined;
10
+ onChange: (next: Light[] | undefined, live: boolean) => void;
11
+ onScrubStart?: () => void;
12
+ onScrubEnd?: () => void;
13
+ }): import("react").JSX.Element;
14
+ export declare function BloomControl({ value, onChange, onScrubStart, onScrubEnd, }: {
15
+ value: Bloom | undefined;
16
+ onChange: (next: Bloom | undefined, live: boolean) => void;
17
+ onScrubStart?: () => void;
18
+ onScrubEnd?: () => void;
19
+ }): import("react").JSX.Element;
20
+ export declare function EnvironmentControl({ value, onChange, }: {
21
+ value: Environment | undefined;
22
+ onChange: (next: Environment | undefined, live: boolean) => void;
23
+ }): import("react").JSX.Element;
24
+ //# sourceMappingURL=LightingControls.d.ts.map