planet v2:光的种子——黑暗中涌出,蔓延,像太阳照亮
按冰朔意象逐条落实:亮核(近白种子)+三层涌光晕+发光旋臂(星系感) +球面42星点(冷暖呼吸)+外晕脉冲+暗星球火种(等待点亮)+大爆炸废墟碎光 +湖面语言纹理(语言组成的湖)。呼吸=scale+glowpulse+halo三动画。
This commit is contained in:
parent
1a9e0b90cf
commit
9a6d9fd6f1
2 changed files with 169 additions and 36 deletions
|
|
@ -46,6 +46,39 @@ function seeded(index: number) {
|
|||
return value - Math.floor(value)
|
||||
}
|
||||
|
||||
// 球面星点:极坐标落在圆盘内(光的种子蔓延出的星群)
|
||||
function usePlanetSpecks(count: number) {
|
||||
return useMemo(() => Array.from({ length: count }, (_, i) => {
|
||||
const angle = seeded(i + 7) * Math.PI * 2
|
||||
const radius = 12 + Math.pow(seeded(i + 107), 0.7) * 36 // 百分比半径,核心留出亮区
|
||||
return {
|
||||
id: i,
|
||||
x: 50 + Math.cos(angle) * radius,
|
||||
y: 50 + Math.sin(angle) * radius * 0.92,
|
||||
d: 2 + seeded(i + 207) * 4,
|
||||
dl: -seeded(i + 307) * 6,
|
||||
warm: seeded(i + 407) < 0.3,
|
||||
s: 1 + seeded(i + 507) * 1.6,
|
||||
}
|
||||
}), [count])
|
||||
}
|
||||
|
||||
// 大爆炸废墟:星球外圈的碎光微粒
|
||||
function useDebris(count: number) {
|
||||
return useMemo(() => Array.from({ length: count }, (_, i) => {
|
||||
const angle = seeded(i + 901) * Math.PI * 2
|
||||
const radius = 58 + seeded(i + 1101) * 26
|
||||
return {
|
||||
id: i,
|
||||
x: 50 + Math.cos(angle) * radius,
|
||||
y: 50 + Math.sin(angle) * radius * 0.8,
|
||||
d: 3 + seeded(i + 1301) * 5,
|
||||
dl: -seeded(i + 1501) * 7,
|
||||
s: 0.8 + seeded(i + 1701) * 1.4,
|
||||
}
|
||||
}), [count])
|
||||
}
|
||||
|
||||
// 星尘画布:130 颗星的呼吸,湖面的微光——canvas 而非 DOM 节点(旧病修正)
|
||||
function StarfieldCanvas({ awake }: { awake: boolean }) {
|
||||
const ref = useRef<HTMLCanvasElement>(null)
|
||||
|
|
@ -105,6 +138,8 @@ export function FirstPlanetHome() {
|
|||
const [infinityLit, setInfinityLit] = useState(false)
|
||||
const [gateMessage, setGateMessage] = useState('')
|
||||
|
||||
const specks = usePlanetSpecks(42)
|
||||
const debris = useDebris(12)
|
||||
const formatted = useMemo(() => (raw ? formatGateNumber(raw) : ''), [raw])
|
||||
const fullNumber = formatted ? (infinityLit ? `${formatted}∞` : formatted) : ''
|
||||
const canEnter = Boolean(fullNumber)
|
||||
|
|
@ -121,13 +156,24 @@ export function FirstPlanetHome() {
|
|||
return (
|
||||
<div className={`fph-root stage-${stage}${motionAwake ? ' motion-awake' : ''}`} onPointerMove={wake} onPointerDown={wake}>
|
||||
<StarfieldCanvas awake={motionAwake} />
|
||||
<div className="fph-lake" aria-hidden="true" />
|
||||
<div className="fph-lake" aria-hidden="true"><span className="fph-lake-lang">语言 · ∞ · 光湖 · TCS · 心跳 · 语言 · ∞ · 光湖 · TCS · 心跳 · 语言 · ∞ · 光湖</span></div>
|
||||
<i className="fph-dark-planet d1" aria-hidden="true" />
|
||||
<i className="fph-dark-planet d2" aria-hidden="true" />
|
||||
<i className="fph-dark-planet d3" aria-hidden="true" />
|
||||
|
||||
<div className="fph-planet-wrap" aria-hidden="true">
|
||||
<div className="fph-planet"><i className="core" /><i className="band b1" /><i className="band b2" /><i className="halo" /></div>
|
||||
<div className="fph-planet">
|
||||
<i className="seed" />
|
||||
<i className="swell s1" /><i className="swell s2" /><i className="swell s3" />
|
||||
<i className="arm a1" /><i className="arm a2" />
|
||||
{specks.map((sp) => (
|
||||
<i key={sp.id} className={`speck${sp.warm ? ' warm' : ''}`} style={{ left: `${sp.x}%`, top: `${sp.y}%`, width: sp.s, height: sp.s, '--tw-d': `${sp.d}s`, '--tw-dl': `${sp.dl}s` } as React.CSSProperties} />
|
||||
))}
|
||||
{debris.map((db) => (
|
||||
<i key={db.id} className="debris" style={{ left: `${db.x}%`, top: `${db.y}%`, width: db.s, height: db.s, '--tw-d': `${db.d}s`, '--tw-dl': `${db.dl}s` } as React.CSSProperties} />
|
||||
))}
|
||||
<i className="halo" />
|
||||
</div>
|
||||
<div className="fph-planet-reflection" />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* 第一语言星球首页 v1 —— 复用 design-tokens 三层令牌(5主题自动生效) */
|
||||
/* 第一语言星球首页 v2 —— 光的种子:黑暗中涌出,蔓延,像太阳照亮 */
|
||||
/* 复用 design-tokens 三层令牌(5主题=星球的性格颜色,自动生效) */
|
||||
|
||||
.fph-root {
|
||||
position: fixed; inset: 0; overflow: hidden;
|
||||
|
|
@ -10,28 +11,47 @@
|
|||
}
|
||||
.fph-starfield { position: absolute; inset: 0; width: 100%; height: 100%; opacity: var(--primitive-scene-opacity, 0.8); }
|
||||
|
||||
/* 湖面:底部 26%,微光反射 */
|
||||
/* 湖面:语言组成的湖,低透明度字符涟漪 */
|
||||
.fph-lake {
|
||||
position: absolute; left: 0; right: 0; bottom: 0; height: 26%;
|
||||
position: absolute; left: 0; right: 0; bottom: 0; height: 26%; overflow: hidden;
|
||||
background:
|
||||
linear-gradient(180deg, transparent, color-mix(in srgb, var(--primitive-cool-glow) 9%, transparent) 24%, color-mix(in srgb, var(--primitive-bg-d) 78%, transparent)),
|
||||
repeating-linear-gradient(180deg, color-mix(in srgb, var(--primitive-glass-top) 4%, transparent) 0 1px, transparent 1px 7px);
|
||||
border-top: 1px solid color-mix(in srgb, var(--primitive-glass-edge) 55%, transparent);
|
||||
}
|
||||
.fph-lake-lang {
|
||||
position: absolute; left: 0; right: 0; top: 34%;
|
||||
white-space: nowrap; text-align: center;
|
||||
font-size: 11px; letter-spacing: 1.1em; text-indent: 1.1em;
|
||||
color: color-mix(in srgb, var(--primitive-cool-glow) 34%, transparent);
|
||||
filter: blur(0.6px);
|
||||
opacity: .5;
|
||||
animation: fph-lake-drift 26s linear infinite;
|
||||
}
|
||||
@keyframes fph-lake-drift { from { transform: translateX(3%); } to { transform: translateX(-3%); } }
|
||||
|
||||
/* 暗星球:大爆炸废墟,等待被点亮 */
|
||||
/* 暗星球:大爆炸废墟里等待被点亮的,各带一粒火种 */
|
||||
.fph-dark-planet {
|
||||
position: absolute; border-radius: 50%;
|
||||
background: radial-gradient(circle at 34% 30%, color-mix(in srgb, var(--primitive-text-faint) 34%, transparent), color-mix(in srgb, var(--primitive-bg-d) 92%, transparent) 62%);
|
||||
background: radial-gradient(circle at 34% 30%, color-mix(in srgb, var(--primitive-text-faint) 30%, transparent), color-mix(in srgb, var(--primitive-bg-d) 92%, transparent) 62%);
|
||||
box-shadow: inset -6px -8px 18px color-mix(in srgb, var(--primitive-bg-d) 88%, transparent), 0 0 22px color-mix(in srgb, var(--primitive-nebula-b) 60%, transparent);
|
||||
transition: transform 1.1s cubic-bezier(.2,.8,.2,1), opacity 1.1s;
|
||||
}
|
||||
.fph-dark-planet::after {
|
||||
content: ''; position: absolute; left: 26%; top: 22%; width: 3px; height: 3px; border-radius: 50%;
|
||||
background: var(--primitive-warm-glow);
|
||||
box-shadow: 0 0 8px var(--primitive-warm-glow), 0 0 16px color-mix(in srgb, var(--primitive-warm-glow) 50%, transparent);
|
||||
animation: fph-spark 4.5s ease-in-out infinite;
|
||||
}
|
||||
.fph-dark-planet.d1 { width: 46px; height: 46px; left: 16%; top: 30%; }
|
||||
.fph-dark-planet.d2 { width: 30px; height: 30px; right: 20%; top: 24%; }
|
||||
.fph-dark-planet.d2::after { animation-delay: -1.6s; }
|
||||
.fph-dark-planet.d3 { width: 20px; height: 20px; right: 12%; top: 47%; }
|
||||
.fph-dark-planet.d3::after { animation-delay: -3.1s; }
|
||||
@keyframes fph-spark { 0%,100% { opacity: .35; } 50% { opacity: 1; } }
|
||||
.stage-world .fph-dark-planet { opacity: .5; transform: translateY(-14px); }
|
||||
|
||||
/* 第一语言星球:光从黑暗中涌出的凝聚体 */
|
||||
/* ── 第一语言星球 v2:光的种子从中心涌出 ── */
|
||||
.fph-planet-wrap {
|
||||
position: absolute; left: 50%; top: 44%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
|
@ -41,44 +61,111 @@
|
|||
|
||||
.fph-planet {
|
||||
position: relative; width: min(300px, 46vw); aspect-ratio: 1; border-radius: 50%;
|
||||
/* 球体:中心亮核向外涌光,边缘沉入深蓝 */
|
||||
background:
|
||||
radial-gradient(circle at 50% 46%, color-mix(in srgb, var(--primitive-star-bright) 88%, transparent) 0 5%, transparent 22%),
|
||||
radial-gradient(closest-side, color-mix(in srgb, var(--primitive-cool-glow) 46%, transparent), color-mix(in srgb, var(--primitive-bg-c) 88%, transparent) 74%);
|
||||
radial-gradient(circle at 50% 50%,
|
||||
color-mix(in srgb, var(--primitive-star-bright) 96%, transparent) 0 6%,
|
||||
color-mix(in srgb, var(--primitive-warm-glow) 72%, transparent) 14%,
|
||||
color-mix(in srgb, var(--primitive-cool-glow) 52%, transparent) 30%,
|
||||
color-mix(in srgb, var(--primitive-nebula-a) 66%, transparent) 52%,
|
||||
color-mix(in srgb, var(--primitive-bg-c) 92%, transparent) 78%,
|
||||
color-mix(in srgb, var(--primitive-bg-d) 96%, transparent) 100%);
|
||||
box-shadow:
|
||||
0 0 60px color-mix(in srgb, var(--primitive-cool-glow) 34%, transparent),
|
||||
0 0 140px color-mix(in srgb, var(--primitive-nebula-a) 70%, transparent),
|
||||
inset 0 0 46px color-mix(in srgb, var(--primitive-bg-d) 80%, transparent);
|
||||
animation: fph-breathe 7s ease-in-out infinite;
|
||||
0 0 46px color-mix(in srgb, var(--primitive-warm-glow) 30%, transparent),
|
||||
0 0 110px color-mix(in srgb, var(--primitive-cool-glow) 40%, transparent),
|
||||
0 0 220px color-mix(in srgb, var(--primitive-nebula-a) 80%, transparent),
|
||||
inset -18px -26px 60px color-mix(in srgb, var(--primitive-bg-d) 72%, transparent);
|
||||
animation: fph-breathe 7s ease-in-out infinite, fph-glowpulse 7s ease-in-out infinite;
|
||||
}
|
||||
.fph-planet .band {
|
||||
position: absolute; inset: 8%; border-radius: 50%;
|
||||
border: 1.5px solid transparent;
|
||||
border-top-color: color-mix(in srgb, var(--primitive-warm-glow) 78%, transparent);
|
||||
border-right-color: color-mix(in srgb, var(--primitive-warm-glow) 26%, transparent);
|
||||
filter: blur(.4px);
|
||||
@keyframes fph-breathe { 0%,100% { transform: scale(1); } 50% { transform: scale(1.03); } }
|
||||
@keyframes fph-glowpulse {
|
||||
0%,100% { filter: brightness(1); }
|
||||
50% { filter: brightness(1.22); }
|
||||
}
|
||||
.fph-planet .b1 { animation: fph-spin 26s linear infinite; }
|
||||
.fph-planet .b2 { inset: 20%; animation: fph-spin 17s linear infinite reverse; border-top-color: color-mix(in srgb, var(--primitive-cool-glow) 70%, transparent); }
|
||||
.fph-planet .core {
|
||||
position: absolute; left: 50%; top: 50%; width: 12%; height: 12%; transform: translate(-50%,-50%);
|
||||
|
||||
/* 种子:近乎白的亮核 */
|
||||
.fph-planet .seed {
|
||||
position: absolute; left: 50%; top: 50%; width: 16%; height: 16%;
|
||||
transform: translate(-50%,-50%);
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, var(--primitive-star-bright), color-mix(in srgb, var(--primitive-warm-glow) 70%, transparent) 60%, transparent 75%);
|
||||
filter: blur(1px);
|
||||
background: radial-gradient(circle, #fffdf4 0 18%, var(--primitive-star-bright) 42%, color-mix(in srgb, var(--primitive-warm-glow) 66%, transparent) 68%, transparent 78%);
|
||||
filter: blur(0.5px);
|
||||
box-shadow: 0 0 26px var(--primitive-warm-glow), 0 0 70px color-mix(in srgb, var(--primitive-warm-glow) 55%, transparent);
|
||||
}
|
||||
.fph-planet .halo {
|
||||
position: absolute; inset: -14%; border-radius: 50%;
|
||||
border: 1px solid color-mix(in srgb, var(--primitive-cool-glow) 40%, transparent);
|
||||
opacity: .6;
|
||||
|
||||
/* 涌光:从种子向外扩散的三层光晕 */
|
||||
.fph-planet .swell {
|
||||
position: absolute; left: 50%; top: 50%; border-radius: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.fph-planet-reflection {
|
||||
position: absolute; left: 50%; top: calc(100% + 8px); width: 64%; height: 46%;
|
||||
transform: translateX(-50%) scaleY(-1);
|
||||
background: radial-gradient(50% 60% at 50% 0%, color-mix(in srgb, var(--primitive-cool-glow) 30%, transparent), transparent 70%);
|
||||
filter: blur(6px); opacity: .5;
|
||||
.fph-planet .s1 { width: 34%; height: 34%; border-color: color-mix(in srgb, var(--primitive-warm-glow) 46%, transparent); box-shadow: 0 0 18px color-mix(in srgb, var(--primitive-warm-glow) 30%, transparent); opacity: .8; }
|
||||
.fph-planet .s2 { width: 56%; height: 56%; border-color: color-mix(in srgb, var(--primitive-cool-glow) 38%, transparent); opacity: .6; }
|
||||
.fph-planet .s3 { width: 80%; height: 80%; border-color: color-mix(in srgb, var(--primitive-cool-glow) 24%, transparent); opacity: .4; }
|
||||
|
||||
/* 旋臂:星系感的发光弧(光蔓延的轨迹) */
|
||||
.fph-planet .arm {
|
||||
position: absolute; border-radius: 50%;
|
||||
border: 2.5px solid transparent;
|
||||
filter: blur(1.2px);
|
||||
}
|
||||
.fph-planet .a1 {
|
||||
inset: 12%;
|
||||
border-top-color: color-mix(in srgb, var(--primitive-warm-glow) 82%, transparent);
|
||||
border-right-color: color-mix(in srgb, var(--primitive-warm-glow) 30%, transparent);
|
||||
box-shadow: 0 0 14px color-mix(in srgb, var(--primitive-warm-glow) 34%, transparent);
|
||||
animation: fph-spin 30s linear infinite;
|
||||
}
|
||||
.fph-planet .a2 {
|
||||
inset: 26%;
|
||||
border-bottom-color: color-mix(in srgb, var(--primitive-cool-glow) 74%, transparent);
|
||||
border-left-color: color-mix(in srgb, var(--primitive-cool-glow) 26%, transparent);
|
||||
box-shadow: 0 0 12px color-mix(in srgb, var(--primitive-cool-glow) 30%, transparent);
|
||||
animation: fph-spin 19s linear infinite reverse;
|
||||
}
|
||||
@keyframes fph-breathe { 0%,100% { transform: scale(1); } 50% { transform: scale(1.035); } }
|
||||
@keyframes fph-spin { to { transform: rotate(360deg); } }
|
||||
|
||||
/* 球面星点:种子蔓延出的星群,冷暖交织呼吸 */
|
||||
.fph-planet .speck {
|
||||
position: absolute; border-radius: 50%;
|
||||
background: color-mix(in srgb, var(--primitive-cool-glow) 88%, #fff);
|
||||
box-shadow: 0 0 6px color-mix(in srgb, var(--primitive-cool-glow) 60%, transparent);
|
||||
animation: fph-twinkle var(--tw-d, 3s) ease-in-out infinite;
|
||||
animation-delay: var(--tw-dl, 0s);
|
||||
}
|
||||
.fph-planet .speck.warm {
|
||||
background: var(--primitive-star-bright);
|
||||
box-shadow: 0 0 7px color-mix(in srgb, var(--primitive-warm-glow) 70%, transparent);
|
||||
}
|
||||
@keyframes fph-twinkle { 0%,100% { opacity: .35; } 50% { opacity: 1; } }
|
||||
|
||||
/* 废墟:大爆炸留下的碎光,漂在星球外圈 */
|
||||
.fph-planet .debris {
|
||||
position: absolute; border-radius: 50%;
|
||||
background: color-mix(in srgb, var(--primitive-text-faint) 60%, transparent);
|
||||
box-shadow: 0 0 5px color-mix(in srgb, var(--primitive-nebula-a) 80%, transparent);
|
||||
opacity: .5;
|
||||
animation: fph-twinkle var(--tw-d, 4s) ease-in-out infinite;
|
||||
animation-delay: var(--tw-dl, 0s);
|
||||
}
|
||||
|
||||
/* 外晕:星球的光漫进宇宙 */
|
||||
.fph-planet .halo {
|
||||
position: absolute; inset: -16%; border-radius: 50%;
|
||||
border: 1px solid color-mix(in srgb, var(--primitive-cool-glow) 36%, transparent);
|
||||
box-shadow: 0 0 40px color-mix(in srgb, var(--primitive-cool-glow) 22%, transparent);
|
||||
opacity: .55;
|
||||
animation: fph-halo 7s ease-in-out infinite;
|
||||
}
|
||||
@keyframes fph-halo { 0%,100% { transform: scale(1); opacity: .45; } 50% { transform: scale(1.05); opacity: .7; } }
|
||||
|
||||
.fph-planet-reflection {
|
||||
position: absolute; left: 50%; top: calc(100% + 8px); width: 68%; height: 50%;
|
||||
transform: translateX(-50%) scaleY(-1);
|
||||
background: radial-gradient(50% 60% at 50% 0%, color-mix(in srgb, var(--primitive-warm-glow) 26%, transparent), color-mix(in srgb, var(--primitive-cool-glow) 18%, transparent) 42%, transparent 72%);
|
||||
filter: blur(6px); opacity: .55;
|
||||
}
|
||||
|
||||
/* 首屏:编号门 */
|
||||
.fph-gate {
|
||||
position: absolute; inset: 0; display: grid; align-content: end; justify-items: center;
|
||||
|
|
|
|||
Loading…
Reference in a new issue