@hyperframes/studio 0.6.0 → 0.6.2
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-CzwFysqv.js +418 -0
- package/dist/assets/index-hYc4aP7M.js +117 -0
- package/dist/index.html +1 -1
- package/package.json +4 -4
- package/src/App.tsx +2 -13
- package/src/captions/components/CaptionOverlay.tsx +13 -246
- package/src/captions/components/CaptionOverlayUtils.ts +221 -0
- package/src/components/StudioPreviewArea.tsx +6 -2
- package/src/components/editor/DomEditOverlay.tsx +88 -1007
- package/src/components/editor/EaseCurveEditor.tsx +221 -0
- package/src/components/editor/FileTree.tsx +13 -621
- package/src/components/editor/FileTreeIcons.tsx +128 -0
- package/src/components/editor/FileTreeNodes.tsx +496 -0
- package/src/components/editor/MotionPanel.tsx +16 -390
- package/src/components/editor/MotionPanelFields.tsx +185 -0
- package/src/components/editor/domEditOverlayGeometry.ts +211 -0
- package/src/components/editor/domEditOverlayGestures.ts +138 -0
- package/src/components/editor/domEditOverlayStartGesture.ts +155 -0
- package/src/components/editor/domEditing.ts +44 -1150
- package/src/components/editor/domEditingAgentPrompt.ts +97 -0
- package/src/components/editor/domEditingDom.ts +266 -0
- package/src/components/editor/domEditingElement.ts +329 -0
- package/src/components/editor/domEditingLayers.ts +460 -0
- package/src/components/editor/domEditingTypes.ts +125 -0
- package/src/components/editor/manualEdits.ts +84 -1081
- package/src/components/editor/manualEditsDom.ts +436 -0
- package/src/components/editor/manualEditsParsing.ts +280 -0
- package/src/components/editor/manualEditsSnapshot.ts +333 -0
- package/src/components/editor/manualEditsTypes.ts +141 -0
- package/src/components/editor/studioMotion.ts +47 -434
- package/src/components/editor/studioMotionOps.ts +299 -0
- package/src/components/editor/studioMotionTypes.ts +168 -0
- package/src/components/editor/useDomEditOverlayGestures.ts +393 -0
- package/src/components/editor/useDomEditOverlayRects.ts +207 -0
- package/src/components/nle/NLELayout.tsx +60 -144
- package/src/components/nle/useCompositionStack.ts +126 -0
- package/src/hooks/useToast.ts +20 -0
- package/src/player/components/Timeline.tsx +189 -1418
- package/src/player/components/TimelineCanvas.tsx +434 -0
- package/src/player/components/TimelineEmptyState.tsx +102 -0
- package/src/player/components/TimelineRuler.tsx +90 -0
- package/src/player/components/timelineIcons.tsx +49 -0
- package/src/player/components/timelineLayout.ts +215 -0
- package/src/player/components/timelineUtils.ts +211 -0
- package/src/player/components/useTimelineClipDrag.ts +388 -0
- package/src/player/components/useTimelinePlayhead.ts +200 -0
- package/src/player/components/useTimelineRangeSelection.ts +135 -0
- package/src/player/hooks/usePlaybackKeyboard.ts +171 -0
- package/src/player/hooks/useTimelinePlayer.ts +69 -1372
- package/src/player/hooks/useTimelineSyncCallbacks.ts +288 -0
- package/src/player/lib/playbackAdapter.ts +145 -0
- package/src/player/lib/playbackShortcuts.ts +68 -0
- package/src/player/lib/playbackTypes.ts +60 -0
- package/src/player/lib/timelineDOM.ts +373 -0
- package/src/player/lib/timelineElementHelpers.ts +303 -0
- package/src/player/lib/timelineIframeHelpers.ts +269 -0
- package/dist/assets/hyperframes-player-DOFETgjy.js +0 -418
- package/dist/assets/index-DUqUmaoH.js +0 -117
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
// ── Manifest parse, serialize, and CRUD operations ──
|
|
2
|
+
|
|
3
|
+
import type { DomEditSelection } from "./domEditing";
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_CUSTOM_EASE_POINTS,
|
|
6
|
+
GSAP_EASE_CONTROL_POINTS,
|
|
7
|
+
CUSTOM_EASE_DATA_PATTERN,
|
|
8
|
+
type StudioCustomEaseControlPoints,
|
|
9
|
+
type StudioGsapCustomEase,
|
|
10
|
+
type StudioGsapMotion,
|
|
11
|
+
type StudioGsapMotionPreset,
|
|
12
|
+
type StudioGsapPresetMotionOptions,
|
|
13
|
+
type StudioMotionManifest,
|
|
14
|
+
type StudioMotionTarget,
|
|
15
|
+
} from "./studioMotionTypes";
|
|
16
|
+
|
|
17
|
+
// ── Private helpers ──
|
|
18
|
+
|
|
19
|
+
function clampPositiveNumber(value: number, fallback: number): number {
|
|
20
|
+
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function clampNonNegativeNumber(value: number, fallback: number): number {
|
|
24
|
+
return Number.isFinite(value) && value >= 0 ? value : fallback;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function sanitizeEase(value: string): string {
|
|
28
|
+
return value.trim() || "none";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function roundEaseNumber(value: number): number {
|
|
32
|
+
return Math.round(value * 1000) / 1000;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function clampRange(value: number, min: number, max: number, fallback: number): number {
|
|
36
|
+
return Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : fallback;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function formatEaseNumber(value: number): string {
|
|
40
|
+
const rounded = roundEaseNumber(value);
|
|
41
|
+
if (Object.is(rounded, -0)) return "0";
|
|
42
|
+
return `${rounded}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function finiteNumber(value: unknown): number | null {
|
|
46
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Custom ease points ──
|
|
50
|
+
|
|
51
|
+
export function clampStudioCustomEasePoints(
|
|
52
|
+
points: Partial<StudioCustomEaseControlPoints>,
|
|
53
|
+
): StudioCustomEaseControlPoints {
|
|
54
|
+
return {
|
|
55
|
+
x1: roundEaseNumber(clampRange(points.x1 ?? DEFAULT_CUSTOM_EASE_POINTS.x1, 0, 1, 0.215)),
|
|
56
|
+
y1: roundEaseNumber(clampRange(points.y1 ?? DEFAULT_CUSTOM_EASE_POINTS.y1, -0.6, 1.6, 0.61)),
|
|
57
|
+
x2: roundEaseNumber(clampRange(points.x2 ?? DEFAULT_CUSTOM_EASE_POINTS.x2, 0, 1, 0.355)),
|
|
58
|
+
y2: roundEaseNumber(clampRange(points.y2 ?? DEFAULT_CUSTOM_EASE_POINTS.y2, -0.6, 1.6, 1)),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function parseStudioCustomEaseData(
|
|
63
|
+
data: string | undefined,
|
|
64
|
+
): StudioCustomEaseControlPoints | null {
|
|
65
|
+
if (!data) return null;
|
|
66
|
+
const match = data.trim().match(CUSTOM_EASE_DATA_PATTERN);
|
|
67
|
+
if (!match) return null;
|
|
68
|
+
const points = {
|
|
69
|
+
x1: Number.parseFloat(match[1] ?? ""),
|
|
70
|
+
y1: Number.parseFloat(match[2] ?? ""),
|
|
71
|
+
x2: Number.parseFloat(match[3] ?? ""),
|
|
72
|
+
y2: Number.parseFloat(match[4] ?? ""),
|
|
73
|
+
};
|
|
74
|
+
if (!Object.values(points).every(Number.isFinite)) return null;
|
|
75
|
+
return clampStudioCustomEasePoints(points);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function serializeStudioCustomEaseData(points: StudioCustomEaseControlPoints): string {
|
|
79
|
+
const clamped = clampStudioCustomEasePoints(points);
|
|
80
|
+
return `M0,0 C${formatEaseNumber(clamped.x1)},${formatEaseNumber(clamped.y1)} ${formatEaseNumber(clamped.x2)},${formatEaseNumber(clamped.y2)} 1,1`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function controlPointsForGsapEase(ease: string): StudioCustomEaseControlPoints {
|
|
84
|
+
return GSAP_EASE_CONTROL_POINTS[ease] ?? DEFAULT_CUSTOM_EASE_POINTS;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── Preset motion builder ──
|
|
88
|
+
|
|
89
|
+
export function buildStudioGsapPresetMotion(
|
|
90
|
+
preset: StudioGsapMotionPreset,
|
|
91
|
+
options: StudioGsapPresetMotionOptions,
|
|
92
|
+
): Omit<StudioGsapMotion, "kind" | "target" | "updatedAt"> {
|
|
93
|
+
const start = clampNonNegativeNumber(options.start, 0);
|
|
94
|
+
const duration = clampPositiveNumber(options.duration, 0.6);
|
|
95
|
+
const distance = clampPositiveNumber(options.distance, 32);
|
|
96
|
+
const ease = sanitizeEase(options.ease);
|
|
97
|
+
const direction = options.direction ?? "up";
|
|
98
|
+
const base = { start, duration, ease, customEase: options.customEase };
|
|
99
|
+
|
|
100
|
+
if (preset === "pop") {
|
|
101
|
+
return {
|
|
102
|
+
...base,
|
|
103
|
+
from: { scale: 0.88, autoAlpha: 0 },
|
|
104
|
+
to: { scale: 1, autoAlpha: 1 },
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (preset === "slide") {
|
|
109
|
+
const x = direction === "right" ? -distance : direction === "left" ? distance : 0;
|
|
110
|
+
const y = direction === "down" ? -distance : direction === "up" ? distance : 0;
|
|
111
|
+
return {
|
|
112
|
+
...base,
|
|
113
|
+
from: { x, y, autoAlpha: 0 },
|
|
114
|
+
to: { x: 0, y: 0, autoAlpha: 1 },
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...base,
|
|
120
|
+
from: { y: direction === "down" ? -distance : distance, autoAlpha: 0 },
|
|
121
|
+
to: { y: 0, autoAlpha: 1 },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── Manifest parse/serialize ──
|
|
126
|
+
|
|
127
|
+
function parseMotionValues(
|
|
128
|
+
value: unknown,
|
|
129
|
+
): import("./studioMotionTypes").StudioGsapMotionValues | null {
|
|
130
|
+
if (!value || typeof value !== "object") return null;
|
|
131
|
+
const record = value as Record<string, unknown>;
|
|
132
|
+
const parsed: import("./studioMotionTypes").StudioGsapMotionValues = {};
|
|
133
|
+
for (const key of ["x", "y", "scale", "rotation", "opacity", "autoAlpha"] as const) {
|
|
134
|
+
const next = finiteNumber(record[key]);
|
|
135
|
+
if (next != null) parsed[key] = next;
|
|
136
|
+
}
|
|
137
|
+
return Object.keys(parsed).length > 0 ? parsed : null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function parseTarget(value: unknown): StudioMotionTarget | null {
|
|
141
|
+
if (!value || typeof value !== "object") return null;
|
|
142
|
+
const record = value as Record<string, unknown>;
|
|
143
|
+
const sourceFile = typeof record.sourceFile === "string" ? record.sourceFile : "";
|
|
144
|
+
if (!sourceFile) return null;
|
|
145
|
+
const selector = typeof record.selector === "string" ? record.selector : undefined;
|
|
146
|
+
const id = typeof record.id === "string" ? record.id : undefined;
|
|
147
|
+
if (!selector && !id) return null;
|
|
148
|
+
return {
|
|
149
|
+
sourceFile,
|
|
150
|
+
selector,
|
|
151
|
+
selectorIndex: finiteNumber(record.selectorIndex) ?? undefined,
|
|
152
|
+
id,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function parseCustomEase(value: unknown): StudioGsapCustomEase | undefined {
|
|
157
|
+
if (!value || typeof value !== "object") return undefined;
|
|
158
|
+
const record = value as Record<string, unknown>;
|
|
159
|
+
const id = typeof record.id === "string" ? record.id.trim() : "";
|
|
160
|
+
const data = typeof record.data === "string" ? record.data.trim() : "";
|
|
161
|
+
if (!id || !data) return undefined;
|
|
162
|
+
return { id, data };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function parseGsapMotion(value: unknown): StudioGsapMotion | null {
|
|
166
|
+
if (!value || typeof value !== "object") return null;
|
|
167
|
+
const record = value as Record<string, unknown>;
|
|
168
|
+
if (record.kind !== "gsap-motion") return null;
|
|
169
|
+
const target = parseTarget(record.target);
|
|
170
|
+
if (!target) return null;
|
|
171
|
+
const start = finiteNumber(record.start);
|
|
172
|
+
const duration = finiteNumber(record.duration);
|
|
173
|
+
if (start == null || duration == null || start < 0 || duration <= 0) return null;
|
|
174
|
+
const ease = typeof record.ease === "string" && record.ease.trim() ? record.ease.trim() : "none";
|
|
175
|
+
const from = parseMotionValues(record.from);
|
|
176
|
+
const to = parseMotionValues(record.to);
|
|
177
|
+
if (!from || !to) return null;
|
|
178
|
+
return {
|
|
179
|
+
kind: "gsap-motion",
|
|
180
|
+
target,
|
|
181
|
+
start,
|
|
182
|
+
duration,
|
|
183
|
+
ease,
|
|
184
|
+
customEase: parseCustomEase(record.customEase),
|
|
185
|
+
from,
|
|
186
|
+
to,
|
|
187
|
+
updatedAt: typeof record.updatedAt === "string" ? record.updatedAt : undefined,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function emptyStudioMotionManifest(): StudioMotionManifest {
|
|
192
|
+
return { version: 1, motions: [] };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function parseStudioMotionManifest(content: string): StudioMotionManifest {
|
|
196
|
+
if (!content.trim()) return emptyStudioMotionManifest();
|
|
197
|
+
try {
|
|
198
|
+
const parsed = JSON.parse(content) as unknown;
|
|
199
|
+
if (!parsed || typeof parsed !== "object") return emptyStudioMotionManifest();
|
|
200
|
+
const motions = (parsed as { motions?: unknown }).motions;
|
|
201
|
+
if (!Array.isArray(motions)) return emptyStudioMotionManifest();
|
|
202
|
+
return {
|
|
203
|
+
version: 1,
|
|
204
|
+
motions: motions
|
|
205
|
+
.map(parseGsapMotion)
|
|
206
|
+
.filter((motion): motion is StudioGsapMotion => motion !== null),
|
|
207
|
+
};
|
|
208
|
+
} catch {
|
|
209
|
+
return emptyStudioMotionManifest();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function serializeStudioMotionManifest(manifest: StudioMotionManifest): string {
|
|
214
|
+
return `${JSON.stringify(manifest, null, 2)}\n`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ── Path helpers ──
|
|
218
|
+
|
|
219
|
+
function normalizeStudioFileChangePath(path: string): string {
|
|
220
|
+
return path
|
|
221
|
+
.trim()
|
|
222
|
+
.replace(/\\/g, "/")
|
|
223
|
+
.replace(/^\.?\//, "");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function isStudioMotionManifestPath(path: string | null): boolean {
|
|
227
|
+
if (!path) return false;
|
|
228
|
+
const normalized = normalizeStudioFileChangePath(path);
|
|
229
|
+
return (
|
|
230
|
+
normalized === "." + "/" + ".hyperframes/studio-motion.json".slice(1) ||
|
|
231
|
+
normalized === ".hyperframes/studio-motion.json" ||
|
|
232
|
+
normalized.endsWith("/.hyperframes/studio-motion.json")
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ── CRUD helpers ──
|
|
237
|
+
|
|
238
|
+
function selectionTarget(selection: DomEditSelection): StudioMotionTarget {
|
|
239
|
+
return {
|
|
240
|
+
sourceFile: selection.sourceFile || "index.html",
|
|
241
|
+
selector: selection.selector,
|
|
242
|
+
selectorIndex: selection.selectorIndex,
|
|
243
|
+
id: selection.id ?? undefined,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function targetKey(target: StudioMotionTarget): string {
|
|
248
|
+
return [
|
|
249
|
+
target.sourceFile,
|
|
250
|
+
target.id ? `id:${target.id}` : "",
|
|
251
|
+
target.selector ? `selector:${target.selector}` : "",
|
|
252
|
+
target.selectorIndex != null ? `index:${target.selectorIndex}` : "",
|
|
253
|
+
].join("|");
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function sameSelectionTarget(motion: StudioGsapMotion, selection: DomEditSelection): boolean {
|
|
257
|
+
const target = selectionTarget(selection);
|
|
258
|
+
if (motion.target.sourceFile !== target.sourceFile) return false;
|
|
259
|
+
if (motion.target.id && target.id && motion.target.id === target.id) return true;
|
|
260
|
+
return targetKey(motion.target) === targetKey(target);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function upsertStudioGsapMotion(
|
|
264
|
+
manifest: StudioMotionManifest,
|
|
265
|
+
selection: DomEditSelection,
|
|
266
|
+
motion: Omit<StudioGsapMotion, "kind" | "target" | "updatedAt">,
|
|
267
|
+
): StudioMotionManifest {
|
|
268
|
+
const target = selectionTarget(selection);
|
|
269
|
+
const nextMotion: StudioGsapMotion = {
|
|
270
|
+
kind: "gsap-motion",
|
|
271
|
+
target,
|
|
272
|
+
...motion,
|
|
273
|
+
updatedAt: new Date().toISOString(),
|
|
274
|
+
};
|
|
275
|
+
return {
|
|
276
|
+
version: 1,
|
|
277
|
+
motions: [
|
|
278
|
+
...manifest.motions.filter((existing) => targetKey(existing.target) !== targetKey(target)),
|
|
279
|
+
nextMotion,
|
|
280
|
+
],
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function removeStudioMotionForSelection(
|
|
285
|
+
manifest: StudioMotionManifest,
|
|
286
|
+
selection: DomEditSelection,
|
|
287
|
+
): StudioMotionManifest {
|
|
288
|
+
return {
|
|
289
|
+
version: 1,
|
|
290
|
+
motions: manifest.motions.filter((motion) => !sameSelectionTarget(motion, selection)),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export function getStudioMotionForSelection(
|
|
295
|
+
manifest: StudioMotionManifest,
|
|
296
|
+
selection: DomEditSelection,
|
|
297
|
+
): StudioGsapMotion | null {
|
|
298
|
+
return manifest.motions.find((motion) => sameSelectionTarget(motion, selection)) ?? null;
|
|
299
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// ── Types and Constants for Studio Motion ──
|
|
2
|
+
|
|
3
|
+
export const STUDIO_MOTION_PATH = ".hyperframes/studio-motion.json";
|
|
4
|
+
export const STUDIO_MOTION_TIMELINE_ID = "studio-motion";
|
|
5
|
+
|
|
6
|
+
export const STUDIO_MOTION_ATTR = "data-hf-studio-motion";
|
|
7
|
+
export const STUDIO_MOTION_ORIGINAL_TRANSFORM_ATTR = "data-hf-studio-motion-original-transform";
|
|
8
|
+
export const STUDIO_MOTION_ORIGINAL_OPACITY_ATTR = "data-hf-studio-motion-original-opacity";
|
|
9
|
+
export const STUDIO_MOTION_ORIGINAL_VISIBILITY_ATTR = "data-hf-studio-motion-original-visibility";
|
|
10
|
+
|
|
11
|
+
export interface StudioMotionTarget {
|
|
12
|
+
sourceFile: string;
|
|
13
|
+
selector?: string;
|
|
14
|
+
selectorIndex?: number;
|
|
15
|
+
id?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface StudioGsapMotionValues {
|
|
19
|
+
x?: number;
|
|
20
|
+
y?: number;
|
|
21
|
+
scale?: number;
|
|
22
|
+
rotation?: number;
|
|
23
|
+
opacity?: number;
|
|
24
|
+
autoAlpha?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface StudioGsapCustomEase {
|
|
28
|
+
id: string;
|
|
29
|
+
data: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface StudioCustomEaseControlPoints {
|
|
33
|
+
x1: number;
|
|
34
|
+
y1: number;
|
|
35
|
+
x2: number;
|
|
36
|
+
y2: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface StudioGsapMotion {
|
|
40
|
+
kind: "gsap-motion";
|
|
41
|
+
target: StudioMotionTarget;
|
|
42
|
+
start: number;
|
|
43
|
+
duration: number;
|
|
44
|
+
ease: string;
|
|
45
|
+
customEase?: StudioGsapCustomEase;
|
|
46
|
+
from: StudioGsapMotionValues;
|
|
47
|
+
to: StudioGsapMotionValues;
|
|
48
|
+
updatedAt?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type StudioGsapMotionPreset = "fade-up" | "slide" | "pop";
|
|
52
|
+
export type StudioGsapMotionDirection = "up" | "down" | "left" | "right";
|
|
53
|
+
|
|
54
|
+
export const STUDIO_GSAP_EASE_OPTIONS = [
|
|
55
|
+
"none",
|
|
56
|
+
"power1.in",
|
|
57
|
+
"power1.out",
|
|
58
|
+
"power1.inOut",
|
|
59
|
+
"power2.in",
|
|
60
|
+
"power2.out",
|
|
61
|
+
"power2.inOut",
|
|
62
|
+
"power3.in",
|
|
63
|
+
"power3.out",
|
|
64
|
+
"power3.inOut",
|
|
65
|
+
"power4.in",
|
|
66
|
+
"power4.out",
|
|
67
|
+
"power4.inOut",
|
|
68
|
+
"sine.in",
|
|
69
|
+
"sine.out",
|
|
70
|
+
"sine.inOut",
|
|
71
|
+
"expo.in",
|
|
72
|
+
"expo.out",
|
|
73
|
+
"expo.inOut",
|
|
74
|
+
"circ.in",
|
|
75
|
+
"circ.out",
|
|
76
|
+
"circ.inOut",
|
|
77
|
+
"back.in(1.7)",
|
|
78
|
+
"back.out(1.7)",
|
|
79
|
+
"back.inOut(1.7)",
|
|
80
|
+
"elastic.out(1, 0.45)",
|
|
81
|
+
"bounce.out",
|
|
82
|
+
] as const;
|
|
83
|
+
|
|
84
|
+
export const DEFAULT_CUSTOM_EASE_POINTS: StudioCustomEaseControlPoints = {
|
|
85
|
+
x1: 0.215,
|
|
86
|
+
y1: 0.61,
|
|
87
|
+
x2: 0.355,
|
|
88
|
+
y2: 1,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const GSAP_EASE_CONTROL_POINTS: Record<string, StudioCustomEaseControlPoints> = {
|
|
92
|
+
none: { x1: 0, y1: 0, x2: 1, y2: 1 },
|
|
93
|
+
"power1.in": { x1: 0.55, y1: 0.085, x2: 0.68, y2: 0.53 },
|
|
94
|
+
"power1.out": { x1: 0.25, y1: 0.46, x2: 0.45, y2: 0.94 },
|
|
95
|
+
"power1.inOut": { x1: 0.455, y1: 0.03, x2: 0.515, y2: 0.955 },
|
|
96
|
+
"power2.in": { x1: 0.55, y1: 0.055, x2: 0.675, y2: 0.19 },
|
|
97
|
+
"power2.out": { x1: 0.215, y1: 0.61, x2: 0.355, y2: 1 },
|
|
98
|
+
"power2.inOut": { x1: 0.645, y1: 0.045, x2: 0.355, y2: 1 },
|
|
99
|
+
"power3.in": { x1: 0.895, y1: 0.03, x2: 0.685, y2: 0.22 },
|
|
100
|
+
"power3.out": { x1: 0.165, y1: 0.84, x2: 0.44, y2: 1 },
|
|
101
|
+
"power3.inOut": { x1: 0.77, y1: 0, x2: 0.175, y2: 1 },
|
|
102
|
+
"power4.in": { x1: 0.755, y1: 0.05, x2: 0.855, y2: 0.06 },
|
|
103
|
+
"power4.out": { x1: 0.23, y1: 1, x2: 0.32, y2: 1 },
|
|
104
|
+
"power4.inOut": { x1: 0.86, y1: 0, x2: 0.07, y2: 1 },
|
|
105
|
+
"sine.in": { x1: 0.47, y1: 0, x2: 0.745, y2: 0.715 },
|
|
106
|
+
"sine.out": { x1: 0.39, y1: 0.575, x2: 0.565, y2: 1 },
|
|
107
|
+
"sine.inOut": { x1: 0.445, y1: 0.05, x2: 0.55, y2: 0.95 },
|
|
108
|
+
"expo.in": { x1: 0.95, y1: 0.05, x2: 0.795, y2: 0.035 },
|
|
109
|
+
"expo.out": { x1: 0.19, y1: 1, x2: 0.22, y2: 1 },
|
|
110
|
+
"expo.inOut": { x1: 1, y1: 0, x2: 0, y2: 1 },
|
|
111
|
+
"circ.in": { x1: 0.6, y1: 0.04, x2: 0.98, y2: 0.335 },
|
|
112
|
+
"circ.out": { x1: 0.075, y1: 0.82, x2: 0.165, y2: 1 },
|
|
113
|
+
"circ.inOut": { x1: 0.785, y1: 0.135, x2: 0.15, y2: 0.86 },
|
|
114
|
+
"back.in(1.7)": { x1: 0.6, y1: -0.28, x2: 0.735, y2: 0.045 },
|
|
115
|
+
"back.out(1.7)": { x1: 0.175, y1: 0.885, x2: 0.32, y2: 1.275 },
|
|
116
|
+
"back.inOut(1.7)": { x1: 0.68, y1: -0.55, x2: 0.265, y2: 1.55 },
|
|
117
|
+
"elastic.out(1, 0.45)": { x1: 0.16, y1: 1.32, x2: 0.28, y2: 0.86 },
|
|
118
|
+
"bounce.out": { x1: 0.34, y1: 1.56, x2: 0.64, y2: 0.74 },
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const CUSTOM_EASE_DATA_PATTERN =
|
|
122
|
+
/^M\s*0\s*,\s*0\s*C\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s+1\s*,\s*1\s*$/i;
|
|
123
|
+
|
|
124
|
+
export interface StudioGsapPresetMotionOptions {
|
|
125
|
+
start: number;
|
|
126
|
+
duration: number;
|
|
127
|
+
distance: number;
|
|
128
|
+
ease: string;
|
|
129
|
+
direction?: StudioGsapMotionDirection;
|
|
130
|
+
customEase?: StudioGsapCustomEase;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface StudioMotionManifest {
|
|
134
|
+
version: 1;
|
|
135
|
+
motions: StudioGsapMotion[];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface StudioGsapTimeline {
|
|
139
|
+
fromTo?: (
|
|
140
|
+
target: HTMLElement,
|
|
141
|
+
from: Record<string, unknown>,
|
|
142
|
+
to: Record<string, unknown>,
|
|
143
|
+
at: number,
|
|
144
|
+
) => StudioGsapTimeline;
|
|
145
|
+
time?: (time: number) => StudioGsapTimeline;
|
|
146
|
+
totalTime?: (time: number, suppressEvents?: boolean) => StudioGsapTimeline;
|
|
147
|
+
pause?: () => StudioGsapTimeline;
|
|
148
|
+
kill?: () => void;
|
|
149
|
+
duration?: () => number;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export type StudioMotionWindow = Window & {
|
|
153
|
+
gsap?: {
|
|
154
|
+
timeline?: (vars?: Record<string, unknown>) => StudioGsapTimeline;
|
|
155
|
+
set?: (target: HTMLElement, vars: Record<string, unknown>) => void;
|
|
156
|
+
registerPlugin?: (...plugins: unknown[]) => void;
|
|
157
|
+
};
|
|
158
|
+
CustomEase?: { create?: (id: string, data: string) => void };
|
|
159
|
+
__player?: {
|
|
160
|
+
getTime?: () => number;
|
|
161
|
+
renderSeek?: (time: number) => void;
|
|
162
|
+
seek?: (time: number) => void;
|
|
163
|
+
};
|
|
164
|
+
__timeline?: { time?: () => number };
|
|
165
|
+
__timelines?: Record<string, StudioGsapTimeline | undefined>;
|
|
166
|
+
__hfStudioMotionApply?: () => number;
|
|
167
|
+
__hfStudioMotionWrapped?: boolean;
|
|
168
|
+
};
|