sceneview-mcp 3.5.1 → 3.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,539 @@
1
+ /**
2
+ * extra-guides.ts
3
+ *
4
+ * Material, collision, model optimization, and web rendering guides.
5
+ */
6
+ // ─── Material Guide ─────────────────────────────────────────────────────────
7
+ export const MATERIAL_GUIDE = `# SceneView Material & Shader Guide
8
+
9
+ ## PBR Material Properties
10
+
11
+ SceneView uses **Filament's PBR material model** — the same physically-based rendering used by Google Maps, Android Auto, and model-viewer. Materials are defined by these core properties:
12
+
13
+ | Property | Range | Description |
14
+ |----------|-------|-------------|
15
+ | **baseColor** | RGB [0-1] | Albedo color (diffuse color for non-metals) |
16
+ | **metallic** | 0.0–1.0 | 0 = dielectric (plastic, wood), 1 = metal (gold, chrome) |
17
+ | **roughness** | 0.0–1.0 | 0 = mirror, 1 = matte |
18
+ | **reflectance** | 0.0–1.0 | F0 reflectance for dielectrics (default 0.5 = 4% reflectance) |
19
+ | **emissive** | RGB [0-∞] | Self-illumination color (HDR values > 1 for bloom) |
20
+ | **ambientOcclusion** | 0.0–1.0 | Baked contact shadows |
21
+ | **normal** | RGB normal map | Surface detail without geometry |
22
+ | **clearCoat** | 0.0–1.0 | Lacquer/varnish layer (car paint, ceramic) |
23
+ | **clearCoatRoughness** | 0.0–1.0 | Roughness of the clear coat layer |
24
+
25
+ ## Accessing Materials on ModelNode
26
+
27
+ \`\`\`kotlin
28
+ @Composable
29
+ fun CustomMaterialScreen() {
30
+ val engine = rememberEngine()
31
+ val modelLoader = rememberModelLoader(engine)
32
+ val modelInstance = rememberModelInstance(modelLoader, "models/chair.glb")
33
+
34
+ Scene(engine = engine) {
35
+ modelInstance?.let { instance ->
36
+ ModelNode(
37
+ modelInstance = instance,
38
+ scaleToUnits = 1.0f
39
+ ) {
40
+ // Access material instances on the model
41
+ instance.materialInstances.forEach { materialInstance ->
42
+ // Change base color to red
43
+ materialInstance.setBaseColor(1f, 0f, 0f, 1f)
44
+ // Make it metallic
45
+ materialInstance.setMetallic(0.9f)
46
+ // Make it shiny
47
+ materialInstance.setRoughness(0.1f)
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ \`\`\`
54
+
55
+ ## Applying Textures
56
+
57
+ \`\`\`kotlin
58
+ @Composable
59
+ fun TexturedModelScreen() {
60
+ val engine = rememberEngine()
61
+ val modelLoader = rememberModelLoader(engine)
62
+ val materialLoader = rememberMaterialLoader(engine)
63
+ val modelInstance = rememberModelInstance(modelLoader, "models/object.glb")
64
+
65
+ Scene(engine = engine) {
66
+ modelInstance?.let { instance ->
67
+ ModelNode(
68
+ modelInstance = instance,
69
+ scaleToUnits = 1.0f
70
+ )
71
+ }
72
+ }
73
+ }
74
+ \`\`\`
75
+
76
+ ## Common Material Recipes
77
+
78
+ ### Glass / Transparent
79
+ \`\`\`kotlin
80
+ materialInstance.setBaseColor(0.9f, 0.9f, 1f, 0.3f) // transparent
81
+ materialInstance.setMetallic(0f)
82
+ materialInstance.setRoughness(0f) // perfectly smooth
83
+ materialInstance.setReflectance(0.5f)
84
+ \`\`\`
85
+
86
+ ### Chrome / Mirror Metal
87
+ \`\`\`kotlin
88
+ materialInstance.setBaseColor(0.95f, 0.95f, 0.95f, 1f)
89
+ materialInstance.setMetallic(1f)
90
+ materialInstance.setRoughness(0.05f)
91
+ \`\`\`
92
+
93
+ ### Gold
94
+ \`\`\`kotlin
95
+ materialInstance.setBaseColor(1f, 0.766f, 0.336f, 1f)
96
+ materialInstance.setMetallic(1f)
97
+ materialInstance.setRoughness(0.3f)
98
+ \`\`\`
99
+
100
+ ### Rubber / Matte Plastic
101
+ \`\`\`kotlin
102
+ materialInstance.setBaseColor(0.2f, 0.2f, 0.2f, 1f)
103
+ materialInstance.setMetallic(0f)
104
+ materialInstance.setRoughness(0.9f)
105
+ \`\`\`
106
+
107
+ ### Car Paint (Clear Coat)
108
+ \`\`\`kotlin
109
+ materialInstance.setBaseColor(0.8f, 0.0f, 0.0f, 1f) // red car
110
+ materialInstance.setMetallic(0.0f)
111
+ materialInstance.setRoughness(0.4f)
112
+ materialInstance.setClearCoat(1f)
113
+ materialInstance.setClearCoatRoughness(0.1f)
114
+ \`\`\`
115
+
116
+ ## Environment Lighting for Materials
117
+
118
+ For PBR materials to look correct, you MUST have **IBL (Image-Based Lighting)**. Without it, metallic surfaces appear black and reflections are missing.
119
+
120
+ SceneView Android loads a default neutral IBL automatically. For custom environments:
121
+
122
+ \`\`\`kotlin
123
+ val engine = rememberEngine()
124
+ val environmentLoader = rememberEnvironmentLoader(engine)
125
+
126
+ Scene(
127
+ engine = engine,
128
+ environment = environmentLoader.createHDREnvironment("environments/studio_2k.hdr")!!
129
+ ) {
130
+ // Your nodes here
131
+ }
132
+ \`\`\`
133
+
134
+ ## Tips
135
+
136
+ 1. **Always check IBL first** — if materials look flat/dark, you're missing environment lighting
137
+ 2. **Metallic = 0 or 1** — intermediate values are physically rare (use only for worn metal)
138
+ 3. **Roughness matters most** — it controls the "feel" more than any other property
139
+ 4. **Normal maps are free detail** — use them instead of adding geometry
140
+ 5. **Keep textures power-of-2** — 1024x1024, 2048x2048 for best GPU performance
141
+ `;
142
+ // ─── Collision & Physics Guide ──────────────────────────────────────────────
143
+ export const COLLISION_GUIDE = `# SceneView Collision & Physics Guide
144
+
145
+ ## Hit Testing (Tap on 3D Objects)
146
+
147
+ SceneView supports hit testing via \`onTouchEvent\` on nodes. The \`hitResult\` gives you the exact 3D point where the user tapped.
148
+
149
+ ### Basic Node Tapping
150
+
151
+ \`\`\`kotlin
152
+ @Composable
153
+ fun TappableModelScreen() {
154
+ val engine = rememberEngine()
155
+ val modelLoader = rememberModelLoader(engine)
156
+ val modelInstance = rememberModelInstance(modelLoader, "models/button.glb")
157
+ var tapped by remember { mutableStateOf(false) }
158
+
159
+ Scene(engine = engine) {
160
+ modelInstance?.let { instance ->
161
+ ModelNode(
162
+ modelInstance = instance,
163
+ scaleToUnits = 0.5f,
164
+ centerOrigin = Position(y = -0.5f)
165
+ ) {
166
+ // Make node respond to touch
167
+ isTouchable = true
168
+ onTouchEvent = { hitResult, motionEvent ->
169
+ if (motionEvent.action == MotionEvent.ACTION_DOWN) {
170
+ tapped = true
171
+ }
172
+ true
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+ \`\`\`
179
+
180
+ ## AR Hit Testing (Tap to Place)
181
+
182
+ In AR, hit testing detects real-world surfaces:
183
+
184
+ \`\`\`kotlin
185
+ @Composable
186
+ fun ARTapToPlaceScreen() {
187
+ val engine = rememberEngine()
188
+ val modelLoader = rememberModelLoader(engine)
189
+ val modelInstance = rememberModelInstance(modelLoader, "models/chair.glb")
190
+
191
+ ARScene(
192
+ engine = engine,
193
+ sessionConfiguration = { session, config ->
194
+ config.planeFindingMode = Config.PlaneFindingMode.HORIZONTAL_AND_VERTICAL
195
+ },
196
+ onSessionUpdated = { session, frame ->
197
+ // frame.hitTest() gives real-world surface intersections
198
+ }
199
+ ) {
200
+ // Place model at anchor when user taps
201
+ }
202
+ }
203
+ \`\`\`
204
+
205
+ ## Collision Detection (KMP Core)
206
+
207
+ SceneView's KMP core module (\`sceneview-core\`) provides cross-platform collision detection:
208
+
209
+ ### Ray-Box Intersection
210
+ \`\`\`kotlin
211
+ import io.github.sceneview.collision.Ray
212
+ import io.github.sceneview.collision.Box
213
+ import io.github.sceneview.collision.Intersections
214
+
215
+ val ray = Ray(
216
+ origin = Float3(0f, 1f, 5f),
217
+ direction = Float3(0f, 0f, -1f)
218
+ )
219
+
220
+ val box = Box(
221
+ center = Float3(0f, 0f, 0f),
222
+ halfExtent = Float3(1f, 1f, 1f)
223
+ )
224
+
225
+ val hit = Intersections.rayBox(ray, box)
226
+ if (hit != null) {
227
+ println("Hit at distance: \${hit.distance}")
228
+ println("Hit point: \${hit.point}")
229
+ }
230
+ \`\`\`
231
+
232
+ ### Ray-Sphere Intersection
233
+ \`\`\`kotlin
234
+ import io.github.sceneview.collision.Sphere
235
+
236
+ val sphere = Sphere(
237
+ center = Float3(0f, 1f, 0f),
238
+ radius = 0.5f
239
+ )
240
+
241
+ val hit = Intersections.raySphere(ray, sphere)
242
+ \`\`\`
243
+
244
+ ## Physics Simulation (KMP Core)
245
+
246
+ The \`sceneview-core\` module includes basic rigid body physics:
247
+
248
+ \`\`\`kotlin
249
+ import io.github.sceneview.physics.PhysicsWorld
250
+ import io.github.sceneview.physics.RigidBody
251
+
252
+ val world = PhysicsWorld(gravity = Float3(0f, -9.81f, 0f))
253
+
254
+ val ball = RigidBody(
255
+ position = Float3(0f, 5f, 0f),
256
+ mass = 1f,
257
+ restitution = 0.8f // bounciness
258
+ )
259
+ world.addBody(ball)
260
+
261
+ // In your render loop:
262
+ world.step(deltaTime)
263
+ // ball.position is updated by physics
264
+ \`\`\`
265
+
266
+ ## Node Bounding Box
267
+
268
+ Every node has a bounding box for collision:
269
+
270
+ \`\`\`kotlin
271
+ ModelNode(modelInstance = instance) {
272
+ // Access bounding box after model loads
273
+ val box = boundingBox
274
+ println("Size: \${box.halfExtent * 2f}")
275
+ println("Center: \${box.center}")
276
+ }
277
+ \`\`\`
278
+
279
+ ## Tips
280
+
281
+ 1. **Use \`isTouchable = true\`** — nodes are not touchable by default
282
+ 2. **AR hit test with \`frame.hitTest()\`** — returns surfaces sorted by distance
283
+ 3. **BoundingBox for broad-phase** — check box overlap before expensive ray tests
284
+ 4. **Physics is optional** — import \`sceneview-core\` separately from \`sceneview\`
285
+ `;
286
+ // ─── Model Optimization Guide ───────────────────────────────────────────────
287
+ export const MODEL_OPTIMIZATION_GUIDE = `# 3D Model Optimization for SceneView
288
+
289
+ ## Polygon Budgets
290
+
291
+ | Device Tier | Total Scene Budget | Per-Model Budget |
292
+ |-------------|-------------------|-----------------|
293
+ | **High-end** (Pixel 8, Samsung S24) | 500K–1M triangles | 200K triangles |
294
+ | **Mid-range** (Pixel 6a, Samsung A54) | 200K–500K triangles | 100K triangles |
295
+ | **Low-end** | 50K–200K triangles | 50K triangles |
296
+ | **AR scenes** (battery + thermal) | 100K–300K triangles | 50K–100K triangles |
297
+
298
+ ## File Size Targets
299
+
300
+ | Format | Good | Acceptable | Too Large |
301
+ |--------|------|------------|-----------|
302
+ | **GLB** | < 5 MB | 5–20 MB | > 20 MB |
303
+ | **With Draco** | < 2 MB | 2–10 MB | > 10 MB |
304
+ | **Textures** (total) | < 8 MB | 8–32 MB | > 32 MB |
305
+
306
+ ## Compression
307
+
308
+ ### Draco Mesh Compression
309
+ Reduces geometry size 5–10x. Supported natively by SceneView/Filament.
310
+
311
+ \`\`\`bash
312
+ # Using gltf-transform CLI
313
+ npx gltf-transform draco input.glb output.glb
314
+
315
+ # Aggressive compression
316
+ npx gltf-transform draco input.glb output.glb \\
317
+ --quantize-position 14 \\
318
+ --quantize-normal 10
319
+ \`\`\`
320
+
321
+ ### Meshopt Compression
322
+ Alternative to Draco with faster decompression:
323
+
324
+ \`\`\`bash
325
+ npx gltf-transform meshopt input.glb output.glb
326
+ \`\`\`
327
+
328
+ ### KTX2 Texture Compression (Basis Universal)
329
+ Reduces texture memory 4–6x. GPU-native — no decompression needed.
330
+
331
+ \`\`\`bash
332
+ # Convert all textures to KTX2
333
+ npx gltf-transform ktx2 input.glb output.glb --slots "baseColor,normal,emissive"
334
+
335
+ # With specific quality
336
+ npx gltf-transform ktx2 input.glb output.glb --quality 128
337
+ \`\`\`
338
+
339
+ ## Optimization Pipeline
340
+
341
+ The recommended optimization pipeline for production models:
342
+
343
+ \`\`\`bash
344
+ # 1. Simplify high-poly meshes
345
+ npx gltf-transform simplify input.glb step1.glb --ratio 0.5
346
+
347
+ # 2. Merge duplicate meshes/materials
348
+ npx gltf-transform dedup step1.glb step2.glb
349
+
350
+ # 3. Compress textures to KTX2
351
+ npx gltf-transform ktx2 step2.glb step3.glb
352
+
353
+ # 4. Apply Draco compression
354
+ npx gltf-transform draco step3.glb output.glb
355
+
356
+ # 5. Verify
357
+ npx gltf-transform inspect output.glb
358
+ \`\`\`
359
+
360
+ ## Texture Optimization
361
+
362
+ | Texture Type | Recommended Size | Format |
363
+ |-------------|-----------------|--------|
364
+ | **Base Color** | 1024x1024 | KTX2 (sRGB) |
365
+ | **Normal Map** | 1024x1024 | KTX2 (linear) |
366
+ | **ORM** (AO/Roughness/Metallic) | 512x512 | KTX2 (linear) |
367
+ | **Emissive** | 512x512 | KTX2 (sRGB) |
368
+
369
+ ### Power of 2 Rule
370
+ Always use power-of-2 textures (256, 512, 1024, 2048). Non-power-of-2 wastes GPU memory because the driver pads them.
371
+
372
+ ## LOD (Level of Detail)
373
+
374
+ For complex scenes, use multiple detail levels:
375
+
376
+ \`\`\`kotlin
377
+ ModelNode(
378
+ modelInstance = when {
379
+ distanceToCamera < 5f -> highDetailInstance
380
+ distanceToCamera < 20f -> medDetailInstance
381
+ else -> lowDetailInstance
382
+ }
383
+ )
384
+ \`\`\`
385
+
386
+ ## Quick Wins
387
+
388
+ 1. **Remove invisible geometry** — interiors users can't see, back faces, underground parts
389
+ 2. **Merge materials** — fewer materials = fewer draw calls = better performance
390
+ 3. **Atlas textures** — combine multiple small textures into one atlas
391
+ 4. **Bake lighting** — for static scenes, bake shadows into the AO map
392
+ 5. **Use instancing** — for repeated objects (trees, buildings), use instanced rendering
393
+
394
+ ## Tools
395
+
396
+ | Tool | Purpose | Link |
397
+ |------|---------|------|
398
+ | **gltf-transform** | CLI optimizer (Draco, KTX2, simplify) | npm install @gltf-transform/cli |
399
+ | **glTF Validator** | Check for errors | github.com/KhronosGroup/glTF-Validator |
400
+ | **gltf.report** | Web-based analyzer | gltf.report |
401
+ | **RapidCompact** | Auto-optimization service | rapidcompact.com |
402
+ | **Blender** | Manual editing + export | blender.org |
403
+ `;
404
+ // ─── Web Rendering Guide ────────────────────────────────────────────────────
405
+ export const WEB_RENDERING_GUIDE = `# SceneView Web Rendering Guide (Filament.js)
406
+
407
+ ## Architecture
408
+
409
+ SceneView Web uses **Filament.js v1.70.1** — Google's Filament engine compiled to WebAssembly. This is the **same PBR rendering engine** as SceneView Android, ensuring visual parity.
410
+
411
+ \`\`\`
412
+ Browser → WebGL2 → Filament.js (WASM) → GPU
413
+ \`\`\`
414
+
415
+ **Bundle size:** ~215KB JS + 3.3MB WASM (~3.5MB total)
416
+
417
+ ## Quick Start
418
+
419
+ ### Using sceneview.js (npm or local)
420
+ \`\`\`html
421
+ <!-- Option 1: npm CDN -->
422
+ <script src="https://unpkg.com/sceneview.js@1.2.0"></script>
423
+
424
+ <!-- Option 2: local hosting (recommended for production) -->
425
+ <!-- Copy js/filament/ directory to your server for faster WASM loading -->
426
+ <script src="js/filament/filament.js"></script>
427
+ <script src="sceneview.js"></script>
428
+
429
+ <canvas id="viewer" style="width:100%;height:400px"></canvas>
430
+ <script>
431
+ // One-liner: creates viewer with KTX IBL, orbit controls, auto-rotate
432
+ sceneview.modelViewer("viewer", "model.glb");
433
+ </script>
434
+ \`\`\`
435
+
436
+ ### Using Kotlin/JS (Gradle)
437
+ \`\`\`kotlin
438
+ SceneView.create(canvas) {
439
+ camera {
440
+ eye(0.0, 1.5, 5.0)
441
+ target(0.0, 0.0, 0.0)
442
+ }
443
+ // IBL environment loaded automatically!
444
+ model("models/helmet.glb")
445
+ autoRotate(true)
446
+ }
447
+ \`\`\`
448
+
449
+ ## IBL Environment Lighting
450
+
451
+ **Critical for PBR quality.** Without IBL, metallic surfaces appear black.
452
+
453
+ SceneView Web loads a **default neutral IBL** automatically (same as Android) using **KTX format** for real PBR reflections. You can override it:
454
+
455
+ \`\`\`kotlin
456
+ SceneView.create(canvas) {
457
+ environment(
458
+ iblUrl = "environments/studio_ibl.ktx",
459
+ skyboxUrl = "environments/studio_skybox.ktx" // optional
460
+ )
461
+ model("model.glb")
462
+ }
463
+ \`\`\`
464
+
465
+ To disable IBL:
466
+ \`\`\`kotlin
467
+ SceneView.create(canvas) {
468
+ noEnvironment()
469
+ light { directional(); intensity(120_000.0) }
470
+ model("model.glb")
471
+ }
472
+ \`\`\`
473
+
474
+ ## Rendering Quality Settings
475
+
476
+ SceneView Web enables these quality features by default:
477
+
478
+ | Feature | Default | Effect |
479
+ |---------|---------|--------|
480
+ | **SSAO** | Enabled | Soft contact shadows between surfaces |
481
+ | **Bloom** | Enabled (subtle) | Glow on bright/emissive surfaces |
482
+ | **TAA** | Enabled | Temporal anti-aliasing for smooth edges |
483
+ | **IBL** | Neutral environment | Physically-correct reflections |
484
+
485
+ ### Custom Quality Settings
486
+
487
+ Access the Filament View directly for advanced tuning:
488
+
489
+ \`\`\`kotlin
490
+ SceneView.create(canvas) { /* ... */ }.let { sv ->
491
+ // Disable SSAO for low-end devices
492
+ sv.view.setAmbientOcclusionOptions(js("({enabled: false})"))
493
+
494
+ // Stronger bloom
495
+ sv.view.setBloomOptions(js("({enabled: true, strength: 0.3, levels: 6})"))
496
+ }
497
+ \`\`\`
498
+
499
+ ## Camera Exposure
500
+
501
+ Camera exposure controls overall brightness. The default is tuned for IBL-lit scenes:
502
+
503
+ | Scenario | Aperture | Shutter | ISO | Look |
504
+ |----------|----------|---------|-----|------|
505
+ | **Studio** (default) | 16.0 | 1/125 | 100 | Balanced, neutral |
506
+ | **Bright outdoor** | 16.0 | 1/250 | 100 | Darker, contrasty |
507
+ | **Indoor/dim** | 2.8 | 1/60 | 800 | Brighter, softer |
508
+ | **Night** | 1.4 | 1/30 | 3200 | Very bright |
509
+
510
+ \`\`\`kotlin
511
+ camera {
512
+ exposure(aperture = 16.0, shutterSpeed = 1.0 / 125.0, sensitivity = 100.0)
513
+ }
514
+ \`\`\`
515
+
516
+ ## Filament.js vs model-viewer
517
+
518
+ | Feature | SceneView (Filament.js) | model-viewer |
519
+ |---------|------------------------|--------------|
520
+ | **Engine** | Filament v1.70.1 WASM | Filament WASM (same engine) |
521
+ | **Bundle size** | ~215KB JS + 3.3MB WASM | ~800 KB (subset) |
522
+ | **Procedural geometry** | Yes (cubes, spheres, etc.) | No |
523
+ | **Custom materials** | Yes (full Filament API) | Limited |
524
+ | **Multi-model scenes** | Yes | No |
525
+ | **AR (WebXR)** | Yes | Yes |
526
+ | **Performance** | Full control | Optimized defaults |
527
+ | **API** | Programmatic (JS/Kotlin) | Web component (\`<model-viewer>\`) |
528
+
529
+ **When to use model-viewer:** Single model viewing with minimal code.
530
+ **When to use SceneView Web:** Complex scenes, procedural content, multi-model, custom materials, or Android visual parity.
531
+
532
+ ## Performance Tips for Web
533
+
534
+ 1. **Lazy-load WASM** — Filament.js is ~3.5MB total (215KB JS + 3.3MB WASM), defer loading until needed
535
+ 2. **Use Draco-compressed GLB** — reduces download time significantly
536
+ 3. **Limit draw calls** — fewer materials = fewer calls = better FPS
537
+ 4. **Canvas size matters** — on mobile, render at \`devicePixelRatio * 0.75\` for 2x FPS
538
+ 5. **Dispose when hidden** — call \`sceneView.destroy()\` when the viewer is off-screen
539
+ `;