sceneview-mcp 3.4.12 → 3.4.13
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.
- package/dist/debug-issue.js +551 -0
- package/dist/generate-scene.js +325 -0
- package/dist/index.js +133 -1
- package/dist/migrate-code.js +203 -0
- package/dist/platform-setup.js +787 -0
- package/package.json +8 -1
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* debug-issue.ts
|
|
3
|
+
*
|
|
4
|
+
* Targeted debugging guide for common SceneView issues.
|
|
5
|
+
* Given a symptom, returns a focused diagnostic checklist.
|
|
6
|
+
*/
|
|
7
|
+
export const DEBUG_CATEGORIES = [
|
|
8
|
+
"model-not-showing",
|
|
9
|
+
"ar-not-working",
|
|
10
|
+
"crash",
|
|
11
|
+
"performance",
|
|
12
|
+
"build-error",
|
|
13
|
+
"black-screen",
|
|
14
|
+
"lighting",
|
|
15
|
+
"gestures",
|
|
16
|
+
"ios",
|
|
17
|
+
];
|
|
18
|
+
const DEBUG_GUIDES = {
|
|
19
|
+
"model-not-showing": {
|
|
20
|
+
title: "Model Not Showing / Invisible",
|
|
21
|
+
guide: `## Debugging: Model Not Showing
|
|
22
|
+
|
|
23
|
+
### Quick Diagnostic Checklist
|
|
24
|
+
|
|
25
|
+
1. **Is \`rememberModelInstance\` returning null?**
|
|
26
|
+
- It returns \`null\` while loading AND if the file fails to load.
|
|
27
|
+
- Add a log: \`Log.d("SV", "model: \$modelInstance")\`
|
|
28
|
+
- Show a loading indicator while null.
|
|
29
|
+
|
|
30
|
+
2. **Is the asset path correct?**
|
|
31
|
+
- Assets must be in \`src/main/assets/\` (not \`res/\`)
|
|
32
|
+
- Path is relative to assets root: \`"models/chair.glb"\` (no leading slash)
|
|
33
|
+
- Check file extension: \`.glb\` or \`.gltf\` (case-sensitive on Android)
|
|
34
|
+
|
|
35
|
+
3. **Is there a light in the scene?**
|
|
36
|
+
- Without light, PBR models appear black (not invisible — but very dark).
|
|
37
|
+
- Add a directional light:
|
|
38
|
+
\`\`\`kotlin
|
|
39
|
+
LightNode(
|
|
40
|
+
engine = engine,
|
|
41
|
+
type = LightManager.Type.DIRECTIONAL,
|
|
42
|
+
apply = {
|
|
43
|
+
intensity(100_000f)
|
|
44
|
+
castShadows(true)
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
\`\`\`
|
|
48
|
+
- Or load an HDR environment for IBL.
|
|
49
|
+
|
|
50
|
+
4. **Is the model too small or too large?**
|
|
51
|
+
- Default scale = 1.0 in model units. Some models are in millimeters (1000x too small) or centimeters (10x).
|
|
52
|
+
- Try \`scaleToUnits = 1.0f\` to normalize.
|
|
53
|
+
- Check in a 3D editor (Blender) what units the model uses.
|
|
54
|
+
|
|
55
|
+
5. **Is the camera pointing at the model?**
|
|
56
|
+
- Default camera is at origin looking -Z.
|
|
57
|
+
- Model at (0, 0, 0) may be inside or behind the camera.
|
|
58
|
+
- Try \`centerOrigin = Position(0f, 0f, 0f)\` on ModelNode.
|
|
59
|
+
- Or move camera: \`cameraNode = rememberCameraNode(engine) { lookAt(Position(0f, 1f, 3f), Position(0f, 0f, 0f)) }\`
|
|
60
|
+
|
|
61
|
+
6. **Is the Scene composable actually visible?**
|
|
62
|
+
- Check Modifier: \`Modifier.fillMaxSize()\` — not \`Modifier.size(0.dp)\` or hidden behind another composable.
|
|
63
|
+
|
|
64
|
+
7. **Is the GLB file valid?**
|
|
65
|
+
- Test in https://gltf-viewer.donmccurdy.com/
|
|
66
|
+
- Corrupt or incompatible GLB files silently fail to load.
|
|
67
|
+
|
|
68
|
+
### Common Fixes
|
|
69
|
+
|
|
70
|
+
\`\`\`kotlin
|
|
71
|
+
// Minimal working example — if this shows the model, the issue is in your code
|
|
72
|
+
@Composable
|
|
73
|
+
fun DebugModelViewer() {
|
|
74
|
+
val engine = rememberEngine()
|
|
75
|
+
val modelLoader = rememberModelLoader(engine)
|
|
76
|
+
|
|
77
|
+
val modelInstance = rememberModelInstance(modelLoader, "models/YOUR_FILE.glb")
|
|
78
|
+
Log.d("SceneView", "Model loaded: \${modelInstance != null}")
|
|
79
|
+
|
|
80
|
+
Scene(
|
|
81
|
+
modifier = Modifier.fillMaxSize(),
|
|
82
|
+
engine = engine,
|
|
83
|
+
modelLoader = modelLoader
|
|
84
|
+
) {
|
|
85
|
+
// Light is essential!
|
|
86
|
+
LightNode(
|
|
87
|
+
engine = engine,
|
|
88
|
+
type = LightManager.Type.DIRECTIONAL,
|
|
89
|
+
apply = { intensity(100_000f) }
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
modelInstance?.let { instance ->
|
|
93
|
+
ModelNode(
|
|
94
|
+
modelInstance = instance,
|
|
95
|
+
scaleToUnits = 1.0f,
|
|
96
|
+
centerOrigin = Position(0f, 0f, 0f)
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
\`\`\``,
|
|
102
|
+
},
|
|
103
|
+
"ar-not-working": {
|
|
104
|
+
title: "AR Not Working",
|
|
105
|
+
guide: `## Debugging: AR Not Working
|
|
106
|
+
|
|
107
|
+
### Quick Diagnostic Checklist
|
|
108
|
+
|
|
109
|
+
1. **Camera permission granted?**
|
|
110
|
+
- AR requires \`CAMERA\` permission at runtime (not just manifest).
|
|
111
|
+
- Request it BEFORE showing ARScene:
|
|
112
|
+
\`\`\`kotlin
|
|
113
|
+
val launcher = rememberLauncherForActivityResult(
|
|
114
|
+
ActivityResultContracts.RequestPermission()
|
|
115
|
+
) { granted -> showAR = granted }
|
|
116
|
+
LaunchedEffect(Unit) { launcher.launch(Manifest.permission.CAMERA) }
|
|
117
|
+
\`\`\`
|
|
118
|
+
|
|
119
|
+
2. **ARCore installed?**
|
|
120
|
+
- Check: \`ArCoreApk.getInstance().checkAvailability(context)\`
|
|
121
|
+
- Emulators need Google Play Services for AR manually installed.
|
|
122
|
+
- Real devices auto-install if manifest has \`com.google.ar.core\` meta-data.
|
|
123
|
+
|
|
124
|
+
3. **Manifest correct?**
|
|
125
|
+
\`\`\`xml
|
|
126
|
+
<uses-permission android:name="android.permission.CAMERA" />
|
|
127
|
+
<uses-feature android:name="android.hardware.camera.ar" android:required="true" />
|
|
128
|
+
<application>
|
|
129
|
+
<meta-data android:name="com.google.ar.core" android:value="required" />
|
|
130
|
+
</application>
|
|
131
|
+
\`\`\`
|
|
132
|
+
|
|
133
|
+
4. **Planes not detecting?**
|
|
134
|
+
- Point at a **textured surface** (not plain white walls).
|
|
135
|
+
- Wait 2-3 seconds for ARCore to initialize.
|
|
136
|
+
- Check \`planeFindingMode\` is not \`DISABLED\`.
|
|
137
|
+
- Ensure good lighting — ARCore struggles in dim conditions.
|
|
138
|
+
|
|
139
|
+
5. **Objects not appearing on tap?**
|
|
140
|
+
- Is \`onTouchEvent\` wired up?
|
|
141
|
+
- Is \`hitResult\` null? Log it: \`Log.d("AR", "hitResult: \$hitResult")\`
|
|
142
|
+
- Are you creating an anchor? \`hitResult.createAnchor()\` must be called.
|
|
143
|
+
- Is the model loaded? Check \`rememberModelInstance\` is not null.
|
|
144
|
+
|
|
145
|
+
6. **Anchor drift / objects moving?**
|
|
146
|
+
- ALWAYS use \`AnchorNode(anchor = ...)\` — never set \`worldPosition\` manually.
|
|
147
|
+
- ARCore's coordinate system shifts during tracking; anchors compensate.
|
|
148
|
+
|
|
149
|
+
7. **Testing on emulator?**
|
|
150
|
+
- ARCore emulator support is limited. Test on a real device.
|
|
151
|
+
- If using emulator: Extended Controls > Virtual Sensors > enable AR.
|
|
152
|
+
|
|
153
|
+
### Common AR Crash Causes
|
|
154
|
+
|
|
155
|
+
| Symptom | Cause | Fix |
|
|
156
|
+
|---------|-------|-----|
|
|
157
|
+
| Crash on ARScene open | No camera permission | Request at runtime |
|
|
158
|
+
| "ARCore not installed" | Missing Play Services | Add manifest meta-data |
|
|
159
|
+
| Session create fails | Device not supported | Check \`checkAvailability()\` |
|
|
160
|
+
| Black camera feed | Permission denied | Check runtime permission result |`,
|
|
161
|
+
},
|
|
162
|
+
crash: {
|
|
163
|
+
title: "Crash / SIGABRT / Native Error",
|
|
164
|
+
guide: `## Debugging: Crashes
|
|
165
|
+
|
|
166
|
+
### SIGABRT / Native Crash
|
|
167
|
+
|
|
168
|
+
**Most common cause:** Filament resource lifecycle violation.
|
|
169
|
+
|
|
170
|
+
#### 1. Wrong thread
|
|
171
|
+
- ALL Filament JNI calls must be on the **main thread**.
|
|
172
|
+
- Check for \`Dispatchers.IO\` or \`Dispatchers.Default\` near Filament calls.
|
|
173
|
+
- Fix: wrap in \`withContext(Dispatchers.Main) { ... }\`
|
|
174
|
+
|
|
175
|
+
#### 2. Wrong destroy order
|
|
176
|
+
- Materials MUST be destroyed before Textures.
|
|
177
|
+
- Textures MUST be destroyed before Engine.
|
|
178
|
+
- \`rememberEngine()\` handles this automatically — avoid manual destroy.
|
|
179
|
+
- If imperative: \`materialLoader.destroyMaterialInstance(mi)\` then \`engine.safeDestroyTexture(tex)\`
|
|
180
|
+
|
|
181
|
+
#### 3. Double destroy
|
|
182
|
+
- Calling \`engine.destroy()\` alongside \`rememberEngine()\` → SIGABRT.
|
|
183
|
+
- \`rememberEngine()\` destroys on composition disposal — remove manual calls.
|
|
184
|
+
- Same for nodes: don't call \`node.destroy()\` on composable nodes.
|
|
185
|
+
|
|
186
|
+
#### 4. Accessing destroyed resources
|
|
187
|
+
- If a composable leaves the tree, its nodes are destroyed.
|
|
188
|
+
- Accessing a node/model after removal → native crash.
|
|
189
|
+
- Fix: null-check before access, use Compose state properly.
|
|
190
|
+
|
|
191
|
+
### NullPointerException
|
|
192
|
+
|
|
193
|
+
- \`rememberModelInstance\` returns null while loading — always null-check.
|
|
194
|
+
- \`hitResult\` can be null in \`onTouchEvent\` if no surface is hit.
|
|
195
|
+
|
|
196
|
+
### Out of Memory
|
|
197
|
+
|
|
198
|
+
- Multiple \`Engine\` instances waste GPU memory → use single \`rememberEngine()\`.
|
|
199
|
+
- Large models (>100K triangles) on old devices → reduce poly count.
|
|
200
|
+
- Multiple 4K HDR environments → use 2K or smaller.
|
|
201
|
+
|
|
202
|
+
### Diagnostic Steps
|
|
203
|
+
|
|
204
|
+
1. Enable Filament debug logging:
|
|
205
|
+
\`\`\`kotlin
|
|
206
|
+
// In Application.onCreate()
|
|
207
|
+
System.setProperty("filament.backend.debug", "true")
|
|
208
|
+
\`\`\`
|
|
209
|
+
|
|
210
|
+
2. Check logcat for Filament errors:
|
|
211
|
+
\`\`\`
|
|
212
|
+
adb logcat -s Filament
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
3. Run with Android Studio memory profiler to detect leaks.`,
|
|
216
|
+
},
|
|
217
|
+
performance: {
|
|
218
|
+
title: "Performance Problems",
|
|
219
|
+
guide: `## Debugging: Performance
|
|
220
|
+
|
|
221
|
+
### Measuring Performance
|
|
222
|
+
|
|
223
|
+
1. **Enable FPS overlay:**
|
|
224
|
+
\`\`\`kotlin
|
|
225
|
+
Scene(
|
|
226
|
+
engine = engine,
|
|
227
|
+
// Check frame time in onFrame callback
|
|
228
|
+
onFrame = { frameTimeNanos ->
|
|
229
|
+
val fps = 1_000_000_000.0 / frameTimeNanos
|
|
230
|
+
Log.d("FPS", "%.1f".format(fps))
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
\`\`\`
|
|
234
|
+
|
|
235
|
+
2. **Android GPU Inspector** — shows exactly where GPU time goes.
|
|
236
|
+
3. **Android Studio Profiler** — CPU and memory usage.
|
|
237
|
+
|
|
238
|
+
### Common Performance Issues
|
|
239
|
+
|
|
240
|
+
#### Low FPS (<30)
|
|
241
|
+
|
|
242
|
+
| Cause | Fix |
|
|
243
|
+
|-------|-----|
|
|
244
|
+
| High poly model (>100K tris) | Reduce in Blender, use Draco/Meshopt compression |
|
|
245
|
+
| Uncompressed textures | Use KTX2 with Basis Universal, max 1024x1024 |
|
|
246
|
+
| Too many draw calls | Merge meshes in 3D editor (1 material = 1 draw call) |
|
|
247
|
+
| Per-frame allocations | Reuse objects in \`onFrame\`, avoid creating Position/Rotation each frame |
|
|
248
|
+
| Multiple engines | Use single \`rememberEngine()\`, never create multiple |
|
|
249
|
+
| Post-processing enabled | Disable if not needed: \`Scene(postProcessing = false)\` |
|
|
250
|
+
| Shadow-casting lights | Each shadow light = extra depth pass. Limit to 1-2. |
|
|
251
|
+
|
|
252
|
+
#### High Memory (>500MB)
|
|
253
|
+
|
|
254
|
+
| Cause | Fix |
|
|
255
|
+
|-------|-----|
|
|
256
|
+
| 4K HDR environments | Use 2K (\`sky_2k.hdr\`) |
|
|
257
|
+
| Multiple scenes | Each \`Scene\` = separate Filament View + Renderer |
|
|
258
|
+
| Unreleased models | Let unused models leave composition (auto-cleanup) |
|
|
259
|
+
| Bitmap texture leaks | Recycle bitmaps after Filament consumes them |
|
|
260
|
+
| Concurrent model loads | Max 3-4 simultaneous \`rememberModelInstance\` calls |
|
|
261
|
+
|
|
262
|
+
#### Model Optimization Checklist
|
|
263
|
+
|
|
264
|
+
- [ ] GLB format (not glTF multi-file)
|
|
265
|
+
- [ ] <100K triangles per model
|
|
266
|
+
- [ ] Textures <=1024x1024
|
|
267
|
+
- [ ] KTX2 compressed textures (Basis Universal)
|
|
268
|
+
- [ ] Draco or Meshopt mesh compression
|
|
269
|
+
- [ ] Single material per mesh where possible
|
|
270
|
+
- [ ] Remove unused animations / morph targets`,
|
|
271
|
+
},
|
|
272
|
+
"build-error": {
|
|
273
|
+
title: "Build / Gradle Errors",
|
|
274
|
+
guide: `## Debugging: Build Errors
|
|
275
|
+
|
|
276
|
+
### "Cannot resolve io.github.sceneview:sceneview:3.3.0"
|
|
277
|
+
|
|
278
|
+
1. Check repositories in \`settings.gradle.kts\`:
|
|
279
|
+
\`\`\`kotlin
|
|
280
|
+
dependencyResolutionManagement {
|
|
281
|
+
repositories {
|
|
282
|
+
google()
|
|
283
|
+
mavenCentral()
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
\`\`\`
|
|
287
|
+
2. Check internet connectivity and proxy settings.
|
|
288
|
+
3. Try: \`./gradlew --refresh-dependencies\`
|
|
289
|
+
|
|
290
|
+
### Java Version Mismatch
|
|
291
|
+
|
|
292
|
+
SceneView requires **Java 17**.
|
|
293
|
+
\`\`\`kotlin
|
|
294
|
+
android {
|
|
295
|
+
compileOptions {
|
|
296
|
+
sourceCompatibility = JavaVersion.VERSION_17
|
|
297
|
+
targetCompatibility = JavaVersion.VERSION_17
|
|
298
|
+
}
|
|
299
|
+
kotlinOptions {
|
|
300
|
+
jvmTarget = "17"
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
\`\`\`
|
|
304
|
+
|
|
305
|
+
### AGP / Gradle Version Compatibility
|
|
306
|
+
|
|
307
|
+
| AGP | Gradle | Status |
|
|
308
|
+
|-----|--------|--------|
|
|
309
|
+
| 8.7+ | 8.11.1+ | Recommended |
|
|
310
|
+
| 8.4-8.6 | 8.6-8.10 | Works |
|
|
311
|
+
| <8.4 | <8.6 | May have issues |
|
|
312
|
+
|
|
313
|
+
### "Duplicate class" Errors
|
|
314
|
+
|
|
315
|
+
SceneView bundles Filament. If you also depend on Filament directly:
|
|
316
|
+
\`\`\`kotlin
|
|
317
|
+
// Remove direct Filament dependency — SceneView includes it
|
|
318
|
+
// implementation("com.google.android.filament:filament-android:1.x.x") // REMOVE
|
|
319
|
+
implementation("io.github.sceneview:sceneview:3.3.0") // This includes Filament
|
|
320
|
+
\`\`\`
|
|
321
|
+
|
|
322
|
+
### "Cannot find Filament material"
|
|
323
|
+
|
|
324
|
+
- Pre-compiled materials live in \`src/main/assets/materials/\`
|
|
325
|
+
- Don't delete them when cleaning
|
|
326
|
+
- If \`filamentPluginEnabled=true\` in gradle.properties, you need Filament desktop tools
|
|
327
|
+
|
|
328
|
+
### Gradle Clean
|
|
329
|
+
|
|
330
|
+
\`\`\`bash
|
|
331
|
+
./gradlew clean
|
|
332
|
+
rm -rf ~/.gradle/caches
|
|
333
|
+
rm -rf .gradle
|
|
334
|
+
./gradlew --refresh-dependencies
|
|
335
|
+
\`\`\``,
|
|
336
|
+
},
|
|
337
|
+
"black-screen": {
|
|
338
|
+
title: "Black Screen / No Rendering",
|
|
339
|
+
guide: `## Debugging: Black Screen
|
|
340
|
+
|
|
341
|
+
### AR Black Screen
|
|
342
|
+
|
|
343
|
+
1. **Camera permission not granted** — most common cause.
|
|
344
|
+
- Check logcat for permission denial.
|
|
345
|
+
- Request permission before showing ARScene.
|
|
346
|
+
|
|
347
|
+
2. **ARCore not initialized** — takes 1-2 seconds.
|
|
348
|
+
- Show a loading overlay until first frame.
|
|
349
|
+
|
|
350
|
+
3. **Device camera in use** — another app or the system camera is using it.
|
|
351
|
+
- Close other camera apps.
|
|
352
|
+
|
|
353
|
+
### 3D Black Screen
|
|
354
|
+
|
|
355
|
+
1. **No light source** — PBR models need light to be visible.
|
|
356
|
+
- Add \`LightNode\` or HDR environment.
|
|
357
|
+
|
|
358
|
+
2. **Camera inside model** — default camera at origin, model also at origin.
|
|
359
|
+
- Set camera position: \`cameraNode = rememberCameraNode(engine) { lookAt(...) }\`
|
|
360
|
+
- Or set \`centerOrigin\` on ModelNode.
|
|
361
|
+
|
|
362
|
+
3. **Environment not loaded** — HDR file path wrong or file missing.
|
|
363
|
+
- Check logcat for "Environment not found" messages.
|
|
364
|
+
- Test without environment first.
|
|
365
|
+
|
|
366
|
+
4. **Scene composable has zero size** — \`Modifier.fillMaxSize()\` missing.
|
|
367
|
+
|
|
368
|
+
5. **OpenGL ES version** — Filament requires OpenGL ES 3.0+.
|
|
369
|
+
- Check: \`GLES30.glGetString(GLES30.GL_VERSION)\`
|
|
370
|
+
- Very old devices (<2015) may not support it.
|
|
371
|
+
|
|
372
|
+
### Diagnostic Code
|
|
373
|
+
|
|
374
|
+
\`\`\`kotlin
|
|
375
|
+
Scene(
|
|
376
|
+
modifier = Modifier
|
|
377
|
+
.fillMaxSize()
|
|
378
|
+
.background(Color.Red), // Should see red if Scene has zero size
|
|
379
|
+
engine = engine,
|
|
380
|
+
onFrame = { Log.d("SV", "Frame rendered") } // If not logged, Scene isn't rendering
|
|
381
|
+
) {
|
|
382
|
+
// Minimal visible content
|
|
383
|
+
CubeNode(engine = engine, size = 1.0f)
|
|
384
|
+
LightNode(engine = engine, type = LightManager.Type.DIRECTIONAL, apply = { intensity(100_000f) })
|
|
385
|
+
}
|
|
386
|
+
\`\`\``,
|
|
387
|
+
},
|
|
388
|
+
lighting: {
|
|
389
|
+
title: "Lighting Issues",
|
|
390
|
+
guide: `## Debugging: Lighting Issues
|
|
391
|
+
|
|
392
|
+
### Model Too Dark / Black
|
|
393
|
+
|
|
394
|
+
- **No light source** — add a directional light or HDR environment.
|
|
395
|
+
- **Intensity too low** — directional lights typically need 100,000+ lux.
|
|
396
|
+
- **Wrong light type** — \`POINT\` lights need to be near the model; \`DIRECTIONAL\` lights work everywhere.
|
|
397
|
+
|
|
398
|
+
### Model Too Bright / Overexposed in AR
|
|
399
|
+
|
|
400
|
+
- **Tone mapping** — AR scenes use the camera feed; default tone mapping enhances contrast.
|
|
401
|
+
- Fix: set linear tone mapping on the AR view.
|
|
402
|
+
- **Double lighting** — if you add lights AND use \`ENVIRONMENTAL_HDR\`, the model gets double-lit.
|
|
403
|
+
- Fix: use one lighting method, not both.
|
|
404
|
+
|
|
405
|
+
### Flat / No Shadows
|
|
406
|
+
|
|
407
|
+
- Shadows disabled by default in \`Scene\` (enabled in \`ARScene\`).
|
|
408
|
+
- Enable: \`Scene(view = rememberView(engine).also { it.setShadowingEnabled(true) })\`
|
|
409
|
+
- Light must have \`castShadows(true)\` in its \`apply\` block.
|
|
410
|
+
|
|
411
|
+
### Environment / IBL Not Working
|
|
412
|
+
|
|
413
|
+
\`\`\`kotlin
|
|
414
|
+
val environmentLoader = rememberEnvironmentLoader(engine)
|
|
415
|
+
Scene(
|
|
416
|
+
environment = rememberEnvironment(environmentLoader) {
|
|
417
|
+
environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
|
|
418
|
+
?: createEnvironment(environmentLoader)
|
|
419
|
+
}
|
|
420
|
+
) { ... }
|
|
421
|
+
\`\`\`
|
|
422
|
+
- Check HDR file exists in \`src/main/assets/environments/\`.
|
|
423
|
+
- Use 2K HDR files (not 4K — wastes memory on mobile).`,
|
|
424
|
+
},
|
|
425
|
+
gestures: {
|
|
426
|
+
title: "Gesture / Interaction Issues",
|
|
427
|
+
guide: `## Debugging: Gesture Issues
|
|
428
|
+
|
|
429
|
+
### Model Not Responding to Touch
|
|
430
|
+
|
|
431
|
+
1. **\`isEditable\` not set:**
|
|
432
|
+
\`\`\`kotlin
|
|
433
|
+
ModelNode(
|
|
434
|
+
modelInstance = instance,
|
|
435
|
+
isEditable = true // Enables pinch-to-scale + drag-to-rotate
|
|
436
|
+
)
|
|
437
|
+
\`\`\`
|
|
438
|
+
|
|
439
|
+
2. **\`onTouchEvent\` consuming events:**
|
|
440
|
+
- If \`onTouchEvent\` returns \`true\`, it consumes the event before nodes see it.
|
|
441
|
+
- Return \`false\` for events you don't handle.
|
|
442
|
+
|
|
443
|
+
3. **Node has no collision shape:**
|
|
444
|
+
- By default, ModelNode uses its bounding box for hit testing.
|
|
445
|
+
- Geometry nodes (CubeNode, SphereNode) have built-in collision.
|
|
446
|
+
|
|
447
|
+
### Tap-to-Place Not Working in AR
|
|
448
|
+
|
|
449
|
+
1. Check \`hitResult\` is not null — log it.
|
|
450
|
+
2. Ensure plane detection is enabled: \`planeFindingMode = HORIZONTAL_AND_VERTICAL\`.
|
|
451
|
+
3. Plane renderer helps user see where planes are: \`planeRenderer = true\`.
|
|
452
|
+
4. Create anchor from hit: \`hitResult.createAnchor()\`.
|
|
453
|
+
|
|
454
|
+
### Camera Orbit Not Working
|
|
455
|
+
|
|
456
|
+
- Default Scene has orbit camera. If overridden:
|
|
457
|
+
\`\`\`kotlin
|
|
458
|
+
Scene(
|
|
459
|
+
cameraManipulator = rememberCameraManipulator() // Enables orbit
|
|
460
|
+
)
|
|
461
|
+
\`\`\`
|
|
462
|
+
- In AR, camera is controlled by ARCore — orbit is disabled.`,
|
|
463
|
+
},
|
|
464
|
+
ios: {
|
|
465
|
+
title: "iOS / SceneViewSwift Issues",
|
|
466
|
+
guide: `## Debugging: iOS Issues
|
|
467
|
+
|
|
468
|
+
### Model Not Loading
|
|
469
|
+
|
|
470
|
+
1. **Wrong format** — RealityKit uses USDZ or .reality, NOT GLB/glTF.
|
|
471
|
+
2. **Missing \`try await\`** — \`ModelNode.load()\` is \`async throws\`:
|
|
472
|
+
\`\`\`swift
|
|
473
|
+
.task {
|
|
474
|
+
do {
|
|
475
|
+
model = try await ModelNode.load("models/car.usdz")
|
|
476
|
+
} catch {
|
|
477
|
+
print("Load failed: \\(error)")
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
\`\`\`
|
|
481
|
+
3. **File not in bundle** — check Xcode: target > Build Phases > Copy Bundle Resources.
|
|
482
|
+
4. **Using \`addChild(model)\` instead of \`addChild(model.entity)\`** — node wrappers aren't Entity subclasses.
|
|
483
|
+
|
|
484
|
+
### AR Camera Black Screen (iOS)
|
|
485
|
+
|
|
486
|
+
- **Missing Info.plist entry:**
|
|
487
|
+
\`\`\`xml
|
|
488
|
+
<key>NSCameraUsageDescription</key>
|
|
489
|
+
<string>Camera needed for AR</string>
|
|
490
|
+
\`\`\`
|
|
491
|
+
- **Simulator** — ARKit doesn't work on simulators. Use a real device.
|
|
492
|
+
- **Device unsupported** — check \`ARWorldTrackingConfiguration.isSupported\`.
|
|
493
|
+
|
|
494
|
+
### ARSceneView Crash on macOS / visionOS
|
|
495
|
+
|
|
496
|
+
- \`ARSceneView\` uses \`ARView\` which is iOS-only.
|
|
497
|
+
- macOS: use \`SceneView\` (3D only).
|
|
498
|
+
- visionOS: use \`RealityView\` with \`ARKitSession\` directly.
|
|
499
|
+
|
|
500
|
+
### SPM Package Resolution Fails
|
|
501
|
+
|
|
502
|
+
- Require Xcode 15.0+ (iOS 17 / visionOS targets).
|
|
503
|
+
- Clean: Xcode > Product > Clean Build Folder.
|
|
504
|
+
- Reset packages: File > Packages > Reset Package Caches.
|
|
505
|
+
- URL must be exactly: \`https://github.com/SceneView/sceneview\`
|
|
506
|
+
|
|
507
|
+
### Swift Concurrency Warnings
|
|
508
|
+
|
|
509
|
+
- RealityKit entities are main-actor-bound.
|
|
510
|
+
- Always load models in \`.task { }\` (inherits @MainActor) or annotate functions with \`@MainActor\`.
|
|
511
|
+
- SceneViewSwift nodes are \`@unchecked Sendable\` — the warning is expected.`,
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
export function getDebugGuide(category) {
|
|
515
|
+
const entry = DEBUG_GUIDES[category];
|
|
516
|
+
if (!entry) {
|
|
517
|
+
return `Unknown debug category "${category}". Available: ${DEBUG_CATEGORIES.join(", ")}`;
|
|
518
|
+
}
|
|
519
|
+
return `# ${entry.title}\n\n${entry.guide}`;
|
|
520
|
+
}
|
|
521
|
+
export function autoDetectIssue(description) {
|
|
522
|
+
const lower = description.toLowerCase();
|
|
523
|
+
if (lower.includes("not showing") || lower.includes("invisible") || lower.includes("can't see") || lower.includes("model doesn't appear")) {
|
|
524
|
+
return "model-not-showing";
|
|
525
|
+
}
|
|
526
|
+
if (lower.includes("ar not") || lower.includes("ar doesn't") || lower.includes("arcore") || lower.includes("plane") || lower.includes("anchor")) {
|
|
527
|
+
return "ar-not-working";
|
|
528
|
+
}
|
|
529
|
+
if (lower.includes("crash") || lower.includes("sigabrt") || lower.includes("native") || lower.includes("fatal") || lower.includes("exception")) {
|
|
530
|
+
return "crash";
|
|
531
|
+
}
|
|
532
|
+
if (lower.includes("slow") || lower.includes("fps") || lower.includes("lag") || lower.includes("jank") || lower.includes("performance") || lower.includes("memory")) {
|
|
533
|
+
return "performance";
|
|
534
|
+
}
|
|
535
|
+
if (lower.includes("build") || lower.includes("gradle") || lower.includes("compile") || lower.includes("dependency") || lower.includes("cannot resolve")) {
|
|
536
|
+
return "build-error";
|
|
537
|
+
}
|
|
538
|
+
if (lower.includes("black screen") || lower.includes("blank") || lower.includes("nothing renders")) {
|
|
539
|
+
return "black-screen";
|
|
540
|
+
}
|
|
541
|
+
if (lower.includes("dark") || lower.includes("bright") || lower.includes("light") || lower.includes("shadow") || lower.includes("overexposed")) {
|
|
542
|
+
return "lighting";
|
|
543
|
+
}
|
|
544
|
+
if (lower.includes("touch") || lower.includes("gesture") || lower.includes("tap") || lower.includes("drag") || lower.includes("rotate") || lower.includes("interact")) {
|
|
545
|
+
return "gestures";
|
|
546
|
+
}
|
|
547
|
+
if (lower.includes("ios") || lower.includes("swift") || lower.includes("xcode") || lower.includes("spm") || lower.includes("realitykit") || lower.includes("usdz")) {
|
|
548
|
+
return "ios";
|
|
549
|
+
}
|
|
550
|
+
return null;
|
|
551
|
+
}
|