Commit Graph
418 Commits
Author SHA1 Message Date
Miguel Angel Simon Sierra 3351fb1a6d chore: release v0.7.17 2026-06-27 13:54:58 -04:00
Miguel Ángel fb4d49d248 chore: release v0.7.16 (#1771) 2026-06-27 12:16:46 -04:00
Miguel Ángel b6146f8e1b fix(core): publish runtime export artifact 2026-06-27 10:04:36 +00:00
Miguel Ángel a14d342bdb chore: release v0.7.15 2026-06-27 10:00:26 +00:00
Miguel Ángel 7a4853dfe6 refactor: extract @hyperframes/studio-server from core (#1757)
* refactor: extract @hyperframes/studio-server package from core

Moves all studio-api routes, helpers, and Hono server wiring from
packages/core/src/studio-api/ into a new standalone packages/studio-server
package (@hyperframes/studio-server).

Core keeps thin re-export stubs at @hyperframes/core/studio-api and the
subpath helpers (screenshot-clip, draft-markers, etc.) for backward
compatibility. Consumer imports (cli studioServer, vite adapter/config,
producer htmlCompiler, studio manualEditsTypes) are updated to import from
@hyperframes/studio-server directly.

Also exports rewriteInlineStyleAssetUrls from @hyperframes/core root (was
in compiler/rewriteSubCompPaths.ts but not re-exported), required by
@hyperframes/studio-server/helpers/subComposition.

Removes postcss-selector-parser from @hyperframes/core dependencies (moved
to @hyperframes/studio-server which owns the routes that used it).

Depends on @hyperframes/parsers (PR #1755).

* fix(ci): add parsers+studio-server to Dockerfile and build before preview tests

* fix(ci): build @hyperframes/studio-server before Test and studio load smoke

Studio's vite.config.ts imports @hyperframes/studio-server, which resolves
via its "node" export condition to built dist. The Test and studio-load-smoke
jobs only built parsers + core, so esbuild's config load failed to resolve the
package entry. Build studio-server too.

* fix(studio): repoint sdkCutoverParity test import to studio-server

sourceMutation moved from core's studio-api to @hyperframes/studio-server;
the test still imported the deleted core path. This was masked while studio's
vite.config failed to load (couldn't resolve studio-server); now that the
config loads, the test runs and the stale import surfaced.
2026-06-27 01:24:01 -04:00
Miguel Ángel 98d0bdd73c refactor: extract @hyperframes/lint from core (#1756)
* refactor: extract @hyperframes/lint package from core

Moves all lint rules, hyperframeLinter, lintProject, and related types
from packages/core/src/lint/ into a new standalone packages/lint package.

Core keeps a thin re-export stub at @hyperframes/core/lint for backward
compatibility. Consumer imports (cli lint command, producer hyperframeLint)
are updated to import from @hyperframes/lint directly.

Depends on @hyperframes/parsers (PR #1755).

* fix: restore postcss-selector-parser in core (sourceMutation.ts still uses it)

* fix(ci): add parsers+lint to Dockerfile and build before preview tests

* chore: update bun.lock after restoring postcss-selector-parser dep

* test(cli): update lintProject test for string-dir signature from @hyperframes/lint

* refactor(core): single-source the lint engine in @hyperframes/lint

Delete core's byte-identical copy of the lint rule engine and re-point
staticGuard at @hyperframes/lint, so the render-time render-gate and the
studio preview share one rule engine instead of two copies that could
silently diverge. Back-compat preserved via the @hyperframes/core/lint stub.

Addresses review feedback on the dual-copy footgun.
2026-06-27 01:16:40 -04:00
Miguel Ángel cdf9c817e1 refactor: extract @hyperframes/parsers from core (#1755)
## Summary

Extracts the GSAP parser/writer suite, HTML parser, hf-ids, spring-ease, and the shared composition data types out of `@hyperframes/core/src/parsers/` into a new, independently-publishable **`@hyperframes/parsers`** package.

This is the foundation of the [#1749](https://github.com/heygen-com/hyperframes/issues/1749) effort: make HyperFrames' parsing/linting/validation usable as plain libraries in a Node app, without shelling out to the CLI. Parsers is the standalone base every other extracted package builds on.

**Part 1 of 3** — splits #1754 into independently-reviewable pieces. Parts 2 (lint) and 3 (studio-server) stack on this branch.

## What moves

| | |
|---|---|
| Source moved out of core | **~9,900 LOC** (`src/parsers/` → `packages/parsers/src/`) |
| Total lines removed from core (incl. tests + goldens) | ~19,600 |
| Files relocated | 39 |
| Tests carried over | **660 passing** (5 skipped, 3 todo) |

The big movers: `gsapParser` / `gsapParserAcorn` (the recast + acorn dual parsers), `gsapWriterAcorn`, `gsapSerialize`, `gsapUnroll`, `htmlParser`, `hfIds`, `springEase`, `stableIds`, plus the `__goldens__` corpus.

## Bundle footprint of the new package

| Artifact | Size |
|---|---|
| `dist/` (unpacked) | 1.7 MB |
| npm tarball (packed) | 409 KB |
| `dist/index.js` | 90 KB (**~21 KB gzipped**) |
| Heaviest entries | `gsapWriterAcorn.js` 93 KB · `gsapParser.js` 91 KB |

Most of the weight is the GSAP AST machinery (recast/babel/acorn). It's tree-shakeable via subpath entries (`@hyperframes/parsers/hf-ids`, `/gsap-constants`, etc.) so a consumer that only needs `hf-ids` (2 KB) doesn't pull the parsers.

## How `@hyperframes/core` changes

The interesting part: **core sheds its entire AST toolchain.**

| core `dependencies` | before | after |
|---|---|---|
| count | 9 | 6 |
| removed | — | `@babel/parser`, `acorn`, `acorn-walk`, `magic-string`, `recast` |
| added | — | `@hyperframes/parsers`, `linkedom` |

Before this PR, importing `@hyperframes/core` at all dragged in babel + recast + acorn just to construct types. Now those live behind `@hyperframes/parsers`, and a consumer that only wants core's runtime/compiler types never resolves the parser stack. Core keeps thin `@deprecated` re-export stubs at the old subpaths (`@hyperframes/core/gsap-parser`, `/gsap-constants`, …) so nothing downstream breaks.

## Design notes

- **`"bun"` export condition before `"node"`** in every package export. Bun resolves the TypeScript source directly (no pre-built `dist/`), while Node/tsx/Docker contexts fall through to `"node"` → `dist/`. This keeps the dev loop zero-build while published artifacts stay Node-consumable.
- `@hyperframes/parsers` is **standalone** — zero `@hyperframes/*` dependencies — so it can be the base of the stack.

## Test plan

- [x] `bun run --filter @hyperframes/parsers test` — 660 tests pass
- [x] `bun run --filter @hyperframes/sdk test` — 382 tests pass
- [x] `bun run build` — full monorepo build succeeds
- [x] Fallow audit passes on CI
2026-06-27 00:46:26 -04:00
Miguel Ángel 8f7fb49d16 chore: release v0.7.14 2026-06-27 00:39:16 +00:00
Miguel Ángel e3edbd55cf chore: release v0.7.13 2026-06-26 22:43:22 +00:00
Miguel Ángel 1d3c68ef69 chore: release v0.7.12 2026-06-26 21:49:37 +00:00
James 413d8187fd chore: release v0.7.11 2026-06-26 18:37:23 +00:00
Miguel Ángel 0c1e236dcd chore: release v0.7.10 (#1734) 2026-06-26 00:51:34 -04:00
Miguel Angel Simon Sierra 8db190dd43 chore: release v0.7.9 2026-06-25 21:32:51 -04:00
Miguel Angel Simon Sierra 764aa02a3a chore: release v0.7.8 2026-06-25 18:59:53 -04:00
Miguel Ángel 1494f715fb chore: release v0.7.7 (#1719) 2026-06-25 11:54:10 -04:00
Miguel Ángel eee376cb5e chore: release v0.7.6 (#1707) 2026-06-24 20:17:20 -04:00
Miguel Ángel 649c216394 chore: release v0.7.5 2026-06-24 04:41:56 +00:00
Miguel Ángel ba77a0bd72 chore: release v0.7.4 2026-06-24 00:10:04 +00:00
Miguel Ángel 997823b6b5 chore: release v0.7.3 2026-06-22 23:07:48 -04:00
Miguel Ángel b8d6c4aa21 chore: release v0.7.2 2026-06-22 22:44:19 +00:00
Miguel Ángel 3a6742bd13 chore: release v0.7.1 2026-06-22 14:09:55 -04:00
Miguel Ángel a97f80433f chore: release v0.7.0 2026-06-22 11:23:33 -04:00
Miguel Ángel e385d213f3 chore: release v0.6.121 (#1627) 2026-06-21 17:59:01 -04:00
Miguel Ángel 6c71cf0240 chore: release v0.6.120 (#1624) 2026-06-21 11:17:48 -04:00
Miguel Ángel 2612b9bdfe fix: publish Node-compatible package entrypoints (#1622) 2026-06-21 10:49:35 -04:00
Vance Ingalls b33a7457a7 chore: release v0.6.119 (#1620) 2026-06-21 01:03:18 -07:00
Miguel Ángel 0d2198e654 chore: release v0.6.118 2026-06-20 18:24:11 -04:00
Miguel Ángel 12d5273812 chore: release v0.6.117 2026-06-20 18:05:59 -04:00
Miguel Ángel 960690e8e5 fix(core): publish missing subpath exports (#1616) 2026-06-20 18:04:43 -04:00
Miguel Ángel 6b279267cd chore: release v0.6.116 2026-06-20 21:25:34 +00:00
Miguel Ángel d6135ca155 chore: release v0.6.115 2026-06-20 00:19:28 +00:00
Miguel Ángel 758eda995c fix(sdk,studio): restore DOM edit cutover parity (#1565)
- Add splitStyleDeclarations with quote/paren-aware CSS parsing
- Fix backslash escape handling inside quoted CSS string values
- Close html-attribute safety gap in SDK cutover (event handlers, dangerous URIs)
- Consolidate HTML attribute safety constants to core/utils/htmlAttrSafety.ts
- Extract NON_HTML_CHILD_TAGS set for foreign-content decline gate
- Add sdkCutoverParity test corpus (shorthand/longhand, mixed batches)
2026-06-19 15:37:10 -04:00
Vance Ingalls 4e32c5e0fe chore: release v0.6.114 2026-06-19 04:38:05 -07:00
Vance Ingalls a38fc4e778 chore: release v0.6.113 2026-06-19 00:35:41 -07:00
Vance Ingalls 8376457989 feat(core): slideshow schema, parser, and lint rule (#1580)
## Slideshow mode — 1/5: core schema, parser & lint

Foundation for slideshow mode: a composition can declare an embedded **slideshow manifest** that turns its continuous timeline into a discrete, navigable deck. This PR adds the data model, parser, and validation — no runtime/UI yet.

### What & why
A slide is just an existing scene (`data-composition-id` + `data-start`/`data-duration`) plus metadata declared in one embedded `<script type="application/hyperframes-slideshow+json">` island. Keeping the manifest *in the composition* means no new file format and no build step — slides are additive metadata over a normal composition.

### Key changes
- `slideshow/slideshow.types.ts` — `SlideshowManifest`, `SlideRef`, `SlideHotspot`, `SlideSequence` and their resolved counterparts. TTS fields (`ttsScript`/`ttsAudioUrl`/`ttsDurationMs`) are present but **reserved** (playback not built).
- `slideshow/parseSlideshow.ts` — `parseSlideshowManifest(html)` extracts the island; `resolveSlideshow(manifest, scenes)` resolves each `sceneId` to a `{start,end}` range (honouring optional `startTime`/`endTime` overrides) and returns validation errors for: unresolved sceneId, fragment outside a slide's range, hotspot targeting an unknown sequence, and overlapping main-line slides.
- `lint/rules/slideshow.ts` — surfaces those resolve errors under `hyperframes lint`; derives scenes from `data-composition-id` (matching the runtime's scene source).
- `lint/rules/core.ts` — exempts the slideshow island MIME type from the inline-script-syntax check.
- `./slideshow` subpath export (dev + publishConfig) so downstream packages import only the lightweight parser, keeping core's Node-only barrel out of their typecheck graph.

### Testing
`parseSlideshow.test.ts` + `slideshow.test.ts` (vitest) cover parse, resolution, every error path, and the lint rule.

### Stack
Bottom of a 5-PR stack: **core** → player (#1581) → studio (#1582) → skill (#1583) → examples (#1584).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-19 00:31:45 -07:00
Vance IngallsandClaude Opus 4.8 967bf9f9ed refactor(core): gate acorn GSAP writer behind cutover flag; keep recast default (WS-3F) (#1573)
* refactor(core): retire recast/babel, route all GSAP mutations to acorn (WS-E/3.F)

- Delete gsapParser.ts (2595-line recast-based parser/writer)
- Delete gsapParser.test.ts, gsapParser.stress.test.ts, gsapParser.test-helpers.ts
- Add gsapParserExports.ts: re-export umbrella for gsap-parser subpath
- Move SplitAnimationsOptions/SplitAnimationsResult to gsapSerialize.ts
- executeGsapMutation: async->sync, static acorn imports replace loadGsapParser()
- Fix 3 function name mismatches in files.ts switch cases
- generators/hyperframes.ts: imports from gsapSerialize (blocker resolved)
- gsapWriterAcorn.ts: SplitAnimationsOptions from gsapSerialize
- Parity tests: recast oracle removed; acorn-only regression (14 pass)
- Remove recast and @babel/parser from core/package.json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(sdk): harden mutation handlers + widen variable API (code-review)

Self-contained review fixes for the SDK-hotspot stack (#1569–#1573). The
dispatch path (_dispatch → applyOp) never runs validateOp, so the new
WS-D/WS-3.C guards were advisory-only; re-enforce them in the handlers.

- addElement: null-guard the resolved parent (no more `as Element` masking a
  null → crash on unknown parent id); reject <script> and multi-root fragments
  via parseInsertableFragment instead of inserting raw markup / silently
  dropping extra roots.
- addWithKeyframes / replaceWithKeyframes: bail on empty keyframes (no
  degenerate `keyframes: {}` tween) and when the animationId resolves to
  nothing (no silent degrade-to-add leaving a duplicate tween).
- isObjectVariableValue: exclude arrays so an array override value can't be
  misclassified as a font/image object and written into the variable model.
- Composition.setVariableValue: widen the public interface signature to
  `… | FontValue | ImageValue` to match the impl + EditOp (B2 object-valued
  variables were unreachable via the typed API).
- mutate.gsap.test.ts: import addKeyframeToScript from gsap-writer-acorn —
  the gsap-parser subpath no longer re-exports write fns after recast retire,
  so the test threw at runtime (red suite).
- Dedup: export EXCLUDED_TAGS from hfIds.ts and drop the verbatim
  HF_EXCLUDED_TAGS copy in mutate.ts.

Adds guard regression tests. SDK 340/340, core hfIds 13/13, build green,
fallow --gate new-only clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(sdk): variable-model dedup + undo/scoped-parent correctness; test honesty (code-review)

Second batch of review fixes for the SDK-hotspot stack.

- Variable model (#7, #13): extract readVariableDefault/writeVariableDefault into
  a shared engine/variableModel.ts used by both mutate.ts (forward) and
  apply-patches.ts (replay), so the model shape can't diverge. Add
  clearVariableDefault and make a `variable` remove patch DELETE the decl's
  `default` key — the exact inverse of a first-set on a default-less variable.
  Previously undo of such a set no-op'd and stranded the value.
- addElement scoped parent (#8): record the caller's id verbatim
  (scoped "hf-host/hf-leaf" path or composition id) as the patch parentId
  instead of the bare data-hf-id, so redo/replay re-resolves the SAME parent via
  resolveScoped rather than the canonical top-level dup (or document.body).
- resolveTimings honesty (#5): correct the header + test that claimed a live
  "preview == render" parity — neither path consumes the resolver yet (anchor
  inputs are Pacific/backend-deferred). It's a pure-function property, not a
  current guarantee.
- GSAP writer parity (#12): the recast oracle was deleted in WS-3.F, leaving the
  WS-3.C keyframe ops comparing acorn output to itself. Pin them as golden inline
  snapshots and drop the now-dead recast scaffolding (replaceWithKfRecast,
  removeAnimRecast alias). Remaining pre-WS-3.C parity blocks noted as follow-up.

Adds regression tests (undo of default-less variable; scoped-parent redo).
SDK 342/342, core timingResolver+parity green, build + fallow --gate new-only clean.

Not changed (need design / out of scope): #9 pre-#1569 persisted-override CSS
replay (moot for unreleased data; proper fix is render-time CSS derivation),
#11 replaceWithKeyframes stale positional id (mitigated by the missing-id no-op
guard + type doc; full fix needs non-positional ids).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(sdk): replay CSS-prop derivation for legacy var overrides; stale-id selector guard (code-review)

Final review-fix batch — the two items deferred from the prior pass.

- #9 legacy variable-override CSS: applyOverrideSet now derives the `--{id}`
  CSS custom prop from any scalar `var.{id}` override on replay (and removes it
  for a null override). Sets written before the model/CSS split carried only
  `var.{id}`; without this, replaying them updated the JSON model but left
  `var(--{id})` bindings rendering the schema default. Replay-path only — the
  undo path (applyOne) is untouched, so #1569's separate-patch undo correctness
  is preserved. Object (font/image) values are never CSS, so they are skipped.
- #11 stale positional id: replaceWithKeyframes now requires the located
  animation to still target the caller's `targetSelector`. Position-derived ids
  re-point after structural edits; a stale id resolving to a DIFFERENT element's
  tween previously got silently replaced. It now bails (no-op) unless the id
  still points at the expected selector.

Adds regression tests (legacy var.{id}-only override restores CSS; object
override writes no CSS; stale-id-wrong-selector replace is a no-op).
SDK 345/345, build + fallow --gate new-only clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(core): gate acorn GSAP writer behind cutover flag; keep recast default (WS-3F)

Product decision pivot: acorn no longer replaces recast as the GSAP writer.
Recast remains the default server writer; acorn runs only when
STUDIO_SDK_CUTOVER_ENABLED=true (or =1) is set server-side — the same env
flag name as the client Vite var, so a single switch flips both sides.

Changes:
- Restore gsapParser.ts (recast writer) + test/stress/helper files deleted by 3F
- Restore @babel/parser + recast deps in packages/core/package.json
- Add isAcornGsapWriterEnabled() + loadGsapParser() to files.ts (lines 59-82)
- Split executeGsapMutation into async dispatcher + executeGsapMutationRecast
  (recast, async via loadGsapParser) + executeGsapMutationAcorn (acorn, sync)
- Dispatcher defaults to recast; acorn branch taken only when flag is on
- Restore gsapWriter.parity.test.ts, gsapWriterParity.acorn.test.ts, and
  gsapWriterParity.corpus.test.ts to true recast-vs-acorn differential suites
  (not acorn-vs-itself)
- Exempt gsapParser.ts in .fallowrc.jsonc health.ignore + ignoreExports
  (pre-existing complexity + barrel re-exports consumed outside diff scope)
- Add fallow-ignore-file code-duplication to files.ts (intentional parallel
  switch bodies for two writers)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 00:22:14 -07:00
Vance Ingalls 1bab79ef4c chore: release v0.6.112 2026-06-18 01:14:30 -07:00
Vance Ingalls de87f3932e chore: release v0.6.111 2026-06-17 22:28:29 -07:00
James RussoandClaude Opus 4.8 8a13a07074 feat(studio): add storyboard manifest contract, parser, and read API (#1528)
First PR in the Studio storyboarding stack. Establishes the parseable
contract the storyboard UI reads from; no UI yet.

- core/storyboard: StoryboardManifest/Frame/Globals types + a lenient
  STORYBOARD.md parser (frontmatter + status/src/duration/transition_in,
  freeform narrative tolerated, never throws, records warnings). Exposed as
  @hyperframes/core/storyboard (browser-safe).
- studio-api: GET /projects/:id/storyboard returns the normalized manifest
  with per-frame srcExists; missing file -> exists:false, not 404.
- fixture: packages/studio/fixtures/storyboard-sample for dogfooding the
  storyboard view in later PRs (built/animated frames + one outline).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 12:06:56 -07:00
Miguel Ángel fcc7b314f0 chore: release v0.6.110 2026-06-17 10:23:49 -04:00
Vance Ingalls 1028f52aa2 chore: release v0.6.109 2026-06-16 21:16:45 -07:00
Vance Ingalls cc7c206e9c chore: release v0.6.108 2026-06-16 17:56:34 -07:00
ukimsanov 3109acb88a feat(core): add color grading schema and lut parsing 2026-06-16 13:41:28 -07:00
Vance Ingalls 6778ad13ef chore: release v0.6.107 2026-06-16 12:49:26 -07:00
Miguel Ángel c0ac03cab2 chore: release v0.6.106 2026-06-16 13:16:09 -04:00
Miguel Ángel 2798b97ef1 chore: release v0.6.105 2026-06-16 12:30:23 -04:00
Vance Ingalls 479184ecf0 chore: release v0.6.104 2026-06-16 02:58:48 -07:00
Miguel Ángel d9dc88ff60 chore: release v0.6.103 2026-06-16 02:57:54 -04:00
Miguel Ángel d6a846300e chore: release v0.6.102 2026-06-16 01:44:54 -04:00
Miguel Ángel 78cce00c50 chore: release v0.6.101 2026-06-15 23:57:57 -04:00