Files
Jyotisha/docs/tasks/assets/birth-sky-cover-sample-20260928.html
T

243 lines
20 KiB
HTML
Raw 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.
<title>个人封面样稿</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600&display=swap">
<style>
:root{
--ground:#f3f2ee; --surface:#fbfaf7; --ink:#1d1d1f; --ink-2:#5b5750; --ink-3:#8c877e;
--line:#dedad2; --accent:#8a5a2b; --accent-soft:#efe6da;
--serif:"Noto Serif SC","Songti SC","STSong",serif;
--sans:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
}
@media (prefers-color-scheme:dark){
:root:not([data-theme="light"]){
--ground:#1a1917; --surface:#22211e; --ink:#ece9e2; --ink-2:#b7b1a6; --ink-3:#88837a;
--line:#35332f; --accent:#d2a06b; --accent-soft:#2e2923; color-scheme:dark;
}
}
:root[data-theme="dark"]{
--ground:#1a1917; --surface:#22211e; --ink:#ece9e2; --ink-2:#b7b1a6; --ink-3:#88837a;
--line:#35332f; --accent:#d2a06b; --accent-soft:#2e2923; color-scheme:dark;
}
*{box-sizing:border-box}
body{background:var(--ground);color:var(--ink);font-family:var(--sans);font-size:15px;line-height:1.65;padding:0 20px}
.wrap{max-width:1180px;margin:0 auto;padding-block:48px 72px}
header{max-width:680px}
h1{font-family:var(--serif);font-weight:600;font-size:clamp(26px,4vw,34px);line-height:1.3;margin:0 0 12px;text-wrap:balance}
.lede{color:var(--ink-2);margin:0}
.facts{display:flex;flex-wrap:wrap;gap:8px 28px;margin:28px 0 40px;padding:14px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);font-size:13px;color:var(--ink-2)}
.facts b{color:var(--ink);font-weight:600;margin-left:6px;font-variant-numeric:tabular-nums}
.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:36px 28px}
@media (max-width:940px){.grid{grid-template-columns:1fr;max-width:460px;margin:0 auto}}
figure{margin:0;display:flex;flex-direction:column;gap:18px}
.poster{width:100%;aspect-ratio:3/4;max-width:100%;display:block;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.06),0 12px 32px -12px rgba(40,30,20,.22)}
.cap h2{font-family:var(--serif);font-size:19px;font-weight:600;margin:0 0 4px;display:flex;align-items:center;gap:10px}
.pick{font-family:var(--sans);font-size:12px;font-weight:500;color:var(--accent);background:var(--accent-soft);padding:1px 9px;border-radius:99px;letter-spacing:.04em}
.cap p{margin:0 0 10px;color:var(--ink-2);font-size:14px}
.cap dl{display:grid;grid-template-columns:auto 1fr;gap:4px 12px;margin:0;font-size:13.5px}
.cap dt{color:var(--ink-3)}
.cap dd{margin:0;color:var(--ink-2)}
.scrub{display:flex;align-items:center;gap:12px;font-size:13px;color:var(--ink-2)}
.scrub input{flex:1;accent-color:var(--accent)}
.scrub output{font-variant-numeric:tabular-nums;min-width:4.5em;text-align:right;color:var(--ink)}
footer{margin-top:56px;color:var(--ink-3);font-size:13px;max-width:680px}
</style>
<div class="wrap">
<header>
<h1>一张盘的封面,三种画法</h1>
<p class="lede">下面三张都是用同一张<strong>虚构</strong>星盘真实算出来的(瑞士星历表,Lahiri 岁差,整宫制),没有一笔是装饰。今天按 2026 年 9 月算“此刻”。</p>
</header>
<div class="facts" aria-label="样稿所用数据">
<span>上升<b>双子 10°58′</b></span>
<span>月亮<b>巨蟹 26°12′(也是 AK)</b></span>
<span>当前大运<b>太阳 2026.03–2032.03</b></span>
<span>分运<b>月亮 至 2026.12</b></span>
</div>
<div class="grid">
<figure>
<svg class="poster" id="pA" viewBox="0 0 600 800" role="img" aria-label="年轮封面"></svg>
<div class="scrub">
<label for="year">拖动看“你在这里”怎么走</label>
<input id="year" type="range" min="1995" max="2113" step="0.25" value="2026.75">
<output id="yearOut">2026</output>
</div>
<div class="cap">
<h2>A · 年轮 <span class="pick">推荐</span></h2>
<p>一生 120 年的大运画成树的横截面。一圈是一段大运,宽窄等于年数,纹理随主星不同。走过的圈是墨色,没走的圈是浅色,赭色小点是“此刻”。</p>
<dl>
<dt>用到</dt><dd>大运起止、当前分运、上升度数(小点所在的那条线)</dd>
<dt>好在</dt><dd>讲时间不讲类型;换大运时画面真的会变,有理由回来看</dd>
<dt>顾虑</dt><dd>第一眼要读出“这是年轮”,需要底下那行小字帮忙</dd>
</dl>
</div>
</figure>
<figure>
<svg class="poster" id="pB" viewBox="0 0 600 800" role="img" aria-label="一笔画封面"></svg>
<div class="cap">
<h2>B · 一笔画</h2>
<p>九颗星按出生时的恒星黄道经度落在圆上,上升在左侧,按“日月火水木金土罗计”的顺序用一根手绘线连起来。</p>
<dl>
<dt>用到</dt><dd>九星经度、上升位置、上升与月亮星座(那一句话)</dd>
<dt>好在</dt><dd>最像一幅画;每个人的形状都不同,也都说得出来历</dd>
<dt>顾虑</dt><dd>不懂的人看不出和自己的关系;那句话容易滑向“贴标签”</dd>
</dl>
</div>
</figure>
<figure>
<svg class="poster" id="pC" viewBox="0 0 600 800" role="img" aria-label="出生时刻天空封面"></svg>
<div class="cap">
<h2>C · 那一刻的天空</h2>
<p>出生地、出生那一刻头顶的真实天空,天顶在圆心,东在左。地平线以上的行星点亮,亮星与北斗、仙后照实画。</p>
<dl>
<dt>用到</dt><dd>行星与亮星的真实高度、方位(需要出生地经纬度)</dd>
<dt>好在</dt><dd>最诚实、最浪漫,不做任何判断</dd>
<dt>顾虑</dt><dd>市面已有“出生星空图”;画面本身就泄露出生时间段与地点</dd>
</dl>
</div>
</figure>
</div>
<footer>样稿说明:星盘资料为虚构(1994 年 5 月,杭州),仅用于演示画法;文字是为样稿临时写的,正式版要对照文案口径再定。</footer>
</div>
<script>
const NS="http://www.w3.org/2000/svg";
const C={paper:"#f7f4ee",ink:"#2b2723",ink2:"#6e675d",faint:"#c9bda9",ochre:"#b0763a",night:"#1f1d1b",cream:"#efe7d8"};
function rng(seed){return function(){seed|=0;seed=seed+0x6D2B79F5|0;let t=Math.imul(seed^seed>>>15,1|seed);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296}}
function el(tag,attrs,parent){const e=document.createElementNS(NS,tag);for(const k in attrs)e.setAttribute(k,attrs[k]);if(parent)parent.appendChild(e);return e}
function txt(parent,x,y,s,o={}){const t=el("text",Object.assign({x,y,fill:C.ink,"font-family":"Noto Serif SC, Songti SC, serif","font-size":14},o),parent);t.textContent=s;return t}
function closedPath(pts){let d="";const n=pts.length;for(let i=0;i<n;i++){const p0=pts[(i-1+n)%n],p1=pts[i],p2=pts[(i+1)%n],p3=pts[(i+2)%n];if(i===0)d+=`M${p1[0].toFixed(1)},${p1[1].toFixed(1)}`;const c1=[p1[0]+(p2[0]-p0[0])/6,p1[1]+(p2[1]-p0[1])/6],c2=[p2[0]-(p3[0]-p1[0])/6,p2[1]-(p3[1]-p1[1])/6];d+=`C${c1[0].toFixed(1)},${c1[1].toFixed(1)} ${c2[0].toFixed(1)},${c2[1].toFixed(1)} ${p2[0].toFixed(1)},${p2[1].toFixed(1)}`}return d+"Z"}
function openPath(pts){let d=`M${pts[0][0].toFixed(1)},${pts[0][1].toFixed(1)}`;for(let i=0;i<pts.length-1;i++){const p0=pts[Math.max(0,i-1)],p1=pts[i],p2=pts[i+1],p3=pts[Math.min(pts.length-1,i+2)];const c1=[p1[0]+(p2[0]-p0[0])/6,p1[1]+(p2[1]-p0[1])/6],c2=[p2[0]-(p3[0]-p1[0])/6,p2[1]-(p3[1]-p1[1])/6];d+=`C${c1[0].toFixed(1)},${c1[1].toFixed(1)} ${c2[0].toFixed(1)},${c2[1].toFixed(1)} ${p2[0].toFixed(1)},${p2[1].toFixed(1)}`}return d}
function paperGrain(svg,id,base){const defs=el("defs",{},svg);const f=el("filter",{id,x:0,y:0,width:"100%",height:"100%"},defs);el("feTurbulence",{type:"fractalNoise",baseFrequency:.85,numOctaves:2,seed:7,result:"n"},f);el("feColorMatrix",{type:"matrix",values:"0 0 0 0 0.45 0 0 0 0 0.38 0 0 0 0 0.3 0 0 0 .07 0"},f);el("rect",{width:600,height:800,fill:base},svg);el("rect",{width:600,height:800,filter:`url(#${id})`},svg)}
/* ---------- data (computed with Swiss Ephemeris, Lahiri) ---------- */
const P={Sun:33.04,Moon:116.20,Mars:1.73,Mercury:51.47,Jupiter:193.83,Venus:62.52,Saturn:317.56,Rahu:210.06,Ketu:30.06};
const ASC=70.98, BIRTH=1994.38;
const ZH={Sun:"太阳",Moon:"月亮",Mars:"火星",Mercury:"水星",Jupiter:"木星",Venus:"金星",Saturn:"土星",Rahu:"罗睺",Ketu:"计都"};
const DASHA=[["Mercury",BIRTH,1999.17],["Ketu",1999.17,2006.17],["Venus",2006.17,2026.17],["Sun",2026.17,2032.17],["Moon",2032.17,2042.17],["Mars",2042.17,2049.17],["Rahu",2049.17,2067.17],["Jupiter",2067.17,2083.17],["Saturn",2083.17,2102.17],["Mercury",2102.17,BIRTH+120]];
const LINE={
Sun:"这一圈,轮到你自己站到光里。",Moon:"这一圈,先照顾好心里那个家。",Mars:"这一圈,力气要花在一件事上。",
Mercury:"这一圈,学、写、说,都会被听见。",Jupiter:"这一圈,有人愿意为你把门打开。",Venus:"这一圈,美和关系是你的功课。",
Saturn:"这一圈,慢,但每一步都算数。",Rahu:"这一圈,你会想走到更远的地方。",Ketu:"这一圈,放下的会比拿到的多。"};
const fmt=y=>{const yr=Math.floor(y),m=Math.round((y-yr)*12)+1;return `${yr}.${String(Math.min(m,12)).padStart(2,"0")}`};
/* ---------- A · 年轮 ---------- */
function drawA(now){
const svg=document.getElementById("pA");svg.innerHTML="";paperGrain(svg,"gA",C.paper);
const R=rng(19940518);const cx=300,cy=392,K=218/120;
const ph=[R()*6.28,R()*6.28,R()*6.28,R()*6.28];
const shape=(t,r)=>1+.035*Math.sin(t+ph[0])+.022*Math.sin(2*t+ph[1])+.012*Math.sin(3*t+ph[2])+(.8/Math.max(r,20))*Math.sin(7*t+ph[3]);
const ringPts=(r,jit,rr)=>{const pts=[];for(let i=0;i<96;i++){const t=i/96*Math.PI*2,k=r*shape(t,r)+jit*(rr()-.5);pts.push([cx+Math.cos(t)*k+r*.05,cy+Math.sin(t)*k*.97])}return pts};
const tex={Saturn:2.1,Mercury:3,Sun:3.4,Moon:4,Venus:5,Mars:4.6,Jupiter:7,Rahu:3.4,Ketu:4.2};
const g=el("g",{fill:"none"},svg);
const age=now-BIRTH;
DASHA.forEach(([lord,s,e])=>{
const r0=6+(s-BIRTH)*K,r1=6+(e-BIRTH)*K,lived=e<=now,cur=s<=now&&now<e;
const col=lived||cur?C.ink:C.faint;
const rr=rng(Math.round(s*100));
for(let r=r0+tex[lord];r<r1-1;r+=tex[lord]){
const inner=el("path",{d:closedPath(ringPts(r,lord==="Moon"?2.4:.9,rr)),stroke:col,"stroke-width":lord==="Venus"?.5:.4,opacity:lived||cur?.55:.75},g);
if(lord==="Rahu")inner.setAttribute("stroke-dasharray","6 3");
if(lord==="Ketu")inner.setAttribute("stroke-dasharray","1 3.2");
}
if(lord==="Mars"){for(let i=0;i<9;i++){const t=rr()*6.28,a=r0+2,b=r1-2;el("path",{d:`M${cx+Math.cos(t)*a},${cy+Math.sin(t)*a}L${cx+Math.cos(t+.01)*b},${cy+Math.sin(t+.01)*b}`,stroke:col,"stroke-width":.5,opacity:.6},g)}}
el("path",{d:closedPath(ringPts(r1,.6,rr)),stroke:col,"stroke-width":lived||cur?1.15:.9},g);
el("path",{d:closedPath(ringPts(r1+.6,1.4,rr)),stroke:col,"stroke-width":.35,opacity:.5},g);
});
el("circle",{cx:cx+.3,cy,r:3.2,fill:C.ink},g);
// 上升方向的细线 + 此刻
const th=Math.PI+ (ASC%30)/30*Math.PI*.5; // 双子 10°58′ → 左上方
const rNow=6+age*K;const shp=shape(th,rNow);
const px=cx+Math.cos(th)*rNow*shp+rNow*.05,py=cy+Math.sin(th)*rNow*shp*.97;
const rEnd=6+120*K+6;
el("path",{d:`M${cx},${cy}L${cx+Math.cos(th)*rEnd*1.04},${cy+Math.sin(th)*rEnd*1.02}`,stroke:C.ink2,"stroke-width":.5,"stroke-dasharray":"2 3"},svg);
el("circle",{cx:px,cy:py,r:9,fill:C.ochre,opacity:.18},svg);
el("circle",{cx:px,cy:py,r:4.2,fill:C.ochre},svg);
const [lord,s,e]=DASHA.find(([,s,e])=>s<=now&&now<e);
txt(svg,48,64,"JYOTISHA · 年 轮",{"font-size":12,fill:C.ink2,"letter-spacing":2});
txt(svg,552,64,`${Math.floor(now)}`,{"font-size":12,fill:C.ink2,"text-anchor":"end","letter-spacing":1});
el("line",{x1:48,y1:80,x2:552,y2:80,stroke:C.faint,"stroke-width":.8},svg);
txt(svg,48,146,LINE[lord],{"font-size":30,"font-weight":600,fill:C.ink});
el("line",{x1:48,y1:650,x2:552,y2:650,stroke:C.faint,"stroke-width":.8},svg);
const yrIn=Math.floor(now-s)+1,tot=Math.round(e-s);
txt(svg,48,686,`${ZH[lord]}大运`,{"font-size":16,"font-weight":600});
txt(svg,48,712,`${fmt(s)} — ${fmt(e)} · 第 ${yrIn} 年,共 ${tot} 年`,{"font-size":13,fill:C.ink2});
txt(svg,552,686,"墨色是走过的,浅色是还没走的",{"font-size":12,fill:C.ink2,"text-anchor":"end"});
txt(svg,552,712,"赭点:此刻",{"font-size":12,fill:C.ochre,"text-anchor":"end"});
txt(svg,300,764,"仅供自我探索,不替你做决定。",{"font-size":11,fill:C.ink2,"text-anchor":"middle"});
}
/* ---------- B · 一笔画 ---------- */
function drawB(){
const svg=document.getElementById("pB");paperGrain(svg,"gB",C.paper);
const cx=300,cy=400,Rr=190;const R=rng(51871);
const pos=lon=>{const a=Math.PI+(lon-ASC)*Math.PI/180;return[cx+Math.cos(a)*Rr,cy-Math.sin(a)*Rr]}; // 上升在左,逆时针
// 铅笔导引圆
for(let k=0;k<2;k++){const pts=[];for(let i=0;i<120;i++){const t=i/120*6.283;const r=Rr+(R()-.5)*1.4+k*1.2;pts.push([cx+Math.cos(t)*r,cy+Math.sin(t)*r])}el("path",{d:closedPath(pts),fill:"none",stroke:C.faint,"stroke-width":.7},svg)}
const order=["Sun","Moon","Mars","Mercury","Jupiter","Venus","Saturn","Rahu","Ketu"];
const pts=order.map(k=>pos(P[k]));
// 在相邻点之间加一个略向圆心弯的控制点,让线条有呼吸
const path=[];pts.forEach((p,i)=>{path.push(p);if(i<pts.length-1){const q=pts[i+1];const m=[(p[0]+q[0])/2,(p[1]+q[1])/2];const pull=.18+R()*.12;path.push([m[0]+(cx-m[0])*pull+(R()-.5)*14,m[1]+(cy-m[1])*pull+(R()-.5)*14])}});
const g=el("g",{fill:"none","stroke-linecap":"round","stroke-linejoin":"round"},svg);
[[0,0,1.6,.9],[1.2,-.8,.7,.45],[-.9,1.1,.5,.35]].forEach(([dx,dy,w,o])=>{el("path",{d:openPath(path.map(p=>[p[0]+dx,p[1]+dy])),stroke:C.ink,"stroke-width":w,opacity:o},g)});
const SH={Sun:"日",Moon:"月",Mars:"火",Mercury:"水",Jupiter:"木",Venus:"金",Saturn:"土",Rahu:"罗",Ketu:"计"};
const placed=[];
order.map((k,i)=>[k,i]).sort((a,b)=>P[a[0]]-P[b[0]]).forEach(([k,i])=>{const [x,y]=pts[i];el("circle",{cx:x,cy:y,r:k==="Moon"?4.5:2.6,fill:k==="Moon"?C.ochre:C.ink},svg);
const a=Math.atan2(y-cy,x-cx);let d=22;while(placed.some(([px,py])=>Math.hypot(px-(cx+Math.cos(a)*(Rr+d)),py-(cy+Math.sin(a)*(Rr+d)))<15))d+=15;
const lx=cx+Math.cos(a)*(Rr+d),ly=cy+Math.sin(a)*(Rr+d);placed.push([lx,ly]);txt(svg,lx,ly+4,SH[k],{"font-size":12,fill:C.ink2,"text-anchor":"middle"})});
// 上升记号
el("line",{x1:cx-Rr-10,y1:cy,x2:cx-Rr+10,y2:cy,stroke:C.ochre,"stroke-width":1.4},svg);
txt(svg,cx-Rr-16,cy+4,"升",{"font-size":12,fill:C.ochre,"text-anchor":"end"});
txt(svg,48,64,"JYOTISHA · 一 笔",{"font-size":12,fill:C.ink2,"letter-spacing":2});
el("line",{x1:48,y1:80,x2:552,y2:80,stroke:C.faint,"stroke-width":.8},svg);
txt(svg,48,146,"脑子先出门,心留在家里。",{"font-size":30,"font-weight":600});
el("line",{x1:48,y1:650,x2:552,y2:650,stroke:C.faint,"stroke-width":.8},svg);
txt(svg,48,686,"双子上升 · 巨蟹月亮",{"font-size":16,"font-weight":600});
txt(svg,48,712,"九星按出生时的位置落在圆上,依日月火水木金土罗计连成一笔",{"font-size":12.5,fill:C.ink2});
txt(svg,552,686,"赭点:月亮,也是 AK",{"font-size":12,fill:C.ochre,"text-anchor":"end"});
txt(svg,300,764,"仅供自我探索,不替你做决定。",{"font-size":11,fill:C.ink2,"text-anchor":"middle"});
}
/* ---------- C · 那一刻的天空 ---------- */
function drawC(){
const svg=document.getElementById("pC");paperGrain(svg,"gC",C.night);
const cx=300,cy=400,Rr=200,LAT=30.27*Math.PI/180,LST=350.59;
const proj=(alt,az)=>{const r=(90-alt)/90*Rr,a=az*Math.PI/180;return[cx-r*Math.sin(a),cy-r*Math.cos(a)]}; // 北上东左
const altaz=(raH,dec)=>{const H=(LST-raH*15)*Math.PI/180,d=dec*Math.PI/180;const sa=Math.sin(d)*Math.sin(LAT)+Math.cos(d)*Math.cos(LAT)*Math.cos(H);const alt=Math.asin(sa);let az=Math.atan2(-Math.cos(d)*Math.sin(H),Math.sin(d)*Math.cos(LAT)-Math.cos(d)*Math.sin(LAT)*Math.cos(H));return[alt*180/Math.PI,(az*180/Math.PI+360)%360]};
const S={Sirius:[6.752,-16.72,-1.4],Arcturus:[14.261,19.18,0],Vega:[18.616,38.78,0],Capella:[5.278,46,.1],Rigel:[5.242,-8.2,.1],Procyon:[7.655,5.22,.4],Betelgeuse:[5.919,7.41,.5],Altair:[19.846,8.87,.8],Aldebaran:[4.599,16.51,.9],Antares:[16.49,-26.43,1],Spica:[13.42,-11.16,1],Pollux:[7.755,28.03,1.1],Fomalhaut:[22.961,-29.62,1.2],Deneb:[20.69,45.28,1.3],Regulus:[10.14,11.97,1.4],Castor:[7.577,31.89,1.6],Polaris:[2.53,89.26,2],Hamal:[2.12,23.46,2],Alpheratz:[0.14,29.09,2.1],Mirfak:[3.405,49.86,1.8],Algol:[3.136,40.96,2.1],Denebola:[11.818,14.57,2.1],Alphard:[9.46,-8.66,2],Rasalhague:[17.582,12.56,2.1],Enif:[21.736,9.88,2.4],Markab:[23.079,15.21,2.5],Scheat:[23.063,28.08,2.4],Algenib:[0.22,15.18,2.8],Sadr:[20.37,40.26,2.2],Albireo:[19.512,27.96,3],
Dubhe:[11.062,61.75,1.8],Merak:[11.031,56.38,2.4],Phecda:[11.897,53.69,2.4],Megrez:[12.257,57.03,3.3],Alioth:[12.9,55.96,1.8],Mizar:[13.399,54.93,2.2],Alkaid:[13.792,49.31,1.9],
Caph:[0.153,59.15,2.3],Schedar:[0.675,56.54,2.2],Navi:[0.945,60.72,2.4],Ruchbah:[1.43,60.24,2.7],Segin:[1.907,63.67,3.4]};
const lines=[["Dubhe","Merak","Phecda","Megrez","Alioth","Mizar","Alkaid"],["Megrez","Dubhe"],["Caph","Schedar","Navi","Ruchbah","Segin"]];
const clip=el("clipPath",{id:"sky"},el("defs",{},svg));el("circle",{cx,cy,r:Rr},clip);
const g=el("g",{"clip-path":"url(#sky)"},svg);
// 高度圈
[30,60].forEach(a=>el("circle",{cx,cy,r:(90-a)/90*Rr,fill:"none",stroke:C.cream,"stroke-width":.4,opacity:.18,"stroke-dasharray":"1 4"},g));
const XY={};
for(const k in S){const[ra,dec,m]=S[k];const[al,az]=altaz(ra,dec);if(al<0)continue;XY[k]=proj(al,az);el("circle",{cx:XY[k][0],cy:XY[k][1],r:Math.max(.7,2.4-m*.55),fill:C.cream,opacity:.85},g)}
lines.forEach(L=>{const p=L.filter(k=>XY[k]).map(k=>XY[k]);if(p.length>1)el("path",{d:"M"+p.map(q=>q.join(",")).join("L"),fill:"none",stroke:C.cream,"stroke-width":.5,opacity:.4},g)});
// 行星(真实高度、方位;swisseph 方位自南起算,已换成自北)
const PL={Sun:[31.71,84.69],Mars:[52.33,117.24],Mercury:[17.78,71.14],Venus:[7.95,65.88],Saturn:[50.31,191.14]};
for(const k in PL){const[x,y]=proj(...PL[k]);if(k==="Sun"){el("circle",{cx:x,cy:y,r:16,fill:C.ochre,opacity:.18},g);el("circle",{cx:x,cy:y,r:6,fill:"none",stroke:C.ochre,"stroke-width":1.4},g);el("circle",{cx:x,cy:y,r:1.6,fill:C.ochre},g)}else el("circle",{cx:x,cy:y,r:3.2,fill:C.cream},g);
txt(svg,x+(k==="Venus"?-9:9),y+(k==="Venus"?14:-7),ZH[k],{"font-size":11,fill:k==="Sun"?C.ochre:C.cream,opacity:.9,"text-anchor":k==="Venus"?"end":"start"})}
el("circle",{cx,cy,r:Rr,fill:"none",stroke:C.cream,"stroke-width":.9,opacity:.6},svg);
[["北",0,-1],["南",0,1],["东",-1,0],["西",1,0]].forEach(([s,dx,dy])=>txt(svg,cx+dx*(Rr+18),cy+dy*(Rr+18)+4,s,{"font-size":12,fill:C.cream,opacity:.6,"text-anchor":"middle"}));
txt(svg,48,64,"JYOTISHA · 那 一 刻",{"font-size":12,fill:C.cream,opacity:.6,"letter-spacing":2});
el("line",{x1:48,y1:80,x2:552,y2:80,stroke:C.cream,"stroke-width":.6,opacity:.25},svg);
txt(svg,48,146,"星星都在,只是还看不见。",{"font-size":30,"font-weight":600,fill:C.cream});
el("line",{x1:48,y1:650,x2:552,y2:650,stroke:C.cream,"stroke-width":.6,opacity:.25},svg);
txt(svg,48,686,"你出生时,太阳已经升起两个多小时",{"font-size":15,"font-weight":600,fill:C.cream});
txt(svg,48,712,"月亮与木星在脚下,土星正悬在南方",{"font-size":12.5,fill:C.cream,opacity:.65});
txt(svg,300,764,"仅供自我探索,不替你做决定。",{"font-size":11,fill:C.cream,opacity:.5,"text-anchor":"middle"});
}
drawA(2026.75);drawB();drawC();
const yr=document.getElementById("year"),out=document.getElementById("yearOut");
yr.addEventListener("input",()=>{const v=+yr.value;out.textContent=Math.floor(v);drawA(v)});
if(document.fonts)document.fonts.ready.then(()=>{drawA(+yr.value)});
</script>