@hyperframes/studio 0.8.103 → 0.8.105

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 (200) hide show
  1. package/dist/assets/{hyperframes-player-DG795Hwu.js → hyperframes-player-tnfCiVdR.js} +1 -1
  2. package/dist/assets/{index-BiEtDkae.js → index-Ca6LZlVb.js} +1 -1
  3. package/dist/assets/index-Cre9X4RS.css +1 -0
  4. package/dist/assets/{index-BPJRf2X9.js → index-DEDhPmPD.js} +215 -215
  5. package/dist/assets/{index-DuCZ3pQw.js → index-zpe332hb.js} +1 -1
  6. package/dist/{chunk-62DDWOSH.js → chunk-EEXSYY5F.js} +19 -18
  7. package/dist/chunk-EEXSYY5F.js.map +1 -0
  8. package/dist/{chunk-6GAO75IU.js → chunk-NCUBAVGK.js} +10 -8
  9. package/dist/chunk-NCUBAVGK.js.map +1 -0
  10. package/dist/{chunk-HIGHVWYD.js → chunk-QADHJFDF.js} +2 -2
  11. package/dist/index.css +6 -1
  12. package/dist/index.css.map +1 -1
  13. package/dist/index.d.ts +181 -168
  14. package/dist/index.html +2 -2
  15. package/dist/index.js +1018 -919
  16. package/dist/index.js.map +1 -1
  17. package/dist/player.js +2 -2
  18. package/dist/styles/tailwind-preset.js.map +1 -1
  19. package/dist/styles.css +1 -1
  20. package/dist/ui.js +2 -2
  21. package/package.json +8 -8
  22. package/src/captions/components/CaptionAnimationPanel.tsx +2 -2
  23. package/src/captions/components/CaptionPropertyPanel.tsx +2 -2
  24. package/src/captions/components/CaptionTimeline.tsx +3 -3
  25. package/src/components/AskAgentModal.tsx +1 -1
  26. package/src/components/LintModal.tsx +35 -35
  27. package/src/components/StudioErrorBoundary.tsx +1 -1
  28. package/src/components/StudioHeader.dom.test.tsx +4 -4
  29. package/src/components/StudioHeader.tsx +2 -1
  30. package/src/components/StudioToast.tsx +7 -16
  31. package/src/components/TimelineToolPicker.tsx +1 -1
  32. package/src/components/TimelineToolbar.tsx +11 -11
  33. package/src/components/dock/Dock.tsx +1 -1
  34. package/src/components/dock/dock.css +9 -1
  35. package/src/components/editor/AnimationCard.tsx +5 -5
  36. package/src/components/editor/AnimationCardParts.tsx +1 -1
  37. package/src/components/editor/BlockParamsPanel.tsx +3 -3
  38. package/src/components/editor/BorderRadiusEditor.tsx +8 -15
  39. package/src/components/editor/CanvasContextMenu.tsx +1 -1
  40. package/src/components/editor/ComputedTweenNotice.tsx +1 -1
  41. package/src/components/editor/DomEditOverlay.tsx +5 -6
  42. package/src/components/editor/DomEditRotateHandle.tsx +1 -1
  43. package/src/components/editor/EaseCurveSection.tsx +14 -19
  44. package/src/components/editor/EaseModeControls.tsx +2 -2
  45. package/src/components/editor/EaseParamFields.tsx +8 -8
  46. package/src/components/editor/FileTree.tsx +1 -1
  47. package/src/components/editor/FileTreeIcons.tsx +47 -26
  48. package/src/components/editor/FileTreeNodes.tsx +11 -8
  49. package/src/components/editor/GestureRecordControl.tsx +3 -3
  50. package/src/components/editor/GsapAddAnimationControl.tsx +1 -1
  51. package/src/components/editor/GsapAnimationSection.tsx +2 -2
  52. package/src/components/editor/InlineTextToolbar.tsx +4 -4
  53. package/src/components/editor/InspectorHeaderActions.tsx +1 -1
  54. package/src/components/editor/KeyframeDiamond.tsx +6 -4
  55. package/src/components/editor/KeyframeNavigation.tsx +4 -4
  56. package/src/components/editor/LayersPanel.tsx +3 -3
  57. package/src/components/editor/PromotableControl.tsx +2 -2
  58. package/src/components/editor/PropertyPanel.tsx +3 -3
  59. package/src/components/editor/PropertyPanelEmptyState.tsx +4 -4
  60. package/src/components/editor/PropertyPanelFlatFooter.tsx +2 -2
  61. package/src/components/editor/PropertyPanelFlatHeader.test.tsx +1 -1
  62. package/src/components/editor/PropertyPanelFlatHeader.tsx +2 -2
  63. package/src/components/editor/SnapToolbar.tsx +5 -5
  64. package/src/components/editor/TimelineFxPopover.tsx +4 -4
  65. package/src/components/editor/Transform3DCube.tsx +1 -1
  66. package/src/components/editor/anchoredResizeCommitFeedsOffset.test.ts +46 -6
  67. package/src/components/editor/anchoredResizeReleaseShift.test.ts +0 -84
  68. package/src/components/editor/domEditOverlayGestures.ts +13 -19
  69. package/src/components/editor/domEditOverlayStartGesture.test.ts +170 -13
  70. package/src/components/editor/domEditOverlayStartGesture.ts +15 -25
  71. package/src/components/editor/easeCurveSvg.tsx +1 -1
  72. package/src/components/editor/manualEdits.test.ts +3 -9
  73. package/src/components/editor/manualEdits.ts +0 -1
  74. package/src/components/editor/manualEditsDom.ts +3 -13
  75. package/src/components/editor/manualEditsDomPatches.test.ts +3 -131
  76. package/src/components/editor/manualEditsDomPatches.ts +1 -53
  77. package/src/components/editor/manualEditsSnapshot.ts +3 -0
  78. package/src/components/editor/manualEditsTypes.ts +2 -0
  79. package/src/components/editor/manualOffsetDrag.test.ts +41 -0
  80. package/src/components/editor/manualOffsetDrag.ts +6 -27
  81. package/src/components/editor/persistSeam.integration.test.ts +0 -18
  82. package/src/components/editor/plainTranslate.ts +42 -6
  83. package/src/components/editor/propertyPanelColorCurveGraph.tsx +2 -2
  84. package/src/components/editor/propertyPanelColorGradingControls.tsx +1 -1
  85. package/src/components/editor/propertyPanelColorGradingSection.tsx +8 -8
  86. package/src/components/editor/propertyPanelColorGradingSlider.tsx +1 -1
  87. package/src/components/editor/propertyPanelColorSecondary.tsx +4 -4
  88. package/src/components/editor/propertyPanelFill.tsx +6 -6
  89. package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +3 -3
  90. package/src/components/editor/propertyPanelFlatColorGradingSection.test.tsx +1 -1
  91. package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +6 -9
  92. package/src/components/editor/propertyPanelFlatEffectsSection.tsx +4 -4
  93. package/src/components/editor/propertyPanelFlatMediaSection.tsx +2 -2
  94. package/src/components/editor/propertyPanelFlatMotionSection.tsx +2 -2
  95. package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +2 -2
  96. package/src/components/editor/propertyPanelFlatPrimitives.test.tsx +4 -3
  97. package/src/components/editor/propertyPanelFlatPrimitives.tsx +1 -1
  98. package/src/components/editor/propertyPanelFlatSliderReadout.tsx +1 -1
  99. package/src/components/editor/propertyPanelFont.tsx +2 -2
  100. package/src/components/editor/propertyPanelFxCarveModule.tsx +1 -1
  101. package/src/components/editor/propertyPanelFxControls.tsx +2 -2
  102. package/src/components/editor/propertyPanelFxEqModule.tsx +2 -2
  103. package/src/components/editor/propertyPanelFxNodeRow.tsx +1 -1
  104. package/src/components/editor/propertyPanelFxPresetRun.tsx +1 -1
  105. package/src/components/editor/propertyPanelMediaSection.tsx +1 -1
  106. package/src/components/editor/propertyPanelPrimitives.tsx +1 -1
  107. package/src/components/editor/propertyPanelSections.tsx +2 -2
  108. package/src/components/editor/propertyPanelTransformCommit.test.ts +29 -0
  109. package/src/components/editor/propertyPanelTransformCommit.ts +8 -5
  110. package/src/components/editor/propertyPanelTypes.ts +1 -0
  111. package/src/components/editor/propertyPanelValueTier.test.ts +1 -1
  112. package/src/components/editor/propertyPanelValueTier.ts +1 -1
  113. package/src/components/editor/rotateInlineSave.test.ts +111 -0
  114. package/src/components/editor/rotationDraft.test.ts +111 -0
  115. package/src/components/editor/rotationDraft.ts +145 -0
  116. package/src/components/editor/useDomEditNudge.test.tsx +33 -0
  117. package/src/components/editor/useDomEditNudge.ts +6 -2
  118. package/src/components/editor/useDomEditOverlayGestures.ts +22 -24
  119. package/src/components/feedback/StudioFeedbackCard.tsx +11 -23
  120. package/src/components/nle/AssetPreviewOverlay.tsx +1 -1
  121. package/src/components/nle/AudioMeterStrip.tsx +2 -2
  122. package/src/components/nle/NLEPreview.test.ts +8 -4
  123. package/src/components/nle/PreviewOverlays.tsx +1 -1
  124. package/src/components/nle/PreviewPane.tsx +3 -3
  125. package/src/components/nle/PreviewPoster.tsx +29 -1
  126. package/src/components/nle/PreviewZoomOverlay.tsx +1 -1
  127. package/src/components/panels/SlideshowPanel.tsx +4 -4
  128. package/src/components/panels/SlideshowSubPanels.tsx +19 -21
  129. package/src/components/panels/VariablesBindElement.tsx +1 -1
  130. package/src/components/panels/VariablesDeclarationForm.tsx +1 -1
  131. package/src/components/panels/VariablesPanel.tsx +4 -6
  132. package/src/components/panels/VariablesRowAction.tsx +1 -1
  133. package/src/components/renders/FfmpegRequiredNotice.tsx +4 -4
  134. package/src/components/renders/RenderQueue.tsx +2 -2
  135. package/src/components/renders/RenderQueueItem.tsx +3 -3
  136. package/src/components/sidebar/AssetCard.tsx +3 -3
  137. package/src/components/sidebar/AssetContextMenu.tsx +7 -7
  138. package/src/components/sidebar/AssetsTab.tsx +6 -6
  139. package/src/components/sidebar/AudioRow.tsx +5 -3
  140. package/src/components/sidebar/BlocksTab.tsx +6 -6
  141. package/src/components/sidebar/CompositionsTab.drag.test.tsx +3 -69
  142. package/src/components/sidebar/CompositionsTab.rootBadge.test.tsx +4 -50
  143. package/src/components/sidebar/CompositionsTab.thumbnails.test.tsx +256 -0
  144. package/src/components/sidebar/CompositionsTab.tsx +65 -12
  145. package/src/components/sidebar/PromptPreviewModal.tsx +3 -3
  146. package/src/components/sidebar/SidebarLintButton.tsx +3 -3
  147. package/src/components/sidebar/compositionsTabTestUtils.tsx +39 -0
  148. package/src/components/timelineToolbarStyles.ts +3 -3
  149. package/src/components/ui/Button.tsx +4 -4
  150. package/src/components/ui/HyperframesLogo.tsx +19 -18
  151. package/src/components/ui/Input.tsx +1 -1
  152. package/src/components/ui/Menu.tsx +4 -2
  153. package/src/hooks/draggedGsapPosition.ts +28 -0
  154. package/src/hooks/elementOffsetStager.ts +34 -13
  155. package/src/hooks/gsapRuntimeBridge.ts +5 -3
  156. package/src/hooks/gsapRuntimeKeyframes.ts +36 -2
  157. package/src/hooks/plainRotation.test.ts +122 -0
  158. package/src/hooks/plainRotation.ts +42 -0
  159. package/src/hooks/useClipboard.source.test.ts +42 -4
  160. package/src/hooks/useClipboard.ts +13 -3
  161. package/src/hooks/useDomEditCommits.ts +0 -3
  162. package/src/hooks/useDomEditSession.ts +5 -5
  163. package/src/hooks/useDomGeometryCommit.test.tsx +79 -1
  164. package/src/hooks/useDomGeometryCommit.ts +16 -17
  165. package/src/hooks/useDomGeometryCommits.test.tsx +233 -33
  166. package/src/hooks/useDomGeometryCommits.ts +27 -80
  167. package/src/hooks/useGsapAwareEditing.test.tsx +194 -11
  168. package/src/hooks/useGsapAwareEditing.ts +43 -42
  169. package/src/hooks/useInlineTextEdit.test.tsx +33 -3
  170. package/src/hooks/useInlineTextEdit.ts +2 -2
  171. package/src/player/components/ClipContextMenu.tsx +1 -1
  172. package/src/player/components/CompositionThumbnail.tsx +23 -11
  173. package/src/player/components/EditModal.tsx +6 -6
  174. package/src/player/components/KeyframeDiamondContextMenu.tsx +2 -2
  175. package/src/player/components/PlayerControls.tsx +3 -3
  176. package/src/player/components/ShortcutsPanel.tsx +8 -20
  177. package/src/player/components/TimelineCanvas.tsx +1 -1
  178. package/src/player/components/TimelineClip.tsx +2 -2
  179. package/src/player/components/TimelineEmptyState.tsx +2 -2
  180. package/src/player/components/TimelineLanes.tsx +0 -1
  181. package/src/player/components/TrackClipCount.tsx +1 -1
  182. package/src/player/components/VolumeControl.tsx +1 -1
  183. package/src/player/components/timelineClipChildren.tsx +1 -1
  184. package/src/player/components/timelineMotionStyles.test.ts +6 -22
  185. package/src/player/components/trackHeaderLabelRows.tsx +16 -16
  186. package/src/player/lib/thumbnailScheduler.ts +4 -5
  187. package/src/player/lib/timelineViewportBudgets.test.ts +1 -1
  188. package/src/player/lib/timelineViewportBudgets.ts +1 -1
  189. package/src/styles/hex-baseline.json +7 -19
  190. package/src/styles/studio.css +0 -9
  191. package/src/styles/tailwind-preset.shared.js +2 -1
  192. package/src/styles/theme.css +204 -147
  193. package/src/styles/theme.test.ts +13 -9
  194. package/src/utils/blockCategories.ts +41 -9
  195. package/src/utils/clipboardPayload.ts +2 -0
  196. package/dist/assets/index-CQN3M56N.css +0 -1
  197. package/dist/chunk-62DDWOSH.js.map +0 -1
  198. package/dist/chunk-6GAO75IU.js.map +0 -1
  199. package/src/hooks/gsapTargetCache.ts +0 -62
  200. /package/dist/{chunk-HIGHVWYD.js.map → chunk-QADHJFDF.js.map} +0 -0
package/dist/ui.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HyperframesLogo
3
- } from "./chunk-62DDWOSH.js";
3
+ } from "./chunk-EEXSYY5F.js";
4
4
  import {
5
5
  Button,
6
6
  ContextMenu,
@@ -30,7 +30,7 @@ import {
30
30
  fieldBase,
31
31
  fieldText,
32
32
  popupSurface
33
- } from "./chunk-6GAO75IU.js";
33
+ } from "./chunk-NCUBAVGK.js";
34
34
  import "./chunk-PZ5AY32C.js";
35
35
  export {
36
36
  Button,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/studio",
3
- "version": "0.8.103",
3
+ "version": "0.8.105",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -60,12 +60,12 @@
60
60
  "dockview-react": "8.3.1",
61
61
  "gsap": "^3.13.0",
62
62
  "mediabunny": "^1.45.3",
63
- "@hyperframes/player": "0.8.103",
64
- "@hyperframes/shader-transitions": "0.8.103",
65
- "@hyperframes/core": "0.8.103",
66
- "@hyperframes/studio-server": "0.8.103",
67
- "@hyperframes/parsers": "0.8.103",
68
- "@hyperframes/sdk": "0.8.103"
63
+ "@hyperframes/core": "0.8.105",
64
+ "@hyperframes/player": "0.8.105",
65
+ "@hyperframes/parsers": "0.8.105",
66
+ "@hyperframes/shader-transitions": "0.8.105",
67
+ "@hyperframes/studio-server": "0.8.105",
68
+ "@hyperframes/sdk": "0.8.105"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@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.103"
84
+ "@hyperframes/producer": "0.8.105"
85
85
  },
86
86
  "peerDependencies": {
87
87
  "react": "19",
@@ -250,7 +250,7 @@ export const CaptionAnimationPanel = memo(function CaptionAnimationPanel() {
250
250
  <div className="flex flex-col h-full min-h-0">
251
251
  {gated && (
252
252
  <div className="shrink-0 mx-3 mt-2 px-2 py-1.5 rounded-sm border border-amber-500/30 bg-amber-500/10">
253
- <p className="text-2xs text-amber-300/90 leading-snug">
253
+ <p className="text-2xs text-warning-ink leading-snug">
254
254
  Animation editing isn&apos;t applied to playback or saved yet, so these controls are
255
255
  disabled.
256
256
  </p>
@@ -292,7 +292,7 @@ export const CaptionAnimationPanel = memo(function CaptionAnimationPanel() {
292
292
  onClick={handleApplyToAll}
293
293
  disabled={gated}
294
294
  title={gated ? "Disabled until animation editing is applied to playback" : undefined}
295
- className="w-full py-1.5 rounded-sm border border-neutral-700 text-2xs text-neutral-300 hover:border-studio-accent/50 hover:text-studio-accent transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:border-neutral-700 disabled:hover:text-neutral-300"
295
+ className="w-full py-1.5 rounded-sm border border-neutral-700 text-2xs text-neutral-300 hover:border-studio-accent/50 hover:text-accent-ink transition-colors disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:border-neutral-700 disabled:hover:text-neutral-300"
296
296
  >
297
297
  Apply to all groups
298
298
  </button>
@@ -227,7 +227,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
227
227
  className={[
228
228
  "flex-1 py-0.5 rounded-sm text-2xs font-medium transition-colors",
229
229
  activeTab === "style"
230
- ? "bg-studio-accent/20 text-studio-accent border border-studio-accent/50"
230
+ ? "bg-studio-accent/20 text-accent-ink border border-studio-accent/50"
231
231
  : "text-neutral-500 border border-neutral-800 hover:text-neutral-300 hover:border-neutral-600",
232
232
  ].join(" ")}
233
233
  >
@@ -241,7 +241,7 @@ export const CaptionPropertyPanel = memo(function CaptionPropertyPanel({
241
241
  className={[
242
242
  "flex-1 py-0.5 rounded-sm text-2xs font-medium transition-colors",
243
243
  activeTab === "animation"
244
- ? "bg-studio-accent/20 text-studio-accent border border-studio-accent/50"
244
+ ? "bg-studio-accent/20 text-accent-ink border border-studio-accent/50"
245
245
  : "text-neutral-500 border border-neutral-800 hover:text-neutral-300 hover:border-neutral-600",
246
246
  ].join(" ")}
247
247
  >
@@ -109,8 +109,8 @@ export const CaptionTimeline = memo(function CaptionTimeline({
109
109
  tabIndex={0}
110
110
  aria-label={`Caption word "${seg.text}"`}
111
111
  aria-pressed={isSelected}
112
- className={`absolute top-1 bottom-1 rounded flex items-center overflow-hidden cursor-pointer focus-visible:ring-1 focus-visible:ring-white outline-hidden${
113
- isSelected ? " ring-1 ring-white/50 z-10" : ""
112
+ className={`absolute top-1 bottom-1 rounded flex items-center overflow-hidden cursor-pointer focus-visible:ring-1 focus-visible:ring-text-0 outline-hidden${
113
+ isSelected ? " ring-1 ring-text-0/50 z-10" : ""
114
114
  }`}
115
115
  style={{
116
116
  left,
@@ -135,7 +135,7 @@ export const CaptionTimeline = memo(function CaptionTimeline({
135
135
 
136
136
  {/* Playhead — correlates blocks with the current frame */}
137
137
  <div
138
- className="absolute top-0 bottom-0 w-px bg-white/70 pointer-events-none z-20"
138
+ className="absolute top-0 bottom-0 w-px bg-text-0/70 pointer-events-none z-20"
139
139
  style={{ left: playheadLeft }}
140
140
  aria-hidden="true"
141
141
  />
@@ -138,7 +138,7 @@ export function AskAgentModal({
138
138
  {navigator.platform.includes("Mac") ? "⌘" : "Ctrl"}+Enter to copy
139
139
  </span>
140
140
  <button
141
- className="px-4 py-1.5 rounded-lg bg-studio-accent/90 text-xs font-medium text-neutral-950 hover:bg-studio-accent disabled:opacity-40 disabled:cursor-not-allowed"
141
+ className="px-4 py-1.5 rounded-lg bg-accent text-xs font-medium text-on-accent hover:bg-accent-hover disabled:opacity-40 disabled:cursor-not-allowed"
142
142
  disabled={!value.trim()}
143
143
  onClick={handleSubmit}
144
144
  >
@@ -75,11 +75,11 @@ export function LintModal({
75
75
  <div className="flex items-center gap-3">
76
76
  {hasIssues ? (
77
77
  <div className="w-8 h-8 rounded-full bg-red-500/10 flex items-center justify-center">
78
- <WarningIcon size={18} className="text-red-400" weight="fill" />
78
+ <WarningIcon size={18} className="text-danger-ink" weight="fill" />
79
79
  </div>
80
80
  ) : (
81
81
  <div className="w-8 h-8 rounded-full bg-studio-accent/10 flex items-center justify-center">
82
- <CheckCircleIcon size={18} className="text-studio-accent" weight="fill" />
82
+ <CheckCircleIcon size={18} className="text-accent-ink" weight="fill" />
83
83
  </div>
84
84
  )}
85
85
  <div>
@@ -107,10 +107,10 @@ export function LintModal({
107
107
  onClick={handleCopyToAgent}
108
108
  className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors active:scale-[0.98] ${
109
109
  copied
110
- ? "bg-green-600 text-white"
110
+ ? "bg-accent text-on-accent"
111
111
  : copyFailed
112
- ? "bg-red-600 text-white"
113
- : "bg-studio-accent hover:bg-studio-accent/80 text-white"
112
+ ? "bg-danger text-on-danger"
113
+ : "bg-accent hover:bg-accent-hover text-on-accent"
114
114
  }`}
115
115
  >
116
116
  {copied
@@ -128,41 +128,41 @@ export function LintModal({
128
128
  </div>
129
129
  )}
130
130
  {errors.map((f, i) => (
131
- <div key={`e-${i}`} className="py-3 border-b border-neutral-800/50 last:border-0">
132
- <div className="flex items-start gap-2">
133
- <WarningIcon size={14} className="text-red-400 shrink-0 mt-0.5" weight="fill" />
134
- <div className="min-w-0">
135
- <p className="text-sm text-neutral-200">{f.message}</p>
136
- {f.file && <p className="text-xs text-neutral-600 font-mono mt-0.5">{f.file}</p>}
137
- {f.fixHint && (
138
- <div className="flex items-start gap-1 mt-1.5">
139
- <CaretRightIcon size={10} className="text-studio-accent shrink-0 mt-0.5" />
140
- <p className="text-xs text-studio-accent">{f.fixHint}</p>
141
- </div>
142
- )}
143
- </div>
144
- </div>
145
- </div>
131
+ <LintFindingRow key={`e-${i}`} finding={f} tone="error" />
146
132
  ))}
147
133
  {warnings.map((f, i) => (
148
- <div key={`w-${i}`} className="py-3 border-b border-neutral-800/50 last:border-0">
149
- <div className="flex items-start gap-2">
150
- <WarningIcon size={14} className="text-amber-400 shrink-0 mt-0.5" />
151
- <div className="min-w-0">
152
- <p className="text-sm text-neutral-300">{f.message}</p>
153
- {f.file && <p className="text-xs text-neutral-600 font-mono mt-0.5">{f.file}</p>}
154
- {f.fixHint && (
155
- <div className="flex items-start gap-1 mt-1.5">
156
- <CaretRightIcon size={10} className="text-studio-accent shrink-0 mt-0.5" />
157
- <p className="text-xs text-studio-accent">{f.fixHint}</p>
158
- </div>
159
- )}
160
- </div>
161
- </div>
162
- </div>
134
+ <LintFindingRow key={`w-${i}`} finding={f} tone="warning" />
163
135
  ))}
164
136
  </div>
165
137
  </div>
166
138
  </div>
167
139
  );
168
140
  }
141
+
142
+ function LintFindingRow({ finding, tone }: { finding: LintFinding; tone: "error" | "warning" }) {
143
+ return (
144
+ <div className="py-3 border-b border-border last:border-0">
145
+ <div className="flex items-start gap-2">
146
+ <WarningIcon
147
+ size={14}
148
+ className={`${tone === "error" ? "text-danger-ink" : "text-warning-ink"} shrink-0 mt-0.5`}
149
+ weight={tone === "error" ? "fill" : undefined}
150
+ />
151
+ <div className="min-w-0">
152
+ <p className={`text-sm ${tone === "error" ? "text-text-0" : "text-text-2"}`}>
153
+ {finding.message}
154
+ </p>
155
+ {finding.file && (
156
+ <p className="text-xs text-text-muted font-mono mt-0.5">{finding.file}</p>
157
+ )}
158
+ {finding.fixHint && (
159
+ <div className="flex items-start gap-1 mt-1.5">
160
+ <CaretRightIcon size={10} className="text-accent-ink shrink-0 mt-0.5" />
161
+ <p className="text-xs text-accent-ink">{finding.fixHint}</p>
162
+ </div>
163
+ )}
164
+ </div>
165
+ </div>
166
+ </div>
167
+ );
168
+ }
@@ -39,7 +39,7 @@ export class StudioErrorBoundary extends Component<Props, State> {
39
39
  <div className="mt-2 flex items-center gap-2">
40
40
  <button
41
41
  onClick={() => this.setState({ error: null })}
42
- className="rounded-md bg-studio-accent px-5 py-2 text-sm font-medium text-neutral-950 transition-[filter] hover:brightness-110 active:scale-[0.98]"
42
+ className="rounded-md bg-accent px-5 py-2 text-sm font-medium text-on-accent transition-colors hover:bg-accent-hover active:scale-[0.98]"
43
43
  >
44
44
  Try again
45
45
  </button>
@@ -139,16 +139,16 @@ it("shows Inspector pressed and filled only when on", () => {
139
139
  const host = mount({ inspectorButtonActive: true });
140
140
  const on = query(host, '[aria-label="Inspector"]');
141
141
  expect(on.getAttribute("aria-pressed")).toBe("true");
142
- expect(hasToken(on.className, "text-accent")).toBe(true);
143
- expect(hasToken(on.className, "bg-hover")).toBe(true);
142
+ expect(hasToken(on.className, "text-accent-ink")).toBe(true);
143
+ expect(hasToken(on.className, "bg-on")).toBe(true);
144
144
  act(() => mounted?.root.unmount());
145
145
  mounted?.host.remove();
146
146
  mounted = null;
147
147
 
148
148
  const off = query(mount(), '[aria-label="Inspector"]');
149
149
  expect(off.getAttribute("aria-pressed")).toBe("false");
150
- expect(hasToken(off.className, "text-accent")).toBe(false);
151
- expect(hasToken(off.className, "bg-hover")).toBe(false);
150
+ expect(hasToken(off.className, "text-accent-ink")).toBe(false);
151
+ expect(hasToken(off.className, "bg-on")).toBe(false);
152
152
  });
153
153
 
154
154
  it("keeps Capture a real download link rather than a button", () => {
@@ -126,7 +126,8 @@ export function StudioHeader({
126
126
  aria-pressed={inspectorButtonActive}
127
127
  className={cn(
128
128
  "h-full rounded-none",
129
- inspectorButtonActive && "bg-hover text-accent enabled:hover:text-accent",
129
+ inspectorButtonActive &&
130
+ "bg-on text-accent-ink enabled:hover:bg-on-hover enabled:hover:text-accent-ink",
130
131
  )}
131
132
  icon={<InspectorIcon size={16} />}
132
133
  onClick={() => {
@@ -14,23 +14,10 @@ export function StudioToast({ message, tone, leaving, onDismiss }: StudioToastPr
14
14
  className={`motion-reduce:animate-none ${leaving ? "hf-toast-exit" : "hf-toast-enter"}`}
15
15
  >
16
16
  <div
17
- className="relative flex max-w-[min(420px,calc(100vw-48px))] items-center gap-3 overflow-hidden rounded-2xl py-3 pl-4 pr-2 text-[12px]"
18
- style={{
19
- background: isError
20
- ? "linear-gradient(135deg, rgba(127,29,29,0.55), rgba(80,10,10,0.45))"
21
- : "linear-gradient(135deg, rgba(38,38,38,0.55), rgba(23,23,23,0.45))",
22
- backdropFilter: "blur(16px) saturate(1.6)",
23
- WebkitBackdropFilter: "blur(16px) saturate(1.6)",
24
- border: `1px solid ${isError ? "rgba(239,68,68,0.18)" : "rgba(255,255,255,0.08)"}`,
25
- boxShadow: [
26
- "0 8px 32px rgba(0,0,0,0.35)",
27
- `inset 0 1px 0 ${isError ? "rgba(239,68,68,0.12)" : "rgba(255,255,255,0.06)"}`,
28
- `inset 0 -1px 0 rgba(0,0,0,0.15)`,
29
- ].join(", "),
30
- }}
17
+ className={`relative flex max-w-[min(420px,calc(100vw-48px))] items-center gap-3 overflow-hidden rounded-2xl py-3 pl-4 pr-2 text-[12px] ${toastSurface(isError)}`}
31
18
  >
32
19
  <span
33
- className={`min-w-0 wrap-break-word leading-5 ${isError ? "text-red-200" : "text-neutral-200"}`}
20
+ className={`min-w-0 wrap-break-word leading-5 ${isError ? "text-danger-ink" : "text-text-0"}`}
34
21
  >
35
22
  {message}
36
23
  </span>
@@ -38,7 +25,7 @@ export function StudioToast({ message, tone, leaving, onDismiss }: StudioToastPr
38
25
  <button
39
26
  type="button"
40
27
  onClick={onDismiss}
41
- className="flex h-5 w-5 shrink-0 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-white/10 hover:text-neutral-300"
28
+ className="flex h-5 w-5 shrink-0 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-hover hover:text-neutral-300"
42
29
  aria-label="Dismiss"
43
30
  >
44
31
  <svg
@@ -57,3 +44,7 @@ export function StudioToast({ message, tone, leaving, onDismiss }: StudioToastPr
57
44
  </div>
58
45
  );
59
46
  }
47
+
48
+ export function toastSurface(isError: boolean): string {
49
+ return `border shadow-popover backdrop-blur-md ${isError ? "border-danger/40 bg-raised" : "border-border bg-raised/95"}`;
50
+ }
@@ -81,7 +81,7 @@ export function TimelineToolPicker({ showSelectAroundPlayhead = true }) {
81
81
  shortcut={row.shortcut}
82
82
  onClick={row.run}
83
83
  data-active={row.active || undefined}
84
- className={row.active ? "bg-neutral-800 text-white" : undefined}
84
+ className={row.active ? "bg-press text-text-0" : undefined}
85
85
  >
86
86
  <span className="flex items-center gap-2">
87
87
  {row.icon}
@@ -307,11 +307,11 @@ export function TimelineToolbar({
307
307
  className={
308
308
  !onToggleKeyframe
309
309
  ? flatDisabled
310
- : `${flatBtn} active:scale-[0.98] hover:bg-white/6 ${
310
+ : `${flatBtn} active:scale-[0.98] hover:bg-hover ${
311
311
  keyframeState === "active"
312
- ? "text-studio-accent"
312
+ ? "text-accent-ink"
313
313
  : keyframeState === "inactive"
314
- ? "text-neutral-400 hover:text-studio-accent"
314
+ ? "text-neutral-400 hover:text-accent-ink"
315
315
  : "text-neutral-600 hover:text-neutral-400"
316
316
  }`
317
317
  }
@@ -342,9 +342,9 @@ export function TimelineToolbar({
342
342
  onClick={() => setAutoKeyframeEnabled(!autoKeyframeEnabled)}
343
343
  aria-label="Auto-record manual edits as keyframes"
344
344
  aria-pressed={autoKeyframeEnabled}
345
- className={`${flatBtn} active:scale-[0.98] hover:bg-white/6 ${
345
+ className={`${flatBtn} active:scale-[0.98] hover:bg-hover ${
346
346
  autoKeyframeEnabled
347
- ? "text-red-400 hover:text-red-300"
347
+ ? "text-danger-ink"
348
348
  : "text-neutral-600 hover:text-neutral-400"
349
349
  }`}
350
350
  >
@@ -442,7 +442,7 @@ export function TimelineToolbar({
442
442
  }}
443
443
  className={
444
444
  canAdd
445
- ? `${flatBtn} text-neutral-400 hover:bg-white/6 hover:text-[#22c55e] active:scale-[0.98]`
445
+ ? `${flatBtn} text-text-2 hover:bg-hover hover:text-accent-ink active:scale-[0.98]`
446
446
  : flatDisabled
447
447
  }
448
448
  >
@@ -479,8 +479,8 @@ export function TimelineToolbar({
479
479
  onClick={() => setThumbnailMode(thumbnailsVisible ? "hidden" : "adaptive")}
480
480
  className={`h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${
481
481
  thumbnailsVisible
482
- ? "bg-studio-accent/10 text-studio-accent"
483
- : "text-neutral-400 hover:bg-white/6 hover:text-neutral-200"
482
+ ? "bg-studio-accent/10 text-accent-ink"
483
+ : "text-neutral-400 hover:bg-hover hover:text-neutral-200"
484
484
  }`}
485
485
  >
486
486
  <Image size={16} aria-hidden="true" />
@@ -494,8 +494,8 @@ export function TimelineToolbar({
494
494
  aria-pressed={zoomMode === "fit"}
495
495
  className={`h-7 px-2 rounded-md text-[11px] font-medium transition-colors ${
496
496
  zoomMode === "fit"
497
- ? "bg-studio-accent/10 text-studio-accent"
498
- : "text-neutral-400 hover:bg-white/6 hover:text-neutral-200"
497
+ ? "bg-studio-accent/10 text-accent-ink"
498
+ : "text-neutral-400 hover:bg-hover hover:text-neutral-200"
499
499
  }`}
500
500
  >
501
501
  <ArrowsOutLineHorizontal size={16} aria-hidden="true" />
@@ -531,7 +531,7 @@ export function TimelineToolbar({
531
531
  }}
532
532
  // h-6 on the input is the 24x24 WCAG 2.2 (2.5.8) target: the visible
533
533
  // track stays 2px and the thumb 10px, only the pointer box grows.
534
- className="mx-1 h-6 w-[96px] cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-[2px] [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-neutral-700 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[10px] [&::-webkit-slider-thumb]:h-[10px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:-mt-1 [&::-webkit-slider-thumb]:shadow-[0_0_0_2px_#0a0a0a,0_1px_3px_rgba(0,0,0,0.5)] [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb:active]:cursor-grabbing"
534
+ className="mx-1 h-6 w-[96px] cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-[2px] [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-neutral-700 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[10px] [&::-webkit-slider-thumb]:h-[10px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-text-0 [&::-webkit-slider-thumb]:-mt-1 [&::-webkit-slider-thumb]:shadow-[0_0_0_2px_#0a0a0a,0_1px_3px_rgba(0,0,0,0.5)] [&::-webkit-slider-thumb]:cursor-grab [&::-webkit-slider-thumb:active]:cursor-grabbing"
535
535
  />
536
536
  <Tooltip label="Zoom in">
537
537
  <button
@@ -301,7 +301,7 @@ function WindowMenu() {
301
301
  onClick={() => togglePanel(id)}
302
302
  className="flex w-full items-center gap-2 px-3 py-1.5 text-left text-[11px] text-neutral-300 hover:bg-neutral-800"
303
303
  >
304
- <span className="w-3 text-panel-accent">{openPanels.has(id) ? "✓" : ""}</span>
304
+ <span className="w-3 text-accent-ink">{openPanels.has(id) ? "✓" : ""}</span>
305
305
  {PANEL_DEFINITIONS[id].title}
306
306
  </button>
307
307
  ))}
@@ -1,9 +1,17 @@
1
1
  @import "dockview-react/dist/styles/dockview.css";
2
2
 
3
+ .dv-shell:has(.hf-dock) {
4
+ /* dockview's runtime stylesheet pins `color-scheme: dark` on its theme class, which sits on
5
+ * the shell around the dock. */
6
+ color-scheme: inherit;
7
+ }
8
+
3
9
  .hf-dock {
4
10
  --dv-group-view-background-color: var(--panel-card-bg);
5
11
  --dv-tabs-and-actions-container-background-color: var(--panel-strip-bg);
6
12
  --dv-tabs-and-actions-container-height: 36px;
13
+ --dv-icon-hover-background-color: var(--color-hover);
14
+ --dv-tabs-container-scrollbar-color: var(--color-text-muted);
7
15
  /* The fill paints the shown tab, so every tab state is transparent. */
8
16
  --dv-activegroup-visiblepanel-tab-background-color: transparent;
9
17
  --dv-activegroup-hiddenpanel-tab-background-color: transparent;
@@ -178,7 +186,7 @@
178
186
  }
179
187
 
180
188
  .dv-groupview:hover .hf-dock-strip-actions {
181
- opacity: 0.5;
189
+ opacity: 0.8;
182
190
  }
183
191
 
184
192
  .hf-dock-strip-actions:hover,
@@ -201,7 +201,7 @@ export const AnimationCard = memo(function AnimationCard({
201
201
  className="flex w-full items-center gap-2 py-1.5 active:scale-[0.99]"
202
202
  >
203
203
  <span
204
- className="rounded-sm bg-panel-accent/10 px-1.5 py-0.5 text-[10px] font-semibold text-panel-accent"
204
+ className="rounded-sm bg-panel-accent/10 px-1.5 py-0.5 text-[10px] font-semibold text-accent-ink"
205
205
  title={METHOD_TOOLTIPS[animation.method]}
206
206
  >
207
207
  {methodLabel}
@@ -354,7 +354,7 @@ export const AnimationCard = memo(function AnimationCard({
354
354
 
355
355
  {animation.method === "fromTo" && (
356
356
  <div className="space-y-1">
357
- <p className="text-[9px] font-semibold uppercase tracking-wider text-orange-400/70">
357
+ <p className="text-[9px] font-semibold uppercase tracking-wider text-warning-ink">
358
358
  From
359
359
  </p>
360
360
  <div className="space-y-1.5">
@@ -378,14 +378,14 @@ export const AnimationCard = memo(function AnimationCard({
378
378
  onAdd={(prop) => onAddFromProperty?.(animation.id, prop)}
379
379
  onOpen={() => setAddingFromProp(true)}
380
380
  onClose={() => setAddingFromProp(false)}
381
- buttonClassName="text-[11px] font-medium text-orange-400/70 transition-colors hover:text-orange-300"
381
+ buttonClassName="text-[11px] font-medium text-warning-ink transition-colors hover:text-text-0"
382
382
  />
383
383
  </div>
384
384
  </div>
385
385
  )}
386
386
 
387
387
  {animation.method === "fromTo" && Object.keys(animation.properties).length > 0 && (
388
- <p className="text-[9px] font-semibold uppercase tracking-wider text-panel-accent/70">
388
+ <p className="text-[9px] font-semibold uppercase tracking-wider text-accent-ink">
389
389
  To
390
390
  </p>
391
391
  )}
@@ -455,7 +455,7 @@ export const AnimationCard = memo(function AnimationCard({
455
455
  <button
456
456
  type="button"
457
457
  onClick={() => onDeleteAnimation(animation.id)}
458
- className="ml-auto text-[11px] font-medium text-red-400 transition-colors hover:text-red-300"
458
+ className="ml-auto text-[11px] font-medium rounded-sm text-danger-ink transition-colors hover:bg-danger/15"
459
459
  title="Remove this animation"
460
460
  >
461
461
  Remove
@@ -46,7 +46,7 @@ function RemoveButton({ onClick, title }: { onClick: () => void; title: string }
46
46
  <button
47
47
  type="button"
48
48
  onClick={onClick}
49
- className="relative shrink-0 rounded-sm p-1.5 text-neutral-600 transition-colors hover:bg-neutral-800 hover:text-red-400 active:scale-[0.95]"
49
+ className="relative shrink-0 rounded-sm p-1.5 text-neutral-600 transition-colors hover:bg-neutral-800 hover:text-danger-ink active:scale-[0.95]"
50
50
  title={title}
51
51
  aria-label={title}
52
52
  >
@@ -170,7 +170,7 @@ export const BlockParamsPanel = memo(function BlockParamsPanel({
170
170
  <div className="text-[10px] text-neutral-500">This block has no editable parameters.</div>
171
171
  )}
172
172
  {!fileManager && params.length > 0 && (
173
- <div className="text-[10px] text-amber-400/90">
173
+ <div className="text-[10px] text-warning-ink">
174
174
  Block params can't be edited here — no project file access.
175
175
  </div>
176
176
  )}
@@ -189,12 +189,12 @@ export const BlockParamsPanel = memo(function BlockParamsPanel({
189
189
  </div>
190
190
  )}
191
191
  {commitState.tone === "saved" && (
192
- <div className="text-[10px] text-emerald-500/90" role="status">
192
+ <div className="text-[10px] text-accent-ink" role="status">
193
193
  Saved to {compositionPath}
194
194
  </div>
195
195
  )}
196
196
  {commitState.tone === "error" && (
197
- <div className="text-[10px] text-red-400" role="alert">
197
+ <div className="text-[10px] text-danger-ink" role="alert">
198
198
  {commitState.message}
199
199
  </div>
200
200
  )}
@@ -63,6 +63,9 @@ export function BorderRadiusEditor({
63
63
  }, [linked, uniform, tl, onCommit]);
64
64
 
65
65
  const path = buildRoundedRectPath(PREVIEW_W, PREVIEW_H, sTL, sTR, sBR, sBL);
66
+ const dotFill = linked
67
+ ? "fill-[light-dark(oklch(0.5_0.2_260),#3b82f6)]"
68
+ : "fill-[light-dark(oklch(0.55_0.2_294),#a78bfa)]";
66
69
 
67
70
  return (
68
71
  <div className="space-y-3">
@@ -73,21 +76,11 @@ export function BorderRadiusEditor({
73
76
  viewBox={`0 0 ${PREVIEW_W} ${PREVIEW_H}`}
74
77
  className="shrink-0"
75
78
  >
76
- <path
77
- d={path}
78
- fill="rgba(255,255,255,0.06)"
79
- stroke="rgba(255,255,255,0.24)"
80
- strokeWidth={1.5}
81
- />
82
- <circle cx={sTL} cy={sTL} r={3} fill={linked ? "#3b82f6" : "#a78bfa"} />
83
- <circle cx={PREVIEW_W - sTR} cy={sTR} r={3} fill={linked ? "#3b82f6" : "#a78bfa"} />
84
- <circle
85
- cx={PREVIEW_W - sBR}
86
- cy={PREVIEW_H - sBR}
87
- r={3}
88
- fill={linked ? "#3b82f6" : "#a78bfa"}
89
- />
90
- <circle cx={sBL} cy={PREVIEW_H - sBL} r={3} fill={linked ? "#3b82f6" : "#a78bfa"} />
79
+ <path d={path} className="fill-text-0/[0.06] stroke-text-0/25" strokeWidth={1.5} />
80
+ <circle cx={sTL} cy={sTL} r={3} className={dotFill} />
81
+ <circle cx={PREVIEW_W - sTR} cy={sTR} r={3} className={dotFill} />
82
+ <circle cx={PREVIEW_W - sBR} cy={PREVIEW_H - sBR} r={3} className={dotFill} />
83
+ <circle cx={sBL} cy={PREVIEW_H - sBL} r={3} className={dotFill} />
91
84
  </svg>
92
85
 
93
86
  <button
@@ -257,7 +257,7 @@ export const CanvasContextMenu = memo(function CanvasContextMenu({
257
257
  {hasDelete && (
258
258
  <button
259
259
  type="button"
260
- className="w-full flex items-center justify-between px-3 py-1.5 text-xs text-red-400 hover:bg-neutral-800 cursor-pointer text-left"
260
+ className="w-full flex items-center justify-between px-3 py-1.5 text-xs text-danger-ink hover:bg-neutral-800 cursor-pointer text-left"
261
261
  onPointerDown={(e) => {
262
262
  if (e.button !== 0) return;
263
263
  e.preventDefault();
@@ -29,7 +29,7 @@ export function ComputedTweenNotice({
29
29
  <button
30
30
  type="button"
31
31
  onClick={onUnroll}
32
- className="shrink-0 rounded-sm px-1.5 py-0.5 text-[9px] font-medium text-panel-accent hover:bg-neutral-800"
32
+ className="shrink-0 rounded-sm px-1.5 py-0.5 text-[9px] font-medium text-accent-ink hover:bg-neutral-800"
33
33
  title="Rewrite the helper/loop into explicit tweens so this keyframe edits directly"
34
34
  >
35
35
  Unroll to edit
@@ -1,3 +1,4 @@
1
+ import type { RotationCommit } from "./rotationDraft";
1
2
  import { memo, useEffect, useMemo, useRef, type RefObject } from "react";
2
3
  import { type DomEditSelection } from "./domEditing";
3
4
  import type { PreviewMouseDownOptions } from "../../hooks/usePreviewInteraction";
@@ -10,6 +11,7 @@ import {
10
11
  type BlockedMoveState,
11
12
  type DomEditGroupPathOffsetCommit,
12
13
  type FocusableDomEditOverlay,
14
+ type MoveCommitOptions,
13
15
  type GestureState,
14
16
  type GroupGestureState,
15
17
  focusDomEditOverlayElement,
@@ -45,7 +47,7 @@ export {
45
47
  hasDomEditRotationChanged,
46
48
  resolveDomEditRotationGesture,
47
49
  } from "./domEditOverlayGestures";
48
- export type { DomEditGroupPathOffsetCommit } from "./domEditOverlayGestures";
50
+ export type { DomEditGroupPathOffsetCommit, MoveCommitOptions } from "./domEditOverlayGestures";
49
51
 
50
52
  export interface DomEditOverlayProps {
51
53
  iframeRef: RefObject<HTMLIFrameElement | null>;
@@ -81,7 +83,7 @@ export interface DomEditOverlayProps {
81
83
  onPathOffsetCommit: (
82
84
  selection: DomEditSelection,
83
85
  next: { x: number; y: number },
84
- modifiers?: { altKey?: boolean },
86
+ modifiers?: MoveCommitOptions,
85
87
  ) => Promise<unknown> | void;
86
88
  onGroupPathOffsetCommit: (updates: DomEditGroupPathOffsetCommit[]) => Promise<unknown> | void;
87
89
  onBoxSizeCommit: (
@@ -90,10 +92,7 @@ export interface DomEditOverlayProps {
90
92
  offset?: { x: number; y: number },
91
93
  restore?: () => void,
92
94
  ) => Promise<unknown> | void;
93
- onRotationCommit: (
94
- selection: DomEditSelection,
95
- next: { angle: number },
96
- ) => Promise<unknown> | void;
95
+ onRotationCommit: (selection: DomEditSelection, next: RotationCommit) => Promise<unknown> | void;
97
96
  onStyleCommit?: (property: string, value: string) => Promise<unknown> | void;
98
97
  recordingState?: GestureRecordingState;
99
98
  onToggleRecording?: () => void;
@@ -38,7 +38,7 @@ export function DomEditRotateHandle({
38
38
  aria-label="Rotate selection"
39
39
  onPointerDown={onStartRotate}
40
40
  >
41
- <span className="pointer-events-none flex h-[18px] w-[18px] items-center justify-center rounded-full border border-studio-accent/70 bg-studio-surface text-studio-accent shadow-[0_0_3px_rgba(0,0,0,0.45)]">
41
+ <span className="pointer-events-none flex h-[18px] w-[18px] items-center justify-center rounded-full border border-studio-accent/70 bg-studio-surface text-accent-ink shadow-[0_0_3px_rgba(0,0,0,0.45)]">
42
42
  <svg
43
43
  width="11"
44
44
  height="11"