Add 3D loose-leaf chronicle of human civilisation

A Three.js site presenting 20 world history milestones as
double-sided loose-leaf pages, with three views: a leather
binder with page-flip animation, a golden timeline, and a
dotted globe with great-circle arcs.

All textures (paper, leather, registration cards, and 18
hand-drawn sketches) are generated procedurally via Canvas
2D, so no external image assets are needed beyond the Earth
map. Includes dev helper scripts for screenshots, ASCII
previews, and headless verification.
This commit is contained in:
2026-09-18 19:19:53 +08:00
commit 4e818d53e3
24 changed files with 4374 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
:root {
--paper: #e6d8b6;
--paper-dark: #cbb88d;
--ink: #3a2d22;
--ink-soft: #6b5740;
--leather: #5a3d2b;
--gold: #c9a227;
--gold-soft: #e0c46a;
--bg: #14100d;
--red: #a03a2a;
--blue: #2c4a6b;
--green: #3f5c3a;
--serif: "Noto Serif SC", "Songti SC", "STSong", "SimSun", Georgia, serif;
--kai: "Kaiti SC", "STKaiti", "KaiTi", "Segoe Script", cursive;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
height: 100%;
overflow: hidden;
background: var(--bg);
font-family: var(--serif);
color: var(--paper);
}
#app { position: fixed; inset: 0; }
#scene { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* 气氛遮罩 */
.vignette {
position: absolute; inset: 0; pointer-events: none;
background: radial-gradient(ellipse at 50% 42%, transparent 40%, rgba(8, 5, 3, 0.55) 100%);
mix-blend-mode: multiply;
}
.grain {
position: absolute; inset: 0; pointer-events: none; opacity: 0.06;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
#iris {
position: absolute; inset: 0; pointer-events: none;
background: #0c0906; opacity: 0; transition: opacity 0.45s ease;
}
/* 顶部标题 */
.hud { position: absolute; z-index: 5; }
.top-left { top: 22px; left: 26px; }
.title {
font-size: clamp(20px, 2.4vw, 34px);
letter-spacing: 0.12em; font-weight: 600; color: var(--gold-soft);
text-shadow: 0 1px 12px rgba(0,0,0,0.7);
}
.subtitle {
margin-top: 4px; font-size: 12px; letter-spacing: 0.18em;
color: rgba(230,216,182,0.65); font-family: Georgia, serif;
}
/* 视图切换 */
.view-switch {
top: 26px; right: 26px; display: flex; gap: 8px;
}
.view-btn {
font-family: var(--serif); font-size: 14px; letter-spacing: 0.1em;
padding: 8px 16px; color: var(--paper); cursor: pointer;
background: rgba(20,14,10,0.55); border: 1px solid rgba(201,162,39,0.35);
border-radius: 3px; backdrop-filter: blur(4px);
transition: all 0.25s ease;
}
.view-btn:hover { border-color: var(--gold); color: #fff; }
.view-btn.active {
background: linear-gradient(180deg, rgba(201,162,39,0.85), rgba(150,115,20,0.85));
color: #1c1308; border-color: var(--gold); font-weight: 600;
}
/* 底部导航 */
.bottom-bar {
left: 50%; bottom: 22px; transform: translateX(-50%);
display: flex; align-items: center; gap: 16px;
padding: 10px 18px; border-radius: 4px;
background: rgba(20,14,10,0.6); border: 1px solid rgba(201,162,39,0.25);
backdrop-filter: blur(6px);
}
.nav-btn {
font-family: var(--serif); font-size: 16px; line-height: 1;
width: 38px; height: 38px; border-radius: 50%;
color: var(--gold-soft); cursor: pointer;
background: rgba(255,255,255,0.04); border: 1px solid rgba(201,162,39,0.4);
transition: all 0.2s ease;
}
.nav-btn:hover { background: rgba(201,162,39,0.25); color: #fff; transform: scale(1.06); }
.nav-btn:active { transform: scale(0.96); }
.flip-hint { width: auto; border-radius: 20px; padding: 0 18px; letter-spacing: 0.12em; font-size: 14px; }
.page-indicator { display: flex; align-items: baseline; gap: 6px; min-width: 200px; justify-content: center; }
#page-num { font-size: 24px; color: var(--gold-soft); font-family: Georgia, serif; }
.sep { color: rgba(230,216,182,0.5); }
#page-total { color: rgba(230,216,182,0.6); font-family: Georgia, serif; }
.page-name { font-size: 14px; color: var(--paper); letter-spacing: 0.05em; margin-left: 10px; }
/* 登记卡详情 */
.detail-card {
right: 24px; bottom: 96px; width: min(320px, 82vw);
padding: 18px 20px; border-radius: 4px;
background: linear-gradient(180deg, rgba(232,216,182,0.96), rgba(214,196,156,0.96));
color: var(--ink); box-shadow: 0 18px 50px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(90,61,43,0.4);
transform: translateY(0); transition: transform 0.35s ease, opacity 0.35s ease;
}
.detail-card.hidden { opacity: 0; pointer-events: none; transform: translateY(14px); }
.detail-head { display: flex; justify-content: space-between; align-items: center; }
.detail-no { font-family: Georgia, serif; font-size: 13px; letter-spacing: 0.14em; color: var(--ink-soft); }
.detail-cat {
font-size: 12px; padding: 2px 10px; border-radius: 2px;
background: var(--leather); color: var(--gold-soft); letter-spacing: 0.2em;
}
.detail-name {
margin: 8px 0 12px; font-size: 22px; letter-spacing: 0.06em; font-weight: 600;
}
.detail-fields { border-top: 1px solid rgba(90,61,43,0.3); padding-top: 8px; }
.field { display: flex; gap: 12px; font-size: 13px; line-height: 1.9; }
.field dt {
flex: 0 0 34px; color: var(--ink-soft); letter-spacing: 0.1em;
}
.field dd { color: var(--ink); }
.detail-desc {
margin-top: 10px; font-size: 13.5px; line-height: 1.75; color: var(--ink);
border-left: 3px solid var(--gold); padding-left: 10px;
}
.detail-sketch { margin-top: 12px; border-top: 1px dashed rgba(90,61,43,0.4); padding-top: 10px; }
.detail-sketch canvas { width: 100%; height: auto; border-radius: 2px; opacity: 0.94; }
/* 提示 */
.hint {
left: 26px; bottom: 26px; font-size: 12px; letter-spacing: 0.06em;
color: rgba(230,216,182,0.55);
}
@media (max-width: 760px) {
.detail-card { display: none; }
.subtitle { display: none; }
.page-name { display: none; }
.hint { display: none; }
}