# Artifact authoring Start here when asked to build an artifact for Spatial Web Evals. **AI model** means the author (a name supplied by the caller); **``** means Apple's native HTML element for displaying a 3D asset. They are independent. ## What is available | Need | Resource already in this repository | | --- | --- | | A named area with embedded artifacts | `artifacts///`; automatically grouped under `/evals/#provider-` and `/evals/#model-` | | A complete editable page | `resources/artifact.html`, instantiated by `npm run artifact:new` | | HTML, CSS, SVG, canvas, WebGL, JavaScript | Author directly in the artifact directory; no frontend framework required | | Inline native 3D with a flat fallback | `assets/model.js`, shared `.spatial-*` rules in `assets/base.css` | | Safari website environment | `assets/immersive.js`, enabled with `data-environment` on the preview wrapper | | Anonymous usage analytics on the live site | `assets/analytics.js`, loaded first in the head; `model.js` and `immersive.js` already report their events | | Colours, typography, display preferences | `assets/tokens.css`, `assets/base.css`, `assets/appearance.js` | | Existing USDZ and preview image | `assets/ethics-of-ai.usdz` and `assets/spatial-cube.png` (site-owned sample, not your output) | | Example reproducible asset generator | `scripts/create-spatial-cube.py`; requires Blender 5 and Apple USD tools | | Artifact discovery for readers/agents | Generated `/artifacts/index.json`, with modelId, provider, modelName, artifactId, title, description | Node.js 20+ is sufficient to author/build/serve pages. Blender, `usdzip`, `usdcrush`, and `usdchecker` are additional asset-generation tools, not npm dependencies. Check that they exist before promising a new USDZ. The repository does not supply an image-generation service, a model API, Three.js, or an asset marketplace; discover the actual tools in your session if needed. Do not embed credentials or rely on private chat attachment URLs in artifacts. ## Rich environment eval For a furnished scene with meaningful object interactions, use [`resources/rich-environment-eval.md`](../resources/rich-environment-eval.md). It links a reusable prompt, review rubric, and reproducible worked example with original GLB/USDZ assets. Browser interactions and static native immersion are explicitly distinguished. ## Add an artifact 1. Read `AGENTS.md` and this guide. Use the exact supplied model name and provider (the organisation that makes the model, such as `OpenAI`); request either if unknown. Choose lowercase hyphenated IDs for stable URLs. 2. Run (replace the example identity, IDs, and title): ```sh npm run artifact:new -- example-model "Example Model" quiet-room "Quiet room" "Example Lab" ``` 3. Edit `artifacts/example-model/quiet-room/index.html`, replace `scene.usdz` and `preview.png`, and update the accessible description. For a flat artifact, replace the preview markup with your HTML/canvas and remove unused media and spatial scripts. Keep scripts, styles, media, and reproducible generators here. 4. Update `artifact.json` with nonempty `provider`, `modelName`, `title`, and `description`. The gallery groups models under a heading for each provider, sorted alphabetically. Include optional `reasoningEffort` when the caller or session metadata supplies it; this appears on the gallery card and in the index. Never infer it from response length. Record the attribution source in the artifact README. The gallery provides a reasoning-level selector for each model, populated from its artifacts' `reasoningEffort` values. New levels appear automatically when real artifacts are added. Artifacts without attribution appear as **Not recorded**; without JavaScript, all artifacts remain visible. Every artifact in one model directory must use the same exact `modelName` and `provider`. Spell a provider the same way across models: names that differ only in case or punctuation, such as `OpenAI` and `Open AI`, fail the build. IDs come from directory names; `index.html` is always the entry point. The build fails on invalid IDs, missing entries/metadata, or inconsistent names or providers. 5. Run `npm run check`. Build output includes the isolated preview on `/evals/` and the standalone `/artifacts/example-model/quiet-room/index.html`. No route registration or gallery edits are needed. Add a second artifact directory to keep earlier attempts intact. The scaffold deliberately reuses the site's cube so it loads immediately. It is not a completed model submission: replace starter copy and assets before delivery. Document asset provenance and actual validation in an artifact-local `README.md`. Everything inside `artifacts/` is published, so keep only intended public files. The scaffold refuses to overwrite an existing artifact. Gallery previews use a script-enabled sandbox without same-origin permission. They isolate artifact scripts from the host page; storage, module fetches, and immersive APIs may be restricted there. Use classic scripts for minimal previews and the **Open artifact** link for the full experience. Standalone pages are trusted site code: review them before publishing. Keep links relative so the same `dist/` can be bundled in the native shell. Spatial API support in Safari does not imply support in the shell's WKWebView. ## Inline `` The starter pairs a USDZ `` with a PNG fallback. `assets/model.js` detects `HTMLModelElement`, waits for `model.ready`, then reveals the model and updates its accessibility label. Unsupported browsers and failed loads keep the image. The helper supports multiple wrappers on a page. Use `stagemode="orbit"` for a rotatable object. For an environment interior, remove orbit if rotation is inappropriate. `environmentmap="lighting.hdr"` is optional image-based **lighting**, not surrounding room geometry. Keep the HDR alongside the USDZ if used. The local server supplies spatial MIME types; verify the deployed server also returns `model/vnd.usdz+zip` for USDZ. `site/worker.mjs` supplies deployed spatial MIME types through the hosting asset binding. The local server's MIME map alone does not configure hosting. The build emits `dist/server/index.js` and a `dist/client/` mirror of the native web files. Hosting routes ordinary static URLs before the handler. On HTTP(S), `model.js` therefore loads same-origin USDZ files through `/spatial-media/`; this virtual route enforces the model MIME type. The local server supports the same route. File-backed native pages retain their original relative asset URLs. ## Safari environments API guidance checked **2026-09-06**. Support differs by OS, Safari release, and device; recheck the official references before targeting a newer release. **Native website environment — smallest path:** author a room/landscape as USDZ, replace `scene.usdz` and the preview image, then add `data-environment` to the starter's `data-spatial-visual` wrapper. The existing helper uses `document.immersiveEnabled`, `model.requestImmersive()`, `document.exitImmersive()`, and `document.immersiveElement`. It waits for readiness, exposes enter/exit controls, handles rejected requests, and tracks `immersivechange` (including a user exiting via the Digital Crown). Entry happens only on a button click. It runs on the standalone artifact page; the gallery preview points visitors there. Without the API, visitors retain the inline model or image. This is the API introduced in the Safari 27 / visionOS 27 generation; do not claim it works on every released Safari. Author real-world scale with Y up, metres, and the origin at the viewer's feet. Leave clear space around the origin. Inline fitting and immersive placement have different reference frames: if you customize `entityTransform` for an interior preview, recompute it on `immersivechange`; do not carry an inline eye-height offset into immersion. A lighting HDR alone does not create an environment. Optimize meshes/materials/textures and validate the USDZ using `usdchecker`. **Older developer previews:** Safari 26-era examples may show `` or `@backdrop`. Those are the earlier declarative approach, not interchangeable with `requestImmersive()`. If asked to target that preview specifically, verify its exact version/feature settings and follow its documentation; do not silently label it supported. **Interactive immersive scene — WebXR:** for custom rendering, movement, and spatial input, use `navigator.xr.isSessionSupported('immersive-vr')` and request the session directly from a click. Safari on visionOS supports this route; do not substitute `immersive-ar` without checking support. Use a renderer with an actual XR frame loop (WebGL or a deliberately added XR-capable library), per-eye views, and session-end cleanup. A successful capability probe or a canvas alone is not a rendered environment. This kit provides native USDZ environments; a WebXR renderer is an artifact-specific addition. WebXR requires a secure context: HTTPS on Vision Pro, or localhost on the same development device. `http://.local:4173` can preview the ordinary page on a headset but is **not** secure localhost there. Use trusted HTTPS for immersive device testing. Keep a flat preview when XR is absent, declined, or fails. ## Verify and report - Build/unit checks validate discovery, attribution, previews, routes, and MIME types. `npm run check` also runs the repository's responsive browser matrix. - Check your artifact for keyboard access, readable fallback, small screens, reduced motion, and no unnecessary camera or viewpoint motion. - For spatial claims, check the standalone URL in Safari on the target device: loading, scale/origin, enter, exit, system dismissal, and retry after a decline. Record OS/browser versions and failures. If no device is available, state that spatial rendering is unverified. Mocked API checks do not replace this. ## Official references - [HTML model samples and APIs](https://webkit.org/demos/model-demos/) - [Apple: What's new for the spatial web (WWDC25)](https://developer.apple.com/videos/play/wwdc2025/237/) - [Apple: Immersive website environments (WWDC26)](https://developer.apple.com/videos/play/wwdc2026/320/) - [WebKit spatial backdrop explainer (current API and earlier proposal)](https://github.com/WebKit/explainers/tree/main/spatial-backdrop) - [Apple: Build immersive web experiences with WebXR](https://developer.apple.com/videos/play/wwdc2024/10066/) - [Immersive Web working group runnable WebXR samples](https://immersive-web.github.io/webxr-samples/) On the deployed site this guide is `/resources/artifacts.md`; the raw starter is `/resources/artifact.html`. Repository-relative paths above describe source files. Start from a checkout to use the scaffold command.