@hyperframes/studio 0.8.53-desktop.0 → 0.8.54
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.
- package/dist/assets/{hyperframes-player-PTEnAHhg.js → hyperframes-player-Cy_AwUa8.js} +1 -1
- package/dist/assets/{index-BjslOS9g.js → index-CTa-6Kso.js} +1 -1
- package/dist/assets/{index-CNyviK_l.js → index-DPUJoO8n.js} +203 -203
- package/dist/assets/{index--myXp8ui.js → index-DkAzKuPZ.js} +1 -1
- package/dist/assets/{index-BnXZuIJD.css → index-DrHQAuGO.css} +1 -1
- package/dist/index.d.ts +43 -8
- package/dist/index.html +2 -2
- package/dist/index.js +7896 -7717
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -0
- package/package.json +8 -7
- package/src/components/StudioHeader.tsx +1 -1
- package/src/components/nle/TimelinePane.tsx +4 -1
- package/src/components/renders/RenderQueue.test.tsx +133 -25
- package/src/components/renders/RenderQueue.tsx +99 -92
- package/src/components/renders/RenderQueueItem.tsx +69 -64
- package/src/components/ui/Select.tsx +4 -0
- package/src/headerExports.test.tsx +23 -0
- package/src/hooks/timelineAudioGroupCreate.ts +17 -1
- package/src/hooks/timelineAudioGroupVolume.ts +35 -2
- package/src/hooks/timelineElementFxAttribute.ts +34 -2
- package/src/hooks/useRightPanelIntents.ts +2 -1
- package/src/hooks/useTimelineAssetDropOps.test.tsx +62 -4
- package/src/hooks/useTimelineAssetDropOps.ts +40 -3
- package/src/hooks/useTimelineEditing.test.tsx +160 -2
- package/src/hooks/useTimelineEditing.ts +76 -39
- package/src/index.ts +5 -2
- package/src/main.tsx +26 -0
- package/src/player/components/Timeline.tsx +6 -6
- package/src/player/components/TimelineTrackHeader.test.tsx +5 -26
- package/src/player/components/TimelineTrackHeader.tsx +1 -1
- package/src/player/components/TimelineTypes.ts +3 -0
- package/src/player/components/timelineTheme.test.ts +4 -4
- package/src/player/components/timelineTheme.ts +30 -30
- package/src/player/components/usePublishRangeSelection.test.tsx +60 -0
- package/src/player/components/usePublishRangeSelection.ts +42 -0
- package/src/player/index.ts +1 -0
- package/src/player/store/playerStore.ts +8 -51
- package/src/player/store/rangeSelectionSlice.ts +13 -0
- package/src/player/store/timelineResetState.ts +51 -0
- package/src/styles/hex-baseline.json +2 -2
- package/src/styles/theme.css +0 -27
|
@@ -34,7 +34,7 @@ const GROUP_MEMBER_INDENT = 14;
|
|
|
34
34
|
const GROUP_MEMBER_TINT = "rgba(255,255,255,0.035)";
|
|
35
35
|
|
|
36
36
|
/** The gutter fill for a row, tinted when it belongs to a group. */
|
|
37
|
-
|
|
37
|
+
function gutterFill(base: string, isGroupMember: boolean): string {
|
|
38
38
|
return isGroupMember
|
|
39
39
|
? `linear-gradient(${GROUP_MEMBER_TINT}, ${GROUP_MEMBER_TINT}), ${base}`
|
|
40
40
|
: base;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { TimelineElement } from "../store/playerStore";
|
|
3
|
+
import type { TimelineTimeRange } from "../store/rangeSelectionSlice";
|
|
3
4
|
import type { TimelineDropCallbacks } from "./timelineCallbacks";
|
|
4
5
|
import type { TimelineTheme } from "./timelineTheme";
|
|
5
6
|
import type { TimelineEditOverrides } from "./useResolvedTimelineEditCallbacks";
|
|
@@ -23,6 +24,8 @@ export interface TimelineProps extends TimelineDropCallbacks, TimelineEditOverri
|
|
|
23
24
|
renderClipOverlay?: (element: TimelineElement) => ReactNode;
|
|
24
25
|
onDeleteElement?: (element: TimelineElement) => Promise<void> | void;
|
|
25
26
|
onSelectElement?: (element: TimelineElement | null) => void;
|
|
27
|
+
/** Notification only; null when cleared. The value lives in usePlayerStore.rangeSelection. */
|
|
28
|
+
onRangeSelect?: (range: TimelineTimeRange | null) => void;
|
|
26
29
|
onCopyClip?: () => boolean;
|
|
27
30
|
onPasteClip?: () => Promise<void>;
|
|
28
31
|
onDuplicateClip?: () => Promise<boolean>;
|
|
@@ -9,10 +9,10 @@ import { getTrackStyle } from "./timelineIcons";
|
|
|
9
9
|
describe("getTimelineTrackStyle", () => {
|
|
10
10
|
it("uses one neutral clip style for every timeline tag", () => {
|
|
11
11
|
const expectedStyle = {
|
|
12
|
-
clip: "
|
|
13
|
-
clipActive: "
|
|
14
|
-
accent: "
|
|
15
|
-
label: "
|
|
12
|
+
clip: "rgba(255,255,255,0.055)",
|
|
13
|
+
clipActive: "rgba(60,230,172,0.16)",
|
|
14
|
+
accent: "#3CE6AC",
|
|
15
|
+
label: "rgba(255,255,255,0.5)",
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
expect(getTimelineTrackStyle("video")).toEqual(expectedStyle);
|
|
@@ -36,43 +36,43 @@ export interface TimelineTheme {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const TRACK_STYLE: TimelineTrackStyle = {
|
|
39
|
-
clip: "
|
|
40
|
-
clipActive: "
|
|
41
|
-
accent: "
|
|
42
|
-
label: "
|
|
39
|
+
clip: "rgba(255,255,255,0.055)",
|
|
40
|
+
clipActive: "rgba(60,230,172,0.16)",
|
|
41
|
+
accent: "#3CE6AC",
|
|
42
|
+
label: "rgba(255,255,255,0.5)",
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
// Every field reads a CSS custom property (declared in styles/theme.css)
|
|
46
|
-
// rather than a literal, so a host themes the timeline the same way it
|
|
47
|
-
// themes the rest of Studio: by overriding the token, not this object.
|
|
48
45
|
export const defaultTimelineTheme: TimelineTheme = {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
46
|
+
// Near-black card surfaces: the panels sit dark while the shell canvas
|
|
47
|
+
// between them is a step LIGHTER (#18181B), so the gaps read as visible
|
|
48
|
+
// seams around dark cards (CapCut-style).
|
|
49
|
+
shellBackground: "#0A0A0B",
|
|
50
|
+
shellBorder: "rgba(255,255,255,0.05)",
|
|
51
|
+
rulerBorder: "rgba(255,255,255,0.16)",
|
|
52
|
+
// All track lanes use a single uniform color — one step lighter than the panel
|
|
53
|
+
// surface (#0A0A0B) so lanes are visibly distinct from the ruler/shell.
|
|
54
|
+
rowBackground: "#101014",
|
|
55
|
+
rowBorder: "rgba(255,255,255,0.06)",
|
|
56
|
+
gutterBackground: "#0E0F12",
|
|
57
|
+
gutterBorder: "rgba(255,255,255,0.10)",
|
|
58
|
+
textPrimary: "rgba(255,255,255,0.92)",
|
|
59
|
+
textSecondary: "rgba(255,255,255,0.62)",
|
|
60
|
+
tickText: "rgba(255,255,255,0.34)",
|
|
61
|
+
tickMajor: "rgba(255,255,255,0.10)",
|
|
62
|
+
tickMinor: "rgba(255,255,255,0.06)",
|
|
63
|
+
clipBackground: "#141922",
|
|
64
|
+
clipBackgroundActive: "#181e28",
|
|
65
|
+
clipBorder: "rgba(255,255,255,0.10)",
|
|
66
|
+
clipBorderHover: "rgba(255,255,255,0.18)",
|
|
67
|
+
clipBorderActive: "rgba(255,255,255,0.24)",
|
|
68
68
|
clipShadow: "none",
|
|
69
69
|
clipShadowHover: "0 2px 8px rgba(0,0,0,0.2)",
|
|
70
70
|
clipShadowActive: "0 2px 8px rgba(0,0,0,0.2), 0 0 0 1px rgba(255,255,255,0.04)",
|
|
71
71
|
clipShadowDragging: "0 8px 24px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.06)",
|
|
72
|
-
handleColor: "
|
|
73
|
-
panelResizeSeam: "
|
|
74
|
-
panelResizeActive: "
|
|
75
|
-
clipRadius: "
|
|
72
|
+
handleColor: "rgba(255,255,255,0.2)",
|
|
73
|
+
panelResizeSeam: "rgba(255,255,255,0.12)",
|
|
74
|
+
panelResizeActive: "rgba(255,255,255,0.24)",
|
|
75
|
+
clipRadius: "8px",
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
export function getTimelineTrackStyle(_tag: string): TimelineTrackStyle {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import React, { act } from "react";
|
|
3
|
+
import { createRoot } from "react-dom/client";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { usePlayerStore } from "../store/playerStore";
|
|
6
|
+
import type { TimelineTimeRange } from "../store/rangeSelectionSlice";
|
|
7
|
+
import type { TimelineRangeSelection } from "./timelineEditing";
|
|
8
|
+
import { usePublishRangeSelection } from "./usePublishRangeSelection";
|
|
9
|
+
|
|
10
|
+
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
|
11
|
+
|
|
12
|
+
function mount(onRangeSelect: (range: TimelineTimeRange | null) => void) {
|
|
13
|
+
const host = document.createElement("div");
|
|
14
|
+
const root = createRoot(host);
|
|
15
|
+
const Harness = ({ selection }: { selection: TimelineRangeSelection | null }) => {
|
|
16
|
+
usePublishRangeSelection(selection, onRangeSelect);
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
const render = (selection: TimelineRangeSelection | null) =>
|
|
20
|
+
act(() => root.render(<Harness selection={selection} />));
|
|
21
|
+
return { render, unmount: () => act(() => root.unmount()) };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const selection = (start: number, end: number): TimelineRangeSelection => ({
|
|
25
|
+
start,
|
|
26
|
+
end,
|
|
27
|
+
anchorX: 0,
|
|
28
|
+
anchorY: 0,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("usePublishRangeSelection", () => {
|
|
32
|
+
afterEach(() => usePlayerStore.setState({ rangeSelection: null }));
|
|
33
|
+
|
|
34
|
+
it("publishes an ordered range to the store and the host, and clears with null", () => {
|
|
35
|
+
const onRangeSelect = vi.fn();
|
|
36
|
+
const view = mount(onRangeSelect);
|
|
37
|
+
|
|
38
|
+
view.render(selection(3, 1));
|
|
39
|
+
expect(usePlayerStore.getState().rangeSelection).toEqual({ t0: 1, t1: 3 });
|
|
40
|
+
expect(onRangeSelect).toHaveBeenLastCalledWith({ t0: 1, t1: 3 });
|
|
41
|
+
|
|
42
|
+
view.render(null);
|
|
43
|
+
expect(usePlayerStore.getState().rangeSelection).toBeNull();
|
|
44
|
+
expect(onRangeSelect).toHaveBeenLastCalledWith(null);
|
|
45
|
+
view.unmount();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("does not re-notify for an unchanged range and preserves a newer store value on unmount", () => {
|
|
49
|
+
const onRangeSelect = vi.fn();
|
|
50
|
+
const view = mount(onRangeSelect);
|
|
51
|
+
|
|
52
|
+
view.render(selection(1, 3));
|
|
53
|
+
view.render(selection(3, 1));
|
|
54
|
+
expect(onRangeSelect).toHaveBeenCalledTimes(1);
|
|
55
|
+
|
|
56
|
+
usePlayerStore.setState({ rangeSelection: { t0: 9, t1: 10 } });
|
|
57
|
+
view.unmount();
|
|
58
|
+
expect(usePlayerStore.getState().rangeSelection).toEqual({ t0: 9, t1: 10 });
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { usePlayerStore } from "../store/playerStore";
|
|
3
|
+
import type { TimelineTimeRange } from "../store/rangeSelectionSlice";
|
|
4
|
+
import type { TimelineRangeSelection } from "./timelineEditing";
|
|
5
|
+
|
|
6
|
+
/** Mirrors the gesture's range into the store and notifies the host. */
|
|
7
|
+
export function usePublishRangeSelection(
|
|
8
|
+
rangeSelection: TimelineRangeSelection | null,
|
|
9
|
+
onRangeSelect?: (range: TimelineTimeRange | null) => void,
|
|
10
|
+
) {
|
|
11
|
+
const onRangeSelectRef = useRef(onRangeSelect);
|
|
12
|
+
const publishedRangeRef = useRef<TimelineTimeRange | null>(null);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
onRangeSelectRef.current = onRangeSelect;
|
|
16
|
+
}, [onRangeSelect]);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const range = rangeSelection
|
|
20
|
+
? {
|
|
21
|
+
t0: Math.min(rangeSelection.start, rangeSelection.end),
|
|
22
|
+
t1: Math.max(rangeSelection.start, rangeSelection.end),
|
|
23
|
+
}
|
|
24
|
+
: null;
|
|
25
|
+
const store = usePlayerStore.getState();
|
|
26
|
+
const current = store.rangeSelection;
|
|
27
|
+
if (current?.t0 === range?.t0 && current?.t1 === range?.t1) return;
|
|
28
|
+
publishedRangeRef.current = range;
|
|
29
|
+
usePlayerStore.setState({ rangeSelection: range });
|
|
30
|
+
onRangeSelectRef.current?.(range);
|
|
31
|
+
}, [rangeSelection]);
|
|
32
|
+
|
|
33
|
+
useEffect(
|
|
34
|
+
() => () => {
|
|
35
|
+
const current = usePlayerStore.getState().rangeSelection;
|
|
36
|
+
const published = publishedRangeRef.current;
|
|
37
|
+
if (current?.t0 !== published?.t0 || current?.t1 !== published?.t1) return;
|
|
38
|
+
usePlayerStore.setState({ rangeSelection: null });
|
|
39
|
+
},
|
|
40
|
+
[],
|
|
41
|
+
);
|
|
42
|
+
}
|
package/src/player/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { resolveIframe } from "./lib/timelineDOM";
|
|
|
12
12
|
// Store
|
|
13
13
|
export { usePlayerStore, liveTime } from "./store/playerStore";
|
|
14
14
|
export type { SelectElementOptions, TimelineElement, ZoomMode } from "./store/playerStore";
|
|
15
|
+
export type { TimelineTimeRange } from "./store/rangeSelectionSlice";
|
|
15
16
|
|
|
16
17
|
// Utils
|
|
17
18
|
export { formatTime } from "./lib/time";
|
|
@@ -2,7 +2,6 @@ import { create } from "zustand";
|
|
|
2
2
|
import { attachPlayerStoreDevHandle } from "./playerStoreDevHandle";
|
|
3
3
|
import { nextSelectionSet, revealTargetsSelection } from "./playerStoreSelection";
|
|
4
4
|
import type { MusicBeatAnalysis } from "@hyperframes/core/beats";
|
|
5
|
-
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
|
|
6
5
|
import type { BeatEditState } from "../../utils/beatEditing";
|
|
7
6
|
import type { ClipManifestClip } from "../lib/playbackTypes";
|
|
8
7
|
import {
|
|
@@ -11,7 +10,7 @@ import {
|
|
|
11
10
|
type TimelineTimeDisplayMode,
|
|
12
11
|
} from "../../utils/studioUiPreferences";
|
|
13
12
|
import { clampTimelineZoomPercent, computePinnedZoomPercent } from "../components/timelineZoom";
|
|
14
|
-
import { createKeyframeSlice, type
|
|
13
|
+
import { createKeyframeSlice, type KeyframeSlice } from "./keyframeSlice";
|
|
15
14
|
import {
|
|
16
15
|
createAutomationSelectionSlice,
|
|
17
16
|
type AutomationSelectionSlice,
|
|
@@ -19,10 +18,12 @@ import {
|
|
|
19
18
|
import { createEditingModeSlice, type EditingModeSlice } from "./editingModeSlice";
|
|
20
19
|
import { createTimelineFocusRequest, type TimelineFocusRequest } from "./timelineFocusState";
|
|
21
20
|
import { createThumbnailSlice, type ThumbnailSlice } from "./thumbnailSlice";
|
|
22
|
-
import { createPlaybackReadinessSlice
|
|
23
|
-
|
|
21
|
+
import { createPlaybackReadinessSlice } from "./readinessSlice";
|
|
22
|
+
import { createRangeSelectionSlice, type RangeSelectionSlice } from "./rangeSelectionSlice";
|
|
23
|
+
import { createTimelineResetState } from "./timelineResetState";
|
|
24
24
|
export type { KeyframeCacheEntry } from "./keyframeSlice";
|
|
25
25
|
export { liveTime } from "./liveTime";
|
|
26
|
+
export { createTimelineResetState };
|
|
26
27
|
|
|
27
28
|
import type {
|
|
28
29
|
TimelineElement,
|
|
@@ -59,7 +60,8 @@ type PlayerStoreSlices = KeyframeSlice &
|
|
|
59
60
|
AutomationSelectionSlice &
|
|
60
61
|
ThumbnailSlice &
|
|
61
62
|
EditingModeSlice &
|
|
62
|
-
ReturnType<typeof createPlaybackReadinessSlice
|
|
63
|
+
ReturnType<typeof createPlaybackReadinessSlice> &
|
|
64
|
+
RangeSelectionSlice;
|
|
63
65
|
interface PlayerState extends PlayerStoreSlices {
|
|
64
66
|
isPlaying: boolean;
|
|
65
67
|
currentTime: number;
|
|
@@ -250,52 +252,6 @@ interface BeatHistoryEntry {
|
|
|
250
252
|
label: string;
|
|
251
253
|
}
|
|
252
254
|
|
|
253
|
-
export function createTimelineResetState() {
|
|
254
|
-
return {
|
|
255
|
-
isPlaying: false,
|
|
256
|
-
currentTime: 0,
|
|
257
|
-
duration: 0,
|
|
258
|
-
...resetPlaybackReadinessState(),
|
|
259
|
-
beatDragging: false,
|
|
260
|
-
elements: [],
|
|
261
|
-
selectedElementId: null,
|
|
262
|
-
zEditVersion: 0,
|
|
263
|
-
inPoint: null,
|
|
264
|
-
outPoint: null,
|
|
265
|
-
activeTool: "select" as const,
|
|
266
|
-
activeKeyframePct: null,
|
|
267
|
-
motionPathArmed: false,
|
|
268
|
-
motionPathCreateAvailable: false,
|
|
269
|
-
selectedKeyframes: new Set<string>(),
|
|
270
|
-
// Ephemeral like every other selection here. A range surviving a project
|
|
271
|
-
// switch can match a same-keyed clip in the new project and redirect a
|
|
272
|
-
// paste through `sel.elementKey === paste.elementKey` to a stale t0.
|
|
273
|
-
automationSelection: null,
|
|
274
|
-
expandedClipIds: new Set<string>(),
|
|
275
|
-
// Per-composition: ids from comp A match nothing in B, silencing all of it.
|
|
276
|
-
collapsedGroupIds: new Set<string>(),
|
|
277
|
-
expandedLaneOwnerIds: new Set<string>(),
|
|
278
|
-
focusedEaseSegment: null,
|
|
279
|
-
revealedAudioFxTarget: null,
|
|
280
|
-
selectedElementIds: new Set<string>(),
|
|
281
|
-
requestedSeekTime: null,
|
|
282
|
-
lintFindingsByElement: new Map<string, { count: number; messages: string[] }>(),
|
|
283
|
-
timelineFocus: null,
|
|
284
|
-
keyframeCache: new Map<string, KeyframeCacheEntry>(),
|
|
285
|
-
gsapAnimations: new Map<string, GsapAnimation[]>(),
|
|
286
|
-
beatAnalysis: null,
|
|
287
|
-
beatEdits: null,
|
|
288
|
-
beatUndo: [],
|
|
289
|
-
beatRedo: [],
|
|
290
|
-
beatPersist: null,
|
|
291
|
-
clipManifest: null,
|
|
292
|
-
clipParentMap: new Map<string, string>(),
|
|
293
|
-
topLevelIds: null,
|
|
294
|
-
domClipChildren: [],
|
|
295
|
-
subCompositionHostState: new Map<string, SubCompositionHostState>(),
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
|
|
299
255
|
export const usePlayerStore = create<PlayerState>((set, get) => ({
|
|
300
256
|
isPlaying: false,
|
|
301
257
|
currentTime: 0,
|
|
@@ -328,6 +284,7 @@ export const usePlayerStore = create<PlayerState>((set, get) => ({
|
|
|
328
284
|
|
|
329
285
|
...createAutomationSelectionSlice(set),
|
|
330
286
|
...createEditingModeSlice(set),
|
|
287
|
+
...createRangeSelectionSlice(),
|
|
331
288
|
...createPlaybackReadinessSlice(set),
|
|
332
289
|
|
|
333
290
|
activeKeyframePct: null,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface TimelineTimeRange {
|
|
2
|
+
t0: number;
|
|
3
|
+
t1: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface RangeSelectionSlice {
|
|
7
|
+
/** Shift-drag ruler range in seconds, normalized so t0 <= t1. */
|
|
8
|
+
rangeSelection: TimelineTimeRange | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createRangeSelectionSlice(): RangeSelectionSlice {
|
|
12
|
+
return { rangeSelection: null };
|
|
13
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
|
|
2
|
+
import type { KeyframeCacheEntry } from "./keyframeSlice";
|
|
3
|
+
import { resetPlaybackReadinessState } from "./readinessSlice";
|
|
4
|
+
import type { SubCompositionHostState } from "./timelineElement";
|
|
5
|
+
|
|
6
|
+
export function createTimelineResetState() {
|
|
7
|
+
return {
|
|
8
|
+
isPlaying: false,
|
|
9
|
+
currentTime: 0,
|
|
10
|
+
duration: 0,
|
|
11
|
+
...resetPlaybackReadinessState(),
|
|
12
|
+
beatDragging: false,
|
|
13
|
+
elements: [],
|
|
14
|
+
selectedElementId: null,
|
|
15
|
+
zEditVersion: 0,
|
|
16
|
+
inPoint: null,
|
|
17
|
+
outPoint: null,
|
|
18
|
+
rangeSelection: null,
|
|
19
|
+
activeTool: "select" as const,
|
|
20
|
+
activeKeyframePct: null,
|
|
21
|
+
motionPathArmed: false,
|
|
22
|
+
motionPathCreateAvailable: false,
|
|
23
|
+
selectedKeyframes: new Set<string>(),
|
|
24
|
+
// Ephemeral like every other selection here. A range surviving a project
|
|
25
|
+
// switch can match a same-keyed clip in the new project and redirect a
|
|
26
|
+
// paste through `sel.elementKey === paste.elementKey` to a stale t0.
|
|
27
|
+
automationSelection: null,
|
|
28
|
+
expandedClipIds: new Set<string>(),
|
|
29
|
+
// Per-composition: ids from comp A match nothing in B, silencing all of it.
|
|
30
|
+
collapsedGroupIds: new Set<string>(),
|
|
31
|
+
expandedLaneOwnerIds: new Set<string>(),
|
|
32
|
+
focusedEaseSegment: null,
|
|
33
|
+
revealedAudioFxTarget: null,
|
|
34
|
+
selectedElementIds: new Set<string>(),
|
|
35
|
+
requestedSeekTime: null,
|
|
36
|
+
lintFindingsByElement: new Map<string, { count: number; messages: string[] }>(),
|
|
37
|
+
timelineFocus: null,
|
|
38
|
+
keyframeCache: new Map<string, KeyframeCacheEntry>(),
|
|
39
|
+
gsapAnimations: new Map<string, GsapAnimation[]>(),
|
|
40
|
+
beatAnalysis: null,
|
|
41
|
+
beatEdits: null,
|
|
42
|
+
beatUndo: [],
|
|
43
|
+
beatRedo: [],
|
|
44
|
+
beatPersist: null,
|
|
45
|
+
clipManifest: null,
|
|
46
|
+
clipParentMap: new Map<string, string>(),
|
|
47
|
+
topLevelIds: null,
|
|
48
|
+
domClipChildren: [],
|
|
49
|
+
subCompositionHostState: new Map<string, SubCompositionHostState>(),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"total":
|
|
2
|
+
"total": 418,
|
|
3
3
|
"files": {
|
|
4
4
|
"packages/studio/src/captions/components/CaptionOverlay.tsx": 5,
|
|
5
5
|
"packages/studio/src/captions/components/CaptionTimeline.tsx": 11,
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"packages/studio/src/player/components/TimelineTrackHeader.tsx": 2,
|
|
76
76
|
"packages/studio/src/player/components/TimelineTrackPlainHeader.tsx": 2,
|
|
77
77
|
"packages/studio/src/player/components/VideoThumbnail.tsx": 6,
|
|
78
|
-
"packages/studio/src/player/components/timelineTheme.ts":
|
|
78
|
+
"packages/studio/src/player/components/timelineTheme.ts": 29,
|
|
79
79
|
"packages/studio/src/player/components/trackHeaderLabelRows.tsx": 6,
|
|
80
80
|
"packages/studio/src/styles/studio.css": 70,
|
|
81
81
|
"packages/studio/src/telemetry/client.ts": 1,
|
package/src/styles/theme.css
CHANGED
|
@@ -46,33 +46,6 @@
|
|
|
46
46
|
--color-brand-gradient-from: #06e3fa;
|
|
47
47
|
--color-brand-gradient-to: #4fdb5e;
|
|
48
48
|
|
|
49
|
-
/* The timeline's own surfaces: darker and bluer than the shared scale, so they
|
|
50
|
-
* get their own names instead of snapping to the nearest --color-bg/-surface
|
|
51
|
-
* step (AD147: a host themes the timeline by overriding these). */
|
|
52
|
-
--timeline-shell-bg: #0a0a0b;
|
|
53
|
-
--timeline-shell-border: rgba(255, 255, 255, 0.05);
|
|
54
|
-
--timeline-ruler-border: rgba(255, 255, 255, 0.16);
|
|
55
|
-
--timeline-row-bg: #101014;
|
|
56
|
-
--timeline-row-border: rgba(255, 255, 255, 0.06);
|
|
57
|
-
--timeline-gutter-bg: #0e0f12;
|
|
58
|
-
--timeline-gutter-border: rgba(255, 255, 255, 0.1);
|
|
59
|
-
--timeline-text-primary: rgba(255, 255, 255, 0.92);
|
|
60
|
-
--timeline-text-secondary: rgba(255, 255, 255, 0.62);
|
|
61
|
-
--timeline-tick-text: rgba(255, 255, 255, 0.34);
|
|
62
|
-
--timeline-tick-major: rgba(255, 255, 255, 0.1);
|
|
63
|
-
--timeline-tick-minor: rgba(255, 255, 255, 0.06);
|
|
64
|
-
--timeline-clip-bg: #141922;
|
|
65
|
-
--timeline-clip-bg-active: #181e28;
|
|
66
|
-
--timeline-clip-border: rgba(255, 255, 255, 0.1);
|
|
67
|
-
--timeline-clip-border-hover: rgba(255, 255, 255, 0.18);
|
|
68
|
-
--timeline-clip-border-active: rgba(255, 255, 255, 0.24);
|
|
69
|
-
--timeline-handle: rgba(255, 255, 255, 0.2);
|
|
70
|
-
--timeline-resize-seam: rgba(255, 255, 255, 0.12);
|
|
71
|
-
--timeline-resize-active: rgba(255, 255, 255, 0.24);
|
|
72
|
-
--timeline-track-clip-fill: rgba(255, 255, 255, 0.055);
|
|
73
|
-
--timeline-track-clip-active: rgba(60, 230, 172, 0.16);
|
|
74
|
-
--timeline-track-label: rgba(255, 255, 255, 0.5);
|
|
75
|
-
|
|
76
49
|
/* -------------------------------------------------------------- geometry */
|
|
77
50
|
|
|
78
51
|
--radius-sm: 0.25rem;
|