npx claudepluginhub kyh/vibedgamesThis skill uses the workspace's default tool permissions.
Build interactive Three.js apps that run in browser and ship in an iOS native shell via Capacitor.
Guides integrating web frameworks like Next.js, React, Vue, Angular, Svelte with Capacitor for mobile apps via static exports. Use when converting web apps to hybrid native mobile.
Builds interactive 3D web scenes with Three.js using WebGL/WebGPU. Guides on scenes, cameras, renderers, geometries, materials, meshes, lights, animations, and OrbitControls.
Routes iOS graphics tasks to specialized skills for Metal/OpenGL migration, GLSL/HLSL shader conversion, RealityKit 3D/AR in SwiftUI, and display performance like ProMotion/VRR.
Share bugs, ideas, or general feedback.
Build interactive Three.js apps that run in browser and ship in an iOS native shell via Capacitor. This skill focuses on the integration boundary where most breakage happens: web build output, animation contracts, controls, and native sync/run workflow.
Treat the project as two systems that must agree:
Most failures happen when their contract is implicit. Make file paths, animation names, build output, and iOS package manager choices explicit and testable.
Before implementing, ask:
dist or www) and does Capacitor webDir match it?assets_index.json) instead of hardcoded strings?Core principles:
npm run build).public/ and load via absolute URLs (/assets/...).webDir: "dist".npx cap add ios --packagemanager SPM).npm run buildnpx cap sync iosnpx cap run ios or npx cap open iosFor command-level details, see references/capacitor-ios-spm-workflow.md.
Prefer this shape for minimal ambiguity:
index.html and src/* for app codepublic/assets/... for GLBs and JSON contractscapacitor.config.ts with webDir: "dist"If using Vite, keep all runtime fetches compatible with both browser and WKWebView:
fetch('/assets/assets_index.json')assets_index.jsonUse one source of truth:
animations[] entries with:
idle, walk, run)sourceClipName (exact AnimationClip.name)Runtime pattern:
sourceClipNameAnimationAction map keyed by app idSee references/threejs-animation-index-pattern.md.
Use OrbitControls and set mappings explicitly:
If product requires vertical-only pan, constrain target/camera translation after controls.update() each frame.
Do not silently change rotate/zoom semantics when adding this constraint.
Math.min(devicePixelRatio, 2).Use SPM by default with Capacitor 8+. For existing CocoaPods projects, migrate intentionally (assistant or recreate iOS platform).
After native-side changes or plugin changes, run npx cap sync ios again.
❌ Hardcoding clip names in UI handlers
Why bad: a renamed clip in GLB silently breaks buttons.
Better: map buttons from assets_index.json and resolve clip names once at startup.
❌ Mixing SPM and CocoaPods assumptions Why bad: dependency drift and broken Xcode project expectations. Better: choose one package manager per project; for modern setups prefer SPM.
❌ Running iOS without rebuilding web assets
Why bad: simulator shows stale JS/CSS and debugging becomes misleading.
Better: use scripts that always build before cap sync/cap run.
❌ Leaving control mappings implicit
Why bad: desktop and mobile interaction diverge from UX requirements.
Better: set mouseButtons and touches explicitly in code.
❌ Debugging native first for web contract errors Why bad: wastes time in Xcode when issue is usually missing JSON keys, bad paths, or unresolved clips. Better: add startup assertions/logs for index shape and clip resolution.
IMPORTANT: Do not produce identical viewers by default. Adjust implementation to the product intent:
Vary at least these dimensions intentionally:
Avoid converging on a single generic "orbit + three buttons" output when context calls for more.
references/capacitor-ios-spm-workflow.md
references/threejs-animation-index-pattern.md
references/gotchas.md
Three.js + Capacitor iOS succeeds when contracts are explicit and workflows are disciplined. Build a clear metadata contract, map controls intentionally, prefer SPM on modern Capacitor, and keep build/sync/run deterministic.