GitHub - cktang88/3d-fps: photorealistic 3d FPS, built by claude opus 5.5

GitHub

12 min read Original article ↗

IRONLINE — realistic browser FPS

A tactical first-person shooter that runs in the browser: three.js r186 rendering, Rapier physics, Recast/Detour navigation for bots, pmndrs/postprocessing + N8AO for the image pipeline and an AMD FSR 1 upscaler.

npm install
npm run dev      # http://localhost:5173
npm run build    # static build in dist/

Team deathmatch in the courtyard

Golden-hour sun over the office block Warehouse interior under sodium lamps
Low storm sun, god rays and wet asphalt Warehouse: practical lamps, light shafts, dust
Warehouse catwalk Container yard
Catwalk over the racking Container yard after the rain

In-engine captures at 1600x900, High quality (no post-edit).

Requirements & performance

  • A WebGL2 browser with hardware acceleration on. Chrome (or another Chromium browser) is recommended and is what the game is tested on.
  • First boot picks graphics settings from the GPU (Renderer.autoQuality): discrete GPUs get High + FSR Quality, Apple Silicon and integrated GPUs (Intel Iris/UHD, Radeon APUs) get Medium + FSR Balanced, software renderers and phones get Low + FSR Performance. On Apple GPUs the automatic setting also turns off the viewmodel light probe (a GPU→CPU readback) and the viewmodel shadow pass, which stall Metal's tile-based GPUs. Picking a quality or upscaling mode yourself turns this off.
  • Adaptive quality: while the quality is still automatic, a machine that averages under 30 fps steps one feature down at a time (AO → god rays → shadow map → viewmodel probe → bloom → render scale) and shows a toast. It never steps back up by itself; picking a quality in Settings resets it.
  • Graphics benchmark: Settings → Video → Run graphics benchmark. It replays a fixed 5-view camera tour once per step, turning one feature off per step, and reports frame ms (mean / p95), main-thread ms, GPU ms per pass (where EXT_disjoint_timer_query_webgl2 exists), draw calls and shader programs. Copy results gives a plain-text table for bug reports.
  • Budgets and measurements: docs/PERF.md.

Features

  • Map: Ironline Depot, an abandoned industrial compound at the edge of a live war zone: warehouse with catwalks and racks, two-storey office, container yard, western ruins and guard tower, central courtyard. Stormy golden hour after rain, with distant artillery, flares, smoke columns, burning wrecks, drizzle, lightning and helicopter fly-bys.
  • Movement (Source-style accel/friction): walk, sprint, tactical sprint (double-tap Shift, limited stamina), crouch, slide (crouch while sprinting), jump, vault over low cover, mantle onto ledges (also from the air), lean Q/E, slow walk (Alt, silent), fall damage. Full-body awareness: your own legs and shadow (PlayerBody.js).
  • Camera feel: eased recoil kick, trauma-based shake, head bob from mocap-derived curves (CamCurves.js), landing dip, lean/slide roll, sprint FOV, ADS zoom with zoom-relative sensitivity. Reduce camera motion scales it down.
  • Weapons (11): M4A1 and AK-47 (assault rifles), SCAR-L (battle rifle), MP5A5 (SMG), VSS Vintorez (marksman SMG), RPK-74 (LMG, drum), M870 MCS (pump shotgun), M24 SWS and AWM .338 (bolt-action), P226 and M1911A1 (pistols). Fire modes auto / burst / semi / pump / bolt (per weapon), sprint-to-fire delay, tactical vs empty reloads (+1 in the chamber, reload cancel before the commit point), shell-by-shell shotgun loading, bolt cycling, inspect, melee (backstabs kill), cookable frag grenades.
  • Recoil (Recoil.js, research in docs/RECOIL_RESEARCH.md): per-weapon climb and drift profiles that move your real aim; nothing returns during a string, so you pull down. A single tap settles back to the point of aim, longer strings only partly. Spread bloom, stance and movement modifiers, bipod bracing. Bots use the same recoil and control it according to difficulty.
  • Gunsmith (menu, or T while dead): optics (iron sights, red dot, holographic, 3.5x picture-in-picture combat scope, 8x sniper scope with 4x/8x zoom, glint and hold-breath), muzzle (suppressor, compensator, flash hider, brake), long/short barrel, vertical/angled grip, bipod, extended/fast mags, tac laser, all with live stat bars and TTK.
  • First-person presentation: per-weapon rigs (gloved arms skinned to each gun, built offline in Blender, see docs/FP_FRAMING.md) with an authored rifle animation set (idle, walk, sprint carry, fire, reload, equip), hand-authored reload choreography (ReloadChoreo.js) with the magazine in the support hand, IK for the support arm, pistol slide/flip springs, inspect animations.
  • Ballistics: projectile bullets with drop and travel time, damage falloff, headshot/limb multipliers, wall penetration through wood / plaster / thin metal, tracers, near-miss whiz and suppression.
  • Effects: muzzle flashes with dynamic light, surface-specific impacts (sparks, dust, chips, blood), bullet-hole decals with normal maps, physical brass, explosions and smoke (Unity Labs flipbooks).
  • Bots: perception (vision cone + LOS + hearing), memory, utility-scored goals (patrol, engage, investigate, cover, reload, grenade), difficulty-based aim (reaction time, tightening aim error, recoil control), strafing, navmesh pathing with crowd avoidance. Animated soldiers with layered upper/lower-body animation, mocap locomotion with foot locking, aim IK and procedural deaths. Four difficulties, 1–8 bots per team.
  • Modes: Team Deathmatch (first to 50) and Free-For-All (first to 25), 10-minute limit, line-of-sight-aware spawns, kill feed, score tally, medals, UAV killstreak at 4, scoreboard, XP and levels, end-of-match summary.
  • HUD: ammo / fire mode, health bar with streak pips, stamina, compass with pings, rotating minimap (UAV reveals enemies), dynamic crosshair (colour selectable), hitmarkers, damage direction arcs, grenade cook timer, scope overlay with breath bar, death card with killer health and killer cam, optional FPS counter (shows internal render scale).
  • Graphics: four quality presets (Low / Medium / High / Ultra), FSR 1 upscaling (EASU + RCAS; Quality / Balanced / Performance / Dynamic), CAS sharpening when upscaling is off, dynamic resolution, adaptive quality, built-in benchmark, N8AO, god rays, bloom, lens dirt, ACES + colour grade, SMAA, height fog, wet-surface puddles. Performance work: precomputed visibility (PVS, Pvs.js), cached static sun shadows (ShadowCache.js), point-light pool (LightPool.js), bot occlusion culling (Occlusion.js), runtime mesh LODs with an IndexedDB cache (Lod.js), baked navmesh, per-pass GPU timers (GpuTimer.js).

Controls

Defaults (src/core/Input.js; also listed in the in-game Controls page).

Key Action
W A S D / Mouse Move / look
LMB / RMB Fire / aim down sights (hold; Toggle ADS in Settings)
Middle mouse Switch 4x / 8x on the sniper scope
Shift Sprint · double-tap: tactical sprint · hold while scoped: hold breath
Space Jump · vault · mantle
C / Ctrl Crouch (toggle; Hold to crouch in Settings) · while sprinting: slide
Alt Slow walk (silent)
Q / E Lean left / right
R Reload
B Cycle fire mode
1 / 2 / mouse wheel Primary / secondary
V Melee
G Frag grenade (hold to cook, release to throw)
I Inspect weapon
L Toggle laser (with the Tac Laser fitted)
Tab Scoreboard (hold)
Esc Pause menu
T Gunsmith (while dead)

Settings

  • Mouse: sensitivity, ADS sensitivity multiplier, invert Y, toggle ADS, hold to crouch.
  • Video: field of view (70–120, default 100), viewmodel FOV, quality (Low / Medium / High / Ultra), upscaling (Off / FSR Quality / Balanced / Performance / Dynamic), sharpness (RCAS with FSR, CAS without), render-resolution readout, render scale (upscaling off), show FPS, dynamic resolution, adaptive quality, reduce camera motion, graphics benchmark, crosshair colour.
  • Audio: master volume.
  • Match: bot difficulty (Recruit / Regular / Hardened / Veteran), bots per team (1–8), practice mode (invulnerable).

Settings, loadout and career XP are stored in localStorage (ironline.settings).

Code map

src/main.js             boot, main loop, pointer lock
src/core/               Input, Physics (Rapier wrapper, hang forensics, step-skip), Audio (WebAudio + synth),
                        Assets (GLTF/meshopt/HDR loading), MathUtil (springs, damping)
src/render/             Renderer (presets, post stack, dynamic res), Fsr (FSR 1 EASU + RCAS), Effects (particles,
                        tracers, decals, brass), ProcTex (procedural textures), Perf (window.__perf instrumentation),
                        Benchmark, Adaptive (adaptive quality), GpuTimer, UploadRing (opt-in Apple/Metal mitigation),
                        Pvs, ShadowCache, Lod, LightPool, Occlusion (bot occlusion culling)
src/world/              Level (Ironline Depot), LevelEnv (HDRI, IBL, height fog, light shafts, dust),
                        Materials (PBR library + shared "unify" pass), Geo (world-UV boxes), Ambience +
                        ambience/ (DistantBattle, Fires, Weather, Flyover, AmbAudio, AmbParticles, flame, glsl)
src/game/               Game (loop, firing, grenades), Player (movement controller), PlayerBody (full-body
                        awareness), FPCamera, CamCurves (baked camera motion), Ballistics, Match (modes, spawns, medals)
src/game/weapons/       WeaponDefs (weapons + attachments + stats), Weapon (state machine), Recoil (aim recoil),
                        GunModels (model loading), ViewModel (first-person presentation), FPRig (rig + arm IK),
                        FPAnims (authored rifle animation set), ReloadChoreo (reload choreography)
src/game/bots/          Bot (AI), Character (third-person animation, IK, LOD), Navigation (Recast + Detour crowd)
src/ui/                 HUD, Menu (pages, settings, gunsmith, end screen), hud.css
public/assets/          models, textures, audio, HDRI, anims, baked nav/ and pvs/
tools/                  QA runner, bakes, Blender rig pipeline, audio/mocap prep (see tools/README.md)
docs/                   design specs, research and reports (see below)

Docs: QUALITY_BAR (principles and art direction), ART_PIPELINE (how assets are made to match), PERF, FP_FRAMING (first-person rig contract), QA_REPORT, RECOIL_RESEARCH, REFERENCE_ENEMIES (bot pose spec), ANIMATION_RESEARCH and ASSET_SOURCES (historical research).

Credits & licences

Code is original except where noted:

  • AMD FidelityFX Super Resolution 1.0 (EASU upscaling + RCAS sharpening): GLSL port of ffx_fsr1.h from GPUOpen-Effects/FidelityFX-FSR, Copyright (c) 2021 Advanced Micro Devices, Inc. — MIT licence (src/render/Fsr.js). The CAS sharpen used with upscaling off follows AMD FidelityFX CAS (MIT).
  • Libraries (npm, their own licences): three.js, Rapier, recast-navigation-js, postprocessing, N8AO, meshoptimizer (via three), Fontsource fonts.
  • Design references: Mugen87/dive & Yuka (bot architecture), Quake/Source movement, CS/Valorant/Insurgency/Tarkov recoil design, F.E.A.R. & Killzone bot AI talks.

Third-party assets shipped in public/assets/. CC BY items are credited here as the licence requires; "modified" means re-posed, re-rigged, rescaled, simplified, maker markings removed and/or textures re-encoded (WebP).

First-person weapons (models/fp/*.glb, built by tools/blender/; CC BY 4.0 unless noted; modified, AO baked):

Optics (models/weapons/optics.glb; CC BY 4.0; logos and markings removed, housings smoothed):

Fallback weapon set (models/weapons/*.glb other than optics.glb; the guns load only for weapons without an FP rig, the legacy arms still load at boot):

Characters (models/characters/):

World:

  • HDRI: Poly Haven "Bambanani Sunset" (Dimitrios Savva, Jarod Guest) — CC0 (hdr/bambanani_sunset_2k.hdr).
  • Props (models/props/): Poly Haven — CC0: old_military_crate, concrete_road_barrier(_02), Barrel_01/02, barrel_03, ammo_box, cardboard_box_01, old_tyre, exterior_aircon_unit, street_lamp_01, security_light, utility_box_01/02, metal_trash_can, water_manhole_cover, covered_car, trashbag, metal_jerrycan_green, propane_tank, portable_generator, hanging_industrial_lamp, mounted_fluorescent_lights, modular_industrial_pipes_01, wooden_crate_02, cement_bag, rusted_wheel_rim_01, WetFloorSign_01, barrel_stove (simplified, WebP via gltf-transform). Also shipped but not currently placed: rollershutter_door, street_lamp_02.
  • Surface textures (textures/), all CC0, re-encoded to WebP (AO baked into colour where present): ambientCG (https://ambientcg.com) Asphalt031, Bricks097, Concrete034, Concrete047A, Concrete048, Fabric083, Facade018A, Facade020A, Fence006, Ground110, Leaking003, Metal046B, Metal055A, Metal063, MetalWalkway013, OfficeCeiling006, PaintedPlaster015, PavingStones138, Plaster003, Tiles139, Wood051, Wood092; Poly Haven (https://polyhaven.com) concrete_floor, corrugated_iron, rusty_painted_metal, weathered_planks (WeatheredPlanks), rusty_corrugated_iron (RustyCorrugated). Some sets came via Tiddybub/3d-assets and operation-steel-tide.
  • Decal atlas (textures/DecalAtlas): ambientCG GraffitiSet001, Leaking012A, Leaking014A, Leaking016A, Leaking019B, Sign004, Sign009, Sign021, Tape001, TireTracks001, AsphaltDamage001 (CC0; cropped, alpha derived/aged), plus procedurally generated oil-stain, scorch, crack and stencil cells made for this project.
  • Ambience (ambience/): "Destroyed Ford Crown Vic" by alexdelker (https://sketchfab.com/3d-models/destroyed-ford-crown-vic-1506140c97654d759cc4c60c20d1d2a8) and "Sikorsky UH-60 Black Hawk" by helijah (https://sketchfab.com/3d-models/sikorsky-uh-60-black-hawk-ee81eb66006b4d8980d0cf9ff6304b69) — CC BY 4.0, simplified/re-lit (see public/assets/ambience/models/*/SOURCE.md); Unity Labs VFX flipbooks Explosion01, WispySmoke02, Flame03 — CC0; Poly Haven rusty_metal_04 — CC0.

Audio (audio/):

Fonts: Rajdhani, Barlow Condensed — SIL OFL, via Fontsource.

Source archives in the repo root (inputs to the offline pipelines, not loaded by the game):

  • Universal Animation Library[Standard].zip, Universal Animation Library 2[Standard].zip — Quaternius, CC0.
  • Blender_Source_Files_FreeFpsTemplate 2.zip — Free FPS Template (Fab), used under its Fab licence; source of the rifle animation set. It also contains the UE5 "Manny" mannequin and the "Low-Poly AAC Honey Badger" by TastyTony (CC BY 4.0); neither mesh is shipped in the game.