diff --git a/docs/docs.json b/docs/docs.json
index c6ae310bea..6048e8322c 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -323,6 +323,9 @@
"group": "Packages",
"pages": [
"packages/core",
+ "packages/parsers",
+ "packages/lint",
+ "packages/studio-server",
"packages/sdk",
"packages/engine",
"packages/player",
diff --git a/docs/packages/core.mdx b/docs/packages/core.mdx
index 22e41c7988..1938d5848a 100644
--- a/docs/packages/core.mdx
+++ b/docs/packages/core.mdx
@@ -177,6 +177,10 @@ const result = validateCompositionHtml(html);
### GSAP Script Parsing
+
+ The GSAP + HTML parsing layer now lives in its own standalone package, [`@hyperframes/parsers`](/packages/parsers). Core re-exports the API below for back-compat; import from `@hyperframes/parsers` directly in new code.
+
+
```typescript
import {
parseGsapScript,
@@ -243,6 +247,10 @@ const styles = getStageStyles('portrait');
## Linter
+
+ The composition linter now lives in its own package, [`@hyperframes/lint`](/packages/lint) — install it directly to lint a project or HTML string from Node without the CLI. `@hyperframes/core/lint` remains a back-compat re-export.
+
+
The composition linter checks for structural issues that would cause rendering failures or unexpected behavior. You can run it from the CLI with `npx hyperframes lint`, or call it programmatically:
```typescript
@@ -431,6 +439,15 @@ import type {
## Related Packages
+
+ The standalone GSAP + HTML parsing layer extracted from core.
+
+
+ The composition linter as a standalone library.
+
+
+ The mountable studio preview/editor backend.
+
The easiest way to create, preview, lint, and render compositions.
@@ -440,7 +457,4 @@ import type {
Full rendering pipeline built on top of core and engine.
-
- Visual composition editor that embeds the core runtime for preview.
-
diff --git a/docs/packages/lint.mdx b/docs/packages/lint.mdx
new file mode 100644
index 0000000000..2c8ea68c85
--- /dev/null
+++ b/docs/packages/lint.mdx
@@ -0,0 +1,112 @@
+---
+title: "@hyperframes/lint"
+description: "The composition linter as a standalone library — lint a directory or a single HTML file without the CLI."
+---
+
+The lint package is the composition linter extracted from core into a dedicated, independently-installable package. It's the **single source of truth** for linting: both the CLI's `hyperframes lint` command and the render-time render-gate consume the same rule engine from here.
+
+```bash
+npm install @hyperframes/lint
+```
+
+## When to Use
+
+
+ This package is the payoff of running validation **as a library** instead of shelling out to the CLI. A Node app (an agent harness, a CI step, an editor plugin) can `import { lintProject } from '@hyperframes/lint'` and lint a composition directory directly — no `npx hyperframes lint` subprocess, no stdout parsing.
+
+
+**Use `@hyperframes/lint` when you need to:**
+- Lint a composition project (an index + sub-compositions) from Node
+- Lint a single HTML string programmatically
+- Gate a render on lint findings (`shouldBlockRender`)
+- Surface lint findings in your own UI or CI annotations
+
+
+ `@hyperframes/core/lint` still resolves (via a back-compat re-export stub), so existing imports keep working. New code should import from `@hyperframes/lint` directly.
+
+
+## Package Exports
+
+The lint package has a single entry point:
+
+```typescript
+import {
+ lintHyperframeHtml,
+ lintMediaUrls,
+ lintProject,
+ shouldBlockRender,
+} from '@hyperframes/lint';
+import type {
+ HyperframeLintResult,
+ HyperframeLintFinding,
+ HyperframeLintSeverity, // "error" | "warning"
+ HyperframeLinterOptions,
+ ProjectLintResult,
+} from '@hyperframes/lint';
+```
+
+## Linting a Single Composition
+
+```typescript
+import { lintHyperframeHtml, lintMediaUrls } from '@hyperframes/lint';
+
+const result = lintHyperframeHtml(html, { filePath: 'index.html' });
+// result.ok, result.errorCount, result.warningCount, result.findings
+
+for (const finding of result.findings) {
+ console.log(finding.severity, finding.code, finding.message);
+ // finding.file, finding.selector, finding.elementId, finding.fixHint, finding.snippet
+}
+
+// Additional media URL validation
+const mediaFindings = lintMediaUrls(result.findings);
+```
+
+## Linting a Project
+
+`lintProject` walks a composition directory — the index plus any sub-compositions — and returns aggregated findings. It takes a **directory path string**, so it's callable from any Node context with nothing but a path:
+
+```typescript
+import { lintProject, shouldBlockRender } from '@hyperframes/lint';
+import type { ProjectLintResult } from '@hyperframes/lint';
+
+const result: ProjectLintResult = await lintProject('./my-composition');
+// result.totalErrors, result.totalWarnings, result.results[]
+// each result entry: { file, result: HyperframeLintResult }
+
+if (shouldBlockRender(result)) {
+ throw new Error(`Lint found ${result.totalErrors} blocking error(s)`);
+}
+```
+
+## What the Linter Catches
+
+Detected issues include:
+
+- Missing timeline registration (`window.__timelines`)
+- Unmuted video elements (causes autoplay failures)
+- Missing `class="clip"` on timed visible elements
+- Deprecated attribute names
+- Missing composition dimensions (`data-width`, `data-height`)
+- Invalid `data-start` references to nonexistent clip IDs
+
+
+ For a full list of what the linter catches and how to fix each issue, see [Common Mistakes](/guides/common-mistakes) and [Troubleshooting](/guides/troubleshooting).
+
+
+## Related Packages
+
+
+
+ The HTML + GSAP parsing layer the linter builds on.
+
+
+ Types and runtime; re-exports the linter for back-compat.
+
+
+ `npx hyperframes lint` wraps this package.
+
+
+ Surfaces lint findings in the editor.
+
+
diff --git a/docs/packages/parsers.mdx b/docs/packages/parsers.mdx
new file mode 100644
index 0000000000..658be7ea5a
--- /dev/null
+++ b/docs/packages/parsers.mdx
@@ -0,0 +1,157 @@
+---
+title: "@hyperframes/parsers"
+description: "The GSAP + HTML parser/writer suite — standalone, zero @hyperframes/* dependencies."
+---
+
+The parsers package is the standalone foundation extracted from core. It owns the GSAP animation parser/writer (recast **and** acorn implementations), the HTML composition parser, hf-id stamping, and spring-ease generation. It has **no `@hyperframes/*` dependencies**, so it's the base every other package builds on.
+
+```bash
+npm install @hyperframes/parsers
+```
+
+## When to Use
+
+
+ **Most users do not need to install `@hyperframes/parsers` directly.** [`@hyperframes/core`](/packages/core) re-exports the parser API it needs, and the [CLI](/packages/cli) / [studio](/packages/studio) depend on it transitively. Reach for it directly only when you want the parsing layer **without** pulling in the rest of core.
+
+
+**Use `@hyperframes/parsers` when you need to:**
+- Parse HTML compositions into structured TypeScript objects
+- Parse, edit, and re-serialize GSAP timeline scripts (AST round-trip)
+- Stamp deterministic `hf-id` attributes onto a document
+- Build tooling that touches the parsing layer but doesn't need core's runtime, compiler, or generators
+
+## Package Exports
+
+| Import | Description |
+|--------|-------------|
+| `@hyperframes/parsers` | HTML parser, GSAP serialize/validate helpers, hf-ids, shared types |
+| `@hyperframes/parsers/gsap-parser-acorn` | Acorn-based GSAP parser (browser-safe, read path) |
+| `@hyperframes/parsers/gsap-writer-acorn` | Acorn-based GSAP writer (mutation helpers) |
+| `@hyperframes/parsers/gsap-parser-recast` | Recast-based GSAP parser/writer (legacy implementation) |
+| `@hyperframes/parsers/gsap-constants` | `SUPPORTED_PROPS`, `SUPPORTED_EASES`, property groups |
+| `@hyperframes/parsers/spring-ease` | Spring-ease curve generation |
+| `@hyperframes/parsers/hf-ids` | Deterministic element id stamping |
+
+
+ The package ships subpath entries so consumers tree-shake to what they use — importing `@hyperframes/parsers/hf-ids` (a couple KB) does **not** pull in the GSAP AST machinery (recast/babel/acorn).
+
+
+## HTML Parsing
+
+Round-trip between HTML and structured data:
+
+```typescript
+import {
+ parseHtml,
+ extractCompositionMetadata,
+ validateCompositionHtml,
+} from '@hyperframes/parsers';
+import type { ParsedHtml, CompositionMetadata } from '@hyperframes/parsers';
+
+// Parse HTML into structured data
+const parsed: ParsedHtml = parseHtml(htmlString);
+// parsed.elements, parsed.gsapScript, parsed.styles, parsed.resolution, parsed.keyframes
+
+// Extract composition metadata (id, duration, dimensions, variables)
+const meta: CompositionMetadata = extractCompositionMetadata(htmlString);
+
+// Validate HTML structure
+const result = validateCompositionHtml(htmlString);
+// result.valid, result.errors
+```
+
+### Modifying HTML
+
+```typescript
+import {
+ updateElementInHtml,
+ addElementToHtml,
+ removeElementFromHtml,
+} from '@hyperframes/parsers';
+
+const updated = updateElementInHtml(html, 'el-1', { start: 5 });
+const added = addElementToHtml(html, newElement);
+const cleaned = removeElementFromHtml(html, 'el-1');
+```
+
+## GSAP Script Parsing
+
+The acorn parser/writer is the primary path (browser-safe). Parse a timeline script, mutate it, and serialize it back without losing surrounding code:
+
+```typescript
+import { parseGsapScriptAcorn, extractGsapLabels } from '@hyperframes/parsers/gsap-parser-acorn';
+import {
+ updateAnimationInScript,
+ addAnimationToScript,
+ removeAnimationFromScript,
+ updateKeyframeInScript,
+ addKeyframeToScript,
+ shiftPositionsInScript,
+ scalePositionsInScript,
+} from '@hyperframes/parsers/gsap-writer-acorn';
+import type { GsapAnimation, GsapMethod, ParsedGsap } from '@hyperframes/parsers';
+
+const parsed: ParsedGsap = parseGsapScriptAcorn(scriptContent);
+// parsed.animations, parsed.timelineVar, parsed.preamble, parsed.postamble
+
+// Mutation helpers operate on the script text and preserve unrelated code
+const next = updateAnimationInScript(scriptContent, animationId, { duration: 2 });
+```
+
+High-level serialize / validate / keyframe-conversion helpers are on the main entry:
+
+```typescript
+import {
+ serializeGsapAnimations,
+ getAnimationsForElementId,
+ validateCompositionGsap,
+ keyframesToGsapAnimations,
+ gsapAnimationsToKeyframes,
+} from '@hyperframes/parsers';
+```
+
+### GSAP Constants
+
+```typescript
+import {
+ SUPPORTED_PROPS, // animatable properties
+ SUPPORTED_EASES, // available easing functions
+ PROPERTY_GROUPS,
+} from '@hyperframes/parsers/gsap-constants';
+import type { PropertyGroupName } from '@hyperframes/parsers/gsap-constants';
+```
+
+## hf-ids
+
+Deterministic element identity for stable diffing and editing:
+
+```typescript
+import { ensureHfIds, mintHfId } from '@hyperframes/parsers/hf-ids';
+
+// Stamp hf-id attributes onto every editable element in a document
+const withIds = ensureHfIds(htmlString);
+```
+
+## Spring Ease
+
+```typescript
+import { generateSpringEaseData, SPRING_PRESETS } from '@hyperframes/parsers/spring-ease';
+```
+
+## Related Packages
+
+
+
+ Types, generators, runtime, and compiler — re-exports the parser API it needs.
+
+
+ The composition linter, built on the parsers.
+
+
+ The studio preview server, built on the parsers.
+
+
+ Create, preview, lint, and render compositions.
+
+
diff --git a/docs/packages/studio-server.mdx b/docs/packages/studio-server.mdx
new file mode 100644
index 0000000000..bb64483a19
--- /dev/null
+++ b/docs/packages/studio-server.mdx
@@ -0,0 +1,96 @@
+---
+title: "@hyperframes/studio-server"
+description: "The studio preview/editor backend — a mountable Hono API, extracted from core."
+---
+
+The studio-server package is the HTTP backend that powers studio preview and editing — project routes, file serving, preview bundling, thumbnails, and source-mutation helpers. It was extracted from `@hyperframes/core/studio-api` into a dedicated package so an embedder can mount the studio backend **without** depending on core's full surface, and so core no longer ships a web server it doesn't need at render time.
+
+```bash
+npm install @hyperframes/studio-server
+```
+
+## When to Use
+
+
+ **Most users do not need this package directly.** The [CLI](/packages/cli) (`npx hyperframes preview`) and [studio](/packages/studio) wire it up for you. Reach for it when you're **embedding** the studio backend into your own server.
+
+
+**Use `@hyperframes/studio-server` when you need to:**
+- Mount the studio preview/editing API into an existing Node/Hono server
+- Serve project files and bundled preview HTML to a custom frontend
+- Drive source mutations (manual edits, draft markers) from your own tooling
+
+
+ `@hyperframes/core/studio-api` still resolves (via a back-compat re-export stub), so existing imports keep working. New code should import from `@hyperframes/studio-server` directly.
+
+
+## Package Exports
+
+| Import | Description |
+|--------|-------------|
+| `@hyperframes/studio-server` | `createStudioApi`, helpers, types |
+| `@hyperframes/studio-server/screenshot-clip` | Element screenshot-clip geometry |
+| `@hyperframes/studio-server/manual-edits-render-script` | Manual-edits render body script |
+| `@hyperframes/studio-server/studio-motion-render-script` | Studio motion render body script |
+| `@hyperframes/studio-server/draft-markers` | Draft gesture-marker attributes |
+| `@hyperframes/studio-server/finite-mutation` | Finite-mutation safety checks |
+
+## Mounting the API
+
+`createStudioApi` returns a [Hono](https://hono.dev) app you can mount into any server. You supply a `StudioApiAdapter` that tells the API how to resolve projects, bundle preview HTML, and lint:
+
+```typescript
+import { createStudioApi } from '@hyperframes/studio-server';
+import type { StudioApiAdapter, ResolvedProject } from '@hyperframes/studio-server';
+
+const adapter: StudioApiAdapter = {
+ listProjects: () => projects,
+ resolveProject: (id) => projectsById.get(id) ?? null,
+ bundle: async (projectDir) => bundleToSingleHtml(projectDir),
+ lint: (html, opts) => lintHyperframeHtml(html, opts),
+ runtimeUrl: '/hyperframe-runtime.js',
+};
+
+const api = createStudioApi(adapter); // → Hono app
+
+// Mount under /api in your own Hono server
+app.route('/api', api);
+```
+
+The adapter is the seam between the framework-agnostic route logic and your storage / bundling / lint implementation — the [CLI](/packages/cli) supplies a filesystem-backed adapter, but you can back it with anything.
+
+## Helpers
+
+```typescript
+import {
+ createProjectSignature, // cache key for a project's files
+ isSafePath, // path-traversal guard
+ walkDir,
+ getMimeType,
+ buildSubCompositionHtml,
+ getElementScreenshotClip,
+} from '@hyperframes/studio-server';
+import type {
+ ResolvedProject,
+ RenderJobState,
+ LintResult,
+ ScreenshotClip,
+} from '@hyperframes/studio-server';
+```
+
+## Related Packages
+
+
+
+ The browser editor UI this server backs.
+
+
+ The HTML + GSAP parsing layer it builds on.
+
+
+ Types and runtime; re-exports the studio API for back-compat.
+
+
+ `npx hyperframes preview` wires this server up for you.
+
+