# Project Context ## Project Type Game project (likely a game jam entry - ggj26). Features top-down twin-stick shooter gameplay. ## Asset Generation Uses ImageMagick scripts (`.imagemagick` files) in `assets_src/` to procedurally generate game assets. ### ImageMagick Script Conventions - Start with `#!/usr/bin/env magick-script` - Standard canvas: `512x512` - Consistent styling: 8px border with `rgb(58,58,58)`, slight blur (`0x0.3-0.5`) - Output to PNG via `-write png:-` - Color palette: grayscale tones (40-80 RGB range) ### Existing Assets - `floor.imagemagick`: Checkerboard pattern floor tile - `wall.imagemagick`: Gray wall tile with horizontal stripe - `player.imagemagick`: Top-down player sprite (circle body, shoulder pads, gun pointing east) - Pre-made button sprites: 18 PNG files for UI buttons (up/down states, 3x3 grid variations) ## Drawing Approach ImageMagick uses `-draw` commands for shapes. Player sprite demonstrates layering: - Base circle for body - Rounded rectangles for shoulder pads - Rectangles for gun barrel extending horizontally ## Shaders (`src/shaders/`) The game uses custom GLSL shaders with MoonScript/Lua setup code, built on the Amulet game engine. ### Rendering Architecture - **Pseudo-3D perspective**: Uses Z-coordinate scaling to create depth without true 3D projection - **Buffered rendering**: Pre-allocated vertex buffers for performance (world.moon sets MAX_PLAYERS=8, MAX_LEVEL_TRIS=1024) - **World-space rendering**: All shaders receive `world_x` and `world_y` uniforms for camera positioning - **Multi-lamp lighting**: Up to 8 dynamic lamps per shader with distance-based illumination ### Color Palette System All lit shaders use a consistent 7-color palette for quantized lighting: - `black` (darkest) - `outline` - `shadow` - `background` - `midground` - `foreground` - `highlight` (brightest) Colors are selected based on calculated light intensity thresholds (>1.0, >0.8, >0.6, >0.4, >0.2, else black). ### Individual Shaders #### Lake Shader (`lake.frag`, `lake.vert`, `lake.moon`) - Water surface rendering with dynamic lighting - Distance-based lamp illumination (up to 8 lamps: `lamp1` through `lamp8`) - Noise/random functions for visual texture - `streamer` uniform: toggles noise off for cleaner rendering - Normal map support via `atlas` texture and `norm` varying - Simple vertex shader (no rotation or Z-effects) #### Land Shader (`land.frag`, `land.vert`) - Ground/terrain rendering, nearly identical to lake shader - Additional `water` uniform: enables simplex noise animation when > 1 - Vertex shader includes rotation matrix (`rot` uniform) - Z-scaling for pseudo-3D perspective (clamped ±0.5) - Normal mapping support #### Player Shader (`player.frag`, `player.vert`) - Character rendering (currently shows UV debug visualization) - Supports texture mapping with `textures`, `emissives`, `normals` samplers - Directional rotation via `dir` uniform - Fixed Z-depth at -2 to position above world - Lamp support declared but not used in fragment shader #### Stars Shader (`stars.frag`, `stars.vert`, `stars.lua`) - Starfield background using point sprites - Procedurally generates ~500 stars in Lua setup - Stars arranged in 3×3 tiling pattern for infinite scrolling - Animated blinking: `gl_PointSize = pow(intensity, 2.) * stars.z * 0.3` where intensity = `sin(stars.z + time) * cos(time) + 1` - Stars avoid circular region in center (radius 0.5) for game area - Wrapping via `world_x_period` and `world_y_period` - Z-position: -0.1 (behind everything) #### World Shader (`world.frag`, `world.vert`, `world.moon`) - Main 3D geometry renderer for levels - Texture-mapped rendering (currently uses floor texture) - Pseudo-3D via Z-based offset: `xoff = clamp(world.z * vxy.x * z_scale, -32., 32.)` - Geometry generation in MoonScript: - `up_down_hall`: Creates hallway segments with floor and walls - `barrel`: Generates cylindrical objects with triangulated sides - `room`: Room generation (partially implemented) - Buffered architecture allows dynamic level geometry - Uses depth testing (`less`) and front-face culling - Support for round objects via radius attribute (unused currently) ### Technical Details - **Noise functions**: Simplex noise from Shadertoy (https://www.shadertoy.com/view/Msf3WH) - **Random function**: Hash-based PRNG by @patriciogv (2015) - **Lamp format**: `vec4(x, y, z, strength)` in normalized coordinates, scaled by 256 in shaders - **Coordinate system**: World space, with fragment coord offset by `worldxy * 256` - **View matrices**: Custom MV/P matrices in MoonScript, not standard OpenGL projection - **Engine**: Amulet (`am.*` functions), uses scene graph with `append`, `bind`, `draw` nodes