PageSourceSearch

https://immersiveweb.dev/model

html immersiveweb.dev collected 2026-10-02 02:52:06 UTC 25,950 bytes, 385 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8">
5  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6  <title>The Model Element - Immersive Web</title>
7  <meta name="description" content="The HTML model element, a proposed standard for embedding 3D content directly in web pages.">
8
9  <!-- Open Graph -->
10  <meta property="og:title" content="The Model Element - Immersive Web">
11  <meta property="og:description" content="The HTML model element, a proposed standard for embedding 3D content directly in web pages.">
12  <meta property="og:type" content="website">
13  <meta property="og:url" content="http://immersiveweb.dev/model.html">
14
15  <link rel="stylesheet" href="/main.css">
16  <link rel="icon" href="/favicon.ico">
17
18  <!-- Model element WebGL fallback for browsers without native support -->
19  
19<script type="module">
20    if (!window.HTMLModelElement) {
21      window.modelFallbackReady = import('/scripts/model-element-polyfill.min.js');
22    }
23  </script>
23
24
25</head>
26<body>
27
28  <nav class="site-nav" aria-label="Site navigation">
29    <div class="site-nav-inner container">
30      <a href="/"
31         class="nav-link"
32         style="view-transition-name: nav-link-webxr"
33         >
34        
35        WebXR
36      </a>
37      <a href="/model"
38         class="nav-link nav-link--active"
39         style="view-transition-name: nav-link-model"
40         aria-current="page">
41        <span class="nav-pill"></span>
42        Model
43      </a>
44    </div>
45  </nav>
46
47  <main class="container">
48    <section class="hero">
49  <h1>The <code>&lt;model&gt;</code> Element</h1>
50  <p>A proposed HTML element for embedding 3D content directly in web pages, rendered by the browser, not by script.</p>
51</section>
52
53<div class="accent-bar" aria-hidden="true"></div>
54<section class="card" id="about">
55
56  <h2 id="what-is-the-model-element">What is the <code class="language-plaintext highlighter-rouge">&lt;model&gt;</code> Element?</h2>
57
58  <p>HTML allows the display of many media types through elements like <code class="language-plaintext highlighter-rouge">&lt;img&gt;</code>, <code class="language-plaintext highlighter-rouge">&lt;picture&gt;</code>, and <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code>,
59but it does not provide a declarative way to embed 3D content directly.
60Displaying a 3D object today requires scripting a <code class="language-plaintext highlighter-rouge">&lt;canvas&gt;</code> element through WebGL,
61a process that depends on third-party libraries
62and cannot work in all contexts
63(for example, in augmented reality where the browser needs to render from the user’s physical viewpoint without exposing sensitive spatial data to the page).</p>
64
65  <p>The <code class="language-plaintext highlighter-rouge">&lt;model&gt;</code> element is a proposed solution:
66a new <a href="https://drafts.csswg.org/css-display/#replaced-element">replaced element</a> that embeds 3D content the same way <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code> embeds video.</p>
67
68  <p>The content of the 3D model file appears as a 3D figure,
69inside a portal in the page.</p>
70
71  <p>The browser itself is responsible for rendering the model,
72which means it can take advantage of platform capabilities
73like stereoscopic display, environment lighting, and casting shadows from real-world objects
74that page-level code cannot safely access.</p>
75
76  <p>It is being developed by the <a href="https://www.w3.org/groups/cg/immersive-web/">W3C Immersive Web Community Group</a>.
77Native support currently ships in <strong>Safari on visionOS</strong>.</p>
78
79  <h3 id="how-does-this-relate-to-the-rest-of-the-immersive-web">How does this relate to the rest of the immersive web?</h3>
80
81  <p>The <code class="language-plaintext highlighter-rouge">&lt;model&gt;</code> element handles <em>inline</em> 3D:
82content anchored to a page layout that does not take over the screen or the camera feed.
83<a href="/">WebXR</a> covers the other end of the spectrum:
84fully immersive sessions on headsets and AR overlays.
85Think of them the way you think of <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code> versus a full-screen streaming app:
86one is a page element, the other is an experience.
87Both are designed to work together.</p>
88
89</section>
90
91<div class="accent-bar" aria-hidden="true"></div>
92<section class="card" id="support">
93  <h2>Does your browser support <code>&lt;model&gt;</code>?</h2>
94
95  <div id="model-support-results">
96    <p class="support-loading">Checking support&hellip;</p>
97  </div>
98
99  
99<script type="module">
100    const container = document.getElementById('model-support-results');
101    const native = 'HTMLModelElement' in window;
102
103    const statusText = native
104      ? '✔ Your browser natively supports the <code>&lt;model&gt;</code> element'
105      : '⚠ No native support — this page is using a WebGL-based fallback';
106    const statusClass = native ? 'status-supported' : 'status-partial';
107
108    const features = [
109      { name: 'Native <code>&lt;model&gt;</code> element', check: native }
110    ];
111
112    const swatchColors = ['var(--cyan)', 'var(--magenta)', 'var(--yellow)'];
113
114    function icon(ok) {
115      return ok
116        ? '<span class="support-icon support-icon--yes" aria-label="Supported">✔</span>'
117        : '<span class="support-icon support-icon--no" aria-label="Not supported">✗</span>';
118    }
119
120    const rows = features.map((f, i) => {
121      const color = swatchColors[i % swatchColors.length];
122      return `<tr>
123        <td>${f.name}</td>
124        <td data-supported="${f.check}"><span class="support-swatch" style="background:${color}"></span>${icon(f.check)} ${f.check ? 'Supported' : 'Not supported'}</td>
125      </tr>`;
126    }).join('');
127
128    container.innerHTML = `
129      <p class="support-status ${statusClass}">${statusText}</p>
130      <table class="support-table">
131        <thead><tr><th scope="col">Feature</th><th scope="col">Status</th></tr></thead>
132        <tbody>${rows}</tbody>
133      </table>`;
134  </script>
134
135</section>
136
137<div class="accent-bar" aria-hidden="true"></div>
138
139<section class="card" id="example">
140
141  <h2 id="live-example">Live Example</h2>
142
143  <p>Drag to rotate the helmet below.
144The <code class="language-plaintext highlighter-rouge">stagemode="orbit"</code> attribute tells the browser to present the model on a turntable that the user can spin and zoom freely.</p>
145
146  <figure>
147  <model stagemode="orbit" alt="Damaged flight helmet 3D model" style="max-width: 300px; width: 100%; height: auto; aspect-ratio: 1;">
148    <source src="/models/DamagedHelmet.usdz" type="model/vnd.usdz+zip" />
149    <source src="/models/DamagedHelmet.glb" type="model/gltf-binary" />
150    <img src="/models/DamagedHelmet.jpg" alt="Damaged flight helmet 3D model" />
151  </model>
152  <figcaption>
153    Flight helmet with damage — <a href="https://sketchfab.com/3d-models/battle-damaged-sci-fi-helmet-pbr-b81008d513954189a063ff901f7abfe4">model by theblueturtle_</a> (CC BY-NC 4.0), <a href="https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/DamagedHelmet">glTF rebuild by ctxwing</a> (CC BY 4.0). Converted to USDZ for this example.
154  </figcaption>
155</figure>
156
157  <p>The markup for this example:</p>
158
159  <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;model</span> <span class="na">style=</span><span class="s">"width: 300px; height: 300px"</span> <span class="na">stagemode=</span><span class="s">"orbit"</span> <span class="na">alt=</span><span class="s">"Damaged flight helmet 3D model"</span><span class="nt">&gt;</span>
160  <span class="nt">&lt;source</span> <span class="na">src=</span><span class="s">"DamagedHelmet.usdz"</span> <span class="na">type=</span><span class="s">"model/vnd.usdz+zip"</span><span class="nt">&gt;</span>
161  <span class="nt">&lt;source</span> <span class="na">src=</span><span class="s">"DamagedHelmet.glb"</span> <span class="na">type=</span><span class="s">"model/gltf-binary"</span><span class="nt">&gt;</span>
162  <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"DamagedHelmet.jpg"</span> <span class="na">alt=</span><span class="s">"Damaged flight helmet 3D model"</span><span class="nt">&gt;</span>
163<span class="nt">&lt;/model&gt;</span>
164</code></pre></div>  </div>
165
166</section>
167
168<div class="accent-bar" aria-hidden="true"></div>
169
170<section class="card" id="quickstart">
171
172  <h2 id="quick-start">Quick Start</h2>
173
174  <p>Like <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code>, the <code class="language-plaintext highlighter-rouge">&lt;model&gt;</code> element uses <code class="language-plaintext highlighter-rouge">&lt;source&gt;</code> children to offer the same asset in multiple formats.
175The browser selects the first format it supports:</p>
176
177  <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;model</span> <span class="na">style=</span><span class="s">"width: 400px; height: 300px"</span><span class="nt">&gt;</span>
178  <span class="nt">&lt;source</span> <span class="na">src=</span><span class="s">"chair.usdz"</span> <span class="na">type=</span><span class="s">"model/vnd.usdz+zip"</span><span class="nt">&gt;</span>
179  <span class="nt">&lt;source</span> <span class="na">src=</span><span class="s">"chair.glb"</span> <span class="na">type=</span><span class="s">"model/gltf-binary"</span><span class="nt">&gt;</span>
180<span class="nt">&lt;/model&gt;</span>
181</code></pre></div>  </div>
182
183  <p>Setting <code class="language-plaintext highlighter-rouge">stagemode="orbit"</code> allows the user to rotate the model directly within the element:</p>
184
185  <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;model</span> <span class="na">style=</span><span class="s">"width: 400px; height: 300px"</span> <span class="na">stagemode=</span><span class="s">"orbit"</span><span class="nt">&gt;</span>
186  <span class="nt">&lt;source</span> <span class="na">src=</span><span class="s">"chair.usdz"</span> <span class="na">type=</span><span class="s">"model/vnd.usdz+zip"</span><span class="nt">&gt;</span>
187  <span class="nt">&lt;source</span> <span class="na">src=</span><span class="s">"chair.glb"</span> <span class="na">type=</span><span class="s">"model/gltf-binary"</span><span class="nt">&gt;</span>
188<span class="nt">&lt;/model&gt;</span>
189</code></pre></div>  </div>
190
191  <p>Without <code class="language-plaintext highlighter-rouge">stagemode</code>, the model is displayed at its authored orientation with no built-in user interaction.
192The <code class="language-plaintext highlighter-rouge">entityTransform</code> JavaScript property can be used to control the view programmatically in that case.</p>
193
194  <h3 id="key-attributes">Key attributes</h3>
195
196  <dl>
197  <dt><code>stagemode</code></dt>
198  <dd>
198Controls how the model responds to user input. When set to <code>"orbit"</code>, the browser provides built-in rotate interaction. When omitted, the model is displayed using its authored transform with no built-in manipulation.</dd>
199
200  <dt><code>autoplay</code></dt>
201  <dd>Boolean attribute. When present, any animation embedded in the model file begins playing on load.</dd>
202
203  <dt><code>loop</code></dt>
204  <dd>Boolean attribute. When present, any animation repeats continuously.</dd>
205
206  <dt><code>width</code> / <code>height</code></dt>
207  <dd>Intrinsic dimensions of the element in pixels, just like <code>&lt;img&gt;</code> or <code>&lt;video&gt;</code>. The element can also be sized with CSS.</dd>
208</dl>
209
210  <h3 id="model-api">Model API</h3>
211
212  <p>The <code class="language-plaintext highlighter-rouge">&lt;model&gt;</code> element exposes a JavaScript API for controlling the 3D scene programmatically.</p>
213
214  <h4 id="the-ready-promise">The <code class="language-plaintext highlighter-rouge">ready</code> promise</h4>
215
216  <p>Know when your model is loaded and ready to use.</p>
217
218  <p>Because model files need to be fetched and decoded,
219the element provides a <code class="language-plaintext highlighter-rouge">ready</code> promise that resolves once the source has been loaded and processed.
220At that point, properties like <code class="language-plaintext highlighter-rouge">boundingBoxCenter</code>, <code class="language-plaintext highlighter-rouge">boundingBoxExtents</code>, and <code class="language-plaintext highlighter-rouge">duration</code> are available.
221The bounding box properties are useful for understanding the size and position of the loaded content,
222for example to place labels relative to the model or to calculate a custom camera framing:</p>
223
224  <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">model</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">model</span><span class="dl">'</span><span class="p">);</span>
225
226<span class="nx">model</span><span class="p">.</span><span class="nx">ready</span><span class="p">.</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
227  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Center:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">model</span><span class="p">.</span><span class="nx">boundingBoxCenter</span><span class="p">);</span>
228  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Extents:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">model</span><span class="p">.</span><span class="nx">boundingBoxExtents</span><span class="p">);</span>
229  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Animation duration:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">model</span><span class="p">.</span><span class="nx">duration</span><span class="p">);</span>
230<span class="p">});</span>
231</code></pre></div>  </div>
232
233  <p>The promise rejects if the source cannot be fetched or is not a valid model asset.</p>
234
235  <h4 id="entitytransform"><code class="language-plaintext highlighter-rouge">entityTransform</code></h4>
236
237  <p>Control the position, rotation, and scale of the model programmatically.</p>
238
239  <p>The <code class="language-plaintext highlighter-rouge">entityTransform</code> property is a read-write <code class="language-plaintext highlighter-rouge">DOMMatrixReadOnly</code> that controls the position, rotation, and scale of the model within the element’s viewport.
240The coordinate system is right-handed and Y-up, with the origin at the centre of the view plane.
241One unit equals one CSS metre.
242A 10 cm (0.1 units) box inside a square 10 cm portal fills it exactly when the <code class="language-plaintext highlighter-rouge">entityTransform</code> is the identity matrix.</p>
243
244  <p>The browser computes an initial <code class="language-plaintext highlighter-rouge">entityTransform</code> that centres the model on its bounding box
245and scales it to fit within the element’s portal.
246Because <code class="language-plaintext highlighter-rouge">DOMMatrixReadOnly</code> methods like <code class="language-plaintext highlighter-rouge">translate()</code> and <code class="language-plaintext highlighter-rouge">rotate()</code> return new matrices,
247you can derive transforms from the initial one without mutating it:</p>
248
249  <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">model</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">model</span><span class="dl">'</span><span class="p">);</span>
250<span class="kd">let</span> <span class="nx">initialTransform</span><span class="p">;</span>
251<span class="k">await</span> <span class="nx">model</span><span class="p">.</span><span class="nx">ready</span><span class="p">;</span>
252<span class="nx">initialTransform</span> <span class="o">=</span> <span class="nx">model</span><span class="p">.</span><span class="nx">entityTransform</span><span class="p">;</span>
253<span class="nx">model</span><span class="p">.</span><span class="nx">entityTransform</span> <span class="o">=</span> <span class="nx">initialTransform</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.05</span><span class="p">).</span><span class="nx">rotate</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">45</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
254</code></pre></div>  </div>
255
256  <p>Note that when <code class="language-plaintext highlighter-rouge">stagemode</code> is set to a value other than <code class="language-plaintext highlighter-rouge">none</code>,
257the browser manages <code class="language-plaintext highlighter-rouge">entityTransform</code> in response to user input
258and <strong>writes to the property are ignored</strong>.
259Remove the <code class="language-plaintext highlighter-rouge">stagemode</code> attribute if you need programmatic control of the transform.</p>
260
261  <h3 id="fallback-content">Fallback content</h3>
262
263  <p>When a browser does not support <code class="language-plaintext highlighter-rouge">&lt;model&gt;</code>, it ignores the tag and renders whatever is inside it,
264the same pattern as <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code>.
265This makes progressive enhancement straightforward:
266place an <code class="language-plaintext highlighter-rouge">&lt;img&gt;</code>, a <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code>, or any other content after the <code class="language-plaintext highlighter-rouge">&lt;source&gt;</code> elements as a fallback:</p>
267
268  <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;model</span> <span class="na">stagemode=</span><span class="s">"orbit"</span><span class="nt">&gt;</span>
269  <span class="nt">&lt;source</span> <span class="na">src=</span><span class="s">"chair.usdz"</span> <span class="na">type=</span><span class="s">"model/vnd.usdz+zip"</span><span class="nt">&gt;</span>
270  <span class="nt">&lt;source</span> <span class="na">src=</span><span class="s">"chair.glb"</span> <span class="na">type=</span><span class="s">"model/gltf-binary"</span><span class="nt">&gt;</span>
271  <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"chair-preview.jpg"</span> <span class="na">alt=</span><span class="s">"A red chair"</span><span class="nt">&gt;</span>
272<span class="nt">&lt;/model&gt;</span>
273</code></pre></div>  </div>
274
275  <p>The fallback can be anything:
276a static image, a <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code> with captions and audio descriptions,
277or a WebGL-based component like <a href="https://modelviewer.dev"><code class="language-plaintext highlighter-rouge">&lt;model-viewer&gt;</code></a>.
278The explainer includes <a href="https://github.com/WebKit/explainers/blob/main/model/explainer.md#fallback-content">an expanded example</a> showing a <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code> fallback with full accessibility tracks.</p>
279
280</section>
281
282<div class="accent-bar" aria-hidden="true"></div>
283
284<section class="card" id="animations">
285
286  <h2 id="animations">Animations</h2>
287
288  <p>Models can carry embedded animations. Set the <code class="language-plaintext highlighter-rouge">autoplay</code> attribute to start playback on load and <code class="language-plaintext highlighter-rouge">loop</code> to repeat. The <a href="https://github.com/WebKit/explainers/blob/main/model/explainer.md#animation"><code class="language-plaintext highlighter-rouge">playbackRate</code></a> property scales playback speed in real time, the same way it does on <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code>.</p>
289
290  <p>Try speeding up or slowing down the propeller:</p>
291
292  <div class="animation-demo">
293  <model id="plane-model" autoplay="" loop="" alt="Small animated plane with a spinning propeller" style="max-width: 480px; width: 100%; height: auto; aspect-ratio: 16/9;">
294    <source src="/models/plane-mini.usdz" type="model/vnd.usdz+zip" />
295    <source src="/models/plane-optim.glb" type="model/gltf-binary" />
296  </model>
297  <div class="animation-controls">
298    <label for="plane-rate">Propeller speed <output id="plane-rate-output">1.0×</output></label>
299    <input type="range" id="plane-rate" min="0" max="10" step="0.1" value="1" />
300    <label><input type="checkbox" id="plane-playing" switch="" checked="" /> Playing</label>
301  </div>
302</div>
303
304  
304<script type="module">
305  if (window.modelFallbackReady) await window.modelFallbackReady;
306
307  const model = document.getElementById('plane-model');
308  const rate = document.getElementById('plane-rate');
309  const rateOutput = document.getElementById('plane-rate-output');
310  const playingSwitch = document.getElementById('plane-playing');
311
312  await model.ready;
313
314  const initialTransform = window.initialTransform = model.entityTransform;
315  const portalHalfHeightUnits = model.getBoundingClientRect().height / 2 * (0.0254 / 96);
316  // Browser's initial transform centers the bbox at the portal centre. Shift so the
317  // model origin lands at the portal bottom (the plane's authored ground level).
318  const deltaY = -portalHalfHeightUnits - initialTransform.m42;
319  const baseTransform = new DOMMatrix().translate(0, deltaY, 0).multiply(initialTransform);
320  model.entityTransform = baseTransform.rotate(0, 45, 0);
321
322  rate.addEventListener('input', () => {
323    const value = Number(rate.value).toFixed(1);
324    model.playbackRate = value;
325    rateOutput.textContent = `${value}×`;
326  });
327
328  playingSwitch.addEventListener('change', () => {
329    if (playingSwitch.checked) {
330      model.play();
331    } else {
332      model.pause();
333    }
334  });
335</script>
335
336
337  <p>The minimal markup:</p>
338
339  <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;model</span> <span class="na">src=</span><span class="s">"plane.usdz"</span> <span class="na">autoplay</span> <span class="na">loop</span><span class="nt">&gt;&lt;/model&gt;</span>
340</code></pre></div>  </div>
341
342  <p>Add a speed slider by reading and writing <code class="language-plaintext highlighter-rouge">playbackRate</code>:</p>
343
344  <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">model</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">model</span><span class="dl">'</span><span class="p">);</span>
345<span class="kd">const</span> <span class="nx">slider</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">#speed</span><span class="dl">'</span><span class="p">);</span>
346
347<span class="k">await</span> <span class="nx">model</span><span class="p">.</span><span class="nx">ready</span><span class="p">;</span>
348<span class="nx">slider</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">input</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
349  <span class="nx">model</span><span class="p">.</span><span class="nx">playbackRate</span> <span class="o">=</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">slider</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
350<span class="p">});</span>
351</code></pre></div>  </div>
352
353</section>
354
355<div class="accent-bar" aria-hidden="true"></div>
356
357<section class="card" id="resources">
358
359  <h2 id="resources">Resources</h2>
360
361  <ul>
362    <li><a href="https://github.com/WebKit/explainers/blob/main/model/explainer.md">Model Element Explainer</a>: motivation, design decisions, and usage examples</li>
363    <li><a href="https://immersive-web.github.io/model-element/">Model Element Specification</a>: the draft W3C spec, including the full IDL interface and attribute definitions</li>
364    <li><a href="https://github.com/immersive-web/model-element">Model Element on GitHub</a>: spec source, issue tracker, and discussion</li>
365  </ul>
366
367</section>
368
369  </main>
370
371  <div class="accent-bar" aria-hidden="true"></div>
372
373  <footer class="site-footer">
374    <div class="container">
375      <p>
376        <a href="https://w3.org/immersive-web">W3C Immersive Web Working and Community Groups</a>.
377        Content is <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0 Licensed</a>.
378        <a href="https://github.com/immersive-web/immersiveweb.dev">Contribute on GitHub</a>.
379      </p>
380    </div>
381  </footer>
382
383<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"9fe3070772174243bcc7b12cb89f8999","r":1,"spa":2}' crossorigin="anonymous"></script>
383
384</body>
385</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.