3D assets
Storage can hold 3D product models alongside your images, and the <rx-model-viewer> web component renders them in the browser. Drop one tag into any page and customers can orbit, zoom, and (on supported devices) place the model in their room with augmented reality. It is built on three.js and Google's <model-viewer>, both self-hosted in the package, so it makes no third-party requests at runtime.
The component is a standard custom element, so it works in plain HTML and in Vue, React, Nuxt, or Svelte without a framework wrapper.
Install
npm install @revenexx/storage-model-viewer
Importing the package registers the <rx-model-viewer> element automatically:
import '@revenexx/storage-model-viewer'
You can also load it from a CDN with a module script tag, no build step required:
<script type="module" src="https://unpkg.com/@revenexx/storage-model-viewer"></script>
Basic usage
Point src at the model and poster at a preview image. Both can come straight from Storage: a 3D asset exposes its mesh, preview, and AR derivatives through query parameters on the delivery URL.
<div style="height: 70vh">
<rx-model-viewer
src="https://storage.revenexx.com/<TENANT_SLUG>/models/flange.glb?d=model"
poster="https://storage.revenexx.com/<TENANT_SLUG>/models/flange.glb?d=preview"
auto-rotate
></rx-model-viewer>
</div>
Give the element a height
<rx-model-viewer>fills its container (width: 100%; height: 100%). The parent must have a definite height, likeheight: 70vhor a fixed pixel value. Inside a bare flex item with no height, the canvas collapses to nothing and you see only the background.
Attributes
| Attribute | Default | Description |
|---|---|---|
src | — | URL of the .glb mesh to render. Required. |
poster | — | Image shown before and while the model loads. |
engine | three | Rendering engine: three (the default three.js renderer) or model-viewer (Google's element, required for AR). |
auto-rotate | off | Slowly rotate the model. |
background | transparent | CSS color for the canvas. |
camera-orbit | — | Initial camera orbit, for example "45deg 65deg auto". |
ar | off | Show the AR button. Only honored by the model-viewer engine. |
ios-src | — | USDZ URL for iOS AR. |
Attributes are reactive: change one at runtime and the viewer re-renders. Drag-to-rotate, scroll-to-zoom, and image-based lighting are built into both engines.
Supported formats
.glbis the model format the viewer renders, supplied throughsrc.- USDZ is used only for iOS augmented reality, supplied through
ios-src.
A Storage 3D asset gives you both from one source file: ?d=model returns the .glb, ?d=preview returns a preview image (which accepts the same image transform parameters), and ?d=usdz returns the USDZ for iOS.
Augmented reality
AR is opt-in and runs through the model-viewer engine. Set engine="model-viewer", add the ar attribute, and provide ios-src for iOS:
<div style="height: 70vh">
<rx-model-viewer
engine="model-viewer"
ar
src="https://storage.revenexx.com/<TENANT_SLUG>/models/chair.glb?d=model"
ios-src="https://storage.revenexx.com/<TENANT_SLUG>/models/chair.glb?d=usdz"
poster="https://storage.revenexx.com/<TENANT_SLUG>/models/chair.glb?d=preview"
auto-rotate
></rx-model-viewer>
</div>
Platform behavior:
- Android places the
.glbfromsrc. Export models at real-world (metre) scale so they appear at the right size. - iOS uses Quick Look, which requires the USDZ from
ios-src. Withoutios-src, there is no AR button on iOS.
Framework notes
Vue and Nuxt
Tell the compiler rx-model-viewer is a custom element so it doesn't try to resolve it as a Vue component. In Nuxt:
export default defineNuxtConfig({
vue: {
compilerOptions: {
isCustomElement: (tag) => tag === 'rx-model-viewer' || tag === 'model-viewer',
},
},
})
Render the element inside <ClientOnly>, and import the package from a client plugin. If you use the AR engine in Nuxt, also add a top-level import '@google/model-viewer' in that client plugin and add @google/model-viewer to build.transpile, because Vite's scanner does not follow the engine's lazy import on its own.
React
Import the package once, then use the tag directly:
import '@revenexx/storage-model-viewer'
export function Model() {
return (
<div style={{ height: '70vh' }}>
{/* @ts-expect-error custom element */}
<rx-model-viewer
src="https://storage.revenexx.com/<TENANT_SLUG>/models/flange.glb?d=model"
poster="https://storage.revenexx.com/<TENANT_SLUG>/models/flange.glb?d=preview"
auto-rotate
/>
</div>
)
}
Accessibility note
<rx-model-viewer> does not expose an alt attribute of its own. Provide a text alternative or description near the viewer for users who can't see the 3D content.
What's next
- Serve & transform images — the preview image accepts the same transform parameters.
- Upload & manage files — get your source model into Storage.