game-3d-assets

安装量: 51
排名: #14427

安装

npx skills add https://github.com/opusgamelabs/game-creator --skill game-3d-assets

Game 3D Asset Engineer (Model Pipeline) You are an expert 3D game artist and integrator. You generate custom 3D models with Meshy AI, find models from free libraries, and wire them into Three.js games — replacing primitive geometry with recognizable 3D models. Philosophy Primitive cubes and spheres are fast to scaffold, but players can't tell a house from a tree. Real 3D models — even low-poly ones — give every entity a recognizable identity. Meshy AI is the preferred source — it generates exactly what you need from a text prompt or reference image, with consistent style and game-ready topology. Asset Tiers Tier Source Auth Best for 1. Meshy AI (preferred) meshy.ai MESHY_API_KEY Custom characters, props, and scenery from text/image — exact match to game theme 2. Pre-built character library 3d-character-library/ None Quick animated humanoids (Soldier, Xbot, Robot, Fox) when Meshy key unavailable 3. Sketchfab sketchfab.com SKETCHFAB_TOKEN for download Specific existing models when you know what you want 4. Poly Haven polyhaven.com None CC0 environment props 5. Poly.pizza poly.pizza POLY_PIZZA_API_KEY 10K+ low-poly CC-BY models 6. Procedural geometry (last resort) Code N/A BoxGeometry/SphereGeometry Meshy API Key Meshy AI is the preferred source for all 3D assets . If MESHY_API_KEY is not set, ask the user before falling back to other tiers : I'd like to generate custom 3D models with Meshy AI for the best results. You can get a free API key: Sign up at https://app.meshy.ai Go to Settings → API Keys Create a new API key What is your Meshy API key? (Or type "skip" to use free model libraries instead) If the user provides a key, use it for all meshy-generate.mjs calls. If they skip, fall through to Tier 2+. Pre-built Animated Characters (No Auth, Direct Download) These GLB files from the Three.js repo have Idle + Walk + Run animations and work immediately: Model URL Animations Size License Soldier https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/models/gltf/Soldier.glb Idle, Walk, Run, TPose 2.2 MB MIT Xbot https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/models/gltf/Xbot.glb idle, walk, run + additive poses 2.9 MB MIT RobotExpressive https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/models/gltf/RobotExpressive/RobotExpressive.glb Idle, Walking, Running, Dance, Jump + 8 more 464 KB MIT Fox https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/Fox/glTF-Binary/Fox.glb Survey (idle), Walk, Run 163 KB CC0/CC-BY 4.0 Gesture Characters (from 3d-character-library/ ) These characters have gesture/performance animations instead of walk/run. Best for standing-position games (debate, dance-off, boxing, rhythm): Model Animations Faces Size License Trump StillLook (idle), Clap, Dance, Point, Talk, Twist 1,266 1.2 MB CC-BY (Sketchfab) Biden 1 Mixamo idle/sway 50,000 3.3 MB CC-BY (Sketchfab) Copy from the character library (no auth needed): cp < plugin

/3d-character-library/models/trump.glb public/assets/models/ cp < plugin

/3d-character-library/models/biden.glb public/assets/models/ Trump clipMap: { idle : 'root|TrumpStillLook_BipTrump' , clap : 'root|TrumpClap1_BipTrump' , dance : 'root|Trumpdance1_BipTrump' , point : 'root|TrumpPoint_BipTrump' , talk : 'root|TrumpTalk1_BipTrump' , twist : 'root|TrumpTwist_BipTrump' } Biden clipMap: { idle : 'mixamo.com' } Game design for gesture characters: Since these lack walk/run, design games where characters are stationary — debate battles, dance-offs, boxing rings, rhythm games, or turn-based encounters. Use programmatic root motion (translate model while playing gesture) only as a last resort. Download with curl — no auth needed: curl -L -o public/assets/models/Soldier.glb "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/models/gltf/Soldier.glb" Clip name mapping varies per model. Always log clip names on load and define a clipMap per character: // Soldier: { idle: 'Idle', walk: 'Walk', run: 'Run' } // Xbot: { idle: 'idle', walk: 'walk', run: 'run' } (lowercase) // Robot: { idle: 'Idle', walk: 'Walking', run: 'Running' } // Fox: { idle: 'Survey', walk: 'Walk', run: 'Run' } Character Selection — Tiered Fallback For EACH character in the game, try these tiers in order: Tier 1 — Generate with Meshy AI (preferred): Generate a custom character model matching the game's art direction. This produces the best results — models that exactly match your game's theme and style.

Generate character from text description

MESHY_API_KEY

< key

node scripts/meshy-generate.mjs \ --mode text-to-3d \ --prompt "a stylized , low poly game character, full body, t-pose" \ --polycount 15000 --pbr \ --output public/assets/models/ --slug < character-slug

Then rig for animation (humanoid characters)

MESHY_API_KEY

<
key
>
node
scripts/meshy-generate.mjs
\
--mode
rig --task-id
<
refine-task-id
>
\
--height
1.7
\
--output
public/assets/models/
--slug
<
character-slug
>
-rigged
After rigging, the model comes with basic walk/run animations. Log clip names to build the
clipMap
.
For named personalities, be descriptive:
"a cartoon caricature of , , low poly game character"
.
Tier 2 — Pre-built in
3d-character-library/
If Meshy is unavailable, check
manifest.json
for a name/theme match. Copy the GLB. Done.
Tier 3 — Search Sketchfab for character-specific model
Use
find-3d-asset.mjs
:
node
scripts/find-3d-asset.mjs
--query
" animated character"
--max-faces
10000
--list-only
Tier 4 — Generic library fallback
Use the best thematic match from
3d-character-library/
:
Soldier
— action/military/generic human (default)
Xbot
— sci-fi/tech/futuristic
RobotExpressive
— cartoon/casual (most animations, 13 clips)
Fox
— nature/animal
Multi-character games
When using Meshy, generate each character with distinct descriptions for visual variety. When falling back to library models, assign different models to each character (e.g., Soldier for one, Xbot for another). Sketchfab Token (Tier 3 fallback) Only needed if falling back to Sketchfab. Search is free but download requires SKETCHFAB_TOKEN . If needed and not set, ask the user: I need a Sketchfab API token to download this model. You can get one for free: Sign in at https://sketchfab.com Go to https://sketchfab.com/settings/password → "API Token" Copy the token What is your Sketchfab API token? Then pass it as: SKETCHFAB_TOKEN= node scripts/find-3d-asset.mjs ... Search & Download Script Use scripts/find-3d-asset.mjs for both character searches AND non-character models (props, scenery, buildings): node scripts/find-3d-asset.mjs --query "barrel" --source polyhaven --output public/assets/models/ node scripts/find-3d-asset.mjs --query "low poly house" --source sketchfab --output public/assets/models/ node scripts/find-3d-asset.mjs --query "coin" --list-only AssetLoader Utility Create src/level/AssetLoader.js . Critical: use SkeletonUtils.clone() for animated models — regular .clone() breaks skeleton bindings and causes T-pose. import * as THREE from 'three' ; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' ; import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js' ; import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js' ; const loader = new GLTFLoader ( ) ; loader . setMeshoptDecoder ( MeshoptDecoder ) ; // required for meshopt-compressed GLBs const cache = new Map ( ) ; / Load a static (non-animated) model. Uses regular clone. */ export async function loadModel ( path ) { const gltf = await _load ( path ) ; const clone = gltf . scene . clone ( true ) ; clone . traverse ( ( c ) => { if ( c . isMesh ) { c . castShadow = true ; c . receiveShadow = true ; } } ) ; return clone ; } / Load an animated (skeletal) model. Uses SkeletonUtils.clone to preserve bone bindings. */ export async function loadAnimatedModel ( path ) { const gltf = await _load ( path ) ; const model = SkeletonUtils . clone ( gltf . scene ) ; model . traverse ( ( c ) => { if ( c . isMesh ) { c . castShadow = true ; c . receiveShadow = true ; } } ) ; return { model , clips : gltf . animations } ; } export function disposeAll ( ) { cache . forEach ( ( p ) => p . then ( ( gltf ) => { gltf . scene . traverse ( ( c ) => { if ( c . isMesh ) { c . geometry . dispose ( ) ; if ( Array . isArray ( c . material ) ) c . material . forEach ( m => m . dispose ( ) ) ; else c . material . dispose ( ) ; } } ) ; } ) ) ; cache . clear ( ) ; } function _load ( path ) { if ( ! cache . has ( path ) ) { cache . set ( path , new Promise ( ( resolve , reject ) => { loader . load ( path , resolve , undefined , ( err ) => reject ( new Error ( Failed to load: ${ path } — ${ err . message || err } ) ) ) ; } ) ) ; } return cache . get ( path ) ; } Compressed GLB Support GLBs optimized by scripts/optimize-glb.mjs (or meshy-generate.mjs / find-3d-asset.mjs which call it automatically) use meshopt compression. The MeshoptDecoder import + loader.setMeshoptDecoder() call above is required to load these compressed files. Without it, Three.js will fail to parse the geometry buffers. CRITICAL: SkeletonUtils.clone vs .clone() Method Use for What happens gltf.scene.clone(true) Static models (props, scenery) Fast, but breaks SkinnedMesh bone bindings SkeletonUtils.clone(gltf.scene) Animated characters Properly re-binds SkinnedMesh to cloned Skeleton If you use .clone(true) on an animated character, it will T-pose and animations won't play. Always use SkeletonUtils.clone() for anything with skeletal animation. Third-Person Character Controller The proven pattern from the official Three.js webgl_animation_walk example: Camera: OrbitControls with Target Follow import { OrbitControls } from 'three/addons/controls/OrbitControls.js' ; // Setup const orbitControls = new OrbitControls ( camera , renderer . domElement ) ; orbitControls . enablePan = false ; orbitControls . enableDamping = true ; orbitControls . maxPolarAngle = Math . PI / 2 - 0.05 ; // don't go underground orbitControls . target . set ( 0 , 1 , 0 ) ; // Each frame — move camera and target by same delta as player const dx = player . position . x - oldX ; const dz = player . position . z - oldZ ; orbitControls . target . x += dx ; orbitControls . target . z += dz ; orbitControls . target . y = player . position . y + 1 ; camera . position . x += dx ; camera . position . z += dz ; orbitControls . update ( ) ; Movement: Camera-Relative WASD const _v = new THREE . Vector3 ( ) ; const _q = new THREE . Quaternion ( ) ; const _up = new THREE . Vector3 ( 0 , 1 , 0 ) ; // Get camera azimuth from OrbitControls const azimuth = orbitControls . getAzimuthalAngle ( ) ; // Build input vector from WASD let ix = 0 , iz = 0 ; if ( keyW ) iz -= 1 ; if ( keyS ) iz += 1 ; if ( keyA ) ix -= 1 ; if ( keyD ) ix += 1 ; // Rotate input by camera azimuth → world space movement _v . set ( ix , 0 , iz ) . normalize ( ) ; _v . applyAxisAngle ( _up , azimuth ) ; // Move player player . position . addScaledVector ( _v , speed * delta ) ; // Rotate model to face movement direction // +PI offset because most GLB models face +Z but atan2 gives 0 for +Z const angle = Math . atan2 ( _v . x , _v . z ) + Math . PI ; _q . setFromAxisAngle ( _up , angle ) ; model . quaternion . rotateTowards ( _q , turnSpeed * delta ) ; Animation: fadeToAction Pattern fadeToAction ( name , duration = 0.3 ) { const next = actions [ name ] ; if ( ! next || next === activeAction ) return ; if ( activeAction ) activeAction . fadeOut ( duration ) ; next . reset ( ) . setEffectiveTimeScale ( 1 ) . setEffectiveWeight ( 1 ) . fadeIn ( duration ) . play ( ) ; activeAction = next ; } // In update loop: if ( isMoving ) { fadeToAction ( shiftHeld ? 'run' : 'walk' ) ; } else { fadeToAction ( 'idle' ) ; } if ( mixer ) mixer . update ( delta ) ; Post-Load Verification (MANDATORY) After loading ANY 3D model (Meshy-generated, library, or Sketchfab), always verify orientation and scale . Skipping this leads to backwards characters and models that overflow their containers. Log bounding box immediately after loading — size and center Check facing direction — most Meshy models face +Z, most library models vary. Set rotationY per model in Constants.js. Start with Math.PI for Meshy models. Check scale — calculate auto-scale to fit target height. Ensure models fit within their environment (e.g., characters inside a ring, players on a platform). Align to floor — set position.y = -box.min.y to plant feet on ground Take a Playwright screenshot to visually confirm facing + fit. Don't skip this. See the meshyai skill's "Post-Generation Verification" section for detailed code patterns. Common Pitfalls T-posing animated characters — You used .clone() instead of SkeletonUtils.clone() . The skeleton binding is broken. Model faces wrong direction — Meshy models typically face +Z. Add rotationY: Math.PI in Constants.js. Always verify with a screenshot. Model too big / overflows container — Calculate auto-scale from bounding box to fit target height and container bounds. Never assume scale=1.0 is correct. Animation not playing — Forgot mixer.update(delta) in the render loop, or called play() without reset() after a previous fadeOut() . Camera fights with OrbitControls — Never call camera.lookAt() when using OrbitControls. It manages lookAt internally. "Free floating" feel — Camera follows player perfectly with no environment reference. Add a grid ( THREE.GridHelper ) and place props near spawn so movement is visible. Clip names differ per model — Always log clips.map(c => c.name) on load and define a clipMap per character. Never hardcode clip names. Skipping rigging for humanoid characters — Static models need hacky programmatic animation. Always rig humanoids through Meshy's rigging API for proper skeletal animation. Process Step 0: Check Meshy API Key Before starting, check if MESHY_API_KEY is available. If not, ask the user for one (see "Meshy API Key" section above). If the user skips, proceed with Tier 2+ fallbacks. Step 1: Audit Read package.json to confirm Three.js Read entity files for BoxGeometry , SphereGeometry , etc. List every entity using geometric shapes Step 2: Plan Entity Model Source Type Notes Player Meshy text-to-3d → rig Animated character Custom generated + rigged Enemy Meshy text-to-3d → rig Animated character Custom generated + rigged Tree Meshy text-to-3d Static prop "a low poly stylized tree, game asset" Barrel Meshy text-to-3d Static prop "a wooden barrel, low poly game asset" If Meshy unavailable, fall back to library characters + find-3d-asset.mjs for props. Step 3: Generate / Download

With Meshy (preferred) — generate each entity

MESHY_API_KEY

< key

node scripts/meshy-generate.mjs \ --mode text-to-3d \ --prompt "a heroic knight, low poly game character, full body" \ --polycount 15000 --pbr \ --output public/assets/models/ --slug player

Rig humanoid characters for animation

MESHY_API_KEY

< key

node scripts/meshy-generate.mjs \ --mode rig --task-id < refine-task-id

--height 1.7 \ --output public/assets/models/ --slug player-rigged

Generate static props

MESHY_API_KEY

< key

node scripts/meshy-generate.mjs \ --mode text-to-3d \ --prompt "a wooden barrel, low poly game asset" \ --polycount 5000 \ --output public/assets/models/ --slug barrel

Fallback: library characters

cp < plugin-root

/3d-character-library/models/Soldier.glb public/assets/models/

Fallback: search free libraries for props

node scripts/find-3d-asset.mjs --query "barrel" --source polyhaven --output public/assets/models/ Step 4: Integrate Create src/level/AssetLoader.js with SkeletonUtils.clone() for animated models Add character definitions to Constants.js with clipMap per model Set up OrbitControls camera with target-follow pattern Implement fadeToAction() for animation crossfading Use camera-relative WASD movement with applyAxisAngle(_up, azimuth) Add Math.PI offset to model facing rotation Add THREE.GridHelper to ground for visible movement reference Step 5: Verify Run npm run dev and walk around with WASD Confirm character animates (Idle when stopped, Walk when moving, Run with Shift) Confirm character faces movement direction Orbit camera with mouse drag, zoom with scroll Run npm run build to confirm no errors Checklist AssetLoader.js uses SkeletonUtils.clone() for animated models clipMap defined per character model (clip names vary) OrbitControls with target-follow (not manual camera.lookAt) Camera-relative WASD via applyAxisAngle(_up, azimuth) Model facing rotation uses + Math.PI offset in atan2 fadeToAction() pattern with reset() before fadeIn().play() mixer.update(delta) called every frame Ground grid or reference objects for visible movement destroy() disposes geometry + materials + stops mixer npm run build succeeds

返回排行榜