23 Commits
Author SHA1 Message Date
Vance Ingalls acce9123b4 chore: release v0.4.11 2026-04-20 12:40:27 -07:00
Vance Ingalls 0d551e3614 chore: release v0.4.11-alpha.1 2026-04-20 12:38:05 -07:00
Miguel Ángel 577e822fa6 chore: release v0.4.10 2026-04-20 11:06:52 -04:00
Miguel Ángel 62ce3679e6 chore: release v0.4.9 2026-04-19 23:03:07 -04:00
Miguel Ángel 479e6c3f81 chore: release v0.4.8 2026-04-19 22:40:57 -04:00
James f622d39962 chore: release v0.4.7 2026-04-19 23:35:35 +00:00
James 38b7cb1c66 chore: release v0.4.6 2026-04-18 22:36:20 +00:00
Miguel Ángel 59aa2c9ec9 chore: release v0.4.5 2026-04-18 20:24:03 +01:00
James 0f4fcbeed8 chore: release v0.4.4 2026-04-18 03:37:09 +00:00
Miguel Ángel 46afe2ea5d chore: release v0.4.3 2026-04-17 12:15:37 +02:00
Miguel Ángel d291358cbc chore: release v0.4.2 2026-04-17 01:16:46 +02:00
Miguel Ángel 96376c9be0 chore: release v0.4.1 2026-04-17 00:25:34 +02:00
James 60780774bb chore: release v0.4.0 2026-04-16 19:58:39 +00:00
James 2718de8776 chore: release v0.3.2 2026-04-16 06:16:31 +00:00
James 0a3ca498ea chore: release v0.3.1 2026-04-15 18:42:14 +00:00
Miguel Ángel 58ddb11bc5 chore: release v0.3.0 (#249)
## Summary

Coordinated minor bump across all published packages. No source changes in this PR itself; it is the version stamp for everything that landed on main since v0.2.5.

## Version bumps

| Package | from | to |
|---|---|---|
| `@hyperframes/cli` | 0.2.5 | **0.3.0** |
| `@hyperframes/core` | 0.2.5 | **0.3.0** |
| `@hyperframes/engine` | 0.2.5 | **0.3.0** |
| `@hyperframes/player` | 0.2.7 | **0.3.0** |
| `@hyperframes/producer` | 0.2.5 | **0.3.0** |
| `@hyperframes/studio` | 0.2.9 | **0.3.0** |

Between 0.2.5 and this release, `player` and `studio` received several patch versions on npm as we iterated on the bundler, entry point, and SSR issues. 0.3.0 collapses that into a single coordinated minor so the ecosystem is aligned again.

## What is in v0.3.0

### `@hyperframes/player`

**Restored package entry points to the compiled `dist/` output.** 0.2.5 shipped with `"main": "./src/hyperframes-player.ts"` but the published tarball only included `dist/` via the `"files"` field. Every consumer trying to import the package failed with `Module not found: Can't resolve '@hyperframes/player'`. Entry points now point at the built JS/`.d.ts` files inside `dist/`.

**DOM-based root timeline resolution in the ready probe.** In a bundled preview, `window.__timelines` contains the master composition alongside its sub-compositions, for example:

```js
{
  main: GSAPTimeline(14s),
  intro: GSAPTimeline(1.5s),
  'scene2-4-canvas': GSAPTimeline(12.6s),
  'scene5-logo-outro': GSAPTimeline(3.2s),
}
```

The probe used to select the adapter with `keys[keys.length - 1]`. Object key ordering meant the last-registered sub-composition would win, so the `ready` event reported a sub-composition's duration (e.g. 3.2s) instead of the master's 14s. The probe now looks up the root composition id from the outermost `[data-composition-id]` element in the iframe DOM and uses its key. Falls back to the last key when no element is present, so standalone sub-composition previews keep working.

### `@hyperframes/studio`

**`useTimelinePlayer.getAdapter()` uses the same DOM-based root id lookup** as the player. Previously play, pause, seek, and duration readout were all driven by whichever sub-composition happened to register its timeline last.

**`Player.tsx` loads `@hyperframes/player` lazily.** The component used to call `import "@hyperframes/player"` at module scope, which runs the package's `customElements.define(...)` side effect during module evaluation. `HTMLElement` does not exist in the Node runtime, so any consumer page that transitively imported the studio during server rendering threw:

```
ReferenceError: HTMLElement is not defined
  at module evaluation (@hyperframes/studio/src/player/components/Player.tsx)
```

The import now runs inside the mount effect via `import(...)` so it only evaluates in the browser. Added a cancellation flag and deferred cleanup so a fast unmount before the dynamic import resolves does not leak listeners or DOM nodes.

**Captions module imports stripped of `.js` extensions.** Files under `src/captions/` imported siblings as `./types.js` and `./parser.js`. That is legal ESM TypeScript but Turbopack and several other bundlers refuse to resolve those specifiers against `.ts` files inside `node_modules`, breaking any consumer build that transitively pulled in the captions module. Captions now uses extensionless imports, matching the rest of the studio codebase.

### `@hyperframes/core`, `@hyperframes/cli`, `@hyperframes/engine`, `@hyperframes/producer`

Version bump only, no source changes since 0.2.5. Kept on the same version so the ecosystem is easier to reason about.

## Impact for consumers

If you use `@hyperframes/studio` in a Next.js app:
- The play button in a bundled preview reports the correct composition duration and drives the master timeline.
- The session page no longer 500s in dev mode when the studio barrel is imported (the SSR fix).
- Turbopack builds that transitively load the captions module no longer fail on `Cannot resolve './types.js'`.

If you use `@hyperframes/player` directly:
- Consumer bundlers can resolve the package again (dist entry points restored).
- The `ready` event duration reports the master, not a sub-composition.

## After merge

Publish each package to npm with `pnpm publish` (workspace deps auto-resolve).
2026-04-14 01:16:06 +02:00
Miguel Ángel bf0d698858 fix(studio): SSR-safe player load, captions import cleanup (#248)
* fix(studio): load @hyperframes/player lazily to support SSR

Player.tsx had a bare `import "@hyperframes/player"` at module scope. The
player package registers a class that extends HTMLElement as a side effect,
and HTMLElement doesn't exist in a Node server runtime. Any consumer that
imported from @hyperframes/studio during server-side rendering (e.g. the
Next.js App Router evaluating a client component for SSR) threw
`HTMLElement is not defined`.

Move the import inside the mount effect via dynamic `import(...)` so it
only runs in the browser, and wire up a cancellation flag and deferred
cleanup so a fast unmount doesn't leak listeners or DOM nodes.

* fix(studio): remove .js extensions from captions-internal imports

The captions module imported sibling files as `./types.js` and
`./parser.js`. That's legal ESM TypeScript, but Turbopack (and other
bundlers) refuse to resolve those specifiers against .ts files when the
package is consumed from node_modules — the rest of @hyperframes/studio
uses extensionless imports for that reason.

Align captions with the rest of the codebase so the package builds
without bundler-specific configuration in consumers.

* chore: release @hyperframes/player@0.2.7 and @hyperframes/studio@0.2.9

Ships the root-timeline resolution fix (#247), the SSR-safe player load,
and the captions import cleanup.
2026-04-14 00:15:16 +02:00
Miguel Ángel f40447f2e8 fix(player,studio): resolve root timeline from DOM instead of last key (#247)
Bundled previews register a master composition alongside its sub-compositions
in `window.__timelines`, e.g. { main, intro, scene2, scene5 }. Both the
player's probe and studio's getAdapter() were using `keys[keys.length - 1]`
to pick the adapter, which returned whichever timeline was registered last.

That made the player report the final sub-composition's duration as the
video length (e.g. 3.2s instead of the master's 14s) and play/pause/seek
targeted that sub-composition instead of the full composition.

Look up the outermost `[data-composition-id]` element in the iframe DOM
and use its id to select the right timeline. Falls back to last-key when
no element is present (standalone sub-composition previews) so drill-down
views keep working.

Also restores `main`/`import` entry points on @hyperframes/player to
point at compiled dist output (the src/ paths broke workspace consumers
that only receive the published tarball).
2026-04-13 23:15:08 +02:00
Miguel Ángel 1dd898786c chore: release v0.2.5 (#246) 2026-04-13 17:55:40 +02:00
Miguel Ángel 0da93cea3d feat(player): add speed control with popup menu and CSS theming (#241)
Add playback speed control to the player controls bar:
- Popup menu with logarithmic presets (0.25x-4x)
- Custom presets via speed-presets attribute
- Full CSS custom property theming (--hfp-accent, --hfp-controls-bg, etc.)
- ratechange event dispatch
- Exports: SPEED_PRESETS, formatSpeed, ControlsOptions
- Fix package.json export condition ordering
2026-04-10 20:47:12 +02:00
Miguel Ángel 3482441c9f feat(studio): use @hyperframes/player web component for preview (#238)
## Summary

- **Replaces the studio's hand-rolled iframe + scaling in** **`Player.tsx`** with the `<hyperframes-player>` web component, eliminating duplicated ResizeObserver, dimension detection, and stage-size message handling
- **Adds a public** **`iframeElement`** **getter** to the player web component so the studio's `useTimelinePlayer` can still access the inner iframe for clip manifest parsing, timeline probing, and DOM inspection
- **Updates player package exports** to resolve from source for workspace consumers (matching `@hyperframes/core` pattern), while npm-published consumers still get built `dist/` files

### Why a separate player package?

1. **Zero dependencies, any framework** — 12KB vanilla web component vs 940KB React+Zustand+CodeMirror studio
2. **CDN-ready** — single `<script>` tag, no build pipeline needed
3. **Embeddable by third parties** — users embed compositions in their own sites without the studio
4. **Single source of truth** — studio now uses the player instead of duplicating its scaling/detection logic

## Test plan

- [x] `pnpm --filter @hyperframes/player typecheck` passes
- [x] `pnpm --filter @hyperframes/studio typecheck` passes
- [x] `pnpm --filter @hyperframes/studio build` passes
- [x] `pnpm --filter @hyperframes/studio test` passes (2 pre-existing failures, unrelated)
- [x] E2E: Standalone player loads composition, detects 4s GSAP timeline, controls work, play/pause works
- [x] E2E: Studio preview renders via `<hyperframes-player>`, `iframeElement` bridge works, playback controls sync correctly
2026-04-10 03:00:54 +02:00
Miguel Ángel 7e7d41f833 docs(player): add README, bump to v0.2.4 (#236)
## Summary

- Add comprehensive README for `@hyperframes/player` covering installation, usage, full API reference (attributes, properties, methods, events), sizing, and distribution formats
- Bump version from 0.2.2 to 0.2.4 to align with monorepo release

## Test plan

- [x] Verify README renders correctly on GitHub
- [x] Confirm package.json version matches monorepo (0.2.4)
2026-04-10 01:57:52 +02:00
Miguel Ángel 5655dabff6 feat: allow clip animation + ship <hyperframes-player> web component (#209)
## Summary

Two independent initiatives that improve agent DX and expand HyperFrames' reach.

### Initiative 1: Fix the Clip Animation Footgun

- `gsap_animates_clip_element` lint rule now uses smart detection — only errors when GSAP animates `visibility` or `display` on a clip element
- All other properties (opacity, transform, x, y, scale, etc.) are allowed silently
- This was the #1 agent failure in QA (10/10 agents hit it on v0.2.1)

### Initiative 2: `<hyperframes-player>` Web Component

- New `@hyperframes/player` package — zero dependencies, 3.3KB gzipped
- Iframe-based web component with Shadow DOM for perfect isolation
- Video-like API: `play()`, `pause()`, `seek()`, `currentTime`, `duration`, events
- Controls overlay with play/pause, scrubber (mouse + touch), time display, auto-hide
- Full docs page at `docs/packages/player.mdx`

## Before / After

### Clip animation lint

**Before (10/10 agents hit this):**

```
✗ gsap_animates_clip_element: GSAP animation targets a clip element.
  Selector "#title" resolves to element <div id="title" class="clip">.
  The framework manages clip visibility — animate an inner wrapper instead.
  Fix: Wrap content in a child <div> and target that with GSAP.
```

**After (only errors on actual conflicts):**

```
# This passes lint — no error:
tl.from("#title", { opacity: 0, y: -50, scale: 0.8 }, 0);

# This still errors — actual conflict with runtime:
tl.to("#title", { visibility: "hidden" }, 3);
✗ gsap_animates_clip_element: GSAP animation sets visibility on a clip element.
  Fix: Remove the visibility/display tween. Use opacity for fade effects.
```

### Embeddable player

**Before:** No way to embed a composition in a web page.
**After:**

```html
<script src="https://cdn.jsdelivr.net/npm/@hyperframes/player"></script>
<hyperframes-player src="./composition/index.html" controls></hyperframes-player>
```

```js
const player = document.querySelector('hyperframes-player');
player.play();
player.pause();
player.seek(2.5);
player.addEventListener('ready', (e) => console.log('Duration:', e.detail.duration));
```

## Test plan

- [x] 427 core tests pass (20 GSAP lint tests with smart detection)
- [x] 7 player tests pass (formatTime + element registration)
- [x] TypeScript compiles cleanly (core + player)
- [x] Lint: GSAP animating clip with safe props → 0 errors
- [x] Lint: GSAP animating clip with `visibility` → 1 error (correct)
- [x] Player builds to 3.3KB gzipped ESM
- [x] Lockfile updated for CI
- [x] Docs page added at `docs/packages/player.mdx`
2026-04-06 19:59:39 +02:00