sceneview-mcp 4.0.11 → 4.0.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/README.md +15 -2
- package/dist/analyze-project.js +9 -2
- package/dist/android-docs.js +206 -0
- package/dist/artifact.js +1 -1
- package/dist/debug-issue.js +35 -10
- package/dist/examples.js +136 -0
- package/dist/extra-guides.js +4 -3
- package/dist/generate-scene.js +1 -9
- package/dist/generated/llms-txt.js +1 -1
- package/dist/generated/version.js +7 -4
- package/dist/guides.js +9 -8
- package/dist/index.js +32 -3
- package/dist/issues.js +54 -3
- package/dist/migration.js +5 -4
- package/dist/platform-setup.js +26 -11
- package/dist/samples.js +65 -64
- package/dist/telemetry.js +178 -2
- package/dist/tiers.js +2 -0
- package/dist/tools/definitions.js +38 -0
- package/dist/tools/handler.js +54 -14
- package/dist/validator.js +9 -0
- package/package.json +15 -4
- package/dist/auth.js +0 -84
- package/dist/billing.js +0 -137
- package/dist/convert-platform.js +0 -302
- package/dist/explain-api.js +0 -246
- package/dist/generate-animation.js +0 -576
- package/dist/generate-environment.js +0 -483
- package/dist/generate-gesture.js +0 -532
- package/dist/generate-physics.js +0 -570
- package/dist/optimize-scene.js +0 -173
- package/llms.txt +0 -3326
package/dist/optimize-scene.js
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
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
|
-
}
|