Skip to content

Commit 2bfa20c

Browse files
author
Thomas Gorisse
committed
sync: new 3D models + wrapper v1.1.0
1 parent 39299c0 commit 2bfa20c

7 files changed

Lines changed: 125 additions & 58 deletions

filament-pure-test.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ <h1>SceneView Web</h1>
2727
canvas.width = canvas.clientWidth * devicePixelRatio;
2828
canvas.height = canvas.clientHeight * devicePixelRatio;
2929

30-
const MODEL_URL = 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/DamagedHelmet/glTF-Binary/DamagedHelmet.glb';
30+
const MODEL_URL = 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb';
3131

3232
Filament.init([MODEL_URL], () => {
3333
status.textContent = 'Creating scene...';

js/package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "sceneview-web",
3+
"version": "1.1.0",
4+
"description": "One-liner 3D for the web — SceneView.modelViewer('canvas', 'model.glb'). Powered by Filament.js WASM.",
5+
"main": "sceneview.js",
6+
"author": "SceneView Tools",
7+
"license": "MIT",
8+
"keywords": ["3d", "ar", "filament", "webgl", "wasm", "pbr", "gltf", "model-viewer", "sceneview"],
9+
"homepage": "https://sceneview.github.io",
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/sceneview/sceneview"
13+
}
14+
}

js/sceneview.js

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,48 @@
44
* One line to render a 3D model:
55
* SceneView.modelViewer("canvas", "model.glb")
66
*
7-
* Prerequisites: load Filament.js CDN via <script> BEFORE this file:
8-
* <script src="https://cdn.jsdelivr.net/npm/filament@1.52.3/filament.js"></script>
7+
* No prerequisites — sceneview.js loads Filament.js CDN automatically.
8+
* Just include one script:
99
* <script src="js/sceneview.js"></script>
1010
*
1111
* Powered by Filament.js (Google's PBR renderer, WASM).
1212
* https://sceneview.github.io
1313
*
14-
* @version 2.0.0
14+
* @version 1.1.0
1515
* @license MIT
1616
*/
1717
(function(global) {
1818
'use strict';
1919

20+
var FILAMENT_CDN = 'https://cdn.jsdelivr.net/npm/filament@1.52.3/filament.js';
21+
22+
/**
23+
* Load Filament.js CDN dynamically if not already present.
24+
* Returns a Promise that resolves when the Filament global is available.
25+
*/
26+
function _ensureFilament() {
27+
return new Promise(function(resolve, reject) {
28+
// Already loaded
29+
if (typeof Filament !== 'undefined') {
30+
resolve();
31+
return;
32+
}
33+
// Check if script tag already exists but hasn't finished loading
34+
var existing = document.querySelector('script[src*="filament"]');
35+
if (existing) {
36+
existing.addEventListener('load', function() { resolve(); });
37+
existing.addEventListener('error', function() { reject(new Error('SceneView: Failed to load Filament.js from CDN')); });
38+
return;
39+
}
40+
// Inject script tag
41+
var script = document.createElement('script');
42+
script.src = FILAMENT_CDN;
43+
script.onload = function() { resolve(); };
44+
script.onerror = function() { reject(new Error('SceneView: Failed to load Filament.js from CDN (' + FILAMENT_CDN + ')')); };
45+
document.head.appendChild(script);
46+
});
47+
}
48+
2049
/**
2150
* SceneView instance — wraps Filament engine, scene, camera, renderer.
2251
*/
@@ -59,7 +88,8 @@
5988
}
6089
return;
6190
}
62-
// Fetch via Filament.init (handles WASM + fetch)
91+
// Fetch via Filament.init with asset — this always fires the callback
92+
// because it needs to fetch the asset even if WASM is already loaded
6393
Filament.init([url], function() {
6494
try {
6595
self._showModel(url);
@@ -291,59 +321,67 @@
291321

292322
/**
293323
* Create an empty SceneView on a canvas.
294-
* Filament.js must be loaded via <script> before calling this.
324+
* Filament.js is loaded automatically from CDN if not already present.
295325
*
296326
* @param {string|HTMLCanvasElement} canvasOrId - Canvas element or its ID
297327
* @param {Object} [options] - Configuration options
298328
* @returns {Promise<SceneViewInstance>}
299329
*/
300330
function create(canvasOrId, options) {
301-
return new Promise(function(resolve, reject) {
302-
if (typeof Filament === 'undefined') {
303-
reject(new Error('SceneView: Filament.js not loaded. Add <script src="https://cdn.jsdelivr.net/npm/filament@1.52.3/filament.js"></script> before sceneview.js'));
304-
return;
305-
}
306-
Filament.init([], function() {
307-
try {
308-
resolve(_createEngine(canvasOrId, options));
309-
} catch (e) {
310-
reject(e);
331+
return _ensureFilament().then(function() {
332+
return new Promise(function(resolve, reject) {
333+
// If WASM is already initialized (Engine exists), skip Filament.init
334+
if (typeof Filament.Engine !== 'undefined') {
335+
try {
336+
resolve(_createEngine(canvasOrId, options));
337+
} catch (e) {
338+
reject(e);
339+
}
340+
return;
311341
}
342+
// First time: initialize WASM
343+
Filament.init([], function() {
344+
try {
345+
resolve(_createEngine(canvasOrId, options));
346+
} catch (e) {
347+
reject(e);
348+
}
349+
});
312350
});
313351
});
314352
}
315353

316354
/**
317355
* One-liner: create viewer and load a model.
318-
* Filament.js must be loaded via <script> before calling this.
356+
* Filament.js is loaded automatically from CDN if not already present.
319357
*
320358
* @param {string|HTMLCanvasElement} canvasOrId
321359
* @param {string} modelUrl - URL to .glb/.gltf model
322360
* @param {Object} [options]
323361
* @returns {Promise<SceneViewInstance>}
324362
*/
325363
function modelViewer(canvasOrId, modelUrl, options) {
326-
return new Promise(function(resolve, reject) {
327-
if (typeof Filament === 'undefined') {
328-
reject(new Error('SceneView: Filament.js not loaded. Add <script src="https://cdn.jsdelivr.net/npm/filament@1.52.3/filament.js"></script> before sceneview.js'));
329-
return;
330-
}
331-
// Pre-fetch model AND initialize WASM in one call
332-
Filament.init([modelUrl], function() {
333-
try {
334-
var instance = _createEngine(canvasOrId, options);
335-
instance._showModel(modelUrl);
336-
resolve(instance);
337-
} catch (e) {
338-
reject(e);
339-
}
364+
return _ensureFilament().then(function() {
365+
return new Promise(function(resolve, reject) {
366+
// Always use Filament.init with the model URL in the assets array.
367+
// This works whether WASM is already loaded or not, because Filament
368+
// needs to fetch the model asset and will call back when done.
369+
Filament.init([modelUrl], function() {
370+
try {
371+
var instance = _createEngine(canvasOrId, options);
372+
instance._showModel(modelUrl);
373+
resolve(instance);
374+
} catch (e) {
375+
reject(e);
376+
}
377+
});
340378
});
341379
});
342380
}
343381

344382
// Public API
345383
global.SceneView = {
346-
version: '2.0.0',
384+
version: '1.1.0',
347385
create: create,
348386
modelViewer: modelViewer
349387
};

sceneview-demo.html

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ <h1>SceneView Web</h1>
3232

3333
<div class="models">
3434
<button class="active" onclick="load(this, 'DamagedHelmet')">Damaged Helmet</button>
35-
<button onclick="load(this, 'FlightHelmet')">Flight Helmet</button>
36-
<button onclick="load(this, 'Avocado')">Avocado</button>
37-
<button onclick="load(this, 'Lantern')">Lantern</button>
35+
<button onclick="load(this, 'SheenChair')">Sheen Chair</button>
36+
<button onclick="load(this, 'ToyCar')">Toy Car</button>
37+
<button onclick="load(this, 'GlassVaseFlowers')">Glass Vase</button>
38+
<button onclick="load(this, 'Fox')">Fox</button>
39+
<button onclick="load(this, 'Duck')">Duck</button>
3840
</div>
3941

4042
<div class="code">
@@ -47,11 +49,14 @@ <h1>SceneView Web</h1>
4749
<script src="https://cdn.jsdelivr.net/npm/filament@1.52.3/filament.js"></script>
4850
<script src="js/sceneview.js"></script>
4951
<script>
52+
const BASE = 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models';
5053
const MODELS = {
51-
'DamagedHelmet': 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/DamagedHelmet/glTF-Binary/DamagedHelmet.glb',
52-
'FlightHelmet': 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/FlightHelmet/glTF-Binary/FlightHelmet.glb',
53-
'Avocado': 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/Avocado/glTF-Binary/Avocado.glb',
54-
'Lantern': 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/Lantern/glTF-Binary/Lantern.glb'
54+
'DamagedHelmet': BASE + '/DamagedHelmet/glTF-Binary/DamagedHelmet.glb',
55+
'SheenChair': BASE + '/SheenChair/glTF-Binary/SheenChair.glb',
56+
'ToyCar': BASE + '/ToyCar/glTF-Binary/ToyCar.glb',
57+
'GlassVaseFlowers': BASE + '/GlassVaseFlowers/glTF-Binary/GlassVaseFlowers.glb',
58+
'Fox': BASE + '/Fox/glTF-Binary/Fox.glb',
59+
'Duck': BASE + '/Duck/glTF-Binary/Duck.glb'
5560
};
5661

5762
const status = document.getElementById('status');

sceneview-live-demo.html

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,11 @@
102102

103103
<div class="controls" id="controls" style="display:none;">
104104
<button class="model-btn active" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb">Damaged Helmet</button>
105-
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Avocado/glTF-Binary/Avocado.glb">Avocado</button>
106-
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Lantern/glTF-Binary/Lantern.glb">Lantern</button>
107-
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/FlightHelmet/glTF-Binary/FlightHelmet.glb">Flight Helmet</button>
105+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/SheenChair/glTF-Binary/SheenChair.glb">Sheen Chair</button>
106+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ToyCar/glTF-Binary/ToyCar.glb">Toy Car</button>
107+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/GlassVaseFlowers/glTF-Binary/GlassVaseFlowers.glb">Glass Vase</button>
108+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Fox/glTF-Binary/Fox.glb">Fox</button>
109+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Duck/glTF-Binary/Duck.glb">Duck</button>
108110
</div>
109111

110112
<div class="code-badge">
@@ -138,11 +140,14 @@
138140
// SceneView Web Live Demo
139141
// This demonstrates real Filament.js WASM rendering through SceneView's Kotlin/JS API.
140142

143+
var BASE = "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models";
141144
var MODELS = {
142-
"DamagedHelmet": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb",
143-
"Avocado": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Avocado/glTF-Binary/Avocado.glb",
144-
"Lantern": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Lantern/glTF-Binary/Lantern.glb",
145-
"FlightHelmet": "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/FlightHelmet/glTF-Binary/FlightHelmet.glb"
145+
"DamagedHelmet": BASE + "/DamagedHelmet/glTF-Binary/DamagedHelmet.glb",
146+
"SheenChair": BASE + "/SheenChair/glTF-Binary/SheenChair.glb",
147+
"ToyCar": BASE + "/ToyCar/glTF-Binary/ToyCar.glb",
148+
"GlassVaseFlowers": BASE + "/GlassVaseFlowers/glTF-Binary/GlassVaseFlowers.glb",
149+
"Fox": BASE + "/Fox/glTF-Binary/Fox.glb",
150+
"Duck": BASE + "/Duck/glTF-Binary/Duck.glb"
146151
};
147152

148153
var statusEl = document.getElementById("status");

sceneview-web-demo.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@
7979

8080
<div class="controls" id="controls" style="display:none;">
8181
<button class="model-btn active" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb">Damaged Helmet</button>
82-
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Avocado/glTF-Binary/Avocado.glb">Avocado</button>
83-
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Lantern/glTF-Binary/Lantern.glb">Lantern</button>
82+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/SheenChair/glTF-Binary/SheenChair.glb">Sheen Chair</button>
83+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/ToyCar/glTF-Binary/ToyCar.glb">Toy Car</button>
84+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Fox/glTF-Binary/Fox.glb">Fox</button>
85+
<button class="model-btn" data-url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Duck/glTF-Binary/Duck.glb">Duck</button>
8486
</div>
8587

8688
<div class="code-badge">

sceneview-wrapper-test.html

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,28 @@ <h1>SceneView Wrapper Test</h1>
3131

3232
<div class="models">
3333
<button class="active" onclick="load(this, 'DamagedHelmet')">Damaged Helmet</button>
34-
<button onclick="load(this, 'FlightHelmet')">Flight Helmet</button>
35-
<button onclick="load(this, 'Avocado')">Avocado</button>
36-
<button onclick="load(this, 'Lantern')">Lantern</button>
34+
<button onclick="load(this, 'SheenChair')">Sheen Chair</button>
35+
<button onclick="load(this, 'ToyCar')">Toy Car</button>
36+
<button onclick="load(this, 'GlassVaseFlowers')">Glass Vase</button>
37+
<button onclick="load(this, 'Fox')">Fox</button>
38+
<button onclick="load(this, 'Duck')">Duck</button>
3739
</div>
3840

3941
<div class="code">
4042
<code>SceneView.modelViewer("viewer", modelUrl)</code>
4143
</div>
4244

43-
<!-- Step 1: Load Filament.js CDN FIRST -->
44-
<script src="https://cdn.jsdelivr.net/npm/filament@1.52.3/filament.js"></script>
45-
<!-- Step 2: Load SceneView wrapper -->
45+
<!-- Only one script needed — sceneview.js loads Filament.js CDN automatically -->
4646
<script src="js/sceneview.js"></script>
4747
<script>
48+
const BASE = 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models';
4849
const MODELS = {
49-
'DamagedHelmet': 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/DamagedHelmet/glTF-Binary/DamagedHelmet.glb',
50-
'FlightHelmet': 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/FlightHelmet/glTF-Binary/FlightHelmet.glb',
51-
'Avocado': 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/Avocado/glTF-Binary/Avocado.glb',
52-
'Lantern': 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/Lantern/glTF-Binary/Lantern.glb'
50+
'DamagedHelmet': BASE + '/DamagedHelmet/glTF-Binary/DamagedHelmet.glb',
51+
'SheenChair': BASE + '/SheenChair/glTF-Binary/SheenChair.glb',
52+
'ToyCar': BASE + '/ToyCar/glTF-Binary/ToyCar.glb',
53+
'GlassVaseFlowers': BASE + '/GlassVaseFlowers/glTF-Binary/GlassVaseFlowers.glb',
54+
'Fox': BASE + '/Fox/glTF-Binary/Fox.glb',
55+
'Duck': BASE + '/Duck/glTF-Binary/Duck.glb'
5356
};
5457

5558
const status = document.getElementById('status');

0 commit comments

Comments
 (0)