A complete augmented-reality studio you can drop into any web page. Place as many 3D models as you like in your real space through the camera, describe a new one and watch it appear, arrange everything by hand, then share the whole scene as a link, a QR code, or a live room someone else can build in with you.
That frame is the real package, running the same code you install. On a phone, tap Camera and the models stand on your actual floor.
No build step, no API key, no account. The models and the text-to-3D lane are free and keyless.
<script type="module" src="https://unpkg.com/3d-ar-studio/dist/ar-studio.min.js"></script>
<ar-studio></ar-studio>
npm i 3d-ar-studio three
import { createArStudio } from '3d-ar-studio'
const studio = createArStudio('#stage', {
assets: 'https://your.cdn/models.json', // your catalogue, or leave it out for the free CC0 library
branding: { title: 'Acme AR', accent: '#00b894' },
})
studio.on('add', ({ placement }) => console.log('placed', placement.title))
npx 3d-ar-studio create my-ar-site # a ready-to-publish folder
npx 3d-ar-studio deploy # push it and turn on GitHub Pages
Place, drag, pinch-resize, twist-rotate and duplicate as many models as you want in a single live camera view. Every other web-AR drop-in stops at one.
Type "a brass desk lamp" into the dock. The generation runs behind the live view and the finished model drops into the room. Free, keyless, no account.
An always-armed hit-test reticle, one XRAnchor per model, real-world light estimation, and depth occlusion so models hide behind your furniture.
iPhones have no WebXR, so they get Apple's AR Quick Look: true plane detection, scale and occlusion. The model is converted to USDZ on the device in about a second. Android without WebXR gets Scene Viewer.
The whole arrangement (models, positions, rotations, scales) round-trips through the URL. Compose on a laptop, scan the QR, it reopens exactly on your phone.
Open a room, share a six-character code, and every add and move syncs to everyone in it in real time, with live presence.
Any humanoid GLB with no baked animation gets an idle clip retargeted onto its own skeleton: Mixamo, VRM, Avaturn, Unreal, Daz. No rig allow-list, no T-poses.
A bundled MCP server lets Claude, ChatGPT or any agent generate a model, compose an arrangement, and hand your user one link that opens it in their room.
Out of the box the tray is filled from three.ws: a few hundred public-domain (CC0) props, free for commercial use, served with open CORS. Swap in your own with one option a URL, an array, or a function.
// 1. A JSON file anywhere. Five common shapes are read without reshaping.
createArStudio(el, { assets: 'https://cdn.acme.com/models.json' })
// 2. A list you hold in code.
import { staticSource } from '3d-ar-studio/sources'
createArStudio(el, { assets: staticSource({
label: 'Our furniture',
items: [{ src: 'https://cdn.acme.com/chair.glb', title: 'Aero chair', poster: '…' }],
}) })
// 3. Several tabs at once, in order.
createArStudio(el, { assets: ['recent', myCatalogue, 'objects', 'link'] })
// 4. Anything else: a source is just an object with a list().
createArStudio(el, { assets: {
id: 'search', label: 'Search', searchable: true,
async list() {
const r = await fetch('/api/models').then((x) => x.json())
return r.map((m) => ({ src: m.glb, title: m.name, poster: m.thumb }))
},
} })
Your users can also point the studio somewhere else themselves, without touching your code:
add ?assets=https://…/manifest.json to the page URL. Only https URLs are accepted, and every
model source is re-validated before it reaches the loader.
| Option | Default | What it does |
|---|---|---|
assets | 'three.ws' | Where models come from: a preset, a manifest URL, a source object, or an array of them. |
generate | enabled, free three.ws lane | { enabled, endpoint, kind, tier }. endpoint is any MCP server exposing a compatible generate tool. |
rooms | enabled | { enabled, server }. Point server at your own Colyseus deployment to host shared rooms yourself. |
animations | three.ws idle clip | { enabled, manifestUrl, clip }. The clip retargeted onto humanoid models that ship no animation. |
lighting | 'studio' HDRI | { preset, urls }. Set preset: null for procedural lighting only and zero HDRI download. |
branding | { title, accent, backHref, backLabel }. | |
shareBaseUrl | this page | Where share links and QR codes point. |
persistKey | 'ar-studio:scene:v1' | localStorage key for the saved scene. Change it to run two studios on one origin. |
maxPlacements | 20 | Cap on simultaneous models. Keeps low-end phones interactive. |
allowUrlOverride | true | Honour ?assets=, ?src=, ?room= and ?forge= on the hosting page's URL. |
onEvent | null | Called with (event, detail) for every notable action: wire it to your analytics. |
Subscribe with studio.on(name, fn), or listen for ar-studio:<name> DOM events on the mounted element:
add, remove, select, clear, generate,
generate-error, camera, xr, room, share.
This is not a demo written to look good in a README. The rendering ladder, the anchor lifecycle, the retargeting pipeline, the scene format and the shared-room protocol are lifted from the AR surfaces running in production on three.ws, and generalized so they work on your site with your models.