Lab Flask
← root/

SPATIAL_EMBEDDING

Put OpenStrate-powered 3D on your own site. After reconstruction, you get a stable viewer URL — drop it into an iframe on your marketing site, docs, or customer portal. No proprietary plugin: standard HTML, optional streaming for heavy models.

Powered by OpenStrate viewer infrastructure · SiL / Spacial Intelligence Labs

00_MODES

Two integration paths. Local is zero-ops: the user’s browser loads and renders the asset. Stream runs the viewer on your server and delivers H.264 over WebRTC — ideal for large meshes, thin clients, and mobile.

Mode Mechanism Server Best for
Local Browser downloads & renders the model No Small models, lowest latency
Stream Headless render + WebRTC video + input channel Yes (embedded-viewer service) Large models, mobile, no big downloads

01_LIVE_LAYOUT

On your page, the viewer occupies an iframe inside your layout (hero, product detail, case study, etc.). Below is the structure users see — the inner region is where your src= points at OpenStrate or your stream host.

https://your-company.com/products/showroom
// IFRAME VIEWPORT src="https://openstrate.com/view/<your_file_id>.glb" Or /stream/… when using the streaming server

02_STREAM_ARCHITECTURE

Stream mode uses a small Node service (Puppeteer + Chrome) that opens the same OpenStrate viewer, captures the WebGL canvas, and negotiates WebRTC with the embedded client. Input is forwarded over a data channel.

03_LOCAL_EMBED

Replace YOUR_FILE_ID.glb with the id and extension you receive after upload (same URL you’d open in a new tab).

<iframe
  src="https://openstrate.com/view/YOUR_FILE_ID.glb"
  width="800"
  height="500"
  frameborder="0"
  allow="autoplay; fullscreen"
  allowfullscreen
  style="border: none; border-radius: 8px;"
></iframe>

Supported formats

Extension Format
.glb glTF binary (meshes + point clouds)
.ply Stanford PLY (point clouds)
.stl STL (meshes)
.bin OpenStrate binary point cloud
.omxl OpenStrate indexed mesh / point cloud

Responsive 16:9 container

<div style="position: relative; width: 100%; padding-bottom: 56.25%; overflow: hidden; border-radius: 8px;">
  <iframe
    src="https://openstrate.com/view/YOUR_FILE_ID.glb"
    style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;"
    allow="autoplay; fullscreen"
    allowfullscreen
  ></iframe>
</div>

04_STREAM_EMBED

Run the embedded-viewer service where browsers can reach it (HTTPS in production). Point VIEW_ORIGIN at the host that serves /view/ (typically https://openstrate.com).

cd embedded-viewer
npm install
STREAM_PORT=8090 VIEW_ORIGIN=https://openstrate.com node server.js

Production-style flags

STREAM_PORT=8090 \
VIEW_ORIGIN=https://openstrate.com \
STREAM_MAX_SESSIONS=8 \
STREAM_POOL_SIZE=3 \
STREAM_USE_GPU=1 \
  node server.js

Iframe — swap in your stream host:

<iframe
  src="https://your-stream-server.com/stream/YOUR_FILE_ID.glb"
  width="800"
  height="500"
  frameborder="0"
  allow="autoplay; fullscreen"
  allowfullscreen
  style="border: none; border-radius: 8px;"
></iframe>

Visibility pause — load the helper once; mark embeds with data-openstrate so streams pause off-screen:

<script src="https://your-stream-server.com/embed-helper.js"></script>

<iframe
  src="https://your-stream-server.com/stream/YOUR_FILE_ID.glb"
  data-openstrate
  width="800"
  height="500"
  frameborder="0"
  allow="autoplay; fullscreen"
  allowfullscreen
></iframe>

Manual postMessage (same contract as the helper):

<script>
  const iframe = document.querySelector('#my-viewer');
  const observer = new IntersectionObserver((entries) => {
    for (const entry of entries) {
      iframe.contentWindow.postMessage({
        type: 'openstrate-visibility',
        visible: entry.isIntersecting
      }, '*');
    }
  }, { threshold: 0.1 });
  observer.observe(iframe);
</script>

05_FULL_PAGE_EXAMPLE

Minimal company page with both a local viewer and a streamed viewer slot.

Expand full HTML example
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D Models — My Company</title>
  <style>
    body {
      font-family: system-ui, sans-serif;
      max-width: 900px;
      margin: 40px auto;
      padding: 0 20px;
      background: #111;
      color: #ddd;
    }
    h2 { margin: 32px 0 12px; }
    .viewer-container {
      position: relative;
      width: 100%;
      padding-bottom: 56.25%;
      overflow: hidden;
      border-radius: 8px;
      background: #0a0a0a;
      margin-bottom: 24px;
    }
    .viewer-container iframe {
      position: absolute;
      top: 0; left: 0;
      width: 100%; height: 100%;
      border: none;
    }
  </style>
</head>
<body>
  <h1>Our 3D Scans</h1>

  <h2>Office Lobby (local rendering)</h2>
  <div class="viewer-container">
    <iframe
      src="https://openstrate.com/view/abc123.glb"
      allow="autoplay; fullscreen"
      allowfullscreen
    ></iframe>
  </div>

  <h2>Warehouse Scan (streamed)</h2>
  <div class="viewer-container">
    <iframe
      src="https://stream.example.com/stream/def456.glb"
      data-openstrate
      allow="autoplay; fullscreen"
      allowfullscreen
    ></iframe>
  </div>

  <script src="https://stream.example.com/embed-helper.js"></script>
</body>
</html>

06_CONFIGURATION

Streaming server environment variables:

Variable Default Description
STREAM_PORT 8090 HTTP + WebSocket port
VIEW_ORIGIN https://openstrate.com Origin hosting /view/ pages
STREAM_WIDTH 1920 Render width (px)
STREAM_HEIGHT 1080 Render height (px)
STREAM_USE_GPU 1 1 = GPU (ANGLE/Vulkan), 0 = CPU (SwiftShader)
STREAM_MAX_SESSIONS 4 Max concurrent streams
STREAM_POOL_SIZE 2 Pre-warmed Chrome instances
STREAM_IDLE_TIMEOUT 30000 Ms after last disconnect before cleanup

Health checkGET https://your-stream-server.com/health

{
  "ok": true,
  "sessions": 2,
  "maxSessions": 4,
  "poolSize": 1,
  "poolTarget": 2,
  "activeSessions": [
    { "file": "abc123.glb", "clients": 1, "alive": true }
  ]
}

07_VIEWER_CONTROLS

Input Action
Left-click drag Orbit
Right-click drag Pan
Scroll wheel Zoom
Pinch (touch) Zoom
One-finger drag (touch) Orbit

08_TROUBLESHOOTING

Iframe blank / white — Open the viewer URL directly; check HTTPS and console for mixed content or CORS.

Stream stuck on “Connecting…” — Confirm the server is up, /health returns ok, and WebRTC UDP isn’t blocked (corporate firewalls; STUN stun.l.google.com:19302 reachable).

Low FPS — Prefer GPU (STREAM_USE_GPU=1), lower STREAM_WIDTH/HEIGHT, reduce concurrent sessions.

Grey model / no color — Vertex colors may be absent; depends on reconstruction and export settings.

09_NEXT_STEP

Need API access, private stream hosting, or SLA-backed embedding?

CONTACT SiL

Sensing as a Service → /cloud/