Best for
- Use when "add 3D", "WebGL hero", "React Three Fiber", or "scroll-driven 3D".
kensaurus/cursor-kenji/skills/enhance-web-web3d/SKILL.md
Add purposeful 3D/WebGL and scroll choreography to an existing site with Three.js/R3F, GSAP, or Motion. Use when "add 3D", "WebGL hero", "React Three Fiber", or "scroll-driven 3D". General UI polish → enhance-web-ui. Motion without 3D → enhance-motion.
Decision brief
Degree of freedom: MIXED. Fit and stack choice [HIGH freedom]; budget, fallbacks, SSR, and verify [LOW freedom — run exactly].
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/kensaurus/cursor-kenji --skill "skills/enhance-web-web3d"Inspect the Agent Skill "enhance-web-web3d" from https://github.com/kensaurus/cursor-kenji/blob/28a0bd8403c950f58ed063d47a858ee3493b0038/skills/enhance-web-web3d/SKILL.md at commit 28a0bd8403c950f58ed063d47a858ee3493b0038. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
1. Fit — does 3D serve comprehension/brand, or is it decoration? 2. Choose — minimal stack from the matrix; one system per property 3. Integrate — budget + reduced-motion + no-WebGL + ssr: false in the same change 4. Prove — mid-tier FPS, fallbacks, LCP not waiting on WebGL
Before touching any library, answer these. If you can't justify the effect, the right move is enhance-web-ui or enhance-web-landing, not WebGL.
Read the entry point, layout, and any existing animated component. Then record:
Map the page to one (rarely more than two) of these archetypes. Each has a different cost/benefit and a different stack.
GSAP is 100% free for all use since April 2025 (all former Club/bonus plugins — ScrollTrigger, SplitText, MorphSVG, etc. — included), so plugin licensing is no longer a reason to avoid it.
Permission review
The documentation asks the agent to read local files, directories, or repositories.
**Scan** — Read the codebase. Identify framework, rendering model (SSR /Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 98/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 9 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Surface router:
/uiux. You are here:enhance-web-web3d. Native iOS/Android (SwiftUI / Compose, no web layer) is out of scope — use Apple HIG / Material directly.
Degree of freedom: MIXED. Fit and stack choice [HIGH freedom]; budget, fallbacks, SSR, and verify [LOW freedom — run exactly].
Add Three.js / React Three Fiber scenes, GSAP scroll choreography, and physics motion to an existing web project — without rewriting it, breaking the build, blowing the performance budget, or shipping a blank canvas to users on weak devices or with WebGL disabled.
This is not a "drop a spinning cube on the homepage" skill. It audits the repo first, decides whether 3D actually serves the page, picks the smallest library combination that fits the existing stack, and ships the effect with fallbacks and reduced-motion support from the first commit.
For greenfield / from-scratch 3D library mechanics (raw Three.js scene setup, R3F primitives, shader authoring), this skill points you at the deeper references but stays focused on integrating into a live repo. For pure visual composition (no 3D) use
enhance-web-ui; for anti-slop landing pages useenhance-web-landing.
ssr: false in the same changeFit: cookware PDP; users decide from the pot shape — a viewer earns cost; a torus knot does not. Choose: Next.js + R3F + drei; Motion overlays; no GSAP (no scroll story). Integrate:
dynamic(..., { ssr: false }); poster as LCP;frameloop="demand"; Draco model. Prove: reduced-motion shows poster; WebGL-off shows the same; LCP unchanged.
enhance-web-ui; motion without 3D → enhance-motion; anti-slop landing → enhance-web-landingWhen applied to an existing project, follow this sequence. Never skip the audit and jump to code — that is how 3D ends up as a 4 MB hero nobody on mobile can load.
Before touching any library, answer these. If you can't justify the effect,
the right move is enhance-web-ui or enhance-web-landing, not WebGL.
<video>, an animated SVG, a CSS scroll effect, or a
high-quality image sequence often beats live WebGL. The DEV community lesson
holds: a scripted DOM/GSAP walkthrough can be under 40 KB gzip vs a
multi-MB MP4/GIF — reach for real WebGL only when interactivity or true 3D
depth is the point.prefers-reduced-motion user and a no-WebGL user see, you're not ready to
build.Anti-slop guardrail. A spinning torus knot, a particle field with no meaning, or a tilt-on-mouse card that fights scrolling are the 3D equivalent of the purple-gradient hero. Motion and depth must explain, demo, or brand — never just sparkle.
Read the entry point, layout, and any existing animated component. Then record:
FRAMEWORK: [Next.js (app/pages?) / Vite+React / Astro / Remix / SvelteKit / vanilla]
RENDER MODEL: [SSR / SSG / CSR — matters for hydration + dynamic import]
REACT?: [yes → R3F is on the table | no → vanilla three.js]
STYLING: [Tailwind v3/v4 / CSS modules / styled-components / vanilla]
BUILD TOOL: [Vite / Webpack / Turbopack / esbuild — affects code-split + worker setup]
EXISTING MOTION: [framer-motion/motion? GSAP? Lenis? CSS only?]
EXISTING 3D: [three? @react-three/fiber? drei? none?]
PERF BASELINE: [current LCP / bundle size / Lighthouse, if measurable]
ASSET PIPELINE: [is there a /public model dir? a CDN? Draco/KTX2 already set up?]
Check the dependency manifest before importing anything — reuse what's installed, match the installed major version (three, @react-three/fiber, gsap, motion vs framer-motion), and never hallucinate an import.
Search for prior art and guard comments:
rg -l "three|@react-three|gsap|ScrollTrigger|Lenis|framer-motion|\"motion\"" --type ts --type tsx package.json
rg -n "useGSAP|registerPlugin|<Canvas|useFrame|frameloop" src/
rg -n "prefers-reduced-motion|matchMedia|DO NOT|deprecated" src/
Map the page to one (rarely more than two) of these archetypes. Each has a different cost/benefit and a different stack.
| Opportunity | What it is | Earns its cost when | Default stack |
|---|---|---|---|
| Hero scene | First-fold 3D centerpiece | The product is visual/physical | Three.js or R3F + a light entrance tween |
| Product viewer / configurator | Rotate/zoom/customize a model | Users decide based on the object | R3F + drei (OrbitControls, Environment) |
| Scroll story (pinned) | Camera/model animates as you scroll | There's a narrative or process to reveal | GSAP ScrollTrigger (pin + scrub) driving the scene |
| Ambient background | Subtle depth behind content | Brand texture, low-distraction | Cheap shader / instanced particles, frameloop="demand" |
| Data viz in 3D | Globe, graph, point cloud | The data is inherently spatial | R3F + instancing; or 2D if it reads better flat |
| Micro-interaction | Hover/drag physics on a card | Delight on a key CTA | Motion / React Spring (often no Three.js at all) |
Rule: one focal 3D moment per page beats five. If everything moves, nothing is special — the same hierarchy logic as
enhance-web-uiapplies in three dimensions.
GSAP is 100% free for all use since April 2025 (all former Club/bonus plugins — ScrollTrigger, SplitText, MorphSVG, etc. — included), so plugin licensing is no longer a reason to avoid it.
| Use case | Recommended stack | Rationale |
|---|---|---|
| Marketing page, scroll-driven 3D | Three.js (or R3F) + GSAP ScrollTrigger + HTML/Motion overlays | GSAP owns scroll orchestration; clean layer separation |
| React app, interactive 3D viewer | R3F + drei + Motion | Declarative, state-driven, component-based |
| Timeline-choreographed sequences | R3F + GSAP (timeline in useGSAP) | GSAP timeline control over R3F objects |
| Physics-y drag / momentum / gestures | R3F + React Spring (@react-spring/three) | Spring physics feel natural |
| High-count particles / instances | Three.js + GSAP, InstancedMesh/BatchedMesh | Imperative control, minimal overhead |
| Smooth-scroll feel under GSAP | add Lenis (lenis / react-lenis) | Inertia scroll that ScrollTrigger can drive |
| Pure UI delight (no real 3D) | Motion or React Spring only | Don't pull in WebGL for a hover effect |
| Non-React repo | vanilla three.js + GSAP | R3F requires React; don't add React for one scene |
One animation system per property. GSAP or React Spring or Motion animating a given transform — never two on the same property. Coordinate by timing or split properties (GSAP drives position, Spring drives scale).
Pick the pattern that matches the stack from Phase 3. Full, current code lives in the foundation references (see Research & Foundation Skills); below are the load-bearing shapes and the integration glue.
Best for non-React repos and marketing sites. Three layers: a 3D layer (scene/camera/render loop), an animation layer (GSAP ScrollTrigger), and an HTML/UI overlay. The scene exposes refs (camera, key meshes); GSAP animates those refs on scroll; HTML sits on top.
// scroll.js — GSAP drives the scene's exposed refs
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
export function initScrollAnimations({ camera, model }) {
const tl = gsap.timeline({
scrollTrigger: { trigger: "#stage", start: "top top", end: "+=3000", scrub: 1, pin: true },
});
tl.to(camera.position, { x: 5, z: 10, onUpdate: () => camera.lookAt(0, 0, 0) })
.to(model.rotation, { y: Math.PI * 2 }, 0);
return () => tl.scrollTrigger?.kill(); // always return teardown
}
Best for React apps with interactive, state-driven 3D. <Canvas> holds the
scene; motion.div overlays carry HTML. Keep per-frame work in useFrame
mutating refs, never React state.
// Lazy-load the canvas so WebGL never blocks first paint / SSR
const Scene = dynamic(() => import("./Scene"), { ssr: false, loading: () => <Poster /> });
<Canvas camera={{ position: [0, 2, 5], fov: 45 }} dpr={[1, 1.5]} frameloop="demand">
<Suspense fallback={null}><Scene /></Suspense>
</Canvas>
R3F renders; GSAP choreographs. Create the timeline inside useGSAP (scoped,
auto-cleaned) and target the R3F object's .current.
import { useGSAP } from "@gsap/react";
useGSAP(() => {
const tl = gsap.timeline({ scrollTrigger: { trigger: ref.current, scrub: 1 } });
tl.to(groupRef.current.position, { y: 2, ease: "power2.inOut" });
}, { scope: ref }); // useGSAP reverts on unmount — handles Strict Mode double-invoke
@react-spring/three for drag/momentum/gesture feedback that should feel
weighty. Spring owns scale/position; nothing else touches those props.
WebGL is expensive and degrades hard on weak devices. Apply these from the first commit, not after a complaint.
Render loop
dpr={[1, 1.5]} (R3F) / renderer.setPixelRatio(Math.min(devicePixelRatio, 2)).frameloop="demand" + invalidate() on change; vanilla → only render when something changed or controls are active.IntersectionObserver stops the loop when the canvas leaves the viewport.useFrame — mutate refs. State in the loop forces 60 fps re-renders.Draw calls & geometry
InstancedMesh / BatchedMesh for repeated objects; merge static geometry.Assets
colorSpace (SRGBColorSpace).Modern renderer (optional, current)
import { WebGPURenderer } from "three/webgpu" ships one renderer with automatic WebGL2 fallback. Use forceWebGL: true to test the fallback path. No urgent migration if a WebGL2 app already runs smoothly.Main thread (advanced)
OffscreenCanvas + Web Worker to keep the main thread free for UI/INP.Cleanup
dispose() every geometry / material / texture / render target on unmount; renderer.dispose(). Kill GSAP tweens/ScrollTriggers (useGSAP does this for you).A 3D enhancement that breaks for some users is a regression, not an upgrade.
prefers-reduced-motion: disable scroll
scrub / auto-rotation / parallax, or swap to a static poster frame. Gate at
the source so the whole scene honors it.const reduce = typeof window !== "undefined"
&& window.matchMedia("(prefers-reduced-motion: reduce)").matches;
// reduce ? render static poster / no scrub : full experience
<video>/SVG that preserves the visual language and the
conversion path. Never a blank canvas.The most common way 3D breaks an existing app is server rendering and React Strict Mode.
dynamic(() => import("./Scene"), { ssr: false }). Guard any window/document access with a client check.useGSAP() from @gsap/react, not bare useEffect — it scopes
selectors and auto-reverts animations on unmount, surviving route changes and
Strict Mode's double-invoke. Never create tweens in the render body (a new
animation per re-render).lenis.on("scroll", ScrollTrigger.update) + ticker wiring so scroll position
stays in sync.| Pitfall | Fix |
|---|---|
| Two libraries animate the same property | One system per property; split or sequence |
React state mutated in useFrame | Mutate refs; lift state out of the loop |
| Scene renders every frame while idle/off-screen | frameloop="demand" + IntersectionObserver pause |
| GSAP tween created in render body | Wrap in useGSAP / contextSafe |
| Blank canvas on no-WebGL / slow device | Feature-detect + poster/video fallback |
| WebGL initialized on server | ssr: false dynamic import; window guards |
| Multi-MB model on the hero | Draco/KTX2 + lazy-load + poster + device-tier scene |
| Scroll jank under ScrollTrigger | scrub numeric (smoothing), Lenis, refs not state |
| Memory grows on route change | Dispose geometries/materials/textures + kill tweens |
| Parallax/tilt fights native scroll | Reduced-motion gate + clamp; don't hijack the wheel |
renderer.info / stats-gl); DPR capped.prefers-reduced-motion path verified (motion off / poster shown).forceWebGL + simulated failure) — graceful fallback, never blank.window is not defined, no hydration mismatch, no Strict Mode double-mount leak.three, @react-three/fiber, @react-three/drei, gsap, @gsap/react, motion/framer-motion, @react-spring/three, lenis).ssr: false), not narration.enhance-web-ui.enhance-web-landing.enhance-web-redesign.enhance-web-ux.design-motion / design-motion.Foundation / deeper mechanics (in this repo):
enhance-web-web3d — Three.js, R3F, shaders, particle systems (greenfield mechanics).design-motion — Framer Motion / Motion, GSAP, CSS animation patterns.design-motion — physics-y micro-interactions and delight.audit-performance — Core Web Vitals (LCP/INP/CLS), bundle analysis.audit-accessibility — reduced-motion, keyboard, screen-reader compliance.Current external anchors:
useGSAP() (@gsap/react) for React cleanup/Strict-Mode safety. https://gsap.com/resources/React/useFrame. https://r3f.docs.pmnd.rs/advanced/scaling-performanceforceWebGL to test. https://threejs.org/manual/en/webgpurenderer.htmluseGSAP cleanup, hydration safety. https://mirax.cc/articles/cinematic-3d-scroll-gsap-nextjs-react-three-fiberOffscreenCanvas/Web Worker + instancing for stable 60 FPS. https://www.krapton.com/blog/boosting-react-three-fiber-mobile-performance-in-2026-a-deep-dive-d6105cAdapted and generalized from the
web3d-integration-patternsmeta-skill in freshtechbro/claudedesignskills (and itsthreejs-webgl/gsap-scrolltrigger/react-three-fiber/motion-framer/react-spring-physicsfoundation skills) into an audit-first, repo-elevation skill in theenhance-web-*family.
Frequently asked questions
Degree of freedom: MIXED. Fit and stack choice [HIGH freedom]; budget, fallbacks, SSR, and verify [LOW freedom — run exactly].
The source record exposes this install command: npx skills add https://github.com/kensaurus/cursor-kenji --skill "skills/enhance-web-web3d". Inspect the command and pinned source before running it.
Static rules flagged read-files in the source; the page lists the matching lines and excerpts.
Alternatives
event4u-app/agent-config
Use BEFORE writing or editing any non-trivial UI — inventories components, design tokens, shadcn primitives, and reusable patterns into state.ui_audit. Hard gate for the ui directive set.
objectstack-ai/objectstack
Author ObjectStack UI metadata — Views (list/form/kanban/calendar/gantt), Apps (navigation), Pages (structured plus the HTML and React source-authoring tiers, ADR-0080/0081), Dashboards, Reports, Charts, Actions, and package Docs (`src/docs/*.md`). Use when the user is adding `*.view.ts` / `*.app.ts` / `*.dashboard.ts` / `*.action.ts` / `src/docs/*.md` files or designing a Studio-rendered UI surface, including dataset-bound dashboard/report widgets. Do not use for: data schema (see objectstack-d
fcakyon/claude-codex-settings
Guide for implementing smooth, native-feeling animations using React's View Transition API (`<ViewTransition>` component, `addTransitionType`, and CSS view transition pseudo-elements). Use this skill whenever the user wants to add page transitions, animate route changes, create shared element animations, animate enter/exit of components, animate list reorder, implement directional (forward/back) navigation animations, or integrate view transitions in Next.js. Also use when the user mentions view
yonatangross/orchestkit
json-render component catalog patterns for AI-safe generative UI. Define Zod-typed catalogs that constrain what AI can generate, use @json-render/shadcn for 36 pre-built components, optimize specs with YAML mode, and apply the three edit modes (patch/merge/diff) for progressive updates. Use when building AI-generated UIs, defining component catalogs, or integrating json-render into React/Vue/Svelte/React Native/Ink/Next.js projects.