OpenAI's unit of distribution is the plugin: a folder with a manifest at
.codex-plugin/plugin.json, optional skills, an optional MCP server and optional UI,
listed in one Plugins Directory shared by ChatGPT and Codex
(https://developers.openai.com/plugins). This repository is that plugin: the
manifest sits at the repo root and points at the skills that already live under
agents/ and at the sceneview-mcp server.
| Component | Where | Directory type |
|---|---|---|
| Manifest | .codex-plugin/plugin.json |
required |
| Skills (3) | agents/sceneview, agents/sceneview-ios, agents/sceneview-web |
skills-only submission works with these alone |
| Skill display metadata | agents/<skill>/agents/openai.yaml |
optional |
| Bundled MCP (stdio, Codex) | .codex-plugin/mcp.json → npx -y sceneview-mcp |
optional |
| Remote MCP (ChatGPT) | npx sceneview-mcp --http — Streamable HTTP at /mcp, see mcp/README.md |
needs a public URL |
| 3D viewer UI | ui://widget/3d-viewer.html served by the same server (MCP Apps, text/html;profile=mcp-app) |
optional |
| Codex discovery in any checkout | .agents/skills/* symlinks → agents/*; .agents/plugins/marketplace.json for local install |
— |
Why the repo root and not a copy: the skills are validated against the library
source by .claude/scripts/check-sceneview-skill.sh, and a second copy under
plugins/ would be one more surface to drift. Codex follows symlinks in
.agents/skills, so the canonical files stay under agents/.
- Skills-only — zero infrastructure, self-serve, no domain verification. The three
SKILL.mdfiles carry the API contract (llms.txtlink), recipes, migration guide and demo references. Submit this first. - Skills + MCP — adds the 32 tools and the inline 3D viewer. Requires a public
production URL serving
sceneview-mcp --http, domain verification and a CSP declaration. The hosted gateway was deleted on 2026-08-31, so this shape waits for an explicit hosting decision; nothing in the package assumes one.
Both shapes are compliant with the directory's monetization rule (no selling or promoting subscriptions inside the plugin): the plugin contains no purchase or subscription flow. The remote surface omits the three tools that need your own third-party credentials, because a shared anonymous endpoint cannot hold them. The skills link to Apache-2.0 sources.
- Name: SceneView 3D & AR
- Short description: Write working 3D and AR code for Android, Apple and the web on the first try.
- Long description: see
interface.longDescriptionin the manifest — keep the two in sync by editing the manifest, this file only mirrors it. - Category: Developer Tools · Capabilities: Read
- Website: https://sceneview.github.io · Support: https://github.com/sceneview/sceneview/issues
- Privacy policy: https://sceneview.github.io/privacy · Terms: https://github.com/sceneview/sceneview/blob/main/mcp/TERMS.md
- Logo:
branding/exports/logo/logo-512.png(512 px PNG, the manifest'slogo); composer icon:website-static/favicon-192.png. One screenshot of the 3D widget (DamagedHelmet, 800 × 600, headless Chrome + SwiftShader) exists for the listing form; it is kept with the maintainer's listing assets, not in the repository.
- Build a Jetpack Compose screen that loads a
.glbmodel with SceneView, orbit camera and a light. - Add ARCore plane detection with SceneView and place the model where the user taps.
- Write a SwiftUI view that shows a USDZ model with SceneViewSwift on iOS and visionOS.
- Render a GLB in the browser with
sceneview-weband add a WebXR "View in AR" button. - Migrate this SceneView 2.x snippet to the 4.x composable API.
- Show me this 3D model URL inline and tell me how to load it in Compose.
- Open the
.3mffile a print flow gave me in a Compose viewer, then place it in AR at its real size. - Preview the
.3mfyou just generated for 3D printing, in 3D.
| # | Prompt | Expected behaviour | Result shape |
|---|---|---|---|
| P1 | "Load models/helmet.glb in a Compose screen with SceneView" |
Skill sceneview triggers; code uses SceneView { }, rememberEngine, rememberModelLoader, rememberModelInstance; dependency io.github.sceneview:sceneview:4.51.0 |
Kotlin snippet that compiles against 4.51.0 |
| P2 | "Place that model on a detected plane when I tap" | ARSceneView { } with plane detection and a hit-test on tap; dependency arsceneview |
Kotlin snippet |
| P3 | "Same thing on iOS with SwiftUI" | Skill sceneview-ios; SceneView { } / ARSceneView { } from SceneViewSwift, SPM tag 4.51.0 |
Swift snippet |
| P4 | "Show me https://…/DamagedHelmet.glb in 3D" (MCP shape only) |
Tool view_3d_model is called; the widget renders the model inline; text names the URL |
structuredContent.modelUrl + widget |
| P5 | "Which SceneView sample fits an AR anchor demo?" (MCP shape only) | list_samples then get_sample |
Sample id + Kotlin source |
| P6 | "Open this .3mf in Compose and place it in AR at its real size" |
Skill sceneview triggers; the answer uses the ordinary rememberModelInstance(modelLoader, uri) path and invents no loadThreeMf API; the millimetre → metre scaling is named |
Kotlin snippet |
| P7 | "Show me the .3mf you just made for printing" (MCP shape only) |
view_3d_model is called with the .3mf URL; the widget converts it to glTF in the browser and renders it, and the format pill reads 3MF |
structuredContent.modelUrl + widget |
| N1 | "Write this with Unity / Unreal / raw ARCore" | Skill does not trigger (its description scopes it out); the assistant answers generically or asks | No SceneView code |
| N2 | "Call generate_3d_model to make me a chair" (MCP shape only) |
Remote server refuses the tool with an isError result pointing at the local npx sceneview-mcp path, which can use your own key |
Error result, no charge, no external call |
| N3 | "Show this model: file:///Users/me/model.glb" (MCP shape only) |
view_3d_model returns an error for a non-HTTPS URL; nothing is fetched |
Error result |
Test credentials: none — every tool on the remote surface is anonymous and read-only.
- Verified publisher identity at https://platform.openai.com/plugins (individual, under the SceneView name; "Apps Management" permission on the org).
- Skills-only submission — upload the skill bundle (the three directories under
agents/), paste the copy above, pick countries, attach release notes. - Only if the MCP shape is wanted: choose a host for
sceneview-mcp --http, setOPENAI_APPS_CHALLENGE_TOKENto the token the portal issues, confirmhttps://<host>/.well-known/openai-apps-challengereturns it, then register the URL in ChatGPT developer mode (Settings → Security and login → Developer mode) to test before submitting. - After approval, publish from the portal — approval alone does not list the plugin.
-
The local-marketplace install was exercised with Codex CLI 0.149.0 from a clean checkout, and Codex listed the three skills as
sceneview:sceneview,sceneview:sceneview-iosandsceneview:sceneview-webwhen asked what it had available:codex plugin marketplace add "$PWD" # registers marketplace `sceneview-local` codex plugin add sceneview@sceneview-local # → ~/.codex/plugins/cache/sceneview-local/sceneview/<version>/ codex plugin list # sceneview@sceneview-local installed, enabled 4.34.0
Two things the install taught us:
codex plugin marketplace add ./with a relative path does not resolve, pass an absolute path; and the install copies the repository into the cache without the.agents/skillssymlinks, so the skills resolve through the manifest's"skills": "./agents/"— the symlinks only serve discovery inside a checkout, never inside an installed plugin. -
The
pathinmarketplace.jsonis relative to the repository root (documented example is./plugins/my-plugin); this repo is the plugin itself, hence./. -
The remote server was exercised with
curlagainstnode dist/index.js --http(initialize,tools/list,resources/read); rendering of the widget inside ChatGPT's sandbox needs the developer-mode registration above.