hyperframes 0.8.53 → 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/cli.js +1 -1
- package/dist/fontLocalizeCli.js +2 -2
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/studio/assets/{hyperframes-player-DKWM-Ons.js → hyperframes-player-Cy_AwUa8.js} +1 -1
- package/dist/studio/assets/{index-UvW6BEwf.js → index-CTa-6Kso.js} +1 -1
- package/dist/studio/assets/{index-HfP3sap2.js → index-DPUJoO8n.js} +191 -191
- package/dist/studio/assets/{index-Y4OnpTEM.js → index-DkAzKuPZ.js} +1 -1
- package/dist/studio/index.d.ts +440 -10
- package/dist/studio/index.html +1 -1
- package/dist/studio/index.js +1850 -1532
- package/dist/studio/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as P}from"./index-
|
|
1
|
+
import{g as P}from"./index-DPUJoO8n.js";function j(c,d){for(var s=0;s<d.length;s++){const a=d[s];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in c)){const l=Object.getOwnPropertyDescriptor(a,i);l&&Object.defineProperty(c,i,l.get?l:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}))}var v={},w;function k(){if(w)return v;w=1,Object.defineProperty(v,"__esModule",{value:!0}),v.default=d;var c=window.OfflineAudioContext||window.webkitOfflineAudioContext;function d(e){var r=a(e);return r.start(0),[i,y,O(e.sampleRate),s].reduce(function(t,o){return o(t)},r.buffer.getChannelData(0))}function s(e){return e.sort(function(r,t){return t.count-r.count}).splice(0,5)[0].tempo}function a(e){var r=e.length,t=e.numberOfChannels,o=e.sampleRate,n=new c(t,r,o),u=n.createBufferSource();u.buffer=e;var f=n.createBiquadFilter();return f.type="lowpass",u.connect(f),f.connect(n.destination),u}function i(e){for(var r=[],t=.9,o=.3,n=15;r.length<n&&t>=o;)r=l(e,t),t-=.05;if(r.length<n)throw new Error("Could not find enough samples for a reliable detection.");return r}function l(e,r){for(var t=[],o=0,n=e.length;o<n;o+=1)e[o]>r&&(t.push(o),o+=1e4);return t}function y(e){var r=[];return e.forEach(function(t,o){for(var n=function(x){var g=e[o+x]-t,_=r.some(function(h){if(h.interval===g)return h.count+=1});_||r.push({interval:g,count:1})},u=0;u<10;u+=1)n(u)}),r}function O(e){return function(r){var t=[];return r.forEach(function(o){if(o.interval!==0){for(var n=60/(o.interval/e);n<90;)n*=2;for(;n>180;)n/=2;n=Math.round(n);var u=t.some(function(f){if(f.tempo===n)return f.count+=o.count});u||t.push({tempo:n,count:o.count})}}),t}}return v}var p,b;function q(){return b||(b=1,p=k().default),p}var m=q();const A=P(m),D=j({__proto__:null,default:A},[m]);export{D as i};
|
package/dist/studio/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ButtonHTMLAttributes, ReactNode, ElementType, ComponentPropsWithoutRef, ReactElement, RefObject } from 'react';
|
|
2
|
+
import { ButtonHTMLAttributes, ReactNode, ElementType, ComponentPropsWithoutRef, ReactElement, RefObject, MutableRefObject } from 'react';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { Tabs as Tabs$1 } from '@base-ui/react/tabs';
|
|
5
5
|
import * as node_modules_cn_dist_types from 'node_modules/cn/dist/types';
|
|
@@ -13,6 +13,7 @@ import { StoreApi } from 'zustand';
|
|
|
13
13
|
import { MusicBeatAnalysis } from '@hyperframes/core/beats';
|
|
14
14
|
import { GsapAnimation as GsapAnimation$1, ArcPathSegment } from '@hyperframes/parsers/gsap-parser';
|
|
15
15
|
import { CanvasResolution } from '@hyperframes/parsers';
|
|
16
|
+
import { Composition } from '@hyperframes/sdk';
|
|
16
17
|
|
|
17
18
|
type ButtonVariant = "primary" | "secondary" | "danger" | "ghost";
|
|
18
19
|
type ButtonSize = "sm" | "md" | "lg";
|
|
@@ -44,6 +45,8 @@ declare const buttonVariants: Record<ButtonVariant, string>;
|
|
|
44
45
|
declare const buttonSizes: Record<ButtonSize, string>;
|
|
45
46
|
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
46
47
|
|
|
48
|
+
declare function HyperframesLogo(): react_jsx_runtime.JSX.Element;
|
|
49
|
+
|
|
47
50
|
interface IconButtonProps extends ButtonBaseProps {
|
|
48
51
|
icon: ReactNode;
|
|
49
52
|
"aria-label": string;
|
|
@@ -76,6 +79,20 @@ declare function Tab({ value, className, ...props }: TabProps): react_jsx_runtim
|
|
|
76
79
|
/** The panel for one tab. Base UI wires `aria-labelledby` back to its tab. */
|
|
77
80
|
declare function TabPanel({ className, ...props }: StyledProps$1<typeof Tabs$1.Panel>): react_jsx_runtime.JSX.Element;
|
|
78
81
|
|
|
82
|
+
interface HyperframesLoaderProps {
|
|
83
|
+
/** Status text shown below the mark. */
|
|
84
|
+
title: string;
|
|
85
|
+
/** Optional secondary detail line. */
|
|
86
|
+
detail?: string;
|
|
87
|
+
/** Optional monospace third line for IDs, counts, or percentages. */
|
|
88
|
+
mono?: string;
|
|
89
|
+
/** Pixel size of the mark itself; status text scales independently. */
|
|
90
|
+
size?: number;
|
|
91
|
+
/** Optional normalized progress value from 0 to 1. */
|
|
92
|
+
progress?: number;
|
|
93
|
+
}
|
|
94
|
+
declare function HyperframesLoader({ title, detail, mono, size, progress, }: HyperframesLoaderProps): react_jsx_runtime.JSX.Element;
|
|
95
|
+
|
|
79
96
|
interface TooltipProps {
|
|
80
97
|
label: string;
|
|
81
98
|
/** A single element, wrapped in a box-less span so a disabled one still gets hover. */
|
|
@@ -88,8 +105,6 @@ interface TooltipProps {
|
|
|
88
105
|
}
|
|
89
106
|
declare function Tooltip({ label, children, delay, side }: TooltipProps): react_jsx_runtime.JSX.Element;
|
|
90
107
|
|
|
91
|
-
declare function HyperframesLogo(): react_jsx_runtime.JSX.Element;
|
|
92
|
-
|
|
93
108
|
/**
|
|
94
109
|
* Studio's tailwind-merge config: teaches it the two scales `theme.css`
|
|
95
110
|
* invents (`text-step-*`, `ctl`/`ctl-sm`/`ctl-lg`) so overrides replace, not stack.
|
|
@@ -543,11 +558,14 @@ interface PlaybackReadinessSlice {
|
|
|
543
558
|
}
|
|
544
559
|
declare function createPlaybackReadinessSlice(set: StoreApi<PlaybackReadinessSlice>["setState"]): PlaybackReadinessSlice;
|
|
545
560
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
561
|
+
interface TimelineTimeRange {
|
|
562
|
+
t0: number;
|
|
563
|
+
t1: number;
|
|
564
|
+
}
|
|
565
|
+
interface RangeSelectionSlice {
|
|
566
|
+
/** Shift-drag ruler range in seconds, normalized so t0 <= t1. */
|
|
567
|
+
rangeSelection: TimelineTimeRange | null;
|
|
568
|
+
}
|
|
551
569
|
|
|
552
570
|
/**
|
|
553
571
|
* One row in the timeline: a clip as Studio needs it, translated from the
|
|
@@ -668,12 +686,18 @@ interface SubCompositionHostState {
|
|
|
668
686
|
automation?: string;
|
|
669
687
|
}
|
|
670
688
|
|
|
689
|
+
type TimeListener = (time: number) => void;
|
|
690
|
+
declare const liveTime: {
|
|
691
|
+
notify: (time: number) => void;
|
|
692
|
+
subscribe: (listener: TimeListener) => () => boolean;
|
|
693
|
+
};
|
|
694
|
+
|
|
671
695
|
type ZoomMode = "fit" | "manual";
|
|
672
696
|
type TimelineTool = "select" | "razor";
|
|
673
697
|
interface SelectElementOptions {
|
|
674
698
|
preserveSet?: boolean;
|
|
675
699
|
}
|
|
676
|
-
type PlayerStoreSlices = KeyframeSlice & AutomationSelectionSlice & ThumbnailSlice & EditingModeSlice & ReturnType<typeof createPlaybackReadinessSlice
|
|
700
|
+
type PlayerStoreSlices = KeyframeSlice & AutomationSelectionSlice & ThumbnailSlice & EditingModeSlice & ReturnType<typeof createPlaybackReadinessSlice> & RangeSelectionSlice;
|
|
677
701
|
interface PlayerState extends PlayerStoreSlices {
|
|
678
702
|
isPlaying: boolean;
|
|
679
703
|
currentTime: number;
|
|
@@ -978,8 +1002,179 @@ declare function buildPickerAgentPrompt({ selection, userInstruction, }: {
|
|
|
978
1002
|
}): string;
|
|
979
1003
|
declare function buildPickerAgentContextPreview(selection: HyperframePickerElementInfo | null): string;
|
|
980
1004
|
|
|
1005
|
+
type EditHistoryKind = "manual" | "motion" | "timeline" | "source";
|
|
1006
|
+
interface EditHistoryFileSnapshot {
|
|
1007
|
+
before: string;
|
|
1008
|
+
after: string;
|
|
1009
|
+
beforeHash: string;
|
|
1010
|
+
afterHash: string;
|
|
1011
|
+
}
|
|
1012
|
+
interface EditHistoryEntry {
|
|
1013
|
+
id: string;
|
|
1014
|
+
projectId: string;
|
|
1015
|
+
label: string;
|
|
1016
|
+
kind: EditHistoryKind;
|
|
1017
|
+
coalesceKey?: string;
|
|
1018
|
+
/** Per-entry coalesce window override (ms). Falls back to the reducer default. */
|
|
1019
|
+
coalesceMs?: number;
|
|
1020
|
+
createdAt: number;
|
|
1021
|
+
files: Record<string, EditHistoryFileSnapshot>;
|
|
1022
|
+
}
|
|
1023
|
+
interface EditHistoryState {
|
|
1024
|
+
version: 1;
|
|
1025
|
+
updatedAt: number;
|
|
1026
|
+
undo: EditHistoryEntry[];
|
|
1027
|
+
redo: EditHistoryEntry[];
|
|
1028
|
+
}
|
|
1029
|
+
interface BuildEditHistoryEntryInput {
|
|
1030
|
+
id: string;
|
|
1031
|
+
projectId: string;
|
|
1032
|
+
label: string;
|
|
1033
|
+
kind?: EditHistoryKind;
|
|
1034
|
+
coalesceKey?: string;
|
|
1035
|
+
coalesceMs?: number;
|
|
1036
|
+
now: number;
|
|
1037
|
+
files: Record<string, {
|
|
1038
|
+
before: string;
|
|
1039
|
+
after: string;
|
|
1040
|
+
}>;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
interface SdkSessionPublication {
|
|
1044
|
+
candidate: Composition;
|
|
1045
|
+
expectedSession: Composition;
|
|
1046
|
+
targetPath: string;
|
|
1047
|
+
}
|
|
1048
|
+
type SdkSessionPublicationResult = "published" | "rejected-active-target" | "rejected-inactive-target";
|
|
1049
|
+
type PublishSdkSession = (publication: SdkSessionPublication) => SdkSessionPublicationResult;
|
|
1050
|
+
|
|
1051
|
+
type TimelineLayerDropPlacement = {
|
|
1052
|
+
type: "onto";
|
|
1053
|
+
layerId: string;
|
|
1054
|
+
} | {
|
|
1055
|
+
type: "between";
|
|
1056
|
+
beforeLayerId: string;
|
|
1057
|
+
afterLayerId: string;
|
|
1058
|
+
} | {
|
|
1059
|
+
type: "above";
|
|
1060
|
+
layerId: string;
|
|
1061
|
+
} | {
|
|
1062
|
+
type: "below";
|
|
1063
|
+
layerId: string;
|
|
1064
|
+
};
|
|
1065
|
+
interface TimelineStackingZIndexChange {
|
|
1066
|
+
key: string;
|
|
1067
|
+
zIndex: number;
|
|
1068
|
+
domId?: string;
|
|
1069
|
+
selector?: string;
|
|
1070
|
+
selectorIndex?: number;
|
|
1071
|
+
sourceFile?: string;
|
|
1072
|
+
}
|
|
1073
|
+
interface TimelineStackingReorderIntent {
|
|
1074
|
+
contextKey: string;
|
|
1075
|
+
placement: TimelineLayerDropPlacement;
|
|
1076
|
+
zIndexChanges: TimelineStackingZIndexChange[];
|
|
1077
|
+
}
|
|
1078
|
+
|
|
981
1079
|
type BlockedTimelineEditIntent = "move" | "resize-start" | "resize-end";
|
|
982
1080
|
|
|
1081
|
+
/**
|
|
1082
|
+
* Durability report for a patch-batches commit. `durable === false` means the
|
|
1083
|
+
* server could not locate at least one patch target on disk — the preview was
|
|
1084
|
+
* reloaded to reconverge, and dependent follow-up writes (the z→lane timeline
|
|
1085
|
+
* mirror) must be skipped. `allMatched` retains the underlying match detail.
|
|
1086
|
+
* `changed === false` means no source file was written: every patch was a
|
|
1087
|
+
* byte-identical no-op, or the atomic gesture was refused before any write.
|
|
1088
|
+
*/
|
|
1089
|
+
interface DomEditPatchBatchesResult {
|
|
1090
|
+
durable: boolean;
|
|
1091
|
+
allMatched: boolean;
|
|
1092
|
+
changed: boolean;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/** A host's verdict on one element: editable, or blocked with a reason to show. */
|
|
1096
|
+
type TimelineEditPermission = true | {
|
|
1097
|
+
blocked: true;
|
|
1098
|
+
reason: string;
|
|
1099
|
+
};
|
|
1100
|
+
type CanEditTimelineElement = (element: TimelineElement) => TimelineEditPermission;
|
|
1101
|
+
|
|
1102
|
+
interface RecordEditInput$1 {
|
|
1103
|
+
label: string;
|
|
1104
|
+
kind: EditHistoryKind;
|
|
1105
|
+
coalesceKey?: string;
|
|
1106
|
+
files: Record<string, {
|
|
1107
|
+
before: string;
|
|
1108
|
+
after: string;
|
|
1109
|
+
}>;
|
|
1110
|
+
}
|
|
1111
|
+
type TimelineZIndexReorderCommit = (entries: Array<{
|
|
1112
|
+
element: HTMLElement;
|
|
1113
|
+
zIndex: number;
|
|
1114
|
+
id?: string;
|
|
1115
|
+
selector?: string;
|
|
1116
|
+
selectorIndex?: number;
|
|
1117
|
+
sourceFile: string;
|
|
1118
|
+
key?: string;
|
|
1119
|
+
}>, coalesceKey?: string) => Promise<DomEditPatchBatchesResult | undefined | void>;
|
|
1120
|
+
interface UseTimelineEditingOptions {
|
|
1121
|
+
projectId: string | null;
|
|
1122
|
+
activeCompPath: string | null;
|
|
1123
|
+
timelineElements: TimelineElement[];
|
|
1124
|
+
showToast: (message: string, tone?: "error" | "info") => void;
|
|
1125
|
+
writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
|
|
1126
|
+
observeProjectFileVersion?: (path: string, version: string | null) => void;
|
|
1127
|
+
recordEdit: (input: RecordEditInput$1) => Promise<void>;
|
|
1128
|
+
reloadPreview: () => void;
|
|
1129
|
+
previewIframeRef: RefObject<HTMLIFrameElement | null>;
|
|
1130
|
+
pendingTimelineEditPathRef: MutableRefObject<Set<string>>;
|
|
1131
|
+
uploadProjectFiles: (files: Iterable<File>, dir?: string) => Promise<string[]>;
|
|
1132
|
+
isRecordingRef?: RefObject<boolean>;
|
|
1133
|
+
/** Stage 7 §3.2: SDK session for routing timing ops through setTiming. */
|
|
1134
|
+
sdkSession?: Composition | null;
|
|
1135
|
+
/** Publish a fully persisted candidate SDK session. */
|
|
1136
|
+
publishSdkSession?: PublishSdkSession;
|
|
1137
|
+
/** Resync the SDK session after a server-authoritative timeline write. */
|
|
1138
|
+
forceReloadSdkSession?: () => void;
|
|
1139
|
+
/** Reparse authored animations after a timing rewrite changes their positions. */
|
|
1140
|
+
invalidateGsapCache?: () => void;
|
|
1141
|
+
handleDomZIndexReorderCommitRef?: MutableRefObject<TimelineZIndexReorderCommit | null>;
|
|
1142
|
+
/** Refuses a hand edit at the persist boundary when set; absent = Studio unchanged. */
|
|
1143
|
+
canEdit?: CanEditTimelineElement;
|
|
1144
|
+
}
|
|
1145
|
+
/** What a timeline move commits: the new start and track, plus the z-index
|
|
1146
|
+
* reorder a vertical drag resolves to (absent for a pure horizontal move). */
|
|
1147
|
+
type TimelineMoveUpdates = Pick<TimelineElement, "start" | "track"> & {
|
|
1148
|
+
stackingReorder?: TimelineStackingReorderIntent | null;
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1151
|
+
interface TimelineGroupMoveChange {
|
|
1152
|
+
element: TimelineElement;
|
|
1153
|
+
start: number;
|
|
1154
|
+
track?: number;
|
|
1155
|
+
}
|
|
1156
|
+
interface TimelineGroupResizeChange {
|
|
1157
|
+
element: TimelineElement;
|
|
1158
|
+
start: number;
|
|
1159
|
+
duration: number;
|
|
1160
|
+
playbackStart?: number;
|
|
1161
|
+
}
|
|
1162
|
+
interface TimelineGroupCommitOptions {
|
|
1163
|
+
beforeTiming?: Promise<void>;
|
|
1164
|
+
coalesceKey?: string;
|
|
1165
|
+
/** Per-entry undo coalesce window override (ms) — see EditHistoryEntry.coalesceMs. */
|
|
1166
|
+
coalesceMs?: number;
|
|
1167
|
+
/** Overrides the default "Move timeline clips" undo-history label. Coalescing
|
|
1168
|
+
* keeps the LAST entry's label (editHistory.ts), so a mechanical follow-up
|
|
1169
|
+
* move folded into another gesture's coalesceKey (e.g. the ripple after a
|
|
1170
|
+
* delete) should carry that gesture's own label, not its own. */
|
|
1171
|
+
label?: string;
|
|
1172
|
+
/** Skips this call's own generic failure toast (the error is still logged
|
|
1173
|
+
* to the console) — for a caller that shows its own more specific message
|
|
1174
|
+
* on the same failure, so the user isn't told about one action twice. */
|
|
1175
|
+
suppressFailureToast?: boolean;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
983
1178
|
type TimelineMoveOperation = "timing" | "lane-reorder" | "track-insert";
|
|
984
1179
|
|
|
985
1180
|
interface TimelineKeyframeTarget {
|
|
@@ -1130,6 +1325,8 @@ interface TimelineProps extends TimelineDropCallbacks, TimelineEditOverrides {
|
|
|
1130
1325
|
renderClipOverlay?: (element: TimelineElement) => ReactNode;
|
|
1131
1326
|
onDeleteElement?: (element: TimelineElement) => Promise<void> | void;
|
|
1132
1327
|
onSelectElement?: (element: TimelineElement | null) => void;
|
|
1328
|
+
/** Notification only; null when cleared. The value lives in usePlayerStore.rangeSelection. */
|
|
1329
|
+
onRangeSelect?: (range: TimelineTimeRange | null) => void;
|
|
1133
1330
|
onCopyClip?: () => boolean;
|
|
1134
1331
|
onPasteClip?: () => Promise<void>;
|
|
1135
1332
|
onDuplicateClip?: () => Promise<boolean>;
|
|
@@ -1749,4 +1946,237 @@ declare function findElementBlock(html: string, elementId: string): {
|
|
|
1749
1946
|
isSelfClosing: boolean;
|
|
1750
1947
|
} | null;
|
|
1751
1948
|
|
|
1752
|
-
|
|
1949
|
+
interface EditHistoryStorageAdapter {
|
|
1950
|
+
get(projectId: string): Promise<EditHistoryState | null>;
|
|
1951
|
+
set(projectId: string, state: EditHistoryState): Promise<void>;
|
|
1952
|
+
delete(projectId: string): Promise<void>;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
interface RecordEditInput {
|
|
1956
|
+
label: string;
|
|
1957
|
+
kind: EditHistoryKind;
|
|
1958
|
+
coalesceKey?: string;
|
|
1959
|
+
coalesceMs?: number;
|
|
1960
|
+
files: BuildEditHistoryEntryInput["files"];
|
|
1961
|
+
}
|
|
1962
|
+
interface ApplyCallbacks {
|
|
1963
|
+
readFile: (path: string) => Promise<string>;
|
|
1964
|
+
writeFile: (path: string, content: string) => Promise<void>;
|
|
1965
|
+
serialize?: <T>(paths: readonly string[], task: () => Promise<T>) => Promise<T>;
|
|
1966
|
+
}
|
|
1967
|
+
interface UsePersistentEditHistoryOptions {
|
|
1968
|
+
projectId: string | null;
|
|
1969
|
+
storage?: EditHistoryStorageAdapter;
|
|
1970
|
+
now?: () => number;
|
|
1971
|
+
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Per-file content the restore just applied. `restored` is the bytes written to
|
|
1974
|
+
* disk (the undo/redo target); `previous` is what was on disk immediately before
|
|
1975
|
+
* (the current live preview state). The undo preview-sync diffs these to decide
|
|
1976
|
+
* whether the restore is soft-reloadable (attributes/style/GSAP-script only) or
|
|
1977
|
+
* needs a full iframe reload.
|
|
1978
|
+
*/
|
|
1979
|
+
interface ApplyRestoredFile {
|
|
1980
|
+
previous: string;
|
|
1981
|
+
restored: string;
|
|
1982
|
+
}
|
|
1983
|
+
interface ApplyResult {
|
|
1984
|
+
ok: boolean;
|
|
1985
|
+
reason?: "empty" | "content-mismatch";
|
|
1986
|
+
label?: string;
|
|
1987
|
+
paths?: string[];
|
|
1988
|
+
files?: Record<string, ApplyRestoredFile>;
|
|
1989
|
+
}
|
|
1990
|
+
declare function usePersistentEditHistory(options: UsePersistentEditHistoryOptions): {
|
|
1991
|
+
recordEdit: (input: RecordEditInput) => Promise<void>;
|
|
1992
|
+
undo: (callbacks: ApplyCallbacks) => Promise<ApplyResult>;
|
|
1993
|
+
redo: (callbacks: ApplyCallbacks) => Promise<ApplyResult>;
|
|
1994
|
+
canUndo: boolean;
|
|
1995
|
+
canRedo: boolean;
|
|
1996
|
+
undoLabel: string;
|
|
1997
|
+
redoLabel: string;
|
|
1998
|
+
undoPaths: string[];
|
|
1999
|
+
redoPaths: string[];
|
|
2000
|
+
state: EditHistoryState;
|
|
2001
|
+
loaded: boolean;
|
|
2002
|
+
};
|
|
2003
|
+
|
|
2004
|
+
declare function useTimelineEditing({ projectId, activeCompPath, timelineElements, showToast, writeProjectFile, observeProjectFileVersion, recordEdit, reloadPreview, previewIframeRef, pendingTimelineEditPathRef, uploadProjectFiles, isRecordingRef, sdkSession, publishSdkSession, forceReloadSdkSession, invalidateGsapCache, handleDomZIndexReorderCommitRef, canEdit, }: UseTimelineEditingOptions): {
|
|
2005
|
+
handleTimelineElementMove: (element: TimelineElement, updates: TimelineMoveUpdates) => Promise<void>;
|
|
2006
|
+
handleTimelineElementResize: (element: TimelineElement, updates: Pick<TimelineElement, "start" | "duration" | "playbackStart">) => Promise<void>;
|
|
2007
|
+
handleToggleTrackHidden: (track: number, hidden: boolean, displayNumber?: number | null | undefined) => Promise<void>;
|
|
2008
|
+
handleToggleElementHidden: (elementKey: string | readonly string[], hidden: boolean) => Promise<void>;
|
|
2009
|
+
handleAutoGroupCarveSources: (clipIds: readonly string[], groupId: string, groupLabel?: string | undefined) => Promise<void>;
|
|
2010
|
+
setAudioGroupAttribute: {
|
|
2011
|
+
setQuiet: (groupId: string, attr: string, value: string | null, label: string) => Promise<void>;
|
|
2012
|
+
setLive: (groupId: string, attr: string, value: string | null) => void;
|
|
2013
|
+
};
|
|
2014
|
+
setElementFxAttribute: {
|
|
2015
|
+
setQuiet: (element: TimelineElement, attr: string, value: string | null, label: string) => Promise<void>;
|
|
2016
|
+
setLive: (element: TimelineElement, attr: string, value: string | null) => void;
|
|
2017
|
+
};
|
|
2018
|
+
handleTimelineElementDelete: (element: TimelineElement) => Promise<void>;
|
|
2019
|
+
handleTimelineElementsDelete: (selection: TimelineElement[]) => Promise<void>;
|
|
2020
|
+
handleTimelineElementSplit: (element: TimelineElement, splitTime: number) => Promise<void>;
|
|
2021
|
+
handleRazorSplit: (element: TimelineElement, splitTime: number) => Promise<void>;
|
|
2022
|
+
handleRazorSplitAll: (splitTime: number) => Promise<void>;
|
|
2023
|
+
handleTimelineAssetDrop: (assetPath: string, placement: TimelineDropPlacement, durationOverride?: number | undefined) => Promise<void>;
|
|
2024
|
+
handleTimelineFileDrop: (files: File[], placement?: TimelineDropPlacement | undefined) => Promise<void>;
|
|
2025
|
+
handleTimelineCompositionDrop: (sourcePath: string, placement: Pick<TimelineElement, "track" | "start">) => Promise<void>;
|
|
2026
|
+
handleBlockedTimelineEdit: (element: TimelineElement) => void;
|
|
2027
|
+
handleTimelineGroupMove: (changes: TimelineGroupMoveChange[], options?: TimelineGroupCommitOptions | undefined) => Promise<void>;
|
|
2028
|
+
handleTimelineGroupResize: (changes: TimelineGroupResizeChange[], options?: TimelineGroupCommitOptions | undefined) => Promise<void>;
|
|
2029
|
+
};
|
|
2030
|
+
|
|
2031
|
+
declare class StudioSaveHttpError extends Error {
|
|
2032
|
+
readonly statusCode: number;
|
|
2033
|
+
readonly alreadyToasted: boolean;
|
|
2034
|
+
constructor(message: string, statusCode: number, options?: {
|
|
2035
|
+
alreadyToasted?: boolean;
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
declare class StudioFileConflictError extends StudioSaveHttpError {
|
|
2039
|
+
readonly filePath: string;
|
|
2040
|
+
readonly currentVersion: string | null;
|
|
2041
|
+
readonly currentContent: string | null;
|
|
2042
|
+
readonly attemptedContent: string;
|
|
2043
|
+
constructor(input: {
|
|
2044
|
+
filePath: string;
|
|
2045
|
+
currentVersion: string | null;
|
|
2046
|
+
currentContent: string | null;
|
|
2047
|
+
attemptedContent: string;
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
type StudioSaveDrainResult<Failure = unknown> = {
|
|
2051
|
+
status: "clean";
|
|
2052
|
+
} | {
|
|
2053
|
+
status: "conflict";
|
|
2054
|
+
error: StudioFileConflictError;
|
|
2055
|
+
} | {
|
|
2056
|
+
status: "failed";
|
|
2057
|
+
error: Failure;
|
|
2058
|
+
};
|
|
2059
|
+
|
|
2060
|
+
type StudioPendingEditsDrainResult = StudioSaveDrainResult;
|
|
2061
|
+
declare function flushStudioPendingEdits(): Promise<StudioPendingEditsDrainResult>;
|
|
2062
|
+
|
|
2063
|
+
interface HistoryResult {
|
|
2064
|
+
ok: boolean;
|
|
2065
|
+
reason?: string;
|
|
2066
|
+
label?: string;
|
|
2067
|
+
paths?: string[];
|
|
2068
|
+
/** Per-file restored/previous content, used to soft-apply the preview. */
|
|
2069
|
+
files?: Record<string, {
|
|
2070
|
+
previous: string;
|
|
2071
|
+
restored: string;
|
|
2072
|
+
}>;
|
|
2073
|
+
}
|
|
2074
|
+
interface HistoryFileCallbacks {
|
|
2075
|
+
readFile: (path: string) => Promise<string>;
|
|
2076
|
+
writeFile: (path: string, content: string) => Promise<void>;
|
|
2077
|
+
serialize?: <T>(paths: readonly string[], task: () => Promise<T>) => Promise<T>;
|
|
2078
|
+
}
|
|
2079
|
+
interface EditHistoryHandle {
|
|
2080
|
+
undo: (cb: HistoryFileCallbacks) => Promise<HistoryResult>;
|
|
2081
|
+
redo: (cb: HistoryFileCallbacks) => Promise<HistoryResult>;
|
|
2082
|
+
state: {
|
|
2083
|
+
undo: ReadonlyArray<{
|
|
2084
|
+
createdAt: number;
|
|
2085
|
+
}>;
|
|
2086
|
+
redo: ReadonlyArray<{
|
|
2087
|
+
createdAt: number;
|
|
2088
|
+
}>;
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
interface UseEditHistoryActionsOptions {
|
|
2092
|
+
editHistory: Pick<EditHistoryHandle, "undo" | "redo">;
|
|
2093
|
+
readOptionalProjectFile: (path: string) => Promise<string>;
|
|
2094
|
+
readProjectFile: (path: string) => Promise<string>;
|
|
2095
|
+
writeProjectFile: (path: string, content: string) => Promise<void>;
|
|
2096
|
+
showToast: (message: string, tone?: "error" | "info") => void;
|
|
2097
|
+
syncHistoryPreviewAfterApply: (restore: Pick<HistoryResult, "paths" | "files">) => Promise<void>;
|
|
2098
|
+
waitForPendingDomEditSaves: () => Promise<void>;
|
|
2099
|
+
onAfterUndoRedo?: () => void;
|
|
2100
|
+
/** Active composition path — decides whether undo/redo must resync the SDK session. */
|
|
2101
|
+
activeCompPath?: string | null;
|
|
2102
|
+
/** Reloads the SDK session after a revert of the active comp, past the self-write suppress window. */
|
|
2103
|
+
forceReloadSdkSession?: () => void;
|
|
2104
|
+
}
|
|
2105
|
+
/** Applies one persisted file-history step: the single owner of undo/redo over project files. */
|
|
2106
|
+
declare function useEditHistoryActions({ editHistory, readOptionalProjectFile, readProjectFile, writeProjectFile, showToast, syncHistoryPreviewAfterApply, waitForPendingDomEditSaves, onAfterUndoRedo, activeCompPath, forceReloadSdkSession, }: UseEditHistoryActionsOptions): {
|
|
2107
|
+
undo: () => Promise<void>;
|
|
2108
|
+
redo: () => Promise<void>;
|
|
2109
|
+
};
|
|
2110
|
+
|
|
2111
|
+
interface UseProjectFileWriterOptions {
|
|
2112
|
+
projectId: string | null;
|
|
2113
|
+
}
|
|
2114
|
+
declare function useProjectFileWriter({ projectId }: UseProjectFileWriterOptions): {
|
|
2115
|
+
fileVersions: Map<string, string | null>;
|
|
2116
|
+
readProjectFile: (path: string) => Promise<string>;
|
|
2117
|
+
writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>;
|
|
2118
|
+
readOptionalProjectFile: (path: string) => Promise<string>;
|
|
2119
|
+
observeProjectFileVersion: (path: string, version: string | null) => void;
|
|
2120
|
+
};
|
|
2121
|
+
|
|
2122
|
+
type ExternalFileChangeBlockedState = {
|
|
2123
|
+
status: "conflict";
|
|
2124
|
+
generation: number;
|
|
2125
|
+
error: StudioFileConflictError;
|
|
2126
|
+
payload: unknown;
|
|
2127
|
+
} | {
|
|
2128
|
+
status: "failed";
|
|
2129
|
+
generation: number;
|
|
2130
|
+
path: string;
|
|
2131
|
+
error: unknown;
|
|
2132
|
+
payload: unknown;
|
|
2133
|
+
studioContent: string | null;
|
|
2134
|
+
recovered: boolean;
|
|
2135
|
+
};
|
|
2136
|
+
interface ExternalFileChangeCoordinatorHandle {
|
|
2137
|
+
blocked: ExternalFileChangeBlockedState | null;
|
|
2138
|
+
retry: () => Promise<void>;
|
|
2139
|
+
useExternalFile: () => Promise<void>;
|
|
2140
|
+
keepStudioFile: () => Promise<void>;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
declare function ExternalFileConflictBanner({ coordinator, }: {
|
|
2144
|
+
coordinator: ExternalFileChangeCoordinatorHandle;
|
|
2145
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
2146
|
+
|
|
2147
|
+
interface TimelinePaneProps {
|
|
2148
|
+
/** Slot rendered above the timeline tracks (toolbar with split, delete, zoom) */
|
|
2149
|
+
timelineToolbar?: ReactNode;
|
|
2150
|
+
/** Slot rendered below the timeline tracks */
|
|
2151
|
+
timelineFooter?: ReactNode;
|
|
2152
|
+
/** Slot for a host's own overlay spanning the whole timeline area (e.g. a draft/ghost
|
|
2153
|
+
* clip), positioned absolutely the same way PreviewPane's previewOverlay is. */
|
|
2154
|
+
timelineOverlay?: ReactNode;
|
|
2155
|
+
/** Custom clip content renderer for timeline (thumbnails, waveforms, etc.) */
|
|
2156
|
+
renderClipContent?: (element: TimelineElement, style: {
|
|
2157
|
+
clip: string;
|
|
2158
|
+
label: string;
|
|
2159
|
+
}) => ReactNode;
|
|
2160
|
+
onFileDrop?: (files: File[], placement?: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
|
|
2161
|
+
onDeleteElement?: (element: TimelineElement) => Promise<void> | void;
|
|
2162
|
+
onAssetDrop?: (assetPath: string, placement: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
|
|
2163
|
+
onBlockDrop?: (blockName: string, placement: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
|
|
2164
|
+
onCompositionDrop?: (sourcePath: string, placement: Pick<TimelineElement, "start" | "track">) => Promise<void> | void;
|
|
2165
|
+
onBlockedEditAttempt?: (element: TimelineElement, intent: BlockedTimelineEditIntent) => void;
|
|
2166
|
+
onSelectTimelineElement?: (element: TimelineElement | null) => void;
|
|
2167
|
+
onRangeSelect?: (range: TimelineTimeRange | null) => void;
|
|
2168
|
+
/** Copy/paste/duplicate act on the store's own selection, not a passed
|
|
2169
|
+
* element, so unlike onDeleteElement they need no composition-basis wrapper. */
|
|
2170
|
+
onCopyClip?: () => boolean;
|
|
2171
|
+
onPasteClip?: () => Promise<void>;
|
|
2172
|
+
onDuplicateClip?: () => Promise<boolean>;
|
|
2173
|
+
canPasteClip?: () => boolean;
|
|
2174
|
+
}
|
|
2175
|
+
declare function TimelinePane({ timelineToolbar, timelineFooter, timelineOverlay, renderClipContent, onFileDrop, onDeleteElement, onAssetDrop, onBlockDrop, onCompositionDrop, onBlockedEditAttempt, onSelectTimelineElement, onRangeSelect, onCopyClip, onPasteClip, onDuplicateClip, canPasteClip, }: TimelinePaneProps): react_jsx_runtime.JSX.Element;
|
|
2176
|
+
|
|
2177
|
+
declare function TimelineEditProvider({ value, children, }: {
|
|
2178
|
+
value: TimelineEditCallbacks;
|
|
2179
|
+
children: ReactNode;
|
|
2180
|
+
}): react_jsx_runtime.JSX.Element;
|
|
2181
|
+
|
|
2182
|
+
export { type AgentModalAnchorPoint, type AgentPromptElementInfo, AskAgentModal, type AskAgentModalProps, type BlockedTimelineEditIntent, Button, type ButtonSize, type ButtonVariant, type CanEditTimelineElement, CompositionBreadcrumb, type CompositionDimensions, type CompositionLevel, CompositionThumbnail, ContextMenu, type EditHistoryHandle, EditorShell, type EditorShellProps, type ExternalFileChangeBlockedState, type ExternalFileChangeCoordinatorHandle, ExternalFileConflictBanner, type FfmpegStatus, FileTree, HyperframesLoader, type HyperframesLoaderProps, HyperframesLogo, IconButton, Input, type InputProps, Menu, MenuItem, type MenuItemTone, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, NLEPreview, NumberField, type NumberFieldProps, type PatchOperation, type PersistedRenderSettings, type PickedElement, Player, PlayerControls, Popover, type PopupPreviewState, type DomEditCompositionRect as PreviewCompositionRect, type PreviewState, PropertyPanel, type RenderJob, RenderQueue, type RenderQueueProps, type ResolutionPreset, Select, type SelectOption, type SelectProps, Slider, type SliderProps, SourceEditor, type StartRenderOptions, StudioApp, StudioFileConflictError, type StudioPendingEditsDrainResult, Tab, TabPanel, Tabs, TabsList, Timeline, type TimelineEditCallbacks, type TimelineEditPermission, TimelineEditProvider, type TimelineElement, TimelinePane, type TimelinePaneProps, type TimelineTimeRange, Toggle, type ToggleProps, Tooltip, type UseEditHistoryActionsOptions, type UsePersistentEditHistoryOptions, type UseProjectFileWriterOptions, type UseTimelineEditingOptions, VideoThumbnail, applyPatch, buildPickerAgentContextPreview, buildPickerAgentPrompt, buttonBase, buttonSizes, buttonVariants, cn, fieldBase, fieldText, findElementBlock, flushStudioPendingEdits, formatTime, getPersistedRenderSettings, liveTime, mergeStyleIntoTag, parseStyleString, persistRenderSettings, popupSurface, resolveIframe, resolveSourceFile, useEditHistoryActions, useElementPicker, usePersistentEditHistory, usePlayerStore, usePreviewCompositionRect, useProjectFileWriter, useRenderQueue, useTimelineEditing, useTimelinePlayer };
|
package/dist/studio/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
7
|
<title>HyperFrames Studio</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DPUJoO8n.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-DrHQAuGO.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|