- Kotlin 100%
| .woodpecker | ||
| app | ||
| gradle/wrapper | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| build.gradle.kts | ||
| Dockerfile.build | ||
| gradle.properties | ||
| gradlew | ||
| LICENSE | ||
| README.md | ||
| settings.gradle.kts | ||
WeatherWall
Open-source, privacy-respecting, battery-friendly Android Live Wallpaper with low-poly vector layers, weather effects, seasonal events, and optional 3D parallax.
✨ Features
🎨 Visual Effects
- Low-poly parallax scene with layered mountains, hills, and pine trees
- Dynamic day/night cycle with smooth sky gradients (dawn, day, dusk, night)
- Procedural moon phases with accurate waxing/waning cycle
- Weather effects: Rain, Snow, Lightning with particle systems
- Fog overlay for atmospheric depth
- Cloud layers with wind-driven movement and soft blur
- Seasonal events: Christmas stars (Dec 15-26), New Year fireworks (Dec 27 - Jan 7)
🦅 Random Events
Animated wildlife and sky events appear randomly throughout the day:
- Day: Airplanes with contrails, bird flocks, eagles, butterflies, hot air balloons
- Night: Shooting stars, fireflies, owls, UFOs (very rare!)
- Any time: Rabbits hopping, foxes walking
🌲 Terrain System
- Layered hills with Perlin noise-based procedural generation
- Pine trees distributed along hillsides with configurable density and spread
- Realistic wind-based tree sway with ambient movement
- Sparsity control for natural treeline gaps
🔋 Battery-First Design
- Adaptive FPS (10-60 FPS configurable)
- Sensors only active when wallpaper is visible
- Zero per-frame allocations (pre-allocated paints, paths, particle pools)
- Efficient low-poly rendering without complex shaders
🔒 Privacy-First
- No trackers, analytics, or ads
- No INTERNET permission required
- Optional Breezy Weather integration for real weather data
- All processing done locally on device
☀️ Breezy Weather Integration
WeatherWall can receive real-time weather data from Breezy Weather (privacy-friendly weather app):
Supported data:
- Sunrise/sunset times - Accurate dawn and dusk transitions based on your location
- Weather conditions - Rain, snow, thunderstorm, fog, clouds affect visual effects
- Wind speed & direction - Drives cloud movement and tree sway
- Cloud cover - Adjusts cloud layer density
- Moon phase & times - Accurate lunar cycle display
Setup:
- Install Breezy Weather from F-Droid or GitHub
- Open Breezy Weather → Settings → External Modules
- Enable "Send Gadgetbridge data" → "Broadcast to all"
- Weather data will be received automatically
Without Breezy Weather, sensible defaults are used (sunrise 6:00, sunset 20:00).
⚙️ Customization
- Parallax strength, smoothing, return speed, and depth separation
- Sun/moon arc height, celestial size, moon enable/disable
- Tree density, spread, sparsity, and sway speed
- Cloud speed, opacity, density, and stretch
- Individual event toggles (enable/disable specific animals)
- Mountain and hill count, height, roughness
- Simulation mode for testing time, weather, wind, moon phase
📱 Screenshots
Coming soon
🚀 Quick Start
Build from Source
# Clone the repository
git clone https://git.olli.info/Oliver/WeatherWall.git
cd WeatherWall
# Build debug APK
./gradlew assembleDebug
# Install on connected device
adb install app/build/outputs/apk/debug/app-debug.apk
Build with Docker (Recommended for CI)
For faster repeated builds, use the pre-cached Docker image:
# Build the cached builder image (one-time, ~5 min)
docker build -t weatherwall-builder -f Dockerfile.build .
# Run tests (~30 sec with cached image)
docker run --rm -v "$PWD":/workspace -w /workspace weatherwall-builder "./gradlew test --no-daemon"
# Build debug APK (~20 sec with cached image)
docker run --rm -v "$PWD":/workspace -w /workspace weatherwall-builder "./gradlew assembleDebug --no-daemon"
# Run tests and build together
docker run --rm -v "$PWD":/workspace -w /workspace weatherwall-builder "./gradlew test assembleDebug --no-daemon"
Without cached image (slower, downloads Gradle each time):
docker run --rm -v "$PWD":/workspace -w /workspace ghcr.io/cirruslabs/android-sdk:35 ./gradlew test assembleDebug --no-daemon
Build Release
./gradlew assembleRelease
🧪 Testing
The project includes 290+ unit tests covering all major features:
# Run all tests locally
./gradlew test
# Run tests in Docker
docker run --rm -v "$PWD":/workspace -w /workspace weatherwall-builder "./gradlew test --no-daemon"
# View test report
open app/build/reports/tests/testDebugUnitTest/index.html
Test Coverage:
ParallaxSceneTest- Terrain baseline, parallax factors, color transitionsParallaxSensorManagerTest- Rotation matrix, orientation extractionParallaxCalculatorTest- Return speed, tilt thresholdsDayNightCycleTest- Time periods, sunset colors, manual time overrideWeatherRepositoryTest- Data freshness, staleness detectionSeasonalEventsTest- Christmas/New Year detection, debug overridesCloudLayerTest- Soft edges, density levels, bitmap sizingSkyLayerTest- Moon phases, celestial renderingTreeRenderingTest- Placement, depth coloring, scalingHillsTerrainTest- Layer ordering, parallax matchingBuildConfigTest- Version codes, surface lifecycle
🏗️ Project Structure
app/src/main/java/info/olli/weatherlwp/
├── MainActivity.kt # Settings activity
├── parallax/
│ ├── ParallaxCalculator.kt # Parallax offset calculations
│ └── ParallaxSensorManager.kt # Accelerometer-based parallax input
├── prefs/
│ └── SettingsFragment.kt # Preferences UI with event spawning
├── rendering/
│ ├── CloudLayer.kt # Animated cloud shapes with caching
│ ├── MountainLayer.kt # Background mountain silhouettes
│ ├── ParallaxScene.kt # Main scene renderer and layer orchestration
│ ├── RandomEventLayer.kt # Wildlife and sky event management
│ ├── RenderConstants.kt # Shared rendering constants
│ ├── SceneLayer.kt # Layer interface for all renderers
│ ├── SeasonalEvents.kt # Christmas/New Year effects
│ ├── SkyLayer.kt # Gradient sky, sun/moon with phases
│ ├── TerrainLayer.kt # Hills and trees with wind animation
│ ├── WeatherLayer.kt # Rain/Snow/Lightning particles
│ └── events/ # Individual event implementations
│ ├── AirplaneEvent.kt
│ ├── AlienEvent.kt
│ ├── BirdFlockEvent.kt
│ ├── ButterflyEvent.kt
│ ├── EagleEvent.kt
│ ├── FireflyEvent.kt
│ ├── FoxEvent.kt
│ ├── HotAirBalloonEvent.kt
│ ├── OwlEvent.kt
│ ├── RabbitEvent.kt
│ ├── RandomEvent.kt # Event interface and EventLayer enum
│ └── ShootingStarEvent.kt
├── simulation/
│ ├── SimulationClock.kt # Time-based day/night calculations
│ ├── SimulationController.kt # Main simulation state manager
│ ├── SimulationSettings.kt # Preference reader
│ └── SimulationState.kt # Immutable state snapshot per frame
├── wallpaper/
│ └── WeatherWallpaper.kt # WallpaperService implementation
└── weather/
├── BreezyWeatherProvider.kt # Breezy Weather integration
├── BreezyWeatherReceiver.kt # Broadcast receiver for weather updates
├── WeatherProvider.kt # Weather data interface
├── WeatherRepository.kt # Weather data storage
└── WeatherType.kt # Weather type enumeration
🔧 Requirements
- Android 8.0+ (API 26)
- Android Studio Hedgehog or newer (for development)
- Gradle 8.13+
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
🔗 Links
- Repository: git.olli.info/Oliver/WeatherWall
- CI/CD: ci.olli.info
- Issues: Report a bug