# Dynamic Sky System for Godot 4.6

A stylized dynamic sky system with day/night cycles, weather, clouds, and VFX.

## Setup Instructions

### Step 1: Open Project in Godot
1. Open your Godot 4.6 project
2. Wait for the editor to import all scripts (check the bottom progress bar)
3. If you see script errors, click **Project > Reload Current Project**

### Step 2: Add to Your Scene
1. Open the scene where you want the sky system
2. Drag `dynamic-sky/dynamic_sky.tscn` into your scene tree
3. Or right-click in the scene tree → **Instance Child Scene** → select `dynamic_sky.tscn`

### Step 3: Configure the Environment
The DynamicSky node auto-creates required children. To link an existing environment:

1. Select the **DynamicSky** node
2. In the Inspector, under **Environment**:
   - Assign your existing `WorldEnvironment` node (or leave empty to auto-create)
   - Assign existing `DirectionalLight3D` for sun/moon (or leave empty)

### Step 4: Generate Cloud Textures
Clouds need textures. Use the procedural generator:

```gdscript
# In a tool script or _ready():
var cloud_tex = ProceduralCloudTexture.create_default_cloud_texture(1)
$DynamicSky/CloudSystem.layer_configs[0].texture = cloud_tex
```

Or assign existing cloud textures to each `CloudLayerConfig` in the Inspector.

### Step 5: Configure Shadow Texture
```gdscript
var shadow_tex = ProceduralCloudTexture.create_shadow_texture()
$DynamicSky/ShadowProxySystem.shadow_texture = shadow_tex
```

## Testing the System

### Test 1: Basic Scene Test
1. Create a new 3D scene with a `Camera3D` and a `MeshInstance3D` (e.g., plane for ground)
2. Instance `dynamic_sky.tscn`
3. Run the scene (F5)
4. You should see a gradient sky with sun light

### Test 2: Time of Day
Add this script to test time changes:

```gdscript
extends Node

@onready var sky = $DynamicSky

func _ready():
	# Start at morning
	sky.set_time_of_day(0.25)

func _process(delta):
	# Press keys to change time
	if Input.is_action_just_pressed("ui_right"):
		sky.set_time_of_day(sky.get_time_of_day() + 0.05)
	if Input.is_action_just_pressed("ui_left"):
		sky.set_time_of_day(sky.get_time_of_day() - 0.05)
	
	# Print current time
	if Input.is_action_just_pressed("ui_accept"):
		print("Time: ", sky.get_time_of_day())
```

### Test 3: Weather System
```gdscript
func _input(event):
	if event.is_action_pressed("ui_up"):
		$DynamicSky.set_weather(WeatherProfile.WeatherState.RAIN)
	if event.is_action_pressed("ui_down"):
		$DynamicSky.set_weather(WeatherProfile.WeatherState.CLEAR)
```

### Test 4: Debug Panel
1. Add a `CanvasLayer` to your scene
2. Add a `Control` node as child
3. Attach the `sky_debug_panel.gd` script
4. In Inspector, assign the `DynamicSky` node to the `dynamic_sky` property
5. Run and use the UI controls

### Test 5: Meteor Shower
```gdscript
func _ready():
	# Ensure it's night for visibility
    $DynamicSky.set_time_of_day(0.0)
    # Wait a moment then trigger
    await get_tree().create_timer(1.0).timeout
    $DynamicSky.trigger_meteor_shower(30.0)
```

### Test 6: Kill Volumes
1. Add an `Area3D` to your scene
2. Attach `weather_kill_volume.gd` script
3. Configure the shape and size in Inspector
4. Precipitation will be blocked inside this volume

## Complete Test Scene Example

Create a new scene with this structure:

```
TestScene (Node3D)
├── DynamicSky (instance of dynamic_sky.tscn)
├── Camera3D
├── Ground (MeshInstance3D with PlaneMesh)
├── CanvasLayer
│   └── DebugPanel (Control with sky_debug_panel.gd)
└── TestScript (Node with test script below)
```

Test script:
```gdscript
extends Node

@onready var sky = $"../DynamicSky"

func _ready():
    # Generate cloud textures
    _setup_clouds()
    
    # Start at mid-morning
    sky.set_time_of_day(0.35)
    
    print("Dynamic Sky Test Ready!")
    print("Arrow keys: Change time")
    print("1-6: Change weather")
    print("M: Meteor shower")
    print("P: Pause/Resume time")

func _setup_clouds():
    var cloud_system = sky.cloud_system
    if cloud_system:
        for i in cloud_system.layer_configs.size():
            var tex = ProceduralCloudTexture.create_default_cloud_texture(i)
            cloud_system.layer_configs[i].texture = tex
        cloud_system.rebuild_layers()
    
    var shadow_system = sky.shadow_proxy_system
    if shadow_system:
        shadow_system.shadow_texture = ProceduralCloudTexture.create_shadow_texture()

func _input(event):
    if event is InputEventKey and event.pressed:
        match event.keycode:
            KEY_RIGHT:
                sky.set_time_of_day(wrapf(sky.get_time_of_day() + 0.02, 0, 1))
            KEY_LEFT:
                sky.set_time_of_day(wrapf(sky.get_time_of_day() - 0.02, 0, 1))
            KEY_1:
                sky.set_weather(WeatherProfile.WeatherState.CLEAR)
            KEY_2:
                sky.set_weather(WeatherProfile.WeatherState.CLOUDY)
            KEY_3:
                sky.set_weather(WeatherProfile.WeatherState.OVERCAST)
            KEY_4:
                sky.set_weather(WeatherProfile.WeatherState.RAIN)
            KEY_5:
                sky.set_weather(WeatherProfile.WeatherState.STORM)
            KEY_6:
                sky.set_weather(WeatherProfile.WeatherState.SNOW)
            KEY_M:
                sky.trigger_meteor_shower(30.0)
            KEY_P:
                if sky.day_night_controller.paused:
                    sky.resume_time()
                else:
                    sky.pause_time()
```

## Troubleshooting

| Issue | Solution |
|-------|----------|
| Script errors on load | Reload project: Project → Reload Current Project |
| No sky visible | Ensure camera is looking up; check WorldEnvironment exists |
| Clouds not visible | Assign textures to CloudLayerConfig or generate procedurally |
| Shadows not visible | Assign shadow_texture to ShadowProxySystem |
| Stars not visible | Set time to night (0.0 or 0.9+); check stars_visibility curve |
| Time not advancing | Check `paused` is false on DayNightController |
| Weather not changing | Check WeatherController has profiles; look at transition progress |

## Features

### Preset Skybox Nodes
- 6 presets: Clear Day, Sunset, Night, Overcast, Storm, Dawn
- Runtime preset switching with smooth transitions
- Non-destructive overrides

### Day/Night Cycle
- Configurable day length (1-1440 minutes)
- Sun/moon arc movement
- Color/intensity curves for sun, moon, ambient, fog
- Star visibility at night
- Time events (sunrise, sunset, noon)

### Weather System
- States: Clear, Cloudy, Overcast, Rain, Storm, Snow
- Smooth transitions between states
- Per-state cloud, wind, and VFX settings
- Random or scripted weather timelines

### 2D Cloudscapes
- 4 independent layers (low, mid, high, wisps)
- Per-layer texture, tiling, opacity, color
- Flow animation with wind influence
- Evolution/morphing over time
- Reactive to sun/moon lighting

### Post-Processing
- Sky gradient shading
- Height and distance fog
- Sun glow halo
- Dawn/dusk enhancement
- Procedural stars

### VFX
- Shooting stars (randomized)
- Meteor showers (event-triggered)
- Configurable appearance

### Cloud Shadows
- Projected shadow overlay
- Syncs with cloud movement
- Blur and opacity controls

### Kill Volumes
- Block precipitation in indoor areas
- Box, sphere, cylinder shapes
- Fade-out margins

## Quick Start

1. Add `dynamic_sky.tscn` to your scene
2. Reference the DynamicSky node in your scripts
3. Use the API:

```gdscript
# Get reference
@onready var sky = $DynamicSky

# Set time (0.0-1.0, where 0.5 = noon)
sky.set_time_of_day(0.5)

# Change weather
sky.set_weather(WeatherProfile.WeatherState.RAIN)

# Apply preset
sky.apply_preset("Sunset")

# Trigger meteor shower
sky.trigger_meteor_shower(60.0)
```

## Debug Panel

Add `SkyDebugPanel` to your UI and assign the DynamicSky reference to see:
- Current time and weather
- Cloud coverage
- Controls for testing

## Resources

- `SkyConfig`: Global sky parameters
- `SkyPreset`: Complete preset configuration  
- `WeatherProfile`: Per-weather-state settings
- `CloudLayerConfig`: Per-layer cloud settings
- `PostProcessProfile`: Post-processing parameters

## Performance

- Disable unused cloud layers
- Reduce cloud texture resolution
- Lower VFX update rates
- Disable shadow blur on low-end hardware
