📘 ADD: Advanced Visual Systems Master Plan

NEW DOC: ADVANCED_VISUAL_SYSTEMS_PLAN.md

🌊💨 Complete implementation plan for:
 Wind & Foliage System (DONE)
 Water Physics & Buoyancy
 Water Ripples (footsteps, splash)
 Water Displacement (refraction shader)
 Caustics (light networks)

📝 Includes:
- Full shader code (GLSL)
- Phaser 3 integration
- Performance optimization
- Style 32 compatibility
- 15-25h time estimate

🎯 Priority: WaterPhysics → Ripples → Displacement → Caustics

📁 Location: docs/technical/
This commit is contained in:
2026-01-07 22:53:44 +01:00
parent 136ad9f544
commit eb78618ea1

View File

@@ -0,0 +1,766 @@
# 🌊💨 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.* 🌊💀