# Tune.Toys — full agent reference

> Tune.Toys is a platform for making, playing and sharing audio instruments and effects as portable Toys: a node graph (the sound), a Frame (the playable interface) and assets in one JSON document that runs in the browser, in a DAW plugin and in exported plugins. The public HTTP API reads the catalog and releases, edits your own draft projects through revision-checked operations, and is described by an OpenAPI 3.1 document. Agents use developer API keys with explicit scopes; publication, billing and moderation always stay signed-in human actions.

Generated by tools/generate-llms.mjs from the repository; the OpenAPI document at https://tune.toys/v1/openapi.json is authoritative for request and response shapes.

## Product

## Product vision

Tune.Toys lets developers, musicians, curious users and agents create and distribute playable software. It begins with audio instruments and effects and keeps a foundation for logic applications, sensing, education, creative tools and connected systems as their runtimes are qualified.

### The creative loop

A recipient reaches a playable web experience from a link. A musician bookmarks it and finds it in TuneToys Player inside a DAW. A developer ships a separate plugin with its own identity and branding. A plugin company could eventually run its catalog, licensing, updates and distribution on the platform.

### Vocabulary

| Term               | Meaning                                                                            |
| ------------------ | ---------------------------------------------------------------------------------- |
| Toy                | The portable authored creation; can be a component or complete application         |
| Patch              | Familiar editor/community term for a Toy graph, not a separate file model          |
| Definition / group | Reusable implementation with typed ports and public parameters                     |
| Instance           | One use of a definition with independent values, DSP state, and observations       |
| Frame              | Explicit playable UI bound to one definition in an instance context                |
| Project            | Editable Toy source and working assets/history                                     |
| Release            | Immutable resolved content plus evidence and distribution terms                    |
| Catalog entry      | Mutable title/discovery/visibility metadata pointing to releases                   |
| Library            | A user's bookmarks, tags, ratings, acquisitions, and installed/cached releases     |
| Player             | TuneToys plugin/application that loads Toys; not a general third-party plugin host |
| Independent plugin | A compiled Toy exported under its own persistent plugin identity                   |

A Toy inside a Toy uses the same composition system as an ordinary reusable group. Reusing a definition shares immutable code and assets; each instance keeps its own runtime state. Forking creates a new project identity and preserves provenance. Remodeling an interface never silently changes the processing graph. The contracts behind these terms are the [Toy source format](../specs/toy-format.md) and [releases](../specs/releases.md).

### Example journeys

A maker builds a stereo effect, asks an agent to expose a useful macro and create a three-knob Frame, auditions the proposal and shares a link. A recipient plays it, bookmarks it and opens the same release in the Player. Reopening the DAW project without internet restores the same sound.

Later, a developer creates a face-controlled synth. Camera inference produces bounded control data outside the audio callback. The web export requests camera access; a native plugin declares whether camera control is available and provides a fallback. A Frame can instead control a separately running host through an authenticated session. Local execution and remote control are explicit modes.

### Durable principles

- One authored model connects behavior, public controls, Frames, assets, presets and provenance.
- Humans and agents use the same authoring API.
- The audio engine runs without an open editor, an active account connection or a live model.
- Published source and remix access follow declared terms; private work stays private across dependencies, previews and builds.

The long-term target set is web hosting and self-hosted static sites, Player, independent VST3/AU plugins, Electron desktop apps, browser extensions, mobile apps and eventually firmware. **Each target earns support through implementation and tests.** Being expressible as JSON does not make a Toy portable to every host.

### Related

- [MVP scope](mvp.md) turns this into acceptance criteria; the [roadmap](../delivery/roadmap.md) orders the gates.
- [System architecture](../architecture/overview.md) and [decision 0001](../decisions/0001-portable-model.md) implement the one-model principle.

## Developer platform

## Developer platform

How do scripts, publisher automation and local agents use Tune.Toys without a browser session, and how does the API describe itself? Developer apps hold scoped API keys; the dispatcher authenticates keys, rate-limits and meters them with database-backed buckets; pro apps receive signed webhooks; and an OpenAPI 3.1 document, JSON Schemas at their `$id` URLs, `llms.txt` and an MCP server are generated from the same route declarations that the server dispatches.

**Status:** Implemented locally (WP-12). Numbers marked _proposed_ are defaults pending the owner decision on advertised API limits and terms ([scope decision 5](../delivery/sprints/v0.0.2/00-scope-and-decisions.md)). Third-party OAuth, a hosted MCP endpoint, paid usage packs and CORS for browser-side keys are planned, not implemented. The plan is [12 Developer platform](../delivery/sprints/v0.0.2/12-developer-platform.md); the wire contract is [the HTTP API](../specs/http-api.md#developer-api-keys).

### Quickstart

1. Sign in, open **Settings → Developer**, create an app and a key. New keys get `read:public` only; tick each extra scope. The full key (`tt_<prefix>_<secret>`) is shown once.
2. Call the API with the key as a bearer token. Never send cookies with it.

```sh
curl -H "Authorization: Bearer $TUNETOYS_API_KEY" https://tune.toys/v1/catalog?q=delay
curl -H "Authorization: Bearer $TUNETOYS_API_KEY" https://tune.toys/v1/developer/key
```

3. From TypeScript, `new PlatformClient('https://tune.toys/v1', fetch, { apiKey })` sends the bearer, omits credentials and skips CSRF. It refuses to run in a browser page unless `allowBrowserKey` is passed.
4. For agents, run the [MCP server](../../packages/mcp/README.md) with `TUNETOYS_API_KEY`.

The machine-readable reference is `GET /v1/openapi.json`, browsable at `/developers` (Swagger UI from the pinned `swagger-ui-dist`, no CDN; "Try it out" sends `credentials: 'omit'`).

### Authentication and keys

| Property     | Behavior                                                                                                                                                                                                                     |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Wire format  | `tt_<prefix>_<secret>`: 8 lowercase base32 characters, then 43 base64url characters of 32 random bytes and a 6-character CRC32 checksum (`^tt_[a-z2-7]{8}_[A-Za-z0-9_-]{49}$`). The checksum rejects typos without a lookup. |
| Presentation | `Authorization: Bearer tt_…` or `X-TuneToys-Key: tt_…`. A key with a cookie, a second key header or any other Authorization value is `400 MIXED_AUTH`.                                                                       |
| Storage      | Only `HMAC-SHA256(pepper, key)`. The pepper is `TUNETOYS_API_KEY_PEPPER` (64 hex) or, when unset, derived from the native authorization key all API tasks share. Rotating either invalidates every key and webhook secret.   |
| Lifetime     | 30, 90 (default) or 365 days; no non-expiring keys. Rotation issues a replacement with the same scopes and keeps the old key for an overlap (default 24 h, at most 7 days).                                                  |
| Revocation   | Immediate on this instance; other instances drop cached key rows within 30 s. `POST /v1/developer/key/revoke` lets a leaked key revoke itself. Deleting an app revokes its keys and disables its webhooks.                   |
| Network      | Optional IP allowlist of up to 16 CIDR entries, checked against the client address (`403 KEY_NETWORK`).                                                                                                                      |
| Acting user  | The key's creator. Handlers run their normal owner and visibility checks; scopes never widen them.                                                                                                                           |
| Last used    | Written at most once per minute per key.                                                                                                                                                                                     |
| Audit        | App, key, webhook and tier changes with actor, key prefix and a hashed address; visible to the app owner.                                                                                                                    |

| Scope                | Allows                                                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `read:public`        | Catalog, listings, releases and release bytes                                                                                         |
| `read:library`       | Library, bookmarks and sync                                                                                                           |
| `write:library`      | Bookmark, annotate and remove library items                                                                                           |
| `read:projects`      | Own draft projects                                                                                                                    |
| `write:projects`     | Create drafts, save, apply revision-checked operation batches and fork. Never publishes.                                              |
| `read:products`      | Own publishers' products and listings; needed for product webhooks                                                                    |
| `write:listings`     | Listing draft fields, assets, documents and translations. Never publishes or changes visibility                                       |
| `read:usage`         | The key's own app usage                                                                                                               |
| `read:notifications` | Reserved for notification inbox reads                                                                                                 |
| `publish:releases`   | Create versions, upload artifacts and publish releases for your publisher; the only way to register `signed` or `notarized` artifacts |

Keys never reach billing, native device authorization, account authentication, developer app/key/webhook management, moderation, release/listing/storefront publication, visibility changes or server agent proposals. Those route declarations omit `key` from `auth`, so the denial is structural (`403 AUTH_MODE`), and `services/api/test/openapi.test.mjs` fails if one gains it.

Key requests are exempt from Origin, `X-TuneToys-Request` and CSRF checks because they carry no ambient credential. Bodies must still be `application/json` (`415` otherwise) and routes that declare `idempotency: 'required'` need an `Idempotency-Key`. No CORS headers are sent for `/v1`.

### Rate limits and quotas

Keys and anonymous reads use GCRA token buckets stored in `api_rate_buckets`, so limits hold across API instances without Redis. A process-local bucket with the same parameters rejects floods before the database; after each database decision it adopts the shared arrival time. Signed-in browser sessions keep the existing 600/minute fixed window and named limits (auth, proposals, checkout, native grants, listing writes).

| Bucket (per minute, burst) _proposed_ | Anonymous (per address) | Free key | Pro key   |
| ------------------------------------- | ----------------------- | -------- | --------- |
| read                                  | 120, 60                 | 300, 100 | 3000, 600 |
| write                                 | not limited here¹       | 30, 10   | 300, 60   |
| expensive                             | 10, 5                   | 20, 10   | 240, 60   |
| Rolling 24 h request quota            | none                    | 10 000   | 500 000   |

¹ Anonymous writes (registration, login) keep the 600/minute window and their named limits.

Weights come from each route's `cost`: list and sync pages 2, release package/engine/asset bytes 5, webhook test sends 25 in `expensive`, and `0` (no bucket) for `/v1/developer/key`, `/v1/developer/limits`, `/v1/developer/scopes` and `/v1/openapi.json`. Daily byte quotas are recorded in usage but not enforced yet.

Every limited response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (seconds) for the most constrained bucket. A rejection is `429 RATE_LIMIT` with `Retry-After` and `details: {bucket, limit, remaining, resetSeconds, retryAfterSeconds, quota}`; `bucket` is `daily` for the quota. The first quota rejection per key per day notifies the owner (`api_limit_reached`).

Anonymous limits key on the client address from the router's trusted-proxy rule: the socket peer, or the right-most untrusted `X-Forwarded-For` hop when the peer is a configured trusted proxy (`TUNETOYS_TRUSTED_PROXIES`). Without that configuration a load balancer makes every caller share one address; configure it before relying on per-address limits.

### Tiers and usage

`developer_apps.tier` records the last observed effective tier. The effective tier is `pro` while the app owner holds an active `feature:api.pro` grant (the `TuneToys Developer API` billing offer) and `free` otherwise, cached 60 s. A change writes a `tier_changed` audit event and an `api_tier_changed` notification; a downgrade pauses active webhooks without deleting them and an upgrade resumes them. Keys never purchase anything; upgrades go through Settings → Billing.

Usage accumulates in process per key and UTC hour and flushes every 30 s (and before usage reads and on shutdown) as additive upserts into `api_usage`: accepted requests, `429` rejections and response bytes. A crash may lose up to 30 s of counts; usage is informational until a paid pack needs an exact ledger. Usage is kept 90 days; `GET /v1/developer/apps/{appId}/usage` returns zero-filled hourly or daily series with per-key totals and `usage.csv` exports `window_start,key_prefix,requests,rejected,bytes_out`. Keys expiring within 7 days and 1 day notify the owner (`api_key_expiring`) from the hourly sweep.

### Webhooks (pro)

| Topic        | Behavior                                                                                                                                                                                                                                               |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Events       | `version_published`, `listing_updated`, `review_created`, `purchase_completed`, `update_feed_changed` for products of the app's publisher (or the owner's personal publisher), when the app has a live key with `read:products`                        |
| Payload      | Thin: `{id, type, createdAt, apiVersion, data}` where `data` holds ids and minimal fields (at most 1 KiB). Fetch details through the API.                                                                                                              |
| Signature    | `TuneToys-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, t + "." + body)>` plus `TuneToys-Webhook-Id` and `TuneToys-Event-Id`. Receivers reject `t` older than five minutes and deduplicate on the event ID; the SDK exports `verifyWebhook`. |
| Secret       | `whsec_…`, 32 random bytes, shown once, stored AES-256-GCM encrypted under a key derived from the pepper                                                                                                                                               |
| Endpoint     | Public HTTPS only. The resolved address is checked at connect time against private, loopback, link-local and other reserved ranges; no redirects; 10 s timeout; 64 KiB read limit                                                                      |
| Verification | Creation (and URL changes or re-enabling) sends `webhook.verify` with `data.challenge`; a 2xx JSON response echoing `{"challenge": …}` makes the webhook `active`                                                                                      |
| Retries      | Eight attempts: immediately, then after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h. Each attempt is a row; after the last failure a webhook with no success in three days is `disabled`                                                             |
| Dispatcher   | Leased (`lease_until`) runner in the API process every 5 s; HTTP runs outside transactions. Test sends and manual redelivery queue rows and wake it                                                                                                    |

Other packages emit events with `emitWebhookEvent(db, {type, publisherId, data})` from `services/api/src/webhooks.ts`. It only inserts delivery rows, so it is safe inside the caller's transaction, and returns the number queued. `version_published` is emitted from version publication in `versions.ts` (deterministic event ID per version). `listing_updated` (listing publish in `listings.ts`), `review_created` (review creation in `posts-store.ts`/`posts-routes.ts`), `purchase_completed` (grant creation in `billing.ts`) and `update_feed_changed` (`appendUpdateFeeds` in `distribution.ts`) are not wired yet; each owner adds one `emitWebhookEvent` call with thin ids in its existing transaction.

### Agent-facing documents

| Path                                      | Source                                                                                                                                                                                       |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /v1/openapi.json`                    | `packages/platform-contracts/openapi.json` from `npm run generate:openapi` (strong ETag, 5-minute cache)                                                                                     |
| `GET /developers`                         | Swagger UI over the document                                                                                                                                                                 |
| `GET /schemas/index.json`, `/schemas/...` | Every platform contract at `https://tune.toys/schemas/platform/<name>.schema.json` and the Toy schema at `/schemas/toy-0.1.0.schema.json`                                                    |
| `GET /llms.txt`, `/llms-full.txt`         | `packages/platform-contracts/llms/` from `npm run generate:llms`: summary and links; full reference with this guide, MCP tools, operations, schemas, Toy format and node summaries (≤ 1 MiB) |

The OpenAPI document embeds the platform-contract and Toy schemas whole in `components.schemas` with their `$id`s, so relative references between contract files keep resolving, and adds shared error responses, `RateLimit-*` headers, security schemes (`sessionCookie`, `apiKey`, `apiKeyHeader`, `nativeBearer`), per-operation scopes and the extensions `x-tunetoys-stability`, `x-tunetoys-auth`, `x-tunetoys-scopes`, `x-tunetoys-rate-bucket` and `x-tunetoys-cost`. Internal routes (OAuth callbacks, signed webhooks, public HTML) are served but omitted. Pre-1.0 schemas still change in place, so they are cached for an hour rather than marked immutable.

### Differences from the plan

| Plan item                                                                                           | Implemented                                                                                                                                                                         |
| --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Session GCRA buckets (600/min read for sessions)                                                    | Not enabled: browser sessions keep the existing fixed window so signed-in behavior is unchanged until the owner sets advertised limits                                              |
| Daily bytes-out quota                                                                               | Recorded in usage; not enforced                                                                                                                                                     |
| Pepper file for SQLite (`<database>.api-key-pepper`)                                                | Derived from the native authorization key (already a stable per-deployment secret, with its own file for SQLite) unless `TUNETOYS_API_KEY_PEPPER` is set                            |
| Webhook payload storage                                                                             | The final schema has no event table, so `api_webhook_deliveries.event_id` stores a self-describing `evt.<base64url>` token with the thin payload; every attempt signs the same body |
| Webhook secret rotation with two signatures, `DELETE` webhooks                                      | Not implemented (one secret column; deliveries reference the row). Disable a webhook with `PATCH {state: 'disabled'}`; receivers already accept several `v1=` values                |
| Delivery log latency, error class and response excerpt                                              | Only status and state are stored (final schema)                                                                                                                                     |
| Publisher-role intersection for publisher apps                                                      | Keys act as their creator through each handler's own publisher-role checks; no separate 60 s role cache                                                                             |
| Keys revoked on password reset or account deletion                                                  | Not yet wired; app deletion revokes its keys                                                                                                                                        |
| `x-tunetoys-cost` object, `TuneToys-API-Version` header, `Deprecation`/`Sunset`, `api-changelog.md` | Cost is split into `x-tunetoys-rate-bucket` and `x-tunetoys-cost`; version headers, deprecation headers and the changelog check are planned                                         |
| Servers `https://tune.toys/v1`                                                                      | Servers are origins (`https://tune.toys`, `http://127.0.0.1:8787`) and paths keep `/v1`, matching the route declarations                                                            |
| Swagger UI at `/developers/api`                                                                     | Served at `/developers` on the API origin                                                                                                                                           |
| Immutable versioned schema file names                                                               | Current `$id`s are unversioned for platform contracts; cached for an hour because pre-1.0 contracts change in place                                                                 |
| MCP `propose_operation_batch` / `apply_operation_batch`                                             | Named `propose_operations` / `apply_operations`; plus `get_listing` and `validate_toy_json`                                                                                         |
| `health` and `config` for keys                                                                      | Not key-accessible yet (deny by default; they live in `server.ts`)                                                                                                                  |

### Related

- [HTTP API](../specs/http-api.md#developer-api-keys) — wire contract and error codes
- [Human and agent authoring](authoring-agents.md) — the revision rules every agent write follows
- [Security](security.md)
- [MCP server](../../packages/mcp/README.md) and [SDK](../../packages/sdk/README.md)

## MCP server

## MCP server

`@tunetoys/mcp` is a stdio [Model Context Protocol](https://modelcontextprotocol.io) server that lets a local agent (Claude Desktop, Claude Code or another MCP client) search the Tune.Toys catalog, read node documentation, validate Toy JSON and make bounded, revision-checked edits to your own drafts.

**Status:** Implemented (WP-12), private package, not yet published to npm. A hosted remote MCP endpoint needs OAuth for users and is planned with that work.

It is an ordinary API client: every network call goes through [`@tunetoys/sdk`](../sdk/README.md) with your developer API key, so the server gets exactly the key's scopes, rate limits and owner checks. Built on the pinned official TypeScript SDK `@modelcontextprotocol/sdk` 1.32.1 (MIT) and `zod` 4.6.7.

### Configuration

| Variable            | Default                | Meaning                                                                      |
| ------------------- | ---------------------- | ---------------------------------------------------------------------------- |
| `TUNETOYS_API_KEY`  | none                   | Developer API key (`tt_…`). Without it only the anonymous read tools appear. |
| `TUNETOYS_API_BASE` | `https://tune.toys/v1` | API base, for example `http://127.0.0.1:8787/v1` for a local API.            |

Create the key in Settings → Developer with only the scopes the agent needs. On start the server calls `GET /v1/developer/key` and lists tools for those scopes.

Claude Code:

```sh
claude mcp add tunetoys --env TUNETOYS_API_KEY=tt_… -- node /path/to/TuneToys/packages/mcp/src/main.ts
```

Claude Desktop (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "tunetoys": {
      "command": "node",
      "args": ["/path/to/TuneToys/packages/mcp/src/main.ts"],
      "env": { "TUNETOYS_API_KEY": "tt_…" }
    }
  }
}
```

Node 24 runs the TypeScript entry directly. Keep the key in the client's secret configuration, never in a repository.

### Tools

| Tool                    | Needs                   | Behavior                                                                                                          |
| ----------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `search_catalog`        | none                    | Catalog search with text, category and offset                                                                     |
| `get_listing`           | none                    | One public or accessible Toy listing                                                                              |
| `get_product`           | none                    | Product versions and rating summary when visible to the key                                                       |
| `get_node_docs`         | none                    | Node contract (ports, parameters) and documentation; local, no network                                            |
| `get_toy_source`        | none or `read:projects` | Release by digest, or your own draft with `read:projects`                                                         |
| `validate_toy_json`     | none                    | `@tunetoys/toy-format` validation with diagnostics; local, no network                                             |
| `list_my_projects`      | `read:projects`         | Your drafts                                                                                                       |
| `propose_operations`    | `read:projects`         | Applies an operation batch locally against the current revision and reports the result; writes nothing            |
| `create_draft_project`  | `write:projects`        | Validates and creates a private draft                                                                             |
| `apply_operations`      | `write:projects`        | `POST /v1/projects/{id}/operations` with expected version and revision and a fresh idempotency key; never retried |
| `update_listing_fields` | `write:listings`        | Saves listing draft overrides at an expected version; does not publish                                            |

### Safety model

- Write tools carry `destructiveHint` so clients ask before calling them, accept at most 64 operations per batch and share a budget of 20 write calls per server process (proposed default).
- Conflicts surface as tool errors with the API's code (`VERSION_CONFLICT`, `REVISION_CONFLICT`); the agent must re-read and propose again.
- No tool publishes, changes visibility, spends model budget, uploads media or touches billing; the API also denies those routes to every key structurally.

### Tests

`node --test packages/mcp/test/*.test.mjs` covers tool listing per scope, closed input schemas, destructive annotations, local validation and node docs, key headers without cookies and the write budget. See [test/README.md](test/README.md).

## Operations

- `GET /v1/account/locale` (`getAccountLocale`) — Account language and time zone. Auth: session; bucket read × 1; experimental.
- `PUT /v1/account/locale` (`setAccountLocale`) — Set account language (UI, email, push) and time zone (digests, quiet hours). Auth: session; bucket write × 1; experimental.
- `GET /v1/addons` (`listEnabledAddons`) — List the addons this account has enabled. Auth: session; bucket read × 1; experimental.
- `PUT /v1/addons` (`putEnabledAddons`) — Replace the set of enabled addons for this account. Auth: session; bucket write × 1; experimental.
- `POST /v1/agent/proposals` (`createAgentProposal`) — Generate a revision-bound Toy edit proposal from a recipe brief. Auth: session; bucket write × 1; experimental.
- `POST /v1/ai/complete` (`completeAi`) — Complete a chat with Anthropic, OpenAI or Gemini using the caller’s own vault key. Auth: session; bucket write × 1; experimental.
- `GET /v1/ai/models` (`getAiModels`) — Pinned model suggestions per provider and the caller’s daily allowance. Auth: session; bucket read × 1; experimental.
- `GET /v1/artifacts/{id}/bytes` (`getArtifactBytes`) — Download a free or browser artifact with digest verification. Auth: anonymous, session, native; bucket read × 1; experimental.
- `POST /v1/artifacts/{id}/tickets` (`createDownloadTicket`) — Issue a one-time, 15-minute download ticket (anonymous for free public artifacts). Auth: anonymous, session, native; bucket write × 1; experimental.
- `POST /v1/auth/email` (`setAccountEmail`) — Add or resend verification for a recovery address. Auth: session; bucket write × 1; experimental.
- `POST /v1/auth/login` (`signIn`) — Create a handle/password session. Auth: anonymous, session; bucket write × 1; experimental.
- `POST /v1/auth/logout` (`signOut`) — Revoke the current session and expire its cookie. Auth: session; bucket write × 1; experimental.
- `GET /v1/auth/me` (`getCurrentAccount`) — Read the current account and browser CSRF token. Auth: anonymous, session, native; bucket read × 1; experimental.
- `POST /v1/auth/oauth/{provider}/start` (`startOAuth`) — Start provider sign-in or explicit identity linking. Auth: anonymous, session; bucket write × 1; experimental.
- `GET /v1/auth/options` (`getAuthOptions`) — List sign-in providers and email delivery availability. Auth: anonymous, session; bucket read × 1; experimental.
- `POST /v1/auth/password` (`changePassword`) — Set or replace the caller's password and end their other browser sessions. Auth: session; bucket write × 1; experimental.
- `GET /v1/auth/profile` (`getAuthProfile`) — Read owner-only email and connected-method metadata. Auth: session; bucket read × 1; experimental.
- `PATCH /v1/auth/profile` (`updateAuthProfile`) — Change the caller's display name. Auth: session; bucket write × 1; experimental.
- `POST /v1/auth/recover` (`recoverAccount`) — Request password recovery email. Auth: anonymous, session; bucket write × 1; experimental.
- `POST /v1/auth/register` (`registerAccount`) — Create a handle/password account and session. Auth: anonymous, session; bucket write × 1; experimental.
- `POST /v1/auth/reset-password` (`resetPassword`) — Consume a reset token and replace the password. Auth: anonymous, session; bucket write × 1; experimental.
- `POST /v1/auth/verify-email` (`verifyEmail`) — Consume an email verification token. Auth: anonymous, session; bucket write × 1; experimental.
- `POST /v1/billing/checkout` (`createCheckout`) — Start a hosted checkout for an offer. Auth: session; bucket write × 1; experimental.
- `GET /v1/billing/entitlements` (`listBillingEntitlements`) — List the caller's entitlements. Auth: session, native; bucket read × 1; experimental.
- `GET /v1/billing/options` (`getBillingOptions`) — List configured offers. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/billing/orders` (`listBillingOrders`) — List the caller's orders. Auth: session; bucket read × 1; experimental.
- `POST /v1/billing/orders/{orderId}/portal` (`openBillingPortal`) — Open the provider billing portal for an order. Auth: session; bucket write × 1; experimental.
- `POST /v1/billing/orders/{orderId}/sync` (`synchronizeBillingOrder`) — Reconcile an order with the provider. Auth: session; bucket write × 1; experimental.
- `GET /v1/catalog` (`getCatalog`) — Search the public catalog. Auth: anonymous, session, native, key; scopes: read:public; bucket read × 2; experimental.
- `GET /v1/certificates` (`listLicenseCertificates`) — The caller's certificates with offline states. Auth: session, native; bucket read × 1; experimental.
- `POST /v1/certificates/{id}/refresh` (`refreshLicenseCertificate`) — Refresh a certificate, or learn that it was revoked. Auth: session, native; bucket write × 1; experimental.
- `GET /v1/community/activity` (`listCommunityActivity`) — List activity from followed accounts. Auth: session; bucket read × 1; experimental.
- `PUT /v1/community/avatar` (`setCommunityAvatar`) — Set the caller's avatar from owned media. Auth: session; bucket write × 1; experimental.
- `GET /v1/community/avatars/{avatarId}` (`getCommunityAvatar`) — Read avatar image bytes. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/community/blocks` (`listBlockedAccounts`) — List accounts the caller blocked. Auth: session; bucket read × 1; experimental.
- `POST /v1/community/collections` (`createCollection`) — Create a collection. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/community/collections/{collectionId}` (`deleteCollection`) — Delete a collection at an expected version. Auth: session; bucket write × 1; experimental.
- `GET /v1/community/collections/{collectionId}` (`getCollection`) — Read a collection page. Auth: anonymous, session; bucket read × 1; experimental.
- `PUT /v1/community/collections/{collectionId}` (`updateCollection`) — Update a collection. Auth: session; bucket write × 1; experimental.
- `PUT /v1/community/collections/{collectionId}/items` (`setCollectionSubject`) — Add, move or remove a Toy or sound in a collection by subject (subjectType project|media). Auth: session; bucket write × 1; experimental.
- `PUT /v1/community/collections/{collectionId}/toys/{toyId}` (`setCollectionItem`) — Add, move or remove a Toy in a collection. Auth: session; bucket write × 1; experimental.
- `GET /v1/community/invitations` (`listInvitations`) — List the caller's pending project invitations. Auth: session; bucket read × 1; experimental.
- `PUT /v1/community/profile` (`updateCommunityProfile`) — Update the caller's community profile. Auth: session; bucket write × 1; experimental.
- `GET /v1/community/profiles/{handle}` (`getCommunityProfile`) — Read a public profile. Auth: anonymous, session; bucket read × 1; experimental.
- `PUT /v1/community/profiles/{handle}/block` (`setProfileBlock`) — Block or unblock a profile. Auth: session; bucket write × 1; experimental.
- `GET /v1/community/profiles/{handle}/collections` (`listProfileCollections`) — List a profile's collections. Auth: anonymous, session; bucket read × 1; experimental.
- `PUT /v1/community/profiles/{handle}/follow` (`setProfileFollow`) — Follow or unfollow a profile. Auth: session; bucket write × 1; experimental.
- `GET /v1/community/profiles/{handle}/followers` (`listProfileFollowers`) — List a profile's followers. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/community/profiles/{handle}/following` (`listProfileFollowing`) — List a profile's followed accounts. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/community/profiles/{handle}/likes` (`listProfileLikes`) — List Toys a profile liked. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/community/profiles/{handle}/toys` (`listProfileToys`) — List a profile's public Toys. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/community/projects/{projectId}/assets/{assetId}` (`getSharedProjectAsset`) — Download a shared project media asset. Auth: session; bucket read × 1; experimental.
- `POST /v1/community/projects/{projectId}/edits` (`applyCollaborativeEdit`) — Apply a collaborative project edit. Auth: session; bucket write × 1; experimental.
- `POST /v1/community/projects/{projectId}/invitation` (`respondProjectInvitation`) — Accept or decline a project invitation. Auth: session; bucket write × 1; experimental.
- `POST /v1/community/projects/{projectId}/members` (`inviteProjectMember`) — Invite a project member. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/community/projects/{projectId}/members/{accountId}` (`removeProjectMember`) — Remove a project member. Auth: session; bucket write × 1; experimental.
- `PUT /v1/community/projects/{projectId}/presence` (`updatePresence`) — Publish collaboration presence. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/community/projects/{projectId}/presence/{sessionId}` (`leavePresence`) — End a collaboration presence session. Auth: session; bucket write × 1; experimental.
- `GET /v1/community/projects/{projectId}/state` (`getCollaborationState`) — Read collaboration state since a source version. Auth: session; bucket read × 1; experimental.
- `GET /v1/community/reports` (`listReports`) — List reports for moderators. Auth: session; bucket read × 1; experimental.
- `POST /v1/community/reports` (`createReport`) — Report content or an account. Auth: session; bucket write × 1; experimental.
- `PATCH /v1/community/reports/{reportId}` (`reviewReport`) — Review a report as a moderator. Auth: session; bucket write × 1; experimental.
- `GET /v1/community/shared` (`listSharedProjects`) — List projects shared with the caller. Auth: session; bucket read × 1; experimental.
- `GET /v1/community/toys/{toyId}/likes` (`getToyLikes`) — Read like count and caller state for a Toy. Auth: anonymous, session; bucket read × 1; experimental.
- `PUT /v1/community/toys/{toyId}/likes` (`setToyLike`) — Like or unlike a Toy. Auth: session; bucket write × 1; experimental.
- `GET /v1/config` (`getConfig`) — Whether server text proposals are configured. Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/connections` (`listConnections`) — List connected services (labels and scopes, never tokens). Auth: session; bucket read × 1; experimental.
- `DELETE /v1/connections/{id}` (`deleteConnection`) — Disconnect a service and revoke its grant at the provider. Auth: session; bucket write × 1; experimental.
- `GET /v1/connections/{id}/files` (`listDriveFiles`) — List app-visible Drive files (parent, name search, page token). Auth: session; bucket read × 1; experimental.
- `POST /v1/connections/{id}/files` (`createDriveFile`) — Create a Drive file from the raw request body (≤ 64 MiB); name, mimeType and parent in the query. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/connections/{id}/files/{fileId}` (`deleteDriveFile`) — Delete a Drive file the app can see. Auth: session; bucket write × 1; experimental.
- `GET /v1/connections/{id}/files/{fileId}` (`getDriveFile`) — Read Drive file metadata. Auth: session; bucket read × 1; experimental.
- `PATCH /v1/connections/{id}/files/{fileId}` (`updateDriveFile`) — Rename (JSON { name }) or replace the bytes (raw body ≤ 64 MiB) of a Drive file. Auth: session; bucket write × 1; experimental.
- `GET /v1/connections/{id}/files/{fileId}/content` (`downloadDriveFile`) — Stream Drive file bytes (≤ 64 MiB). Auth: session; bucket read × 1; experimental.
- `GET /v1/connections/{id}/picker` (`getDrivePicker`) — Short-lived drive.file access token and Picker settings for the Google Drive picker. Auth: session; bucket read × 1; experimental.
- `POST /v1/connections/{provider}/start` (`startConnection`) — Start Google Drive consent (drive.file, offline) for this account. Auth: session; bucket write × 1; experimental.
- `GET /v1/creators` (`listCreators`) — Creators with public Toys, sounds or chains: counts, filter by what they publish, sort by followers or newest. Auth: anonymous, session; bucket read × 2; experimental.
- `GET /v1/developer/apps` (`listDeveloperApps`) — List the caller's developer apps. Auth: session; bucket read × 1; experimental.
- `POST /v1/developer/apps` (`createDeveloperApp`) — Create a developer app (at most 10 per account). Auth: session; bucket write × 1; experimental.
- `DELETE /v1/developer/apps/{appId}` (`deleteDeveloperApp`) — Delete an app; revokes its keys and disables its webhooks. Auth: session; bucket write × 1; experimental.
- `GET /v1/developer/apps/{appId}` (`getDeveloperApp`) — Read one app with its effective tier. Auth: session; bucket read × 1; experimental.
- `PATCH /v1/developer/apps/{appId}` (`updateDeveloperApp`) — Update app fields at an expected version. Auth: session; bucket write × 1; experimental.
- `GET /v1/developer/apps/{appId}/audit` (`listDeveloperAudit`) — Recent audit events of one app, newest first. Auth: session; bucket read × 1; experimental.
- `GET /v1/developer/apps/{appId}/keys` (`listApiKeys`) — Key metadata for one app; never secrets. Auth: session; bucket read × 1; experimental.
- `POST /v1/developer/apps/{appId}/keys` (`createApiKey`) — Create a key; the secret is returned once. Auth: session; bucket write × 1; experimental.
- `GET /v1/developer/apps/{appId}/tier` (`getDeveloperTier`) — Effective tier, its limits and whether an upgrade can be purchased. Auth: session; bucket read × 1; experimental.
- `GET /v1/developer/apps/{appId}/usage` (`getApiUsage`) — Hourly or daily usage series with per-key totals. Auth: session, key; scopes: read:usage; bucket read × 1; experimental.
- `GET /v1/developer/apps/{appId}/usage.csv` (`exportApiUsage`) — Hourly usage as CSV (UTC, at most 90 days). Auth: session; bucket read × 1; experimental.
- `GET /v1/developer/apps/{appId}/webhooks` (`listWebhooks`) — Webhooks of one app. Auth: session; bucket read × 1; experimental.
- `POST /v1/developer/apps/{appId}/webhooks` (`createWebhook`) — Create a webhook (pro); sends a verification challenge. Auth: session; bucket write × 1; experimental.
- `POST /v1/developer/deliveries/{deliveryId}/redeliver` (`redeliverWebhook`) — Queue another attempt of a delivered or failed event. Auth: session; bucket write × 1; experimental.
- `GET /v1/developer/key` (`getCurrentApiKey`) — Introspect the presenting key: app, scopes, tier and expiry. Auth: key; no rate cost; experimental.
- `POST /v1/developer/key/revoke` (`revokeCurrentApiKey`) — Self-revocation for leak response. Auth: key; no rate cost; experimental.
- `PATCH /v1/developer/keys/{keyId}` (`updateApiKey`) — Rename a key, change its scopes or IP allowlist. Auth: session; bucket write × 1; experimental.
- `POST /v1/developer/keys/{keyId}/revoke` (`revokeApiKey`) — Revoke a key immediately. Auth: session; bucket write × 1; experimental.
- `POST /v1/developer/keys/{keyId}/rotate` (`rotateApiKey`) — Issue a replacement key; the old key keeps working for the overlap. Auth: session; bucket write × 1; experimental.
- `GET /v1/developer/limits` (`getRateLimits`) — Current bucket and quota state for a key, or the tier policies. Auth: session, key; no rate cost; experimental.
- `GET /v1/developer/scopes` (`listApiKeyScopes`) — Scopes a key may hold, with descriptions. Auth: anonymous, session, key; no rate cost; experimental.
- `PATCH /v1/developer/webhooks/{webhookId}` (`updateWebhook`) — Change events, URL or state; URL changes and re-enabling re-verify. Auth: session; bucket write × 1; experimental.
- `GET /v1/developer/webhooks/{webhookId}/deliveries` (`listWebhookDeliveries`) — Delivery log: one row per attempt, newest first. Auth: session; bucket read × 1; experimental.
- `POST /v1/developer/webhooks/{webhookId}/test` (`testWebhook`) — Queue a signed webhook.test delivery. Auth: session; bucket expensive × 25; experimental.
- `POST /v1/developer/webhooks/{webhookId}/verify` (`verifyWebhook`) — Resend the verification challenge. Auth: session; bucket write × 1; experimental.
- `GET /v1/distribution/keys` (`listDistributionKeys`) — Public Ed25519 keys by purpose (diagnostics; clients pin keys). Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/downloads/{ticketId}` (`downloadTicketBytes`) — Artifact bytes for a ticket token (`?t=`): single Range, ETag digest, Repr-Digest. Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/email/unsubscribe` (`getEmailUnsubscribe`) — Browser page that confirms an email unsubscribe; never mutates. Auth: anonymous, session; bucket read × 1; experimental.
- `POST /v1/email/unsubscribe` (`postEmailUnsubscribe`) — RFC 8058 one-click and page unsubscribe for one token scope. Auth: anonymous; bucket write × 1; experimental.
- `POST /v1/embed/events` (`recordEmbedPlay`) — Count one in-frame play (bounded daily counter, no viewer data). Auth: anonymous; no rate cost; experimental.
- `GET /v1/exports` (`listExports`) — The caller's 50 newest export and convert jobs. Auth: session; bucket read × 1; experimental.
- `POST /v1/exports` (`createExport`) — Queue a take render, Frame video or screen-recording transcode. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/exports/{exportId}` (`cancelExport`) — Cancel a queued or running export; finished jobs are unchanged. Auth: session; bucket write × 1; experimental.
- `GET /v1/exports/{exportId}` (`getExport`) — Export state, progress, warnings, error class and output. Auth: session; bucket read × 1; experimental.
- `GET /v1/exports/{exportId}/output` (`getExportOutput`) — Download a finished export as a sandboxed attachment. Auth: session; bucket read × 1; experimental.
- `GET /v1/health` (`getHealth`) — Readiness and engine ABI. Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/install/{product}/{version}` (`getInstallPage`) — Install deep-link fallback page (HTML). Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/installations` (`listInstallations`) — Installation records for the caller, optionally per device or product. Auth: session, native; bucket read × 1; experimental.
- `POST /v1/installations` (`recordInstallation`) — Record a verified install on a Player or Installer device. Auth: session, native; bucket write × 1; experimental.
- `PUT /v1/installations/{id}` (`updateInstallation`) — Change state or version, report last seen, or roll back. Auth: session, native; bucket write × 1; experimental.
- `GET /v1/library` (`listLibrary`) — List the caller's library. Auth: session, native, key; scopes: read:library; bucket read × 2; experimental.
- `DELETE /v1/library/{itemId}` (`removeLibraryItem`) — Remove a library item at an expected version. Auth: session, key; scopes: write:library; bucket write × 1; experimental.
- `PUT /v1/library/{itemId}` (`annotateLibraryItem`) — Write library bookmark, tags and pinned release. Auth: session, key; scopes: write:library; bucket write × 1; experimental.
- `PUT /v1/library/{itemId}/bookmark` (`setLibraryBookmark`) — Set the quick-bookmark flag. Auth: session, key; scopes: write:library; bucket write × 1; experimental.
- `GET /v1/library/bookmarks` (`getBookmarkStates`) — Read quick-bookmark flags for listed Toys. Auth: session, key; scopes: read:library; bucket read × 1; experimental.
- `GET /v1/library/sync` (`syncLibrary`) — Read library events after a cursor. Auth: session, native, key; scopes: read:library; bucket read × 2; experimental.
- `GET /v1/listings/publishers` (`listListingPublishers`) — Publishers where the caller is an active member, with roles. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `GET /v1/media` (`listMedia`) — Search visible media (alias of GET /v1/sounds in the pre-0.0.8 item shape; kind= filters by family). Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/media/{mediaId}` (`getMedia`) — Read media metadata. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/media/{mediaId}/bytes` (`getMediaBytes`) — Download media bytes as a sandboxed attachment. Auth: anonymous, session; bucket read × 1; experimental.
- `POST /v1/media/{mediaId}/convert` (`convertMedia`) — Queue a conversion of a library item into a new private library item. Auth: session; bucket write × 1; experimental.
- `GET /v1/media/upload-access` (`getMediaUploadAccess`) — Read the caller's upload permission and policy mode. Auth: anonymous, session; bucket read × 1; experimental.
- `POST /v1/media/uploads` (`beginMediaUpload`) — Reserve an upload with its transfer facts, rights and catalog metadata in one request. Auth: session; bucket write × 1; experimental.
- `POST /v1/media/uploads/{uploadId}/complete` (`completeMediaUpload`) — Verify and publish an uploaded media version. Auth: session; bucket write × 1; experimental.
- `GET /v1/native/authorize` (`validateNativeAuthorization`) — Validate a Player authorization request and loopback callback. Auth: anonymous, session; bucket read × 1; experimental.
- `POST /v1/native/authorize` (`authorizeNativeClient`) — Consent to a Player request and issue a short-lived code. Auth: session; bucket write × 1; experimental.
- `GET /v1/native/devices` (`listNativeDevices`) — List the caller's authorized Player devices. Auth: session; bucket read × 1; experimental.
- `POST /v1/native/devices/{deviceId}/revoke` (`revokeNativeDevice`) — Revoke an owned Player device. Auth: session; bucket write × 1; experimental.
- `GET /v1/network/allowlist` (`getNetworkAllowlist`) — Read the extra exact hosts this account allows for web nodes. Auth: session; bucket read × 1; experimental.
- `PUT /v1/network/allowlist` (`putNetworkAllowlist`) — Replace the account network allowlist (exact hosts, at most 32; private ranges stay refused). Auth: session; bucket write × 1; experimental.
- `GET /v1/notifications` (`listNotifications`) — Page of the caller's rendered notifications (ETag). Auth: session, native; bucket read × 1; experimental.
- `POST /v1/notifications/{notificationId}/dismiss` (`dismissNotification`) — Dismiss one notification from every filter. Auth: session, native; bucket write × 1; experimental.
- `POST /v1/notifications/{notificationId}/unread` (`markNotificationUnread`) — Mark one notification unread. Auth: session, native; bucket write × 1; experimental.
- `PUT /v1/notifications/channels/{channel}` (`setNotificationChannel`) — Digest cadence and quiet hours for one channel. Auth: session; bucket write × 1; experimental.
- `GET /v1/notifications/preferences` (`getNotificationPreferences`) — Event × channel matrix, digests, quiet hours and channel availability. Auth: session; bucket read × 1; experimental.
- `PUT /v1/notifications/preferences` (`setNotificationPreferences`) — Change matrix cells; required events cannot be disabled. Auth: session; bucket write × 1; experimental.
- `POST /v1/notifications/read` (`markNotificationsRead`) — Mark notifications read by id, or all in a filter. Auth: session, native; bucket write × 1; experimental.
- `POST /v1/notifications/test` (`sendTestNotification`) — Send a test notification by email or web push (3 per hour). Auth: session; bucket write × 1; experimental.
- `GET /v1/notifications/unread-count` (`countUnreadNotifications`) — Unread notification count for polling (ETag). Auth: session, native; bucket read × 1; experimental.
- `PATCH /v1/offers/{offerId}` (`setOfferState`) — Activate or deactivate a creator offer. Auth: session; bucket write × 1; experimental.
- `GET /v1/openapi.json` (`getOpenApi`) — This OpenAPI 3.1 document. Auth: anonymous, session, native, key; no rate cost; experimental.
- `GET /v1/platform/targets` (`listPlatformTargets`) — The 13 target profiles with buildable formats and builder status. Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/posts` (`listPosts`) — List root posts of a subject with inline replies. Auth: anonymous, session; bucket read × 1; experimental.
- `POST /v1/posts` (`createPost`) — Create a comment or reply. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/posts/{postId}` (`removePost`) — Remove a post, leaving a tombstone. Auth: session; bucket write × 1; experimental.
- `GET /v1/posts/{postId}` (`getPost`) — Read a post with its visible replies. Auth: anonymous, session; bucket read × 1; experimental.
- `PATCH /v1/posts/{postId}` (`editPost`) — Edit a post or resolve a project note. Auth: session; bucket write × 1; experimental.
- `POST /v1/posts/{postId}/moderation` (`moderatePost`) — Remove, restore or clear the verified flag of a post (moderator). Auth: session; bucket write × 1; experimental.
- `PUT /v1/posts/{postId}/pin` (`setPostPin`) — Pin or unpin a root post (subject owner, at most three). Auth: session; bucket write × 1; experimental.
- `PUT /v1/posts/{postId}/reactions/{kind}` (`setPostReaction`) — Set or clear a like or helpful vote. Auth: session; bucket write × 1; experimental.
- `GET /v1/posts/{postId}/replies` (`listPostReplies`) — List every visible reply below a post. Auth: anonymous, session; bucket read × 1; experimental.
- `PUT /v1/posts/{postId}/response` (`savePublisherResponse`) — Create or edit the publisher response to a review. Auth: session; bucket write × 1; experimental.
- `GET /v1/posts/{postId}/revisions` (`listPostRevisions`) — List prior versions of a post (author or moderator). Auth: session; bucket read × 1; experimental.
- `POST /v1/products/{id}/aliases/{alias}` (`moveProductAlias`) — Move stable or beta with an expected-previous check. Auth: session; bucket write × 1; experimental.
- `POST /v1/products/{id}/certificate` (`issueLicenseCertificate`) — Issue a signed 30-day offline license certificate for an owned product. Auth: session, native; bucket write × 1; experimental.
- `GET /v1/products/{id}/embed` (`getProductEmbed`) — Embed policy, origins, effective frame-ancestors and the Patch view opt-in. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `PATCH /v1/products/{id}/embed` (`updateProductEmbed`) — Replace the embed policy and origin allowlist; optionally set the Patch view opt-in. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `GET /v1/products/{id}/embed/analytics` (`getProductEmbedAnalytics`) — Loads and plays per embedding origin for the last N days. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `GET /v1/products/{id}/feed/{channel}` (`getUpdateFeed`) — Signed update manifest (tunetoys.update-manifest/1) with its changelog text. Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/products/{id}/latest/{target}` (`getLatestDesktopArtifact`) — Latest installable desktop app artifact for macos, windows or linux (`?channel=`, Linux `?format=appimage|deb`). Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/products/{id}/versions` (`listProductVersions`) — List versions with matrix, artifacts and aliases (drafts for publisher members only). Auth: anonymous, session, native; bucket read × 1; experimental.
- `POST /v1/products/{id}/versions` (`createProductVersion`) — Create a draft version pinned to project releases. Auth: session, key; scopes: publish:releases; bucket write × 1; experimental.
- `GET /v1/products/{id}/versions/suggest` (`suggestProductVersion`) — Suggest the next semver from the public-control diff of the latest release. Auth: session, key; scopes: publish:releases; bucket read × 1; experimental.
- `GET /v1/products/{productId}/access` (`getProductAccess`) — The caller's access to a product's paid content. Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/products/{productId}/documents` (`listListingDocuments`) — Manuals, docs and FAQ documents. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `POST /v1/products/{productId}/documents` (`createListingDocument`) — Create a Markdown or PDF document. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `DELETE /v1/products/{productId}/documents/{documentId}` (`deleteListingDocument`) — Delete a document. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `PUT /v1/products/{productId}/documents/{documentId}` (`updateListingDocument`) — Update a document (title, slug, body, PDF or position). Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `GET /v1/products/{productId}/listing` (`getProductListing`) — Listing, draft and published revisions, effective fields and checks. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `PATCH /v1/products/{productId}/listing` (`updateProductListing`) — Change listing visibility, default locale or product slug. Auth: session; bucket write × 1; experimental.
- `GET /v1/products/{productId}/listing/assets` (`listListingAssets`) — Generated listing asset slots with status, overrides, jobs and the daily budget. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `POST /v1/products/{productId}/listing/assets` (`attachListingAsset`) — Attach an uploaded image as the thumbnail, social or marketing image. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `DELETE /v1/products/{productId}/listing/assets/{assetId}` (`removeListingAsset`) — Remove an uploaded asset override (reset to generated). Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `GET /v1/products/{productId}/listing/assets/{assetId}/bytes` (`getListingAssetBytes`) — Member preview of a ready generated asset, whatever the listing visibility. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `POST /v1/products/{productId}/listing/assets/jobs/{jobId}/cancel` (`cancelListingAssetJob`) — Cancel a queued or running asset job; the previous ready asset stays. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `DELETE /v1/products/{productId}/listing/draft` (`discardListingDraft`) — Discard the unpublished draft revision. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `PUT /v1/products/{productId}/listing/draft` (`saveListingDraft`) — Save the draft revision (named top-level keys only). Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `DELETE /v1/products/{productId}/listing/draft/overrides/{field}` (`resetListingField`) — Reset one field (or all) to the generated value. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `POST /v1/products/{productId}/listing/gallery/video-links` (`parseListingVideoLink`) — Parse a YouTube or Vimeo URL to a canonical video id. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `POST /v1/products/{productId}/listing/publish` (`publishListing`) — Validate and publish the draft revision. Auth: session; bucket write × 1; experimental.
- `POST /v1/products/{productId}/listing/regenerate` (`regenerateListingAssets`) — Regenerate all generated assets, some kinds, or one variant (never touches uploaded overrides). Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `GET /v1/products/{productId}/listing/revisions` (`listListingRevisions`) — Listing revision history. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `POST /v1/products/{productId}/listing/revisions/{revisionId}/restore` (`restoreListingRevision`) — Copy a revision into the draft. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `GET /v1/products/{productId}/listing/translations` (`listListingTranslations`) — Translations of the draft (or published) revision. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `PUT /v1/products/{productId}/listing/translations/{locale}` (`putListingTranslation`) — Save translated fields and their state for the draft revision. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `GET /v1/products/{productId}/offers` (`listProductOffers`) — List active offers (managers also see inactive offers). Auth: anonymous, session; bucket read × 1; experimental.
- `POST /v1/products/{productId}/offers` (`createProductOffer`) — Create a free or one-time creator offer (owner/finance). Auth: session; bucket write × 1; experimental.
- `GET /v1/products/{productId}/rating-summary` (`getRatingSummary`) — Read the review rating summary of a product. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/products/{productId}/review` (`getMyReview`) — Read the caller's review of a product with eligibility. Auth: anonymous, session; bucket read × 1; experimental.
- `PUT /v1/products/{productId}/review` (`saveReview`) — Create or edit the caller's review of a product. Auth: session; bucket write × 1; experimental.
- `GET /v1/projects` (`listProjects`) — List the caller's drafts, newest first. Auth: session, key; scopes: read:projects; bucket read × 2; experimental.
- `POST /v1/projects` (`createProject`) — Create an owned project from a validated document. Auth: session, key; scopes: write:projects; bucket write × 1; experimental.
- `GET /v1/projects/{projectId}` (`getProject`) — Read an owned project. Auth: session, key; scopes: read:projects; bucket read × 1; experimental.
- `PUT /v1/projects/{projectId}` (`saveProject`) — Save a draft at an expected revision. Auth: session, key; scopes: write:projects; bucket write × 1; experimental.
- `PUT /v1/projects/{projectId}/catalog` (`updateProjectCatalog`) — Update public discovery tags and category. Auth: session; bucket write × 1; experimental.
- `GET /v1/projects/{projectId}/listing` (`getProjectListing`) — Listing editor read model for a published Toy's product. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `POST /v1/projects/{projectId}/operations` (`applyProjectOperations`) — Apply an authoring operation batch at an expected revision. Auth: session, key; scopes: write:projects; bucket write × 1; experimental.
- `GET /v1/projects/{projectId}/product` (`getProjectProduct`) — The product that wraps a published project, for version and download UI. Auth: anonymous, session, native; bucket read × 1; experimental.
- `POST /v1/projects/{projectId}/publish` (`publishProject`) — Publish an immutable release. Auth: session; bucket write × 1; experimental.
- `PUT /v1/projects/{projectId}/visibility` (`setProjectVisibility`) — Change listing visibility. Auth: session; bucket write × 1; experimental.
- `POST /v1/proxy/request` (`proxyRequest`) — Make one allowlisted HTTPS request, optionally injecting a vault secret server-side. Auth: session; bucket write × 1; experimental.
- `GET /v1/publishers/{handle}/products` (`listPublisherProducts`) — A publisher's products with listing state, for members. Auth: session, key; scopes: read:products; bucket read × 1; experimental.
- `GET /v1/publishers/{handle}/storefront` (`getStorefront`) — Published storefront, or the draft and revisions for members with ?draft=1. Auth: anonymous, session, key; scopes: read:public; bucket read × 1; experimental.
- `PUT /v1/publishers/{handle}/storefront/draft` (`saveStorefrontDraft`) — Save theme tokens and sections to the draft revision. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `POST /v1/publishers/{handle}/storefront/publish` (`publishStorefront`) — Validate references and publish the draft revision. Auth: session; bucket write × 1; experimental.
- `POST /v1/publishers/{handle}/storefront/revisions/{revisionId}/restore` (`restoreStorefrontRevision`) — Copy an older revision into a new draft. Auth: session, key; scopes: write:listings; bucket write × 1; experimental.
- `PATCH /v1/publishers/{publisherId}` (`updatePublisher`) — Update display name, support email or seller terms acceptance. Auth: session; bucket write × 1; experimental.
- `GET /v1/publishers/{publisherId}/connect` (`getPublisherConnect`) — Read Stripe Connect capability state (owner/finance). Auth: session; bucket read × 1; experimental.
- `POST /v1/publishers/{publisherId}/connect/onboard` (`startPublisherConnectOnboarding`) — Create or resume Stripe Express onboarding (owner only). Auth: session; bucket write × 1; experimental.
- `POST /v1/publishers/{publisherId}/connect/sync` (`syncPublisherConnect`) — Reconcile Connect state with Stripe (owner/finance). Auth: session; bucket write × 1; experimental.
- `GET /v1/publishers/{publisherId}/members` (`listPublisherMembers`) — List publisher members and roles. Auth: session; bucket read × 1; experimental.
- `POST /v1/publishers/{publisherId}/members` (`addPublisherMember`) — Add a member by handle with a role (owner only). Auth: session; bucket write × 1; experimental.
- `DELETE /v1/publishers/{publisherId}/members/{accountId}` (`removePublisherMember`) — Remove a member (owner only). Auth: session; bucket write × 1; experimental.
- `GET /v1/publishers/me` (`getMyPublisher`) — Read (creating on first use) the caller's personal publisher. Auth: session; bucket read × 1; experimental.
- `GET /v1/push-subscriptions` (`listPushSubscriptions`) — The caller's push devices. Auth: session; bucket read × 1; experimental.
- `POST /v1/push-subscriptions` (`registerPushSubscription`) — Register this browser for web push. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/push-subscriptions/{subscriptionId}` (`deletePushSubscription`) — Remove a push device. Auth: session; bucket write × 1; experimental.
- `GET /v1/push/vapid-public-key` (`getVapidPublicKey`) — Web push application server key. Auth: anonymous, session; bucket read × 1; experimental.
- `GET /v1/releases/{digest}` (`getRelease`) — Read an immutable release. Auth: anonymous, session, native, key; scopes: read:public; bucket read × 1; experimental.
- `GET /v1/releases/{digest}/assets/{assetId}` (`getReleaseAsset`) — Download a release asset as a sandboxed attachment. Auth: anonymous, session, native, key; scopes: read:public; bucket read × 5; experimental.
- `GET /v1/releases/{digest}/engine` (`getReleaseEngine`) — Download the release engine WebAssembly. Auth: anonymous, session, native, key; scopes: read:public; bucket read × 5; experimental.
- `POST /v1/releases/{digest}/fork` (`forkRelease`) — Fork a release into a new owned project. Auth: session, key; scopes: write:projects; bucket write × 1; experimental.
- `GET /v1/releases/{digest}/package` (`getReleasePackage`) — Download the canonical release package. Auth: anonymous, session, native, key; scopes: read:public; bucket read × 5; experimental.
- `GET /v1/sounds` (`searchSounds`) — Search and filter public sounds (or the caller’s own with mine=1); page of 40. Auth: anonymous, session, native; bucket read × 2; experimental.
- `DELETE /v1/sounds/{mediaId}` (`removeSound`) — Remove a sound from the catalog; pinned release versions stay. Auth: session; bucket write × 1; experimental.
- `GET /v1/sounds/{mediaId}` (`getSound`) — Item, current version, resolved fields with sources, renditions, counts and viewer state. Auth: anonymous, session, native; bucket read × 1; experimental.
- `PATCH /v1/sounds/{mediaId}` (`updateSound`) — Edit the catalog entry at an expected version (owner). Auth: session; bucket write × 1; experimental.
- `GET /v1/sounds/{mediaId}/analysis` (`getSoundAnalysis`) — Every analysis run of the current version with the full report. Auth: anonymous, session, native; bucket read × 1; experimental.
- `GET /v1/sounds/{mediaId}/bytes` (`getSoundBytes`) — Original bytes as a sandboxed attachment: the owner, or anyone when reusable; counted. Auth: session, native; bucket read × 5; experimental.
- `POST /v1/sounds/{mediaId}/events` (`recordSoundEvent`) — Play or preview beacon, bounded per address per day. Auth: anonymous, session, native; no rate cost; experimental.
- `PUT /v1/sounds/{mediaId}/like` (`setSoundLike`) — Like or unlike a sound. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/sounds/{mediaId}/relations` (`removeSoundRelation`) — Remove a relation (owner of either side). Auth: session; bucket write × 1; experimental.
- `GET /v1/sounds/{mediaId}/relations` (`listSoundRelations`) — Relations in both directions the caller may read. Auth: anonymous, session, native; bucket read × 1; experimental.
- `PUT /v1/sounds/{mediaId}/relations` (`addSoundRelation`) — Relate this sound to another (owner of either side). Auth: session; bucket write × 1; experimental.
- `GET /v1/sounds/{mediaId}/renditions/{kind}` (`getSoundRendition`) — Rendition bytes (peaks, preview, thumbnail, score page); 404 RENDITION_NOT_READY until produced. Auth: anonymous, session, native; bucket read × 2; experimental.
- `PUT /v1/sounds/{mediaId}/save` (`setSoundSaved`) — Save or unsave a sound (synced to hosts like library bookmarks). Auth: session; bucket write × 1; experimental.
- `GET /v1/sounds/facets` (`getSoundFacets`) — Facet counts for a sounds filter set. Auth: anonymous, session, native; bucket read × 3; experimental.
- `GET /v1/sounds/saved` (`listSavedSounds`) — List the caller's saved sounds. Auth: session, native; bucket read × 1; experimental.
- `GET /v1/sounds/saved/sync` (`syncSavedSounds`) — Read saved-sound events after a cursor (the library sync protocol). Auth: session, native; bucket read × 1; experimental.
- `GET /v1/sounds/similar/{mediaId}` (`getSimilarSounds`) — Nearest sounds by embedding, or unsupported with the reason. Auth: anonymous, session, native; bucket read × 3; experimental.
- `GET /v1/subscriptions` (`listSubscriptions`) — Followed products, publishers, threads and docs pages. Auth: session; bucket read × 1; experimental.
- `DELETE /v1/subscriptions/{subjectType}/{subjectId}` (`unfollowSubject`) — Stop following a subject. Auth: session; bucket write × 1; experimental.
- `GET /v1/subscriptions/{subjectType}/{subjectId}` (`getSubscription`) — Follow state for one subject. Auth: session; bucket read × 1; experimental.
- `PUT /v1/subscriptions/{subjectType}/{subjectId}` (`followSubject`) — Follow a product, publisher, thread or docs page. Auth: session; bucket write × 1; experimental.
- `GET /v1/toys/{toyId}` (`getListing`) — Read a public or authorized Toy listing. Auth: anonymous, session, native, key; scopes: read:public; bucket read × 1; experimental.
- `GET /v1/vault/secrets` (`listVaultSecrets`) — List vault secret metadata (never values). Auth: session; bucket read × 1; experimental.
- `POST /v1/vault/secrets` (`createVaultSecret`) — Store a secret in a slot; returns metadata only. Auth: session; bucket write × 1; experimental.
- `DELETE /v1/vault/secrets/{id}` (`deleteVaultSecret`) — Remove a secret. Auth: session; bucket write × 1; experimental.
- `PUT /v1/vault/secrets/{id}` (`rotateVaultSecret`) — Replace a secret value atomically (new prefix and last4). Auth: session; bucket write × 1; experimental.
- `GET /v1/versions/{id}` (`getProductVersion`) — Read one version with its matrix and artifacts. Auth: anonymous, session, native; bucket read × 1; experimental.
- `PATCH /v1/versions/{id}` (`updateProductVersion`) — Edit a draft, or the matrix claims of a published version. Auth: session; bucket write × 1; experimental.
- `GET /v1/versions/{id}/artifacts` (`listVersionArtifacts`) — Registered artifacts of a version (public fields). Auth: anonymous, session, native; bucket read × 1; experimental.
- `POST /v1/versions/{id}/artifacts` (`registerVersionArtifact`) — Upload and register an artifact (application/octet-stream body, metadata in the query). Auth: session, key; scopes: publish:releases; bucket write × 1; experimental.
- `POST /v1/versions/{id}/publish` (`publishProductVersion`) — Freeze and publish a version; creates the browser artifact. Auth: session, key; scopes: publish:releases; bucket write × 1; experimental.
- `GET /v1/versions/{id}/targets` (`listVersionTargets`) — Platform matrix for a version: all 13 profiles. Auth: anonymous, session, native; bucket read × 1; experimental.
- `POST /v1/versions/{id}/yank` (`yankProductVersion`) — Withdraw a published version with a public reason. Auth: session; bucket write × 1; experimental.

## JSON Schemas

- [ApiError](https://tune.toys/schemas/platform/api-error.schema.json) — Error envelope returned by every failing API response. `requestId` echoes the X-Request-Id response header.
- [ApiKeyScopes](https://tune.toys/schemas/platform/api-key-scopes.schema.json) — Scopes granted to one developer API key.
- [ApiKey](https://tune.toys/schemas/platform/api-key.schema.json) — Metadata of one developer API key. The secret is returned once at creation or rotation and never stored in plain text.
- [ApiUsage](https://tune.toys/schemas/platform/api-usage.schema.json) — Metered usage of one developer app in UTC hourly or daily windows. Counters are informational and may lag by up to 30 seconds.
- [ArtifactDescriptor](https://tune.toys/schemas/platform/artifact.schema.json) — One registered build output of a product version. digest, size, inventory, targetProfile, format and arch never change; a correction is a new artifact.
- [PlatformCommon](https://tune.toys/schemas/platform/common.schema.json) — Shared scalar formats referenced by the other platform contracts.
- [DeveloperApp](https://tune.toys/schemas/platform/developer-app.schema.json) — A developer app groups API keys, usage, webhooks and a tier. `tier` is the last observed effective tier, computed from the owner's feature:api.pro grant.
- [PlatformEnums](https://tune.toys/schemas/platform/enums.schema.json) — Closed platform enums. Generated TypeScript exports each as a type and an as-const array; this file is their single source.
- [LicenseCertificate](https://tune.toys/schemas/platform/license-certificate.schema.json) — Offline license certificate payload (tunetoys.license-certificate/1), signed in a SignedEnvelope with the license key. Contains no device ID, email or handle. allowedMajor or until is absent for the all update policy.
- [ListingRevisionContent](https://tune.toys/schemas/platform/listing-revision.schema.json) — Content of one product listing revision. The effective value of a field is overrides[field] ?? generated[field].
- [SoundAnalysis](https://tune.toys/schemas/platform/media-analysis.schema.json) — One engine run over a media version: its state, the facet summary the index reads and the full report. A newer engine version appends a row; the resolved view takes the newest ready one.
- [SoundItem](https://tune.toys/schemas/platform/media-item.schema.json) — The mutable catalog entry of one upload: what people see and edit (title, artwork, tags, declared musical fields, visibility). Bytes and rights live on its versions. Server-owned counters and the resolved view are separate shapes here.
- [SoundRelation](https://tune.toys/schemas/platform/media-relation.schema.json) — A directional relation between two media items, created by either owner. Symmetric in the UI; a relation to an item the viewer cannot read is omitted.
- [SoundRendition](https://tune.toys/schemas/platform/media-rendition.schema.json) — One derived artifact of a media version (peaks, preview, thumbnail, score page, piano roll, beats). Immutable; unique per version, kind, recipe, toolchain and profile.
- [SoundVersion](https://tune.toys/schemas/platform/media-version.schema.json) — One immutable upload of a media item: bytes, digest, rights, what the probe found and the tags the file carried. Never edited after creation; releases pin versions.
- [MediaVocabulary](https://tune.toys/schemas/platform/media-vocabulary.schema.json) — The closed vocabularies of the Sounds catalog as one document (served to editors and used as the zero-shot tag prompts). The long lists (`Instrument`, `Genre`, `Mood`) are defined here; the short ones reference enums.schema.json. Generated TypeScript exports each titled list as a type and an as-const array.
- [NotificationEvent](https://tune.toys/schemas/platform/notification-event.schema.json) — Input of the single notify helper. params holds ICU arguments (ids, counts, handles), never rendered strings or private content.
- [PlatformMatrix](https://tune.toys/schemas/platform/platform-matrix.schema.json) — Per-version platform matrix: one entry per target profile. included means an artifact exists, supported is a creator claim, tested requires evidence.
- [PostContent](https://tune.toys/schemas/platform/post.schema.json) — Author-supplied content of a review, comment or reply. Server-owned fields (author, verified owner, root, depth, pins, state) are not part of it. Replies inherit subject and team scope from their root.
- [SignedEnvelope](https://tune.toys/schemas/platform/signed-envelope.schema.json) — Ed25519 envelope for update manifests and license certificates. The signature covers a purpose-specific domain prefix followed by the exact payload bytes; verifiers check it before parsing and never re-canonicalize.
- [SoundSearchParams](https://tune.toys/schemas/platform/sound-search.schema.json) — Query of GET /v1/sounds and /v1/sounds/facets: every filter optional, bounded, and owned by the page URL. Facet counts answer for the same filter set.
- [StorefrontRevisionContent](https://tune.toys/schemas/platform/storefront-revision.schema.json) — Content of one publisher storefront revision: validated theme tokens and ordered typed sections. Storefronts are data, never code.
- [UpdateManifest](https://tune.toys/schemas/platform/update-manifest.schema.json) — Signed update feed payload for one product and channel (tunetoys.update-manifest/1). Lists artifact digests, never URLs or tickets. Signed in a SignedEnvelope with the update_feed key.
- [Webhook](https://tune.toys/schemas/platform/webhook.schema.json) — A pro-tier webhook endpoint. Deliveries are signed with TuneToys-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, t + "." + body)>.
- [ToyDocument](https://tune.toys/schemas/toy-0.1.0.schema.json) — Draft local authoring contract. Validation is not runtime admission or a release certificate.

## Toy format

## Toy source format 0.1.0

This specification governs the portable `*.toy.json` document: what it contains, which references must resolve, which bounds every host enforces, and which parts are still draft. It is the write model shared by the browser editor, the agent authoring path, the native Player and independent exports.

**Status:** draft local authoring subset; schema and validator implemented on browser, native and WASM, including the v0.0.5 cable types, parameter sockets, node `data`, buses and node-face widgets. Video and sensing nodes validate everywhere but execute only in the browser. The authoritative structure is [toy.schema.json](../../packages/toy-format/schemas/toy.schema.json). TypeScript types are generated from it, never maintained by hand. The schema `$id` is a proposed stable identifier; validation loads the bundled schema and never fetches that URL.

### Document shape

A Toy is UTF-8 JSON with `format: "tune-toys"` and an exact `schemaVersion`. It is source, not an installed binary or a published release manifest.

| Top-level field            | Holds                                                                                  |
| -------------------------- | -------------------------------------------------------------------------------------- |
| `id`, `revision`, `title`  | Durable Toy identity, authoring revision and presentation title                        |
| `entrypoint`, `entryFrame` | The definition that runs and the Frame that opens; entry Frame ownership must match    |
| `definitions`              | Keyed reusable implementations: nodes, connections, public parameters, inputs, outputs |
| `frames`                   | Keyed explicit playable surfaces, each owned by one definition                         |
| `assets`                   | Declared media with relative `assets/` path, SHA-256, size, media type and license     |
| `styles`, `theme`          | Optional portable appearance (see [Appearance](#appearance))                           |
| `tuning`                   | Optional Toy-wide note tuning for instruments and Tuners (see [Tuning](#tuning))       |
| Namespaced extensions      | Optional non-executable metadata, preserved within JSON bounds and reserved-key rules  |

### Identity and composition

**Keys are stable lowercase IDs; names and labels are presentation.** A node is either a pinned draft primitive or a reference to a local group definition. A group node's key identifies its instance; the definition ID identifies reusable source. Runtime addresses derive from instance paths and are never substituted for source IDs.

Connections and ports:

- Endpoints are `{node, port}`. `$in` is the enclosing definition's input source and `$out` its output destination; neither can be used in reverse.
- Every port is a bundle of lanes of one signal type: `audio` (1–32 `channels`), `video` (1–8 `streams`), `control` (1–32 `lanes`) or `midi` (one stream of sixteen MIDI channels). Widths are fixed or `"auto"`, with optional ordered labels. The shared engine executes audio, control and MIDI on every host; video runs only where a host has a video engine (the browser), and the host-only `data` type is described with the [data cable](../architecture/data-nodes.md). Manifest ports may also be `signal` (Math and Compare, resolved to audio or control per cable; never a definition boundary, `PORT_TYPE`) or `any` (`bus.send`/`bus.receive` only). See [signal types and domains](../architecture/signal-types-and-domains.md).
- A connection needs matching types, compatible resolved lane counts and exactly one driver per destination. Mixers and conversions are explicit.
- Feedback is rejected entirely in this draft. Delayed feedback needs a later compiler/profile contract.
- A connection may end at a **parameter socket**, `{ node, port: "@name" }`: exactly one one-lane `control` cable drives that parameter, its 0–1 value maps across the parameter's linear or logarithmic domain, and a public parameter aliasing the slot becomes read-only (no LFO or MIDI mapping may share it).
- A primitive may carry bounded `data` the manifest admits per key: float tables (`std.wavetable` `table`, 1–8 frames of 2048 samples in −1…1; `ctl.curve` `points`, 2–32 `(x, y, bend)` groups with x and y in 0…1 and bend in −1…1, from the manifest's `minItems` and per-position `fields`, `NODE_DATA` otherwise) and short text (for example the logical `label` of `midi.in` or `video.camera`, the `asset` or `source` of `media.player`, the `template` of `video.text`). The whole object stays within 64 KiB. Data is source, hashed into releases and edited through authoring; large media stays in `assets`. A `video.image` or `media.player` `asset` must name a declared asset of the image, or video/audio, family (`ASSET_REFERENCE`).
- `bus.send` and `bus.receive` nodes carry a `bus` name and connect without a cable inside one definition: one Send per name, any number of Receives, type and width inherited from the Send's driver; an unnamed node is inert. The compiler lowers them to direct connections; a Receive feeding its own Send is a cycle.

Public parameters declare label, range, default, unit, linear or log scale, smoothing time and direct node-parameter targets. A group parameter targets the child's public parameter. The draft uses identity conversion and requires the public range to fit each target; nonlinear or multi-range mappings need explicit future operations. One public owner may target a node parameter. Node `values` are instance defaults, and enclosing public parameter defaults override their targets during preparation.

### Frames

A Frame belongs to a definition and contains explicit widgets. Geometry lays out only explicit members. A nested Frame names a group node plus a Frame of that group's definition and binds relatively to that instance.

| Widget kind                                | Binding and rules                                                                                                                                                                                                                                                                       |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `knob`, `slider`                           | One public parameter                                                                                                                                                                                                                                                                    |
| `toggle`, `momentary`, `trigger`           | One public parameter with optional in-domain distinct `onValue`/`offValue`; only `trigger` admits `pulseMs` (10–2000, default 80)                                                                                                                                                       |
| `xy`                                       | Two distinct public parameter IDs                                                                                                                                                                                                                                                       |
| `filter`, `envelope`                       | Graphical roles must resolve to matching parameters of one real processor, including nested aliases                                                                                                                                                                                     |
| `face`                                     | `face` names a node face; `parameters` binds every role in `FACE_BINDINGS` to a distinct public control reaching that role's parameter of one node of the face's type, nested aliases included; `node` (that node) is required for data faces (`FRAME_PARAMETER`, `WIDGET_SOURCE_KIND`) |
| `text`                                     | Inert                                                                                                                                                                                                                                                                                   |
| `icon`                                     | Schema-admitted bundled `icon` name, accessible `label` (empty for decorative art), bounds; optional `appearance` with `none`/`currentColor`/six-digit hex fill and stroke and a 0–4 stroke width                                                                                       |
| `piano`                                    | `node`: a durable path to a `midi.keyboard` node, and a 2–37 key range; otherwise `FRAME_PERFORMANCE`                                                                                                                                                                                   |
| `screen`                                   | `mode` `image` or `video` with a declared asset (16 MiB), `scene` with a built-in scene, or `live` with `source: {node, port}` naming a video output of the Frame's definition and an optional 0-based `stream` for bundles (`FRAME_SOURCE`, `ASSET_REFERENCE`)                         |
| `paint`                                    | `source`: the `video` output of a `video.paint` node of the definition; optional `color`, `width`, `opacity` (`WIDGET_SOURCE_KIND`)                                                                                                                                                     |
| `curve`                                    | `node`: a `std.wavetable` node of the definition; `tableFrame` 0–7 (`WIDGET_SOURCE_KIND`)                                                                                                                                                                                               |
| `switcher`                                 | `node`: a `video.switch`; `parameters` binds `program`, `preview` and `transition` roles to distinct public controls targeting that node (`WIDGET_SOURCE_KIND`, `FRAME_PARAMETER`)                                                                                                      |
| `readout`                                  | Exactly one of a public `parameter` or a `source` control output with a `lane`; `format` number, percent, integer or boolean, `precision`, `unit` (`FRAME_PARAMETER`, `WIDGET_SOURCE_KIND`)                                                                                             |
| Nested Frame                               | Group node plus a Frame of that group's definition                                                                                                                                                                                                                                      |
| Meters, presets, MIDI and transport fields | Admitted by the draft schema; executable semantics in [creation workflows](../architecture/creation-workflows.md)                                                                                                                                                                       |

Buttons, XY pads and graphical editors are numeric controls, not executable actions or a MIDI-note graph; see [interaction semantics](../architecture/playable-inspection.md). Unknown icon names, external SVG and event handlers reject; see [icons](../architecture/icons.md). `face`, `paint`, `curve`, `switcher`, `readout` and a live `screen` are faces of one node in the Frame's own definition; the validator, the editor palette and Design fields share their admission in [`faces.ts`](../../packages/toy-format/src/faces.ts). A host without the service behind a face shows an unavailable state rather than a frozen picture ([video](../architecture/video.md#status-and-unavailable-states)).

Layers and folders:

- Every widget may carry a layer `name` (1–128 characters), `hidden` and `locked`. Missing flags mean visible and unlocked. Names are independent of widget IDs, text content and control labels.
- Hidden members are omitted from presentation at every nesting level without altering graph execution or bindings. Locks guard browser design edits; they are not an authorization boundary and do not disable live controls.
- A Frame may hold up to 64 keyed `layerFolders`, each with `name`, sibling `zIndex` (0–255) and optional `parent`, `hidden`, `locked`. A widget's optional `folder` names its parent. Folder and widget IDs are distinct within a Frame. Missing parents, cycles and depth beyond 16 fail admission on every host. Folders form contiguous sibling stacking contexts, hidden state propagates to descendants, and locks inherit without disabling playback. See [layer behavior](../architecture/appearance.md#multi-selection-and-layer-folders).

Responsive layout: optional Frame `layout` gives bounded viewport minimum and maximum sizes; widget `constraints` select start/end/center/stretch/proportional anchors and element limits. Authored bounds remain the reference and the shared renderer projects them. Omitted layout keeps fixed-canvas scaling. Reversed limits and unknown anchors reject. See [responsive Frames](../architecture/responsive-frames.md).

### Tuning

An optional Toy-level `tuning` says how instruments map MIDI notes to pitch, so every instrument and every Tuner left on **Toy tuning** agree. It lives on the Toy, beside `transport`, rather than on a definition: a reusable instrument definition plays in whatever tuning the Toy that uses it declares, and nested groups never disagree.

| Field       | Holds                                                                                                                                                      |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `preset`    | One of `12-tet`, `19-edo`, `22-edo`, `24-edo`, `31-edo`, `53-edo`, `just`, `pythagorean`, `bohlen-pierce` (tables in `packages/node-catalog/tunings.json`) |
| `cents`     | Instead of a preset: 1–128 custom degrees in cents, `0` first, strictly ascending, each below `period` and at most 9600                                    |
| `period`    | With `cents`: the repeat interval in cents, 1–9600 (1200 for an octave)                                                                                    |
| `root`      | Required. Tonic pitch class 0–11 (C = 0) of root-anchored tunings (just, Pythagorean, Bohlen–Pierce and custom); equal divisions of the octave ignore it   |
| `reference` | Required. A4 in Hz, 400–480                                                                                                                                |

Exactly one of `preset` or `cents` + `period` is present, and the custom degree rules are semantic (`TUNING`); the schema bounds each field (`SCHEMA`). Absent means 12-TET at A4 = 440 Hz. The compiler copies the tuning into the Program and the engine resolves it once at preparation: MIDI note 60 is degree 0 (60 + `root` for root-anchored tunings), and degree `note − 60` folds across periods. An equal division of the octave keeps A4 on the degree three of its own fifths above C; a root-anchored tuning puts its root at its 12-TET pitch from `reference`. 12-TET keeps `reference · 2^((note − 69) / 12)` in single precision, bit for bit. See [`std.poly`](../../packages/node-docs/std.poly/index.md) and [`std.tuner`](../../packages/node-docs/std.tuner/index.md).

### Appearance

Optional Toy and Frame `theme` values and element `style` overrides are portable presentation. A theme selects a bounded preset and/or overrides color, typography and radius tokens, plus the optional instrument-screen tokens `screen`, `screenTrace` and `screenGlow` (0–1); an explicit preset resets the base before its overrides. Element styles add bounded, geometry-independent visual properties. Colors are six-digit hex, fonts come from a local allowlist, and no arbitrary CSS or remote resource is admitted.

Toy-wide `styles` holds up to 64 named text or control definitions by durable ID, each with `name`, `kind` and bounded `values`. A widget `styleRef` must reference an existing compatible definition: text styles address text, control styles address knobs, sliders and meters. Resolved appearance merges theme, named values, then local element values. Shared values exclude layer depth, layout, content and bindings. Rename preserves identity; authoring deletion materializes effective appearance before detaching. See [appearance resolution](../architecture/appearance.md).

### Bounds and diagnostics

| Bound              | Limit                                                                                                    |
| ------------------ | -------------------------------------------------------------------------------------------------------- |
| Source bytes       | 1 MiB UTF-8 (`readToy`), then JSON parse, then `validateToy`                                             |
| JSON traversal     | Depth 64, 50,000 values; well-formed Unicode without NUL; lone surrogates reject                         |
| Structure          | 64 definitions, 64 nodes and 256 connections per definition, 64 Frames, 128 widgets per Frame, 64 assets |
| Semantic expansion | 256 expanded node instances per definition and 16 definition levels; repeated empty groups count         |

These are validator limits, not measured audio budgets. All definitions and Frames are checked, including unused ones. Native and WASM compilation derive structural checks from the same schema at Cargo build time and repeat semantic admission before lowering; the build generator supports the schema's closed JSON Schema 2020-12 keyword and ASCII-pattern subset and fails on anything else. Native JSON parsing runs a streaming Rust preflight first. A shared corpus compares browser, native and WASM acceptance without claiming general JSON Schema certification.

Diagnostics return stable category codes and source paths for schema, references, domains, ownership, cycles, expansion and Frame/asset declarations. Validation never mutates input or fills defaults. Unknown core fields and versions fail visibly. Unknown namespaced extension values are preserved but are never executable authority.

The maintained catalog admits `std.gain`, `std.lowpass`, `std.delay`, `std.oscillator` and `std.mixer` at version 0.1.0, implemented in Rust. Version 0.2.0 adds channel-aware versions of those primitives plus `std.sum`, `std.combine`, `std.select` and `std.matrix`; see [multichannel contracts](../architecture/multichannel-audio.md). v0.0.5 adds `bus.*`, `std.bus`, `std.wavetable`, `ctl.*`, `midi.*`, `video.*`, `media.player`, `media.recorder` and `sense.*` at 0.2.0 ([node catalog](../../packages/node-catalog/README.md#primitives)). Engine admission is a separate bounded profile.

Host requirements are never authored. The compiler derives `requires` on the prepared program (and `toyRequirements()` on source) from the node manifest and the root buses, so a Toy cannot claim or omit a service its graph does not use. Assets: the validator checks declaration shape, path uniqueness and traversal only. The development media/publication service verifies library-backed bytes, pinned versions, declared rights and closure bounds; full decoder and archive admission is a managed-ingestion gate.

### Evolution beyond the subset

Definition presets, parameter MIDI CC and LFO settings, Toy transport defaults, preview-asset references and Frame meters are admitted by the draft schema; their executable semantics are in [creation workflows](../architecture/creation-workflows.md) and [media library](media-library.md). External dependencies and release locks, sized port families, MIDI 2.0, nonlinear target mappings, explicit side-effect roots and broader target profiles are future versioned contracts. **Do not hide essential behavior in extensions to bypass validation.** Proposed release fields live in [releases](releases.md).

The source version, DSP semantic version, engine build, target profile, state version and package release version are distinct. Before format v1: add migration fixtures, exact canonicalization and hash vectors, supported reader/writer rules and compatibility tests. Until then, 0.x draft revisions may change with explicit example and tool updates. Legacy `.bitdsp` is not automatically compatible.

### Implementation

- [packages/toy-format](../../packages/toy-format/README.md) — schema, generated types, validator and fixtures.
- [crates/compiler](../../crates/compiler/README.md) — generated structural checks and semantic admission for native and WASM.
- [examples](../../examples/README.md) — [gain](../../examples/gain/gain.toy.json), [nested gain](../../examples/nested-gain/nested-gain.toy.json), Warm Echo and Little Sine all run through the shared Rust engine.
- [tests/conformance](../../tests/conformance/README.md) — cross-host acceptance corpus.

### Related

- [Frames and UI composition](../architecture/frames.md) and [appearance](../architecture/appearance.md).
- [Revisioned authoring operations](operations.md) are the only write path to this document.
- [Decision 0001: one portable model](../decisions/0001-portable-model.md).

## Nodes

- `addon.dictionary.define` — Meanings and phonetics of an English word. ([docs](https://docs.tune.toys/nodes/addon.dictionary.define))
- `addon.open-meteo.forecast` — Current weather and forecasts for a place, no key. ([docs](https://docs.tune.toys/nodes/addon.open-meteo.forecast))
- `addon.randomuser.get` — Generated placeholder people with names and pictures. ([docs](https://docs.tune.toys/nodes/addon.randomuser.get))
- `addon.wikipedia.search` — Search English Wikipedia for matching pages. ([docs](https://docs.tune.toys/nodes/addon.wikipedia.search))
- `addon.wikipedia.summary` — Lead extract of an English Wikipedia article. ([docs](https://docs.tune.toys/nodes/addon.wikipedia.summary))
- `ai.chat` — Ask Anthropic, OpenAI or Gemini with your own vault key through the completion endpoint; text or JSON out. ([docs](https://docs.tune.toys/nodes/ai.chat))
- `bus.receive` — Pick up a named bus without a cable. Its type and width follow whatever drives the Send. ([docs](https://docs.tune.toys/nodes/bus.receive))
- `bus.send` — Name a bus and send a signal to it. Every Receive with the same name in this definition hears it. ([docs](https://docs.tune.toys/nodes/bus.send))
- `ctl.bands` — Split audio into log-spaced bands and follow each one's energy as a control lane: the audio-to-visual bridge. ([docs](https://docs.tune.toys/nodes/ctl.bands))
- `ctl.clock` — Bar, beat, eighth, sixteenth and triplet pulses plus the phase within the beat on six lanes, locked to the transport or at its own tempo. ([docs](https://docs.tune.toys/nodes/ctl.clock))
- `ctl.combine` — Concatenate two control bundles, preserving every lane without mixing. ([docs](https://docs.tune.toys/nodes/ctl.combine))
- `ctl.const` — A fixed control vector of up to eight lanes, set in the inspector. The number box of the control domain. ([docs](https://docs.tune.toys/nodes/ctl.const))
- `ctl.counter` — Count rising edges of a trigger lane, with step, limit, wrap and reset. Lane 1 is the normalised count, lane 2 the raw count. ([docs](https://docs.tune.toys/nodes/ctl.counter))
- `ctl.curve` — A drawn breakpoint curve on a control lane: shape the input or Position through it, or loop it at a rate, mapped onto Min to Max. ([docs](https://docs.tune.toys/nodes/ctl.curve))
- `ctl.envelope` — A control-rate ADSR, AD or AR envelope on a gate lane, 0 to 1, with velocity scaling and a done event. ([docs](https://docs.tune.toys/nodes/ctl.envelope))
- `ctl.follow` — Track the level of an audio bundle as one control lane per channel, with attack and release. ([docs](https://docs.tune.toys/nodes/ctl.follow))
- `ctl.hold` — Capture the input lanes whenever the trigger lane rises and hold them until the next trigger. ([docs](https://docs.tune.toys/nodes/ctl.hold))
- `ctl.lfo` — A free-running or tempo-synced low-frequency oscillator on a control lane, 0 to 1, with depth, offset, phase, skew, random shapes and a reset input. ([docs](https://docs.tune.toys/nodes/ctl.lfo))
- `ctl.random` — A seeded random control lane: steps, glides or walks to a new value on each trigger, or free-running at a rate or tempo division. ([docs](https://docs.tune.toys/nodes/ctl.random))
- `ctl.scale` — Map a control range onto another with a curve, clamp and inversion. Depth and offset for any modulation. ([docs](https://docs.tune.toys/nodes/ctl.scale))
- `ctl.select` — Extract a contiguous lane range from a control bundle. Use several to split a sensor's lanes. ([docs](https://docs.tune.toys/nodes/ctl.select))
- `ctl.smooth` — Slow a control lane down with separate rise and fall times so jumpy sensors and buttons stop clicking. ([docs](https://docs.tune.toys/nodes/ctl.smooth))
- `data.compare` — Compare two data values as numbers, text or lists and send true or false: ordering, equality, contains, starts or ends with, pattern match, empty, in list. ([docs](https://docs.tune.toys/nodes/data.compare))
- `data.convert` — Convert a value to another datatype, optionally picking a field or formatting a string; failures go to error. ([docs](https://docs.tune.toys/nodes/data.convert))
- `data.list` — List operations on data values: get, push, insert, remove, slice, sort, unique, flatten, join, range, sum, minimum, maximum, mean, shuffle and more. ([docs](https://docs.tune.toys/nodes/data.list))
- `data.math` — Arithmetic on data values, with the same operations as signal Math. Numbers in, numbers out; lists are worked element by element. ([docs](https://docs.tune.toys/nodes/data.math))
- `data.merge` — Combine up to eight inputs into one JSON object keyed by port, when any or all have arrived. ([docs](https://docs.tune.toys/nodes/data.merge))
- `data.random` — Make a random number, integer, boolean, string, colour or choice on each trigger; seeded when a seed is wired. ([docs](https://docs.tune.toys/nodes/data.random))
- `data.set` — Read CSV, TSV, JSON or NDJSON from an asset, a host-chosen file or a connection as rows, JSON and text. ([docs](https://docs.tune.toys/nodes/data.set))
- `data.string` — Text operations on data values: length, case, trim, split, replace, slice, pad, repeat, search, regular expressions, format and JSON. ([docs](https://docs.tune.toys/nodes/data.string))
- `data.to-control` — Turn numbers into one control lane for a parameter or control input, mapped from a declared range. ([docs](https://docs.tune.toys/nodes/data.to-control))
- `data.value` — A literal source, the data domain's number box and message box. ([docs](https://docs.tune.toys/nodes/data.value))
- `log.console` — Write each incoming value to the Console panel with a level and label, rate-limited. ([docs](https://docs.tune.toys/nodes/log.console))
- `media.player` — Plays a video asset or an open stream URL (MP4, WebM; HLS where the browser plays it natively) as one video stream with play, loop and rate controls. ([docs](https://docs.tune.toys/nodes/media.player))
- `media.recorder` — Record a video stream to a file while Record is on. Audio joins when external audio buses land. ([docs](https://docs.tune.toys/nodes/media.recorder))
- `midi.arp` — Play held notes one at a time, locked to the transport: up, down, up-down, down-up, random, as played or as chords, over 1–4 octaves, with latch. ([docs](https://docs.tune.toys/nodes/midi.arp))
- `midi.channel` — Pass every channel, keep one channel, or move everything onto one channel. ([docs](https://docs.tune.toys/nodes/midi.channel))
- `midi.euclid` — Spread pulses as evenly as possible over a cycle of steps, locked to the transport, and play each as a note, with rotation, swing and accent. ([docs](https://docs.tune.toys/nodes/midi.euclid))
- `midi.from-control` — Send control lanes as MIDI controllers: lane 1 to the first CC number, lane 2 to the next, one message per change. ([docs](https://docs.tune.toys/nodes/midi.from-control))
- `midi.from-data` — Play a JSON list of notes in beats as MIDI on each trigger, scheduled on the transport. ([docs](https://docs.tune.toys/nodes/midi.from-data))
- `midi.in` — A logical MIDI input port. The host binds it to a device or the DAW's MIDI bus; the Toy never stores a device. ([docs](https://docs.tune.toys/nodes/midi.in))
- `midi.keyboard` — Notes from the on-screen piano and computer typing become MIDI. The face of the piano widget. ([docs](https://docs.tune.toys/nodes/midi.keyboard))
- `midi.merge` — Interleave up to four MIDI streams by time, in input order for equal offsets. ([docs](https://docs.tune.toys/nodes/midi.merge))
- `midi.notes` — Turn control lanes (pitch, gate and velocity) into MIDI notes, the inverse of MIDI to control, so control sources and sensors can play instruments. ([docs](https://docs.tune.toys/nodes/midi.notes))
- `midi.out` — A logical MIDI output port. The host binds it to a device or the DAW; messages leave at their sample offsets. ([docs](https://docs.tune.toys/nodes/midi.out))
- `midi.step` — Up to 64 steps of notes, rests and ties locked to the transport, with per-step pitch, velocity and probability, swing and four directions. ([docs](https://docs.tune.toys/nodes/midi.step))
- `midi.to-control` — Turn MIDI into six control lanes: pitch, gate, velocity, bend, pressure and one CC, with last-note priority. ([docs](https://docs.tune.toys/nodes/midi.to-control))
- `midi.transpose` — Shift note numbers by semitones and octaves, clamped to the MIDI range. ([docs](https://docs.tune.toys/nodes/midi.transpose))
- `midi.velocity` — Scale, offset, floor or fix note-on velocities. ([docs](https://docs.tune.toys/nodes/midi.velocity))
- `sense.body` — Track one body's pose into control lanes: torso position, hand positions, arm spread, lean, crouch and presence. ([docs](https://docs.tune.toys/nodes/sense.body))
- `sense.face` — Track one face into control lanes: position, head pose, gaze, mouth, smile, blinks, brows and presence. ([docs](https://docs.tune.toys/nodes/sense.face))
- `sense.gesture` — Recognise seven hand gestures into one gate lane each, with confidence and presence. ([docs](https://docs.tune.toys/nodes/sense.gesture))
- `sense.hands` — Track up to two hands from a video stream into control lanes: position, depth, pinch, spread, openness and presence per hand. ([docs](https://docs.tune.toys/nodes/sense.hands))
- `sense.motion` — The device's accelerometer and gyroscope as control lanes: acceleration, rotation rate, tilt, heading and a shake gate. ([docs](https://docs.tune.toys/nodes/sense.motion))
- `std.autotune` — Detects the pitch of a monophonic input and pulls it to the nearest note of the Toy tuning, a scale or held MIDI notes. ([docs](https://docs.tune.toys/nodes/std.autotune))
- `std.bus` — Sum up to eight inputs with per-strip gain, pan and mute into one bus with a master level. The Mix drawer's desk. ([docs](https://docs.tune.toys/nodes/std.bus))
- `std.chorus` — Prepared multi-voice chorus, ensemble and vibrato over arbitrary channel bundles. ([docs](https://docs.tune.toys/nodes/std.chorus))
- `std.combine` — Concatenate two audio buses, preserving every channel without mixing. ([docs](https://docs.tune.toys/nodes/std.combine))
- `std.compare` — Turn any signal into a gate or trigger by comparing it to a threshold or to another signal, lane by lane, with hysteresis and tolerance. ([docs](https://docs.tune.toys/nodes/std.compare))
- `std.compressor` — Peak/RMS compression with a sidechain key input, detector filtering, hold, adaptive release and channel linking. ([docs](https://docs.tune.toys/nodes/std.compressor))
- `std.convolver` — Convolution with an attached WAV impulse response: real rooms, speaker cabinets and creative textures, with predelay, trims and gain. ([docs](https://docs.tune.toys/nodes/std.convolver))
- `std.crossover` — Splits audio into 2–4 Linkwitz-Riley bands, output as one band-major bundle whose bands sum back flat. ([docs](https://docs.tune.toys/nodes/std.crossover))
- `std.crush` — Reduces bit depth and sample rate: 2^bits levels, sample-and-hold with jitter, optional triangular dither. ([docs](https://docs.tune.toys/nodes/std.crush))
- `std.delay` — Tempo-aware, smoothly retimed echoes with colored, ducked and explicit multichannel feedback. ([docs](https://docs.tune.toys/nodes/std.delay))
- `std.denoise` — Spectral noise gate: learn a noise profile or follow the floor adaptively, then turn down each frequency bin that stays near it. ([docs](https://docs.tune.toys/nodes/std.denoise))
- `std.drive` — Four nonlinear shapers with DC removal, tone and latency-aligned filtered oversampling. ([docs](https://docs.tune.toys/nodes/std.drive))
- `std.envelope` — Curved AD, AR and ADSR gain envelopes with looping and explicit retrigger behavior. ([docs](https://docs.tune.toys/nodes/std.envelope))
- `std.eq` — Six-band parametric EQ: RBJ biquad cuts, shelves, bells and notches with per-band bypass and output trim. ([docs](https://docs.tune.toys/nodes/std.eq))
- `std.gain` — A clean multichannel gain stage. ([docs](https://docs.tune.toys/nodes/std.gain))
- `std.gate` — Noise gate and downward expander with a sidechain key input, range, hold, lookahead, detector filtering and channel linking. ([docs](https://docs.tune.toys/nodes/std.gate))
- `std.granulator` — Replays windowed grains of the live input: up to 32 at once, scheduled from the node path, with freeze, reverse and pitch. ([docs](https://docs.tune.toys/nodes/std.granulator))
- `std.harmonizer` — Adds up to three pitch-shifted voices to the input, each with its own interval, level and pan. ([docs](https://docs.tune.toys/nodes/std.harmonizer))
- `std.limiter` — Linked or independent sample-peak limiting with hold and adaptive release. ([docs](https://docs.tune.toys/nodes/std.limiter))
- `std.lowpass` — A gentle one-pole filter for warmer edges. ([docs](https://docs.tune.toys/nodes/std.lowpass))
- `std.math` — Arithmetic on any signal, lane by lane: add, multiply, divide, power and more on audio or control operands. The output runs at the rate of its fastest input. ([docs](https://docs.tune.toys/nodes/std.math))
- `std.matrix` — Route and mix input channels into a declared output bundle with explicit gains. ([docs](https://docs.tune.toys/nodes/std.matrix))
- `std.mixer` — Blend two multichannel signals with a shared balance. ([docs](https://docs.tune.toys/nodes/std.mixer))
- `std.multiband` — Three-band compressor on a flat-summing crossover: per-band threshold, ratio, attack, release, makeup and solo, then an output trim. ([docs](https://docs.tune.toys/nodes/std.multiband))
- `std.noise` — Thirteen streaming noise colors and textures with independent channel and instance state. ([docs](https://docs.tune.toys/nodes/std.noise))
- `std.oscillator` — A continuous multichannel sine voice. Start with a low monitor level. ([docs](https://docs.tune.toys/nodes/std.oscillator))
- `std.phaser` — Swept allpass notches: 2 to 12 stages, a free or transport-locked sweep, signed feedback and channel spread. ([docs](https://docs.tune.toys/nodes/std.phaser))
- `std.pitch` — Shifts audio up or down by up to two octaves with a splicing delay line, with fine cents, feedback and a dry/wet mix. ([docs](https://docs.tune.toys/nodes/std.pitch))
- `std.player` — Plays an attached WAV asset as one stream for loops, beds and backing tracks, following the transport or running free. ([docs](https://docs.tune.toys/nodes/std.player))
- `std.poly` — Eight owned, velocity-sensitive oscillator voices with ADSR, sustain and MPE, played from a MIDI cable in the Toy's tuning. ([docs](https://docs.tune.toys/nodes/std.poly))
- `std.resonance` — Spectral resonance suppressor: finds narrow peaks that stand above the local spectral average and pulls them down dynamically, bin by bin. ([docs](https://docs.tune.toys/nodes/std.resonance))
- `std.reverb` — An eight-line modulated feedback-delay network with room, hall and plate-like tunings. ([docs](https://docs.tune.toys/nodes/std.reverb))
- `std.sampler` — Plays an attached WAV asset as an instrument of up to eight voices in the Toy's tuning, with a playback region, a sustain loop and ADSR. ([docs](https://docs.tune.toys/nodes/std.sampler))
- `std.select` — Extract a contiguous channel range. Use several selectors to split a bundle. ([docs](https://docs.tune.toys/nodes/std.select))
- `std.sum` — Sum four audio buses channel by channel. Width follows the connected buses. ([docs](https://docs.tune.toys/nodes/std.sum))
- `std.suppressor` — Feedback suppressor: tracks howling tones and places up to eight narrow time-domain notches on them, with no added latency. ([docs](https://docs.tune.toys/nodes/std.suppressor))
- `std.svf` — Multimode resonant state-variable filtering with selectable slopes. ([docs](https://docs.tune.toys/nodes/std.svf))
- `std.transient` — Boosts or softens the attack and sustain of each hit, independent of level, with a floor, mix and output trim. ([docs](https://docs.tune.toys/nodes/std.transient))
- `std.tuner` — Passes audio through unchanged and shows the nearest degree of a microtonal tuning on its face. Mute silences it like a tuner pedal. ([docs](https://docs.tune.toys/nodes/std.tuner))
- `std.vocoder` — Channel vocoder: a modulator on Key imposes its band envelopes on the carrier through 8 to 32 band-pass filters, with formant shift and sibilance. ([docs](https://docs.tune.toys/nodes/std.vocoder))
- `std.wave` — Selected waveform kernels, continuous morphing, harmonic shapes and phase/gate control; an optional MIDI input plays notes in the Toy's tuning. ([docs](https://docs.tune.toys/nodes/std.wave))
- `std.wavetable` — Plays a drawn or preset table of up to eight 2048-sample frames with position morphing, unison and MIDI pitch. ([docs](https://docs.tune.toys/nodes/std.wavetable))
- `time.cron` — Fire a trigger on an interval, a cron expression or musical beats, with the time as JSON. ([docs](https://docs.tune.toys/nodes/time.cron))
- `video.blur` — Gaussian blur with a bounded radius at the source resolution. ([docs](https://docs.tune.toys/nodes/video.blur))
- `video.camera` — A camera feed as one video stream. The Toy names a logical camera; the host binds it to a device after the person allows it. ([docs](https://docs.tune.toys/nodes/video.camera))
- `video.chroma-key` — Turn one colour transparent with tolerance, softness and spill suppression: the green screen. ([docs](https://docs.tune.toys/nodes/video.chroma-key))
- `video.color` — Adjust brightness, contrast, saturation, hue, gamma and warmth, or invert the picture. ([docs](https://docs.tune.toys/nodes/video.color))
- `video.combine` — Concatenate two video bundles into one, preserving every stream. ([docs](https://docs.tune.toys/nodes/video.combine))
- `video.composite` — Stack up to four layers over a base at the base's size with blend mode, opacity, position and scale per layer. ([docs](https://docs.tune.toys/nodes/video.composite))
- `video.crossfade` — Blend two streams with one mix control. ([docs](https://docs.tune.toys/nodes/video.crossfade))
- `video.display` — A window, tab or whole display as one video stream, chosen by the person each time it starts. ([docs](https://docs.tune.toys/nodes/video.display))
- `video.image` — A declared image asset as a still video stream, for logos, backgrounds and keys. ([docs](https://docs.tune.toys/nodes/video.image))
- `video.multiview` — Tile a bundle of streams into one picture with labels, for monitoring. ([docs](https://docs.tune.toys/nodes/video.multiview))
- `video.paint` — A transparent surface the paint widget draws on, as one video stream to composite over anything. ([docs](https://docs.tune.toys/nodes/video.paint))
- `video.pixelate` — Mosaic cells and posterised levels for a chunky look. ([docs](https://docs.tune.toys/nodes/video.pixelate))
- `video.select` — Extract a contiguous range of streams from a video bundle. ([docs](https://docs.tune.toys/nodes/video.select))
- `video.snapshot` — Capture the newest frame as a still when the shutter fires; the host saves it. ([docs](https://docs.tune.toys/nodes/video.snapshot))
- `video.switch` — Cut or transition between up to four sources; outputs the program. The face of the switcher widget. ([docs](https://docs.tune.toys/nodes/video.switch))
- `video.text` — Renders a text template as a transparent video stream; {1} to {8} in the template show control lanes. Scoreboards and lower thirds. ([docs](https://docs.tune.toys/nodes/video.text))
- `video.transform` — Move, scale, rotate, crop and mirror a stream, and set the output size. Also the resize node. ([docs](https://docs.tune.toys/nodes/video.transform))
- `web.frame` — A sandboxed web page shown by a web widget, exchanging messages only with its declared origin. ([docs](https://docs.tune.toys/nodes/web.frame))
- `web.request` — Fetch a URL on each trigger under the network allowlist; secrets come from a vault slot, never the Toy. ([docs](https://docs.tune.toys/nodes/web.request))
- `web.scrape` — Fetch a page through the proxy and extract text, rows or links with a CSS selector; scripts never run. ([docs](https://docs.tune.toys/nodes/web.scrape))
- `web.socket` — Keep a WebSocket open to an allowlisted host, sending and receiving messages with optional reconnect. ([docs](https://docs.tune.toys/nodes/web.socket))
