Integrations

Embed API

Put 3D on any website. Drive it from your code.

Every project you publish in MeshMAX can live inside your own site with one tag — as a product viewer, a background, or a scroll story. A small JavaScript API lets your page move the camera, play states, switch configurator options and react to what the visitor does.


No code: Dashboard

You don’t need to write code to embed. In the Dashboard → Embeds you build it by hand and copy the result:

  1. Pick a published project — or several, for a scroll story.
  2. Set it up — size, position, background or foreground, and how it behaves while the page scrolls.
  3. Preview it live on a sample page, exactly as your visitors will see it.
  4. Copy one snippet and paste it into Shopify, Wix, Webflow, WordPress or any page.

Open the Dashboard ↗

Everything below is for developers who want to go further: the same embed, driven from your own code.


Quick start

  1. Publish your project in the MeshMAX Studio.
  2. Copy its project ID — the part after /c/ in the published link. In meshmax.app/c/qlu7s1wt1n the ID is qlu7s1wt1n.
  3. Paste two lines into your page, and give the scene a size with normal CSS.
HTML
<meshmax-scene project="YOUR_PROJECT_ID" style="display:block; height:520px"></meshmax-scene>

<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>

That's the whole setup: no build step, no other library. Load the script once per page, however many scenes you put on it.

Playground

A real scene on this page. Each button calls the API, and the panel shows the exact line it ran. Paste the ID of one of your own published projects to try it with yours.

ViewsLoading…
StatesLoading…
Camera
Your code ran
// Press a button above
Events received

Layouts

The same scene can sit in your page four ways. Pick one with the layout attribute.

inline · default

A box in your layout, like an image or a video. You set its size.

background

Fixed and full-screen behind your content. Clicks go through to your page.

foreground

Fixed and full-screen over your content, always see-through. Clicks still go through.

pinned

A scroll story: the 3D holds on screen while the visitor scrolls through a tall section, and its scroll timeline plays from start to end.

Attributes

AttributeWhat it does
projectRequired. The published project ID. Change it and the scene swaps to the new project.
layoutinline (default), background, foreground or pinned — see Layouts.
transparentNo background colour, so your page shows through behind the 3D. A foreground is always transparent.
interactiveFor a background: lets visitors turn the camera. Without it the layer stays calm and never catches a click. Don't put it on a foreground — see the warning under Recipes.
scrollWhat drives a scroll timeline in an inline scene. element (default) plays it as the scene passes through the screen; page plays it across the whole page; manual leaves it to your page, through setScrollProgress() (see Methods).
uinone hides the scene’s own buttons (View in AR, home, share, settings) — for a scene used as a backdrop that takes no clicks.
zoomoff stops the mouse wheel and a pinch from zooming the scene, so over it the wheel scrolls your page. on lets an interactive background or foreground zoom with the wheel even on a page that scrolls. Without it the project's own setting applies, and a turnable layer leaves the wheel to a page that scrolls.
fitadaptive widens the view on narrow and portrait screens, so the object isn't cropped on a phone.

Only project can change while the scene is on the page. The others are read when the scene loads.

Methods

Each scene carries its own API on the element: element.api. Several scenes on one page never get in each other's way.

JavaScript
const scene = document.querySelector('meshmax-scene');

scene.addEventListener('meshmax:ready', () => {
  scene.api.goToView('Front');   // the scene has loaded — safe to drive it
});
Wait for meshmax:ready. element.api is empty (null) until the scene has loaded, so code that runs straight away should wait for the event.

Camera

MethodWhat it does
goToView(name, seconds)Flies the camera to a view you saved in the Studio, by its name (or id). seconds is optional (0.7). Returns true if the view exists.
nextView() · prevView()Steps through the saved views in their order, wrapping around.
getViews()The saved views: [{ id, name }].
setAutoRotate(on)Turns the slow automatic turn on (true) or off (false).

Objects and states

MethodWhat it does
goToState(name, seconds)Plays a state you captured in the Studio's Animate panel — every object that has a state with that name moves to it. seconds is optional (0.4).
getModels()The objects and their states: [{ id, name, states: [{ id, name }] }].

Configurator

In projects with a configurator.

MethodWhat it does
selectVariant(variantId)Picks an option, exactly as if the visitor clicked it: materials, animation, camera, price and summary all follow.
showHotspots(on)Shows or hides the hotspots.
showDimensions(on)Shows or hides the dimension lines.

Scroll and chapters

MethodWhat it does
setProgress(percent)Scroll-timeline projects: jumps the timeline to a point, 0 to 100. The next scroll takes over again.
sequencer.go(index)Sequencer projects: goes to a chapter, counting from 0.
sequencer.next() · sequencer.prev()The next or previous chapter.
sequencer.chapters()The chapters: [{ id, name }]. sequencer.count is how many there are.
sequencer.autoPause() · sequencer.autoResume()Pauses or resumes chapters that play on their own.
element.setScrollProgress(p)On the element itself, not element.api. With scroll="manual", tells the scene how far through its story your page is, from 0 to 1 — for a page with its own scroll layout. Safe to call before the scene has loaded.

A method that doesn't apply to a project isn't there: scene.api.selectVariant is undefined in a project without a configurator. Check before you call it.

Events

The scene tells your page what happens inside it with normal DOM events. They bubble, so you can listen on the element or on document. The details are in event.detail.

EventWhen · detail
meshmax:readyThe scene has loaded and is showing. { models } — how many objects it has.
meshmax:variantchangeA configurator option was picked, by the visitor or by selectVariant. { variantId, groupId }
meshmax:hotspotThe visitor opened a hotspot. { id, kind } — kind is what it does: tooltip, card, flyTo, link…
meshmax:scrollprogressThe scroll timeline moved. { progress } from 0 to 1.
meshmax:handcontrolHand control (camera by hand gestures) was turned on or off. { on }
meshmax:errorThe scene could not be loaded (a wrong ID, or not published). { project, message } — put something else in its place if you like.
JavaScript
document.addEventListener('meshmax:hotspot', (e) => {
  console.log('Hotspot opened:', e.detail.id, 'in', e.target.getAttribute('project'));
});

Recipes

Every recipe here started as a test page, and each one was tried on a real published project first.

Your page and the scene

Buttons on your page that move the camera

HTML
<meshmax-scene id="product" project="YOUR_PROJECT_ID" style="display:block; height:520px"></meshmax-scene>

<button data-view="Front">Front</button>
<button data-view="Side">Side</button>
<button data-view="Detail">Detail</button>

<script>
  const product = document.getElementById('product');
  document.querySelectorAll('[data-view]').forEach((btn) => {
    btn.addEventListener('click', () => {
      if (product.api) product.api.goToView(btn.dataset.view);   // the view names you saved in the Studio
    });
  });
</script>
<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>

Send the visitor's choice to your shop

Option ids are MeshMAX's own. Map them to your product codes once, then react to every pick.

JavaScript
const SKU = {
  'var-red':   'CHAIR-RED',    // your option ids → your product codes
  'var-green': 'CHAIR-GREEN',
};

document.querySelector('meshmax-scene').addEventListener('meshmax:variantchange', (e) => {
  const sku = SKU[e.detail.variantId];
  if (sku) document.querySelector('#add-to-cart').dataset.sku = sku;
});

To find the ids, log them once: addEventListener('meshmax:variantchange', (e) => console.log(e.detail)), then click through the options.

Layers

A 3D background behind your hero

Your content must sit above the scene: give it position: relative and a z-index of 1 or more. Clicks go through the scene to your page.

HTML
<meshmax-scene project="YOUR_PROJECT_ID" layout="background"></meshmax-scene>

<section style="position:relative; z-index:1; min-height:100vh">
  <h1>Your headline, over the 3D</h1>
</section>

<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>

A background visitors can turn, with your buttons on top

With interactive, the background answers the mouse and touch. Whatever lies over it has to let the pointer through (pointer-events: none) — and switch it back on (auto) only for what should take clicks.

HTML
<meshmax-scene project="YOUR_PROJECT_ID" layout="background" interactive></meshmax-scene>

<style>
  .overlay        { position: fixed; inset: 0; z-index: 2; pointer-events: none; }  /* drags pass through to the 3D */
  .overlay button { pointer-events: auto; }                                           /* but the button still clicks */
</style>

<div class="overlay">
  <h1>Turn the product behind this text</h1>
  <button>Add to cart</button>
</div>

<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>

3D behind and in front of your content

Two projects and your page in between: an environment behind, a product floating over the text. The background can be interactive; the gaps between your cards let drags reach it.

HTML
<meshmax-scene project="ENVIRONMENT_ID" layout="background" interactive></meshmax-scene>
<meshmax-scene project="PRODUCT_ID" layout="foreground"></meshmax-scene>

<style>
  .content       { position: relative; z-index: 1; pointer-events: none; }  /* the gaps pass drags to the background */
  .content .card { pointer-events: auto; }                                  /* the cards stay readable and selectable */
</style>

<div class="content">
  <section class="card">Your content, between the two 3D layers</section>
</div>

<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>
Never make a foreground interactive. A foreground is a full-screen layer on top of your whole page. With interactive it takes every click, tap and scroll, and the page underneath stops working. Make the background interactive instead.

Scroll

These need a project with a scroll timeline (Studio → Animate → Scroll). Your page scrolls normally the whole time — nothing is taken over, nothing snaps.

The whole page drives the 3D

As a background, the timeline follows the whole page: the top of the page is the start, the bottom is the end.

HTML
<meshmax-scene project="YOUR_PROJECT_ID" layout="background"></meshmax-scene>

<main style="position:relative; z-index:1">
  <section style="min-height:100vh">The start</section>
  <section style="min-height:100vh">The middle</section>
  <section style="min-height:100vh">The end</section>
</main>

<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>

A scene per section

An inline scene plays its timeline as it crosses the screen: it starts as it comes in at the bottom and ends as it leaves at the top. Several on one page each play on their own, as their section arrives — they can be different projects.

HTML
<p>Your content…</p>
<meshmax-scene project="FIRST_ID" style="display:block; height:100vh"></meshmax-scene>

<p>More content…</p>
<meshmax-scene project="SECOND_ID" style="display:block; height:100vh"></meshmax-scene>

<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>

Add scroll="page" to an inline scene to have it follow the whole page instead.

A scroll story that holds in place

A pinned scene is a tall runway. The 3D locks on screen when it reaches the top, plays its timeline while the visitor scrolls, and lets go at the end. The height is the length of the story: 300vh is about three screens.

HTML
<style>
  .story { position: relative; }
  .story meshmax-scene { display: block; height: 300vh; }
  .steps { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
  .step  { height: 100vh; display: flex; align-items: center; justify-content: center; }
  .step div { pointer-events: auto; max-width: 480px; }
</style>

<div class="story">
  <meshmax-scene project="YOUR_PROJECT_ID" layout="pinned" transparent></meshmax-scene>
  <div class="steps">
    <div class="step"><div>The story starts.</div></div>
    <div class="step"><div>It holds and animates.</div></div>
    <div class="step"><div>And it finishes.</div></div>
  </div>
</div>

<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>

Want your page to follow the story too? Listen for meshmax:scrollprogress and fade your own elements in and out with e.detail.progress.

3D in the midground

The same pinned story with three layers: a colour or image per section at the back, the 3D held in the middle, your text in front. The backdrop changes behind the object as the visitor scrolls.

HTML
<style>
  .story { position: relative; }
  .bands { position: absolute; inset: 0; z-index: 0; }                          /* back */
  .bands div { height: 100vh; }
  .story meshmax-scene { display: block; height: 300vh; position: relative; z-index: 1; }   /* middle */
  .steps { position: absolute; inset: 0; z-index: 2; pointer-events: none; }    /* front */
  .step  { height: 100vh; display: flex; align-items: center; justify-content: center; }
  .step div { pointer-events: auto; max-width: 480px; }
</style>

<div class="story">
  <div class="bands">
    <div style="background:#f3f3f5"></div>
    <div style="background:#8a8a93"></div>
    <div style="background:url(your-image.jpg) center / cover"></div>
  </div>
  <meshmax-scene project="YOUR_PROJECT_ID" layout="pinned" transparent></meshmax-scene>
  <div class="steps">
    <div class="step"><div>On white.</div></div>
    <div class="step"><div>On grey.</div></div>
    <div class="step"><div>On your image.</div></div>
  </div>
</div>

<script type="module" src="https://studio.meshmax.app/js/v1/meshmax.js"></script>

transparent is what lets the backdrop show through the scene.

Good to know

Building something bigger, or need an API we don't have yet? [email protected]