Files
hyperframes/docs/packages/studio-server.mdx
James RussoandClaude Opus 5.5 7f19f2335a feat(studio): load GSAP from the CLI's bundled copy by default (#6256)
* feat(studio): load GSAP from the CLI's bundled copy by default

Studio preview now loads the GSAP, CustomEase and MotionPathPlugin scripts
it adds from files the CLI ships and serves same-origin at /api/vendor/npm,
instead of jsDelivr. HYPERFRAMES_GSAP_BASE_URL still wins when set, and a
composition on another GSAP version gets its plugin from jsDelivr.

Renders now honor HYPERFRAMES_GSAP_BASE_URL when they replace a missing
local GSAP script, and the setting accepts plain http only for loopback
hosts.

Closes #6205

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

* refactor(studio): keep comment share flat for the GSAP local root

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

* fix(cli): find the installed gsap with node resolution when run from source

The Windows CI lane installs with the hoisted linker, so gsap is not under
packages/core/node_modules there.

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

* fix(producer): load a nested composition's missing GSAP from the mirror

A sub-composition's missing local gsap/dist script was hoisted into the
render unchanged, so HYPERFRAMES_GSAP_BASE_URL (and the jsDelivr fallback)
only reached the entry document. Run the same rewrite on every
sub-composition before it is compiled, resolving its path the way the
inliner will hoist it.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 03:08:42 +00:00

173 lines
7.2 KiB
Plaintext

---
title: "@hyperframes/studio-server"
description: "Mount the Studio project and preview API in your own server."
---
`@hyperframes/studio-server` is the backend used by Studio. It serves projects
and previews, applies source mutations, creates thumbnails, and starts render
jobs.
Most users do not need it. The CLI wires the server and Studio together when
you run `npx hyperframes preview`. Use this package only when your own
application must host the Studio backend.
```bash
npm install @hyperframes/studio-server
```
## Mount the API
`createStudioApi()` returns a Hono application. The adapter is the boundary
between Studio and your project storage, bundler, linter, and renderer.
```ts
import type { Hono } from "hono";
import {
createStudioApi,
type StudioApiAdapter,
} from "@hyperframes/studio-server";
export function mountStudioApi(
app: Hono,
adapter: StudioApiAdapter,
) {
app.route("/api", createStudioApi(adapter));
}
```
When it is served from loopback (`localhost`, `127.0.0.1` or `[::1]`), Studio
sends its API requests without cookies, so they don't queue behind the
preview's media. On any other origin it sends them as usual, so remote and
proxied setups (Codespaces, tunnels, an access proxy) keep their cookies by
default. A loopback host that authenticates its mounted API with same-origin
cookies sets `VITE_STUDIO_API_SAME_ORIGIN_CREDENTIALS=true`, at build time or at
runtime in `window.__HF_STUDIO_ENV__`; it costs that host the connection
speedup.
Studio reads the flag once, when its modules load, so set
`window.__HF_STUDIO_ENV__` before loading Studio; the CLI injects it, but a host
that mounts the API itself must inject it too.
A `StudioApiAdapter` supplies:
- project listing and resolution;
- composition bundling and linting;
- render output storage and job startup;
- optional thumbnails, sessions, registry installation, and background removal.
Use the interface exported by your installed version as the exact contract. It
changes as Studio gains capabilities.
`bundle(projectDir, options)` must pass `options` through to `bundleToSingleHtml`,
spread over your own options. The preview sets `stampHfIds` there so each element
is served with the id its source file mints. If a host drops it, a composition
the bundler inlines can be served with ids that a later save does not mint.
```ts
bundle: (dir, options) => bundleToSingleHtml(dir, { runtime: "inline", ...options }),
```
## Where Studio loads GSAP from
Studio adds GSAP scripts to previews when a composition needs them: the GSAP
core and CustomEase for motion you edit in Studio, and MotionPathPlugin for
motion paths. It picks the source in this order:
1. `HYPERFRAMES_GSAP_BASE_URL`, when set. Studio uses only that mirror and
never retries through jsDelivr.
2. The host's bundled copy, when the host passes `gsapLocalRoot`. The
HyperFrames CLI ships GSAP `3.15.0` and serves it from
`/api/vendor/npm`, so `npx hyperframes preview` makes no jsDelivr request for
these scripts. The bundled copy holds one version: a composition that loads
another GSAP version, such as `gsap@3.14.2`, still gets the matching plugin
from jsDelivr.
3. jsDelivr (`https://cdn.jsdelivr.net/npm`), for hosts without a bundled copy.
A host embedding this package opts in by serving the files and naming the
root:
```ts
gsapLocalRoot: "/api/vendor/npm", // serves /api/vendor/npm/gsap@3.15.0/dist/gsap.min.js
```
`gsapLocalRoot` must be a path on the preview's own origin, such as
`/api/vendor/npm`, with no query or fragment.
### Use your own mirror
Set `HYPERFRAMES_GSAP_BASE_URL` before starting the preview server or creating
the Studio API:
```bash
HYPERFRAMES_GSAP_BASE_URL=http://127.0.0.1:8080/vendor/npm \
npx hyperframes preview ./my-video
```
The mirror is an HTTP server, not a folder: a file path is refused. Serve the
GSAP distribution files under that URL with this layout, using the versions
your compositions need:
```text
<mirror-root>/gsap@3.15.0/dist/gsap.min.js
<mirror-root>/gsap@3.15.0/dist/CustomEase.min.js
<mirror-root>/gsap@3.15.0/dist/MotionPathPlugin.min.js
```
Keep `gsap@<version>` in authored GSAP URLs so the server can infer which
plugin version to add. When it cannot infer a version, it uses the framework's
default, currently `3.15.0`.
The base must be an absolute URL without credentials, a query string, or a
fragment. Use HTTPS. Plain `http://` is accepted only for this machine:
`localhost`, `127.0.0.0/8`, and `::1`. Surrounding whitespace and trailing
slashes are removed. An invalid nonempty value stops API startup with a
configuration error.
The server reads this setting once at startup. Restart it after changing the
value. For a managed CLI preview, run `npx hyperframes preview ./my-video --stop`
before starting it again with the new setting. Cached preview HTML is keyed
by the GSAP source, so a different mirror takes effect after restart
without deleting the preview cache.
Renders read the same setting. When a composition points at a local
`gsap/dist/` script that does not exist, the render compiler loads that file
from the mirror instead of jsDelivr and inlines it, as it does for other
remote scripts. An invalid value fails that render with the same
configuration error. Renders do not use the CLI's bundled copy.
This setting changes only GSAP scripts HyperFrames adds. Your composition's
own script, font, image, and media URLs stay as authored, including a GSAP
`<script>` that points at jsDelivr; serve those locally too for an offline
project. When Studio writes GSAP into a composition file, for example when you
add the first animation to a file without one, it writes the jsDelivr URL so
the file still renders outside Studio. If the selected mirror is unavailable or lacks a requested file,
Studio does not retry that dependency through jsDelivr.
## Other entry points
| Import | Purpose |
| --- | --- |
| `@hyperframes/studio-server/source-mutation` | Apply guarded changes to composition source |
| `@hyperframes/studio-server/screenshot-clip` | Calculate element screenshot geometry |
| `@hyperframes/studio-server/safe-path` | Resolve paths inside a project and walk its files, without the server |
| `@hyperframes/studio-server/hf-ids` | Stamp stable element ids into a project's HTML, without the server |
| `@hyperframes/studio-server/history` | Open a project's undo history, without the server |
| `@hyperframes/studio-server/manual-edits-render-script` | Reapply Studio manual edits during render |
| `@hyperframes/studio-server/studio-motion-render-script` | Reapply Studio motion edits during render |
| `@hyperframes/studio-server/draft-markers` | Work with draft gesture markers |
| `@hyperframes/studio-server/finite-mutation` | Guard source mutations against non-finite values |
| `@hyperframes/studio-server/media-proxy-preview` | Support proxied media in preview |
`@hyperframes/core/studio-api` remains a deprecated compatibility re-export.
New integrations should import from `@hyperframes/studio-server`.
## Related topics
<CardGroup cols={2}>
<Card title="@hyperframes/studio" icon="palette" href="/packages/studio">
Embed lower-level Studio interface components.
</Card>
<Card title="Studio guide" icon="display" href="/studio">
Use the complete editor that ships with HyperFrames.
</Card>
</CardGroup>