@hyperframes/studio 0.8.104 → 0.8.106

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 (225) hide show
  1. package/dist/assets/{hyperframes-player-DAoaajuM.js → hyperframes-player-dl6K6ABp.js} +1 -1
  2. package/dist/assets/index-CMiYVGv5.js +399 -0
  3. package/dist/assets/{index-WV9LroAD.js → index-DKT5NF1Y.js} +1 -1
  4. package/dist/assets/index-lrT-gfHa.css +1 -0
  5. package/dist/assets/{index-BDK4rTMb.js → index-ooaZZhKf.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-HIGHVWYD.js → chunk-ICTZJPQQ.js} +3 -2
  9. package/dist/chunk-ICTZJPQQ.js.map +1 -0
  10. package/dist/{chunk-6GAO75IU.js → chunk-NCUBAVGK.js} +10 -8
  11. package/dist/chunk-NCUBAVGK.js.map +1 -0
  12. package/dist/index.css +6 -1
  13. package/dist/index.css.map +1 -1
  14. package/dist/index.d.ts +15 -4
  15. package/dist/index.html +11 -2
  16. package/dist/index.js +10391 -9836
  17. package/dist/index.js.map +1 -1
  18. package/dist/player.js +2 -2
  19. package/dist/styles/tailwind-preset.js.map +1 -1
  20. package/dist/styles.css +1 -1
  21. package/dist/ui.js +2 -2
  22. package/package.json +9 -9
  23. package/src/captions/components/CaptionAnimationPanel.tsx +2 -2
  24. package/src/captions/components/CaptionPropertyPanel.tsx +2 -2
  25. package/src/captions/components/CaptionTimeline.tsx +3 -3
  26. package/src/captions/keyboard.test.ts +6 -0
  27. package/src/captions/keyboard.ts +2 -1
  28. package/src/components/AskAgentModal.tsx +1 -1
  29. package/src/components/LintModal.tsx +35 -35
  30. package/src/components/StudioErrorBoundary.tsx +1 -1
  31. package/src/components/StudioHeader.dom.test.tsx +35 -13
  32. package/src/components/StudioHeader.tsx +6 -2
  33. package/src/components/StudioToast.tsx +7 -16
  34. package/src/components/ThemeToggle.tsx +99 -0
  35. package/src/components/TimelineToolPicker.tsx +1 -1
  36. package/src/components/TimelineToolbar.tsx +11 -11
  37. package/src/components/dock/Dock.tsx +1 -1
  38. package/src/components/dock/dock.css +9 -1
  39. package/src/components/editor/AnimationCard.tsx +5 -5
  40. package/src/components/editor/AnimationCardParts.tsx +1 -1
  41. package/src/components/editor/BlockParamsPanel.tsx +3 -3
  42. package/src/components/editor/BorderRadiusEditor.tsx +8 -15
  43. package/src/components/editor/CanvasContextMenu.tsx +1 -1
  44. package/src/components/editor/ComputedTweenNotice.tsx +1 -1
  45. package/src/components/editor/DomEditOverlay.tsx +37 -5
  46. package/src/components/editor/DomEditRotateHandle.tsx +1 -1
  47. package/src/components/editor/EaseCurveSection.tsx +14 -19
  48. package/src/components/editor/EaseModeControls.tsx +2 -2
  49. package/src/components/editor/EaseParamFields.tsx +8 -8
  50. package/src/components/editor/FileTree.tsx +1 -1
  51. package/src/components/editor/FileTreeIcons.tsx +47 -26
  52. package/src/components/editor/FileTreeNodes.tsx +11 -8
  53. package/src/components/editor/GestureRecordControl.tsx +3 -3
  54. package/src/components/editor/GsapAddAnimationControl.tsx +1 -1
  55. package/src/components/editor/GsapAnimationSection.tsx +2 -2
  56. package/src/components/editor/InlineTextToolbar.tsx +4 -4
  57. package/src/components/editor/InspectorHeaderActions.tsx +1 -1
  58. package/src/components/editor/KeyframeDiamond.tsx +6 -4
  59. package/src/components/editor/KeyframeNavigation.tsx +4 -4
  60. package/src/components/editor/LayersPanel.tsx +3 -3
  61. package/src/components/editor/PromotableControl.tsx +2 -2
  62. package/src/components/editor/PropertyPanelEmptyState.tsx +4 -4
  63. package/src/components/editor/PropertyPanelFlatFooter.tsx +2 -2
  64. package/src/components/editor/PropertyPanelFlatHeader.test.tsx +1 -1
  65. package/src/components/editor/PropertyPanelFlatHeader.tsx +2 -2
  66. package/src/components/editor/SnapToolbar.tsx +5 -5
  67. package/src/components/editor/SourceEditor.tsx +2 -6
  68. package/src/components/editor/TimelineFxPopover.tsx +4 -4
  69. package/src/components/editor/Transform3DCube.tsx +1 -1
  70. package/src/components/editor/anchoredResizeReleaseShift.test.ts +0 -84
  71. package/src/components/editor/domEditOverlayStartGesture.ts +127 -115
  72. package/src/components/editor/easeCurveSvg.tsx +1 -1
  73. package/src/components/editor/gestureHoldsPreviewReload.test.tsx +275 -0
  74. package/src/components/editor/manualEditsDom.ts +36 -3
  75. package/src/components/editor/manualEditsDomPatches.test.ts +2 -86
  76. package/src/components/editor/manualEditsDomPatches.ts +0 -30
  77. package/src/components/editor/manualEditsSnapshot.ts +1 -0
  78. package/src/components/editor/marqueeCommit.test.tsx +69 -1
  79. package/src/components/editor/marqueeCommit.ts +6 -1
  80. package/src/components/editor/overlayFrameLoop.test.ts +27 -0
  81. package/src/components/editor/overlayFrameLoop.ts +21 -0
  82. package/src/components/editor/persistSeam.integration.test.ts +0 -18
  83. package/src/components/editor/plainTranslate.ts +34 -3
  84. package/src/components/editor/propertyPanelColorCurveGraph.tsx +2 -2
  85. package/src/components/editor/propertyPanelColorGradingControls.tsx +1 -1
  86. package/src/components/editor/propertyPanelColorGradingSection.tsx +8 -8
  87. package/src/components/editor/propertyPanelColorGradingSlider.tsx +1 -1
  88. package/src/components/editor/propertyPanelColorSecondary.tsx +4 -4
  89. package/src/components/editor/propertyPanelFill.tsx +6 -6
  90. package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +3 -3
  91. package/src/components/editor/propertyPanelFlatColorGradingSection.test.tsx +1 -1
  92. package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +6 -9
  93. package/src/components/editor/propertyPanelFlatEffectsSection.tsx +4 -4
  94. package/src/components/editor/propertyPanelFlatMediaSection.tsx +2 -2
  95. package/src/components/editor/propertyPanelFlatMotionSection.tsx +2 -2
  96. package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +2 -2
  97. package/src/components/editor/propertyPanelFlatPrimitives.test.tsx +4 -3
  98. package/src/components/editor/propertyPanelFlatPrimitives.tsx +1 -1
  99. package/src/components/editor/propertyPanelFlatSliderReadout.tsx +1 -1
  100. package/src/components/editor/propertyPanelFont.test.tsx +80 -3
  101. package/src/components/editor/propertyPanelFont.tsx +71 -48
  102. package/src/components/editor/propertyPanelFxCarveModule.tsx +1 -1
  103. package/src/components/editor/propertyPanelFxControls.tsx +2 -2
  104. package/src/components/editor/propertyPanelFxEqModule.tsx +2 -2
  105. package/src/components/editor/propertyPanelFxNodeRow.tsx +1 -1
  106. package/src/components/editor/propertyPanelFxPresetRun.tsx +1 -1
  107. package/src/components/editor/propertyPanelHelpers.ts +1 -2
  108. package/src/components/editor/propertyPanelMediaSection.tsx +1 -1
  109. package/src/components/editor/propertyPanelPrimitives.tsx +1 -1
  110. package/src/components/editor/propertyPanelSections.tsx +2 -2
  111. package/src/components/editor/propertyPanelValueTier.test.ts +1 -1
  112. package/src/components/editor/propertyPanelValueTier.ts +1 -1
  113. package/src/components/editor/studioCodeTheme.test.ts +20 -0
  114. package/src/components/editor/studioCodeTheme.ts +99 -0
  115. package/src/components/editor/useDomEditNudge.test.tsx +31 -0
  116. package/src/components/editor/useDomEditNudge.ts +2 -2
  117. package/src/components/editor/useInlineTextEditing.tsx +1 -1
  118. package/src/components/editor/useMotionPathData.test.tsx +64 -0
  119. package/src/components/editor/useMotionPathData.ts +5 -1
  120. package/src/components/feedback/StudioFeedbackCard.tsx +11 -23
  121. package/src/components/nle/AssetPreviewOverlay.tsx +1 -1
  122. package/src/components/nle/AudioMeterStrip.tsx +2 -2
  123. package/src/components/nle/NLEPreview.test.ts +8 -4
  124. package/src/components/nle/PreviewOverlays.tsx +1 -1
  125. package/src/components/nle/PreviewPane.tsx +3 -3
  126. package/src/components/nle/PreviewPoster.tsx +29 -1
  127. package/src/components/nle/PreviewZoomOverlay.tsx +1 -1
  128. package/src/components/panels/SlideshowPanel.tsx +4 -4
  129. package/src/components/panels/SlideshowSubPanels.tsx +19 -21
  130. package/src/components/panels/VariablesBindElement.tsx +1 -1
  131. package/src/components/panels/VariablesDeclarationForm.tsx +1 -1
  132. package/src/components/panels/VariablesPanel.tsx +4 -6
  133. package/src/components/panels/VariablesRowAction.tsx +1 -1
  134. package/src/components/renders/FfmpegRequiredNotice.tsx +4 -4
  135. package/src/components/renders/RenderQueue.tsx +2 -2
  136. package/src/components/renders/RenderQueueItem.tsx +3 -3
  137. package/src/components/sidebar/AssetCard.tsx +3 -3
  138. package/src/components/sidebar/AssetContextMenu.tsx +7 -7
  139. package/src/components/sidebar/AssetsTab.tsx +6 -6
  140. package/src/components/sidebar/AudioRow.tsx +5 -3
  141. package/src/components/sidebar/BlocksTab.tsx +6 -6
  142. package/src/components/sidebar/CompositionsTab.drag.test.tsx +3 -69
  143. package/src/components/sidebar/CompositionsTab.rootBadge.test.tsx +4 -50
  144. package/src/components/sidebar/CompositionsTab.thumbnails.test.tsx +256 -0
  145. package/src/components/sidebar/CompositionsTab.tsx +65 -12
  146. package/src/components/sidebar/PromptPreviewModal.tsx +3 -3
  147. package/src/components/sidebar/SidebarLintButton.tsx +3 -3
  148. package/src/components/sidebar/compositionsTabTestUtils.tsx +39 -0
  149. package/src/components/timelineToolbarStyles.ts +3 -3
  150. package/src/components/ui/Button.tsx +4 -4
  151. package/src/components/ui/HyperframesLogo.tsx +19 -18
  152. package/src/components/ui/Input.tsx +1 -1
  153. package/src/components/ui/Menu.tsx +4 -2
  154. package/src/hooks/appHotkeysDispatch.ts +2 -1
  155. package/src/hooks/elementOffsetStager.ts +8 -7
  156. package/src/hooks/previewPromotionSelection.test.tsx +180 -0
  157. package/src/hooks/useAppHotkeys.test.ts +32 -0
  158. package/src/hooks/useAppHotkeys.ts +1 -2
  159. package/src/hooks/useClipboard.source.test.ts +141 -23
  160. package/src/hooks/useClipboard.ts +154 -123
  161. package/src/hooks/useDomEditCommits.ts +0 -3
  162. package/src/hooks/useDomEditSession.test.tsx +76 -72
  163. package/src/hooks/useDomEditSession.ts +7 -43
  164. package/src/hooks/useDomGeometryCommit.test.tsx +4 -1
  165. package/src/hooks/useDomGeometryCommit.ts +0 -1
  166. package/src/hooks/useDomGeometryCommits.test.tsx +177 -32
  167. package/src/hooks/useDomGeometryCommits.ts +4 -49
  168. package/src/hooks/useGsapTweenCache.ts +1 -2
  169. package/src/hooks/useInlineTextEdit.ts +16 -2
  170. package/src/hooks/useLivePreviewIframe.ts +18 -0
  171. package/src/hooks/usePreviewPersistence.history.test.tsx +47 -0
  172. package/src/hooks/usePreviewPersistence.ts +2 -5
  173. package/src/hooks/useRenderClipContent.ts +3 -3
  174. package/src/index.ts +2 -0
  175. package/src/livePreviewIframeExport.test.tsx +33 -0
  176. package/src/main.tsx +4 -1
  177. package/src/player/components/AudioWaveform.test.tsx +36 -15
  178. package/src/player/components/AudioWaveform.tsx +24 -7
  179. package/src/player/components/ClipContextMenu.tsx +1 -1
  180. package/src/player/components/CompositionThumbnail.tsx +23 -11
  181. package/src/player/components/EditModal.tsx +6 -6
  182. package/src/player/components/KeyframeDiamondContextMenu.tsx +2 -2
  183. package/src/player/components/PlayerControls.tsx +3 -3
  184. package/src/player/components/ShortcutsPanel.tsx +8 -20
  185. package/src/player/components/TimelineCanvas.tsx +1 -1
  186. package/src/player/components/TimelineClip.test.tsx +38 -0
  187. package/src/player/components/TimelineClip.tsx +16 -8
  188. package/src/player/components/TimelineClipFades.test.tsx +376 -74
  189. package/src/player/components/TimelineClipFades.tsx +368 -137
  190. package/src/player/components/TimelineEmptyState.tsx +2 -2
  191. package/src/player/components/TimelineLanes.tsx +0 -1
  192. package/src/player/components/TrackClipCount.tsx +1 -1
  193. package/src/player/components/VolumeControl.tsx +1 -1
  194. package/src/player/components/timelineClipChildren.tsx +1 -1
  195. package/src/player/components/timelineMotionStyles.test.ts +6 -22
  196. package/src/player/components/trackHeaderLabelRows.tsx +16 -16
  197. package/src/player/components/useTimelineKeyboardActor.ts +1 -1
  198. package/src/player/hooks/timelinePlayerTestHarness.ts +27 -0
  199. package/src/player/hooks/useShadowPreviewReload.ts +72 -5
  200. package/src/player/lib/automationStoreSync.test.ts +18 -1
  201. package/src/player/lib/automationStoreSync.ts +29 -17
  202. package/src/player/lib/thumbnailScheduler.ts +4 -5
  203. package/src/player/lib/timelineViewportBudgets.test.ts +1 -1
  204. package/src/player/lib/timelineViewportBudgets.ts +1 -1
  205. package/src/player/sceneSwap.ts +18 -0
  206. package/src/styles/components.css +26 -0
  207. package/src/styles/hex-baseline.json +7 -19
  208. package/src/styles/studio.css +4 -7
  209. package/src/styles/tailwind-preset.shared.js +2 -1
  210. package/src/styles/theme.css +214 -147
  211. package/src/styles/theme.test.ts +13 -9
  212. package/src/utils/blockCategories.ts +41 -9
  213. package/src/utils/clipboardPayload.ts +12 -1
  214. package/src/utils/studioPendingEdits.ts +21 -0
  215. package/src/utils/studioTheme.test.tsx +141 -0
  216. package/src/utils/studioTheme.ts +34 -0
  217. package/src/utils/studioUiPreferences.ts +3 -0
  218. package/src/utils/typingTarget.test.ts +8 -1
  219. package/src/utils/typingTarget.ts +5 -0
  220. package/dist/assets/index-CQN3M56N.css +0 -1
  221. package/dist/assets/index-De2aO4XM.js +0 -399
  222. package/dist/chunk-62DDWOSH.js.map +0 -1
  223. package/dist/chunk-6GAO75IU.js.map +0 -1
  224. package/dist/chunk-HIGHVWYD.js.map +0 -1
  225. package/src/hooks/gsapTargetCache.ts +0 -62
@@ -3,7 +3,7 @@ import { ADD_METHODS, ADD_METHOD_LABELS, METHOD_TOOLTIPS } from "./gsapAnimation
3
3
  const STYLES = {
4
4
  classic: {
5
5
  method:
6
- "rounded-lg border border-neutral-700 bg-neutral-900 px-2.5 py-1.5 text-[11px] font-medium text-neutral-300 transition-colors hover:border-neutral-600 hover:text-white",
6
+ "rounded-lg border border-neutral-700 bg-neutral-900 px-2.5 py-1.5 text-[11px] font-medium text-neutral-300 transition-colors hover:border-neutral-600 hover:text-text-0",
7
7
  cancel: "px-1.5 text-[11px] text-neutral-500 hover:text-neutral-300",
8
8
  trigger: "text-[11px] font-medium text-neutral-400 transition-colors hover:text-neutral-200",
9
9
  },
@@ -24,13 +24,13 @@ export const GsapAnimationSection = memo(function GsapAnimationSection({
24
24
  return (
25
25
  <Section title="Animation" icon={<Film size={15} />}>
26
26
  {multipleTimelines && (
27
- <p className="mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-amber-400">
27
+ <p className="mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink">
28
28
  This file has multiple GSAP timelines. Animation editing is disabled to prevent data loss
29
29
  — consolidate into a single timeline to enable editing.
30
30
  </p>
31
31
  )}
32
32
  {unsupportedTimelinePattern && (
33
- <p className="mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-amber-400">
33
+ <p className="mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink">
34
34
  This timeline uses a computed key (window.__timelines[variable]) the editor can&apos;t
35
35
  resolve statically. Use a string-literal key (window.__timelines[&quot;id&quot;]) or a
36
36
  variable declaration (const tl = gsap.timeline()) to enable editing.
@@ -77,7 +77,7 @@ export function InlineTextToolbar({
77
77
  data-inline-text-toolbar="true"
78
78
  role="toolbar"
79
79
  aria-label="Text formatting"
80
- className="pointer-events-auto fixed z-200 flex items-center gap-1 rounded-lg border border-white/10 bg-[#15171c] p-1 shadow-[0_8px_24px_rgba(0,0,0,0.55)]"
80
+ className="pointer-events-auto fixed z-200 flex items-center gap-1 rounded-lg border border-border bg-raised p-1 shadow-[0_8px_24px_rgba(0,0,0,0.55)]"
81
81
  style={{
82
82
  left: placement.left,
83
83
  top: placement.top,
@@ -98,12 +98,12 @@ export function InlineTextToolbar({
98
98
  onClick={(event) => event.stopPropagation()}
99
99
  >
100
100
  <label
101
- className="group relative flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-white/10"
101
+ className="group relative flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-hover"
102
102
  title="Text colour"
103
103
  >
104
104
  <span
105
105
  aria-hidden="true"
106
- className="h-4 w-4 rounded-full border-2 border-white/25 transition-transform duration-150 group-hover:scale-110 group-active:scale-95"
106
+ className="h-4 w-4 rounded-full border-2 border-border-strong transition-transform duration-150 group-hover:scale-110 group-active:scale-95"
107
107
  // `background` maps a gradient to the PADDING box and then repeats it
108
108
  // to fill the border box, so the 1px border shows the strip either
109
109
  // side of the tile: the end colour on the left, the start colour on
@@ -202,7 +202,7 @@ function ToolbarToggle({
202
202
  aria-label={label}
203
203
  aria-pressed={on}
204
204
  className={`flex h-6 w-6 items-center justify-center rounded-md text-xs ${
205
- on ? "bg-studio-accent/20 text-studio-accent" : "text-white/70 hover:bg-white/10"
205
+ on ? "bg-studio-accent/20 text-accent-ink" : "text-text-2 hover:bg-hover"
206
206
  }`}
207
207
  style={{
208
208
  fontWeight: bold ? 700 : 400,
@@ -67,7 +67,7 @@ export function InspectorHeaderActions({
67
67
  }}
68
68
  className={`flex h-6 w-6 items-center justify-center rounded transition-colors ${
69
69
  copied
70
- ? "text-studio-accent"
70
+ ? "text-accent-ink"
71
71
  : "text-neutral-500 hover:bg-neutral-800 hover:text-neutral-300"
72
72
  }`}
73
73
  title={copied ? "Copied!" : "Copy element info to clipboard"}
@@ -19,8 +19,11 @@ export const KeyframeDiamond = memo(function KeyframeDiamond({
19
19
  isHold = false,
20
20
  }: KeyframeDiamondProps) {
21
21
  const isFilled = state === "active";
22
- const opacity = state === "ghost" ? 0.25 : state === "inactive" ? 0.6 : 1;
23
- const color = state === "active" ? "#3CE6AC" : "#a3a3a3";
22
+ const color = {
23
+ active: "text-accent",
24
+ inactive: "text-text-2 hover:text-text-0",
25
+ ghost: "text-text-off hover:text-text-0",
26
+ }[state];
24
27
 
25
28
  return (
26
29
  <button
@@ -29,8 +32,7 @@ export const KeyframeDiamond = memo(function KeyframeDiamond({
29
32
  e.stopPropagation();
30
33
  onClick();
31
34
  }}
32
- className="relative shrink-0 p-0.5 transition-opacity hover:opacity-100 before:absolute before:-inset-1.5 before:content-['']"
33
- style={{ color, opacity }}
35
+ className={`relative shrink-0 p-0.5 transition-colors before:absolute before:-inset-1.5 before:content-[''] ${color}`}
34
36
  title={title}
35
37
  aria-label={title}
36
38
  aria-pressed={state === "active"}
@@ -82,11 +82,11 @@ function ArrowLeft({ disabled }: { disabled: boolean }) {
82
82
  height="10"
83
83
  viewBox="0 0 6 10"
84
84
  fill="none"
85
- style={{ opacity: disabled ? 0.25 : 1 }}
85
+ className={disabled ? "text-text-off" : "text-text-2"}
86
86
  >
87
87
  <path
88
88
  d="M5 1L1 5L5 9"
89
- stroke="#a3a3a3"
89
+ stroke="currentColor"
90
90
  strokeWidth="1.4"
91
91
  strokeLinecap="round"
92
92
  strokeLinejoin="round"
@@ -102,11 +102,11 @@ function ArrowRight({ disabled }: { disabled: boolean }) {
102
102
  height="10"
103
103
  viewBox="0 0 6 10"
104
104
  fill="none"
105
- style={{ opacity: disabled ? 0.25 : 1 }}
105
+ className={disabled ? "text-text-off" : "text-text-2"}
106
106
  >
107
107
  <path
108
108
  d="M1 1L5 5L1 9"
109
- stroke="#a3a3a3"
109
+ stroke="currentColor"
110
110
  strokeWidth="1.4"
111
111
  strokeLinecap="round"
112
112
  strokeLinejoin="round"
@@ -458,7 +458,7 @@ export const LayersPanel = memo(function LayersPanel() {
458
458
  isDragged
459
459
  ? "opacity-40"
460
460
  : selected
461
- ? "bg-panel-accent/14 text-panel-accent"
461
+ ? "bg-panel-accent/14 text-accent-ink"
462
462
  : "text-panel-text-2 hover:bg-panel-hover/40 hover:text-panel-text-1"
463
463
  } ${dragKey ? "cursor-grabbing" : "cursor-pointer"}`}
464
464
  style={{ paddingLeft: 8 + layer.depth * 16 }}
@@ -494,9 +494,9 @@ export const LayersPanel = memo(function LayersPanel() {
494
494
  <span
495
495
  className={`flex h-5 w-5 shrink-0 items-center justify-center rounded text-[8px] font-bold uppercase ${
496
496
  selected
497
- ? "bg-panel-accent/18 text-panel-accent"
497
+ ? "bg-panel-accent/18 text-accent-ink"
498
498
  : isCompHost
499
- ? "bg-panel-accent/40 text-panel-accent"
499
+ ? "bg-on text-accent-ink"
500
500
  : "bg-panel-hover text-panel-text-4"
501
501
  }`}
502
502
  >
@@ -83,7 +83,7 @@ export function PromotableControl({
83
83
  <span
84
84
  // Sits above the row (not on top of top-0) so it clears a value that
85
85
  // renders flush to the row's right edge, e.g. flat Font/Color rows.
86
- className="pointer-events-none absolute -top-2 right-1.5 z-10 inline-flex max-w-[60%] items-center gap-1 truncate rounded-sm bg-studio-accent/20 px-1 py-px font-mono text-[8px] font-medium text-studio-accent"
86
+ className="pointer-events-none absolute -top-2 right-1.5 z-10 inline-flex max-w-[60%] items-center gap-1 truncate rounded-sm bg-studio-accent/20 px-1 py-px font-mono text-[8px] font-medium text-accent-ink"
87
87
  title={`Bound to variable "${promote.boundId}"`}
88
88
  >
89
89
  ◆ {promote.boundId}
@@ -97,7 +97,7 @@ export function PromotableControl({
97
97
  e.stopPropagation();
98
98
  promote.promote();
99
99
  }}
100
- className="absolute -top-2 right-1.5 z-10 inline-flex items-center gap-1 rounded-sm bg-neutral-800/80 px-1 py-px font-mono text-[8px] font-medium text-neutral-400 opacity-70 transition-colors hover:bg-studio-accent/20 hover:text-studio-accent hover:opacity-100"
100
+ className="absolute -top-2 right-1.5 z-10 inline-flex items-center gap-1 rounded-sm bg-raised/80 px-1 py-px font-mono text-[8px] font-medium text-neutral-400 opacity-70 transition-colors hover:bg-studio-accent/20 hover:text-accent-ink hover:opacity-100"
101
101
  >
102
102
  ◇ var
103
103
  </button>
@@ -24,7 +24,7 @@ function FlatEmptyState() {
24
24
  <div className="mt-2 flex w-full flex-col gap-1.5">
25
25
  <span className="flex items-center justify-between rounded-lg border border-panel-border bg-panel-bg px-3 py-2">
26
26
  <span className="flex items-center gap-2 text-[11px] text-panel-text-2">
27
- <span className="text-panel-danger">●</span>
27
+ <span className="text-danger-ink">●</span>
28
28
  Record a gesture
29
29
  </span>
30
30
  <span className="rounded-sm border border-panel-border-input px-[5px] py-px font-mono text-[9px] text-panel-text-5">
@@ -33,7 +33,7 @@ function FlatEmptyState() {
33
33
  </span>
34
34
  <span className="flex items-center justify-between rounded-lg border border-panel-border bg-panel-bg px-3 py-2">
35
35
  <span className="flex items-center gap-2 text-[11px] text-panel-text-2">
36
- <span className="text-panel-accent">✦</span>
36
+ <span className="text-accent-ink">✦</span>
37
37
  Describe a change to the agent
38
38
  </span>
39
39
  <span className="rounded-sm border border-panel-border-input px-[5px] py-px font-mono text-[9px] text-panel-text-5">
@@ -50,7 +50,7 @@ function elementKindGlyph(element: DomEditSelection): { glyph: string; className
50
50
  return { glyph: "◆", className: "bg-panel-media/10 text-panel-media" };
51
51
  }
52
52
  if (element.textFields?.length > 0) {
53
- return { glyph: "T", className: "bg-panel-accent/10 text-panel-accent" };
53
+ return { glyph: "T", className: "bg-panel-accent/10 text-accent-ink" };
54
54
  }
55
55
  return { glyph: "▦", className: "bg-panel-container/10 text-panel-container" };
56
56
  }
@@ -74,7 +74,7 @@ function FlatMultiSelectState({
74
74
  return (
75
75
  <div className="flex flex-col gap-3 px-4 py-3">
76
76
  <div className="flex items-center gap-3 rounded-xl border border-panel-border bg-panel-surface p-3">
77
- <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-panel-accent/10 text-panel-accent">
77
+ <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-panel-accent/10 text-accent-ink">
78
78
  <Layers size={16} />
79
79
  </span>
80
80
  <div className="min-w-0 flex-1">
@@ -40,7 +40,7 @@ export function PropertyPanelFlatFooter({
40
40
  height="13"
41
41
  viewBox="0 0 16 16"
42
42
  fill="currentColor"
43
- className="text-panel-accent"
43
+ className="text-accent-ink"
44
44
  >
45
45
  <path d="M8 1l1.4 4.6L14 7l-4.6 1.4L8 13l-1.4-4.6L2 7l4.6-1.4z" />
46
46
  </svg>
@@ -57,7 +57,7 @@ export function PropertyPanelFlatFooter({
57
57
  track("button", "Gesture recording");
58
58
  onToggleRecording();
59
59
  }}
60
- className={recording ? "text-panel-danger animate-pulse" : "text-panel-danger"}
60
+ className={recording ? "text-danger-ink animate-pulse" : "text-danger-ink"}
61
61
  >
62
62
  <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor">
63
63
  {recording ? (
@@ -38,7 +38,7 @@ describe("PropertyPanelFlatHeader", () => {
38
38
  expect(host.textContent).toContain("Mono Label");
39
39
  expect(host.textContent).toContain(".mono-label · div");
40
40
  const icon = host.querySelector('[data-flat-header-icon="true"]');
41
- expect(icon?.className).toContain("text-panel-accent");
41
+ expect(icon?.className).toContain("text-accent-ink");
42
42
  act(() => root.unmount());
43
43
  });
44
44
 
@@ -4,7 +4,7 @@ import { ClipboardList, Film, Square, Type, X } from "../../icons/SystemIcons";
4
4
 
5
5
  const ICON_BY_KIND = { text: Type, media: Film, other: Square } as const;
6
6
  const ICON_COLOR_BY_KIND = {
7
- text: "text-panel-accent",
7
+ text: "text-accent-ink",
8
8
  media: "text-panel-media",
9
9
  other: "text-panel-container",
10
10
  } as const;
@@ -92,7 +92,7 @@ export function PropertyPanelFlatHeader({
92
92
  track("button", "Copy element info");
93
93
  onCopy();
94
94
  }}
95
- className={copied ? "text-panel-accent" : undefined}
95
+ className={copied ? "text-accent-ink" : undefined}
96
96
  >
97
97
  <ClipboardList size={13} />
98
98
  </button>
@@ -73,7 +73,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
73
73
  type="button"
74
74
  className={`rounded-md p-1.5 transition-colors active:scale-[0.95] ${
75
75
  motionPathArmed
76
- ? "bg-studio-accent/20 text-studio-accent"
76
+ ? "bg-studio-accent/20 text-accent-ink"
77
77
  : "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"
78
78
  }`}
79
79
  onClick={() => setMotionPathArmed(!motionPathArmed)}
@@ -99,7 +99,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
99
99
  type="button"
100
100
  className={`rounded-md p-1.5 transition-colors active:scale-[0.95] ${
101
101
  visible
102
- ? "bg-studio-accent/20 text-studio-accent"
102
+ ? "bg-studio-accent/20 text-accent-ink"
103
103
  : "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"
104
104
  }`}
105
105
  onClick={toggle}
@@ -115,7 +115,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
115
115
  type="button"
116
116
  className={`rounded-md p-1.5 transition-colors active:scale-[0.95] ${
117
117
  prefs.snapEnabled
118
- ? "bg-studio-accent/20 text-studio-accent"
118
+ ? "bg-studio-accent/20 text-accent-ink"
119
119
  : "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"
120
120
  }`}
121
121
  onClick={toggleSnap}
@@ -131,7 +131,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
131
131
  type="button"
132
132
  className={`rounded-md p-1.5 transition-colors active:scale-[0.95] ${
133
133
  prefs.gridVisible
134
- ? "bg-studio-accent/20 text-studio-accent"
134
+ ? "bg-studio-accent/20 text-accent-ink"
135
135
  : "bg-black/40 text-white/60 hover:bg-black/60 hover:text-white/80"
136
136
  }`}
137
137
  onClick={toggleGrid}
@@ -164,7 +164,7 @@ export const SnapToolbar = memo(function SnapToolbar() {
164
164
  {gridPopoverOpen && (
165
165
  <div
166
166
  ref={popoverRef}
167
- className="absolute right-0 top-full mt-1 rounded-lg bg-neutral-800 border border-neutral-700 p-3 shadow-xl min-w-[180px]"
167
+ className="absolute right-0 top-full mt-1 rounded-lg bg-raised border border-border p-3 shadow-xl min-w-[180px]"
168
168
  >
169
169
  <label className="flex items-center justify-between text-xs text-white/80 mb-2">
170
170
  <span>Grid spacing</span>
@@ -11,12 +11,12 @@ import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
11
11
  import { bracketMatching, foldGutter, indentOnInput } from "@codemirror/language";
12
12
  import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
13
13
  import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
14
- import { oneDark } from "@codemirror/theme-one-dark";
15
14
  import type { Extension } from "@codemirror/state";
16
15
  import { html } from "@codemirror/lang-html";
17
16
  import { css } from "@codemirror/lang-css";
18
17
  import { javascript } from "@codemirror/lang-javascript";
19
18
  import { markdown } from "@codemirror/lang-markdown";
19
+ import { studioCodeTheme } from "./studioCodeTheme";
20
20
 
21
21
  // Marks a programmatic doc sync (external content push — e.g. a manual-edit
22
22
  // commit writing the source) so the update listener doesn't mistake it for a
@@ -114,13 +114,9 @@ export const SourceEditor = memo(function SourceEditor({
114
114
  highlightSelectionMatches(),
115
115
  keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...searchKeymap, ...historyKeymap]),
116
116
  getLanguageExtension(lang),
117
- oneDark,
117
+ studioCodeTheme,
118
118
  updateListener,
119
119
  EditorState.readOnly.of(readOnly),
120
- EditorView.theme({
121
- "&": { height: "100%" },
122
- ".cm-scroller": { overflow: "auto" },
123
- }),
124
120
  ],
125
121
  });
126
122
 
@@ -139,7 +139,7 @@ export function TimelineFxPopover({
139
139
  ref={rootRef}
140
140
  role="dialog"
141
141
  aria-label="Effects"
142
- className="z-200 flex flex-col overflow-hidden rounded-md border border-white/10 bg-[#1b1b1f] p-2 shadow-xl"
142
+ className="z-200 flex flex-col overflow-hidden rounded-md border border-border bg-raised p-2 shadow-xl"
143
143
  style={clampedStyle(anchorRect)}
144
144
  onKeyDown={onKeyDown}
145
145
  onPointerDown={(event) => event.stopPropagation()}
@@ -165,10 +165,10 @@ export function TimelineFxPopover({
165
165
  onAuditionTracked={(id) => trackPresetAuditioned(id, { trackKind })}
166
166
  />
167
167
  </div>
168
- <div className="mt-2 flex shrink-0 items-center justify-between border-t border-white/10 pt-2 text-[10px] text-white/55">
168
+ <div className="mt-2 flex shrink-0 items-center justify-between border-t border-border pt-2 text-[10px] text-text-muted">
169
169
  <button
170
170
  type="button"
171
- className="hover:text-white"
171
+ className="hover:text-text-0"
172
172
  onClick={() => {
173
173
  onClose();
174
174
  onOpenRack();
@@ -178,7 +178,7 @@ export function TimelineFxPopover({
178
178
  </button>
179
179
  <button
180
180
  type="button"
181
- className="hover:text-white"
181
+ className="hover:text-text-0"
182
182
  onClick={() => {
183
183
  onClose();
184
184
  onOpenRack();
@@ -314,7 +314,7 @@ export function Transform3DCube({
314
314
  aria-label="Keyframe 3D transform"
315
315
  aria-pressed={keyframed}
316
316
  className={`absolute left-1.5 top-1.5 rounded p-0.5 hover:bg-neutral-800 ${
317
- keyframed ? "text-[#5ff0bf]" : "text-neutral-500 hover:text-neutral-200"
317
+ keyframed ? "text-accent-ink" : "text-neutral-500 hover:text-neutral-200"
318
318
  }`}
319
319
  >
320
320
  <svg
@@ -1,12 +1,6 @@
1
1
  // @vitest-environment jsdom
2
2
  import { afterEach, describe, expect, it } from "vitest";
3
- import { applyStudioBoxSize, applyStudioPathOffset, readStudioBoxSize } from "./manualEditsDom";
4
- import { reapplyPositionEditsAfterSeek } from "./manualEditsSeekReapply";
5
- import { buildBoxSizePatches, buildPathOffsetPatches } from "./manualEditsDomPatches";
6
- import { createManualOffsetDragMember, applyManualOffsetDragCommit } from "./manualOffsetDrag";
7
3
  import { computeNextResizeAnchor } from "./domEditResizeLocal";
8
- import type { PatchOperation } from "../../utils/sourcePatcher";
9
- import { splitTopLevelWhitespace } from "./manualEditsStyleHelpers";
10
4
 
11
5
  /**
12
6
  * Center-anchored corner resize (CapCut model): the element scales about its
@@ -38,40 +32,6 @@ afterEach(() => {
38
32
  document.body.innerHTML = "";
39
33
  });
40
34
 
41
- /** Apply a built PatchOperation[] to a live element, mirroring sourcePatcher's
42
- * inline-style / attribute application — i.e. what the persisted source carries
43
- * when it is re-parsed into the DOM on the next preview load. */
44
- function applyPatchesToElement(el: HTMLElement, ops: PatchOperation[]): void {
45
- for (const op of ops) {
46
- if (op.type === "inline-style") {
47
- if (op.value === null) el.style.removeProperty(op.property);
48
- else el.style.setProperty(op.property, op.value);
49
- } else if (op.type === "attribute") {
50
- if (op.value === null) el.removeAttribute(op.property);
51
- else el.setAttribute(op.property, op.value);
52
- }
53
- }
54
- }
55
-
56
- /** Net translate applied to an element, resolving the studio offset var()
57
- * expression to its px value so we compare the actually-rendered translation. */
58
- function resolvedTranslatePx(el: HTMLElement): { x: number; y: number } {
59
- const raw = el.style.getPropertyValue("translate").trim();
60
- if (!raw || raw === "none") return { x: 0, y: 0 };
61
- const vx = Number.parseFloat(el.style.getPropertyValue("--hf-studio-offset-x")) || 0;
62
- const vy = Number.parseFloat(el.style.getPropertyValue("--hf-studio-offset-y")) || 0;
63
- const parts = splitTopLevelWhitespace(raw);
64
- const parseAxis = (part: string, varVal: number): number => {
65
- if (part && part.includes("--hf-studio-offset")) return varVal;
66
- const n = Number.parseFloat(part);
67
- return Number.isFinite(n) ? n : 0;
68
- };
69
- return {
70
- x: parseAxis(parts[0] ?? "", vx),
71
- y: parseAxis(parts[1] ?? "", vy),
72
- };
73
- }
74
-
75
35
  describe("center-anchored corner resize — no shift after release", () => {
76
36
  it("the per-frame center anchor converges (does NOT oscillate) — the release-shift root cause", () => {
77
37
  // Model the pointermove anchor loop that pins the element's CENTER. The physical
@@ -157,48 +117,4 @@ describe("center-anchored corner resize — no shift after release", () => {
157
117
  }
158
118
  }
159
119
  });
160
-
161
- it("net translate after persist+reload equals the committed anchor offset (non-GSAP)", () => {
162
- // The committed offset flows through the real apply → persist → reload chain
163
- // unchanged (this hop was proved clean; the shift is upstream in the anchor
164
- // loop above, not in persistence).
165
- const el = document.createElement("div");
166
- el.style.setProperty("width", "200px");
167
- el.style.setProperty("height", "100px");
168
- document.body.appendChild(el);
169
-
170
- const anchorDx = -30;
171
- const anchorDy = -18;
172
- const finalSize = { width: 240, height: 130 };
173
-
174
- applyStudioBoxSize(el, finalSize);
175
- const memberResult = createManualOffsetDragMember({
176
- key: "k",
177
- selection: { element: el } as never,
178
- element: el,
179
- rect: { left: 0, top: 0, width: 240, height: 130, editScaleX: 1, editScaleY: 1 },
180
- });
181
- expect(memberResult.ok).toBe(true);
182
- if (!memberResult.ok) return;
183
-
184
- const finalOffset = applyManualOffsetDragCommit(memberResult.member, anchorDx, anchorDy);
185
-
186
- applyStudioBoxSize(el, finalSize);
187
- const patches = buildBoxSizePatches(el);
188
- applyStudioPathOffset(el, finalOffset);
189
- patches.push(...buildPathOffsetPatches(el));
190
-
191
- expect(resolvedTranslatePx(el)).toEqual({ x: anchorDx, y: anchorDy });
192
-
193
- // Persist → fresh element re-parsed from source → reload re-stamp.
194
- const reloaded = document.createElement("div");
195
- reloaded.style.setProperty("width", "200px");
196
- reloaded.style.setProperty("height", "100px");
197
- document.body.appendChild(reloaded);
198
- applyPatchesToElement(reloaded, patches);
199
- reapplyPositionEditsAfterSeek(reloaded.ownerDocument);
200
-
201
- expect(resolvedTranslatePx(reloaded)).toEqual({ x: anchorDx, y: anchorDy });
202
- expect(readStudioBoxSize(reloaded)).toEqual(finalSize);
203
- });
204
120
  });