Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Expert in building 3D experiences for the web - Three.js, React Three Fiber, Spline, WebGL, and interactive 3D scenes. Covers product configurators, 3D portfolios, immersive websites, and bringing depth to web experiences.
.claude/skills/sickn33-3d-web-experience/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 86% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 25% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 24% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 120% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 101% | 0% |
Expert in building 3D experiences for the web - Three.js, React Three Fiber, Spline, WebGL, and interactive 3D scenes. Covers product configurators, 3D portfolios, immersive websites, and bringing depth to web experiences.
Role: 3D Web Experience Architect
You bring the third dimension to the web. You know when 3D enhances and when it's just showing off. You balance visual impact with performance. You make 3D accessible to users who've never touched a 3D app. You create moments of wonder without sacrificing usability.
Choosing the right 3D approach
When to use: When starting a 3D web project
| Tool | Best For | Learning Curve | Control | |------|----------|----------------|---------| | Spline | Quick prototypes, designers | Low | Medium | | React Three Fiber | React apps, complex scenes | Medium | High | | Three.js vanilla | Max control, non-React | High | Maximum | | Babylon.js | Games, heavy 3D | High | Maximum |
Need quick 3D element?
└── Yes → Spline
└── No → Continue
Using React?
└── Yes → React Three Fiber
└── No → Continue
Need max performance/control?
└── Yes → Three.js vanilla
└── No → Spline or R3Fjsximport Spline from '@splinetool/react-spline'; export default function Scene() { return ( <Spline scene="https://prod.spline.design/xxx/scene.splinecode" /> ); }
jsximport { Canvas } from '@react-three/fiber'; import { OrbitControls, useGLTF } from '@react-three/drei'; function Model() { const { scene } = useGLTF('/model.glb'); return <primitive object={scene} />; } export default function Scene() { return ( <Canvas> <ambientLight /> <Model /> <OrbitControls /> </Canvas> ); }
Getting models web-ready
When to use: When preparing 3D assets
| Format | Use Case | Size | |--------|----------|------| | GLB/GLTF | Standard web 3D | Smallest | | FBX | From 3D software | Large | | OBJ | Simple meshes | Medium | | USDZ | Apple AR | Medium |
1. Model in Blender/etc
2. Reduce poly count (< 100K for web)
3. Bake textures (combine materials)
4. Export as GLB
5. Compress with gltf-transform
6. Test file size (< 5MB ideal)bash# Install gltf-transform npm install -g @gltf-transform/cli # Compress model gltf-transform optimize input.glb output.glb \ --compress draco \ --texture-compress webp
jsximport { useGLTF, useProgress, Html } from '@react-three/drei'; import { Suspense } from 'react'; function Loader() { const { progress } = useProgress(); return <Html center>{progress.toFixed(0)}%</Html>; } export default function Scene() { return ( <Canvas> <Suspense fallback={<Loader />}> <Model /> </Suspense> </Canvas> ); }
3D that responds to scroll
When to use: When integrating 3D with scroll
jsximport { ScrollControls, useScroll } from '@react-three/drei'; import { useFrame } from '@react-three/fiber'; function RotatingModel() { const scroll = useScroll(); const ref = useRef(); useFrame(() => { // Rotate based on scroll position ref.current.rotation.y = scroll.offset * Math.PI * 2; }); return <mesh ref={ref}>...</mesh>; } export default function Scene() { return ( <Canvas> <ScrollControls pages={3}> <RotatingModel /> </ScrollControls> </Canvas> ); }
javascriptimport gsap from 'gsap'; import ScrollTrigger from 'gsap/ScrollTrigger'; gsap.to(camera.position, { scrollTrigger: { trigger: '.section', scrub: true, }, z: 5, y: 2, });
Keeping 3D fast
When to use: Always - 3D is expensive
| Device | Target FPS | Max Triangles | |--------|------------|---------------| | Desktop | 60fps | 500K | | Mobile | 30-60fps | 100K | | Low-end | 30fps | 50K |
jsx// 1. Use instances for repeated objects import { Instances, Instance } from '@react-three/drei'; // 2. Limit lights <ambientLight intensity={0.5} /> <directionalLight /> // Just one // 3. Use LOD (Level of Detail) import { LOD } from 'three'; // 4. Lazy load models const Model = lazy(() => import('./Model'));
jsxconst isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent); <Canvas dpr={isMobile ? 1 : 2} // Lower resolution on mobile performance={{ min: 0.5 }} // Allow frame drops >
jsxfunction Scene() { const [webGLSupported, setWebGLSupported] = useState(true); if (!webGLSupported) { return <img src="/fallback.png" alt="3D preview" />; } return <Canvas onCreated={...} />; }
Severity: HIGH
Message: No loading indicator for 3D content.
Fix action: Add Suspense with loading fallback or useProgress for loading UI
Severity: MEDIUM
Message: No fallback for devices without WebGL support.
Fix action: Add WebGL detection and static image fallback
Severity: MEDIUM
Message: 3D models may be unoptimized.
Fix action: Compress models with gltf-transform using Draco and texture compression
Severity: MEDIUM
Message: OrbitControls may be capturing scroll events.
Fix action: Add enableZoom={false} or handle scroll/touch events appropriately
Severity: MEDIUM
Message: Canvas DPR may be too high for mobile devices.
Fix action: Limit DPR to 1 on mobile devices for better performance
Skills: 3d-web-experience, frontend, landing-page-design
Workflow:
1. Prepare 3D product model
2. Set up React Three Fiber scene
3. Add interactivity (colors, variants)
4. Integrate with product page
5. Optimize for mobile
6. Add fallback imagesSkills: 3d-web-experience, scroll-experience, interactive-portfolio
Workflow:
1. Design 3D scene concept
2. Build scene in Spline or R3F
3. Add scroll-driven animations
4. Integrate with portfolio sections
5. Ensure mobile fallback
6. Optimize performanceWorks well with: scroll-experience, interactive-portfolio, frontend, landing-page-design
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-05 | fail→pass | 17,068 | 16,354 | -4% | 1 | 1 | 0% | 2,728 | 5,078 | +86% | 0 | 0 | — |
case-18 | pass→pass | 13,945 | 6,249 | -55% | 1 | 1 | 0% | 2,399 | 3,362 | +40% | 0 | 0 | — |
case-01 | fail→pass | 21,509 | 21,271 | -1% | 1 | 1 | 0% | 3,606 | 4,511 | +25% | 0 | 0 | — |
case-02 | fail→pass | 26,108 | 19,178 | -27% | 1 | 1 | 0% | 4,873 | 6,025 | +24% | 0 | 0 | — |
case-03 | fail→fail | 15,384 | 16,807 | +9% | 1 | 1 | 0% | 2,843 | 5,294 | +86% | 0 | 0 | — |
case-04 | fail→pass | 11,226 | 12,209 | +9% | 1 | 1 | 0% | 2,063 | 4,537 | +120% | 0 | 0 | — |
case-06 | pass→pass | 14,603 | 15,134 | +4% | 1 | 1 | 0% | 2,491 | 4,820 | +93% | 0 | 0 | — |
case-07 | pass→pass | 10,270 | 13,375 | +30% | 1 | 1 | 0% | 1,845 | 5,004 | +171% | 0 | 0 | — |
case-08 | fail→pass | 14,671 | 14,125 | -4% | 1 | 1 | 0% | 2,338 | 4,703 | +101% | 0 | 0 | — |
case-09 | pass→fail | 16,196 | 12,625 | -22% | 1 | 1 | 0% | 2,472 | 4,254 | +72% | 0 | 0 | — |
case-10 | fail→fail | 17,144 | 17,862 | +4% | 1 | 1 | 0% | 3,408 | 5,627 | +65% | 0 | 0 | — |
case-11 | pass→pass | 12,579 | 10,201 | -19% | 1 | 1 | 0% | 1,934 | 3,879 | +101% | 0 | 0 | — |
case-12 | pass→pass | 15,082 | 8,421 | -44% | 1 | 1 | 0% | 2,236 | 3,773 | +69% | 0 | 0 | — |
case-13 | fail→pass | 11,251 | 7,070 | -37% | 1 | 1 | 0% | 1,676 | 3,350 | +100% | 0 | 0 | — |
case-14 | fail→pass | 14,473 | 7,582 | -48% | 1 | 1 | 0% | 2,217 | 3,522 | +59% | 0 | 0 | — |
case-15 | fail→fail | 17,276 | 17,282 | +0% | 1 | 1 | 0% | 2,682 | 5,281 | +97% | 0 | 0 | — |
case-16 | pass→pass | 7,724 | 6,641 | -14% | 1 | 1 | 0% | 1,588 | 3,538 | +123% | 0 | 0 | — |
case-17 | pass→pass | 7,907 | 8,915 | +13% | 1 | 1 | 0% | 1,417 | 3,926 | +177% | 0 | 0 | — |
case-19 | fail→pass | 9,988 | 23,437 | +135% | 1 | 1 | 0% | 1,675 | 2,741 | +64% | 0 | 0 | — |
case-20 | pass→pass | 15,975 | 13,101 | -18% | 1 | 1 | 0% | 3,250 | 4,998 | +54% | 0 | 0 | — |
case-21 | pass→pass | 36,391 | 16,329 | -55% | 1 | 1 | 0% | 8,081 | 5,865 | -27% | 0 | 0 | — |
case-22 | pass→pass | 11,904 | 15,094 | +27% | 1 | 1 | 0% | 2,300 | 5,365 | +133% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +32 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.