Shared device frames serve at /frames/<name>.html and previously assigned the raw ?screen= value to the inner iframe.src. A project-relative value like screen=screens/foo.html resolved against /frames/, producing /frames/screens/foo.html (404), instead of the embedding project's /api/projects/:id/raw/screens/foo.html. The five frame HTML files now resolve relative ?screen= values against document.referrer when present (the embedding project preview), falling back to location.href so standalone /frames/* loads keep working. Absolute and root-relative paths are passed through unchanged. Adds an e2e Vitest spec that evaluates each frame's inline <script> in a Node vm and asserts iframe.src under five scenarios per file (25 cases total): project-relative against referrer, root-relative pass-through, absolute pass-through, empty referrer fallback, and missing ?screen= no-op. Fixes #2234 |
||
|---|---|---|
| .. | ||
| android-pixel.html | ||
| browser-chrome.html | ||
| ipad-pro.html | ||
| iphone-15-pro.html | ||
| macbook.html | ||
| README.md | ||
Shared device frames
Reusable, pixel-accurate device chrome that any skill can compose into a multi-device or multi-screen layout. Each frame is a self-contained HTML snippet that renders a device shell and embeds its inner screen via an ` \`\`\`
In an OD-managed project, the recommended pattern is:
``` my-project/ ├── index.html ← gallery view: composes 3+ frames in a row ├── screens/ │ ├── home.html ← inner content rendered inside iphone-15-pro.html │ ├── search.html │ └── detail.html └── (no copy of frames — point at the shared assets folder) ```
Design tokens
Each frame reads its inner screen's tokens via `postMessage` if you want the bezel to tint with the active palette. The default state is "phone in hand" — neutral metallic — which works against any background.
Authoring rules
When extending this library:
- No external assets. Inline all SVG. No font imports. No image URLs.
- One frame per file. Don't bundle iPhone + Android in one HTML.
- `?screen=` query is the only contract. Don't introduce other query params; the harness has to be predictable for skills to use.
- The frame is decorative chrome only. All content lives in the inner
screen file. The frame must work with
?screen=about:blank(showing just the device shell). - Match real device dimensions. iPhone 15 Pro is 390×844 logical pixels. iPad Pro 11" is 834×1194. Don't ship a "looks like" frame — the seed has to match.