Skip to main content

threejs-best-practices

Enforces @react-three/fiber and @react-three/drei best practices for Black Trigram, including proper Canvas setup, Korean-themed lighting, resource cleanup patterns, Html overlay vs 3D mesh decision guide, performance optimization (useFrame, useMemo), testing patterns, and common Three.js anti-patterns to avoid.

来源信息

仓库
Hack23/blacktrigram
最近来源活动
2026年1月31日 18:12
检测到的 SKILL.md 语言
英语
星标
8
分支
7

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
threejs-best-practices
description
Enforces @react-three/fiber and @react-three/drei best practices for Black Trigram, including proper Canvas setup, Korean-themed lighting, resource cleanup patterns, Html overlay vs 3D mesh decision guide, performance optimization (useFrame, useMemo), testing patterns, and common Three.js anti-patterns to avoid.
license
MIT
# Three.js Best Practices Skill ## Purpose This skill ensures that all Three.js implementations in Black Trigram follow React Three Fiber best practices, maintain 60fps performance, properly manage resources, and create immersive 3D Korean martial arts experiences with proper separation between 3D world and UI overlays. ## When to Apply **Automatically trigger this skill when:** - Creating or modifying Three.js scenes or components - Implementing 3D models, characters, or environments - Adding visual effects, particles, or shaders - Working with cameras, lights, or materials - Creating UI overlays with `<Html>` components - Implementing animations with `useFrame` - Debugging performance issues in 3D rendering - Implementing camera controls or orbital navigation - Optimizing rendering performance (instancing, LOD, culling) - Adding textures, geometries, or Three.js objects - Optimizing 3D rendering performance - Reviewing pull requests with Three.js changes ## Core Principles ### 1. Canvas Setup and Scene Configuration **ALWAYS use proper Canvas configuration:** ✅ **Standard Canvas Setup for Black Trigram** ```typescript import { Canvas } from '@react-three/fiber'; import { PerspectiveCamera, Environment, Stats } from '@react-three/drei'; import { KOREAN_COLORS } from '@/types/constants'; import * as THREE from 'three'; interface Scene3DWrapperProps { readonly width: number; readonly height: number; readonly children: React.ReactNode; readonly showStats?: boolean; readonly enableShadows?: boolean; } export const Scene3DWrapper: React.FC<Scene3DWrapperProps> = ({ width, height, children, showStats = false, enableShadows = true, }) => { return ( <Canvas style={{ width, height }} gl={{ antialias: true, // Smooth edges alpha: false, // Opaque background (better performance) powerPreference: 'high-performance', // Use discrete GPU if available preserveDrawingBuffer: false, // Better performance }} dpr={[1, 2]} // Adaptive pixel ratio (1x on low-end, 2x on high-end) shadows={enableShadows} // Enable shadow rendering frameloop="always" // Always render (for games) onCreated={({ gl, scene }) => { // Set Korean cyberpunk background gl.setClearColor(KOREAN_COLORS.UI_BACKGROUND_DARK, 1); // Add fog for depth perception scene.fog = new THREE.Fog( KOREAN_COLORS.UI_BACKGROUND_DARK, 10, // Near distance 50 // Far distance ); // Enable tone mapping for better colors gl.toneMapping = THREE.ACESFilmicToneMapping; gl.toneMappingExposure = 1.0; }} data-testid="game-canvas" > {/* Korean-themed lighting */} <ambientLight intensity={0.4} color={KOREAN_COLORS.PRIMARY_CYAN} /> <directionalLight position={[10, 10, 5]} intensity={1} castShadow shadow-camera-left={-10} shadow-camera-right={10} shadow-camera-top={10} shadow-camera-bottom={-10} shadow-mapSize={[2048, 2048]} color={KOREAN_COLORS.ACCENT_GOLD} /> {/* Environment for reflections */} <Environment preset="city" /> {/* Default camera */} <PerspectiveCamera makeDefault position={[0, 5, 10]} fov={75} /> {/* Game content */} {children} {/* Performance stats in development */} {showStats && process.env.NODE_ENV === 'development' && <Stats />} </Canvas> ); }; ``` ✅ **Canvas Performance Configuration** ```typescript // GOOD: Optimized Canvas for 60fps <Canvas gl={{ antialias: true, alpha: false, // Opaque background = better performance powerPreference: 'high-performance', stencil: false, // Disable if not using depth: true, // Enable depth testing }} dpr={[1, 2]} // Adaptive DPR based on device shadows // Enable shadows (moderate cost) frameloop="always" // For games, always render performance={{ current: 1, // Performance factor (1 = normal) min: 0.5, // Minimum performance factor max: 1, // Maximum performance factor debounce: 200, // Debounce time for performance adjustments }} /> // BAD: Unoptimized Canvas <Canvas gl={{ antialias: true, alpha: true }} // Alpha = performance cost dpr={3} // Fixed 3x DPR = performance cost frameloop="demand" // For games, use "always" /> ``` ### 2. Korean-Themed Lighting and Aesthetics **ALWAYS apply Korean cyberpunk lighting:** ✅ **Standard Three-Light Setup** ```typescript // GOOD: Efficient three-light setup with Korean colors import { KOREAN_COLORS } from '@/types/constants'; export const KoreanSceneLighting: React.FC = () => { return ( <> {/* 1. Ambient light for base illumination (Korean cyan) */} <ambientLight intensity={0.4} color={KOREAN_COLORS.PRIMARY_CYAN} /> {/* 2. Directional light for main shadows (Korean gold) */} <directionalLight position={[10, 10, 5]} intensity={1} castShadow shadow-mapSize={[2048, 2048]} shadow-camera-far={50} shadow-camera-left={-10} shadow-camera-right={10} shadow-camera-top={10} shadow-camera-bottom={-10} color={KOREAN_COLORS.ACCENT_GOLD} /> {/* 3. Accent point light for highlights (Korean blue) */} <pointLight position={[-10, 5, -5]} intensity={0.5} distance={20} decay={2} color={KOREAN_COLORS.ACCENT_BLUE} /> </> ); }; // BAD: Too many lights (kills performance) export const UnoptimizedLighting: React.FC = () => { return ( <> {/* 50 point lights = FPS drops to 10! */} {Array.from({ length: 50 }).map((_, i) => ( <pointLight key={i} position={[i, 0, 0]} castShadow /> ))} </> ); }; ``` ✅ **Korean-Themed Materials** ```typescript // GOOD: Korean cyberpunk materials with emissive effects import { useMemo, useEffect } from 'react'; import * as THREE from 'three'; import { KOREAN_COLORS } from '@/types/constants'; export const KoreanStyledMesh: React.FC<{ stance: TrigramStance }> = ({ stance }) => { const material = useMemo(() => { const stanceColor = TRIGRAM_STANCES[stance].color; return new THREE.MeshStandardMaterial({ color: stanceColor, emissive: KOREAN_COLORS.PRIMARY_CYAN, emissiveIntensity: 0.2, metalness: 0.5, roughness: 0.5, envMapIntensity: 1.0, }); }, [stance]); useEffect(() => { return () => material.dispose(); }, [material]); return ( <mesh material={material} castShadow receiveShadow> <boxGeometry args={[1, 1, 1]} /> </mesh> ); }; // Enhanced material with Korean aesthetics export const EnhancedKoreanMaterial: React.FC = () => { return ( <mesh> <boxGeometry args={[1, 2, 0.1]} /> <meshStandardMaterial color={KOREAN_COLORS.UI_BACKGROUND_MEDIUM} emissive={KOREAN_COLORS.PRIMARY_CYAN} emissiveIntensity={0.3} metalness={0.6} roughness={0.4} transparent={true} opacity={0.9} /> </mesh> ); }; ``` ### 3. Html Overlay vs 3D Mesh Decision Guide **ALWAYS choose the right approach:** ✅ **Use Html Overlays For:** ```typescript import { Html } from '@react-three/drei'; import { FONT_FAMILY, KOREAN_COLORS } from '@/types/constants'; // 1. UI ELEMENTS (buttons, menus, text) export const PlayerNametag: React.FC<{ name: string; health: number }> = ({ name, health }) => { return ( <Html position={[0, 2.5, 0]} center distanceFactor={10}> <div style={{ background: `#${KOREAN_COLORS.UI_BACKGROUND_DARK.toString(16).padStart(6, '0')}dd`, border: `2px solid #${KOREAN_COLORS.PRIMARY_CYAN.toString(16).padStart(6, '0')}`, borderRadius: '8px', padding: '8px 12px', fontFamily: FONT_FAMILY.KOREAN, color: `#${KOREAN_COLORS.TEXT_PRIMARY.toString(16).padStart(6, '0')}`, pointerEvents: 'none', }}> <div>{name}</div> <HealthBar value={health} /> </div> </Html> ); }; // 2. INTERACTIVE MENUS export const CombatMenu: React.FC<{ onAction: (action: string) => void }> = ({ onAction }) => { return ( <Html fullscreen> <div style={{ position: 'absolute', bottom: 20, left: '50%', transform: 'translateX(-50%)', display: 'flex', gap: '10px', }}> <button onClick={() => onAction('attack')} style={{ fontFamily: FONT_FAMILY.KOREAN, background: `#${KOREAN_COLORS.PRIMARY_CYAN.toString(16)}`, border: 'none', padding: '10px 20px', cursor: 'pointer', }} > 공격 | Attack </button> <button onClick={() => onAction('defend')}> 방어 | Defend </button> </div> </Html> ); }; // 3. FULLSCREEN UI OVERLAYS export const CombatHUD: React.FC = () => { return ( <Html fullscreen> <div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', pointerEvents: 'none', }}> <div style={{ position: 'absolute', top: 20, left: 20 }}> <PlayerStatus /> </div> <div style={{ position: 'absolute', top: 20, right: 20 }}> <EnemyStatus /> </div> <div style={{ position: 'absolute', bottom: 20, left: '50%', transform: 'translateX(-50%)' }}> <StanceIndicator /> </div> </div> </Html> ); }; ``` ✅ **Use 3D Meshes For:** ```typescript // 1. GAME OBJECTS AND CHARACTERS export const CombatCharacter3D: React.FC<{ position: Vector3; stance: TrigramStance; isAttacking: boolean; }> = ({ position, stance, isAttacking }) => { return ( <group position={position}> {/* Character mesh */} <mesh castShadow receiveShadow> <capsuleGeometry args={[0.5, 1.5, 16, 32]} /> <meshStandardMaterial color={TRIGRAM_STANCES[stance].color} emissive={KOREAN_COLORS.PRIMARY_CYAN} emissiveIntensity={isAttacking ? 0.5 : 0.1} /> </mesh> {/* Stance aura (3D effect) */} <StanceAura3D stance={stance} /> </group> ); }; // 2. VISUAL EFFECTS AND PARTICLES export const AttackEffect3D: React.FC<{ position: Vector3 }> = ({ position }) => { return ( <group position={position}> {/* Point light for impact */} <pointLight intensity={2} distance={5} decay={2} color={KOREAN_COLORS.ACCENT_GOLD} /> {/* Particle system */} <ImpactParticles count={50} spread={2} /> </group> ); }; // 3. ENVIRONMENT AND WORLD OBJECTS export const CombatArena3D: React.FC = () => { return ( <group> {/* Floor */} <mesh rotation={[-Math.PI / 2, 0, 0]} receiveShadow> <planeGeometry args={[20, 20]} /> <meshStandardMaterial
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看