Gigachad Sim
Gigachad Sim — a Three.js starter mirrored from OpusGameLabs/game-creator.
Preview
Edit on StackBlitzInstall
npx create-gamecn my-game --template gigachad-simSource preview
Compatibility
| Engines | three >=0.160.0 |
| Frameworks | vanilla |
| Languages | javascript |
| Bundlers | vite |
| Platforms | web, mobile-web |
Files installed
- .gitignore
- design-brief.md(docs)
- index.html
- package.json
- progress.md(docs)
- public/assets/models/barbell.glb(asset)
- public/assets/models/barbell.meta.json
- public/assets/models/dumbbell.glb(asset)
- public/assets/models/dumbbell.meta.json
- public/assets/models/gigachad-run.glb(asset)
- public/assets/models/gigachad-v2-run.glb(asset)
- public/assets/models/gigachad-v2-walk.glb(asset)
- public/assets/models/gigachad-v2.glb(asset)
- public/assets/models/gigachad-v2.meta.json
- public/assets/models/gigachad-walk.glb(asset)
- public/assets/models/gigachad.glb(asset)
- public/assets/models/gigachad.meta.json
- public/assets/models/kettlebell.glb(asset)
- public/assets/models/kettlebell.meta.json
- public/assets/models/protein-shake.glb(asset)
- public/assets/models/protein-shake.meta.json
- src/audio/AudioBridge.js
- src/audio/AudioManager.js
- src/audio/music.js
- src/audio/sfx.js
- src/core/Constants.js
- src/core/EventBus.js
- src/core/Game.js
- src/core/GameState.js
- src/effects/FloatingText.js
- src/effects/ParticleManager.js
- src/effects/ScreenEffects.js
- src/gameplay/Player.js
- src/gameplay/PowerupManager.js
- src/gameplay/WeightManager.js
- src/level/AssetLoader.js
- src/level/LevelBuilder.js
- src/main.js
- src/systems/InputSystem.js
- src/ui/Menu.js
- src/ui/MuteButton.js
- vite.config.js
- gamecn.json
Notes
Concept
An endless gym workout simulator where GigaChad must catch falling weights to build his Chad Score. Think rhythm/timing game meets weightlifting sim. Weights fall from the ceiling of a 3D gym environment, and the player must position GigaChad underneath them to auto-catch and lift. The game progressively gets harder with faster, more frequent weight drops.
Core Mechanics
Movement
- GigaChad moves left and right along the gym floor (A/D keys or arrow keys on desktop, virtual joystick on mobile)
- Movement is constrained to a 20-unit wide arena
- Speed: 12 units per second for responsive dodging
Catching Weights
- Weights fall from Y=15 toward the floor
- When a weight reaches Y=2.5 and the player is within 1.8 units horizontally, it is auto-caught
- A successful catch triggers a lifting animation (arms up) and a brief scale pop
- Points are awarded based on weight type, multiplied by any active multiplier
- Missing a weight (it hits the floor at Y=0.5) costs one life
Scoring
- Dumbbell (blue, small): 1 point
- Barbell (red, large): 3 points
- Kettlebell (gold, medium): 5 points
- Combo system: Consecutive catches increment a combo counter. Combo resets on miss.
- Flex bonus: Pressing Space (or tap flex button on mobile) during a catch adds +2 points
- Protein shake: Collecting the green powerup grants 2x multiplier for 8 seconds
Difficulty Ramp
- Every 10 seconds, difficulty increases (up to level 15)
- Each level adds +0.4 to fall speed and -0.12s to spawn interval
- At low difficulty, mostly dumbbells spawn. At high difficulty, more barbells and kettlebells
- Max 8 weights on screen at once
Lives & Game Over
- Player starts with 3 lives (shown as red squares in top-right)
- Each missed weight costs 1 life with screen shake feedback
- At 0 lives, game over overlay appears with final score, best score, and best combo
- Restart via button click, Space, or Enter
Entity Descriptions
GigaChad (Player)
- Visual: Large, imposing box-based figure. 2.0 units wide, 3.0 units tall.
- Distinguishing features: Very wide torso and chest, thick arms, tiny head relative to body — the classic GigaChad proportions.
- Colors: Skin tone body (#d4a574), dark hair (#2a1a0a), dark shorts (#1a1a2e), dark shoes (#333333).
- Animations: Arms rest at sides normally, raise up for catching/lifting, flex pose on Space press.
- Entrance: Slides in from behind (Z=-15) with a bounce arc, taking 1.2 seconds.
Dumbbell
- Visual: Horizontal cylinder bar with disc plates on each end. Blue (#4488ff).
- Scale: 0.8 units. Smallest weight type.
- Points: 1 (x multiplier)
Barbell
- Visual: Long horizontal bar with multiple stacked red plates on each end. Red (#ff4444).
- Scale: 1.2 units. Largest weight type.
- Points: 3 (x multiplier)
Kettlebell
- Visual: Sphere body with a half-torus handle on top. Gold (#ffd700).
- Scale: 1.0 units. Medium weight type.
- Points: 5 (x multiplier)
Protein Shake (Powerup)
- Visual: Green cylinder (#44ff44) with white cap, surrounded by a pulsing green glow sphere.
- Scale: 0.6 units radius.
- Behavior: Falls at speed 3 units/sec, bobs and rotates. Collecting grants 2x multiplier for 8 seconds.
- Spawn: 15% chance every 8 seconds.
Gym Environment
- Floor: Dark rubber mat (#333340) with grid lines (#444455) at 2-unit intervals.
- Back wall: Dark (#3a3a4e) with horizontal red accent stripes and a gold strip.
- Side walls: Slightly different shade (#353548).
- Ceiling: Dark (#222233) at Y=18.
- Lighting: Ambient + directional overhead + spotlight pointing at center for dramatic gym effect.
Win/Lose Conditions
- Win condition: None — endless high-score chaser. Play until all lives are lost.
- Lose condition: All 3 lives lost (weights hit the floor 3 times).
- Score persistence: Best score and best combo are tracked across sessions in memory (not persisted to storage).
Input
Desktop
- A / Left Arrow: Move left
- D / Right Arrow: Move right
- Space: Flex/taunt (bonus points if timed during a catch)
- Space / Enter: Restart from game over screen
Mobile
- Virtual joystick (left side): Horizontal movement
- Flex button (right side): Gold circle labeled "FLEX"
- Both controls are visible only on touch-capable devices
Camera
- Fixed third-person perspective: positioned at (0, 6, 10), looking at (0, 2, 0)
- No orbit controls — camera stays still so the player focuses on the falling weights
- Screen shake on weight miss for impact feedback
Original Prompt
GigaChad Gym Simulator - endless gym workout simulator where GigaChad catches falling weights to build Chad Score. Rhythm/timing game meets weightlifting sim in a 3D gym environment.
Step 1: Scaffold (Complete)
What was built
- Full Three.js game with event-driven modular architecture
- GigaChad character built from box primitives (wide torso, thick arms, small head)
- Three weight types: dumbbell (blue, 1pt), barbell (red, 3pt), kettlebell (gold, 5pt)
- Protein shake powerup (green glow, 2x multiplier for 8s)
- 3-life system with screen shake on miss
- Combo tracking with visual feedback
- Flex mechanic (Space key) for bonus points during catch
- Difficulty ramp: speed/frequency increase every 10s up to level 15
- Entrance animation: GigaChad bounces in from off-screen
- Gym environment: dark rubber floor, walls with accent stripes, ceiling, dramatic lighting
- Mobile support: virtual joystick + flex button
- Full
render_game_to_text()with all game state advanceTime(ms)for testing- Game over overlay with score, best, combo stats + keyboard restart
- Play.fun safe zone respected on all overlays
Architecture
core/— Game.js (orchestrator), EventBus.js (18 events), GameState.js, Constants.jsgameplay/— Player.js, WeightManager.js, PowerupManager.jssystems/— InputSystem.js (keyboard + touch)level/— LevelBuilder.js (gym environment), AssetLoader.js (for future GLB models)ui/— Menu.js (game over + HUD lives/multiplier/combo)
Decisions
- Fixed camera (no OrbitControls) — keeps focus on falling weights
- Auto-catch mechanic (no button press needed) — more accessible, especially on mobile
- Flex is optional bonus mechanic, not required to play
- Player built from boxes (Step 2 will replace with 3D models)
- Weights built from basic geometries (Step 2 will improve)
TODOs for next steps
- Step 1.5: Replace primitives with Meshy AI GLB models
- Step 2: Visual design — particles, transitions, screen effects, juice
- Step 4: Record promo video
- Step 3: Add BGM (gym beats) + SFX (catch clank, miss thud, powerup chime, flex grunt)
- Step 6: Deploy to here.now
- Step 7: Monetize with Play.fun
Step 1.5: 3D Assets (Complete)
Models used (all Meshy AI-generated)
- gigachad.glb (1.6 MB) — Rigged character with skeleton, base pose
- gigachad-walk.glb (1.6 MB) — Walking animation clip
- gigachad-run.glb (1.6 MB) — Running animation clip
- barbell.glb (1.7 MB) — Red barbell weight prop
- dumbbell.glb (715 KB) — Blue dumbbell weight prop
- kettlebell.glb (719 KB) — Gold kettlebell weight prop
- protein-shake.glb (588 KB) — Green protein shake powerup
What was changed
- Constants.js — Added
MODELSconfig section with paths, scales, and rotation for all 7 GLB files - Player.js — Replaced primitive box character with rigged GLB model using
SkeletonUtils.clone()vialoadAnimatedModel(). Walk/run animations loaded from separate GLB files.AnimationMixerdrives smoothfadeToAction()transitions between idle and walk states. Primitive box model retained as.catch()fallback - WeightManager.js — All 3 weight types (dumbbell, barbell, kettlebell) now load GLB models via
loadModel(). Models are cloned per spawn with independent materials for opacity fading on catch. Primitive geometries retained as fallback - PowerupManager.js — Protein shake GLB loaded and cloned per spawn. Green glow sphere preserved around the model. Primitive cylinder fallback retained
- Game.js — Added
preloadAll()call beforestartGame()that loads all 7 GLB paths in parallel. Render loop starts immediately (gym environment visible during load). Game begins after preload completes (or gracefully falls back on failure)
Scale/orientation adjustments
- GigaChad: scale 2.0, rotationY = Math.PI (Meshy models face +Z, flipped to face camera)
- Weights: dumbbell 0.8, barbell 0.5, kettlebell 0.7 (scaled to match game proportions)
- Protein shake: scale 0.8
- All models auto-aligned to floor via bounding box calculation (
position.y = -bbox.min.y)
Issues / Notes
- Animation clip names from Meshy vary per model — clips logged to console on load for debugging
- Walk/run clips loaded from separate GLB files (Meshy exports animations as separate files)
- All model loads have
.catch()fallback to original primitive geometries — game fully playable even if all GLBs fail to load - Materials cloned per instance for weight fade-out animation (opacity changes must be independent)
Step 2: Design (Complete)
What was added
Three new effect systems under src/effects/, plus Constants and Game.js integration.
New files
src/effects/ParticleManager.js— GPU particle system usingTHREE.Pointswith a pre-allocated pool of 200 particles. Supports burst emissions at arbitrary positions with configurable count, color, and speed. Also manages ambient floating dust/chalk particles (30 always-active motes drifting through the gym) and expanding shockwave rings on the floor.src/effects/FloatingText.js— CSS-based floating score text. Projects 3D catch positions to screen coordinates and shows "+N" text that rises upward and fades over 1 second. Font size scales with combo level (28px base + 4px per combo, capped at 56px). Colors match weight types: blue for dumbbell, red for barbell, gold for kettlebell. Also shows "2x POWER!" for powerup collection and streak milestone labels ("ON FIRE!", "UNSTOPPABLE!", "LEGENDARY!", "GODLIKE!", "GIGACHAD!").src/effects/ScreenEffects.js— Full-screen visual effects manager. Handles flash overlays (white on entrance, red on miss, green on powerup, gold on streak), camera FOV pulse (60 to 55 degrees on catch, 0.1s in / 0.2s out), directional light intensity pulse (+0.3 for 0.2s on catch/powerup/streak), hit freeze (60ms gameplay pause on damage), and combo-scaled screen shake (base 0.15 + combo * 0.03, capped at 0.5).
Modified files
src/core/Constants.js— AddedEFFECTSconfiguration object with 35+ tuning values: particle pool size, burst counts per event type (catch: 15, miss: 10, powerup: 20, streak: 40, entrance: 20), particle physics (size, speed, lifetime, gravity), ambient particle settings (count: 30, drift speed, size, opacity), floating text parameters (duration, rise, font sizes), flash overlay durations/alphas, hit freeze duration (60ms), FOV pulse amounts/timing, light pulse amount/duration, shockwave ring settings, and per-weight-type particle colors.src/core/Game.js— Integrated all three effects systems. CreatesParticleManager,FloatingText, andScreenEffectsinstances during construction. The animate loop now: (1) updates screen effects first to get freeze/shake state, (2) updates particles and floating text every frame (even during freeze for visual continuity), (3) skips gameplay updates during hit freeze, (4) applies screen shake offsets to camera position. Removed the old manual screen shake implementation (_shakeTimer,_shakeIntensity,_triggerScreenShake(),PLAYER_HITlistener) in favor of the ScreenEffects system.src/level/LevelBuilder.js— Exposed the directional light asthis.dirLight(was a local variable) so Game.js can pass it to ScreenEffects for the light pulse effect.
Event-to-effect mapping
| Event | Particles | Floating Text | Screen Effect |
|---|---|---|---|
WEIGHT_CAUGHT |
15-40 particles (color by type, count scales with combo) | "+N" score popup (color by type, size by combo) | FOV pulse + light pulse. White flash at combo >= 3 |
WEIGHT_MISSED |
10 red particles at floor + shockwave ring | - | Red flash + screen shake |
POWERUP_COLLECTED |
20 green spiral particles | "2x POWER!" centered text | Green flash + light pulse |
SPECTACLE_COMBO |
10 + combo*3 gold particles | - | Combo-scaled micro-shake |
SPECTACLE_STREAK |
40 orange particles + gold shockwave ring | Milestone label (ON FIRE!/UNSTOPPABLE!/etc.) | Gold flash + strong shake + light pulse |
SPECTACLE_ENTRANCE |
20 white particles (delayed 1s for landing) | - | White flash + small shake (delayed 1s) |
PLAYER_HIT |
- | - | 60ms hit freeze |
Ambient effects (always active)
- 30 floating dust/chalk particles drifting slowly through the gym volume with sinusoidal motion
- Particles wrap around gym boundaries for seamless loop
- Opacity gently pulses over time
Design decisions
- All effects are non-blocking and degrade gracefully via try/catch
- Particle pool is pre-allocated (zero GC during gameplay)
- Ambient particles use separate THREE.Points instance (always rendered, not pooled)
- Floating text uses CSS positioned divs (not Three.js sprites) for crisp rendering at all resolutions
- Shockwave rings are individual meshes created and disposed per instance (low frequency events)
- Hit freeze skips gameplay updates but continues rendering particles/effects for visual continuity
- Screen shake is managed entirely by ScreenEffects (old manual shake removed from Game.js)
- All magic numbers in Constants.js under the EFFECTS object
Step 3: Audio (Complete)
What was added
Full procedural audio system using Web Audio API — zero external audio files or npm packages. Background music (step sequencer) and 7 one-shot sound effects, all synthesized with OscillatorNode, GainNode, and BiquadFilterNode.
New files
src/audio/AudioManager.js— Singleton that owns the AudioContext and master GainNode. Creates/resumes AudioContext on first user interaction (browser autoplay policy). ProvidesplayMusic(patternFn),stopMusic(), andsetMuted(bool). All audio routes through a single master GainNode for instant global mute.src/audio/music.js— Two BGM patterns using a Web Audio API step sequencer:- Gameplay BGM (140 BPM): Energetic gym/workout beat with 6 layers — 4-on-the-floor kick, offbeat hi-hats, deep sawtooth bass (E minor), power riff melody with 3 phrase variations (A/B/C cycled across 8 phrases = 128 steps before melody repeat), synth stab accents, and high arp texture. Anti-repetition via: different layer lengths (16/12/14/128/8/10 steps), random note omission (12%), and 3 melody phrase variations.
- Game Over BGM (70 BPM): Somber minor-key piece with descending triangle melody, sustained A minor pad (root + fifth), and deep bass drone. Chord changes between Am and Em.
src/audio/sfx.js— 7 one-shot sound effects, all procedural:- catch: Metallic clank — bandpass-filtered square wave with pitch drop (1200->400 Hz), sine overtone ring at 3200 Hz, and noise transient click
- miss: Heavy thud — sine with deep pitch drop (120->30 Hz), low-passed at 200 Hz, plus noise rumble and sub-bass impact at 50 Hz
- flex: Power grunt/growl — sawtooth with filter sweep (300->800->200 Hz), plus noise burst for breath/exertion
- powerup: Ascending chime — 5 sine notes (C5->E5->G5->C6->E6) spaced 50ms apart, plus high shimmer overtone
- combo: Quick ascending arpeggio (E4->G4->B4) with pitch scaling based on combo count (1.0x to 2.0x), filter opens wider with higher combos
- streak: Epic fanfare — 4-note sawtooth chord (G3+C4+E4+G4) with filter sweep up, plus rising square accent
- entrance: Dramatic slam — deep sine boom with pitch drop (200->25 Hz), sub rumble at 40 Hz, noise impact transient, and metallic ring at 1600 Hz
src/audio/AudioBridge.js— Wires EventBus events to audio playback. Initializes AudioContext on first user interaction (click/touchstart/keydown). Handles BGM transitions (gameplay/game over/restart), all 7 SFX triggers, and mute toggle with localStorage persistence. Unmuting resumes appropriate BGM based on game state.src/ui/MuteButton.js— HTML/Canvas-based mute toggle button. Speaker icon drawn on a<canvas>element at 2x resolution for retina. Positioned bottom-right above Play.fun safe zone. Shows sound waves when unmuted, red X when muted. Click/touch handler + M key shortcut.
Modified files
src/core/EventBus.js— AddedAUDIO_TOGGLE_MUTE: 'audio:toggleMute'event (now 20 events total)src/core/GameState.js—isMutednow initializes fromlocalStorage.getItem('muted')for persistence across sessionssrc/main.js— Imports and initializesinitAudioBridge()andMuteButtonbefore game creation. Both wrapped in try/catch for non-blocking fallback.
Event-to-audio mapping
| Event | Audio Response |
|---|---|
GAME_START |
Ensure AudioContext initialized |
MUSIC_GAMEPLAY |
Play gameplay BGM (140 BPM workout beat) |
GAME_OVER |
Stop BGM, play game over BGM (70 BPM somber) |
GAME_RESTART |
Stop all music (GAME_START/MUSIC_GAMEPLAY restarts it) |
WEIGHT_CAUGHT |
Metallic clank SFX |
WEIGHT_MISSED |
Heavy thud SFX |
PLAYER_FLEX |
Power grunt/growl SFX |
POWERUP_COLLECTED |
Ascending chime SFX |
SPECTACLE_COMBO |
Ascending arpeggio SFX (pitch scales with combo) |
SPECTACLE_STREAK |
Epic fanfare blast SFX |
SPECTACLE_ENTRANCE |
Dramatic slam/impact SFX |
AUDIO_TOGGLE_MUTE |
Toggle mute, persist to localStorage, stop/resume BGM |
Design decisions
- Zero npm packages — all Web Audio API (OscillatorNode, GainNode, BiquadFilterNode)
- Audio is completely non-blocking — if AudioContext fails to create, game works without sound
- All SFX and BGM functions wrapped in try/catch
- AudioContext created on first user interaction (click/touch/key) per browser autoplay policy
- Master GainNode controls global volume;
gain.value = 0for instant mute of all audio - Mute state persisted to localStorage and restored on page load
- BGM uses look-ahead step sequencer (schedules 100ms ahead, checks every 25ms) for sample-accurate timing
- Different layer lengths in gameplay BGM create polyrhythmic variation (LCM of 16/12/14/128/8/10 = very long before exact repeat)
- Random note omission (12% chance on quiet layers) adds organic feel
- Combo SFX pitch scales with combo count for escalating feedback
- M key shortcut for quick mute toggle during gameplay
Related
- 3D Asset TestTemplate
3D Asset Test — a Three.js starter mirrored from OpusGameLabs/game-creator.
- Castle SiegeTemplate
Castle Siege — a Three.js starter mirrored from OpusGameLabs/game-creator.
- Crowd DashTemplate
Crowd Dash — a Three.js starter mirrored from OpusGameLabs/game-creator.
- Flappy Bird 3DTemplate
Flappy Bird 3D — a Three.js starter mirrored from OpusGameLabs/game-creator.