# dash-model-viewer — interactive 3D models and AR for Dash

> dash-model-viewer — interactive 3D models and AR for Dash. Google's model-viewer vendored in the wheel: no CDN, works offline. By Pip Install Python.

> **`dash-model-viewer` — embed interactive 3D models directly into your Dash applications with Augmented Reality (AR) support.** By [Pip Install Python](https://2plot.dev).

A Dash wrapper around Google's [`model-viewer`](https://modelviewer.dev/). Drag
the model above — then note that reading its camera, its dimensions, or a click
on it takes a normal Dash callback and no JavaScript at all.

```bash
pip install dash-model-viewer
```

```python
from dash import Dash, html
import dash_model_viewer as dmv

app = Dash(__name__)
app.layout = html.Div([
    dmv.ModelViewer(
        id="viewer",
        src="/assets/astronaut.glb",
        alt="A 3D model of an astronaut",
        style={"width": "100%", "height": "480px"},
    )
])
```

That is the whole setup. Importing the package installs the runtime.

---

## What is different in 1.0.0

This release is a rebuild, and it fixes two things that had been broken for the
package's entire published life.

### AR actually works out of the box

`ar_modes` used to default to `"basic_annotations scene-viewer quick-look"`.
`basic_annotations` is not an AR mode — it was the name of a folder in the
repository, copy-pasted into the default. `webxr` was therefore missing, so
in-page WebXR AR never ran unless you happened to override the prop. Nothing
errored; the flagship feature was just quietly degraded everywhere.

The default is now `"webxr scene-viewer quick-look"`, and the test suite
asserts it. → [Augmented reality](/augmented-reality)

### Events reach Python

0.0.1 had **no output props**. Its single `setProps` call was commented out, so
nothing the model did could reach your callbacks. Anything interactive needed a
JavaScript file in `assets/` and a `clientside_callback` to reach it.

The canonical camera-presets example was **230 lines** because of that. It is
now **47 lines of Python**, with no JavaScript.
→ [Camera and views](/camera-and-views)

| Prop | Updates when |
| :-- | :-- |
| `camera` | the user moves the camera (debounced, echo-suppressed) |
| `model_state` | loading, loaded, failed |
| `model_info` | on load — dimensions in metres, variants, animations |
| `ar_status` / `ar_tracking` | an AR session changes state |
| `scene_point` | the model is clicked, with `pick_on_click=True` |
| `Slot.n_clicks` | a hotspot is clicked |

---

## The bundle ships in the wheel

`model-viewer` used to be fetched at runtime from a hard-coded
`ajax.googleapis.com` URL pinned to 3.5.0 — not a declared dependency, not
pinnable by you, and unavailable offline, behind a corporate egress proxy, or
under a strict `script-src` Content-Security-Policy.

Version 4.3.1 is now vendored inside the package and injected by a Dash hook.
It costs about 1 MB per page, which is a real number and is stated plainly on
the [quick start](/quick-start) rather than buried. `configure(use_cdn=...)`
opts back out.

---

## Full upstream parity, permanently

`<model-viewer>` has ~70 attributes and gains more each release. This package
names about twenty and gives you two escape hatches that reach all of the rest
— including attributes that do not exist yet:

```python
dmv.ModelViewer(
    id="viewer", src=..., alt=...,
    mv_environment_image="neutral",          # -> environment-image
    attributes={"orientation": "0deg 0deg 15deg"},
)
```

No regeneration, no release, no waiting.
→ [Attributes and parity](/attributes-and-parity)

---

## Where to go next

| Page | What it covers |
| :-- | :-- |
| [Quick start](/quick-start) | Install, first viewer, and why the script order matters |
| [Events and callbacks](/events-and-callbacks) | Every output prop, and `camera_change_debounce` |
| [Camera and views](/camera-and-views) | Presets, flight, framing an unknown model |
| [Slots and hotspots](/slots-and-hotspots) | Anchoring any Dash component to the geometry |
| [Attributes and parity](/attributes-and-parity) | `attributes` and `mv_*` |
| [Augmented reality](/augmented-reality) | The three AR modes, and the fixed default |
| [Model switching](/model-switching) | Runtime `src` swaps and GLTF variants |
| [Scene Director](/scene-director) | **Generative.** Describe a shot; Claude stages it, grounded in the model's measured geometry |
| [Generative 3D art](/generative-3d) | **Generative.** Describe a sculpture; get a real `.glb` built from primitives |
| [Image to 3D](/image-to-3d) | **Generative.** Upload a picture; Claude reads it and code carves a relief |
| [Benchmark](/benchmark) | One prompt, several models or settings, sculptures side by side |
| [API reference](/api-reference) | Every prop, every payload |
| [Migrating from 0.0.1](/migrating) | Prop-by-prop map |

---

## Credits

Built on Google's [`model-viewer`](https://modelviewer.dev/) (Apache-2.0),
vendored at 4.3.1. Demo models are Google's own `model-viewer` shared assets
and the Khronos Group's glTF Sample Assets. The CC BY 4.0 models require
attribution, so: Materials Variants Shoe © 2021 Shopify; Glam Velvet Sofa
© 2021 Wayfair, LLC (Eric Chadwick); Glass Hurricane Candle Holder © 2021
Wayfair, LLC (Eric Chadwick). Sheen Chair (© 2020 Wayfair, LLC) and
Scattering Skull (© 2025 Vladimir Petkovic) are CC0 1.0.

[Source on GitHub](https://github.com/pip-install-python/dash-model-viewer) ·
[PyPI](https://pypi.org/project/dash-model-viewer/)

## Other sizes of this document

- [/llms-small.txt](https://modelviewer.2plot.dev/llms-small.txt): compact briefing — start here if context is tight. (5.9 KB, ~1.5k tok)
- [/llms.txt](https://modelviewer.2plot.dev/llms.txt): this document — the index you are reading. (16.5 KB, ~4.2k tok)
- [/llms-full.txt](https://modelviewer.2plot.dev/llms-full.txt): every page's prose in one document — 22 pages. (228.7 KB, ~58.5k tok)

## Access policy

- Terms: these documents are free to fetch. A free account unlocks any gated document.
- Identity: agents may present a key by appending `?key=<value>` to any document URL. Get one: https://2plot.ai
- Rate: prefer ONE `/llms-full.txt` fetch over N per-page fetches. On 429, honour `Retry-After` and back off exponentially.
- Coordination: start at https://2plot.dev/llms.txt — one index enumerates every site; do not rediscover the network by crawling it.
- Crawler policy (mirrors /robots.txt): allowed: GPTBot, ClaudeBot, CCBot, Google-Extended, FacebookBot, Omgili, ByteSpider, Amazonbot, Applebot-Extended, meta-externalagent, AI2Bot, Diffbot, Timpibot, ImagesiftBot, ChatGPT-User, Claude-User, Claude-SearchBot, PerplexityBot, OAI-SearchBot, Perplexity-User, Googlebot, Bingbot, Slurp, DuckDuckBot, GoogleOther, Google-InspectionTool, Storebot-Google, AdsBot-Google.
- Accounting: every document read is logged with the requesting vendor (verified against published IP ranges where the operator publishes them). See https://2plot.dev/llms.txt

## Pages

Every page in this application. Each has a Markdown version at the `llms.txt` URL beside it.

- [dash-model-viewer — interactive 3D models and AR for Dash](https://modelviewer.2plot.dev/): dash-model-viewer — interactive 3D models and AR for Dash. Google's model-viewer vendored in the wheel: no CDN, works offline. By Pip Install Python.
  - Machine-readable: https://modelviewer.2plot.dev/llms.txt (16.5 KB, ~4.2k tok)
- [Animation](https://modelviewer.2plot.dev/animation): Play a model's built-in animation clips, switch between them with a crossfade, and pause — entirely through attributes, with the clip list reported by the model itself.
  - Machine-readable: https://modelviewer.2plot.dev/animation/llms.txt (8.2 KB, ~2.1k tok)
- [API](https://modelviewer.2plot.dev/api): Component props reference for dash_model_viewer.
  - Machine-readable: https://modelviewer.2plot.dev/api/llms.txt (4.7 KB, ~1.2k tok)
- [API Reference](https://modelviewer.2plot.dev/api-reference): Every prop on ModelViewer and Slot, every event payload, and the precedence rules.
  - Machine-readable: https://modelviewer.2plot.dev/api-reference/llms.txt (6.4 KB, ~1.6k tok)
- [Attribute Tour](https://modelviewer.2plot.dev/attribute-tour): The model-viewer attributes with no named prop — loading, reveal, scale, skybox, pan and tap locks, and the AR-only ones — each shown or honestly marked as unshowable.
  - Machine-readable: https://modelviewer.2plot.dev/attribute-tour/llms.txt (11.3 KB, ~2.9k tok)
- [Attributes and Parity](https://modelviewer.2plot.dev/attributes-and-parity): Reach every model-viewer attribute — including ones added upstream after this release — without waiting for a new version of this package.
  - Machine-readable: https://modelviewer.2plot.dev/attributes-and-parity/llms.txt (5.8 KB, ~1.5k tok)
- [Augmented Reality](https://modelviewer.2plot.dev/augmented-reality): Place a model in a real room — and the default that silently disabled WebXR on Android for the whole life of 0.0.1.
  - Machine-readable: https://modelviewer.2plot.dev/augmented-reality/llms.txt (6.3 KB, ~1.6k tok)
- [Benchmark](https://modelviewer.2plot.dev/benchmark): Run one prompt across several models, efforts or token budgets at once and compare the sculptures side by side.
  - Machine-readable: https://modelviewer.2plot.dev/benchmark/llms.txt (21.6 KB, ~5.5k tok)
- [Camera and Views](https://modelviewer.2plot.dev/camera-and-views): Camera presets, flight between them, and the 230-line clientside example that became 47 lines of Python.
  - Machine-readable: https://modelviewer.2plot.dev/camera-and-views/llms.txt (5.7 KB, ~1.5k tok)
- [Changelog](https://modelviewer.2plot.dev/changelog): Version history of dash-model-viewer, rendered from CHANGELOG.md.
  - Machine-readable: https://modelviewer.2plot.dev/changelog/llms.txt (16.0 KB, ~4.1k tok)
- [Events and Callbacks](https://modelviewer.2plot.dev/events-and-callbacks): The camera, load state, model dimensions, AR status and hotspot clicks arrive as ordinary Dash props — no clientside callbacks.
  - Machine-readable: https://modelviewer.2plot.dev/events-and-callbacks/llms.txt (8.1 KB, ~2.1k tok)
- [Generative 3D Art](https://modelviewer.2plot.dev/generative-3d): Describe a sculpture and get a real .glb — with Claude as a scene compiler, not a mesh generator, and every triangle built by deterministic Python.
  - Machine-readable: https://modelviewer.2plot.dev/generative-3d/llms.txt (25.7 KB, ~6.6k tok)
- [Image to 3D](https://modelviewer.2plot.dev/image-to-3d): Upload a picture and get a real .glb — Claude reads the image and chooses the carving parameters, and deterministic code cuts the relief.
  - Machine-readable: https://modelviewer.2plot.dev/image-to-3d/llms.txt (12.8 KB, ~3.3k tok)
- [Migrating from 0.0.1](https://modelviewer.2plot.dev/migrating): A prop-by-prop map from the 0.0.1 API to 1.0.0, and an honest account of why it is a clean break.
  - Machine-readable: https://modelviewer.2plot.dev/migrating/llms.txt (7.0 KB, ~1.8k tok)
- [Model Switching and Variants](https://modelviewer.2plot.dev/model-switching): Swap the model at runtime, and drive GLTF material variants from a dropdown the viewer populates itself.
  - Machine-readable: https://modelviewer.2plot.dev/model-switching/llms.txt (6.5 KB, ~1.7k tok)
- [Model Upload](https://modelviewer.2plot.dev/model-upload): Drop a .glb file onto the page and render it immediately, with a readout of what is actually inside the file.
  - Machine-readable: https://modelviewer.2plot.dev/model-upload/llms.txt (8.6 KB, ~2.2k tok)
- [Quick Start](https://modelviewer.2plot.dev/quick-start): Install the package, put a 3D model on the page, and understand what got injected.
  - Machine-readable: https://modelviewer.2plot.dev/quick-start/llms.txt (4.5 KB, ~1.1k tok)
- [Scene Director](https://modelviewer.2plot.dev/scene-director): Describe a shot in plain language and let Claude stage it — grounded in the model's measured geometry, then clamped before anything reaches the browser.
  - Machine-readable: https://modelviewer.2plot.dev/scene-director/llms.txt (12.8 KB, ~3.3k tok)
- [Scene Manifest](https://modelviewer.2plot.dev/scene-manifest): The versioned JSON a generated sculpture is made of — a complete, deterministic description you can export, edit by hand, and render again without paying a model.
  - Machine-readable: https://modelviewer.2plot.dev/scene-manifest/llms.txt (19.1 KB, ~4.9k tok)
- [Sculpt from an Image](https://modelviewer.2plot.dev/sculpt-from-image): Upload a photograph and a vision model composes a sculpture that evokes it — a generated scene in the spirit of the picture, not a reconstruction of it.
  - Machine-readable: https://modelviewer.2plot.dev/sculpt-from-image/llms.txt (24.9 KB, ~6.4k tok)
- [Slots and Hotspots](https://modelviewer.2plot.dev/slots-and-hotspots): Anchor any Dash component to a point on the model — and why hotspots used to be a list of dictionaries.
  - Machine-readable: https://modelviewer.2plot.dev/slots-and-hotspots/llms.txt (5.3 KB, ~1.4k tok)
- [Texture Upload](https://modelviewer.2plot.dev/texture-upload): Upload a PNG or JPEG and have it replace the model's base-colour texture in the 3D scene, not as a flat overlay.
  - Machine-readable: https://modelviewer.2plot.dev/texture-upload/llms.txt (7.5 KB, ~1.9k tok)

## About The 2plot network

Open-source Dash component libraries by Pip Install Python. Each component has its own documentation site and its own llms.txt; 2plot.dev indexes all of them, and 2plot.ai is the hub.

Network index: [https://2plot.dev](https://2plot.dev/llms.txt)

## Network

Other applications in this network. Same operator; each one serves its own `/llms.txt` in this format.

- [2plot.ai](https://2plot.ai): Network hub and account origin.
  - Machine-readable: https://2plot.ai/llms.txt
- [2plot.dev](https://2plot.dev): Package index for every open-source component in the network.
  - Machine-readable: https://2plot.dev/llms.txt
- [Documentation boilerplate](https://boilerplate.2plot.dev): The markdown-driven documentation template every satellite site is built from.
  - Machine-readable: https://boilerplate.2plot.dev/llms.txt
- [dash-leaflet2](https://leaflet.2plot.dev): Leaflet 2 maps as Dash components.
  - Machine-readable: https://leaflet.2plot.dev/llms.txt
- [dash-mui-scheduler](https://muischeduler.2plot.dev): MUI X Scheduler — calendars and event scheduling for Dash.
  - Machine-readable: https://muischeduler.2plot.dev/llms.txt
- [dash-mui-charts](https://muicharts.2plot.dev): MUI X charts, tree views and time pickers for Dash.
  - Machine-readable: https://muicharts.2plot.dev/llms.txt
- [flexlayout-dash](https://flexlayout.2plot.dev): IDE-style dockable, resizable and floatable window panels.
  - Machine-readable: https://flexlayout.2plot.dev/llms.txt
- [dash-improve-my-llms](https://llms.2plot.dev): The AI/LLM and SEO package every site in this network is built on.
  - Machine-readable: https://llms.2plot.dev/llms.txt
- [dash-flows](https://flows.2plot.dev): Node-graph editors built on React Flow.
  - Machine-readable: https://flows.2plot.dev/llms.txt
- [dash-pannellum](https://pannellum.2plot.dev): 360° panorama and virtual-tour viewer.
  - Machine-readable: https://pannellum.2plot.dev/llms.txt
- [dash-emoji-mart](https://emojimart.2plot.dev): Emoji picker component.
  - Machine-readable: https://emojimart.2plot.dev/llms.txt
- [dash-email](https://email.2plot.dev): Email composition and delivery components.
  - Machine-readable: https://email.2plot.dev/llms.txt
- [dash-excalidraw](https://excalidraw.2plot.dev): Excalidraw virtual whiteboard and sketching canvas.
  - Machine-readable: https://excalidraw.2plot.dev/llms.txt

## Related projects

Projects by the same author on their own domains. Built on the same stack, but not part of the primary network.

- [Pirate's Bargain](https://piratesbargain.com): Deal aggregator built on the same Dash stack.
  - Machine-readable: https://piratesbargain.com/llms.txt
- [ai-agent.buzz](https://ai-agent.buzz): Agent tooling directory.
  - Machine-readable: https://ai-agent.buzz/llms.txt
- [2plot.media](https://2plot.media): Media and streaming, on the same Dash stack.
  - Machine-readable: https://2plot.media/llms.txt

## External references

Third-party documentation this project depends on or references. Not affiliated — listed so an agent can follow a dependency directly instead of searching for it.

- [Dash Mantine Components](https://www.dash-mantine-components.com): The UI component layer these docs are built with.
  - Machine-readable: https://www.dash-mantine-components.com/llms.txt
- [Plotly Dash documentation](https://dash.plotly.com): Upstream framework documentation.
  - Machine-readable: https://dash.plotly.com/llms.txt
