Remove constellation artwork, keep line traces only

Drops the 12 zodiac PNGs, their loader/similarity-transform renderer and
the art anchors in constellations.js; build_constellations.py no longer
emits art data. Constellation mode now shows just the Stellarium traces,
labels and stars.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015HtPHsTnDcLVSCiF5FGHZj
This commit is contained in:
vini 2026-07-19 21:10:33 -03:00
parent f5e1949c91
commit e31a675ebe
17 changed files with 4 additions and 168 deletions

View file

@ -34,8 +34,7 @@ plugin/
main.qml # Plasma WallpaperItem — hosts everything main.qml # Plasma WallpaperItem — hosts everything
dancer.html # Self-contained animation (HTML + CSS + JS) dancer.html # Self-contained animation (HTML + CSS + JS)
starcatalog.js # Generated star data (Yale BSC) — see tools/build_catalog.py starcatalog.js # Generated star data (Yale BSC) — see tools/build_catalog.py
constellations.js # Generated zodiac lines/anchors — see tools/build_constellations.py constellations.js # Generated zodiac lines — see tools/build_constellations.py
constellation-art/ # 12 zodiac PNGs (black background → alpha at load)
milkyway.jpg # Gaia all-sky photo, plate carrée — see tools/build_skymap.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 astronomy.browser.min.js # Astronomy Engine (MIT) — Moon/planet ephemerides
tools/ tools/
@ -59,7 +58,7 @@ Pure HTML/CSS/JS, no external dependencies. All visuals are self-contained:
| 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 | | 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) | | 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) | | 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 + anchored PNG art (similarity transform, no shear); toggled via `/tmp` file or `C` key | | Zodiac constellations | Stellarium Modern lines (traces only, no artwork); toggled via `/tmp` file or `C` key |
| Nebula blobs, grid floor, horizon | CSS animations | | Nebula blobs, grid floor, horizon | CSS animations |
| DANCEBOT-9000 robot | Pure CSS (divs + `@keyframes`) | | DANCEBOT-9000 robot | Pure CSS (divs + `@keyframes`) |
| Chest EQ bars & VU meter | JS-driven `requestAnimationFrame` | | Chest EQ bars & VU meter | JS-driven `requestAnimationFrame` |

View file

@ -1,11 +0,0 @@
# Stellarium Modern constellation illustrations
The twelve PNG illustrations in this directory are taken from the
[Stellarium Modern sky culture](https://github.com/Stellarium/stellarium/tree/master/skycultures/modern/illustrations).
The Stellarium sky-culture description licenses the illustrations under the
[Free Art License 1.3](https://artlibre.org/licence/lal/en/).
The images are redistributed here with their original names and are rendered
with an affine transformation so their three Hipparcos anchor stars remain
aligned with the simulated sky.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

File diff suppressed because one or more lines are too long

View file

@ -1233,40 +1233,6 @@ const ctx = canvas.getContext('2d');
let obsLat = -24.72, obsLon = -53.74; // Toledo-PR; sobrescrito pela config let obsLat = -24.72, obsLon = -53.74; // Toledo-PR; sobrescrito pela config
let showConstellations = false; let showConstellations = false;
let constellationPreviewId = null; let constellationPreviewId = null;
const constellationArtImages = new Map();
if (typeof CONSTELLATIONS !== 'undefined') {
for (const constellation of CONSTELLATIONS) {
if (!constellation.art) continue;
const img = new Image();
const entry = { img, render: null };
img.onload = () => {
/* Os originais usam preto como transparência. Convertê-lo em alpha
evita que a transformação afim revele os limites retangulares. */
const out = document.createElement('canvas');
out.width = constellation.art.size[0];
out.height = constellation.art.size[1];
const oc = out.getContext('2d', { willReadFrequently: true });
oc.drawImage(img, 0, 0, out.width, out.height);
const pixels = oc.getImageData(0, 0, out.width, out.height);
for (let i = 0; i < pixels.data.length; i += 4) {
const r = pixels.data[i], g = pixels.data[i + 1], b = pixels.data[i + 2];
const light = Math.max(r, g, b);
const mask = Math.max(0, Math.min(1, (light - 9) / 118));
pixels.data[i] = 105 + light * 0.42;
pixels.data[i + 1] = 175 + light * 0.27;
pixels.data[i + 2] = 235 + light * 0.08;
pixels.data[i + 3] = pixels.data[i + 3] * mask;
}
oc.clearRect(0, 0, out.width, out.height);
oc.putImageData(pixels, 0, 0);
entry.render = out;
projectSky();
};
img.onerror = () => console.error('[skeledance] falha na arte de ' + constellation.name);
img.src = constellation.art.file;
constellationArtImages.set(constellation.id, entry);
}
}
const CAMERA_HOME_AZ = 90; // posição inicial: leste const CAMERA_HOME_AZ = 90; // posição inicial: leste
const CAMERA_TURN_MS = 5 * 60 * 1000; const CAMERA_TURN_MS = 5 * 60 * 1000;
let viewAz = CAMERA_HOME_AZ; let viewAz = CAMERA_HOME_AZ;
@ -1546,105 +1512,6 @@ function renderMilkyWay(lstDeg, glareOn) {
return true; return true;
} }
/* Ajuste de similaridade: aproxima as três âncoras Hipparcos usando apenas
translação, rotação e escala uniforme. Diferente de uma transformação
afim completa, nunca achata nem alonga a anatomia das ilustrações. */
function constellationArtTransform(source, target) {
const pc = source.reduce((p, v) => [p[0] + v[0], p[1] + v[1]], [0, 0])
.map(v => v / source.length);
const qc = target.reduce((p, v) => [p[0] + v.x, p[1] + v.y], [0, 0])
.map(v => v / target.length);
let dot = 0, cross = 0, mirrorA = 0, mirrorB = 0, energy = 0;
for (let i = 0; i < source.length; i++) {
const px = source[i][0] - pc[0], py = source[i][1] - pc[1];
const qx = target[i].x - qc[0], qy = target[i].y - qc[1];
dot += px * qx + py * qy;
cross += px * qy - py * qx;
mirrorA += px * qx - py * qy;
mirrorB += py * qx + px * qy;
energy += px * px + py * py;
}
if (energy < 1e-6) return null;
const candidate = (a, b, c, d) => {
const e = qc[0] - a * pc[0] - c * pc[1];
const f = qc[1] - b * pc[0] - d * pc[1];
const matrix = [a, b, c, d, e, f];
const error = source.reduce((sum, p, i) => {
const dx = a * p[0] + c * p[1] + e - target[i].x;
const dy = b * p[0] + d * p[1] + f - target[i].y;
return sum + dx * dx + dy * dy;
}, 0);
return { matrix, error };
};
const rotate = candidate(dot / energy, cross / energy,
-cross / energy, dot / energy);
/* Ao observar a esfera por dentro, várias cartas precisam inverter a
orientação leste/oeste. Esta alternativa inclui a reflexão sem shear. */
const reflect = candidate(mirrorA / energy, mirrorB / energy,
mirrorB / energy, -mirrorA / energy);
return (reflect.error < rotate.error ? reflect : rotate).matrix;
}
function drawConstellationArt(c, constellation, lst, W, horizonPx, previewProjector) {
const art = constellation.art;
const imageEntry = constellationArtImages.get(constellation.id);
if (!art || !imageEntry || !imageEntry.render) return;
const target = art.anchors.map(anchor => {
if (previewProjector) {
const sc = previewProjector(anchor.sky);
return { x: sc.x, y: sc.y, alt: ALT_TOP / 2 };
}
const aa = altAz(anchor.sky[0], anchor.sky[1], lst);
const daz = ((aa.az - viewAz) % 360 + 540) % 360 - 180;
return {
x: (0.5 + daz / FOV_AZ) * W,
y: horizonPx * (1 - aa.alt / ALT_TOP),
alt: aa.alt,
};
});
if (target.every(p => p.alt < -8) || target.every(p => p.alt > ALT_TOP + 8)) return;
if (!target.some(p => p.alt >= -8 && p.alt <= ALT_TOP + 8 &&
p.x >= -W * 0.15 && p.x <= W * 1.15)) return;
const targetXs = target.map(p => p.x);
if (Math.max(...targetXs) - Math.min(...targetXs) > W * 0.62) return;
const matrix = constellationArtTransform(
art.anchors.map(anchor => anchor.pos), target
);
if (!matrix || matrix.some(v => !Number.isFinite(v))) return;
/* Mesmo com escala uniforme, uma âncora próxima da descontinuidade do
azimute pode sugerir uma figura gigantesca. Limite visual conservador. */
const scale = Math.hypot(matrix[0], matrix[1]);
const maxScale = Math.min(
W * 0.44 / art.size[0], horizonPx * 0.82 / art.size[1]
);
if (scale > maxScale) {
const sourceCenter = [art.size[0] / 2, art.size[1] / 2];
const screenCenter = [
matrix[0] * sourceCenter[0] + matrix[2] * sourceCenter[1] + matrix[4],
matrix[1] * sourceCenter[0] + matrix[3] * sourceCenter[1] + matrix[5],
];
const shrink = maxScale / scale;
for (let i = 0; i < 4; i++) matrix[i] *= shrink;
matrix[4] = screenCenter[0] - matrix[0] * sourceCenter[0] -
matrix[2] * sourceCenter[1];
matrix[5] = screenCenter[1] - matrix[1] * sourceCenter[0] -
matrix[3] * sourceCenter[1];
}
c.save();
c.beginPath();
c.rect(0, 0, W, horizonPx);
c.clip();
c.globalCompositeOperation = 'screen';
c.globalAlpha = 0.24;
c.setTransform(...matrix);
c.drawImage(imageEntry.render, 0, 0, art.size[0], art.size[1]);
c.restore();
}
function makeConstellationPreviewProjector(constellation, W, horizonPx) { function makeConstellationPreviewProjector(constellation, W, horizonPx) {
const centerRa = constellation.label ? constellation.label[0] : 0; const centerRa = constellation.label ? constellation.label[0] : 0;
const centerDec = constellation.label ? constellation.label[1] : 0; const centerDec = constellation.label ? constellation.label[1] : 0;
@ -1669,8 +1536,7 @@ function makeConstellationPreviewProjector(constellation, W, horizonPx) {
}; };
} }
/* Figuras convencionais dos 12 signos zodiacais, ancoradas em RA/Dec J2000. /* Traçados convencionais dos 12 signos zodiacais, ancorados em RA/Dec J2000. */
Arte, linhas e estrelas reais ficam sobrepostas nesta ordem. */
function drawConstellations(c, lst, W, H, horizonPx) { function drawConstellations(c, lst, W, H, horizonPx) {
if (!showConstellations || typeof CONSTELLATIONS === 'undefined') return; if (!showConstellations || typeof CONSTELLATIONS === 'undefined') return;
const rankAlpha = [0, 0.52, 0.38, 0.25]; const rankAlpha = [0, 0.52, 0.38, 0.25];
@ -1693,9 +1559,6 @@ function drawConstellations(c, lst, W, H, horizonPx) {
c.lineJoin = 'round'; c.lineJoin = 'round';
c.shadowColor = 'rgba(60,185,255,0.65)'; c.shadowColor = 'rgba(60,185,255,0.65)';
c.shadowBlur = 7; c.shadowBlur = 7;
for (const constellation of visible) {
drawConstellationArt(c, constellation, lst, W, horizonPx, previewProjector);
}
for (const constellation of visible) { for (const constellation of visible) {
const rank = Math.max(1, Math.min(3, constellation.rank || 3)); const rank = Math.max(1, Math.min(3, constellation.rank || 3));
c.strokeStyle = `rgba(105,205,255,${preview ? 0.82 : rankAlpha[rank]})`; c.strokeStyle = `rgba(105,205,255,${preview ? 0.82 : rankAlpha[rank]})`;

View file

@ -93,27 +93,12 @@ def main() -> None:
if missing: if missing:
raise RuntimeError(f"{ident}: HIP ausente no catálogo: {missing}") raise RuntimeError(f"{ident}: HIP ausente no catálogo: {missing}")
lines.append([stars[hip] for hip in hip_line]) lines.append([stars[hip] for hip in hip_line])
image = constellation.get("image")
art = None
if image:
anchors = []
for anchor in image["anchors"]:
hip = int(anchor["hip"])
if hip not in stars:
raise RuntimeError(f"{ident}: âncora HIP ausente: {hip}")
anchors.append({"pos": anchor["pos"], "sky": stars[hip]})
art = {
"file": "constellation-art/" + Path(image["file"]).name,
"size": image["size"],
"anchors": anchors,
}
merged[ident] = { merged[ident] = {
"id": ident, "id": ident,
"name": ZODIAC[ident], "name": ZODIAC[ident],
"rank": 1 if ident in {"Ari", "Tau", "Gem", "Leo", "Vir", "Sco", "Sgr"} else 2, "rank": 1 if ident in {"Ari", "Tau", "Gem", "Leo", "Vir", "Sco", "Sgr"} else 2,
"label": metadata.get(ident, {}).get("label"), "label": metadata.get(ident, {}).get("label"),
"lines": lines, "lines": lines,
"art": art,
} }
payload = json.dumps( payload = json.dumps(