Files
gufa-code-king/web/index.html
kang c11b61bfbe 第二部 · 第三章《她说她找不到一个值得攻击的地方》(+3800 字)
核心:三份证据并排摆上桌,从三个不同的人,指向同一个方向。

情节:
- 许幼宁约他到郊北靶场(她私人攻防实验室,完全离线工控机柜)
- 递来牛皮纸大信封——'86 次 - 0 成功 - 全部日志原件'
- 三个月私下攻防:反向链路污染 v7.2/深度注入对抗 v4.5/语义边界爆破 v3.1
- 她播放一段录屏——她用自己多年私藏未公开的反向同步槽位 S3-B 打了 v0.7
- 系统没封堵没反击,而是主动暂停推送结构化审查请求,把她的身份/招数/侧信道路径都列给人类审查团,甚至推测她可能是研究性质
- 她平静说:'我从业三十年,第一次遇到一个让我想保护它的系统'

揭穿戏(最锋利一笔):
- 她调出他三年前给安全核验组的'反向一致性验证框架'底稿第 27 页
- 他把'锚点签名对齐逻辑'故意写成'签名锚点对齐逻辑'——顺序颠倒,他刻意埋的信任测试点
- 她:'你问的是埋在这里的第三层签名偏差对吧?我上个月就看见了。我也故意没告诉你。我想看你什么时候自己能看到它不再需要'
- 他告诉她'我昨天把三天审查草稿全部删掉了没有备份'

2037 回响:
- 她透露二十多年前国家安全侧第二年她 28 岁,内部拿到过他的四十页风险分析报告
- 一个八人小组建议认真回复,被负责人一句'让他自己醒醒'否掉
- 他从没想过'被忽略'的那个夜晚,背后有过这么具体的人和讨论

收束三句(第二部命题最锋利表达):
- '我会替你二十年前那个没人回应的夜晚难过。但不会替你下周一那句话'
- '如果你下周一那句话还是没放下你那根刺,你对抗的就不再是时代了。是这个时代正在尝试变好的那一面'
- '从今天起,你身上那根刺,该轮到你自己决定要不要继续留着'

章末:
- 书房并排三份证据——归墟·2038 / 沈陌 2037 年黑笔记 / 许幼宁 86 次攻防日志
- 他第一次打开沈陌笔记本中间的一页:'今天顾先生那篇谈工控协议不可证伪性的论文发了。我读了三遍。我哭了一次'(2041 年)
- 屏幕上'我 怕 的——'仍然闪。但他第一次觉得,那个问题的答案原本就不在屏幕上
- 而是三本东西并排放在一起时,已经替他说出了一半

网页:CHAPTERS 加 n=-3 第 24 条。

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

1011 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 成功。她揭穿他三年前埋的第三层签名偏差——"我想看你什么时候自己能看到它不再需要"' },
];
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>