auto-save 2026-05-15 16:33 (~4)

This commit is contained in:
2026-05-15 16:33:17 +08:00
parent ecc5894e52
commit 1336fc6ad2
4 changed files with 158 additions and 23 deletions

View File

@@ -1,12 +1,5 @@
{
"entries": [
{
"files_changed": 7,
"hash": "3684917",
"message": "auto-save 2026-05-14 01:05 (+4, ~3)",
"ts": "2026-05-14T01:06:06+08:00",
"type": "commit"
},
{
"files_changed": 8,
"hash": "4610ef8",
@@ -3251,6 +3244,13 @@
"type": "session-heartbeat",
"message": "Codex 会话活跃 · 最近命令codex · 1 项未提交变更 · 最近提交auto-save 2026-05-15 16:22 (~1)",
"files_changed": 1
},
{
"ts": "2026-05-15T16:27:46+08:00",
"type": "commit",
"message": "auto-save 2026-05-15 16:27 (~3)",
"hash": "ecc5894",
"files_changed": 3
}
]
}

View File

@@ -942,6 +942,16 @@ SubjectAsset {
<h2>变更记录</h2>
<p>这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。</p>
<div class="changelog">
<article class="change">
<header>
<h3>2026-05-15 · 登录页角色视觉样式升级</h3>
<span class="tag rose">UI</span>
</header>
<div class="body">
<p><strong>改动:</strong>在保留四个几何角色结构的基础上,增加底座阴影、发光边、玻璃高光、内部面板和状态点,让角色更像 SKG 内容工作台里的小模块,而不是纯色几何块。</p>
<p><strong>影响:</strong><code>web/components/login/animated-login-characters.tsx</code><code>web/app/globals.css</code><code>docs/source-analysis.html</code></p>
</div>
</article>
<article class="change">
<header>
<h3>2026-05-15 · 登录页角色取消默认上下浮动</h3>

View File

@@ -205,46 +205,104 @@
transform: translateX(-50%) scale(0.74);
transform-origin: bottom center;
}
.login-character-base {
position: absolute;
left: 28px;
right: 18px;
bottom: -12px;
height: 28px;
border-radius: 999px;
background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.48), rgba(0, 0, 0, 0) 72%);
filter: blur(1px);
}
.login-figure {
position: absolute;
bottom: 0;
transform-origin: bottom center;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.16);
transition:
transform 0.7s cubic-bezier(0.4, 0, 0.2, 1),
height 0.55s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.2s ease;
will-change: transform;
filter: drop-shadow(0 28px 34px rgba(0, 0, 0, 0.32));
filter: drop-shadow(0 28px 34px rgba(0, 0, 0, 0.34));
}
.login-figure::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(105deg, rgba(255, 255, 255, 0.16), transparent 34%, rgba(0, 0, 0, 0.12));
background:
linear-gradient(105deg, rgba(255, 255, 255, 0.2), transparent 30%, rgba(0, 0, 0, 0.15)),
linear-gradient(180deg, rgba(255, 255, 255, 0.06), transparent 28%);
pointer-events: none;
}
.login-figure--purple {
left: 70px;
width: 180px;
height: 400px;
.login-figure__rim {
position: absolute;
inset: 8px;
z-index: 1;
background: #6c3ff5;
border-radius: 0;
border: 1px solid rgba(255, 255, 255, 0.16);
border-radius: inherit;
opacity: 0.85;
pointer-events: none;
}
.login-figure__shine {
position: absolute;
z-index: 1;
left: 18%;
top: 18%;
width: 42%;
height: 11%;
border-radius: 999px;
background: rgba(255, 255, 255, 0.22);
transform: rotate(-14deg);
pointer-events: none;
}
.login-figure__panel {
position: absolute;
z-index: 1;
border: 1px solid rgba(255, 255, 255, 0.13);
background: rgba(255, 255, 255, 0.1);
pointer-events: none;
}
.login-figure__signal {
position: absolute;
z-index: 2;
display: flex;
gap: 6px;
pointer-events: none;
}
.login-figure__signal span {
width: 7px;
height: 7px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.56);
box-shadow: 0 0 12px rgba(255, 255, 255, 0.24);
}
.login-figure--purple {
left: 72px;
width: 176px;
height: 392px;
z-index: 1;
background: linear-gradient(165deg, #9b7bff 0%, #6c3ff5 46%, #3e1eb8 100%);
border-radius: 22px 22px 8px 8px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.26);
}
.login-figure--black {
left: 240px;
width: 120px;
height: 310px;
z-index: 2;
background: #2d2d2d;
border-radius: 0;
background: linear-gradient(165deg, #34343a 0%, #202126 48%, #111217 100%);
border-radius: 18px 18px 6px 6px;
border-color: rgba(170, 160, 255, 0.18);
}
.login-figure--orange {
left: 0;
width: 240px;
height: 150px;
z-index: 3;
background: #ff9b6b;
background: linear-gradient(160deg, #ffb27f 0%, #ff8f61 56%, #dc6f48 100%);
border-radius: 120px 120px 0 0;
}
.login-figure--yellow {
@@ -252,9 +310,66 @@
width: 140px;
height: 230px;
z-index: 4;
background: #e8d754;
background: linear-gradient(160deg, #fff17a 0%, #e8d754 58%, #bfa73a 100%);
border-radius: 70px 70px 0 0;
}
.login-figure--purple .login-figure__panel {
left: 22px;
bottom: 88px;
width: 36px;
height: 152px;
border-radius: 999px;
}
.login-figure--purple .login-figure__signal {
left: 26px;
bottom: 46px;
}
.login-figure--black .login-figure__panel {
right: 16px;
bottom: 40px;
width: 12px;
height: 190px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.08);
}
.login-figure--black .login-figure__signal {
right: 18px;
top: 88px;
flex-direction: column;
}
.login-figure--orange .login-figure__panel {
left: 42px;
bottom: 24px;
width: 88px;
height: 18px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.16);
}
.login-figure--orange .login-figure__signal {
right: 54px;
bottom: 28px;
}
.login-figure--yellow .login-figure__panel {
left: 24px;
bottom: 44px;
width: 92px;
height: 24px;
border-radius: 999px;
background: rgba(45, 45, 45, 0.08);
border-color: rgba(45, 45, 45, 0.12);
}
.login-figure--yellow .login-figure__shine {
background: rgba(255, 255, 255, 0.3);
}
.login-figure--yellow .login-figure__signal {
left: 34px;
top: 124px;
}
.login-figure--yellow .login-figure__signal span,
.login-figure--orange .login-figure__signal span {
background: rgba(45, 45, 45, 0.36);
box-shadow: none;
}
.login-eyes {
position: absolute;
z-index: 2;

View File

@@ -8,13 +8,14 @@ type FigureSpec = {
id: "purple" | "black" | "orange" | "yellow"
eyeKind: EyeKind
mouth?: "purple" | "orange" | "yellow"
marks?: number
}
const FIGURES: FigureSpec[] = [
{ id: "purple", eyeKind: "eye", mouth: "purple" },
{ id: "black", eyeKind: "small-eye" },
{ id: "orange", eyeKind: "pupil", mouth: "orange" },
{ id: "yellow", eyeKind: "pupil", mouth: "yellow" },
{ id: "purple", eyeKind: "eye", mouth: "purple", marks: 3 },
{ id: "black", eyeKind: "small-eye", marks: 2 },
{ id: "orange", eyeKind: "pupil", mouth: "orange", marks: 2 },
{ id: "yellow", eyeKind: "pupil", mouth: "yellow", marks: 3 },
]
function Eyes({ figure, kind }: { figure: FigureSpec["id"]; kind: EyeKind }) {
@@ -45,6 +46,14 @@ function Mouth({ type }: { type: NonNullable<FigureSpec["mouth"]> }) {
function Figure({ spec }: { spec: FigureSpec }) {
return (
<div className={`login-figure login-figure--${spec.id}`}>
<span className="login-figure__rim" />
<span className="login-figure__shine" />
<span className="login-figure__panel" />
<span className="login-figure__signal">
{Array.from({ length: spec.marks ?? 0 }).map((_, index) => (
<span key={index} />
))}
</span>
<Eyes figure={spec.id} kind={spec.eyeKind} />
{spec.mouth ? <Mouth type={spec.mouth} /> : null}
</div>
@@ -72,6 +81,7 @@ export function AnimatedLoginCharacters({
>
<div className="login-stage-grid" />
<div className="login-characters-container">
<div className="login-character-base" />
{FIGURES.map((spec) => (
<Figure key={spec.id} spec={spec} />
))}