# Frame views: any interface code

Build a Block interface with React or another framework, SVG, canvas, drag and timers, run in a guarded opaque frame with StillMade theming and shared editing.

A frame view (`"runtime": "frame"` in the view) is an interface written with
ordinary web code: React, Svelte, Vue or Preact bundles, SVG, canvas and
WebGL, pointer capture and drag, timers, loops, recursion, classes and Web
Workers. Use it when the reviewed subset of standard views is too small for
the interface you want.

### Folder layout

```
my-block/
  stillmade.block.json
  src/run.js             or another runtime (recipe, module, capability)
  src/view.html          markup, for example <div id="root"></div>
  src/view.css           styles; use StillMade's theme variables
  src/view.js            ONE classic script: bundle with --format=iife
  src/view.config.json   {"runtime": "frame"}
  tests/fixtures.json
```

`src/view.config.json` may also set `"appearance"` and `"files"` (assets, see
below). Bundle npm dependencies into `src/view.js` as an IIFE, for example:

```sh
esbuild src/view.jsx --bundle --format=iife --minify --jsx=automatic \
  --define:process.env.NODE_ENV='"production"' --outfile=src/view.js
```

Limits: markup and each stylesheet up to 256 KiB, `view.js` up to 4 MiB,
and up to 32 asset files with 8 MiB in total.

### The `StillMade` object

Frame views get the same `StillMade` object as standard views: `input` and
`onInput`, `run`, `useOutput`, `getShared`, `onShared`, `updateShared`,
`bindShared`, `connectDocument`, `previewImage`, `previewMedia`, `render`
and the rest of the interface bridge. In addition:

| Member | What it does |
| --- | --- |
| `StillMade.asset(path)` | A `blob:` URL for one of the view's asset files, for `<img>`, `new FontFace()` or `<video>`. |
| `StillMade.assetBytes(path)` | A copy of an asset file's bytes as an `ArrayBuffer`. |

Shared state works as in every view: keep each independently edited value in
its own field (for example `point0`, `point1`) so two people editing
different values never conflict.

### Theming

The theme variables from StillMade's design system are always defined:
`var(--bg)`, `var(--bg-elev-1)`, `var(--fg)`, `var(--fg-muted)`,
`var(--accent)`, `var(--border-tok)`, `var(--divider)`, `var(--r-3)` and the
rest. Colors written with them follow Light, Dark and White automatically.
Frame views are not required to use them; the appearance check reports
hard-coded colors as advice instead of refusing the view.

### Assets

Images, fonts, JSON, audio and video the view needs ship as files named by
SHA-256, like module files:

```json
{"runtime": "frame", "files": {"schemaVersion": 1, "files": {
  "fonts/inter.woff2": {"sha256": "…", "bytes": 48256, "mediaType": "font/woff2"}
}}}
```

`stillmade-block pack` fills in the digests and sizes. StillMade checks every
file against its SHA-256 before the view starts.

### What the frame does not allow

The view runs in an opaque-origin frame with its own policy:

- no network (`fetch`, WebSocket and remote images, fonts or scripts fail);
- no code from strings (`eval`, `new Function`, inline event attributes) and
  no extra script elements;
- no navigation, popups, downloads, forms that submit, or dialogs;
- no WebAssembly on the page (run heavy computation in the Block's runtime,
  for example a module Block, and call it with `StillMade.run`);
- no storage or access to StillMade's page.

Workers created from `blob:` URLs are allowed and run off the page's thread.

### Run limits

StillMade compiles the view so every function and loop checks a time budget.
One task may run for 250 ms; past that it is stopped with an error, and a view
that keeps the page busy most of the time, stops answering, or navigates its
frame is closed with a message. Move long computation into a Worker or the Block's runtime.
