Communitygithub.com

dembsky/PropMotion

Fähigkeit für Claude Code: Ein 3D-Objekt in Ihrer SwiftUI-App performen lassen. SceneKit-Bühne, gebackene Choreografie, handgewickelte Physik, echte Schatten.

Was ist PropMotion?

Diese Fähigkeit bietet eine Produktionslösung, um ein einzelnes 3D-Objekt als polierten Produktdarsteller in einer SwiftUI-App zu inszenieren. Sie nutzt eine transparente SceneKit-Bühne (SCNView), die nahtlos über SwiftUI-Layouts gelegt wird, und behandelt alle typischen Fallstricke: Schatten, die mit MSAA nicht funktionieren, Ruckler beim ersten Frame durch Metal-Pipeline-Kompilierung, und fehlerhafte Animationen durch falsche Keyframe-Interpolation. Die Fähigkeit enthält detaillierte Rezepte für Bühnenaufbau, Beleuchtung, gebackene Animationen, Physik ohne Engine, Gesten und Haptik, Sequenzierung mehrerer Bühnen sowie Referenzmaterial zu Kameraführung, Instancing und Schwärmen. Besonders nützlich ist die Integration mit Claude Code, um diese komplexen 3D-Setups schnell und fehlerfrei in ein SwiftUI-Projekt einzubinden, wobei die gesamte Choreografie als gebackene CAKeyframe-Animationen definiert wird.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add dembsky/PropMotion

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Was macht PropMotion?

Lassen Sie ein 3D-Objekt in Ihrer SwiftUI-App performen. Produktionsmuster für eine spezifische, häufige Aufgabe: Ein polierter Produktdarsteller auf einer transparenten SceneKit-Bühne – Auftritte, Abgänge, Würfe, Schatten, Haptik und die stillen Fallstricke, die Tage kosten.

Wann man SceneKit überhaupt verwendet

Seien Sie ehrlich über die Position des Frameworks:

  • SceneKit befindet sich im Wartungsmodus. Für neue Apps mit umfangreichen 3D-Anforderungen (Asset- Pipelines, USD/USDZ, AR, große Welten) bevorzugen Sie RealityKit.
  • SceneKit ist immer noch der schnellste Weg zu einem dekorativen 3D-Akteur in einer SwiftUI- App: Eine transparente SCNView fügt sich über jedes SwiftUI-Layout ein, Geometrie-Shader-Modifikatoren sind ein einzelner MSL-String, die CoreAnimation-Interop ist ausgereift, und alles hier läuft auf einfachen UIKit-Views ohne Session-Setup.
  • Wenn das 3D-Element ein einzelnes Heldenobjekt mit choreografierter Bewegung ist, sind die Rezepte dieser Fähigkeit direkt anwendbar. Wenn es sich um eine vollständige interaktive Welt handelt, halten Sie inne und ziehen Sie zuerst RealityKit in Betracht.

Das Kernrezept für die Bühne

Eine Bühne besteht aus: Transparente SCNView, ein @MainActor-Koordinator, der die Szenengrafik besitzt, eine Kamera auf Augenhöhe eines stehenden Betrachters, ein Drei-Licht-Rig plus ein dediziertes Schattenlicht, ein Kontakt-Blob und ein Schattenfänger. Der Darsteller agiert über gebackene Keyframe-Animationen.

struct ProductStage: UIViewRepresentable {
    let item: Item

    // Der Schlüssel darf sich NUR ändern, wenn sich die Szene sichtbar ändern muss.
    private var stateKey: String { "\(item.id)" }

    func makeCoordinator() -> Coordinator { Coordinator() }

    func makeUIView(context: Context) -> SCNView {
        let view = SCNView()
        view.backgroundColor = .clear   // die Bühne legt sich über SwiftUI
        view.isOpaque = false
        view.antialiasingMode = .multisampling4X
        view.scene = context.coordinator.buildScene()
        view.pointOfView = context.coordinator.cameraNode
        context.coordinator.install(item)
        context.coordinator.markState(stateKey)
        // First-Frame-Warm-up, Zwei-Schlüssel-Zündung: Shader außerhalb des
        // kritischen Pfads kompilieren, den Darsteller hinter der Bühne parken und den ersten
        // Auftritt sowohl durch eine minimale Verzögerung als auch durch den Abschluss von prepare gaten.
        context.coordinator.parkOffstage()
        if let scene = view.scene {
            view.prepare([scene]) { _ in
                DispatchQueue.main.async { context.coordinator.markPipelinesWarm() }
            }
        }
        context.coordinator.scheduleFirstEntrance()
        return view
    }

    func updateUIView(_ view: SCNView, context: Context) {
        // State-Key-Diffing: SwiftUI-Neu-Renderungen dürfen niemals Auftritte wiederholen.
        guard context.coordinator.stateKey != stateKey else { return }
        context.coordinator.markState(stateKey)
        context.coordinator.transition(to: item)
    }
}

Die Teile, in der Baureihenfolge:

  1. Transparente View-Flags (backgroundColor = .clear, isOpaque = false), MSAA 4x. Der Host-Bildschirm liefert den Hintergrund; die Szene hat keine Box.
  2. Der Koordinator besitzt die Node-Hierarchie, aufgeteilt in eine Node pro Bewegungs- aspekt (Reise, Lift, Gieren, Drehung), sodass unabhängige Animationen nie um eine einzelne Transformation kämpfen.
  3. Kamera: projectionDirection = .horizontal, damit die Größe des Darstellers der Bühnenbreite folgt; erhöhte Position mit leichter Neigung nach unten wirkt wie ein stehender Beobachter. Halten Sie sie statisch; eine sich bewegende Kamera wirkt synthetisch.
  4. Lichter: warmes Key, kühles niedriges Fill, hartes Rim, Ambient nur als Bodenwert, plus ein separates schattenwerfendes Richtungslicht, das von hinten-oben auf den Darsteller gerichtet ist, damit es die sichtbare Skulptur nie stört.
  5. Bodenkontakt: Eine weiche, dunkle Verlaufsebene (der Kontakt-Blob) unter dem Darsteller plus eine unsichtbare .shadowOnly-Fängerebene für den echten Schatten.
  6. Reflektierende Materialien sampeln eine kleine programmatische Umgebungskarte, kein Foto. Halten Sie den Bereich hinter der Kamera dunkel.
  7. Die gesamte Choreografie besteht aus gebackenen CAKeyframeAnimations, geschützt durch Erzeugungs- Token, sodass jeder neue Schlag ausstehende Arbeiten überschreibt.

Vollständige Details mit Code: references/stage-recipe.md

Die Fallstricke, die am meisten Zeit kosten

FalleLösung
Deferred Shadows rendern nie, wenn MSAA aktiviert ist, ohne KonsolenfehlerVerwenden Sie shadowMode = .forward plus einen .shadowOnly-Fänger. Debuggen Sie fehlende Schatten, indem Sie der Szene zuerst einen sichtbaren grauen Lambert-Boden geben.
Der erste Frame einer frischen SCNView kompiliert Metal-Pipelines mitten in Ihrer Auftrittsanimationprepare([scene]) im Hintergrund, parken Sie den Darsteller hinter der Bühne, verzögern Sie den ersten Auftritt. Starten Sie nie eine Animation in Frame eins.
fillMode = .forwards + isRemovedOnCompletion = false fixiert die Darstellung, und die Entfernung ist pro ObjektEine zentrale clearAnimations, die die Node, jede untergeordnete Geometrie, die Lichter und laufende Aktionen säubert, aufgerufen von jedem Einstiegspunkt.
Frontalansicht von echtem Metall rendert als graues oder schwarzes LochEin frontal betrachteter Spiegel reflektiert den Umgebungsbereich hinter der Kamera. Behalten Sie die genehmigte bemalte Basis bei und fügen Sie eine dünne additive Schicht mit eigener Reflexionskarte hinzu.
Umschalten von castsShadow erzeugt einen weichgezeichneten Halbschatten in einem Frame; shadowBias und der categoryBitMask des Lichts werden bei Forward-Directional-Schatten ignoriertLassen Sie castsShadow dauerhaft eingeschaltet und animieren Sie den shadowColor-Alpha, synchronisiert mit der Bewegung.
Eine feste Aufwärmverzögerung ruckelt immer noch auf kalten Geräten und dem Simulator; der erste Frame eines Partikeleffekts kompiliert seine eigene Pipeline und fällt genau dann aus, wenn er feuertZwei-Schlüssel-Zündung: Gaten Sie den Auftritt durch die minimale Verzögerung UND den Abschluss-Handler von prepare. Wärmen Sie Partikel-Pipelines mit einem Burst ohne Deckkraft auf, der die Flags des echten Effekts entspricht.
Das Standardformat von UIGraphicsImageRenderer übernimmt die Bildschirmskalierung und bläht jede generierte Textur 9-fach in Pixeln auf – tödlich für Texturen, die live neu gerendert werden (per-Tastendruck-Gravur)Setzen Sie die Skalierung des Renderer-Formats auf 1 und dimensionieren Sie die Leinwand auf die projizierte Darstellung des Darstellers; fassen Sie Multi-Input-Neuzielungen zu einem Render pro Update-Durchlauf zusammen.
Die Nachbildung der Bewegung eines realen Objekts aus Fotos ergibt zuversichtliche Rigs, die seitlich versagen – jede Korrektur offenbart ein neues ProblemStandbilder enthalten Posen, keine Pfade oder Mechanismen; Endposenanpassungen bestimmen nicht die Flugbahn. Modellieren Sie den Pfad: Ein Kalibrierungs-Rig mit direkten Steuerelementen für Posen, der Ersteller erstellt Keyframes am physischen Objekt.
Eine keyframe-basierte Bewegung ruckelt rhythmisch an den Keyframes und überlebt jede Rendering- und Timing-KorrekturDie Ruckler sind in die Kurve eingebrannt: Die gleichmäßige Catmull-Rom-Basis auf ungleichmäßig verteilten Keyframes ändert die Geschwindigkeit an jedem Knoten. Interpolieren Sie mit spannen-gewichteten Hermite-Tangenten (oder einem natürlichen Kubik) über distanzbasierte Phasen und gaten Sie mit einer numerischen Kontinuitätsprüfung.
Ein aus einem größeren Modell ausgeschnittenes Sub-Mesh wird gemessen, als wäre es das gesamte Objekt, ohne FehlermeldungDer Schnitt hat nur den Indexbuffer getrimmt; der Vertexbuffer enthält immer noch jeden Vertex des Originals. Messen Sie nur Vertices, die von den Submesh-Indizes referenziert werden.
Ein quadratisches Bild, das scene.lightingEnvironment zugewiesen wird, wird still ignoriert – Null-Reflexionen, jedes Spiegelmaterial rendert schwarz, keine KonsolenausgabeMalen Sie die Umgebungskarte in einem erkannten Cube-Map-Layout, am einfachsten einer 2:1 sphärischen Leinwand (1024x512). Nur material.reflective akzeptiert eine quadratische Spheremap.

Referenzkarte

  • references/stage-recipe.md: Die vollständige Bühne, View-Setup, Koordinator, Node-Hierarchie, Kamera, Beleuchtungs-Rig, Kontakt-Blob und -Fänger, programmatische Umgebungskarten und Texturen, Aufprallpartikel auf einer Bühne, Shader-Modifikatoren auf Bühnenakteuren (die Linear-Space-Uniform- Falle), Aufrechterhaltung der SwiftUI-Identität der Bühne (Remount- und Update-Sturm- Fallen).
  • references/first-frame-and-warmup.md: Der Metal-Pipeline-Kompilierungs-Ruckler beim ersten Zeichnen und beide Heilmittel, Aufwärmen mit einem verzögerten Auftritt (aktualisiert auf Zwei-Schlüssel-Zündung, gegatet durch den Abschluss von prepare), oder das warme Halten der montierten Szene und deren Neuzielung; Partikel-Pipeline-Aufwärmen; Nachweis der Heilung mit Wegweisern und Ruckler-Traces auf dem Gerät.
  • references/shadows-and-lights.md: Jede stille Schattenfalle, die zuverlässige forward + shadowOnly-Kombination, Animieren der Schattensichtbarkeit, das neutrale Lichtbudget, frontal angesehenes Metall.
  • references/baked-animation.md: Warum gebackene Keyframes Timer schlagen, das Cue-Sheet zum Entwerfen mehrphasiger Beats vor dem Backen, Naht-Klassifizierung (C1 vs. Kontaktimpulse), Entwerfen von Gewicht, dichtes Sampling, Bereinigungs-Buchhaltung, Erzeugungs- Token, Stehlen einer Node mitten in der Animation, Rollen ohne Gleiten, Rollen entlang von Bodenpfaden (Lenkung, Bildschirmraum-Staging, Debug-Spuren), Kanäle jenseits von Transformationen (Morpher-Gewichte, Linsenwerte, Shader-Uniforms), Federn als Autorenmaterial, ein Eigentümer pro Eigenschaft.
  • references/motion-from-reference.md: Nachbildung der Bewegung eines realen Objekts – was Standbilder und Video Ihnen sagen können und was nicht, Modellierung des Pfads anstelle des Mechanismus, das Kalibrierungs-Rig (der Beszer posiert den Darsteller und speichert Keyframes), Distanzparametrisierung und spannen-gewichtete Interpolation von handgespeicherten Posen, die gleichförmige Catmull-Rom-Falle, numerische Kontinuitätsgates, nahtlose Kosinus-Zustandsschleifen mit Ausgängen aus der aktuellen Phase, Messen von getrimmten Sub-Meshes.
  • references/physics-without-engine.md: Der handgewickelte Fixed-Step-Integrator, der in Keyframes gebacken wurde, Wände und Boden als einfache Zahlen, kontaktgesteuerte Haptik, ein Rim-Pivot-Umfallen und warum dies SCNPhysics für choreografierte Szenen schlägt.
  • references/gestures-and-haptics.md: Pan-to-Grab ohne Hit-Testing, weiche Klammern während des Haltens, Loslass-Geschwindigkeit, Aufprall-Haptik, inszenierte Beats, die live Finger überleben (begrenzte Wiederholungen, tokenisierte Polls, versteckte Darsteller-Gesten-Schutz, Stehlen schließt den Haltevertrag), Reduce Motion als Taxonomie, VoiceOver-Zugriff auf eine unsichtbare Bühne, Koexistenz mit SwiftUI-Gesten.
  • references/sequencing-stages.md: Regie über mehrere Bühnen als einen Film – eine Master-Clock mit Beats als Daten, Wandzeit-Drift-Fallen, Schnitte auf Bewegung nachdem der Abgang die Bühne räumt, Vormontieren der nächsten Bühne zum Aufwärmen, eine Bühne, die ihren eigenen Schnitt überlebt (verweilender Rauch), Neufestlegen der Timeline auf eine Benutzerinteraktion, eine Aufnahmeleitung, Überprüfen von Schnitten Frame für Frame.
  • references/modeling-actors.md: Aufbau glaubwürdiger Heldenobjekte aus Primitiven – reale Verhältnisse vor dem Augenmaß, Ringe für versenkte Flächen, Röhre-plus-Torus-Silhouetten, radiale Muster-Lesbarkeit, Instanz-Neigung für konkave Flächen, offene Lücken, Reliefmerkmale als Geometrie (niemals Farbe), satinierter Metall-Albedo auf dunklen Bühnen, Gaten von Darstellern, die als Dateien ankommen.
  • references/camera-choreography.md: Die Kamera als Darsteller – das Orbit-Rig, gebackene Enthüllungsflüge, Fokus, der dem Dolly folgt, Drag-Orbit mit Trägheit und Rückflug, SCNFloor- Reflexionen als Erdung, matter Staging unter Downlights, Constraints für Tracking-Rigs (und warum sie niemals auf den Darsteller gehen).
  • references/instancing-and-swarms.md: Dutzende Darsteller gleichzeitig – eine Geometrie für den Schwarm, Slot-basierte Haufen statt Physik, Parabeln rückwärts gelöst vom Landepunkt, Taumel zur Ruhepose überblendet, gesäte Zufälligkeit, Abstufung durch Planung, Budget-Notizen.
  • references/multi-actor-physics.md: Mehrere Darsteller in einer gebackenen Simulation – N Zustandsvektoren auf einer Uhr, paarweise Kollisionen (trennen, dann austauschen bei Annäherung), der Freeze-the-World-Griff, Hit-Testing, welchen Darsteller der Finger ausgewählt hat, Pro-Darsteller-Kontaktlisten für Quetschung und Haptik.

Review-Checkliste

Stellen Sie vor dem Ausliefern einer Bühne Folgendes sicher:

  • backgroundColor = .clear und isOpaque = false auf der SCNView; die Bühne fügt sich ohne sichtbare Box oder Naht ein.
  • Keine Animation startet im ersten Frame der View; prepare läuft und der erste Auftritt wird verzögert, oder die Szene wird warm montiert gehalten.
  • Schatten verwenden den Forward-Modus mit einem .shadowOnly-Fänger; nichts verlässt sich auf deferred shadows, shadowBias oder categoryBitMask-Gating.
  • Alpha-Textur-Ebenen (Labels, Decals) haben castsShadow = false, oder sie werfen quadratische Schatten.
  • Schattensichtbarkeitsänderungen rampen den shadowColor-Alpha; castsShadow wird zur Laufzeit nie umgeschaltet.
  • Wenn die Szene eine Textur farbtreu rendern muss, summiert sich ambient plus directional mal cos(incidence) zu neutral (1000) für eine flache Oberfläche; keine überstrahlten hellgrauen Töne.
  • Jedes Bild auf lightingEnvironment (oder background) verwendet ein erkanntes Cube-Map-Layout – 2:1 sphärisch, 6:1 oder 1:6 Streifen, oder sechs Bilder; ein quadratisches Bild dort wird still ignoriert und reflektierende Materialien rendern schwarz.
  • Jede asynchrone Fortsetzung (verzögerte Auftritte, geplante Haptik, verkettete Übergänge) erfasst ein Erzeugungs-Token und überprüft es vor dem Handeln erneut.
  • Jeder Code, der eine animierende Node stiehlt, snapshotet .presentation-Werte in das Modell, bevor removeAllAnimations aufgerufen wird.
  • Gebackene Animationen setzen das Modell auf die endgültige Pose vor addAnimation; nichts verlässt sich auf fillMode = .forwards ohne einen Bereinigungsdurchlauf.
  • Mehrphasige Beats haben einen Cue-Sheet-Kommentar über der Pose-Funktion, der der phasengrenzenden Struktur entspricht; Phasen- und Cue-Zeiten leben in dieser einen Struktur, niemals als Literale in der Sample-Schleife oder in geplanter Haptik. Jede Naht wird klassifiziert: Design-Nähte sind C1, Impuls-Nähte treten nur bei Kontaktereignissen auf und jede landet einen Cue.
  • Rollende Objekte koppeln die Drehung an Distanz geteilt durch Radius; nichts gleitet.
  • Von einem realen Objekt kopierte Bewegung wird als Keyframes durch ein Kalibrierungs-Rig erstellt (direkte Steuerelemente für Posen, gespeicherte Posen, das Auge des Besitzers),

…

[für die Übersetzung gekürzt]

Verwandte Skills