Skip to content
Mobile
Agent

cheatsheet

The **canonical, complete** API reference is [`docs/docs/cheatsheet-ios.md`](https://github.com/sceneview/sceneview/blob/main/docs/docs/cheatsheet-ios.md) in the repo — it carries every node factory, every view modifier, the environment presets, the Android↔Apple mapping table,

From plugin
sceneview
1.3k5 skills5 agents1 MCP

How it fires

How this agent gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.

Context preview

The summary Claude sees to decide when to auto-load this agent.

The **canonical, complete** API reference is [`docs/docs/cheatsheet-ios.md`](https://github.com/sceneview/sceneview/blob/main/docs/docs/cheatsheet-ios.md) in the repo — it carries every node factory, every view modifier, the environment presets, the Android↔Apple mapping table,

Agent definition

cheatsheet.md

SceneViewSwift cheat sheet (Apple platforms)

The **canonical, complete** API reference is [`docs/docs/cheatsheet-ios.md`](https://github.com/sceneview/sceneview/blob/main/docs/docs/cheatsheet-ios.md) in the repo — it carries every node factory, every view modifier, the environment presets, the Android↔Apple mapping table, and the iOS parity-status tables. **Read that file first.** This page is a quick extract of the most-used signatures, verified against `SceneViewSwift/Sources/SceneViewSwift/`.

Top-level views

| View | Platform | Demo | | --- | --- | --- | | `SceneView { … }` | iOS / macOS / visionOS | `ModelViewerDemo.swift` | | `ARSceneView(…)` | iOS only (ARKit) | `ARPlacementDemo.swift` |

`SceneView` — two initializers

// Declarative — @NodeBuilder result-builder
SceneView {
    GeometryNode.cube(size: 0.3, color: .red)
}

// Imperative — gives you the RealityKit root Entity
SceneView { root in
    root.addChild(model.entity)
}

`SceneView` modifiers

SceneView { … }
    .environment(.studio)        // IBL preset — see "Environment presets" below
    .cameraControls(.orbit)      // .orbit (default) | .pan | .firstPerson | native (iOS 18+): .none | .tilt | .dolly
    .onEntityTapped { entity in }
    .autoRotate(speed: 0.3)      // turntable
    .autoCenterContent(true)     // translate content centroid to orbit pivot
    .framingMargin(0.95)         // auto-fit padding; 1.15 default, 1.0 = bounding sphere tangent, < 1 tighter
    .contentInsets(EdgeInsets(top: 0, leading: 0, bottom: sheetHeight, trailing: 0))  // v4.53.0+, 3D SceneView only (not AR) — keep the subject clear of your sheet; view not resized, pose untouched when autoCenterContent(false)
    .cameraOrbit(azimuth: .pi / 5, elevation: .pi / 15)  // INITIAL orbit pose, radians (defaults 0, 30°)
    .cameraPose(pose)            // v4.27.0+ — continuous camera drive (SceneCameraPose, radians)
    .onCameraChanged { new in Task { @MainActor in pose = new } }  // v4.27.0+ — read-back after every change; the hop is required
    .cameraGesturesEnabled(false) // v4.27.0+ — freeze drag/pinch without handing the camera to Apple
    .onEntityTapHit { hit in }   // v4.27.0+ — tap + world position (bounds centre, not the surface point)
    .mainLight(.systemDefault)   // see LightSlot
    .fillLight(.systemDefault)
    .renderQuality(.default)     // .cinematic | .default | .performance
    .contentID(model == nil ? nil : selectedID)  // re-runs the content closure IN PLACE when the id changes

**Swapping the model: `.contentID(_:)`, never SwiftUI's `.id(_:)`.** The content closure runs once, when the scene is created. Change `.contentID(_:)` to show a different model, and do not wrap the `SceneView` in an `if let model` that unmounts it while the next one loads — put the spinner in an overlay. Both change the view's *identity*, so SwiftUI discards the `RealityView` and builds a new one, and a re-created `RealityView` on iOS 26 Simulator intermittently renders nothing at all — no model, no skybox — permanently (#3008). The id must change every time the closure would build something different, **including "loading" → "loaded"**, so make it an `Optional`: keyed on the selection alone it already sits at its final value while the model is still being fetched and the scene stays empty forever.

ZStack {
    SceneView { root in
        guard let model else { return }
        root.addChild(model.entity)
    }
    .contentID(model == nil ? nil : selectedID)

    if model == nil { ProgressView() }
}

Android needs no equivalent — its DSL content is re-read on recomposition.

The auto-fit fits the content's **bounding sphere** to the narrower frustum axis, then scales that distance by `framingMargin` — lower it to fill a tall portrait frame, but stay at or above ~`0.95` on an `autoRotate` scene or a long model clips at its broadside azimuth. `framingMargin` runs *inside* the auto-fit, so it is a **silent no-op under `.autoCenterContent(false)`**. Android's equivalent is `frameToContent(padding =)`, a fraction rather than a multiplier: `margin == 1 + padding` (iOS `1.15` = Android `0.15`). `cameraOrbit` seeds only the starting pose. Watch elevation: at the 60° vertical FOV the **30° default pitch puts the horizon on the top edge**, so a `showSkybox` environment shows no sky until you lower it.

`ARSceneView` (iOS)

ARSceneView(
    planeDetection: .horizontal,   // .horizontal | .vertical | .both | .none
    showPlaneOverlay: true,
    showCoachingOverlay: true,
    showPlacementReticle: true,   // continuous smoothed placement cursor (#894, opt-in)
    groundingShadows: true,       // contact shadows on tap-placed models (#894, DEFAULT ON — opt out with false; sync placement flow only)
    onTapOnPlane: { position, arView in /* place content */ }
)
    .onSessionStarted { arView in }
    .cameraExposure(0.0)           // EV stops — AR-only camera exposure (iOS-specific semantics)
    .onFrame { frame, arView in }  // (ARFrame, ARView)
    .mainLight(.systemDefault)
    .fillLight(.systemDefault)

Node factories — 3D

| Node | Factory | Notes | | --- | --- | --- | | `ModelNode` | `ModelNode.load("file.usdz")` | `async throws`. Then `.scaleToUnits(_:)`, `.centerOrigin(normalized:)` (apply before positioning), `.playAllAnimations()` | | `GeometryNode` | `.cube(size:color:)` `.sphere(radius:color:)` `.cylinder(radius:height:color:)` `.plane(width:depth:color:)` `.cone(height:radius:color:)` `.torus(...)` `.capsule(...)` | also `material: .pbr(...)` overloads; `unlit: Bool` for flat fill | | `LightNode` | `.directional(color:intensity:castsShadow:)` `.point(color:intensity:attenuationRadius:)` `.spot(color:intensity:innerAngle:outerAngle:)` | aim via `.position(_:)` / `.lookAt(_:)` | | `TextNode` | `TextNode(text:fontSize:color:depth:)` | `.centered()` | | `ImageNode` | `ImageNode.load("img.png")` | `async throws`; `width:` / `height:` | | `BillboardNode` | `BillboardNode(chil

Read more
Ships withsceneview

The AI-first 3D & AR SDK for Jetpack Compose, SwiftUI and the web. Declarative 3D and AR for app developers who want a model on screen, or in the room, without a game engine: Filament + ARCore on Android, RealityKit + ARKit on Apple, Filament.js + WebXR in

Get the whole plugin
Stats
1,346
Stars
248
Forks
Active
Maintenance
Kotlin
Language
Apache-2.0
License
4h ago
Last commit
4y ago
Created
5h ago
Added

Repo: sceneview/sceneview

Other agents on sceneview.

REGISTRY
Agent

REGISTRY

This directory ships the SceneView SDK as **agent skills** for AI coding assistants. Each skill is a self-contained `SKILL.md`…

migration
Agent

migration

This page covers the rewrites AI agents most often need when bringing existing Apple-platform 3D code onto SceneViewSwift. The…

recipes
Agent

recipes

**Do not improvise.** Every pattern below has a matching SwiftUI demo file in `samples/ios-demo/SceneViewDemo/Views/Demos/`. Read…