sceneview-mcp 3.6.2 → 3.6.5
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 +39 -0
- package/dist/analyze-project.js +500 -0
- package/dist/auth.js +84 -0
- package/dist/billing.js +137 -0
- package/dist/convert-platform.js +302 -0
- package/dist/debug-issue.js +2 -2
- package/dist/explain-api.js +245 -0
- package/dist/extra-guides.js +1 -1
- package/dist/generate-animation.js +576 -0
- package/dist/generate-environment.js +483 -0
- package/dist/generate-gesture.js +532 -0
- package/dist/generate-physics.js +570 -0
- package/dist/generate-scene.js +4 -4
- package/dist/generated/llms-txt.js +6 -0
- package/dist/guides.js +8 -8
- package/dist/index.js +54 -1111
- package/dist/migration.js +2 -2
- package/dist/optimize-scene.js +173 -0
- package/dist/platform-setup.js +11 -11
- package/dist/samples.js +64 -64
- package/dist/search-models.js +214 -0
- package/dist/telemetry.js +120 -0
- package/dist/tiers.js +100 -0
- package/dist/tools/definitions.js +467 -0
- package/dist/tools/handler.js +791 -0
- package/dist/tools/index.js +18 -0
- package/dist/tools/types.js +8 -0
- package/dist/validator.js +1 -1
- package/llms.txt +24 -1
- package/package.json +9 -20
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate-environment.ts
|
|
3
|
+
*
|
|
4
|
+
* Generates code for HDR environment setup, dynamic sky, and lighting configurations.
|
|
5
|
+
*/
|
|
6
|
+
export const ENVIRONMENT_TYPES = [
|
|
7
|
+
"hdr-environment",
|
|
8
|
+
"dynamic-sky",
|
|
9
|
+
"studio-lighting",
|
|
10
|
+
"outdoor-lighting",
|
|
11
|
+
"night-scene",
|
|
12
|
+
"ar-lighting",
|
|
13
|
+
];
|
|
14
|
+
const ANDROID_ENVIRONMENTS = {
|
|
15
|
+
"hdr-environment": {
|
|
16
|
+
description: "Load an HDR environment map for physically-based image-based lighting",
|
|
17
|
+
code: `@Composable
|
|
18
|
+
fun HDREnvironmentScreen() {
|
|
19
|
+
val engine = rememberEngine()
|
|
20
|
+
val modelLoader = rememberModelLoader(engine)
|
|
21
|
+
val environmentLoader = rememberEnvironmentLoader(engine)
|
|
22
|
+
|
|
23
|
+
val modelInstance = rememberModelInstance(modelLoader, "models/helmet.glb")
|
|
24
|
+
|
|
25
|
+
SceneView(
|
|
26
|
+
modifier = Modifier.fillMaxSize(),
|
|
27
|
+
engine = engine,
|
|
28
|
+
modelLoader = modelLoader,
|
|
29
|
+
environment = rememberEnvironment(environmentLoader) {
|
|
30
|
+
environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
|
|
31
|
+
?: createEnvironment(environmentLoader)
|
|
32
|
+
},
|
|
33
|
+
mainLightNode = rememberMainLightNode(engine) {
|
|
34
|
+
intensity = 100_000f
|
|
35
|
+
},
|
|
36
|
+
cameraManipulator = rememberCameraManipulator()
|
|
37
|
+
) {
|
|
38
|
+
modelInstance?.let { instance ->
|
|
39
|
+
ModelNode(
|
|
40
|
+
modelInstance = instance,
|
|
41
|
+
scaleToUnits = 1.0f,
|
|
42
|
+
centerOrigin = Position(0f, 0f, 0f)
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}`,
|
|
47
|
+
notes: [
|
|
48
|
+
"Place HDR files in `src/main/assets/environments/`.",
|
|
49
|
+
"Use 2K HDR files for mobile (4K wastes GPU memory).",
|
|
50
|
+
"HDR environment provides both skybox (background) and IBL (reflections).",
|
|
51
|
+
"Without IBL, metallic surfaces appear black.",
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
"dynamic-sky": {
|
|
55
|
+
description: "Time-of-day dynamic sky with sun simulation",
|
|
56
|
+
code: `@Composable
|
|
57
|
+
fun DynamicSkyScreen() {
|
|
58
|
+
val engine = rememberEngine()
|
|
59
|
+
val modelLoader = rememberModelLoader(engine)
|
|
60
|
+
val modelInstance = rememberModelInstance(modelLoader, "models/building.glb")
|
|
61
|
+
|
|
62
|
+
var sunAngle by remember { mutableFloatStateOf(45f) }
|
|
63
|
+
|
|
64
|
+
Column(modifier = Modifier.fillMaxSize()) {
|
|
65
|
+
SceneView(
|
|
66
|
+
modifier = Modifier.weight(1f).fillMaxWidth(),
|
|
67
|
+
engine = engine,
|
|
68
|
+
modelLoader = modelLoader,
|
|
69
|
+
cameraManipulator = rememberCameraManipulator()
|
|
70
|
+
) {
|
|
71
|
+
// DynamicSkyNode simulates a procedural sky with sun position
|
|
72
|
+
DynamicSkyNode(
|
|
73
|
+
engine = engine,
|
|
74
|
+
sunAngle = sunAngle,
|
|
75
|
+
turbidity = 4.0f, // atmospheric haze (2=clear, 10=overcast)
|
|
76
|
+
groundAlbedo = 0.3f // ground reflectance
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
modelInstance?.let { instance ->
|
|
80
|
+
ModelNode(
|
|
81
|
+
modelInstance = instance,
|
|
82
|
+
scaleToUnits = 2.0f,
|
|
83
|
+
centerOrigin = Position(0f, 0f, 0f)
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
LightNode(
|
|
88
|
+
engine = engine,
|
|
89
|
+
type = LightManager.Type.SUN,
|
|
90
|
+
apply = {
|
|
91
|
+
intensity(110_000f)
|
|
92
|
+
castShadows(true)
|
|
93
|
+
direction(
|
|
94
|
+
-kotlin.math.cos(Math.toRadians(sunAngle.toDouble())).toFloat(),
|
|
95
|
+
-kotlin.math.sin(Math.toRadians(sunAngle.toDouble())).toFloat(),
|
|
96
|
+
0f
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
Slider(
|
|
103
|
+
value = sunAngle,
|
|
104
|
+
onValueChange = { sunAngle = it },
|
|
105
|
+
valueRange = 0f..180f,
|
|
106
|
+
modifier = Modifier.padding(16.dp)
|
|
107
|
+
)
|
|
108
|
+
Text(
|
|
109
|
+
"Sun angle: \${sunAngle.toInt()}°",
|
|
110
|
+
modifier = Modifier.padding(horizontal = 16.dp),
|
|
111
|
+
color = Color.White
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}`,
|
|
115
|
+
notes: [
|
|
116
|
+
"DynamicSkyNode is a SceneScope composable — must be inside SceneView { }.",
|
|
117
|
+
"sunAngle: 0° = sunrise, 90° = noon, 180° = sunset.",
|
|
118
|
+
"turbidity: 2 = crystal clear, 4 = average, 10 = overcast/hazy.",
|
|
119
|
+
"Sync the LightNode direction with the sun angle for consistent shadows.",
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
"studio-lighting": {
|
|
123
|
+
description: "Three-point studio lighting setup for product visualization",
|
|
124
|
+
code: `@Composable
|
|
125
|
+
fun StudioLightingScreen() {
|
|
126
|
+
val engine = rememberEngine()
|
|
127
|
+
val modelLoader = rememberModelLoader(engine)
|
|
128
|
+
val environmentLoader = rememberEnvironmentLoader(engine)
|
|
129
|
+
val modelInstance = rememberModelInstance(modelLoader, "models/product.glb")
|
|
130
|
+
|
|
131
|
+
SceneView(
|
|
132
|
+
modifier = Modifier.fillMaxSize(),
|
|
133
|
+
engine = engine,
|
|
134
|
+
modelLoader = modelLoader,
|
|
135
|
+
environment = rememberEnvironment(environmentLoader) {
|
|
136
|
+
environmentLoader.createHDREnvironment("environments/studio_2k.hdr")
|
|
137
|
+
?: createEnvironment(environmentLoader)
|
|
138
|
+
},
|
|
139
|
+
cameraManipulator = rememberCameraManipulator()
|
|
140
|
+
) {
|
|
141
|
+
// Key light — main illumination from upper-left
|
|
142
|
+
LightNode(
|
|
143
|
+
engine = engine,
|
|
144
|
+
type = LightManager.Type.DIRECTIONAL,
|
|
145
|
+
apply = {
|
|
146
|
+
intensity(120_000f)
|
|
147
|
+
direction(-0.5f, -1f, -0.5f)
|
|
148
|
+
castShadows(true)
|
|
149
|
+
color(1f, 0.98f, 0.95f) // slightly warm
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
// Fill light — softer from the right
|
|
154
|
+
LightNode(
|
|
155
|
+
engine = engine,
|
|
156
|
+
type = LightManager.Type.DIRECTIONAL,
|
|
157
|
+
apply = {
|
|
158
|
+
intensity(40_000f)
|
|
159
|
+
direction(0.7f, -0.5f, -0.3f)
|
|
160
|
+
castShadows(false)
|
|
161
|
+
color(0.9f, 0.95f, 1f) // slightly cool
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
// Rim/back light — highlights edges
|
|
166
|
+
LightNode(
|
|
167
|
+
engine = engine,
|
|
168
|
+
type = LightManager.Type.DIRECTIONAL,
|
|
169
|
+
apply = {
|
|
170
|
+
intensity(60_000f)
|
|
171
|
+
direction(0f, -0.3f, 1f)
|
|
172
|
+
castShadows(false)
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
modelInstance?.let { instance ->
|
|
177
|
+
ModelNode(
|
|
178
|
+
modelInstance = instance,
|
|
179
|
+
scaleToUnits = 1.0f,
|
|
180
|
+
centerOrigin = Position(0f, 0f, 0f)
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}`,
|
|
185
|
+
notes: [
|
|
186
|
+
"Three-point lighting: key (main), fill (secondary), rim (edge highlight).",
|
|
187
|
+
"Key light at ~120K lux, fill at ~40K, rim at ~60K for product photography look.",
|
|
188
|
+
"Use a studio HDR environment for realistic reflections on metallic surfaces.",
|
|
189
|
+
"Adjust light colors for warm/cool mood (warm key + cool fill is classic).",
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
"outdoor-lighting": {
|
|
193
|
+
description: "Outdoor scene with sunlight, sky, and atmospheric effects",
|
|
194
|
+
code: `@Composable
|
|
195
|
+
fun OutdoorLightingScreen() {
|
|
196
|
+
val engine = rememberEngine()
|
|
197
|
+
val modelLoader = rememberModelLoader(engine)
|
|
198
|
+
val environmentLoader = rememberEnvironmentLoader(engine)
|
|
199
|
+
val modelInstance = rememberModelInstance(modelLoader, "models/car.glb")
|
|
200
|
+
|
|
201
|
+
SceneView(
|
|
202
|
+
modifier = Modifier.fillMaxSize(),
|
|
203
|
+
engine = engine,
|
|
204
|
+
modelLoader = modelLoader,
|
|
205
|
+
environment = rememberEnvironment(environmentLoader) {
|
|
206
|
+
environmentLoader.createHDREnvironment("environments/outdoor_2k.hdr")
|
|
207
|
+
?: createEnvironment(environmentLoader)
|
|
208
|
+
},
|
|
209
|
+
cameraManipulator = rememberCameraManipulator()
|
|
210
|
+
) {
|
|
211
|
+
// Sun light
|
|
212
|
+
LightNode(
|
|
213
|
+
engine = engine,
|
|
214
|
+
type = LightManager.Type.SUN,
|
|
215
|
+
apply = {
|
|
216
|
+
intensity(110_000f)
|
|
217
|
+
direction(0f, -1f, -0.5f) // high noon, slightly forward
|
|
218
|
+
castShadows(true)
|
|
219
|
+
color(1f, 0.96f, 0.9f) // warm sunlight
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
modelInstance?.let { instance ->
|
|
224
|
+
ModelNode(
|
|
225
|
+
modelInstance = instance,
|
|
226
|
+
scaleToUnits = 2.0f,
|
|
227
|
+
centerOrigin = Position(0f, 0f, 0f)
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Ground plane for shadow reception
|
|
232
|
+
val materialLoader = rememberMaterialLoader(engine)
|
|
233
|
+
val groundMat = remember(materialLoader) {
|
|
234
|
+
materialLoader.createColorInstance(Color(0.3f, 0.35f, 0.25f), roughness = 0.9f)
|
|
235
|
+
}
|
|
236
|
+
PlaneNode(
|
|
237
|
+
size = Size(20f, 20f),
|
|
238
|
+
materialInstance = groundMat
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
}`,
|
|
242
|
+
notes: [
|
|
243
|
+
"Use LightManager.Type.SUN for outdoor scenes (physically-based sun model).",
|
|
244
|
+
"Sun intensity of ~110,000 lux matches real-world daylight.",
|
|
245
|
+
"Add a ground plane for shadow reception.",
|
|
246
|
+
"Use an outdoor HDR environment for sky reflections.",
|
|
247
|
+
],
|
|
248
|
+
},
|
|
249
|
+
"night-scene": {
|
|
250
|
+
description: "Night/mood scene with point lights and dim ambient",
|
|
251
|
+
code: `@Composable
|
|
252
|
+
fun NightSceneScreen() {
|
|
253
|
+
val engine = rememberEngine()
|
|
254
|
+
val modelLoader = rememberModelLoader(engine)
|
|
255
|
+
val modelInstance = rememberModelInstance(modelLoader, "models/scene.glb")
|
|
256
|
+
|
|
257
|
+
SceneView(
|
|
258
|
+
modifier = Modifier.fillMaxSize(),
|
|
259
|
+
engine = engine,
|
|
260
|
+
modelLoader = modelLoader,
|
|
261
|
+
cameraManipulator = rememberCameraManipulator()
|
|
262
|
+
) {
|
|
263
|
+
// Warm point light (like a lamp/candle)
|
|
264
|
+
LightNode(
|
|
265
|
+
engine = engine,
|
|
266
|
+
type = LightManager.Type.POINT,
|
|
267
|
+
apply = {
|
|
268
|
+
intensity(50_000f)
|
|
269
|
+
falloff(8f)
|
|
270
|
+
castShadows(true)
|
|
271
|
+
color(1f, 0.8f, 0.5f) // warm orange
|
|
272
|
+
},
|
|
273
|
+
position = Position(1f, 2f, 0f)
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
// Cool accent light
|
|
277
|
+
LightNode(
|
|
278
|
+
engine = engine,
|
|
279
|
+
type = LightManager.Type.SPOT,
|
|
280
|
+
apply = {
|
|
281
|
+
intensity(30_000f)
|
|
282
|
+
falloff(10f)
|
|
283
|
+
castShadows(false)
|
|
284
|
+
color(0.5f, 0.7f, 1f) // cool blue
|
|
285
|
+
innerConeAngle(0.2f)
|
|
286
|
+
outerConeAngle(0.5f)
|
|
287
|
+
},
|
|
288
|
+
position = Position(-2f, 3f, 1f)
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
modelInstance?.let { instance ->
|
|
292
|
+
ModelNode(
|
|
293
|
+
modelInstance = instance,
|
|
294
|
+
scaleToUnits = 2.0f,
|
|
295
|
+
centerOrigin = Position(0f, 0f, 0f)
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}`,
|
|
300
|
+
notes: [
|
|
301
|
+
"Night scenes use POINT and SPOT lights instead of directional/sun.",
|
|
302
|
+
"Lower intensities (30K-50K lux) create mood lighting.",
|
|
303
|
+
"Use warm colors (orange/yellow) for lamps, cool colors (blue) for moonlight.",
|
|
304
|
+
"falloff controls how far the light reaches (in meters).",
|
|
305
|
+
"Spot lights need innerConeAngle and outerConeAngle (in radians).",
|
|
306
|
+
],
|
|
307
|
+
},
|
|
308
|
+
"ar-lighting": {
|
|
309
|
+
description: "AR scene with environmental HDR light estimation",
|
|
310
|
+
code: `@Composable
|
|
311
|
+
fun ARLightingScreen() {
|
|
312
|
+
val engine = rememberEngine()
|
|
313
|
+
val modelLoader = rememberModelLoader(engine)
|
|
314
|
+
val modelInstance = rememberModelInstance(modelLoader, "models/furniture.glb")
|
|
315
|
+
var anchor by remember { mutableStateOf<Anchor?>(null) }
|
|
316
|
+
|
|
317
|
+
ARSceneView(
|
|
318
|
+
modifier = Modifier.fillMaxSize(),
|
|
319
|
+
engine = engine,
|
|
320
|
+
modelLoader = modelLoader,
|
|
321
|
+
planeRenderer = true,
|
|
322
|
+
sessionConfiguration = { session, config ->
|
|
323
|
+
// ENVIRONMENTAL_HDR is the most realistic lighting mode
|
|
324
|
+
// It captures real-world lighting and applies it to virtual objects
|
|
325
|
+
config.lightEstimationMode = Config.LightEstimationMode.ENVIRONMENTAL_HDR
|
|
326
|
+
config.depthMode =
|
|
327
|
+
if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC))
|
|
328
|
+
Config.DepthMode.AUTOMATIC else Config.DepthMode.DISABLED
|
|
329
|
+
config.planeFindingMode = Config.PlaneFindingMode.HORIZONTAL_AND_VERTICAL
|
|
330
|
+
},
|
|
331
|
+
onTouchEvent = { event, hitResult ->
|
|
332
|
+
if (event.action == MotionEvent.ACTION_UP && hitResult != null) {
|
|
333
|
+
anchor = hitResult.createAnchor()
|
|
334
|
+
}
|
|
335
|
+
true
|
|
336
|
+
}
|
|
337
|
+
) {
|
|
338
|
+
anchor?.let { a ->
|
|
339
|
+
AnchorNode(anchor = a) {
|
|
340
|
+
modelInstance?.let { instance ->
|
|
341
|
+
ModelNode(
|
|
342
|
+
modelInstance = instance,
|
|
343
|
+
scaleToUnits = 0.5f,
|
|
344
|
+
isEditable = true
|
|
345
|
+
)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}`,
|
|
351
|
+
notes: [
|
|
352
|
+
"ENVIRONMENTAL_HDR captures the real environment and applies it as IBL to virtual objects.",
|
|
353
|
+
"This is the most realistic AR lighting mode but costs more CPU/GPU.",
|
|
354
|
+
"For simpler lighting, use AMBIENT_INTENSITY (just brightness + color temperature).",
|
|
355
|
+
"ARCore automatically adjusts directional light to match real shadows.",
|
|
356
|
+
],
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
const IOS_ENVIRONMENTS = {
|
|
360
|
+
"hdr-environment": {
|
|
361
|
+
description: "RealityKit scene with environment lighting in SwiftUI",
|
|
362
|
+
code: `import SwiftUI
|
|
363
|
+
import SceneViewSwift
|
|
364
|
+
import RealityKit
|
|
365
|
+
|
|
366
|
+
struct EnvironmentLightingView: View {
|
|
367
|
+
@State private var model: ModelNode?
|
|
368
|
+
|
|
369
|
+
var body: some View {
|
|
370
|
+
SceneView { root in
|
|
371
|
+
if let model {
|
|
372
|
+
root.addChild(model.entity)
|
|
373
|
+
}
|
|
374
|
+
// RealityKit uses built-in IBL automatically
|
|
375
|
+
// For custom environments, use .environment(.lighting) modifiers
|
|
376
|
+
}
|
|
377
|
+
.cameraControls(.orbit)
|
|
378
|
+
.task {
|
|
379
|
+
do {
|
|
380
|
+
model = try await ModelNode.load("models/helmet.usdz")
|
|
381
|
+
model?.scaleToUnits(1.0)
|
|
382
|
+
} catch {
|
|
383
|
+
print("Failed to load: \\(error)")
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}`,
|
|
388
|
+
notes: [
|
|
389
|
+
"RealityKit provides built-in IBL automatically.",
|
|
390
|
+
"For custom environment maps, use ImageBasedLightComponent on the anchor entity.",
|
|
391
|
+
"USDZ models carry their own material properties that work with RealityKit's PBR pipeline.",
|
|
392
|
+
],
|
|
393
|
+
},
|
|
394
|
+
"ar-lighting": {
|
|
395
|
+
description: "iOS AR with automatic environment lighting from ARKit",
|
|
396
|
+
code: `import SwiftUI
|
|
397
|
+
import SceneViewSwift
|
|
398
|
+
import RealityKit
|
|
399
|
+
|
|
400
|
+
struct ARLightingView: View {
|
|
401
|
+
@State private var model: ModelNode?
|
|
402
|
+
|
|
403
|
+
var body: some View {
|
|
404
|
+
ARSceneView(
|
|
405
|
+
planeDetection: .horizontal,
|
|
406
|
+
showCoachingOverlay: true,
|
|
407
|
+
onTapOnPlane: { position, arView in
|
|
408
|
+
guard let model else { return }
|
|
409
|
+
let anchor = AnchorNode.world(position: position)
|
|
410
|
+
let clone = model.entity.clone(recursive: true)
|
|
411
|
+
clone.scale = .init(repeating: 0.5)
|
|
412
|
+
anchor.add(clone)
|
|
413
|
+
arView.scene.addAnchor(anchor.entity)
|
|
414
|
+
}
|
|
415
|
+
)
|
|
416
|
+
.edgesIgnoringSafeArea(.all)
|
|
417
|
+
.task {
|
|
418
|
+
do {
|
|
419
|
+
model = try await ModelNode.load("models/furniture.usdz")
|
|
420
|
+
} catch {
|
|
421
|
+
print("Failed to load: \\(error)")
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}`,
|
|
426
|
+
notes: [
|
|
427
|
+
"ARKit automatically provides environment lighting estimation.",
|
|
428
|
+
"RealityKit applies real-world lighting to virtual objects by default.",
|
|
429
|
+
"No manual light estimation configuration needed on iOS.",
|
|
430
|
+
],
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
export function generateEnvironmentCode(environmentType, platform = "android") {
|
|
434
|
+
if (platform === "ios") {
|
|
435
|
+
const iosEnv = IOS_ENVIRONMENTS[environmentType];
|
|
436
|
+
if (iosEnv) {
|
|
437
|
+
return {
|
|
438
|
+
code: iosEnv.code,
|
|
439
|
+
platform: "ios",
|
|
440
|
+
environmentType,
|
|
441
|
+
description: iosEnv.description,
|
|
442
|
+
notes: iosEnv.notes,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
code: IOS_ENVIRONMENTS["hdr-environment"].code,
|
|
447
|
+
platform: "ios",
|
|
448
|
+
environmentType: "hdr-environment",
|
|
449
|
+
description: `iOS equivalent for '${environmentType}' not available. Showing HDR environment instead.`,
|
|
450
|
+
notes: [`The '${environmentType}' environment type is Android-specific. RealityKit handles lighting differently.`],
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const env = ANDROID_ENVIRONMENTS[environmentType];
|
|
454
|
+
if (!env)
|
|
455
|
+
return null;
|
|
456
|
+
return {
|
|
457
|
+
code: env.code,
|
|
458
|
+
platform: "android",
|
|
459
|
+
environmentType,
|
|
460
|
+
description: env.description,
|
|
461
|
+
notes: env.notes,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
export function formatEnvironmentCode(result) {
|
|
465
|
+
const lang = result.platform === "ios" ? "swift" : "kotlin";
|
|
466
|
+
const parts = [
|
|
467
|
+
`## Environment: ${result.environmentType}`,
|
|
468
|
+
`**Platform:** ${result.platform === "ios" ? "iOS (SwiftUI + RealityKit)" : "Android (Jetpack Compose + Filament)"}`,
|
|
469
|
+
`**Description:** ${result.description}`,
|
|
470
|
+
``,
|
|
471
|
+
`### Code`,
|
|
472
|
+
``,
|
|
473
|
+
"```" + lang,
|
|
474
|
+
result.code,
|
|
475
|
+
"```",
|
|
476
|
+
``,
|
|
477
|
+
];
|
|
478
|
+
if (result.notes.length > 0) {
|
|
479
|
+
parts.push(`### Notes`);
|
|
480
|
+
result.notes.forEach((n, i) => parts.push(`${i + 1}. ${n}`));
|
|
481
|
+
}
|
|
482
|
+
return parts.join("\n");
|
|
483
|
+
}
|