sceneview-mcp 3.5.1 → 3.5.2

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/samples.js CHANGED
@@ -4,8 +4,8 @@ export const SAMPLES = {
4
4
  title: "3D Model Viewer",
5
5
  description: "Full-screen 3D scene with a GLB model, HDR environment, orbit camera, and animation controls",
6
6
  tags: ["3d", "model", "environment", "camera", "animation"],
7
- dependency: "io.github.sceneview:sceneview:3.3.0",
8
- prompt: "Create an Android Compose screen that loads a GLB model and displays it with HDR lighting, orbit camera, and animation playback. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
7
+ dependency: "io.github.sceneview:sceneview:3.4.7",
8
+ prompt: "Create an Android Compose screen that loads a GLB model and displays it with HDR lighting, orbit camera, and animation playback. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
9
9
  code: `@Composable
10
10
  fun ModelViewerScreen() {
11
11
  val engine = rememberEngine()
@@ -38,8 +38,8 @@ fun ModelViewerScreen() {
38
38
  title: "AR Tap-to-Place Model Viewer",
39
39
  description: "AR scene with plane detection. Tap a surface to place a 3D model with pinch-to-scale and drag-to-rotate gestures.",
40
40
  tags: ["ar", "model", "anchor", "plane-detection", "placement", "gestures"],
41
- dependency: "io.github.sceneview:arsceneview:3.3.0",
42
- prompt: "Create an AR screen that detects surfaces and lets the user tap to place a GLB model. Support pinch-to-scale and drag-to-rotate. Use SceneView `io.github.sceneview:arsceneview:3.3.0`.",
41
+ dependency: "io.github.sceneview:arsceneview:3.4.7",
42
+ prompt: "Create an AR screen that detects surfaces and lets the user tap to place a GLB model. Support pinch-to-scale and drag-to-rotate. Use SceneView `io.github.sceneview:arsceneview:3.4.7`.",
43
43
  code: `@Composable
44
44
  fun ARModelViewerScreen() {
45
45
  val engine = rememberEngine()
@@ -83,8 +83,8 @@ fun ARModelViewerScreen() {
83
83
  title: "AR Augmented Image",
84
84
  description: "Detects reference images in the camera feed and overlays 3D models or video above them.",
85
85
  tags: ["ar", "model", "image-tracking"],
86
- dependency: "io.github.sceneview:arsceneview:3.3.0",
87
- prompt: "Create an AR screen that detects a printed reference image and places a 3D model above it. Use SceneView `io.github.sceneview:arsceneview:3.3.0`.",
86
+ dependency: "io.github.sceneview:arsceneview:3.4.7",
87
+ prompt: "Create an AR screen that detects a printed reference image and places a 3D model above it. Use SceneView `io.github.sceneview:arsceneview:3.4.7`.",
88
88
  code: `@Composable
89
89
  fun AugmentedImageScreen() {
90
90
  val engine = rememberEngine()
@@ -125,8 +125,8 @@ fun AugmentedImageScreen() {
125
125
  title: "AR Cloud Anchor",
126
126
  description: "Host and resolve persistent cross-device anchors using ARCore Cloud Anchors.",
127
127
  tags: ["ar", "anchor", "cloud-anchor"],
128
- dependency: "io.github.sceneview:arsceneview:3.3.0",
129
- prompt: "Create an AR screen that can host a cloud anchor (saving its ID) and resolve it later on another device. Use SceneView `io.github.sceneview:arsceneview:3.3.0`.",
128
+ dependency: "io.github.sceneview:arsceneview:3.4.7",
129
+ prompt: "Create an AR screen that can host a cloud anchor (saving its ID) and resolve it later on another device. Use SceneView `io.github.sceneview:arsceneview:3.4.7`.",
130
130
  code: `@Composable
131
131
  fun CloudAnchorScreen() {
132
132
  val engine = rememberEngine()
@@ -156,8 +156,8 @@ fun CloudAnchorScreen() {
156
156
  title: "AR Point Cloud",
157
157
  description: "Visualizes ARCore feature points as 3D spheres with confidence-based filtering.",
158
158
  tags: ["ar", "point-cloud"],
159
- dependency: "io.github.sceneview:arsceneview:3.3.0",
160
- prompt: "Create an AR screen that visualizes ARCore feature points as small 3D spheres, filtered by confidence. Use SceneView `io.github.sceneview:arsceneview:3.3.0`.",
159
+ dependency: "io.github.sceneview:arsceneview:3.4.7",
160
+ prompt: "Create an AR screen that visualizes ARCore feature points as small 3D spheres, filtered by confidence. Use SceneView `io.github.sceneview:arsceneview:3.4.7`.",
161
161
  code: `@Composable
162
162
  fun PointCloudScreen() {
163
163
  val engine = rememberEngine()
@@ -188,8 +188,8 @@ fun PointCloudScreen() {
188
188
  title: "AR Face Mesh",
189
189
  description: "AR face tracking with AugmentedFaceNode — applies a textured mesh overlay to detected faces using the front camera.",
190
190
  tags: ["ar", "face-tracking", "model"],
191
- dependency: "io.github.sceneview:arsceneview:3.3.0",
192
- prompt: "Create an AR screen that uses the front camera to detect faces and overlay a 3D mesh on them. Use SceneView `io.github.sceneview:arsceneview:3.3.0`.",
191
+ dependency: "io.github.sceneview:arsceneview:3.4.7",
192
+ prompt: "Create an AR screen that uses the front camera to detect faces and overlay a 3D mesh on them. Use SceneView `io.github.sceneview:arsceneview:3.4.7`.",
193
193
  code: `@Composable
194
194
  fun ARFaceMeshScreen() {
195
195
  val engine = rememberEngine()
@@ -232,8 +232,8 @@ fun ARFaceMeshScreen() {
232
232
  title: "glTF Camera",
233
233
  description: "Extracts and uses camera definitions embedded in a glTF file for cinematic viewpoints.",
234
234
  tags: ["3d", "model", "camera"],
235
- dependency: "io.github.sceneview:sceneview:3.3.0",
236
- prompt: "Create a 3D scene that loads a GLB file containing embedded camera definitions, then uses those cameras for cinematic viewpoints. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
235
+ dependency: "io.github.sceneview:sceneview:3.4.7",
236
+ prompt: "Create a 3D scene that loads a GLB file containing embedded camera definitions, then uses those cameras for cinematic viewpoints. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
237
237
  code: `@Composable
238
238
  fun GltfCameraScreen() {
239
239
  val engine = rememberEngine()
@@ -262,8 +262,8 @@ fun GltfCameraScreen() {
262
262
  title: "Camera Manipulator",
263
263
  description: "Orbit, pan, and zoom camera with customizable sensitivity and bounds.",
264
264
  tags: ["3d", "camera", "gestures"],
265
- dependency: "io.github.sceneview:sceneview:3.3.0",
266
- prompt: "Create a 3D scene with a fully configurable orbit camera — drag to rotate, two-finger pan, pinch to zoom. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
265
+ dependency: "io.github.sceneview:sceneview:3.4.7",
266
+ prompt: "Create a 3D scene with a fully configurable orbit camera — drag to rotate, two-finger pan, pinch to zoom. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
267
267
  code: `@Composable
268
268
  fun CameraManipulatorScreen() {
269
269
  val engine = rememberEngine()
@@ -293,8 +293,8 @@ fun CameraManipulatorScreen() {
293
293
  title: "Camera Animation",
294
294
  description: "Animated camera flythrough around a 3D model — smooth orbit using LaunchedEffect and trigonometric interpolation.",
295
295
  tags: ["3d", "camera", "animation", "model"],
296
- dependency: "io.github.sceneview:sceneview:3.3.0",
297
- prompt: "Create a 3D scene with a camera that automatically orbits around a model in a smooth circle. Include a play/pause button. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
296
+ dependency: "io.github.sceneview:sceneview:3.4.7",
297
+ prompt: "Create a 3D scene with a camera that automatically orbits around a model in a smooth circle. Include a play/pause button. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
298
298
  code: `@Composable
299
299
  fun CameraAnimationScreen() {
300
300
  val engine = rememberEngine()
@@ -352,108 +352,256 @@ fun CameraAnimationScreen() {
352
352
  "autopilot-demo": {
353
353
  id: "autopilot-demo",
354
354
  title: "Autopilot Demo",
355
- description: "Full autonomous driving HUD with animated car, traffic lights, road, and real-time telemetry overlay.",
355
+ description: "Autonomous driving HUD with animated car, road geometry, and real-time telemetry overlay.",
356
356
  tags: ["3d", "model", "animation", "geometry"],
357
- dependency: "io.github.sceneview:sceneview:3.3.0",
358
- prompt: "Create a Tesla FSD-style autopilot visualization with a 3D car on a road, traffic lights, and a HUD overlay showing speed, distance, and status. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
357
+ dependency: "io.github.sceneview:sceneview:3.4.7",
358
+ prompt: "Create an autopilot-style visualization with a 3D car on a road and a HUD overlay showing speed, distance, and status. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
359
359
  code: `@Composable
360
360
  fun AutopilotScreen() {
361
361
  val engine = rememberEngine()
362
362
  val modelLoader = rememberModelLoader(engine)
363
+ val materialLoader = rememberMaterialLoader(engine)
364
+ var speed by remember { mutableFloatStateOf(60f) }
363
365
 
364
- Scene(
365
- modifier = Modifier.fillMaxSize(),
366
- engine = engine,
367
- modelLoader = modelLoader
368
- ) {
369
- // Road surface
370
- PlaneNode(engine, size = Size(6f, 0f, 50f),
371
- position = Position(y = -0.01f))
366
+ Box(modifier = Modifier.fillMaxSize()) {
367
+ Scene(
368
+ modifier = Modifier.fillMaxSize(),
369
+ engine = engine,
370
+ modelLoader = modelLoader,
371
+ cameraNode = rememberCameraNode(engine) {
372
+ position = Position(x = 0f, y = 2f, z = 5f)
373
+ lookAt(Position(0f, 0f, -2f))
374
+ },
375
+ mainLightNode = rememberMainLightNode(engine) { intensity = 110_000f }
376
+ ) {
377
+ // Road surface
378
+ val roadMat = remember(materialLoader) {
379
+ materialLoader.createColorInstance(Color.DarkGray, roughness = 0.95f)
380
+ }
381
+ PlaneNode(size = Size(6f, 50f), materialInstance = roadMat, position = Position(y = -0.01f))
382
+
383
+ // Lane markings (white lines)
384
+ val whiteMat = remember(materialLoader) {
385
+ materialLoader.createColorInstance(Color.White)
386
+ }
387
+ for (z in -20..20 step 4) {
388
+ CubeNode(
389
+ size = Size(0.1f, 0.01f, 2f),
390
+ materialInstance = whiteMat,
391
+ position = Position(x = 0f, y = 0f, z = z.toFloat())
392
+ )
393
+ }
394
+
395
+ // Ego car
396
+ rememberModelInstance(modelLoader, "models/car.glb")?.let { instance ->
397
+ ModelNode(modelInstance = instance, scaleToUnits = 2f)
398
+ }
372
399
 
373
- // Ego car
374
- rememberModelInstance(modelLoader, "models/car.glb")?.let { instance ->
375
- ModelNode(modelInstance = instance, scaleToUnits = 2f)
400
+ // Traffic light post
401
+ val greenMat = remember(materialLoader) {
402
+ materialLoader.createColorInstance(Color.Green, metallic = 0f, roughness = 0.3f)
403
+ }
404
+ SphereNode(radius = 0.1f, materialInstance = greenMat, position = Position(x = 2f, y = 3f, z = -8f))
376
405
  }
377
406
 
378
- // Traffic light with state machine
379
- // See samples/autopilot-demo for the full implementation
407
+ // HUD overlay
408
+ Column(
409
+ modifier = Modifier.align(Alignment.TopStart).padding(24.dp)
410
+ .background(Color.Black.copy(alpha = 0.7f), RoundedCornerShape(12.dp))
411
+ .padding(16.dp)
412
+ ) {
413
+ Text("\${speed.toInt()} km/h", color = Color.White, fontSize = 32.sp, fontWeight = FontWeight.Bold)
414
+ Text("AUTOPILOT ACTIVE", color = Color.Green, fontSize = 14.sp)
415
+ Spacer(Modifier.height(8.dp))
416
+ Text("Next turn: 2.3 km", color = Color.LightGray, fontSize = 12.sp)
417
+ }
380
418
  }
381
419
  }`,
382
420
  },
383
421
  "physics-demo": {
384
422
  id: "physics-demo",
385
- title: "Physics Demo",
386
- description: "Interactive physics simulation with bouncing spheres, gravity, configurable restitution, and colour selection.",
423
+ title: "Physics Simulation",
424
+ description: "Animated physics simulation with spheres falling under gravity and bouncing off a floor, using onFrame for per-frame updates.",
387
425
  tags: ["3d", "physics", "geometry", "animation"],
388
- dependency: "io.github.sceneview:sceneview:3.3.0",
389
- prompt: "Create a 3D scene where tapping spawns coloured spheres that fall under gravity and bounce off a floor. Add a bounciness slider. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
426
+ dependency: "io.github.sceneview:sceneview:3.4.7",
427
+ prompt: "Create a 3D scene with spheres that fall under gravity and bounce on a floor using per-frame animation. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
390
428
  code: `@Composable
391
429
  fun PhysicsDemoScreen() {
392
430
  val engine = rememberEngine()
393
431
  val materialLoader = rememberMaterialLoader(engine)
432
+ val environmentLoader = rememberEnvironmentLoader(engine)
394
433
  var restitution by remember { mutableFloatStateOf(0.7f) }
395
434
 
396
- Scene(
397
- modifier = Modifier.fillMaxSize(),
398
- engine = engine,
399
- materialLoader = materialLoader
400
- ) {
401
- // Floor
402
- PlaneNode(engine, size = Size(4f, 0f, 4f),
403
- materialInstance = materialLoader.createColorInstance(Color.DarkGray))
435
+ // Simple physics state: y-positions and velocities for 5 spheres
436
+ data class Ball(var y: Float, var vy: Float, val x: Float, val color: Color)
437
+ val balls = remember {
438
+ mutableStateListOf(
439
+ Ball(3.0f, 0f, -1.0f, Color.Red),
440
+ Ball(4.0f, 0f, -0.5f, Color.Blue),
441
+ Ball(3.5f, 0f, 0.0f, Color.Green),
442
+ Ball(4.5f, 0f, 0.5f, Color.Yellow),
443
+ Ball(5.0f, 0f, 1.0f, Color.Cyan)
444
+ )
445
+ }
404
446
 
405
- // Spawn spheres and attach PhysicsNode
406
- val sphere = remember(engine) {
407
- SphereNode(engine, radius = 0.15f).apply {
408
- position = Position(y = 3f)
447
+ // Per-frame gravity + bounce
448
+ LaunchedEffect(restitution) {
449
+ while (true) {
450
+ withFrameNanos { _ ->
451
+ val dt = 0.016f
452
+ val gravity = -9.8f
453
+ val floorY = 0.15f
454
+ for (ball in balls) {
455
+ ball.vy += gravity * dt
456
+ ball.y += ball.vy * dt
457
+ if (ball.y < floorY) {
458
+ ball.y = floorY
459
+ ball.vy = -ball.vy * restitution
460
+ }
461
+ }
409
462
  }
410
463
  }
411
- PhysicsNode(
412
- node = sphere,
413
- restitution = restitution,
414
- radius = 0.15f
415
- )
464
+ }
465
+
466
+ Column {
467
+ Scene(
468
+ modifier = Modifier.weight(1f).fillMaxWidth(),
469
+ engine = engine,
470
+ cameraManipulator = rememberCameraManipulator(
471
+ orbitHomePosition = Position(x = 0f, y = 3f, z = 6f),
472
+ targetPosition = Position(0f, 1f, 0f)
473
+ ),
474
+ environment = rememberEnvironment(environmentLoader) {
475
+ environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
476
+ ?: createEnvironment(environmentLoader)
477
+ },
478
+ mainLightNode = rememberMainLightNode(engine) { intensity = 100_000f }
479
+ ) {
480
+ // Floor
481
+ val floorMat = remember(materialLoader) {
482
+ materialLoader.createColorInstance(Color.DarkGray, roughness = 0.9f)
483
+ }
484
+ PlaneNode(size = Size(6f, 6f), materialInstance = floorMat)
485
+
486
+ // Bouncing spheres
487
+ for (ball in balls) {
488
+ val mat = remember(materialLoader, ball.color) {
489
+ materialLoader.createColorInstance(ball.color, roughness = 0.4f)
490
+ }
491
+ SphereNode(
492
+ radius = 0.15f,
493
+ materialInstance = mat,
494
+ position = Position(x = ball.x, y = ball.y, z = 0f)
495
+ )
496
+ }
497
+ }
498
+ // Bounciness slider
499
+ Row(
500
+ modifier = Modifier.fillMaxWidth().padding(16.dp),
501
+ verticalAlignment = Alignment.CenterVertically
502
+ ) {
503
+ Text("Bounciness: \${String.format("%.1f", restitution)}")
504
+ Slider(
505
+ value = restitution,
506
+ onValueChange = { restitution = it },
507
+ valueRange = 0f..1f,
508
+ modifier = Modifier.weight(1f).padding(start = 8.dp)
509
+ )
510
+ }
416
511
  }
417
512
  }`,
418
513
  },
419
514
  "dynamic-sky": {
420
515
  id: "dynamic-sky",
421
- title: "Dynamic Sky",
422
- description: "Time-of-day sun cycle with DynamicSkyNode and atmospheric fog via FogNode.",
423
- tags: ["3d", "sky", "fog", "environment"],
424
- dependency: "io.github.sceneview:sceneview:3.3.0",
425
- prompt: "Create a 3D scene with a time-of-day sun that moves from sunrise through noon to sunset, with atmospheric fog. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
516
+ title: "Dynamic Sky & Lighting",
517
+ description: "Time-of-day sun cycle with animated LightNode direction, intensity, and color to simulate sunrise through sunset.",
518
+ tags: ["3d", "sky", "environment", "animation", "lighting"],
519
+ dependency: "io.github.sceneview:sceneview:3.4.7",
520
+ prompt: "Create a 3D scene with a time-of-day sun that moves from sunrise through noon to sunset, with animated light color and intensity. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
426
521
  code: `@Composable
427
522
  fun DynamicSkyScreen() {
428
523
  val engine = rememberEngine()
429
524
  val modelLoader = rememberModelLoader(engine)
525
+ val materialLoader = rememberMaterialLoader(engine)
526
+ val environmentLoader = rememberEnvironmentLoader(engine)
430
527
  var timeOfDay by remember { mutableFloatStateOf(12f) }
431
528
 
432
- Scene(
433
- modifier = Modifier.fillMaxSize(),
434
- engine = engine,
435
- modelLoader = modelLoader
436
- ) {
437
- DynamicSkyNode(
438
- timeOfDay = timeOfDay,
439
- turbidity = 2f,
440
- sunIntensity = 110_000f
441
- )
529
+ // Compute sun angle and color from time of day
530
+ val sunAngle = remember(timeOfDay) {
531
+ val normalized = (timeOfDay - 6f) / 12f // 6am=0, 18pm=1
532
+ normalized.coerceIn(0f, 1f) * Math.PI.toFloat()
533
+ }
534
+ val sunIntensity = remember(timeOfDay) {
535
+ val noon = 1f - abs(timeOfDay - 12f) / 6f
536
+ (noon.coerceIn(0.1f, 1f) * 110_000f)
537
+ }
538
+
539
+ Column {
540
+ Scene(
541
+ modifier = Modifier.weight(1f).fillMaxWidth(),
542
+ engine = engine,
543
+ modelLoader = modelLoader,
544
+ cameraManipulator = rememberCameraManipulator(
545
+ orbitHomePosition = Position(x = 0f, y = 2f, z = 6f),
546
+ targetPosition = Position(0f, 0f, 0f)
547
+ ),
548
+ environment = rememberEnvironment(environmentLoader) {
549
+ environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
550
+ ?: createEnvironment(environmentLoader)
551
+ }
552
+ ) {
553
+ // Animated sun light — position and color change with time
554
+ LightNode(
555
+ type = LightManager.Type.SUN,
556
+ apply = {
557
+ // Warm at sunrise/sunset, neutral at noon
558
+ val warmth = abs(timeOfDay - 12f) / 6f
559
+ color(1.0f, 1.0f - warmth * 0.3f, 1.0f - warmth * 0.5f)
560
+ intensity(sunIntensity)
561
+ castShadows(true)
562
+ },
563
+ position = Position(
564
+ x = cos(sunAngle) * 5f,
565
+ y = sin(sunAngle) * 5f,
566
+ z = 0f
567
+ )
568
+ )
442
569
 
443
- rememberModelInstance(modelLoader, "models/scene.glb")?.let { instance ->
444
- ModelNode(modelInstance = instance)
570
+ // Ground
571
+ val floorMat = remember(materialLoader) {
572
+ materialLoader.createColorInstance(Color(0.3f, 0.5f, 0.2f), roughness = 0.9f)
573
+ }
574
+ PlaneNode(size = Size(20f, 20f), materialInstance = floorMat)
575
+
576
+ // Scene model
577
+ rememberModelInstance(modelLoader, "models/scene.glb")?.let { instance ->
578
+ ModelNode(modelInstance = instance, scaleToUnits = 2f)
579
+ }
580
+ }
581
+
582
+ // Time of day slider
583
+ Row(
584
+ modifier = Modifier.fillMaxWidth().padding(16.dp),
585
+ verticalAlignment = Alignment.CenterVertically
586
+ ) {
587
+ Text("Time: \${String.format("%02d:%02d", timeOfDay.toInt(), ((timeOfDay % 1) * 60).toInt())}")
588
+ Slider(
589
+ value = timeOfDay,
590
+ onValueChange = { timeOfDay = it },
591
+ valueRange = 5f..19f,
592
+ modifier = Modifier.weight(1f).padding(start = 8.dp)
593
+ )
445
594
  }
446
595
  }
447
- // Add a Slider to control timeOfDay from 0 to 24
448
596
  }`,
449
597
  },
450
598
  "line-path": {
451
599
  id: "line-path",
452
600
  title: "Line & Path",
453
- description: "Animated 3D line art with sine waves, Lissajous curves, and parameter sliders.",
601
+ description: "Animated 3D line art with sine waves and Lissajous curves using PathNode and LineNode, with parameter sliders.",
454
602
  tags: ["3d", "lines", "geometry", "animation"],
455
- dependency: "io.github.sceneview:sceneview:3.3.0",
456
- prompt: "Create a 3D scene that draws animated parametric curves (sine wave, Lissajous) using PathNode with amplitude and frequency sliders. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
603
+ dependency: "io.github.sceneview:sceneview:3.4.7",
604
+ prompt: "Create a 3D scene that draws animated parametric curves (sine wave, Lissajous) using PathNode with amplitude and frequency sliders. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
457
605
  code: `@Composable
458
606
  fun LinePathScreen() {
459
607
  val engine = rememberEngine()
@@ -461,51 +609,124 @@ fun LinePathScreen() {
461
609
  var amplitude by remember { mutableFloatStateOf(1f) }
462
610
  var frequency by remember { mutableFloatStateOf(2f) }
463
611
 
464
- val points = remember(amplitude, frequency) {
612
+ val sinePoints = remember(amplitude, frequency) {
465
613
  (0..200).map { i ->
466
614
  val t = i / 200f * Math.PI.toFloat() * 4
467
615
  Position(x = t * 0.5f - 3f, y = sin(t * frequency) * amplitude, z = 0f)
468
616
  }
469
617
  }
618
+ val lissajousPoints = remember(amplitude, frequency) {
619
+ (0..300).map { i ->
620
+ val t = i / 300f * Math.PI.toFloat() * 2
621
+ Position(
622
+ x = sin(t * 3f) * amplitude,
623
+ y = sin(t * frequency) * amplitude,
624
+ z = cos(t * 2f) * 0.5f
625
+ )
626
+ }
627
+ }
628
+
629
+ Column {
630
+ Scene(
631
+ modifier = Modifier.weight(1f).fillMaxWidth(),
632
+ engine = engine,
633
+ cameraManipulator = rememberCameraManipulator(
634
+ orbitHomePosition = Position(x = 0f, y = 1f, z = 5f),
635
+ targetPosition = Position(0f, 0f, 0f)
636
+ )
637
+ ) {
638
+ // Sine wave path (cyan)
639
+ val cyanMat = remember(materialLoader) {
640
+ materialLoader.createColorInstance(Color.Cyan)
641
+ }
642
+ PathNode(
643
+ points = sinePoints,
644
+ materialInstance = cyanMat
645
+ )
646
+
647
+ // Lissajous curve (magenta)
648
+ val magentaMat = remember(materialLoader) {
649
+ materialLoader.createColorInstance(Color.Magenta)
650
+ }
651
+ PathNode(
652
+ points = lissajousPoints,
653
+ closed = true,
654
+ materialInstance = magentaMat
655
+ )
656
+
657
+ // Axis lines
658
+ val grayMat = remember(materialLoader) {
659
+ materialLoader.createColorInstance(Color.Gray)
660
+ }
661
+ LineNode(start = Position(-3f, 0f, 0f), end = Position(3f, 0f, 0f), materialInstance = grayMat)
662
+ LineNode(start = Position(0f, -2f, 0f), end = Position(0f, 2f, 0f), materialInstance = grayMat)
663
+ }
470
664
 
471
- Scene(modifier = Modifier.fillMaxSize(), engine = engine, materialLoader = materialLoader) {
472
- val path = remember(engine, points) {
473
- PathNode(engine = engine, points = points)
665
+ // Parameter sliders
666
+ Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
667
+ Text("Amplitude: \${String.format("%.1f", amplitude)}")
668
+ Slider(value = amplitude, onValueChange = { amplitude = it }, valueRange = 0.1f..3f)
669
+ Text("Frequency: \${String.format("%.1f", frequency)}")
670
+ Slider(value = frequency, onValueChange = { frequency = it }, valueRange = 0.5f..5f)
474
671
  }
475
- Node(node = path)
476
672
  }
477
- // Add Sliders for amplitude and frequency
478
673
  }`,
479
674
  },
480
675
  "text-labels": {
481
676
  id: "text-labels",
482
677
  title: "Text Labels",
483
- description: "Camera-facing 3D text labels (TextNode + BillboardNode) with interactive label cycling.",
678
+ description: "Camera-facing 3D text labels using TextNode floating labels above geometry spheres representing planets.",
484
679
  tags: ["3d", "text", "geometry"],
485
- dependency: "io.github.sceneview:sceneview:3.3.0",
486
- prompt: "Create a 3D scene with floating text labels that always face the camera. Labels show planet names and can be tapped to cycle display modes. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
680
+ dependency: "io.github.sceneview:sceneview:3.4.7",
681
+ prompt: "Create a 3D scene with floating text labels above colored spheres representing planets. Use TextNode for the labels. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
487
682
  code: `@Composable
488
683
  fun TextLabelsScreen() {
489
684
  val engine = rememberEngine()
490
685
  val materialLoader = rememberMaterialLoader(engine)
491
- var cameraPos by remember { mutableStateOf(Position()) }
686
+ val environmentLoader = rememberEnvironmentLoader(engine)
687
+
688
+ data class Planet(val name: String, val color: Color, val x: Float)
689
+ val planets = listOf(
690
+ Planet("Earth", Color.Blue, -1.5f),
691
+ Planet("Mars", Color.Red, 0f),
692
+ Planet("Venus", Color(1f, 0.8f, 0.3f), 1.5f)
693
+ )
492
694
 
493
695
  Scene(
494
696
  modifier = Modifier.fillMaxSize(),
495
697
  engine = engine,
496
- materialLoader = materialLoader,
497
- onFrame = { cameraPos = cameraNode.worldPosition }
698
+ cameraManipulator = rememberCameraManipulator(
699
+ orbitHomePosition = Position(x = 0f, y = 1.5f, z = 5f),
700
+ targetPosition = Position(0f, 0.5f, 0f)
701
+ ),
702
+ environment = rememberEnvironment(environmentLoader) {
703
+ environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
704
+ ?: createEnvironment(environmentLoader)
705
+ },
706
+ mainLightNode = rememberMainLightNode(engine) { intensity = 100_000f }
498
707
  ) {
499
- TextNode(
500
- materialLoader = materialLoader,
501
- text = "Earth",
502
- fontSize = 48f,
503
- textColor = android.graphics.Color.WHITE,
504
- backgroundColor = 0xCC000000.toInt(),
505
- widthMeters = 0.6f,
506
- heightMeters = 0.2f,
507
- cameraPositionProvider = { cameraPos }
508
- )
708
+ for (planet in planets) {
709
+ // Planet sphere
710
+ val mat = remember(materialLoader, planet.color) {
711
+ materialLoader.createColorInstance(planet.color, roughness = 0.6f)
712
+ }
713
+ SphereNode(
714
+ radius = 0.3f,
715
+ materialInstance = mat,
716
+ position = Position(x = planet.x, y = 0.3f, z = 0f)
717
+ )
718
+
719
+ // Text label above the planet
720
+ TextNode(
721
+ text = planet.name,
722
+ fontSize = 48f,
723
+ textColor = android.graphics.Color.WHITE,
724
+ backgroundColor = 0xCC000000.toInt(),
725
+ widthMeters = 0.6f,
726
+ heightMeters = 0.2f,
727
+ position = Position(x = planet.x, y = 0.9f, z = 0f)
728
+ )
729
+ }
509
730
  }
510
731
  }`,
511
732
  },
@@ -514,8 +735,8 @@ fun TextLabelsScreen() {
514
735
  title: "Reflection Probe",
515
736
  description: "Zone-based IBL overrides with material picker (Chrome, Gold, Copper, Rough) and probe toggle.",
516
737
  tags: ["3d", "reflection", "environment", "model"],
517
- dependency: "io.github.sceneview:sceneview:3.3.0",
518
- prompt: "Create a 3D scene with a metallic sphere and a ReflectionProbeNode that overrides the IBL. Add a material picker to switch between Chrome, Gold, Copper, and Rough. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
738
+ dependency: "io.github.sceneview:sceneview:3.4.7",
739
+ prompt: "Create a 3D scene with a metallic sphere and a ReflectionProbeNode that overrides the IBL. Add a material picker to switch between Chrome, Gold, Copper, and Rough. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
519
740
  code: `@Composable
520
741
  fun ReflectionProbeScreen() {
521
742
  val engine = rememberEngine()
@@ -550,8 +771,8 @@ fun ReflectionProbeScreen() {
550
771
  title: "Post-Processing",
551
772
  description: "Real-time post-processing effects: bloom, vignette, tone mapping, FXAA, and SSAO controls.",
552
773
  tags: ["3d", "post-processing", "environment"],
553
- dependency: "io.github.sceneview:sceneview:3.3.0",
554
- prompt: "Create a 3D scene with interactive post-processing controls for bloom, vignette, tone mapping, FXAA, and SSAO. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
774
+ dependency: "io.github.sceneview:sceneview:3.4.7",
775
+ prompt: "Create a 3D scene with interactive post-processing controls for bloom, vignette, tone mapping, FXAA, and SSAO. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
555
776
  code: `@Composable
556
777
  fun PostProcessingScreen() {
557
778
  val engine = rememberEngine()
@@ -578,8 +799,8 @@ fun PostProcessingScreen() {
578
799
  title: "Video Texture",
579
800
  description: "Video playback on a 3D plane using VideoNode with MediaPlayer — supports looping, chroma-key, and auto-sizing.",
580
801
  tags: ["3d", "video", "model"],
581
- dependency: "io.github.sceneview:sceneview:3.3.0",
582
- prompt: "Create a 3D scene with a video playing on a floating 3D plane. Include play/pause controls and chroma-key support. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
802
+ dependency: "io.github.sceneview:sceneview:3.4.7",
803
+ prompt: "Create a 3D scene with a video playing on a floating 3D plane. Include play/pause controls and chroma-key support. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
583
804
  code: `@Composable
584
805
  fun VideoTextureScreen() {
585
806
  val context = LocalContext.current
@@ -628,8 +849,8 @@ fun VideoTextureScreen() {
628
849
  title: "Multi-Model Scene",
629
850
  description: "Scene with multiple 3D models loaded independently, positioned and scaled to create a complete environment.",
630
851
  tags: ["3d", "model", "multi-model", "environment"],
631
- dependency: "io.github.sceneview:sceneview:3.3.0",
632
- prompt: "Create a 3D scene that loads multiple GLB models (a car, a building, and trees) and positions them to form a street scene. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
852
+ dependency: "io.github.sceneview:sceneview:3.4.7",
853
+ prompt: "Create a 3D scene that loads multiple GLB models (a car, a building, and trees) and positions them to form a street scene. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
633
854
  code: `@Composable
634
855
  fun MultiModelScreen() {
635
856
  val engine = rememberEngine()
@@ -694,8 +915,8 @@ fun MultiModelScreen() {
694
915
  title: "Gesture Interaction",
695
916
  description: "Full gesture handling — tap to select, double-tap to scale, long-press for info, pinch-to-scale, drag-to-move on editable nodes.",
696
917
  tags: ["3d", "gestures", "model"],
697
- dependency: "io.github.sceneview:sceneview:3.3.0",
698
- prompt: "Create a 3D scene with a model that responds to tap (select), double-tap (scale up), long-press (show info), and supports pinch-to-scale and drag-to-move. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
918
+ dependency: "io.github.sceneview:sceneview:3.4.7",
919
+ prompt: "Create a 3D scene with a model that responds to tap (select), double-tap (scale up), long-press (show info), and supports pinch-to-scale and drag-to-move. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
699
920
  code: `@Composable
700
921
  fun GestureInteractionScreen() {
701
922
  val engine = rememberEngine()
@@ -758,8 +979,8 @@ fun GestureInteractionScreen() {
758
979
  title: "Environment & Lighting",
759
980
  description: "Complete lighting setup — HDR environment (IBL + skybox), main directional light, point light, and spot light with LightNode.",
760
981
  tags: ["3d", "environment", "lighting", "model"],
761
- dependency: "io.github.sceneview:sceneview:3.3.0",
762
- prompt: "Create a 3D scene with full HDR environment lighting (IBL + skybox), a directional sun light, a red point light, and a blue spot light. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
982
+ dependency: "io.github.sceneview:sceneview:3.4.7",
983
+ prompt: "Create a 3D scene with full HDR environment lighting (IBL + skybox), a directional sun light, a red point light, and a blue spot light. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
763
984
  code: `@Composable
764
985
  fun EnvironmentLightingScreen() {
765
986
  val engine = rememberEngine()
@@ -827,8 +1048,8 @@ fun EnvironmentLightingScreen() {
827
1048
  title: "Procedural Geometry",
828
1049
  description: "Procedural shapes — CubeNode, SphereNode, CylinderNode, PlaneNode — with PBR materials (metallic, roughness, color).",
829
1050
  tags: ["3d", "geometry", "model"],
830
- dependency: "io.github.sceneview:sceneview:3.3.0",
831
- prompt: "Create a 3D scene showing procedural geometry shapes (cube, sphere, cylinder, plane) with different PBR materials. No model files needed. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
1051
+ dependency: "io.github.sceneview:sceneview:3.4.7",
1052
+ prompt: "Create a 3D scene showing procedural geometry shapes (cube, sphere, cylinder, plane) with different PBR materials. No model files needed. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
832
1053
  code: `@Composable
833
1054
  fun ProceduralGeometryScreen() {
834
1055
  val engine = rememberEngine()
@@ -907,8 +1128,8 @@ fun ProceduralGeometryScreen() {
907
1128
  title: "Compose UI in 3D",
908
1129
  description: "Embed interactive Jetpack Compose UI (Cards, Buttons, Text) inside 3D space using ViewNode.",
909
1130
  tags: ["3d", "compose-ui", "text"],
910
- dependency: "io.github.sceneview:sceneview:3.3.0",
911
- prompt: "Create a 3D scene with interactive Compose UI elements (Card with text and a button) floating in 3D space using ViewNode. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
1131
+ dependency: "io.github.sceneview:sceneview:3.4.7",
1132
+ prompt: "Create a 3D scene with interactive Compose UI elements (Card with text and a button) floating in 3D space using ViewNode. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
912
1133
  code: `@Composable
913
1134
  fun ComposeUI3DScreen() {
914
1135
  val engine = rememberEngine()
@@ -957,8 +1178,8 @@ fun ComposeUI3DScreen() {
957
1178
  title: "Node Hierarchy",
958
1179
  description: "Parent-child node relationships — a spinning solar system with planet groups orbiting a central sun.",
959
1180
  tags: ["3d", "hierarchy", "geometry", "animation"],
960
- dependency: "io.github.sceneview:sceneview:3.3.0",
961
- prompt: "Create a 3D solar system where planets orbit a sun using parent-child node hierarchies. Each planet group rotates independently. Use SceneView `io.github.sceneview:sceneview:3.3.0`.",
1181
+ dependency: "io.github.sceneview:sceneview:3.4.7",
1182
+ prompt: "Create a 3D solar system where planets orbit a sun using parent-child node hierarchies. Each planet group rotates independently. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
962
1183
  code: `@Composable
963
1184
  fun NodeHierarchyScreen() {
964
1185
  val engine = rememberEngine()
@@ -1038,7 +1259,7 @@ fun NodeHierarchyScreen() {
1038
1259
  title: "iOS 3D Model Viewer",
1039
1260
  description: "SwiftUI 3D scene with a USDZ model, IBL environment, orbit camera, and animation playback.",
1040
1261
  tags: ["3d", "model", "environment", "camera", "animation", "ios", "swift"],
1041
- dependency: "https://github.com/sceneview/sceneview — from: \"3.3.0\"",
1262
+ dependency: "https://github.com/sceneview/sceneview — from: \"3.4.7\"",
1042
1263
  spmDependency: "https://github.com/sceneview/sceneview",
1043
1264
  prompt: "Create a SwiftUI screen that loads a USDZ model and displays it with IBL lighting, orbit camera, and animation playback. Use SceneViewSwift.",
1044
1265
  language: "swift",
@@ -1077,7 +1298,7 @@ struct ModelViewerScreen: View {
1077
1298
  title: "iOS AR Tap-to-Place Model Viewer",
1078
1299
  description: "AR scene with plane detection. Tap a surface to place a 3D model using ARKit + RealityKit.",
1079
1300
  tags: ["ar", "model", "anchor", "plane-detection", "placement", "ios", "swift"],
1080
- dependency: "https://github.com/sceneview/sceneview — from: \"3.3.0\"",
1301
+ dependency: "https://github.com/sceneview/sceneview — from: \"3.4.7\"",
1081
1302
  spmDependency: "https://github.com/sceneview/sceneview",
1082
1303
  prompt: "Create an iOS AR screen that detects surfaces and lets the user tap to place a USDZ model. Use SceneViewSwift.",
1083
1304
  language: "swift",
@@ -1117,7 +1338,7 @@ struct ARModelViewerScreen: View {
1117
1338
  title: "iOS AR Augmented Image",
1118
1339
  description: "Detects reference images in the camera feed and overlays 3D content above them using ARKit.",
1119
1340
  tags: ["ar", "model", "image-tracking", "ios", "swift"],
1120
- dependency: "https://github.com/sceneview/sceneview — from: \"3.3.0\"",
1341
+ dependency: "https://github.com/sceneview/sceneview — from: \"3.4.7\"",
1121
1342
  spmDependency: "https://github.com/sceneview/sceneview",
1122
1343
  prompt: "Create an iOS AR screen that detects a printed reference image and places a 3D model above it. Use SceneViewSwift.",
1123
1344
  language: "swift",
@@ -1155,7 +1376,7 @@ struct AugmentedImageScreen: View {
1155
1376
  title: "iOS Procedural Geometry",
1156
1377
  description: "Procedural geometry shapes — cube, sphere, cylinder, cone, and plane — with PBR materials.",
1157
1378
  tags: ["3d", "geometry", "ios", "swift"],
1158
- dependency: "https://github.com/sceneview/sceneview — from: \"3.3.0\"",
1379
+ dependency: "https://github.com/sceneview/sceneview — from: \"3.4.7\"",
1159
1380
  spmDependency: "https://github.com/sceneview/sceneview",
1160
1381
  prompt: "Create a SwiftUI scene showing procedural geometry shapes (cube, sphere, cylinder, cone, plane) with different materials. Use SceneViewSwift.",
1161
1382
  language: "swift",
@@ -1209,7 +1430,7 @@ struct GeometryShapesScreen: View {
1209
1430
  title: "iOS Lighting",
1210
1431
  description: "Directional, point, and spot lights with configurable intensity, color, and shadows.",
1211
1432
  tags: ["3d", "lighting", "environment", "ios", "swift"],
1212
- dependency: "https://github.com/sceneview/sceneview — from: \"3.3.0\"",
1433
+ dependency: "https://github.com/sceneview/sceneview — from: \"3.4.7\"",
1213
1434
  spmDependency: "https://github.com/sceneview/sceneview",
1214
1435
  prompt: "Create a SwiftUI 3D scene with directional, point, and spot lights illuminating geometry. Use SceneViewSwift.",
1215
1436
  language: "swift",
@@ -1273,7 +1494,7 @@ struct LightingScreen: View {
1273
1494
  title: "iOS Physics Demo",
1274
1495
  description: "Interactive physics simulation with bouncing spheres, gravity, and configurable restitution.",
1275
1496
  tags: ["3d", "physics", "geometry", "ios", "swift"],
1276
- dependency: "https://github.com/sceneview/sceneview — from: \"3.3.0\"",
1497
+ dependency: "https://github.com/sceneview/sceneview — from: \"3.4.7\"",
1277
1498
  spmDependency: "https://github.com/sceneview/sceneview",
1278
1499
  prompt: "Create a SwiftUI 3D scene where tapping spawns coloured spheres that fall under gravity and bounce off a floor. Use SceneViewSwift.",
1279
1500
  language: "swift",
@@ -1337,7 +1558,7 @@ struct PhysicsDemoScreen: View {
1337
1558
  title: "iOS 3D Text Labels",
1338
1559
  description: "Camera-facing 3D text labels using TextNode and BillboardNode for always-facing-camera behavior.",
1339
1560
  tags: ["3d", "text", "geometry", "ios", "swift"],
1340
- dependency: "https://github.com/sceneview/sceneview — from: \"3.3.0\"",
1561
+ dependency: "https://github.com/sceneview/sceneview — from: \"3.4.7\"",
1341
1562
  spmDependency: "https://github.com/sceneview/sceneview",
1342
1563
  prompt: "Create a SwiftUI 3D scene with floating text labels that always face the camera, showing planet names. Use SceneViewSwift.",
1343
1564
  language: "swift",
@@ -1385,7 +1606,7 @@ struct TextLabelsScreen: View {
1385
1606
  title: "iOS Video on 3D Surface",
1386
1607
  description: "Video playback on a 3D plane using VideoNode with play/pause controls.",
1387
1608
  tags: ["3d", "video", "ios", "swift"],
1388
- dependency: "https://github.com/sceneview/sceneview — from: \"3.3.0\"",
1609
+ dependency: "https://github.com/sceneview/sceneview — from: \"3.4.7\"",
1389
1610
  spmDependency: "https://github.com/sceneview/sceneview",
1390
1611
  prompt: "Create a SwiftUI 3D scene with a video playing on a floating 3D plane. Include play/pause controls. Use SceneViewSwift.",
1391
1612
  language: "swift",
@@ -1448,6 +1669,344 @@ struct VideoPlayerScreen: View {
1448
1669
  }
1449
1670
  }
1450
1671
  }
1672
+ }`,
1673
+ },
1674
+ // ─── New Android Samples ──────────────────────────────────────────────
1675
+ "image-node": {
1676
+ id: "image-node",
1677
+ title: "Image Node",
1678
+ description: "Display images on 3D planes using ImageNode — from assets, resources, or Bitmaps.",
1679
+ tags: ["3d", "image", "geometry"],
1680
+ dependency: "io.github.sceneview:sceneview:3.4.7",
1681
+ prompt: "Create a 3D scene with images displayed on floating planes using ImageNode. Show examples from file, resource, and Bitmap. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
1682
+ code: `@Composable
1683
+ fun ImageNodeScreen() {
1684
+ val engine = rememberEngine()
1685
+ val environmentLoader = rememberEnvironmentLoader(engine)
1686
+
1687
+ Scene(
1688
+ modifier = Modifier.fillMaxSize(),
1689
+ engine = engine,
1690
+ cameraManipulator = rememberCameraManipulator(
1691
+ orbitHomePosition = Position(x = 0f, y = 1f, z = 4f),
1692
+ targetPosition = Position(0f, 0.5f, 0f)
1693
+ ),
1694
+ environment = rememberEnvironment(environmentLoader) {
1695
+ environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
1696
+ ?: createEnvironment(environmentLoader)
1697
+ },
1698
+ mainLightNode = rememberMainLightNode(engine) { intensity = 100_000f }
1699
+ ) {
1700
+ // Image from assets file
1701
+ ImageNode(
1702
+ imageFileLocation = "images/logo.png",
1703
+ size = Size(1f, 1f),
1704
+ position = Position(x = -1.2f, y = 0.5f, z = 0f)
1705
+ )
1706
+
1707
+ // Image from drawable resource
1708
+ ImageNode(
1709
+ imageResId = R.drawable.my_image,
1710
+ position = Position(x = 0f, y = 0.5f, z = 0f)
1711
+ )
1712
+
1713
+ // Image from Bitmap (e.g., dynamically generated)
1714
+ val bitmap = remember {
1715
+ Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888).apply {
1716
+ val canvas = android.graphics.Canvas(this)
1717
+ canvas.drawColor(android.graphics.Color.WHITE)
1718
+ val paint = Paint().apply {
1719
+ color = android.graphics.Color.BLUE
1720
+ textSize = 48f
1721
+ textAlign = Paint.Align.CENTER
1722
+ }
1723
+ canvas.drawText("SceneView", 128f, 140f, paint)
1724
+ }
1725
+ }
1726
+ ImageNode(
1727
+ bitmap = bitmap,
1728
+ size = Size(1f, 1f),
1729
+ position = Position(x = 1.2f, y = 0.5f, z = 0f)
1730
+ )
1731
+ }
1732
+ }`,
1733
+ },
1734
+ "billboard-sprite": {
1735
+ id: "billboard-sprite",
1736
+ title: "Billboard Sprite",
1737
+ description: "Always-facing-camera sprites using BillboardNode — useful for markers, icons, and info overlays in 3D space.",
1738
+ tags: ["3d", "billboard", "image"],
1739
+ dependency: "io.github.sceneview:sceneview:3.4.7",
1740
+ prompt: "Create a 3D scene with billboard sprites that always face the camera, useful for markers and info overlays. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
1741
+ code: `@Composable
1742
+ fun BillboardSpriteScreen() {
1743
+ val engine = rememberEngine()
1744
+ val modelLoader = rememberModelLoader(engine)
1745
+ val materialLoader = rememberMaterialLoader(engine)
1746
+ val environmentLoader = rememberEnvironmentLoader(engine)
1747
+ val context = LocalContext.current
1748
+
1749
+ // Create marker bitmaps
1750
+ val markerBitmap = remember {
1751
+ Bitmap.createBitmap(64, 64, Bitmap.Config.ARGB_8888).apply {
1752
+ val canvas = android.graphics.Canvas(this)
1753
+ val paint = Paint(Paint.ANTI_ALIAS_FLAG)
1754
+ paint.color = android.graphics.Color.RED
1755
+ canvas.drawCircle(32f, 32f, 28f, paint)
1756
+ paint.color = android.graphics.Color.WHITE
1757
+ paint.textSize = 32f
1758
+ paint.textAlign = Paint.Align.CENTER
1759
+ canvas.drawText("!", 32f, 44f, paint)
1760
+ }
1761
+ }
1762
+
1763
+ Scene(
1764
+ modifier = Modifier.fillMaxSize(),
1765
+ engine = engine,
1766
+ modelLoader = modelLoader,
1767
+ cameraManipulator = rememberCameraManipulator(
1768
+ orbitHomePosition = Position(x = 0f, y = 2f, z = 5f),
1769
+ targetPosition = Position(0f, 0.5f, 0f)
1770
+ ),
1771
+ environment = rememberEnvironment(environmentLoader) {
1772
+ environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
1773
+ ?: createEnvironment(environmentLoader)
1774
+ },
1775
+ mainLightNode = rememberMainLightNode(engine) { intensity = 100_000f }
1776
+ ) {
1777
+ // A model with billboard markers above it
1778
+ rememberModelInstance(modelLoader, "models/damaged_helmet.glb")?.let { instance ->
1779
+ ModelNode(modelInstance = instance, scaleToUnits = 1.0f)
1780
+ }
1781
+
1782
+ // Billboard markers that always face the camera
1783
+ BillboardNode(
1784
+ bitmap = markerBitmap,
1785
+ widthMeters = 0.3f,
1786
+ heightMeters = 0.3f,
1787
+ position = Position(x = 0.5f, y = 1.2f, z = 0f)
1788
+ )
1789
+
1790
+ BillboardNode(
1791
+ bitmap = markerBitmap,
1792
+ widthMeters = 0.3f,
1793
+ heightMeters = 0.3f,
1794
+ position = Position(x = -0.5f, y = 0.8f, z = 0.3f)
1795
+ )
1796
+ }
1797
+ }`,
1798
+ },
1799
+ "animation-state": {
1800
+ id: "animation-state",
1801
+ title: "Animation State Machine",
1802
+ description: "Reactive animation driven by Compose state — switch between Idle, Walk, and Run animations on a character model.",
1803
+ tags: ["3d", "model", "animation"],
1804
+ dependency: "io.github.sceneview:sceneview:3.4.7",
1805
+ prompt: "Create a 3D scene with a character model that switches between Idle, Walk, and Run animations based on button clicks. Use animationName for state-driven animation. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
1806
+ code: `@Composable
1807
+ fun AnimationStateScreen() {
1808
+ val engine = rememberEngine()
1809
+ val modelLoader = rememberModelLoader(engine)
1810
+ val environmentLoader = rememberEnvironmentLoader(engine)
1811
+ var currentAnim by remember { mutableStateOf("Idle") }
1812
+
1813
+ Column {
1814
+ Scene(
1815
+ modifier = Modifier.weight(1f).fillMaxWidth(),
1816
+ engine = engine,
1817
+ modelLoader = modelLoader,
1818
+ cameraManipulator = rememberCameraManipulator(
1819
+ orbitHomePosition = Position(x = 0f, y = 1f, z = 3f),
1820
+ targetPosition = Position(0f, 0.8f, 0f)
1821
+ ),
1822
+ environment = rememberEnvironment(environmentLoader) {
1823
+ environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
1824
+ ?: createEnvironment(environmentLoader)
1825
+ },
1826
+ mainLightNode = rememberMainLightNode(engine) { intensity = 100_000f }
1827
+ ) {
1828
+ rememberModelInstance(modelLoader, "models/character.glb")?.let { instance ->
1829
+ ModelNode(
1830
+ modelInstance = instance,
1831
+ scaleToUnits = 1.5f,
1832
+ centerOrigin = Position(y = -1f),
1833
+ autoAnimate = false,
1834
+ animationName = currentAnim,
1835
+ animationLoop = true,
1836
+ animationSpeed = if (currentAnim == "Run") 1.5f else 1f
1837
+ )
1838
+ }
1839
+ }
1840
+
1841
+ // Animation controls
1842
+ Row(
1843
+ modifier = Modifier.fillMaxWidth().padding(16.dp),
1844
+ horizontalArrangement = Arrangement.SpaceEvenly
1845
+ ) {
1846
+ listOf("Idle", "Walk", "Run").forEach { anim ->
1847
+ Button(
1848
+ onClick = { currentAnim = anim },
1849
+ colors = ButtonDefaults.buttonColors(
1850
+ containerColor = if (currentAnim == anim)
1851
+ MaterialTheme.colorScheme.primary
1852
+ else
1853
+ MaterialTheme.colorScheme.surfaceVariant
1854
+ )
1855
+ ) {
1856
+ Text(anim)
1857
+ }
1858
+ }
1859
+ }
1860
+ }
1861
+ }`,
1862
+ },
1863
+ "spring-animation": {
1864
+ id: "spring-animation",
1865
+ title: "Spring Animation",
1866
+ description: "Smooth spring-based node animations using Compose animateFloatAsState with spring spec for natural motion.",
1867
+ tags: ["3d", "animation", "spring", "geometry"],
1868
+ dependency: "io.github.sceneview:sceneview:3.4.7",
1869
+ prompt: "Create a 3D scene with geometry nodes that animate position using spring physics via Compose's animateFloatAsState. Tap to toggle positions with springy motion. Use SceneView `io.github.sceneview:sceneview:3.4.7`.",
1870
+ code: `@Composable
1871
+ fun SpringAnimationScreen() {
1872
+ val engine = rememberEngine()
1873
+ val materialLoader = rememberMaterialLoader(engine)
1874
+ val environmentLoader = rememberEnvironmentLoader(engine)
1875
+ var expanded by remember { mutableStateOf(false) }
1876
+
1877
+ // Spring-animated positions
1878
+ val cubeX by animateFloatAsState(
1879
+ targetValue = if (expanded) -2f else -0.5f,
1880
+ animationSpec = spring(dampingRatio = 0.4f, stiffness = 200f)
1881
+ )
1882
+ val sphereY by animateFloatAsState(
1883
+ targetValue = if (expanded) 2f else 0.5f,
1884
+ animationSpec = spring(dampingRatio = 0.3f, stiffness = 150f)
1885
+ )
1886
+ val cylinderX by animateFloatAsState(
1887
+ targetValue = if (expanded) 2f else 0.5f,
1888
+ animationSpec = spring(dampingRatio = 0.5f, stiffness = 300f)
1889
+ )
1890
+ val uniformScale by animateFloatAsState(
1891
+ targetValue = if (expanded) 1.5f else 1f,
1892
+ animationSpec = spring(dampingRatio = 0.6f, stiffness = 250f)
1893
+ )
1894
+
1895
+ Column {
1896
+ Scene(
1897
+ modifier = Modifier.weight(1f).fillMaxWidth(),
1898
+ engine = engine,
1899
+ cameraManipulator = rememberCameraManipulator(
1900
+ orbitHomePosition = Position(x = 0f, y = 2f, z = 6f),
1901
+ targetPosition = Position(0f, 0.5f, 0f)
1902
+ ),
1903
+ environment = rememberEnvironment(environmentLoader) {
1904
+ environmentLoader.createHDREnvironment("environments/sky_2k.hdr")
1905
+ ?: createEnvironment(environmentLoader)
1906
+ },
1907
+ mainLightNode = rememberMainLightNode(engine) { intensity = 100_000f }
1908
+ ) {
1909
+ // Floor
1910
+ val floorMat = remember(materialLoader) {
1911
+ materialLoader.createColorInstance(Color.DarkGray, roughness = 0.9f)
1912
+ }
1913
+ PlaneNode(size = Size(8f, 8f), materialInstance = floorMat)
1914
+
1915
+ // Spring-animated cube
1916
+ val redMat = remember(materialLoader) {
1917
+ materialLoader.createColorInstance(Color.Red, metallic = 0.2f, roughness = 0.4f)
1918
+ }
1919
+ CubeNode(
1920
+ size = Size(0.4f * uniformScale),
1921
+ materialInstance = redMat,
1922
+ position = Position(x = cubeX, y = 0.3f * uniformScale, z = 0f)
1923
+ )
1924
+
1925
+ // Spring-animated sphere
1926
+ val blueMat = remember(materialLoader) {
1927
+ materialLoader.createColorInstance(Color.Blue, metallic = 0.8f, roughness = 0.1f)
1928
+ }
1929
+ SphereNode(
1930
+ radius = 0.3f * uniformScale,
1931
+ materialInstance = blueMat,
1932
+ position = Position(x = 0f, y = sphereY, z = 0f)
1933
+ )
1934
+
1935
+ // Spring-animated cylinder
1936
+ val greenMat = remember(materialLoader) {
1937
+ materialLoader.createColorInstance(Color.Green, metallic = 0.3f, roughness = 0.5f)
1938
+ }
1939
+ CylinderNode(
1940
+ radius = 0.2f * uniformScale,
1941
+ height = 0.6f * uniformScale,
1942
+ materialInstance = greenMat,
1943
+ position = Position(x = cylinderX, y = 0.3f * uniformScale, z = 0f)
1944
+ )
1945
+ }
1946
+
1947
+ Button(
1948
+ onClick = { expanded = !expanded },
1949
+ modifier = Modifier.align(Alignment.CenterHorizontally).padding(16.dp)
1950
+ ) {
1951
+ Text(if (expanded) "Contract" else "Expand")
1952
+ }
1953
+ }
1954
+ }`,
1955
+ },
1956
+ "ar-surface-cursor": {
1957
+ id: "ar-surface-cursor",
1958
+ title: "AR Surface Cursor",
1959
+ description: "AR scene with a center-screen reticle using HitResultNode that follows the detected surface.",
1960
+ tags: ["ar", "cursor", "plane-detection", "placement"],
1961
+ dependency: "io.github.sceneview:arsceneview:3.4.7",
1962
+ prompt: "Create an AR screen with a surface cursor (reticle) in the center of the screen that follows detected surfaces, using HitResultNode. Tap to place a model at the cursor position. Use SceneView `io.github.sceneview:arsceneview:3.4.7`.",
1963
+ code: `@Composable
1964
+ fun ARSurfaceCursorScreen() {
1965
+ val engine = rememberEngine()
1966
+ val modelLoader = rememberModelLoader(engine)
1967
+ val materialLoader = rememberMaterialLoader(engine)
1968
+ val view = LocalView.current
1969
+ val modelInstance = rememberModelInstance(modelLoader, "models/chair.glb")
1970
+ var placedAnchors by remember { mutableStateOf(listOf<Anchor>()) }
1971
+
1972
+ ARScene(
1973
+ modifier = Modifier.fillMaxSize(),
1974
+ engine = engine,
1975
+ modelLoader = modelLoader,
1976
+ planeRenderer = true,
1977
+ sessionConfiguration = { session, config ->
1978
+ config.depthMode = if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC))
1979
+ Config.DepthMode.AUTOMATIC else Config.DepthMode.DISABLED
1980
+ config.lightEstimationMode = Config.LightEstimationMode.ENVIRONMENTAL_HDR
1981
+ },
1982
+ onTouchEvent = { event, hitResult ->
1983
+ if (event.action == MotionEvent.ACTION_UP && hitResult != null) {
1984
+ placedAnchors = placedAnchors + hitResult.createAnchor()
1985
+ }
1986
+ true
1987
+ }
1988
+ ) {
1989
+ // Surface cursor — follows the center of the screen
1990
+ val cursorMat = remember(materialLoader) {
1991
+ materialLoader.createColorInstance(Color.White.copy(alpha = 0.6f))
1992
+ }
1993
+ HitResultNode(xPx = view.width / 2f, yPx = view.height / 2f) {
1994
+ CylinderNode(radius = 0.03f, height = 0.005f, materialInstance = cursorMat)
1995
+ }
1996
+
1997
+ // Placed models
1998
+ for (anchor in placedAnchors) {
1999
+ AnchorNode(anchor = anchor) {
2000
+ modelInstance?.let { instance ->
2001
+ ModelNode(
2002
+ modelInstance = instance,
2003
+ scaleToUnits = 0.5f,
2004
+ isEditable = true
2005
+ )
2006
+ }
2007
+ }
2008
+ }
2009
+ }
1451
2010
  }`,
1452
2011
  },
1453
2012
  // ── Web Samples (Kotlin/JS + Filament.js) ──────────────────────────────