From 4e01c768c9f7e34e8afbeb6b4a836fe0461d3162 Mon Sep 17 00:00:00 2001 From: vini Date: Sun, 19 Jul 2026 14:32:48 -0300 Subject: [PATCH] Add fixed constellation inspection mode --- plugin/contents/ui/dancer.html | 96 +++++++++++++++++++++++++++++----- preview-constellation.sh | 12 +++++ 2 files changed, 96 insertions(+), 12 deletions(-) create mode 100755 preview-constellation.sh diff --git a/plugin/contents/ui/dancer.html b/plugin/contents/ui/dancer.html index c273192..19032c3 100644 --- a/plugin/contents/ui/dancer.html +++ b/plugin/contents/ui/dancer.html @@ -1219,6 +1219,7 @@ const ctx = canvas.getContext('2d'); let obsLat = -24.72, obsLon = -53.74; // Toledo-PR; sobrescrito pela config let showConstellations = false; +let constellationPreviewId = null; const constellationArtImages = new Map(); if (typeof CONSTELLATIONS !== 'undefined') { for (const constellation of CONSTELLATIONS) { @@ -1485,12 +1486,16 @@ function constellationArtTransform(source, target) { return [a, b, -b, a, e, f]; } -function drawConstellationArt(c, constellation, lst, W, horizonPx) { +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 - VIEW_AZ) % 360 + 540) % 360 - 180; return { @@ -1541,31 +1546,66 @@ function drawConstellationArt(c, constellation, lst, W, horizonPx) { c.restore(); } +function makeConstellationPreviewProjector(constellation, W, horizonPx) { + const centerRa = constellation.label ? constellation.label[0] : 0; + const centerDec = constellation.label ? constellation.label[1] : 0; + const flatten = point => { + const dra = ((point[0] - centerRa) % 360 + 540) % 360 - 180; + return [dra * Math.cos(centerDec * DEG), point[1] - centerDec]; + }; + const points = constellation.lines.flat().map(flatten); + const xs = points.map(p => p[0]), ys = points.map(p => p[1]); + const minX = Math.min(...xs), maxX = Math.max(...xs); + const minY = Math.min(...ys), maxY = Math.max(...ys); + const scale = Math.min( + W * 0.34 / Math.max(1, maxX - minX), + horizonPx * 0.48 / Math.max(1, maxY - minY) + ); + const midX = (minX + maxX) / 2, midY = (minY + maxY) / 2; + const screenX = W / 2, screenY = horizonPx * 0.42; + return point => { + const p = flatten(point); + return { x: screenX + (p[0] - midX) * scale, + y: screenY - (p[1] - midY) * scale }; + }; +} + /* Figuras convencionais dos 12 signos zodiacais, ancoradas em RA/Dec J2000. Arte, linhas e estrelas reais ficam sobrepostas nesta ordem. */ function drawConstellations(c, lst, W, H, horizonPx) { if (!showConstellations || typeof CONSTELLATIONS === 'undefined') return; const rankAlpha = [0, 0.52, 0.38, 0.25]; const rankWidth = [0, 1.35, 1.05, 0.82]; + const preview = constellationPreviewId + ? CONSTELLATIONS.find(item => item.id === constellationPreviewId) + : null; + const visible = preview ? [preview] : CONSTELLATIONS; + const previewProjector = preview + ? makeConstellationPreviewProjector(preview, W, horizonPx) + : null; + const projectPoint = point => { + if (previewProjector) return previewProjector(point); + const aa = altAz(point[0], point[1], lst); + return skyToScreen(aa.alt, aa.az, W, horizonPx); + }; c.save(); c.lineCap = 'round'; c.lineJoin = 'round'; c.shadowColor = 'rgba(60,185,255,0.65)'; c.shadowBlur = 7; - for (const constellation of CONSTELLATIONS) { - drawConstellationArt(c, constellation, lst, W, horizonPx); + for (const constellation of visible) { + drawConstellationArt(c, constellation, lst, W, horizonPx, previewProjector); } - for (const constellation of CONSTELLATIONS) { + for (const constellation of visible) { const rank = Math.max(1, Math.min(3, constellation.rank || 3)); - c.strokeStyle = `rgba(105,205,255,${rankAlpha[rank]})`; - c.lineWidth = rankWidth[rank]; + c.strokeStyle = `rgba(105,205,255,${preview ? 0.82 : rankAlpha[rank]})`; + c.lineWidth = preview ? 2.1 : rankWidth[rank]; for (const line of constellation.lines) { c.beginPath(); let previous = null; for (const point of line) { - const aa = altAz(point[0], point[1], lst); - const sc = skyToScreen(aa.alt, aa.az, W, horizonPx); + const sc = projectPoint(point); if (!sc) { previous = null; continue; @@ -1583,6 +1623,22 @@ function drawConstellations(c, lst, W, H, horizonPx) { } } + if (preview) { + const seen = new Set(); + c.shadowColor = 'rgba(160,225,255,0.95)'; + c.shadowBlur = 9; + c.fillStyle = 'rgba(225,245,255,0.96)'; + for (const point of preview.lines.flat()) { + const key = point.join(','); + if (seen.has(key)) continue; + seen.add(key); + const sc = projectPoint(point); + c.beginPath(); + c.arc(sc.x, sc.y, Math.max(2.4, H * 0.0018), 0, Math.PI * 2); + c.fill(); + } + } + /* Todos os signos recebem nome; colisões na tela ainda são evitadas. */ c.shadowBlur = 5; c.font = `${Math.max(10, Math.round(H * 0.0105))}px ui-monospace, monospace`; @@ -1590,10 +1646,9 @@ function drawConstellations(c, lst, W, H, horizonPx) { c.textBaseline = 'middle'; c.fillStyle = 'rgba(170,225,255,0.66)'; const occupied = []; - for (const constellation of CONSTELLATIONS) { + for (const constellation of visible) { if (!constellation.label) continue; - const aa = altAz(constellation.label[0], constellation.label[1], lst); - const sc = skyToScreen(aa.alt, aa.az, W, horizonPx); + const sc = projectPoint(constellation.label); if (!sc || sc.y < 24 || sc.y > horizonPx - 18) continue; const width = c.measureText(constellation.name).width + 14; const box = { x1: sc.x - width / 2, y1: sc.y - 9, @@ -1601,7 +1656,7 @@ function drawConstellations(c, lst, W, H, horizonPx) { if (occupied.some(o => box.x1 < o.x2 && box.x2 > o.x1 && box.y1 < o.y2 && box.y2 > o.y1)) continue; occupied.push(box); - c.fillText(constellation.name, sc.x, sc.y); + c.fillText(preview ? `Prévia: ${constellation.name}` : constellation.name, sc.x, sc.y); } c.restore(); } @@ -1627,6 +1682,23 @@ let constellationsFileVal = null; .finally(() => setTimeout(pollConstellationsFile, 800)); })(); +/* Modo de inspeção temporário: centraliza um único signo sem alterar suas + coordenadas internas. Controlado por preview-constellation.sh. */ +let constellationPreviewFileVal = null; +(function pollConstellationPreviewFile() { + fetch('file:///tmp/skeledance-constellation-preview?t=' + Date.now()) + .then(r => r.text()) + .then(t => { + const v = t.trim(); + if (v === constellationPreviewFileVal) return; + constellationPreviewFileVal = v; + constellationPreviewId = CONSTELLATIONS.some(item => item.id === v) ? v : null; + projectSky(); + }) + .catch(() => {}) + .finally(() => setTimeout(pollConstellationPreviewFile, 800)); +})(); + /* ── Passo de projeção: recalcula posições de tela (a cada 30s o céu gira ~0.125°, imperceptível). Camada estática (Via Láctea + estrelas fracas) é pré-renderizada fora da tela; só as brilhantes cintilam por frame. diff --git a/preview-constellation.sh b/preview-constellation.sh new file mode 100755 index 0000000..bc4734e --- /dev/null +++ b/preview-constellation.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +STATE_FILE=/tmp/skeledance-constellation-preview +SIGN=${1:-Vir} + +if [ "$SIGN" = "off" ]; then + printf 'off\n' > "$STATE_FILE" + printf 'Prévia de constelação desativada\n' +else + printf '%s\n' "$SIGN" > "$STATE_FILE" + printf 'Prévia fixa: %s\n' "$SIGN" +fi