sceneview-mcp 3.6.2 → 3.6.4

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/migration.js CHANGED
@@ -8,8 +8,8 @@ SceneView 3.0 is a full rewrite from Android Views to **Jetpack Compose**. Nearl
8
8
 
9
9
  | 2.x | 3.0 |
10
10
  |-----|-----|
11
- | \`io.github.sceneview:sceneview:2.x.x\` | \`io.github.sceneview:sceneview:3.6.0\` |
12
- | \`io.github.sceneview:arsceneview:2.x.x\` | \`io.github.sceneview:arsceneview:3.6.0\` |
11
+ | \`io.github.sceneview:sceneview:2.x.x\` | \`io.github.sceneview:sceneview:3.6.2\` |
12
+ | \`io.github.sceneview:arsceneview:2.x.x\` | \`io.github.sceneview:arsceneview:3.6.2\` |
13
13
 
14
14
  ---
15
15
 
@@ -0,0 +1,173 @@
1
+ /**
2
+ * optimize-scene.ts
3
+ *
4
+ * Analyzes SceneView code and suggests performance optimizations.
5
+ */
6
+ export function optimizeScene(code) {
7
+ const suggestions = [];
8
+ const lines = code.split("\n");
9
+ // ── Check for multiple engine instances ──
10
+ const engineCount = (code.match(/rememberEngine\(\)/g) || []).length;
11
+ if (engineCount > 1) {
12
+ suggestions.push({
13
+ severity: "high",
14
+ category: "Memory",
15
+ issue: `${engineCount} Engine instances detected. Each Engine allocates significant GPU memory.`,
16
+ suggestion: "Create ONE engine at the top level and pass it down to all Scene composables.",
17
+ codeExample: `// At top-level composable:\nval engine = rememberEngine()\n// Pass to all scenes:\nScene(engine = engine) { ... }`,
18
+ });
19
+ }
20
+ // ── Check for per-frame allocations ──
21
+ if (/onFrame\s*=\s*\{/.test(code)) {
22
+ if (/Position\(/.test(code) && /onFrame/.test(code)) {
23
+ suggestions.push({
24
+ severity: "medium",
25
+ category: "Performance",
26
+ issue: "Potential per-frame Position allocation inside onFrame callback.",
27
+ suggestion: "Reuse mutable position objects instead of creating new Position instances every frame.",
28
+ codeExample: `// Before (bad): onFrame = { node.position = Position(x, y, z) }\n// After (good):\nval pos = remember { MutablePosition() }\nonFrame = { pos.set(x, y, z); node.position = pos }`,
29
+ });
30
+ }
31
+ }
32
+ // ── Check for large environment files ──
33
+ if (/4k\.hdr|4K\.hdr|8k\.hdr|8K\.hdr/.test(code)) {
34
+ suggestions.push({
35
+ severity: "high",
36
+ category: "Memory",
37
+ issue: "Large HDR environment file detected (4K or 8K).",
38
+ suggestion: "Use 2K HDR files for mobile. 4K+ wastes GPU memory with minimal visual improvement on small screens.",
39
+ codeExample: `// Use 2K: "environments/sky_2k.hdr"\n// NOT: "environments/sky_4k.hdr"`,
40
+ });
41
+ }
42
+ // ── Check for missing post-processing flag ──
43
+ if (/SceneView\s*\(/.test(code) && !/postProcessing/.test(code)) {
44
+ suggestions.push({
45
+ severity: "low",
46
+ category: "Performance",
47
+ issue: "Post-processing is enabled by default (bloom, SSAO, tone mapping).",
48
+ suggestion: "If you don't need post-processing effects, disable them to save ~2ms per frame.",
49
+ codeExample: `SceneView(\n engine = engine,\n postProcessing = false // saves ~2ms/frame\n) { ... }`,
50
+ });
51
+ }
52
+ // ── Check for too many concurrent model loads ──
53
+ const modelLoadCount = (code.match(/rememberModelInstance/g) || []).length;
54
+ if (modelLoadCount > 4) {
55
+ suggestions.push({
56
+ severity: "medium",
57
+ category: "Memory",
58
+ issue: `${modelLoadCount} concurrent model loads detected. Loading many models simultaneously spikes memory.`,
59
+ suggestion: "Limit to 3-4 concurrent loads. Use pagination or lazy loading for large model lists.",
60
+ codeExample: `// Load only visible models:\nval visibleItems = items.take(4)\nvisibleItems.forEach { item ->\n rememberModelInstance(modelLoader, item.path)\n}`,
61
+ });
62
+ }
63
+ // ── Check for missing scaleToUnits ──
64
+ if (/ModelNode\s*\(/.test(code) && !/scaleToUnits/.test(code)) {
65
+ suggestions.push({
66
+ severity: "low",
67
+ category: "Quality",
68
+ issue: "ModelNode without scaleToUnits — model may render at unexpected size.",
69
+ suggestion: "Use scaleToUnits to normalize model size. Without it, the model uses its original units which vary by source.",
70
+ codeExample: `ModelNode(\n modelInstance = instance,\n scaleToUnits = 1.0f // normalizes to 1 meter\n)`,
71
+ });
72
+ }
73
+ // ── Check for multiple shadow-casting lights ──
74
+ const shadowLights = (code.match(/castShadows\s*\(\s*true\s*\)/g) || []).length;
75
+ if (shadowLights > 2) {
76
+ suggestions.push({
77
+ severity: "high",
78
+ category: "Performance",
79
+ issue: `${shadowLights} shadow-casting lights detected. Each adds a depth render pass.`,
80
+ suggestion: "Limit to 1-2 shadow-casting lights on mobile. Disable shadows on secondary lights.",
81
+ codeExample: `// Primary light with shadows:\nLightNode(apply = { castShadows(true) })\n// Fill light without shadows:\nLightNode(apply = { castShadows(false) })`,
82
+ });
83
+ }
84
+ // ── Check for texture compression hints ──
85
+ if (/\.png|\.jpg|\.jpeg/.test(code) && /Texture|texture|bitmap/i.test(code)) {
86
+ suggestions.push({
87
+ severity: "medium",
88
+ category: "Memory",
89
+ issue: "Uncompressed texture format (PNG/JPG) detected.",
90
+ suggestion: "Use KTX2 with Basis Universal compression for textures. 4-6x memory reduction on GPU.",
91
+ });
92
+ }
93
+ // ── Check for Dispatchers.IO with Filament calls ──
94
+ if (/Dispatchers\.(IO|Default)/.test(code) && /(modelLoader|materialLoader|engine\.)/.test(code)) {
95
+ suggestions.push({
96
+ severity: "high",
97
+ category: "Correctness",
98
+ issue: "Filament JNI calls detected near background dispatcher.",
99
+ suggestion: "ALL Filament calls must run on the main thread. Use rememberModelInstance in composables or wrap in withContext(Dispatchers.Main).",
100
+ });
101
+ }
102
+ // ── Check for missing environment/IBL ──
103
+ if (/SceneView\s*\(/.test(code) && !/environment|createHDR|rememberEnvironment/.test(code) && /ModelNode/.test(code)) {
104
+ suggestions.push({
105
+ severity: "medium",
106
+ category: "Quality",
107
+ issue: "No environment/IBL detected. Metallic surfaces will appear black without image-based lighting.",
108
+ suggestion: "Add an HDR environment for physically-correct reflections on PBR materials.",
109
+ codeExample: `SceneView(\n environment = rememberEnvironment(environmentLoader) {\n environmentLoader.createHDREnvironment("environments/sky_2k.hdr")\n ?: createEnvironment(environmentLoader)\n }\n)`,
110
+ });
111
+ }
112
+ // ── Check for missing Modifier.fillMaxSize ──
113
+ if (/SceneView\s*\(/.test(code) && !/fillMaxSize/.test(code)) {
114
+ suggestions.push({
115
+ severity: "low",
116
+ category: "Quality",
117
+ issue: "SceneView may have zero size without Modifier.fillMaxSize().",
118
+ suggestion: "Add modifier = Modifier.fillMaxSize() to ensure the 3D view is visible.",
119
+ });
120
+ }
121
+ // Calculate score
122
+ const highCount = suggestions.filter((s) => s.severity === "high").length;
123
+ const mediumCount = suggestions.filter((s) => s.severity === "medium").length;
124
+ const lowCount = suggestions.filter((s) => s.severity === "low").length;
125
+ const score = Math.max(0, 100 - highCount * 20 - mediumCount * 10 - lowCount * 5);
126
+ let summary;
127
+ if (score >= 90) {
128
+ summary = "Excellent! This code follows SceneView best practices with minimal optimization opportunities.";
129
+ }
130
+ else if (score >= 70) {
131
+ summary = "Good code with some optimization opportunities. Address the high-severity items for best performance.";
132
+ }
133
+ else if (score >= 50) {
134
+ summary = "Several optimization opportunities found. Focus on high-severity items first for the biggest impact.";
135
+ }
136
+ else {
137
+ summary = "Significant performance issues detected. Address the high-severity items immediately to avoid crashes and poor performance.";
138
+ }
139
+ return { suggestions, score, summary };
140
+ }
141
+ export function formatOptimizationReport(report) {
142
+ const parts = [
143
+ `## Scene Optimization Report`,
144
+ ``,
145
+ `**Score:** ${report.score}/100`,
146
+ `**Summary:** ${report.summary}`,
147
+ ``,
148
+ ];
149
+ if (report.suggestions.length === 0) {
150
+ parts.push("No optimization suggestions. Your code looks well-optimized!");
151
+ return parts.join("\n");
152
+ }
153
+ const severityIcon = { high: "!!!", medium: "!!", low: "!" };
154
+ const severityLabel = { high: "HIGH", medium: "MEDIUM", low: "LOW" };
155
+ // Group by severity
156
+ for (const sev of ["high", "medium", "low"]) {
157
+ const items = report.suggestions.filter((s) => s.severity === sev);
158
+ if (items.length === 0)
159
+ continue;
160
+ parts.push(`### ${severityIcon[sev]} ${severityLabel[sev]} Priority (${items.length})\n`);
161
+ for (const item of items) {
162
+ parts.push(`**[${item.category}] ${item.issue}**`);
163
+ parts.push(`> ${item.suggestion}`);
164
+ if (item.codeExample) {
165
+ parts.push("```kotlin");
166
+ parts.push(item.codeExample);
167
+ parts.push("```");
168
+ }
169
+ parts.push(``);
170
+ }
171
+ }
172
+ return parts.join("\n");
173
+ }
@@ -12,7 +12,7 @@ const ANDROID_3D = `## SceneView Android — 3D Setup
12
12
  \`\`\`kotlin
13
13
  // build.gradle.kts (app module)
14
14
  dependencies {
15
- implementation("io.github.sceneview:sceneview:3.6.0")
15
+ implementation("io.github.sceneview:sceneview:3.6.2")
16
16
  }
17
17
  \`\`\`
18
18
 
@@ -87,7 +87,7 @@ const ANDROID_AR = `## SceneView Android — AR Setup
87
87
  \`\`\`kotlin
88
88
  // build.gradle.kts (app module)
89
89
  dependencies {
90
- implementation("io.github.sceneview:arsceneview:3.6.0")
90
+ implementation("io.github.sceneview:arsceneview:3.6.2")
91
91
  // arsceneview includes sceneview transitively
92
92
  }
93
93
  \`\`\`
@@ -177,7 +177,7 @@ In Xcode: **File > Add Package Dependencies** > paste:
177
177
  \`\`\`
178
178
  https://github.com/sceneview/sceneview
179
179
  \`\`\`
180
- Set version rule to **"from: 3.6.0"**.
180
+ Set version rule to **"from: 3.6.2"**.
181
181
 
182
182
  Or in Package.swift:
183
183
  \`\`\`swift
@@ -188,7 +188,7 @@ let package = Package(
188
188
  name: "MyApp",
189
189
  platforms: [.iOS(.v18), .macOS(.v15), .visionOS(.v1)],
190
190
  dependencies: [
191
- .package(url: "https://github.com/sceneview/sceneview", from: "3.6.0")
191
+ .package(url: "https://github.com/sceneview/sceneview", from: "3.6.2")
192
192
  ],
193
193
  targets: [
194
194
  .executableTarget(
@@ -273,7 +273,7 @@ const IOS_AR = `## SceneViewSwift — iOS AR Setup
273
273
  ### 1. SPM Dependency
274
274
 
275
275
  \`\`\`swift
276
- .package(url: "https://github.com/sceneview/sceneview", from: "3.6.0")
276
+ .package(url: "https://github.com/sceneview/sceneview", from: "3.6.2")
277
277
  \`\`\`
278
278
 
279
279
  ### 2. Info.plist — Camera Permission (Required)
@@ -417,7 +417,7 @@ SceneView Flutter uses **PlatformView** to embed native SceneView (Android: Fila
417
417
  \`\`\`yaml
418
418
  # pubspec.yaml
419
419
  dependencies:
420
- sceneview_flutter: ^3.6.0
420
+ sceneview_flutter: ^3.6.2
421
421
  \`\`\`
422
422
 
423
423
  ### 2. Android Setup
@@ -476,7 +476,7 @@ const FLUTTER_AR = `## SceneView Flutter — AR Setup
476
476
 
477
477
  \`\`\`yaml
478
478
  dependencies:
479
- sceneview_flutter: ^3.6.0
479
+ sceneview_flutter: ^3.6.2
480
480
  \`\`\`
481
481
 
482
482
  ### 2. Android Manifest
@@ -632,7 +632,7 @@ plugins {
632
632
 
633
633
  dependencies {
634
634
  implementation(compose.desktop.currentOs)
635
- implementation("io.github.sceneview:sceneview-desktop:3.6.0") // when published
635
+ implementation("io.github.sceneview:sceneview-desktop:3.6.2") // when published
636
636
  }
637
637
  \`\`\`
638
638
 
@@ -683,7 +683,7 @@ SceneView on Android TV uses the same Filament renderer as mobile Android, with
683
683
 
684
684
  \`\`\`kotlin
685
685
  dependencies {
686
- implementation("io.github.sceneview:sceneview:3.6.0")
686
+ implementation("io.github.sceneview:sceneview:3.6.2")
687
687
  implementation("androidx.leanback:leanback:1.0.0")
688
688
  implementation("androidx.tv:tv-foundation:1.0.0-alpha10")
689
689
  }
@@ -748,14 +748,14 @@ const SETUPS = {
748
748
  android: {
749
749
  name: "Android (Jetpack Compose)",
750
750
  renderer: "Filament (OpenGL ES / Vulkan)",
751
- status: "Stable (v3.6.0)",
751
+ status: "Stable (v3.6.2)",
752
752
  guide3d: ANDROID_3D,
753
753
  guideAr: ANDROID_AR,
754
754
  },
755
755
  ios: {
756
756
  name: "iOS / macOS / visionOS (SwiftUI)",
757
757
  renderer: "RealityKit (Metal)",
758
- status: "Alpha (v3.6.0)",
758
+ status: "Alpha (v3.6.2)",
759
759
  guide3d: IOS_3D,
760
760
  guideAr: IOS_AR,
761
761
  },