Template·three·v1.0.0·ISC

Gigachad Sim

Gigachad Sim — a Three.js starter mirrored from OpusGameLabs/game-creator.

#template#three#gigachad#sim

Install

npx create-gamecn my-game --template gigachad-sim

Source preview

Compatibility

Engines
three >=0.160.0
Frameworksvanilla
Languagesjavascript
Bundlersvite
Platformsweb, 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.js
  • gameplay/ — Player.js, WeightManager.js, PowerupManager.js
  • systems/ — 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 MODELS config section with paths, scales, and rotation for all 7 GLB files
  • Player.js — Replaced primitive box character with rigged GLB model using SkeletonUtils.clone() via loadAnimatedModel(). Walk/run animations loaded from separate GLB files. AnimationMixer drives smooth fadeToAction() 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 before startGame() 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 using THREE.Points with 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 — Added EFFECTS configuration 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. Creates ParticleManager, FloatingText, and ScreenEffects instances 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_HIT listener) in favor of the ScreenEffects system.
  • src/level/LevelBuilder.js — Exposed the directional light as this.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). Provides playMusic(patternFn), stopMusic(), and setMuted(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 — Added AUDIO_TOGGLE_MUTE: 'audio:toggleMute' event (now 20 events total)
  • src/core/GameState.jsisMuted now initializes from localStorage.getItem('muted') for persistence across sessions
  • src/main.js — Imports and initializes initAudioBridge() and MuteButton before 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 = 0 for 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