mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 07:09:59 +00:00
feat(studio): GSAP tween editing in Design panel (#1102)
* feat(studio): GSAP tween editing in Design panel
Add a GSAP animation editor to the studio Design panel: select an element,
view and edit its tweens (properties, easing, timing), add/delete animations,
and drag custom bezier speed curves — all persisted back to the composition
HTML. Gated behind VITE_STUDIO_ENABLE_GSAP_PANEL.
Parsing of existing GSAP source now uses a recast + Babel AST parser instead of
regex, giving scope resolution, stable tween IDs, and round-trip preservation of
extras and unresolved raw values.
recast compiles to CommonJS that calls require("fs"), which breaks browser and
Vite SSR bundles. To contain it, @hyperframes/core is split into an isomorphic
layer and a Node-only AST layer:
- gsapSerialize.ts holds the recast-free helpers (serialization, keyframe
conversion, validation, shared types). htmlParser.ts is now fully isomorphic.
- parseGsapScript and the script-mutation helpers live in gsapParser.ts,
reachable only via the @hyperframes/core/gsap-parser subpath, loaded
server-side by the studio-api mutation routes and the linter via dynamic
import (recast stays external under SSR).
- The barrel and the gsap-constants subpath are recast-free, so studio browser
bundles never trace recast.
Adds AST parser unit + stress coverage and e2e helpers for the panel.
* fix(lint): await async lintHyperframeHtml in all callers
lintHyperframeHtml became async (gsap rules use dynamic import)
but lintProject and check-hyperframe-static weren't awaiting it,
causing typecheck failures and runtime crashes in CI.
Also wire LintRule type in gsap rules to fix fallow unused-type
finding, and suppress render.ts exported-for-tests symbols.
This commit is contained in:
@@ -103,6 +103,8 @@ export function MetricField({
|
||||
disabled,
|
||||
liveCommit,
|
||||
scrub,
|
||||
suffix,
|
||||
tooltip,
|
||||
onCommit,
|
||||
}: {
|
||||
label: string;
|
||||
@@ -110,6 +112,8 @@ export function MetricField({
|
||||
disabled?: boolean;
|
||||
liveCommit?: boolean;
|
||||
scrub?: boolean;
|
||||
suffix?: string;
|
||||
tooltip?: string;
|
||||
onCommit: (nextValue: string) => void;
|
||||
}) {
|
||||
const scrubRef = useRef<{ startX: number; startValue: number; pointerId: number } | null>(null);
|
||||
@@ -151,7 +155,7 @@ export function MetricField({
|
||||
: ({ className: "flex-shrink-0 text-[11px] font-medium text-neutral-500" } as const);
|
||||
|
||||
return (
|
||||
<div className={FIELD}>
|
||||
<div className={FIELD} title={tooltip}>
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
<span {...scrubProps}>{label}</span>
|
||||
<CommitField
|
||||
@@ -160,6 +164,7 @@ export function MetricField({
|
||||
liveCommit={liveCommit}
|
||||
onCommit={onCommit}
|
||||
/>
|
||||
{suffix && <span className="flex-shrink-0 text-[10px] text-neutral-600">{suffix}</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user