skeledance/CLAUDE.md
vini a181614e38 Add golden-hour veil driven by real sun altitude
New #duskSky layer — purple high up through coral to deep orange at the
horizon — whose opacity is a smoothstepped triangle peaking at +1° sun
altitude and vanishing outside -6°..+8°. It rides above the day sky and
also glows over the stars right after sunset and before sunrise.
Hidden in balada/chuva.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015HtPHsTnDcLVSCiF5FGHZj
2026-07-19 22:02:37 -03:00

73 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this is
A KDE Plasma 6 wallpaper plugin — a dancing retrowave robot (DANCEBOT-9000) that reacts to currently playing music via `playerctl`. No build step, no dependencies to install; the plugin is deployed directly.
Plugin ID: `com.vini.dancingcharacter`
Install path: `~/.local/share/plasma/wallpapers/com.vini.dancingcharacter`
## Deploy / test cycle
```bash
# Install (or reinstall after edits)
./install.sh
# Remove
./uninstall.sh
```
After install, activate via: Right-click desktop → Configure Desktop and Wallpaper → Wallpaper Type → Dancing Character.
Plasma hot-reloads QML changes when you reinstall; for HTML/CSS/JS changes you may need to switch away and back to the wallpaper type to force a reload.
**Runtime requirement**: `QtWebEngine` QML module must be installed (e.g., `qml6-module-qtwebengine` on Debian/Ubuntu). `playerctl` must be running for the music ticker to show track info.
## Architecture
```
plugin/
metadata.json # KPackage/KPlugin descriptor for Plasma 6
contents/ui/
main.qml # Plasma WallpaperItem — hosts everything
dancer.html # Self-contained animation (HTML + CSS + JS)
starcatalog.js # Generated star data (Yale BSC) — see tools/build_catalog.py
constellations.js # Generated zodiac lines — see tools/build_constellations.py
milkyway.jpg # Gaia all-sky photo, plate carrée — see tools/build_skymap.py
astronomy.browser.min.js # Astronomy Engine (MIT) — Moon/planet ephemerides
tools/
build_catalog.py # Regenerates starcatalog.js from the Yale Bright Star Catalog
build_constellations.py # Regenerates constellations.js (Stellarium Modern + d3-celestial)
build_skymap.py # Reprojects ESA Gaia all-sky map (Hammer → plate carrée)
```
### main.qml — the Plasma host
- Declares a `WallpaperItem` with a full-screen `WebEngineView` pointed at `dancer.html`.
- A `Plasma5Support.DataSource` with `engine: "executable"` runs `playerctl metadata` every 2 s and injects the result into the page with `webView.runJavaScript("updateMusic(...)")`.
- JavaScript is enabled; local file access and local storage are on/off respectively.
### dancer.html — the visual layer
Pure HTML/CSS/JS, no external dependencies. All visuals are self-contained:
| Layer | Technique |
|---|---|
| Realistic sky (stars) | `<canvas>`; real-time alt-az projection of `starcatalog.js` (8,404 Yale BSC stars, V ≤ 6.5) for the configured lat/long (default Toledo-PR). Static layer pre-rendered offscreen with triple-buffer + 1.4 s crossfade between reprojections (every 30 s; 4 s during timelapse/camera rotation); bright stars twinkle per frame. Debug: `window.__skyTimeOffset` (ms) fast-forwards the sky |
| Milky Way | Per-pixel sampling of `milkyway.jpg` (Gaia photo, full res): `buildMwGrid` caches viewport unit vectors + extinction/glare, `renderMilkyWay` applies only the sidereal rotation (camera azimuth folded into the equatorial→galactic matrix) and stylized "development" (deep blacks, saturation, cool shadows). Decoded texture stays resident (~75 MB) |
| Moon & planets | Astronomy Engine topocentric ephemerides: Moon with real phase texture + bright-limb angle, 7 planets with magnitude-scaled dots (labels only in constellation mode) |
| Zodiac constellations | Stellarium Modern lines (traces only, no artwork); toggled via `/tmp` file or `C` key |
| Day mode | Real sun altitude (Astronomy Engine, follows the timelapse clock) drives `--sun-bottom` (horizon → ~78% at culmination) and a `dia` body class: pink vaporwave `#daySky` with green grass below the horizon, drifting CSS clouds, bright sun disc, golden horizon, stars dimmed to ghosts (0.12), dancer replaced by a grounded gravestone (CC0 tileset PNG, flattened-ellipse mound/shadow for perspective, no religious symbols). A `#duskSky` golden-hour veil peaks at sun altitude +1° (zero outside 6°..+8°), JS-driven, on both dawn and dusk. Balada/chuva override day visuals via `:not()` selectors |
| Nebula blobs, grid floor, horizon | CSS animations |
| DANCEBOT-9000 robot | Pure CSS (divs + `@keyframes`) |
| Chest EQ bars & VU meter | JS-driven `requestAnimationFrame` |
| Music ticker / album art / karaoke lyrics | DOM text set by `updateMusic(artist, title)` (called from QML); lyrics left, album art right, ticker centered — all with dark veils/shadows for contrast over the Milky Way |
| Dance style cycling | `data-dance` attribute on `<body>`, toggled by JS every 8 s |
**Runtime controls** (state files in `/tmp/skeledance-*`, polled every 800 ms by dancer.html; each has a root-level helper script): `toggle-balada.sh`, `toggle-chuva.sh` (mutually exclusive modes), `toggle-constellations.sh`, `preview-constellation.sh <Vir|off>`, `set-camera-position.sh <norte|leste|sul|oeste|graus>`, `toggle-camera-rotation.sh` (360° pan in 5 min), `toggle-sky-timelapse.sh` (360× time), `set-sky-time.sh <HH:MM|off>` (jump the sky clock to a time of day; combines with the timelapse). `test-modes.sh` reloads the plugin and cycles modes.
**Tempo anchor**: everything is keyed to 120 BPM (`BEAT_MS = 500 ms`). CSS animation durations for the robot parts use multiples/fractions of 0.5 s, 1 s, or 2 s.
**Dance styles** (cycle order): `bounce → wave → shuffle → moonwalk → spin`. CSS selectors like `[data-dance="spin"] .robot { ... }` override the default animations via `!important`.