--- 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 /gsap@3.15.0/dist/gsap.min.js /gsap@3.15.0/dist/CustomEase.min.js /gsap@3.15.0/dist/MotionPathPlugin.min.js ``` Keep `gsap@` 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 `