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.
package/dist/validator.js CHANGED
@@ -322,6 +322,103 @@ const RULES = [
322
322
  return issues;
323
323
  },
324
324
  },
325
+ // ─── Multiple Engine instances ───────────────────────────────────────────
326
+ {
327
+ id: "performance/multiple-engines",
328
+ severity: "warning",
329
+ check(code, lines) {
330
+ const issues = [];
331
+ const engineCreations = findLines(lines, /rememberEngine\(\)|Engine\.create\(/);
332
+ if (engineCreations.length > 1) {
333
+ engineCreations.slice(1).forEach((line) => issues.push({
334
+ severity: "warning",
335
+ rule: "performance/multiple-engines",
336
+ message: "Multiple Engine instances detected. Each Engine allocates significant GPU memory. Use a single `rememberEngine()` at the top level and pass it to all Scene composables.",
337
+ line,
338
+ }));
339
+ }
340
+ return issues;
341
+ },
342
+ },
343
+ // ─── Model loaded in LaunchedEffect with wrong dispatcher ──────────────
344
+ {
345
+ id: "threading/model-in-launched-effect",
346
+ severity: "error",
347
+ check(code, lines) {
348
+ const issues = [];
349
+ // Detect modelLoader calls inside LaunchedEffect — should use rememberModelInstance instead
350
+ if (/LaunchedEffect/.test(code) && /modelLoader\.(createModel|loadModel)/.test(code)) {
351
+ findLines(lines, /modelLoader\.(createModel|loadModel)/).forEach((line) => issues.push({
352
+ severity: "error",
353
+ rule: "threading/model-in-launched-effect",
354
+ message: "Model loading inside `LaunchedEffect` is risky — if the coroutine runs on a background dispatcher, Filament will crash. Use `rememberModelInstance(modelLoader, path)` instead, which handles threading and lifecycle automatically.",
355
+ line,
356
+ }));
357
+ }
358
+ return issues;
359
+ },
360
+ },
361
+ // ─── rememberModelInstance without modelLoader ────────────────────────────
362
+ {
363
+ id: "api/remember-model-missing-loader",
364
+ severity: "error",
365
+ check(code, lines) {
366
+ const issues = [];
367
+ if (code.includes("rememberModelInstance") && !code.includes("modelLoader") && !code.includes("rememberModelLoader")) {
368
+ findLines(lines, /rememberModelInstance\(/).forEach((line) => issues.push({
369
+ severity: "error",
370
+ rule: "api/remember-model-missing-loader",
371
+ message: "`rememberModelInstance` requires a `ModelLoader`. Add `val modelLoader = rememberModelLoader(engine)` and pass it as the first parameter.",
372
+ line,
373
+ }));
374
+ }
375
+ return issues;
376
+ },
377
+ },
378
+ // ─── GLB path with leading slash ────────────────────────────────────────
379
+ {
380
+ id: "api/asset-path-leading-slash",
381
+ severity: "warning",
382
+ check(code, lines) {
383
+ const issues = [];
384
+ // Matches rememberModelInstance or loadModel with "/models/..." (leading slash)
385
+ const patterns = [
386
+ /rememberModelInstance\s*\([^,]+,\s*"\/[^"]+"/,
387
+ /loadModel\w*\s*\(\s*"\/[^"]+"/,
388
+ /createHDREnvironment\s*\(\s*"\/[^"]+"/,
389
+ ];
390
+ for (const pat of patterns) {
391
+ findLines(lines, pat).forEach((line) => issues.push({
392
+ severity: "warning",
393
+ rule: "api/asset-path-leading-slash",
394
+ message: "Asset path starts with `/`. Android asset paths are relative to `src/main/assets/` — use `\"models/file.glb\"` without a leading slash.",
395
+ line,
396
+ }));
397
+ }
398
+ return issues;
399
+ },
400
+ },
401
+ // ─── Scene missing Modifier.fillMaxSize ─────────────────────────────────
402
+ {
403
+ id: "api/scene-zero-size",
404
+ severity: "info",
405
+ check(code, lines) {
406
+ const issues = [];
407
+ const sceneLines = findLines(lines, /\b(AR)?Scene\s*\(/);
408
+ sceneLines.forEach((line) => {
409
+ const block = lines.slice(line - 1, line + 5).join("\n");
410
+ if (!block.includes("fillMaxSize") && !block.includes("size") && !block.includes("height") && !block.includes("width")) {
411
+ issues.push({
412
+ severity: "info",
413
+ rule: "api/scene-zero-size",
414
+ message: "`Scene` / `ARScene` may have zero size without a `Modifier`. Add `modifier = Modifier.fillMaxSize()` to ensure the 3D view is visible.",
415
+ line,
416
+ });
417
+ }
418
+ });
419
+ return issues;
420
+ },
421
+ },
325
422
  // ─── Scene missing engine param ───────────────────────────────────────────
326
423
  {
327
424
  id: "api/scene-missing-engine",
@@ -500,7 +597,7 @@ function detectLanguage(code) {
500
597
  if (code.includes("import SwiftUI") ||
501
598
  code.includes("import RealityKit") ||
502
599
  code.includes("import SceneViewSwift") ||
503
- code.includes("struct ") && code.includes(": View") ||
600
+ (code.includes("struct ") && code.includes(": View")) ||
504
601
  code.includes("@State private var") ||
505
602
  /SceneView\s*\{.*\bin\b/.test(code)) {
506
603
  return "swift";