400 lines
23 KiB
HTML
400 lines
23 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8"/>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||
<title>光湖 · 五域生长 · 预览 v0.6</title>
|
||
<style>
|
||
:root {
|
||
--bg-a: #0a1020; --bg-b: #0b1220; --bg-c: #070c16; --bg-d: #04070d;
|
||
--star-core: #f7ebc8; --star-bright: #ffefc2;
|
||
--text-primary: rgba(234,238,248,.96); --text-body: rgba(222,228,242,.88);
|
||
--text-aux: rgba(196,206,228,.62); --text-faint: rgba(180,192,220,.4);
|
||
--nebula-a: rgba(91,111,196,.13); --nebula-b: rgba(138,111,201,.05);
|
||
--glass-edge: rgba(202,216,255,.13);
|
||
--cool-glow: rgba(157,180,255,.42); --warm-glow: rgba(247,235,200,.5);
|
||
--lake-top: #101830;
|
||
}
|
||
* { margin:0; padding:0; box-sizing:border-box; }
|
||
html,body { height:100%; }
|
||
body {
|
||
font-family:"PingFang SC","Hiragino Sans GB","Source Han Sans SC",system-ui,sans-serif;
|
||
background:
|
||
radial-gradient(140% 90% at 50% -18%, var(--nebula-a), transparent 56%),
|
||
radial-gradient(120% 80% at 82% 8%, var(--nebula-b), transparent 60%),
|
||
linear-gradient(180deg, var(--bg-a) 0%, var(--bg-b) 40%, var(--bg-c) 62%, var(--bg-d) 100%);
|
||
color:var(--text-body); overflow:hidden;
|
||
}
|
||
|
||
.stars { position:fixed; inset:0 0 40% 0; pointer-events:none; z-index:1; }
|
||
.stars i { position:absolute; width:2px; height:2px; border-radius:50%;
|
||
background:var(--star-core); opacity:.4; box-shadow:0 0 6px var(--warm-glow); }
|
||
|
||
#skyLight { position:fixed; z-index:2; width:130vw; height:130vw; left:0; top:0;
|
||
pointer-events:none; will-change:transform;
|
||
background:radial-gradient(circle, var(--sky-tint, rgba(255,236,180,.14)) 0%, transparent 46%); }
|
||
|
||
/* ── 日月本体:一颗真正的星球,与五域同宗 ── */
|
||
#celestial { position:fixed; z-index:8; width:0; height:0; cursor:pointer; will-change:left,top; }
|
||
#celestial .halo3 { position:absolute; left:-100px; top:-100px; width:200px; height:200px;
|
||
border-radius:50%; background:radial-gradient(circle, var(--glow-outer), transparent 62%); }
|
||
#celestial .halo2 { position:absolute; left:-56px; top:-56px; width:112px; height:112px;
|
||
border-radius:50%; background:radial-gradient(circle, var(--glow-mid), transparent 68%); }
|
||
#celestial .halo1 { position:absolute; left:-36px; top:-36px; width:72px; height:72px;
|
||
border-radius:50%; background:radial-gradient(circle, var(--glow-inner, rgba(255,244,210,.5)), transparent 72%); }
|
||
#celestial .core { position:absolute; left:-27px; top:-27px; width:54px; height:54px;
|
||
border-radius:50%;
|
||
background:
|
||
radial-gradient(circle at 38% 34%, #fff8e0 0%, #ffe9a8 34%, #f7c86a 68%, #e2a24a 100%);
|
||
box-shadow:0 0 26px var(--glow-mid), 0 0 64px var(--glow-outer);
|
||
animation:sun-breathe 7s ease-in-out infinite; }
|
||
@keyframes sun-breathe { 0%,100%{transform:scale(1)} 50%{transform:scale(1.03)} }
|
||
#celestial.moon .core { background:
|
||
radial-gradient(circle at 62% 56%, rgba(120,134,176,.5) 6%, transparent 7%),
|
||
radial-gradient(circle at 44% 68%, rgba(120,134,176,.4) 9%, transparent 10%),
|
||
radial-gradient(circle at 70% 30%, rgba(120,134,176,.35) 7%, transparent 8%),
|
||
radial-gradient(circle at 40% 36%, #f6f8ff, #d9e0f5 52%, #a8b4da 100%);
|
||
box-shadow:0 0 22px var(--glow-mid), 0 0 54px var(--glow-outer); }
|
||
#celestial.moon .halo1 { opacity:.6; }
|
||
#celestial .caption { position:absolute; left:50%; top:58px; transform:translateX(-50%);
|
||
white-space:nowrap; text-align:center; opacity:0; transition:opacity .25s ease; pointer-events:none; }
|
||
#celestial:hover .caption { opacity:1; }
|
||
#celestial .caption b { display:block; color:var(--star-core); font-size:12px;
|
||
font-weight:720; letter-spacing:.18em; font-variant-numeric:tabular-nums; }
|
||
#celestial .caption em { display:block; margin-top:5px; color:var(--text-aux); font-style:normal;
|
||
font-size:11px; font-weight:650; letter-spacing:.1em; font-variant-numeric:tabular-nums; }
|
||
#celestial .caption span { display:block; margin-top:5px; color:var(--text-faint);
|
||
font-size:9.5px; font-weight:620; letter-spacing:.3em; text-indent:.3em; }
|
||
|
||
/* ── 湖面:没有任何线,只有光与渐变 ── */
|
||
.lake { position:fixed; left:0; right:0; bottom:0; height:36vh; z-index:4;
|
||
background:linear-gradient(180deg, transparent 0%, rgba(16,24,48,.55) 20%, #0b1122 46%, #060a14 78%, #04070d 100%); }
|
||
/* 天水交接的柔光带(不是线,是一片洇开的亮) */
|
||
.lake .haze { position:absolute; top:-7vh; left:8%; right:8%; height:14vh;
|
||
background:radial-gradient(ellipse at center, rgba(190,210,255,.12), transparent 70%);
|
||
filter:blur(10px); pointer-events:none; }
|
||
/* 波光粼粼:满湖碎光点,各自明灭 */
|
||
#sparkles { position:absolute; inset:0; pointer-events:none; }
|
||
#sparkles i { position:absolute; width:2px; height:2px; border-radius:50%;
|
||
background:#cfe0ff; box-shadow:0 0 5px rgba(190,210,255,.7);
|
||
opacity:0; animation:glint var(--gt) ease-in-out infinite; animation-delay:var(--gd); }
|
||
#sparkles i.lit { background:var(--spark-lit, #ffe9b8); box-shadow:0 0 7px var(--refl-c, rgba(255,236,180,.8)); }
|
||
@keyframes glint { 0%,100%{opacity:0} 50%{opacity:var(--go)} }
|
||
/* 日月倒影:一条柔光路,无条纹,随日月呼吸 */
|
||
#reflection { position:absolute; top:0; width:130px; height:78%;
|
||
transform:translateX(-50%); pointer-events:none; will-change:left;
|
||
background:linear-gradient(180deg, var(--refl-c, rgba(255,236,180,.44)), transparent 86%);
|
||
opacity:.5; filter:blur(9px);
|
||
animation:refl-shimmer 5.2s ease-in-out infinite; }
|
||
@keyframes refl-shimmer { 0%,100%{opacity:.48;transform:translateX(-50%) scaleX(1)}
|
||
50%{opacity:.68;transform:translateX(-50%) scaleX(1.18)} }
|
||
|
||
/* ── 五域:正在成长的天体,悬于湖上,影落湖中 ── */
|
||
.domain { position:absolute; z-index:6; text-align:center; cursor:pointer; width:150px; }
|
||
.d-body { position:relative; margin:0 auto; }
|
||
/* 星核(随阶段变大变实) */
|
||
.d-core { position:absolute; left:50%; top:50%; border-radius:50%;
|
||
transform:translate(-50%,-50%);
|
||
background:
|
||
radial-gradient(circle at 32% 26%, rgba(255,255,255,.95) 0%, rgba(255,255,255,.16) 22%, transparent 34%),
|
||
radial-gradient(circle at 50% 50%, var(--d-hi), var(--d-lo) 84%);
|
||
box-shadow:0 0 calc(var(--d-glow-r) * 1.4) var(--d-glow), 0 0 calc(var(--d-glow-r) * 3) var(--d-glow-soft);
|
||
animation:core-breathe 6s ease-in-out infinite; }
|
||
@keyframes core-breathe { 0%,100%{transform:translate(-50%,-50%) scale(1)} 50%{transform:translate(-50%,-50%) scale(1.045)} }
|
||
/* 光晕(成星后才有) */
|
||
.d-halo { position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); border-radius:50%;
|
||
background:radial-gradient(circle, var(--d-glow-soft), transparent 66%); }
|
||
/* 星环(生环期后) */
|
||
.d-ring { position:absolute; left:50%; top:50%; border-radius:50%;
|
||
border:1px solid var(--d-ring-c); transform:translate(-50%,-50%) rotateX(64deg);
|
||
animation:ring-turn 26s linear infinite; }
|
||
@keyframes ring-turn { from{transform:translate(-50%,-50%) rotateX(64deg) rotate(0)} to{transform:translate(-50%,-50%) rotateX(64deg) rotate(360deg)} }
|
||
.d-ring::before { content:''; position:absolute; top:-2.5px; left:50%; width:5px; height:5px;
|
||
margin-left:-2.5px; border-radius:50%; background:var(--d-hi);
|
||
box-shadow:0 0 8px var(--d-glow); }
|
||
/* 卫星(行星期后):旋臂携星绕行 */
|
||
.d-sat-arm { position:absolute; left:50%; top:50%; width:0; height:0;
|
||
animation:sat-orbit 17s linear infinite; }
|
||
@keyframes sat-orbit { from{transform:rotate(0)} to{transform:rotate(360deg)} }
|
||
.d-sat { position:absolute; left:var(--d-sat-r); top:0; width:7px; height:7px; margin:-3.5px 0 0 -3.5px;
|
||
border-radius:50%; background:radial-gradient(circle at 34% 30%, #fff, var(--d-lo));
|
||
box-shadow:0 0 8px var(--d-glow); }
|
||
/* 光尘汇流(聚光尘期):尘点旋入中心,生生不息 */
|
||
.d-dust { position:absolute; left:50%; top:50%; width:0; height:0; }
|
||
.d-dust i { position:absolute; width:3px; height:3px; margin:-1.5px; border-radius:50%;
|
||
background:var(--d-hi); box-shadow:0 0 6px var(--d-glow);
|
||
animation:dust-fall var(--dust-t) linear infinite; }
|
||
@keyframes dust-fall {
|
||
0% { transform:rotate(var(--dust-a)) translateX(var(--dust-r0)); opacity:0; }
|
||
12% { opacity:.9; }
|
||
88% { opacity:.75; }
|
||
100% { transform:rotate(calc(var(--dust-a) + 300deg)) translateX(3px); opacity:0; } }
|
||
/* 域影落湖 */
|
||
.d-mirror { margin:2px auto 0; border-radius:50%;
|
||
background:radial-gradient(circle, var(--d-glow), transparent 70%);
|
||
filter:blur(4px); opacity:.6; animation:mirror-breathe 6s ease-in-out infinite; }
|
||
@keyframes mirror-breathe { 0%,100%{opacity:.44;transform:scaleX(1)} 50%{opacity:.66;transform:scaleX(1.12)} }
|
||
.d-label { margin-top:12px; color:var(--text-body); font-size:14px; font-weight:700;
|
||
letter-spacing:.3em; text-indent:.3em; transition:color .18s ease;
|
||
text-shadow:0 1px 8px rgba(0,0,0,.6); }
|
||
.domain:hover .d-label { color:var(--text-primary); }
|
||
.d-stage { margin-top:5px; color:var(--text-aux); font-size:10.5px; letter-spacing:.28em; text-indent:.28em;
|
||
opacity:0; transition:opacity .25s ease; }
|
||
.domain:hover .d-stage { opacity:1; }
|
||
.domain.on-duty .d-label { color:var(--star-core); }
|
||
.domain.on-duty .d-stage { opacity:1; color:color-mix(in srgb, var(--star-core) 72%, transparent); }
|
||
|
||
/* ── 首页官方门面:商标名+技术名,正式书式 ── */
|
||
.masthead { position:fixed; top:4.6vh; left:0; right:0; text-align:center; z-index:6; }
|
||
.masthead small { display:block; color:var(--star-core); font-size:10px; font-weight:760;
|
||
letter-spacing:.5em; text-indent:.5em; opacity:.85; }
|
||
.masthead b { display:block; margin-top:12px; color:var(--text-primary); font-size:34px;
|
||
font-weight:780; letter-spacing:.56em; text-indent:.56em; }
|
||
.masthead span { display:block; margin-top:10px; color:var(--text-aux); font-size:11px;
|
||
font-weight:650; letter-spacing:.4em; text-indent:.4em; }
|
||
.era-foot { position:fixed; bottom:1.6vh; left:0; right:0; text-align:center; z-index:6;
|
||
color:var(--text-faint); font-size:10.5px; font-weight:620; letter-spacing:.3em; text-indent:.3em; }
|
||
|
||
/* ── 演化史长河 ── */
|
||
.river { position:fixed; inset:0; z-index:20; display:grid; place-items:center;
|
||
background:color-mix(in srgb, var(--bg-d) 88%, transparent); backdrop-filter:blur(22px);
|
||
opacity:0; pointer-events:none; transition:opacity .4s ease; }
|
||
.river.open { opacity:1; pointer-events:auto; }
|
||
.river-close { position:absolute; top:30px; right:34px; width:36px; height:36px;
|
||
border:1px solid var(--glass-edge); border-radius:50%; background:transparent;
|
||
color:var(--text-body); font-size:20px; cursor:pointer; }
|
||
.river-close:hover { border-color:color-mix(in srgb, var(--warm-glow) 55%, transparent); }
|
||
.river-title { position:absolute; top:5.5vh; left:0; right:0; text-align:center; }
|
||
.river-title b { color:var(--text-primary); font-size:22px; font-weight:760; letter-spacing:.3em; text-indent:.3em; }
|
||
.river-title small { display:block; margin-top:8px; color:var(--text-aux); font-size:11px; letter-spacing:.2em; }
|
||
.river-path { position:relative; width:min(860px,88vw); height:52vh; }
|
||
.river-path svg { position:absolute; inset:0; width:100%; height:100%; overflow:visible; }
|
||
.river-path svg path { fill:none; stroke:var(--glass-edge); stroke-width:1; }
|
||
.ev { position:absolute; transform:translate(-50%,-50%); text-align:center; }
|
||
.ev .orb { width:11px; height:11px; margin:0 auto; border-radius:50%;
|
||
background:radial-gradient(circle at 34% 30%, var(--star-bright), var(--cool-glow));
|
||
box-shadow:0 0 14px var(--cool-glow); }
|
||
.ev .ev-date { margin-top:12px; color:var(--star-core); font-size:11px; font-weight:720;
|
||
letter-spacing:.14em; font-variant-numeric:tabular-nums; }
|
||
.ev .ev-name { margin-top:4px; color:var(--text-primary); font-size:13.5px; font-weight:680; letter-spacing:.06em; }
|
||
.ev .ev-note { margin-top:4px; color:var(--text-aux); font-size:11px; max-width:210px; margin-inline:auto; }
|
||
.ev.origin .orb { width:15px; height:15px;
|
||
background:radial-gradient(circle at 34% 30%, #fff, var(--warm-glow));
|
||
box-shadow:0 0 22px var(--warm-glow), 0 0 52px var(--warm-glow); }
|
||
.ev.now .orb { animation:now-pulse 3.6s ease-in-out infinite; }
|
||
@keyframes now-pulse { 0%,100%{box-shadow:0 0 14px var(--warm-glow)} 50%{box-shadow:0 0 26px var(--warm-glow),0 0 60px var(--warm-glow)} }
|
||
.river-foot { position:absolute; bottom:4vh; left:0; right:0; text-align:center;
|
||
color:var(--text-faint); font-size:10.5px; letter-spacing:.16em; padding:0 8vw; }
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.d-core,.d-ring,.d-sat-arm,.d-dust i,.d-mirror,#sparkles i,#reflection,.ev.now .orb,#celestial .core { animation:none; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="stars" id="stars"></div>
|
||
<div id="skyLight"></div>
|
||
|
||
<div class="masthead">
|
||
<small>HOLOLAKE · GH-AIOS</small>
|
||
<b>光湖</b>
|
||
<span>语言世界</span>
|
||
</div>
|
||
|
||
<div id="celestial" role="button" tabindex="0" aria-label="展开曜冥纪元演化史">
|
||
<div class="halo3"></div><div class="halo2"></div><div class="halo1"></div><div class="core"></div>
|
||
<div class="caption"><b id="capDay"></b><em id="capTime"></em><span>曜冥纪元 · 光湖历 · 精确到毫秒</span></div>
|
||
</div>
|
||
|
||
<div class="lake">
|
||
<div class="haze"></div>
|
||
<div id="sparkles"></div>
|
||
<div id="reflection"></div>
|
||
</div>
|
||
<div id="domains"></div>
|
||
|
||
<div class="era-foot">五域在生长 · 星相就是历史</div>
|
||
|
||
<div class="river" id="river" role="dialog" aria-modal="true" aria-label="曜冥纪元演化史长河">
|
||
<button class="river-close" type="button" aria-label="关闭" id="riverClose">×</button>
|
||
<div class="river-title"><b>演化史长河</b><small>自源点 2025-04-26 · 沿星轨至今</small></div>
|
||
<div class="river-path" id="riverPath">
|
||
<svg aria-hidden="true"><path id="riverCurve"/></svg>
|
||
</div>
|
||
<div class="river-foot">源点精度只确认到 2025-04-26 当日 · 公众时间线只呈现现实可成立的演化事实</div>
|
||
</div>
|
||
|
||
<script>
|
||
const EPOCH = new Date('2025-04-26T00:00:00+08:00')
|
||
const pad = (n, l = 2) => String(n).padStart(l, '0')
|
||
const events = [
|
||
{ date: '2025-04-26', name: '源点 · 世界第一次心跳', note: '曜冥与光湖世界起点', cls: 'origin' },
|
||
{ date: '2025-05-14', name: '一代仓库首次着陆', note: '最早的可见提交', cls: '' },
|
||
{ date: '2026-03-05', name: '铸渊出生', note: 'ICE-GL-ZY001 可核验出生记录', cls: '' },
|
||
{ date: null, name: '此刻', note: '世界仍在转动', cls: 'now' },
|
||
]
|
||
|
||
const stars = document.getElementById('stars')
|
||
for (let i = 0; i < 60; i++) {
|
||
const s = document.createElement('i')
|
||
s.style.left = (Math.random() * 100) + '%'
|
||
s.style.top = (Math.random() * 100) + '%'
|
||
s.style.opacity = (0.14 + Math.random() * 0.42).toFixed(2)
|
||
stars.appendChild(s)
|
||
}
|
||
|
||
/* ── 湖面波光:随机撒碎光点,近大远小;日光道内的点跟日月颜色走 ── */
|
||
const sparkles = document.getElementById('sparkles')
|
||
const sparkleDots = []
|
||
for (let i = 0; i < 150; i++) {
|
||
const s = document.createElement('i')
|
||
const ty = Math.pow(Math.random(), 1.35) /* 偏近处多一点 */
|
||
const size = 1 + ty * 2.3
|
||
s.style.width = size + 'px'
|
||
s.style.height = size + 'px'
|
||
const px = Math.random() * 100
|
||
s.style.left = px + '%'
|
||
s.style.top = (ty * 92 + 3) + '%'
|
||
s.style.setProperty('--gt', (2.6 + Math.random() * 4.6).toFixed(2) + 's')
|
||
s.style.setProperty('--gd', (-Math.random() * 7).toFixed(2) + 's')
|
||
s.style.setProperty('--go', (0.22 + Math.random() * 0.6).toFixed(2))
|
||
sparkles.appendChild(s)
|
||
sparkleDots.push({ el: s, x: px })
|
||
}
|
||
|
||
/* ── 五域档案:各自色相 + 生长阶段 ──
|
||
阶段 stage:1 聚光尘 → 2 凝星核 → 3 初生环 → 4 行星态 → 5 主星态
|
||
预览里五域故意停在不同阶段,从左到右就是一部成长史;
|
||
正式软件里阶段由该域的真实成长数据驱动。 */
|
||
const domains = [
|
||
{ name: '分域', stage: 1, stageName: '聚光尘',
|
||
hi: '#b9f2dd', lo: '#2c5a4a', glow: 'rgba(150,230,200,.5)', glowSoft: 'rgba(150,230,200,.18)', x: 10, y: -46 },
|
||
{ name: '零感域', stage: 2, stageName: '凝星核',
|
||
hi: '#dcc4ff', lo: '#48326a', glow: 'rgba(206,178,246,.5)', glowSoft: 'rgba(206,178,246,.18)', x: 30, y: -66 },
|
||
{ name: '零域', stage: 3, stageName: '初生环',
|
||
hi: '#ffcf9e', lo: '#6e4630', glow: 'rgba(255,200,140,.5)', glowSoft: 'rgba(255,200,140,.18)', x: 50, y: -52 },
|
||
{ name: '主域', stage: 4, stageName: '行星态',
|
||
hi: '#c9d6ff', lo: '#33406e', glow: 'rgba(168,190,255,.52)', glowSoft: 'rgba(168,190,255,.18)', x: 70, y: -78 },
|
||
{ name: '第五域', stage: 5, stageName: '主星态',
|
||
hi: '#fdeec2', lo: '#6b5626', glow: 'rgba(250,226,150,.56)', glowSoft: 'rgba(250,226,150,.2)', x: 90, y: -60 },
|
||
]
|
||
const dayIndex = Math.floor((Date.now() - EPOCH) / 86400000) % 5
|
||
const lakeTop = () => window.innerHeight * 0.64 /* 湖面在水线 y=64vh 起 */
|
||
|
||
const dw = document.getElementById('domains')
|
||
domains.forEach((d, i) => {
|
||
const size = [30, 40, 50, 62, 76][d.stage - 1] /* 阶段越大星越大 */
|
||
const haloR = size * 2.6
|
||
const ringR = size * 2.1
|
||
const satR = size * 1.55
|
||
const el = document.createElement('div')
|
||
el.className = 'domain' + (i === dayIndex ? ' on-duty' : '')
|
||
el.style.setProperty('--d-hi', d.hi)
|
||
el.style.setProperty('--d-lo', d.lo)
|
||
el.style.setProperty('--d-glow', d.glow)
|
||
el.style.setProperty('--d-glow-soft', d.glowSoft)
|
||
el.style.setProperty('--d-glow-r', (size * 0.7) + 'px')
|
||
el.style.setProperty('--d-ring-c', d.glow)
|
||
el.style.setProperty('--d-sat-r', satR + 'px')
|
||
el.style.left = `calc(${d.x}% - 75px)`
|
||
el.style.top = `calc(${lakeTop() + d.y}px)`
|
||
let html = `<div class="d-body" style="width:${haloR}px;height:${haloR}px">`
|
||
if (d.stage >= 2) html += `<div class="d-halo" style="width:${haloR}px;height:${haloR}px"></div>`
|
||
if (d.stage >= 3) html += `<div class="d-ring" style="width:${ringR}px;height:${ringR}px"></div>`
|
||
if (d.stage >= 4) html += `<div class="d-sat-arm"><i class="d-sat"></i></div>`
|
||
if (d.stage >= 2) html += `<div class="d-core" style="width:${size}px;height:${size}px"></div>`
|
||
if (d.stage === 1) {
|
||
html += `<div class="d-core" style="width:${size * 0.55}px;height:${size * 0.55}px;opacity:.7"></div><div class="d-dust">`
|
||
for (let k = 0; k < 6; k++) {
|
||
html += `<i style="--dust-a:${k * 60}deg;--dust-r0:${26 + (k % 3) * 7}px;--dust-t:${4.6 + k * 0.7}s;animation-delay:${-k * 0.9}s"></i>`
|
||
}
|
||
html += `</div>`
|
||
}
|
||
html += `</div>`
|
||
html += `<div class="d-mirror" style="width:${size * 2.2}px;height:${size * 0.5}px"></div>`
|
||
html += `<div class="d-label">${d.name}</div><div class="d-stage">${d.stageName}</div>`
|
||
el.innerHTML = html
|
||
dw.appendChild(el)
|
||
})
|
||
|
||
/* 日月行天:毫秒驱动 */
|
||
const celestial = document.getElementById('celestial')
|
||
const skyLight = document.getElementById('skyLight')
|
||
const reflection = document.getElementById('reflection')
|
||
const capDay = document.getElementById('capDay')
|
||
const capTime = document.getElementById('capTime')
|
||
let lastIsDay = null
|
||
function frame() {
|
||
const now = new Date()
|
||
const ms = now.getHours() * 3600000 + now.getMinutes() * 60000 + now.getSeconds() * 1000 + now.getMilliseconds()
|
||
const h = ms / 3600000
|
||
const isDay = h >= 6 && h < 18
|
||
const t = isDay ? (h - 6) / 12 : ((h >= 18 ? h - 18 : h + 6) / 12)
|
||
const x = 8 + t * 84
|
||
const y = 52 - Math.sin(t * Math.PI) * 26 /* 弧顶 26vh,让开门面 */
|
||
celestial.style.left = x + 'vw'
|
||
celestial.style.top = y + 'vh'
|
||
reflection.style.left = x + '%'
|
||
/* 日光道内的波光点被点亮,跟着日月的颜色走 */
|
||
for (const dot of sparkleDots) {
|
||
const lit = Math.abs(dot.x - x) < 8
|
||
if (lit !== dot.lit) { dot.lit = lit; dot.el.classList.toggle('lit', lit) }
|
||
}
|
||
skyLight.style.transform = `translate(${(x / 100) * window.innerWidth - window.innerWidth * 0.65}px,
|
||
${(y / 100) * window.innerHeight - window.innerWidth * 0.65}px)`
|
||
if (isDay !== lastIsDay) {
|
||
lastIsDay = isDay
|
||
celestial.classList.toggle('moon', !isDay)
|
||
if (isDay) {
|
||
celestial.style.setProperty('--glow-outer', 'rgba(255,214,120,.30)')
|
||
celestial.style.setProperty('--glow-mid', 'rgba(255,232,170,.5)')
|
||
celestial.style.setProperty('--glow-inner', 'rgba(255,244,210,.55)')
|
||
skyLight.style.setProperty('--sky-tint', 'rgba(255,236,180,.13)')
|
||
reflection.style.setProperty('--refl-c', 'rgba(255,232,170,.46)')
|
||
} else {
|
||
celestial.style.setProperty('--glow-outer', 'rgba(190,208,255,.26)')
|
||
celestial.style.setProperty('--glow-mid', 'rgba(222,232,255,.44)')
|
||
celestial.style.setProperty('--glow-inner', 'rgba(234,240,255,.4)')
|
||
skyLight.style.setProperty('--sky-tint', 'rgba(190,208,255,.10)')
|
||
reflection.style.setProperty('--refl-c', 'rgba(222,232,255,.4)')
|
||
}
|
||
}
|
||
capDay.textContent = `光湖历 · 第 ${Math.floor((now - EPOCH) / 86400000) + 1} 天`
|
||
capTime.textContent = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}`
|
||
requestAnimationFrame(frame)
|
||
}
|
||
requestAnimationFrame(frame)
|
||
|
||
const river = document.getElementById('river')
|
||
const riverPath = document.getElementById('riverPath')
|
||
function buildRiver() {
|
||
riverPath.querySelectorAll('.ev').forEach(n => n.remove())
|
||
const w = riverPath.clientWidth, h = riverPath.clientHeight
|
||
const pts = events.map((_, i) => {
|
||
const t = i / (events.length - 1)
|
||
return [w * (0.08 + t * 0.84), h * (0.72 - t * 0.44) + Math.sin(t * Math.PI) * h * 0.1]
|
||
})
|
||
document.getElementById('riverCurve').setAttribute('d',
|
||
`M ${pts.map(p => p.join(' ')).join(' L ')}`)
|
||
events.forEach((ev, i) => {
|
||
const el = document.createElement('div')
|
||
el.className = 'ev ' + ev.cls
|
||
el.style.left = pts[i][0] + 'px'
|
||
el.style.top = pts[i][1] + 'px'
|
||
el.innerHTML = `<div class="orb"></div>
|
||
<div class="ev-date">${ev.date || 'NOW'}</div>
|
||
<div class="ev-name">${ev.name}</div>
|
||
<div class="ev-note">${ev.note}</div>`
|
||
riverPath.appendChild(el)
|
||
})
|
||
}
|
||
function openRiver() { buildRiver(); river.classList.add('open') }
|
||
function closeRiver() { river.classList.remove('open') }
|
||
celestial.addEventListener('click', openRiver)
|
||
celestial.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openRiver() } })
|
||
document.getElementById('riverClose').addEventListener('click', closeRiver)
|
||
river.addEventListener('click', (e) => { if (e.target === river) closeRiver() })
|
||
window.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeRiver() })
|
||
</script>
|
||
</body>
|
||
</html>
|