Loading scene...
Frontend Integration

Selectors: prefer publicId, then id, then exact name. Duplicate names return a structured error.

Coordinates: API defaults to { coordSystem: "panda", space: "local" }. Use coordSystem: "three" to work in Three.js axes. Local means transform relative to parent.

// Same-page JS API
const viewer = window.EGWebGLViewer;
await viewer.ready;

const nodes = viewer.nodes.list();
const hero = nodes.find((node) => node.kind === "model");

viewer.animation.play({ publicId: hero.publicId }, {
  clip: "Walk",
  loop: true,
  restart: true,
});

viewer.nodes.translate({ publicId: hero.publicId }, { x: 1, y: 0, z: 0 });
viewer.nodes.setTransform(
  { publicId: hero.publicId },
  { rotation: { h: 45, p: 0, r: 0 } },
  { coordSystem: "panda", space: "local" },
);

viewer.events.on("animationFinished", (payload) => {
  console.log("animation finished", payload);
});
// iframe + postMessage
const iframe = document.querySelector("iframe");

iframe.contentWindow.postMessage({
  source: "eg-frontend",
  type: "handshake",
  id: "hello-1",
}, iframe.src ? new URL(iframe.src).origin : "*");

window.addEventListener("message", (event) => {
  if (!event.data || event.data.source !== "eg-webgl") return;
  console.log("viewer message", event.data);
});

iframe.contentWindow.postMessage({
  source: "eg-frontend",
  type: "command",
  id: "cmd-1",
  command: "animation.play",
  payload: {
    selector: { publicId: "model:asset-guid:root" },
    options: { clip: "Idle", loop: true },
  },
}, iframe.src ? new URL(iframe.src).origin : "*");

Message protocol: commands use { source: "eg-frontend", id, type: "command", command, payload }. Responses/events use { source: "eg-webgl", type, replyTo?, event?, ok?, result?, error? }.

Events: ready, error, animationFinished, stateChanged.

Demo page: after export, open frontend_demo.html to see a working iframe host example.