@hyperframes/studio 0.8.59 → 0.8.61

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 (94) hide show
  1. package/dist/assets/{hyperframes-player-BBub3ZdI.js → hyperframes-player-nmVkPQza.js} +1 -1
  2. package/dist/assets/{index-CI7WON-E.js → index-2-HsQB2C.js} +1 -1
  3. package/dist/assets/{index-D1KNPijK.js → index-BK36b0XY.js} +162 -162
  4. package/dist/assets/{index-BxZ5Cw5w.js → index-COG0K-CQ.js} +1 -1
  5. package/dist/assets/{index-DZBHG9TW.css → index-DS0kLbuM.css} +1 -1
  6. package/dist/index.d.ts +5 -6
  7. package/dist/index.html +2 -2
  8. package/dist/index.js +4977 -4273
  9. package/dist/index.js.map +1 -1
  10. package/dist/styles.css +1 -1
  11. package/package.json +7 -7
  12. package/src/App.tsx +2 -0
  13. package/src/components/StudioHeader.tsx +2 -13
  14. package/src/components/TimelineToolbar.test.tsx +42 -0
  15. package/src/components/TimelineToolbar.tsx +5 -10
  16. package/src/components/editor/propertyPanelFill.tsx +3 -2
  17. package/src/components/icons/AudioMetersIcon.tsx +16 -0
  18. package/src/components/icons/InspectorIcon.tsx +18 -0
  19. package/src/components/icons/ReverseGradientIcon.tsx +23 -0
  20. package/src/components/icons/RippleEditIcon.tsx +19 -0
  21. package/src/components/nle/AudioMeterStrip.test.tsx +278 -7
  22. package/src/components/nle/AudioMeterStrip.tsx +264 -47
  23. package/src/components/ui/Menu.test.tsx +3 -4
  24. package/src/components/ui/Menu.tsx +18 -5
  25. package/src/components/ui/Select.tsx +7 -1
  26. package/src/components/ui/Tooltip.tsx +6 -1
  27. package/src/hooks/useExternalFileChangeCoordinator.test.tsx +56 -0
  28. package/src/hooks/useExternalFileChangeCoordinator.ts +13 -0
  29. package/src/hooks/useRenderClipContent.test.ts +33 -4
  30. package/src/hooks/useRenderClipContent.ts +7 -3
  31. package/src/hooks/useSdkSession.lifecycle.test.tsx +179 -0
  32. package/src/hooks/useSdkSession.ts +84 -14
  33. package/src/hooks/useStudioSdkSessions.ts +8 -1
  34. package/src/player/components/AudioWaveform.test.tsx +53 -1
  35. package/src/player/components/AudioWaveform.tsx +124 -65
  36. package/src/player/components/ImageThumbnail.tsx +3 -5
  37. package/src/player/components/LayerDisclosureRow.tsx +9 -4
  38. package/src/player/components/PlayheadIndicator.tsx +3 -3
  39. package/src/player/components/TimelineAutomationLane.test.tsx +1 -1
  40. package/src/player/components/TimelineAutomationLane.tsx +5 -5
  41. package/src/player/components/TimelineCanvas.tsx +18 -15
  42. package/src/player/components/TimelineClip.test.tsx +41 -4
  43. package/src/player/components/TimelineClip.tsx +11 -4
  44. package/src/player/components/TimelineClipDiamonds.test.tsx +3 -1
  45. package/src/player/components/TimelineClipDiamonds.tsx +2 -2
  46. package/src/player/components/TimelineClipFades.tsx +64 -31
  47. package/src/player/components/TimelineDiamondConnectors.tsx +2 -2
  48. package/src/player/components/TimelineEmptyState.tsx +1 -1
  49. package/src/player/components/TimelineFxButton.tsx +10 -8
  50. package/src/player/components/TimelineGroupHeader.tsx +18 -9
  51. package/src/player/components/TimelineGroupLaneLabels.tsx +12 -5
  52. package/src/player/components/TimelineGroupRow.tsx +1 -1
  53. package/src/player/components/TimelineLanes.test.tsx +14 -0
  54. package/src/player/components/TimelineLanes.tsx +15 -8
  55. package/src/player/components/TimelinePropertyLanes.test.tsx +1 -1
  56. package/src/player/components/TimelineRazorInteraction.tsx +1 -1
  57. package/src/player/components/TimelineRuler.tsx +3 -2
  58. package/src/player/components/TimelineShortcutHint.tsx +2 -2
  59. package/src/player/components/TimelineTrackHeader.test.tsx +1 -1
  60. package/src/player/components/TimelineTrackHeader.tsx +4 -6
  61. package/src/player/components/TimelineTrackPlainHeader.tsx +10 -3
  62. package/src/player/components/TimelineTransitionBadge.tsx +59 -0
  63. package/src/player/components/TimelineTransitionOverlays.tsx +30 -0
  64. package/src/player/components/VideoThumbnail.test.tsx +23 -12
  65. package/src/player/components/VideoThumbnail.tsx +86 -32
  66. package/src/player/components/audioClipLink.test.ts +34 -0
  67. package/src/player/components/audioClipLink.ts +33 -0
  68. package/src/player/components/audioWaveformPeaks.test.ts +32 -0
  69. package/src/player/components/audioWaveformPeaks.ts +46 -0
  70. package/src/player/components/thumbnailUtils.test.ts +17 -0
  71. package/src/player/components/thumbnailUtils.ts +7 -0
  72. package/src/player/components/timelineMotionStyles.test.ts +96 -30
  73. package/src/player/components/timelineTheme.test.ts +14 -0
  74. package/src/player/components/timelineTheme.ts +18 -11
  75. package/src/player/components/timelineTransitionSeams.test.ts +48 -0
  76. package/src/player/components/timelineTransitionSeams.ts +36 -0
  77. package/src/player/components/timelineZones.test.ts +18 -0
  78. package/src/player/components/timelineZones.ts +4 -1
  79. package/src/player/lib/playbackTypes.ts +2 -0
  80. package/src/player/lib/timelineDOM.test.ts +28 -0
  81. package/src/player/lib/timelineDOM.ts +24 -2
  82. package/src/player/lib/timelineIframeHelpers.ts +7 -0
  83. package/src/player/lib/timelineTransitionMetadata.ts +52 -0
  84. package/src/player/lib/timelineViewportBudgets.ts +2 -1
  85. package/src/player/store/timelineElement.ts +1 -0
  86. package/src/styles/hex-baseline.json +3 -22
  87. package/src/styles/studio.css +126 -46
  88. package/src/styles/theme.css +113 -1
  89. package/src/styles/theme.test.ts +9 -0
  90. package/src/utils/audioMeterVisibility.ts +2 -2
  91. package/src/utils/sdkCutover.test.ts +102 -1
  92. package/src/utils/sdkCutover.ts +16 -21
  93. package/src/utils/sdkEditTransaction.ts +50 -1
  94. package/src/utils/studioUiPreferences.ts +1 -1
@@ -4,6 +4,11 @@ import { hashContent, markSelfWrite } from "../hooks/sdkSelfWriteRegistry";
4
4
  import { trackStudioEvent } from "./studioTelemetry";
5
5
  import { serializeStudioFileMutation } from "./studioFileMutationCoordinator";
6
6
  import type { StudioSdkOperationFamily } from "./sdkCutoverPolicy";
7
+ import {
8
+ StudioFileConflictError,
9
+ StudioSaveHttpError,
10
+ StudioSaveNetworkError,
11
+ } from "./studioSaveDiagnostics";
7
12
 
8
13
  export type CutoverResult =
9
14
  | { status: "declined"; reason: string }
@@ -91,10 +96,54 @@ export function declinedCutover(
91
96
  return { status: "declined", reason };
92
97
  }
93
98
 
94
- export function asCutoverError(error: unknown): Error {
99
+ function asCutoverError(error: unknown): Error {
95
100
  return error instanceof Error ? error : new Error(String(error));
96
101
  }
97
102
 
103
+ // Browser rejection strings for a fetch that never produced a response (offline,
104
+ // the dev server gone, a CSP/PNA block, an extension rewriting fetch). See
105
+ // `useSdkSession.ts`'s `readProjectFileOptional` catch for the same list.
106
+ const FETCH_REJECTION_MESSAGE = /Failed to fetch|Load failed|NetworkError when attempting to fetch/;
107
+
108
+ /**
109
+ * Classify a cutover failure for the gate dashboard. `writeProjectFile`'s own
110
+ * fetch wraps a rejection as `StudioSaveNetworkError`, but two raw fetches in
111
+ * this same transaction — `readProjectFile` (via `captureOnDiskBefore`) and
112
+ * `writeProjectFile`'s own read-before-write preflight — throw an unwrapped
113
+ * `TypeError` that reaches here undecorated. Without the message fallback,
114
+ * those file as `"sdk"` and trip the cutover-failure rollback gate on a
115
+ * network blip the SDK never had a chance to own.
116
+ */
117
+ function cutoverErrorKind(error: Error): "network" | "conflict" | "http" | "sdk" {
118
+ if (error instanceof StudioSaveNetworkError) return "network";
119
+ if (error instanceof StudioFileConflictError) return "conflict";
120
+ if (error instanceof StudioSaveHttpError) return "http";
121
+ if (error.name === "TypeError" && FETCH_REJECTION_MESSAGE.test(error.message)) return "network";
122
+ return "sdk";
123
+ }
124
+
125
+ /**
126
+ * Record a cutover that could not commit. Replaces ad hoc `trackStudioEvent("sdk_cutover_failed", ...)`
127
+ * calls so every gate event carries `family` and `error_kind` — without them the
128
+ * dashboard's rollback gate (any `sdk_cutover_failed` on a flipped version) cannot
129
+ * distinguish a real SDK defect from a rejected fetch it doesn't own.
130
+ */
131
+ export function failedCutover(
132
+ error: unknown,
133
+ family: StudioSdkOperationFamily,
134
+ context: { hfId?: string | null; opCount?: number } = {},
135
+ ): CutoverResult {
136
+ const err = asCutoverError(error);
137
+ trackStudioEvent("sdk_cutover_failed", {
138
+ ...context,
139
+ family,
140
+ error_kind: cutoverErrorKind(err),
141
+ ...(err instanceof StudioSaveHttpError ? { status: err.statusCode } : {}),
142
+ error: err.message,
143
+ });
144
+ return { status: "failed", error: err };
145
+ }
146
+
98
147
  /** Only an explicit decline may enter the legacy mutation backend. */
99
148
  export function cutoverCommittedOrThrow(result: CutoverResult): boolean {
100
149
  if (result.status === "failed") throw result.error;
@@ -25,7 +25,7 @@ export interface StudioUiPreferences {
25
25
  snapToGrid?: boolean;
26
26
  /** Timeline magnet: snap clip drags/trims/drops to playhead, clip edges, and beats. */
27
27
  timelineSnapEnabled?: boolean;
28
- /** Audio level meters at the timeline's right edge; shown unless hidden here. */
28
+ /** Audio level meters at the timeline's right edge; hidden unless enabled here. */
29
29
  audioMetersVisible?: boolean;
30
30
  /** Keeps the main track gapless: deleting a clip closes the gap. Distinct
31
31
  * from `timelineSnapEnabled` ("Magnet", drag/trim snapping). */