Files
gufa-code-king/web/index.html
kang 18670d2267 第二部 · 第四章《那一夜,他关掉了屏幕》(+3800 字)
审查会前最后 12 小时。沉淀章——从'他必须写下答案'到'他不再需要一个明确答案'。

核心剧情:
- 苏青禾九点半先睡,留一碗炖鸡在书房门口只说'你自己看着来'——她今晚大概率知道他不会去写'那句话'
- 他做了一件很笨的事——把沈陌 213 页黑色笔记本从第一页读到最后一页,不跳不挑
- 读到第 47 页(2038-07-14 沈陌给两岁女儿画的铅笔画+'爸爸今天没说出那句该说的话')停了一小时
- 意识到'这本笔记不是技术观察手册,是一个人怎么在我看见了却没人听的漫长孤独里把自己继续撑下去的证据'
- 凌晨 2:40 拨通沈陌电话只说'我还在读你的本子',对方只回一个'好'
- 忽然想起 23 年前那封被他遗忘的老总监邮件——查邮箱,发信日期 2037-12-04 02:17,他自己 11-03 沈陌 11-04 老总监 12-04,那个秋冬之交至少三个地方三个人几乎同时看见同一件事

关键领悟:
- 他这 20 多年一直以为自己是孤身一人扛着被忽略的警告走过来。其实不是——他只是那个被留下来替很多人继续咬着不放的人
- 他身上的刺是代价,不是美德,不是尊严,是代价
- 老总监说的是'看住'不是'否掉'——看住是长期在场,是长程陪伴,让这件事在接下来三十年五十年一百年都不至于再被任何一代人轻易松手

决定性动作:
- 按下电源键,'我 怕 的——'连同光标在一瞬间消失
- 他没写完那句话。让问题不再是一个非答不可的问题
- 直接去睡——20 年第一次不靠酒不靠熬不靠咬着牙睡
- 苏青禾 2:57 醒来愣一秒帮他掖被子

第二天早上:
- 穿深灰棉衬衫+15 年没换款式的旧黑大衣(不是定制深色西装)
- 帆布包里塞三样东西:归墟·2038 + 沈陌黑笔记 + 许幼宁 86 次攻防日志
- 早饭桌上苏青禾不问他任何关于审查会的问题
- 门口她替他整理衣领看着他眼睛'我信你' → 他低声'嗯'
- 专车驶向中央大厅,车里他闭眼回放:许幼宁那根刺的话 + 韩锐'不会再站到那个舞台上' + 沈陌最后一页 + 苏青禾'我信你' + 老总监'替我看住'

章末:他不知道一小时后自己走上审查台张开嘴第一个字会是赞同还是否决还是两者都不是。但他知道,自己今天不是一个人上去的。中央技术大厅在城市天际线慢慢浮现。

网页:CHAPTERS 加 n=-4 第 25 条。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:31:03 +08:00

1012 lines
34 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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>古法代码之王 · 全世界 AI 崩溃后一位古法程序员的逆袭</title>
<meta name="description" content="一部近未来科幻爽文:当全世界把写代码交给 AI只有一个被时代淘汰的人还记得如何真正让系统运转。">
<meta property="og:title" content="古法代码之王">
<meta property="og:description" content="全世界 AI 崩溃后,一位被时代淘汰的程序员,独自把文明重新点亮。">
<meta property="og:image" content="./images/protagonist_reference.jpg">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect fill='%230a0b10' width='100' height='100'/%3E%3Ctext x='50' y='68' font-size='60' text-anchor='middle' fill='%23c9a357' font-family='serif'%3E王%3C/text%3E%3C/svg%3E">
<style>
:root {
--bg: #0a0b10;
--bg-soft: #12141c;
--bg-card: #171923;
--border: #252836;
--fg: #e8e8ec;
--fg-soft: #a8aab4;
--fg-dim: #6e7080;
--gold: #c9a357;
--gold-soft: #8d7035;
--blue: #6a8aad;
--red: #c45a4d;
}
* { box-sizing: border-box; }
html, body {
margin: 0; padding: 0;
background: var(--bg);
color: var(--fg);
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', 'Source Han Sans SC', sans-serif;
font-size: 16px;
line-height: 1.75;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
body { overflow-x: hidden; }
a { color: var(--gold); text-decoration: none; }
a:hover { color: var(--fg); }
img { max-width: 100%; display: block; }
/* ---------- Hero ---------- */
.hero {
position: relative;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
padding: 40px 20px;
}
.hero::before {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(ellipse at center, rgba(201,163,87,0.08) 0%, transparent 60%),
linear-gradient(180deg, #05060a 0%, var(--bg) 100%);
z-index: 0;
}
.hero-portrait {
position: absolute;
right: -10%;
top: 0;
bottom: 0;
width: 70%;
background-image: url('./images/protagonist_reference.jpg');
background-size: cover;
background-position: center right;
opacity: 0.22;
filter: grayscale(30%) contrast(1.05);
mask-image: linear-gradient(90deg, transparent 0%, black 55%);
-webkit-mask-image: linear-gradient(90deg, transparent 0%, black 55%);
z-index: 1;
}
.hero-inner {
position: relative;
z-index: 2;
max-width: 820px;
width: 100%;
}
.hero-kicker {
color: var(--gold);
font-size: 13px;
letter-spacing: 0.4em;
text-transform: uppercase;
margin-bottom: 32px;
padding-left: 24px;
position: relative;
}
.hero-kicker::before {
content: '';
position: absolute;
left: 0; top: 50%;
width: 16px; height: 1px;
background: var(--gold);
}
.hero-title {
font-family: 'Songti SC', 'Noto Serif CJK SC', 'Source Han Serif SC', serif;
font-weight: 700;
font-size: clamp(56px, 11vw, 132px);
line-height: 1.05;
margin: 0 0 28px;
letter-spacing: 0.04em;
background: linear-gradient(180deg, #f2e4b8 0%, var(--gold) 50%, var(--gold-soft) 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-shadow: 0 4px 40px rgba(201,163,87,0.15);
}
.hero-subtitle {
font-size: clamp(16px, 2.4vw, 22px);
color: var(--fg-soft);
max-width: 620px;
line-height: 1.8;
margin: 0 0 12px;
}
.hero-tagline {
font-family: 'Songti SC', 'Noto Serif CJK SC', serif;
font-size: clamp(18px, 2.4vw, 24px);
color: var(--fg);
line-height: 1.8;
font-style: italic;
border-left: 2px solid var(--gold);
padding-left: 20px;
margin: 36px 0 48px;
max-width: 620px;
}
.hero-meta {
display: flex;
gap: 40px;
flex-wrap: wrap;
color: var(--fg-dim);
font-size: 13px;
letter-spacing: 0.2em;
}
.hero-meta span strong {
display: block;
color: var(--fg);
font-size: 22px;
font-weight: 600;
letter-spacing: 0;
margin-top: 4px;
font-family: 'Songti SC', serif;
}
.hero-cta {
margin-top: 48px;
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.btn {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 14px 28px;
border: 1px solid var(--border);
border-radius: 0;
background: transparent;
color: var(--fg);
font-size: 14px;
letter-spacing: 0.2em;
cursor: pointer;
transition: all 0.25s ease;
font-family: inherit;
}
.btn:hover { border-color: var(--gold); color: var(--gold); }
.btn.primary { border-color: var(--gold); color: var(--gold); }
.btn.primary:hover { background: var(--gold); color: var(--bg); }
.hero-scroll {
position: absolute;
bottom: 32px;
left: 50%;
transform: translateX(-50%);
color: var(--fg-dim);
font-size: 11px;
letter-spacing: 0.4em;
z-index: 2;
animation: pulse 2.4s ease infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.4; transform: translate(-50%, 0); }
50% { opacity: 1; transform: translate(-50%, 6px); }
}
/* ---------- Section shared ---------- */
section {
padding: 120px 24px;
position: relative;
}
.container {
max-width: 1100px;
margin: 0 auto;
}
.container-reading {
max-width: 780px;
margin: 0 auto;
}
.eyebrow {
color: var(--gold);
font-size: 12px;
letter-spacing: 0.4em;
text-transform: uppercase;
margin-bottom: 16px;
}
.section-title {
font-family: 'Songti SC', serif;
font-size: clamp(32px, 5vw, 56px);
font-weight: 700;
margin: 0 0 48px;
line-height: 1.2;
}
/* ---------- About / Synopsis ---------- */
.about { background: var(--bg-soft); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.about-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 80px;
align-items: start;
}
.about-text p {
color: var(--fg-soft);
margin: 0 0 20px;
line-height: 1.9;
}
.about-text p:first-of-type::first-letter {
float: left;
font-family: 'Songti SC', serif;
font-size: 64px;
line-height: 0.9;
padding: 8px 12px 0 0;
color: var(--gold);
font-weight: 700;
}
.about-stats {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32px;
padding: 40px;
background: var(--bg-card);
border: 1px solid var(--border);
}
.stat-num {
font-family: 'Songti SC', serif;
font-size: 48px;
color: var(--gold);
line-height: 1;
font-weight: 700;
margin-bottom: 8px;
}
.stat-label {
color: var(--fg-dim);
font-size: 12px;
letter-spacing: 0.3em;
text-transform: uppercase;
}
/* ---------- Characters ---------- */
.characters { background: var(--bg); }
.char-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 24px;
margin-top: 40px;
}
.char-card {
padding: 32px 28px;
background: var(--bg-card);
border: 1px solid var(--border);
transition: all 0.3s ease;
}
.char-card:hover {
border-color: var(--gold-soft);
transform: translateY(-2px);
}
.char-role {
color: var(--gold);
font-size: 11px;
letter-spacing: 0.3em;
text-transform: uppercase;
margin-bottom: 10px;
}
.char-name {
font-family: 'Songti SC', serif;
font-size: 26px;
font-weight: 700;
margin: 0 0 16px;
}
.char-desc {
color: var(--fg-soft);
font-size: 14px;
line-height: 1.8;
margin: 0;
}
/* ---------- Chapters list ---------- */
.chapters { background: var(--bg-soft); border-top: 1px solid var(--border); }
.volume-heading {
display: flex;
align-items: center;
gap: 20px;
margin: 72px 0 32px;
color: var(--gold);
font-family: 'Songti SC', serif;
font-size: 22px;
font-weight: 700;
}
.volume-heading::before, .volume-heading::after {
content: '';
flex: 1;
height: 1px;
background: linear-gradient(90deg, transparent, var(--gold-soft), transparent);
}
.chapter-row {
display: grid;
grid-template-columns: 80px 1fr auto;
gap: 24px;
align-items: center;
padding: 24px 0;
border-bottom: 1px solid var(--border);
cursor: pointer;
transition: all 0.2s ease;
}
.chapter-row:hover {
padding-left: 12px;
border-color: var(--gold-soft);
}
.chapter-row:hover .chapter-num {
color: var(--gold);
}
.chapter-num {
font-family: 'Songti SC', serif;
font-size: 36px;
font-weight: 700;
color: var(--fg-dim);
line-height: 1;
transition: color 0.2s;
}
.chapter-title {
font-family: 'Songti SC', serif;
font-size: 22px;
font-weight: 600;
margin: 0 0 6px;
}
.chapter-hint {
color: var(--fg-dim);
font-size: 13px;
}
.chapter-arrow {
color: var(--fg-dim);
font-size: 24px;
}
.chapter-row:hover .chapter-arrow { color: var(--gold); }
/* ---------- Reader (chapter content) ---------- */
.reader { background: var(--bg); }
.reader-chapter {
margin: 0 0 120px;
padding-top: 60px;
}
.reader-chapter:first-of-type { padding-top: 0; }
.reader-chapter-num {
color: var(--gold);
font-family: 'Songti SC', serif;
font-size: 14px;
letter-spacing: 0.4em;
margin-bottom: 12px;
}
.reader-chapter-title {
font-family: 'Songti SC', serif;
font-size: clamp(36px, 5vw, 56px);
font-weight: 700;
margin: 0 0 40px;
line-height: 1.15;
}
.reader-chapter-img {
width: 100%;
margin: 0 0 48px;
aspect-ratio: 16/10;
object-fit: cover;
background: var(--bg-card);
border: 1px solid var(--border);
}
.reader-chapter-body p {
font-family: 'Songti SC', 'Noto Serif CJK SC', serif;
font-size: 17px;
line-height: 2;
color: #d2d2d6;
margin: 0 0 24px;
text-indent: 2em;
}
.reader-chapter-body p.no-indent { text-indent: 0; }
.reader-chapter-body blockquote {
border-left: 3px solid var(--gold);
padding: 4px 0 4px 24px;
margin: 32px 0;
color: var(--fg);
font-family: 'Songti SC', serif;
font-size: 19px;
line-height: 1.9;
}
.chapter-divider {
text-align: center;
margin: 80px 0;
color: var(--gold);
font-size: 20px;
letter-spacing: 1.5em;
}
/* ---------- Gallery ---------- */
.gallery { background: var(--bg-soft); border-top: 1px solid var(--border); }
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 24px;
margin-top: 40px;
}
.gallery-item {
background: var(--bg-card);
border: 1px solid var(--border);
overflow: hidden;
cursor: pointer;
transition: all 0.3s ease;
}
.gallery-item:hover {
border-color: var(--gold-soft);
transform: translateY(-4px);
}
.gallery-item img {
width: 100%;
aspect-ratio: 16/10;
object-fit: cover;
transition: transform 0.5s ease;
}
.gallery-item:hover img { transform: scale(1.04); }
.gallery-meta {
padding: 20px;
}
.gallery-cap {
font-family: 'Songti SC', serif;
font-size: 18px;
margin: 0 0 6px;
font-weight: 600;
}
.gallery-sub {
color: var(--fg-dim);
font-size: 12px;
letter-spacing: 0.2em;
}
/* ---------- Part II separator ---------- */
.reader-chapter-part2 {
margin-top: 200px !important;
padding-top: 120px;
border-top: 1px solid var(--gold-soft);
position: relative;
}
.reader-chapter-part2::before {
content: 'PART · II';
position: absolute;
top: 48px;
left: 50%;
transform: translateX(-50%);
color: var(--gold);
font-family: 'Songti SC', serif;
font-size: 13px;
font-weight: 700;
letter-spacing: 0.6em;
padding: 6px 24px;
background: var(--bg);
border: 1px solid var(--gold-soft);
}
.reader-chapter-part2 .reader-chapter-num {
color: var(--gold);
}
/* ---------- Reader extras (章末延伸图) ---------- */
.reader-extras {
margin: 64px 0 40px;
padding: 32px 0 0;
border-top: 1px solid var(--border);
}
.reader-extras-label {
color: var(--gold);
font-size: 11px;
letter-spacing: 0.4em;
text-transform: uppercase;
margin-bottom: 24px;
}
.reader-extras-grid {
display: grid;
grid-template-columns: 1fr;
gap: 28px;
}
.reader-extra {
margin: 0;
cursor: zoom-in;
transition: transform 0.3s ease;
}
.reader-extra:hover { transform: translateY(-2px); }
.reader-extra img {
width: 100%;
aspect-ratio: 16/10;
object-fit: cover;
background: var(--bg-card);
border: 1px solid var(--border);
}
.reader-extra figcaption {
padding: 16px 0 0;
}
.reader-extra-cap {
font-family: 'Songti SC', serif;
font-size: 19px;
font-weight: 600;
color: var(--fg);
margin-bottom: 4px;
}
.reader-extra-sub {
color: var(--gold);
font-size: 11px;
letter-spacing: 0.3em;
text-transform: uppercase;
}
/* ---------- Gallery extras divider ---------- */
.gallery-extras-heading {
display: flex;
align-items: center;
gap: 20px;
margin: 80px 0 32px;
color: var(--gold);
font-family: 'Songti SC', serif;
font-size: 22px;
font-weight: 700;
}
.gallery-extras-heading::before, .gallery-extras-heading::after {
content: '';
flex: 1;
height: 1px;
background: linear-gradient(90deg, transparent, var(--gold-soft), transparent);
}
.gallery-extras-sub {
text-align: center;
color: var(--fg-dim);
font-size: 12px;
letter-spacing: 0.3em;
margin: -16px 0 40px;
text-transform: uppercase;
}
/* ---------- Footer ---------- */
footer {
padding: 64px 24px 40px;
border-top: 1px solid var(--border);
color: var(--fg-dim);
font-size: 13px;
text-align: center;
background: var(--bg);
}
footer p { margin: 8px 0; }
/* ---------- Lightbox ---------- */
.lightbox {
position: fixed;
inset: 0;
background: rgba(5,6,10,0.96);
z-index: 100;
display: none;
align-items: center;
justify-content: center;
padding: 24px;
cursor: zoom-out;
}
.lightbox.active { display: flex; }
.lightbox img { max-width: 96%; max-height: 92vh; object-fit: contain; }
.lightbox-close {
position: absolute;
top: 24px; right: 32px;
color: var(--fg);
font-size: 28px;
cursor: pointer;
background: none;
border: none;
}
/* ---------- Nav ---------- */
.topnav {
position: fixed;
top: 0; left: 0; right: 0;
z-index: 50;
padding: 20px 32px;
display: flex;
justify-content: space-between;
align-items: center;
background: linear-gradient(180deg, rgba(10,11,16,0.9), transparent);
backdrop-filter: blur(4px);
pointer-events: none;
}
.topnav > * { pointer-events: auto; }
.topnav-logo {
font-family: 'Songti SC', serif;
font-weight: 700;
font-size: 20px;
letter-spacing: 0.1em;
color: var(--fg);
}
.topnav-links {
display: flex;
gap: 32px;
}
.topnav-links a {
color: var(--fg-soft);
font-size: 13px;
letter-spacing: 0.2em;
text-transform: uppercase;
}
.topnav-links a:hover { color: var(--gold); }
/* ---------- Responsive ---------- */
@media (max-width: 768px) {
section { padding: 80px 20px; }
.about-grid { grid-template-columns: 1fr; gap: 48px; }
.hero-portrait { width: 100%; right: 0; opacity: 0.14; }
.topnav-links { display: none; }
.chapter-row { grid-template-columns: 56px 1fr; gap: 16px; }
.chapter-arrow { display: none; }
.chapter-num { font-size: 28px; }
.chapter-title { font-size: 18px; }
.reader-chapter-body p { font-size: 16px; line-height: 1.95; }
.hero-meta { gap: 24px; }
.hero-meta span strong { font-size: 18px; }
.reader-chapter { margin-bottom: 80px; }
}
/* ---------- Loading ---------- */
.loading {
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
color: var(--fg-dim);
font-size: 14px;
letter-spacing: 0.3em;
}
</style>
</head>
<body>
<nav class="topnav">
<div class="topnav-logo">古法代码之王</div>
<div class="topnav-links">
<a href="#about">简介</a>
<a href="#characters">人物</a>
<a href="#chapters">章节</a>
<a href="#reader">阅读</a>
<a href="#gallery">画廊</a>
</div>
</nav>
<header class="hero">
<div class="hero-portrait"></div>
<div class="hero-inner">
<div class="hero-kicker">近未来 · 都市 · 科技爽文</div>
<h1 class="hero-title">古法代码<br>&nbsp;</h1>
<p class="hero-subtitle">全世界 AI 崩溃后一位古法程序员的逆袭。</p>
<blockquote class="hero-tagline">
当全世界都把写代码交给 AI<br>只有一个被时代淘汰的人,还记得如何真正让系统运转。
</blockquote>
<div class="hero-meta">
<span>章节数<strong>20 + 终章</strong></span>
<span>字数<strong>约 12 万字</strong></span>
<span>原创插图<strong>22 幅</strong></span>
<span>时间跨度<strong>20 年</strong></span>
</div>
<div class="hero-cta">
<a href="#reader" class="btn primary">开始阅读 →</a>
<a href="#chapters" class="btn">章节目录</a>
</div>
</div>
<div class="hero-scroll">↓ SCROLL</div>
</header>
<section class="about" id="about">
<div class="container">
<div class="eyebrow">SYNOPSIS · 简介</div>
<h2 class="section-title">这是一个<br>旧时代火种的故事。</h2>
<div class="about-grid">
<div class="about-text">
<p>二十一世纪三十年代后,全球进入"全栈智编时代"。绝大多数公司不再招聘传统程序员,而是招聘"意图架构师""模型协同师""AI 产线调度员"。人类几乎不再真正编写代码,只需要向超大型编程模型描述需求。</p>
<p>随着二十年的沉浸式依赖,真正理解数据结构、编译原理、操作系统、网络协议和底层工程实现的人越来越少。社会舆论将手写代码视为落后、低效、古怪甚至可笑的旧时代手艺。</p>
<p>然而这一切建立在一个全球统一的基础上:所有大型系统都深度依赖"宙核智能编程网"。一旦底层智能编程能力发生系统性失灵,整个世界将出现无人能修的灾难性后果。</p>
<p>顾沉舟,一个始终坚持手写代码、读源码、理解底层的"异类"——在漫长二十年里,他穷过、被辞退过、被恋人嫌弃过,也怀疑过自己是不是抱着一堆过时骨头不肯松手。直到那一天,世界停电。</p>
</div>
<div class="about-stats">
<div>
<div class="stat-num">20</div>
<div class="stat-label">Chapters · 章</div>
</div>
<div>
<div class="stat-num">12w</div>
<div class="stat-label">Words · 字</div>
</div>
<div>
<div class="stat-num">22</div>
<div class="stat-label">Illustrations</div>
</div>
<div>
<div class="stat-num"></div>
<div class="stat-label">Iteration</div>
</div>
</div>
</div>
</div>
</section>
<section class="characters" id="characters">
<div class="container">
<div class="eyebrow">CAST · 人物</div>
<h2 class="section-title">那些站在他身边的人,<br>和那些笑过他的人。</h2>
<div class="char-grid">
<div class="char-card">
<div class="char-role">男主 · Protagonist</div>
<h3 class="char-name">顾沉舟</h3>
<p class="char-desc">底层技术狂人。信奉"代码必须自己写过,系统必须自己跑懂"。嘴硬、寡言、倔强,在全球智能编程崩溃之前,他是个被时代嫌弃二十年的穷光蛋。</p>
</div>
<div class="char-card">
<div class="char-role">旧爱 · First Love</div>
<h3 class="char-name">林晚乔</h3>
<p class="char-desc">大学时代最接近恋人的女孩。聪明、现实、心软却怕穷。喜欢过他写代码时专注到近乎冷峻的模样,也最终在房租与前途面前选择离开。</p>
</div>
<div class="char-card">
<div class="char-role">救赎 · Redemption</div>
<h3 class="char-name">苏青禾</h3>
<p class="char-desc">前期唯一真正看懂男主价值的人。安静、克制、细腻,在他最落魄时多次帮他扛过现实危机。陪伴型、治愈型,后期极具分量。</p>
</div>
<div class="char-card">
<div class="char-role">权势 · Power</div>
<h3 class="char-name">沈知意</h3>
<p class="char-desc">资本与媒体的宠儿。出身顶级财团,聪明、美艳、掌控欲强,对技术天才有近乎病态的占有欲。男主一朝成名后,她主动出手。</p>
</div>
<div class="char-card">
<div class="char-role">战友 · Comrade</div>
<h3 class="char-name">许幼宁</h3>
<p class="char-desc">国家级关键项目中的天才安全研究员,冷感、锋利、极致专业。与男主先是惺惺相惜的战友,后因共同经历全球危机而逐渐动情。</p>
</div>
<div class="char-card">
<div class="char-role">反派 · Foil</div>
<h3 class="char-name">韩锐</h3>
<p class="char-desc">最早全面拥抱 AI 编码红利的大学同学。擅长包装、迎合资本、表演"技术领袖"人设。危机爆发后,成为最典型的"离开 AI 就彻底无能"的昔日天才。</p>
</div>
</div>
</div>
</section>
<section class="chapters" id="chapters">
<div class="container">
<div class="eyebrow">CHAPTERS · 章节目录</div>
<h2 class="section-title">二十年,<br>四卷沉浮。</h2>
<div id="chapters-list"></div>
</div>
</section>
<section class="reader" id="reader">
<div class="container-reading">
<div class="eyebrow">READ · 在线阅读</div>
<h2 class="section-title">正文</h2>
<div id="reader-content"><div class="loading">载入中 …</div></div>
</div>
</section>
<section class="gallery" id="gallery">
<div class="container">
<div class="eyebrow">GALLERY · 插图画廊</div>
<h2 class="section-title">命运的二十二帧。</h2>
<p style="color: var(--fg-soft); max-width: 620px; margin: -24px 0 40px;">从毕业即过时,到代码之王——画面随男主心境推进:冷灰蓝 → 工业寒夜 → 红色告警 → 深黑金巅峰。点击任一幅放大查看。</p>
<div class="gallery-grid" id="gallery-grid"></div>
<div class="gallery-extras-heading">扩集画面 · EXTRA</div>
<div class="gallery-extras-sub">扩写之后新生的关键时刻 · 6 幅</div>
<div class="gallery-grid" id="gallery-extras"></div>
</div>
</section>
<footer>
<p>《古法代码之王》 · 近未来都市科技爽文 · 创作归档 2026-04</p>
<p style="color: var(--fg-dim)">展示站部署于 kang-kang.com · 仓库 gitea@kangwang</p>
<p style="margin-top: 24px; color: var(--fg-dim); font-size: 11px; letter-spacing: 0.3em;">GUFA · CODE · KING · MMXXVI</p>
</footer>
<div class="lightbox" id="lightbox" onclick="closeLightbox()">
<button class="lightbox-close" onclick="closeLightbox()">×</button>
<img id="lightbox-img" src="" alt="">
</div>
<script>
const CHAPTERS = [
{ n: 1, title: '毕业即过时', img: 'ch01_graduation_outdated.jpg', volume: '第一卷 · 被时代埋掉的人', hint: 'AI 编码招聘横扫市场,他被视为古董' },
{ n: 2, title: '最便宜的程序员', img: 'ch02_the_cheapest_programmer.jpg', volume: '第一卷 · 被时代埋掉的人', hint: '边缘公司,遗留系统,人人轻视' },
{ n: 3, title: '她说你这样没有未来', img: 'ch03_you_have_no_future.jpg', volume: '第一卷 · 被时代埋掉的人', hint: '贫穷与理想,裂痕第一道' },
{ n: 4, title: '全世界都在笑他', img: 'ch04_the_world_laughed_at_him.jpg', volume: '第一卷 · 被时代埋掉的人', hint: '韩锐风光无限,他在出租屋里修服务器' },
{ n: 5, title: '被裁员的人没有资格谈梦想', img: 'ch05_laid_off_no_dreams.jpg', volume: '第一卷 · 被时代埋掉的人', hint: '第一份工作失去,跌入谷底' },
{ n: 6, title: '旧电脑与冷泡面', img: 'ch06_old_computer_cold_noodles.jpg', volume: '第二卷 · 寒冬里独自敲键盘', hint: '低端外包,熬夜,凄惨地活着',
extras: [
{ file: 'extra/ch06_panic_night.jpg', cap: '第三天夜里 · 被自己的恐惧按在地上', sub: 'PTSD 原点' }
] },
{ n: 7, title: '只有她递来一把伞', img: 'ch07_she_brought_an_umbrella.jpg', volume: '第二卷 · 寒冬里独自敲键盘', hint: '苏青禾登场,一点温柔的光' },
{ n: 8, title: '爱也会输给房租', img: 'ch08_love_lost_to_rent.jpg', volume: '第二卷 · 寒冬里独自敲键盘', hint: '林晚乔正式离开,情感谷底' },
{ n: 9, title: '没人相信的底层能力', img: 'ch09_no_one_believed_him.jpg', volume: '第二卷 · 寒冬里独自敲键盘', hint: '想推销离线开发,被当笑话' },
{ n: 10, title: '十年一梦,满身风雪', img: 'ch10_ten_years_in_snow.jpg', volume: '第二卷 · 寒冬里独自敲键盘', hint: '在行业边缘漂泊多年',
extras: [
{ file: 'extra/ch10_cafe_read_alone.jpg', cap: '他给自己读完一场没有听众的演讲', sub: '40 岁 · 平静庄严' }
] },
{ n: 11, title: '聪明人都不会手写代码了', img: 'ch11_no_one_writes_code_anymore.jpg', volume: '第三卷 · 黑箱时代的裂缝', hint: '传统工程师彻底绝迹' },
{ n: 12, title: '第一次异常', img: 'ch12_first_anomaly.jpg', volume: '第三卷 · 黑箱时代的裂缝', hint: '核心系统零星故障,被当波动' },
{ n: 13, title: '无人能读懂的补丁', img: 'ch13_unreadable_patch.jpg', volume: '第三卷 · 黑箱时代的裂缝', hint: '大平台自修复越修越乱' },
{ n: 14, title: '世界停电的那一天', img: 'ch14_the_day_the_world_went_dark.jpg',volume: '第三卷 · 黑箱时代的裂缝', hint: '金融交通医疗能源连锁崩塌',
extras: [
{ file: 'extra/ch14_linwanqiao_window.jpg', cap: '她认出了那只黑色帆布包', sub: '旧情视角 · 一面落地窗' }
] },
{ n: 15, title: '求他出山的人排到了楼下', img: 'ch15_people_queued_to_beg_him.jpg', volume: '第三卷 · 黑箱时代的裂缝', hint: '昔日嘲笑他的人开始低头' },
{ n: 16, title: '一人重启一座城', img: 'ch16_one_man_restart_a_city.jpg', volume: '第四卷 · 旧时代火种', hint: '凭古法工程修复核心调度',
extras: [
{ file: 'extra/ch16_victory_night_alone.jpg', cap: '庆功夜 · 锁门独饮', sub: '成功的空旷 · 那接下来呢' }
] },
{ n: 17, title: '财团、公权与资本都在抢他', img: 'ch17_everyone_is_fighting_for_him.jpg',volume: '第四卷 · 旧时代火种', hint: '沈知意、国家机构、巨头同时伸手' },
{ n: 18, title: '她们都在等他一句话', img: 'ch18_they_wait_for_his_answer.jpg', volume: '第四卷 · 旧时代火种', hint: '情感线全面升温' },
{ n: 19, title: '代码之王', img: 'ch19_king_of_code.jpg', volume: '第四卷 · 旧时代火种', hint: '组建离线工程联盟,重塑秩序' },
{ n: 20, title: '坐拥繁花,归来仍是少年', img: 'ch20_among_flowers_still_young.jpg', volume: '第四卷 · 旧时代火种', hint: '站上巅峰,事业情感双圆满' },
{ n: 0, title: '终章 · 写代码的人,重新定义世界', img: 'epilogue_redefine_the_world.jpg', volume: '终章', hint: 'AI 重新成为工具而非拐杖',
extras: [
{ file: 'extra/ring_classroom_10yrs_later.jpg', cap: '十年后 · 新一代走进教室', sub: '环状收尾 · 黑板三字:写 代 码' },
{ file: 'extra/s2_blank_second_page.jpg', cap: '我 怕 的——', sub: '第二部 · 序章 · 留白' }
] },
{ n: -1, title: '另一个看见了的人', img: 'extra/s2_blank_second_page.jpg', volume: '第二部 · 起笔', hint: '沈陌登门:顾先生,我写到这里,就等您告诉我,下面该不该写下去' },
{ n: -2, title: '他差一点把那些刺长回来', img: null, volume: '第二部 · 起笔', hint: '三天读尽白皮书,差一点对一个系统动了信任测试的念头;出门去见了韩锐' },
{ n: -3, title: '她说她找不到一个值得攻击的地方', img: null, volume: '第二部 · 起笔', hint: '许幼宁 86 次攻防 0 成功。她揭穿他三年前埋的第三层签名偏差——"我想看你什么时候自己能看到它不再需要"' },
{ n: -4, title: '那一夜,他关掉了屏幕', img: null, volume: '第二部 · 起笔', hint: '审查会前夜:读完沈陌整本笔记 + 想起二十三年前老总监那封被遗忘的邮件"替我看住这套东西" + 关掉屏幕不写答案直接去睡 + 苏青禾那句"我信你"' },
];
function renderChapterList() {
const wrap = document.getElementById('chapters-list');
let html = '', lastVolume = '';
CHAPTERS.forEach((ch, idx) => {
if (ch.volume !== lastVolume) {
html += `<div class="volume-heading">${ch.volume}</div>`;
lastVolume = ch.volume;
}
let num;
if (ch.n === 0) num = '终';
else if (ch.n < 0) num = 'II·' + String(-ch.n).padStart(2, '0');
else num = ch.n.toString().padStart(2, '0');
const title = ch.n === 0 ? ch.title.replace('终章 · ', '') : ch.title;
html += `
<div class="chapter-row" onclick="jumpToChapter(${idx})">
<div class="chapter-num">${num}</div>
<div>
<h3 class="chapter-title">${title}</h3>
<div class="chapter-hint">${ch.hint}</div>
</div>
<div class="chapter-arrow">→</div>
</div>`;
});
wrap.innerHTML = html;
}
function renderGallery() {
const wrap = document.getElementById('gallery-grid');
wrap.innerHTML = CHAPTERS.map((ch, idx) => {
const num = ch.n === 0 ? '终章' : `${ch.n}`;
const title = ch.n === 0 ? '写代码的人,重新定义世界' : ch.title;
return `
<div class="gallery-item" onclick="openLightbox('./images/${ch.img}')">
<img src="./images/${ch.img}" alt="${title}" loading="lazy">
<div class="gallery-meta">
<div class="gallery-cap">${title}</div>
<div class="gallery-sub">${num}</div>
</div>
</div>`;
}).join('');
// Extras gallery — new scenes born from expansion
const extrasWrap = document.getElementById('gallery-extras');
if (extrasWrap) {
const extraItems = [];
CHAPTERS.forEach(ch => {
if (!ch.extras) return;
const num = ch.n === 0 ? '终章' : `${ch.n}`;
ch.extras.forEach(ex => {
extraItems.push({ ...ex, num, chTitle: ch.title });
});
});
extrasWrap.innerHTML = extraItems.map(ex => `
<div class="gallery-item" onclick="openLightbox('./images/${ex.file}')">
<img src="./images/${ex.file}" alt="${ex.cap}" loading="lazy">
<div class="gallery-meta">
<div class="gallery-cap">${ex.cap}</div>
<div class="gallery-sub">${ex.num} · ${ex.sub}</div>
</div>
</div>`).join('');
}
}
function jumpToChapter(idx) {
const el = document.getElementById('chapter-' + idx);
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function openLightbox(src) {
const box = document.getElementById('lightbox');
document.getElementById('lightbox-img').src = src;
box.classList.add('active');
document.body.style.overflow = 'hidden';
}
function closeLightbox() {
document.getElementById('lightbox').classList.remove('active');
document.body.style.overflow = '';
}
async function loadNovel() {
try {
const resp = await fetch('./novel.md');
const text = await resp.text();
renderNovel(text);
} catch (e) {
document.getElementById('reader-content').innerHTML =
'<div class="loading" style="color: var(--red)">小说载入失败:' + e.message + '</div>';
}
}
function renderNovel(md) {
// Strip title & quote block before first ## section
const sections = md.split(/^## /m).slice(1); // each section starts with chapter heading
const out = [];
sections.forEach((sec, idx) => {
const lines = sec.split('\n');
const heading = lines[0].trim();
const body = lines.slice(1).join('\n').trim();
// match "第1章 标题" / "终章 标题" / "第二部 · 第一章 · 标题"
let m = heading.match(/^(第(\d+)章|终章)\s+(.+)$/);
let isPart2 = false;
let num, title;
if (m) {
const isEpilogue = !m[2];
num = isEpilogue ? '终' : m[2].padStart(2, '0');
title = m[3];
// kicker assigned below
var kicker = isEpilogue ? 'EPILOGUE' : 'CHAPTER ' + num;
} else {
const m2 = heading.match(/^第二部\s*·\s*第(.+?)章\s*·\s*(.+)$/);
if (!m2) return;
isPart2 = true;
const cnMap = { '一': '01', '二': '02', '三': '03', '四': '04', '五': '05', '六': '06', '七': '07', '八': '08', '九': '09', '十': '10' };
const arabic = cnMap[m2[1]] || m2[1];
num = 'II · ' + arabic;
title = m2[2];
var kicker = 'PART II · CHAPTER ' + arabic;
}
const ch = CHAPTERS[idx];
const imgPath = ch ? `./images/${ch.img}` : '';
const paragraphs = body.split(/\n\s*\n/).map(p => {
const line = p.trim();
if (!line) return '';
if (line.startsWith('>')) {
return '<blockquote>' + line.replace(/^>\s*/, '') + '</blockquote>';
}
return '<p>' + escapeHtml(line) + '</p>';
}).join('\n');
const extrasHtml = (ch && ch.extras) ? `
<div class="reader-extras">
<div class="reader-extras-label">章末延伸画面 · Extra</div>
<div class="reader-extras-grid">
${ch.extras.map(ex => `
<figure class="reader-extra" onclick="openLightbox('./images/${ex.file}')">
<img src="./images/${ex.file}" alt="${ex.cap}" loading="lazy">
<figcaption>
<div class="reader-extra-cap">${ex.cap}</div>
<div class="reader-extra-sub">${ex.sub}</div>
</figcaption>
</figure>`).join('')}
</div>
</div>` : '';
out.push(`
<article class="reader-chapter ${isPart2 ? 'reader-chapter-part2' : ''}" id="chapter-${idx}">
<div class="reader-chapter-num">${kicker}</div>
<h2 class="reader-chapter-title">${title}</h2>
${imgPath ? `<img class="reader-chapter-img" src="${imgPath}" alt="${title}" loading="lazy" onclick="openLightbox('${imgPath}')" style="cursor: zoom-in;">` : ''}
<div class="reader-chapter-body">${paragraphs}</div>
${extrasHtml}
${idx < sections.length - 1 ? '<div class="chapter-divider">· · ·</div>' : ''}
</article>
`);
});
document.getElementById('reader-content').innerHTML = out.join('');
}
function escapeHtml(s) {
return s.replace(/[&<>]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]));
}
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeLightbox();
});
renderChapterList();
renderGallery();
loadNovel();
</script>
</body>
</html>