# 🌊💨 ADVANCED VISUAL SYSTEMS - MASTER PLAN **Created:** Jan 7, 2026 22:50 CET **Purpose:** Complete implementation plan for advanced shader & particle systems **Style:** Style 32 Dark-Chibi Noir compatible **Engine:** Phaser 3 + Custom Shaders --- ## 📋 TABLE OF CONTENTS 1. [Wind & Foliage System](#-1-wind--foliage-system) ✅ 2. [Water Displacement Mapping](#-2-water-displacement-mapping) 3. [Ripple Effects](#-3-ripple-effects) 4. [Caustics (Light Networks)](#-4-caustics-light-networks) 5. [Water Physics & Buoyancy](#-5-water-physics--buoyancy) 6. [Integration Plan](#-integration-plan) 7. [Performance Optimization](#-performance-optimization) --- ## 🌬️ 1. WIND & FOLIAGE SYSTEM **Status:** ✅ **IMPLEMENTED** (Jan 7, 2026) **File:** `src/systems/WindFoliageSystem.js` ### Features: - ✅ Vertex Shader for hair animation (Kai, Ana, Gronk dreads) - ✅ Perlin Noise algorithm for natural wind - ✅ Particle Emitter for falling leaves - ✅ Wobble physics - ✅ Biome-specific wind strength ### Technical Details: ```javascript // Wind strength per biome biomeWindSettings = { 'grassland': { strength: 1.0, frequency: 2.0 }, 'mountains': { strength: 2.0, frequency: 3.5 }, 'swamp': { strength: 0.3, frequency: 1.0 }, 'forest': { strength: 0.8, frequency: 2.5 }, 'desert': { strength: 1.5, frequency: 2.8 } } ``` ### Performance: - Uses shaders instead of sprite animations (RAM optimized) - CPU-side Perlin noise fallback - Particle pooling for leaves ### Integration: ```javascript // In GameScene.js create() this.windSystem = new WindFoliageSystem(this); this.windSystem.init(); // Apply to sprites this.windSystem.applyWindToSprite(kaiHairLayer, 'hair'); this.windSystem.applyWindToSprite(grassSprite, 'grass'); // Create leaf emitter this.windSystem.createLeafEmitter(treeX, treeY, 0.5); // In update() this.windSystem.update(delta); ``` --- ## 💧 2. WATER DISPLACEMENT MAPPING **Status:** ❌ **TODO - High Priority** **Purpose:** Light refraction when objects are underwater ### Concept: When Kai steps into water, the submerged part of her body should appear "wavy" due to light refraction (like looking at legs in a pool). ### Technical Approach: **Displacement Shader:** ```glsl // Fragment shader for underwater displacement precision mediump float; uniform sampler2D uMainSampler; uniform float uTime; uniform float uWaterLevel; // Y coordinate of water surface uniform float uDisplacementStrength; // 0.01 - 0.05 varying vec2 vTexCoord; varying vec2 vPosition; // Sine wave displacement vec2 getDisplacement(vec2 uv, float time) { float wave1 = sin(uv.x * 10.0 + time * 2.0) * 0.005; float wave2 = sin(uv.y * 8.0 + time * 1.5) * 0.005; return vec2(wave1, wave2) * uDisplacementStrength; } void main() { // Check if pixel is underwater if (vPosition.y > uWaterLevel) { // Apply displacement to UV coordinates vec2 displacement = getDisplacement(vTexCoord, uTime); vec2 distortedUV = vTexCoord + displacement; vec4 color = texture2D(uMainSampler, distortedUV); // Add slight blue tint underwater color.rgb = mix(color.rgb, vec3(0.4, 0.5, 0.6), 0.15); gl_FragColor = color; } else { // Above water - no distortion gl_FragColor = texture2D(uMainSampler, vTexCoord); } } ``` ### Implementation Plan: **File:** `src/systems/WaterDisplacementSystem.js` ```javascript class WaterDisplacementSystem { constructor(scene) { this.scene = scene; this.waterLevel = 0; // Y coordinate this.displacementStrength = 0.03; } createDisplacementShader() { // Create custom Phaser pipeline const DisplacementPipeline = new Phaser.Class({ Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline, initialize: function() { Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, { game: this.game, renderer: this.renderer, fragShader: [fragment shader code from above] }); } }); this.scene.game.renderer.addPipeline('waterDisplacement', new DisplacementPipeline()); } applyToSprite(sprite, waterY) { sprite.setPipeline('waterDisplacement'); sprite.pipeline.set1f('uWaterLevel', waterY); sprite.pipeline.set1f('uDisplacementStrength', this.displacementStrength); } update(time) { // Update time uniform for animation this.scene.children.list.forEach(child => { if (child.pipeline && child.pipeline.name === 'waterDisplacement') { child.pipeline.set1f('uTime', time * 0.001); } }); } } ``` ### Usage: ```javascript // In GameScene this.waterSystem = new WaterDisplacementSystem(this); this.waterSystem.createDisplacementShader(); // Apply to player when in water if (this.player.y > waterSurfaceY) { this.waterSystem.applyToSprite(this.player, waterSurfaceY); } ``` ### Style 32 Compatibility: - Displacement is SUBTLE (0.03 strength) - Maintains thick black outlines - Blue tint is minimal (15% mix) - Works with cell-shaded sprites --- ## 🌊 3. RIPPLE EFFECTS **Status:** ❌ **TODO - Medium Priority** **Purpose:** Create circular ripples when walking in water or when objects fall ### Concept: When Kai walks through shallow water, or when a leaf falls from a tree into water, circular ripples should emanate from the impact point. ### Technical Approach: **Particle-Based Ripples:** **File:** `src/systems/WaterRipplesSystem.js` ```javascript class WaterRipplesSystem { constructor(scene) { this.scene = scene; this.ripplesParticles = null; } init() { // Create ripple texture (Style 32 noir aesthetic) this.createRippleTexture(); // Initialize particle manager this.ripplesParticles = this.scene.add.particles('waterRipple'); } createRippleTexture() { const graphics = this.scene.add.graphics(); // Style 32: Thick black outline with subtle fill graphics.lineStyle(3, 0x000000, 1); // 3px black outline graphics.strokeCircle(32, 32, 28); // Outer circle graphics.lineStyle(2, 0x000000, 0.6); // Thinner inner ring graphics.strokeCircle(32, 32, 24); // Generate texture graphics.generateTexture('waterRipple', 64, 64); graphics.destroy(); } createRipple(x, y, size = 1.0) { const emitter = this.ripplesParticles.createEmitter({ x: x, y: y, lifespan: 1500, speed: 0, scale: { start: 0.1 * size, end: 2.0 * size }, alpha: { start: 0.7, end: 0 }, blendMode: 'NORMAL', frequency: -1, // Emit once quantity: 1, rotate: 0 }); emitter.explode(1); // Auto-destroy emitter after animation this.scene.time.delayedCall(1500, () => { emitter.stop(); this.ripplesParticles.removeEmitter(emitter); }); } createFootstepRipples(x, y) { // Smaller ripples for footsteps this.createRipple(x, y, 0.5); } createSplashRipples(x, y) { // Larger ripples for falling objects this.createRipple(x, y, 1.5); // Create multiple concentric ripples this.scene.time.delayedCall(150, () => this.createRipple(x, y, 1.2)); this.scene.time.delayedCall(300, () => this.createRipple(x, y, 0.9)); } } ``` ### Integration with Movement: ```javascript // In Player update() update(delta) { // Check if player is in water if (this.isInWater && this.velocity > 0) { // Create ripple at player position every 300ms if (this.scene.time.now - this.lastRippleTime > 300) { this.scene.waterRipples.createFootstepRipples(this.x, this.y + 16); this.lastRippleTime = this.scene.time.now; } } } ``` ### Integration with Wind System: ```javascript // In WindFoliageSystem - when leaf hits water onLeafLand(leaf) { if (this.isOverWater(leaf.x, leaf.y)) { this.scene.waterRipples.createSplashRipples(leaf.x, leaf.y); } } ``` --- ## ✨ 4. CAUSTICS (LIGHT NETWORKS) **Status:** ❌ **TODO - Medium Priority** **Purpose:** Animated dancing light patterns on underwater surfaces ### Concept: Those beautiful, shimmering light patterns you see on the bottom of a pool or cenote when sunlight refracts through moving water. ### Technical Approach: **Animated Texture with Additive Blending:** **File:** `src/systems/WaterCausticsSystem.js` ```javascript class WaterCausticsSystem { constructor(scene) { this.scene = scene; this.causticsLayers = []; } init() { // Generate procedural caustics texture this.generateCausticsTexture(); } generateCausticsTexture() { // Create 4 frames for animation for (let frame = 0; frame < 4; frame++) { const graphics = this.scene.add.graphics(); // Style 32 noir caustics: Subtle light patterns graphics.fillStyle(0xffffff, 0.15); // Draw organic light patterns (simplified) const offset = frame * 20; for (let i = 0; i < 20; i++) { const x = (Math.sin(i * 0.5 + offset) * 30) + 64; const y = (Math.cos(i * 0.7 + offset) * 30) + 64; const size = 15 + Math.sin(i) * 5; graphics.fillCircle(x, y, size); } graphics.generateTexture(`caustics_${frame}`, 128, 128); graphics.destroy(); } // Create animation this.scene.anims.create({ key: 'caustics_anim', frames: [ { key: 'caustics_0' }, { key: 'caustics_1' }, { key: 'caustics_2' }, { key: 'caustics_3' } ], frameRate: 6, repeat: -1 }); } addCausticsLayer(x, y, width, height, depthLayer = 0) { const caustics = this.scene.add.sprite(x, y, 'caustics_0') .setOrigin(0, 0) .setDisplaySize(width, height) .setBlendMode(Phaser.BlendModes.ADD) // Additive blend! .setAlpha(0.3) .setDepth(depthLayer); caustics.play('caustics_anim'); this.causticsLayers.push(caustics); return caustics; } setCausticsIntensity(intensity) { // Adjust based on water depth or time of day this.causticsLayers.forEach(layer => { layer.setAlpha(intensity * 0.3); }); } } ``` ### Usage: ```javascript // In WaterBiomeScene (Mexican Cenotes, Atlantis, etc.) create() { // Add caustics to water floor this.caustics = new WaterCausticsSystem(this); this.caustics.init(); // Add caustics layer to cenote floor this.caustics.addCausticsLayer( 0, waterFloorY, // Position mapWidth, 200, // Size -1 // Below player ); // Dynamic intensity based on depth if (playerDepth > 50) { this.caustics.setCausticsIntensity(0.2); // Darker at depth } } ``` ### Style 32 Compatibility: - Uses white light with low alpha (15-30%) - Additive blend mode for light effect - Subtle, not overpowering - Works on dark gothic floors --- ## 🏊 5. WATER PHYSICS & BUOYANCY **Status:** ❌ **TODO - High Priority** **Purpose:** Realistic movement underwater with drag and buoyancy ### Concept: - Kai moves 30% slower in water - Hair floats upward (dreads like in zero gravity) - Jumping is reduced underwater - Swimming animation triggers ### Technical Approach: **File:** `src/systems/WaterPhysicsSystem.js` ```javascript class WaterPhysicsSystem { constructor(scene) { this.scene = scene; // Physics constants this.waterDragFactor = 0.7; // 30% slower this.waterJumpReduction = 0.5; // 50% jump power this.buoyancyForce = -20; // Upward force this.hairFloatStrength = 1.5; // Hair rises more } applyWaterPhysics(player, isInWater) { if (isInWater) { // Apply drag to movement player.body.velocity.x *= this.waterDragFactor; player.body.velocity.y *= this.waterDragFactor; // Apply buoyancy (slow upward drift) player.body.velocity.y += this.buoyancyForce * this.scene.game.loop.delta * 0.001; // Modify jump power if (player.isJumping) { player.jumpVelocity *= this.waterJumpReduction; } // Trigger swimming animation if (!player.anims.currentAnim || player.anims.currentAnim.key !== 'swim') { player.play('swim'); } // Float hair upward this.floatHair(player, true); } else { // Reset hair this.floatHair(player, false); } } floatHair(player, float) { if (!player.hairLayer) return; if (float) { // Modify wind system to make hair float upward if (this.scene.windSystem) { // Override wind direction for hair to point UP this.scene.windSystem.windAffectedLayers.forEach(layer => { if (layer.sprite === player.hairLayer) { layer.buoyantMode = true; layer.floatStrength = this.hairFloatStrength; } }); } } else { // Restore normal wind behavior if (this.scene.windSystem) { this.scene.windSystem.windAffectedLayers.forEach(layer => { if (layer.sprite === player.hairLayer) { layer.buoyantMode = false; layer.floatStrength = 0; } }); } } } checkWaterDepth(x, y) { // Return depth: 0 = surface, 100 = deep // Can use tilemap water layer or zone detection const waterTile = this.scene.waterLayer.getTileAtWorldXY(x, y); if (!waterTile) return 0; // No water // Use tile properties for depth return waterTile.properties.depth || 50; } } ``` ### Enhanced Wind System Integration: **Update `src/systems/WindFoliageSystem.js`:** ```javascript // Add to WindFoliageSystem.update() update(delta) { this.time += delta * 0.001; this.windAffectedLayers.forEach(layer => { const { sprite, type, baseX, baseY, buoyantMode, floatStrength } = layer; if (!sprite || !sprite.active) return; if (buoyantMode && floatStrength > 0) { // UNDERWATER BUOYANCY MODE // Hair floats upward with gentle wave const floatOffset = Math.sin(this.time * 0.5) * 5 * floatStrength; sprite.y = baseY - floatOffset; // Negative = upward sprite.angle = floatOffset * 0.3; // Slight rotation } else { // NORMAL WIND MODE const noiseX = baseX * 0.01 * this.wind.frequency + this.time * this.wind.speed; const noiseY = baseY * 0.01 * this.wind.frequency + this.time * this.wind.speed * 0.7; const windNoise = this.perlinNoise(noiseX, noiseY); const displacement = windNoise * this.wind.strength * this.wind.amplitude; if (type === 'hair') { sprite.x = baseX + displacement * 1.5; sprite.angle = displacement * 0.5; } else if (type === 'grass') { sprite.x = baseX + displacement; } } }); // ... rest of update } ``` ### Usage: ```javascript // In GameScene update() update(time, delta) { const playerDepth = this.waterPhysics.checkWaterDepth(this.player.x, this.player.y); const isInWater = playerDepth > 10; this.waterPhysics.applyWaterPhysics(this.player, isInWater); // Update other systems this.windSystem.update(delta); } ``` --- ## 🔧 INTEGRATION PLAN ### Phase 1 - Core Systems (Already Done) - ✅ WindFoliageSystem ### Phase 2 - Water Effects (Next Priority) 1. **WaterPhysicsSystem** - Drag, buoyancy, hair float - Estimated time: 4-6 hours - Dependencies: WindFoliageSystem integration 2. **WaterRipplesSystem** - Footstep and splash ripples - Estimated time: 2-3 hours - Dependencies: None 3. **WaterDisplacementSystem** - Underwater refraction - Estimated time: 6-8 hours - Dependencies: Custom shader pipeline ### Phase 3 - Advanced Effects (Polish) 4. **WaterCausticsSystem** - Light networks - Estimated time: 3-4 hours - Dependencies: None ### File Structure: ``` src/systems/ ├── WindFoliageSystem.js ✅ Done ├── WaterPhysicsSystem.js ❌ TODO ├── WaterRipplesSystem.js ❌ TODO ├── WaterDisplacementSystem.js ❌ TODO └── WaterCausticsSystem.js ❌ TODO ``` ### Integration in GameScene: ```javascript // In GameScene.js create() { // Initialize all systems this.windSystem = new WindFoliageSystem(this); this.windSystem.init(); this.waterPhysics = new WaterPhysicsSystem(this); this.waterRipples = new WaterRipplesSystem(this); this.waterRipples.init(); this.waterDisplacement = new WaterDisplacementSystem(this); this.waterDisplacement.createDisplacementShader(); this.caustics = new WaterCausticsSystem(this); this.caustics.init(); // Set biome wind this.windSystem.setBiomeWind(this.currentBiome); // Apply systems to player this.windSystem.applyWindToSprite(this.player.hairLayer, 'hair'); } update(time, delta) { // Update all systems this.windSystem.update(delta); // Check if in water const depth = this.waterPhysics.checkWaterDepth(this.player.x, this.player.y); const isInWater = depth > 10; this.waterPhysics.applyWaterPhysics(this.player, isInWater); if (isInWater) { this.waterDisplacement.update(time); } } ``` --- ## ⚡ PERFORMANCE OPTIMIZATION ### RAM Optimization: - ✅ Shaders use GPU instead of sprite sheets - ✅ Particle pooling (max 50 active ripples) - ✅ Texture atlasing for caustics (4 frames only) - ❌ TODO: Level-of-Detail (LOD) - disable effects on mobile ### GPU Optimization: - ✅ Minimize shader complexity (max 20 instructions) - ✅ Use low-precision floats (mediump) - ❌ TODO: Batch draw calls - ❌ TODO: Frustum culling for particles ### CPU Optimization: - ✅ Perlin noise cached per frame - ✅ Water depth checks only on movement - ❌ TODO: Spatial partitioning for ripples ### Memory Budget: | System | Memory Usage | GPU Load | |--------|--------------|----------| | Wind | ~2MB | Low | | Ripples | ~5MB | Medium | | Displacement | ~1MB | High | | Caustics | ~3MB | Low | | **TOTAL** | **~11MB** | **Medium-High** | ### Target Performance: - 60 FPS on desktop (GTX 1060 equivalent) - 30 FPS on mobile (Snapdragon 855+) - Graceful degradation on low-end devices --- ## 📊 IMPLEMENTATION CHECKLIST ### Immediate (Next Session): - [ ] Implement WaterPhysicsSystem - [ ] Test hair buoyancy with WindFoliageSystem - [ ] Implement WaterRipplesSystem - [ ] Test ripples with player movement ### Short-Term (This Week): - [ ] Implement WaterDisplacementSystem - [ ] Create custom shader pipeline - [ ] Test underwater refraction effect - [ ] Style 32 compatibility testing ### Medium-Term (Next Week): - [ ] Implement WaterCausticsSystem - [ ] Generate procedural caustics textures - [ ] Integrate all systems in test scene - [ ] Performance profiling ### Long-Term (Phase 2): - [ ] Mobile optimization - [ ] Water surface waves (optional) - [ ] Underwater fog/particles (optional) - [ ] Rain effects integration --- ## 🎨 STYLE 32 COMPATIBILITY NOTES All systems MUST maintain Style 32 Dark-Chibi Noir aesthetic: 1. **Thick Black Outlines:** Ripples have 3px black strokes 2. **Cell-Shaded:** Displacement maintains flat color regions 3. **Subtle Effects:** All effects at 15-30% opacity 4. **Gothic Palette:** Use dark blues/greens for water tints 5. **No Realism:** Effects are stylized, not photorealistic --- ## 🔗 SYSTEM DEPENDENCIES ``` WindFoliageSystem (✅ Done) ↓ WaterPhysicsSystem (uses WindSystem for hair float) ↓ WaterRipplesSystem (triggered by WaterPhysics movement) ↓ WaterDisplacementSystem (visual only, independent) ↓ WaterCausticsSystem (visual only, independent) ``` --- ## 📝 NOTES TO SELF (ADHD-Friendly) 🌬️ **Wind = DONE!** (Check WindFoliageSystem.js) 💧 **Water Physics NEXT** → Start here! - Drag factor = player moves slow - Hair floats UP (modify WindSystem) - Swimming animation trigger 🌊 **Ripples EASY** → Do this second! - Just particles with scale+alpha animation - Style 32 = black circles - Trigger on footsteps ✨ **Displacement HARD** → Do this third! - Need custom shader pipeline - Test extensively - Fallback for mobile 💎 **Caustics OPTIONAL** → Polish phase - Low priority - Looks amazing but not critical - Mexican Cenotes will LOVE this! --- **TOTAL ESTIMATED TIME:** 15-25 hours across all systems **PRIORITY ORDER:** 1. WaterPhysicsSystem (critical for gameplay) 2. WaterRipplesSystem (polish, medium effort) 3. WaterDisplacementSystem (polish, high effort) 4. WaterCausticsSystem (optional, medium effort) --- *DolinaSmrti - Where even the water is gothic.* 🌊💀