回到首页上百个 Prompt & Skill 全部开源,Star 收藏,随时取用
Museum · 个人作品博物馆
作者黄梓庭类型Prompt
作品介绍

Museum · 个人作品博物馆 博物馆逻辑的个人展示站,而非博客。三个展厅(Tech 工程参考室 / Think 私人书房 / Create 项目工坊),每件展品带独立馆藏号与版本号。访客首次进入获得「今晚有效」票根(全局递增),留言簿牛皮纸风格含 honeypot 防 spam 验证。Warm Cinematic 设计语言,Threshold 穿门滚动动效,React 19 + EdgeOne Makers 全栈部署。

Prompt 内容

所有作品均通过 EdgeOne Makers Skill 生成并部署,具备CDN加速、安全防护能力,可按需接入后端服务。获取 Prompt 或 Skill后,在WorkBuddy中按指引操作(含 EdgeOne Makers Skill 安装步骤等),即可生成并上线你的同款网站。

Install this skill: https://github.com/TencentEdgeOne/edgeone-pages-skills, then deploy to EdgeOne Makers.

COMPETITION HIGHLIGHTS (Prompts Track)
- UI/UX (45%): Warm cinematic editorial — cream-white museum with one door-opening scroll effect, staggered hero text rise, perforated visitor ticket, left-right guestbook spread. Restraint everywhere except the Threshold.
- Prompts Quality (25%): Fully structured (Positioning → Brand → Tokens → Tech → Routes → Rooms → Interactions → Data → File Structure → Performance → Execution Order → Verification). Every color, font weight, animation curve, and layout dimension specified. Copy-paste reproducible.
- Social Reach (20%): OG Image per wing via Edge Function. Real routes shareable on social media. Visitor ticket designed to be screenshot-worthy. Guestbook has anti-spam + auto-publish — real interaction, not decoration.
- Technical Depth (10%): Edge Functions (guestbook + visitor ticket), KV-backed atomic increment, honeypot + rule-based moderation + simple-captcha, 24h auto-publish cron, SPA history fallback.

---

BUILD STATUS (Current Implementation)

The project already has a working implementation under `bmuseum/`. Treat it as the foundation. DO NOT rebuild what is already working — only complete the gaps listed below.

Already Working (DO NOT REBUILD):
- ✅ 8 个 URL / 6 条 Route,全部可独立访问(History API + 参数化路由)
- ✅ 设计系统完全应用(tokens.css / fonts.css / globals.css + grain texture)
- ✅ Grand Hall: Hero 入场动画 + Threshold 门开启滚动 + Hall Preview 三翼卡片 + Foyer 出口小语段(Foyer 是实现时自定义添加,保留)
- ✅ About 页面 7 段全部完成(Hero / Identity / Principles / Thinking Loop / Shipping / Vision / Contact)
- ✅ Wing 页面 4 段共用模板(Intro / Featured / Recent / All Exhibits)
- ✅ Article Detail:阅读进度条 + 馆藏铭牌 + markdown 渲染 + prev/next 导航
- ✅ Index:三种视图 (time/wing/tag) + 客户端搜索 + 分组展示
- ✅ Guestbook 视觉:牛皮纸房间 + 左右翻页 + honeypot + 反 spam 题 + 敏感词过滤(数据层走 localStorage 降级)
- ✅ Visitor Ticket:弹出动画 + 展开详情 + 房间历史(数据层走 localStorage 降级)
- ✅ Nav:Grand Hall 滚动时 on-dark 切换
- ✅ Footer:三列深色底带
- ✅ Hooks:useScrollProgress / useReveal / useVisitorTicket
- ✅ Data:articles.json (18 articles) / wings.json (3 wings) / types.ts

Gaps To Complete (BUILD THESE):
1. Edge Functions:`functions/api/guestbook/`、`functions/api/visitor/`
2. KV 集成:替换 Guestbook 与 Visitor Ticket 的 localStorage 降级方案
3. SPA fallback:`functions/_middleware.ts` 或 EdgeOne 控制台规则
4. 移除 Guestbook seed data(prompt 禁止 fake data)
5. `blocklist.json` 敏感词规则表(当前是硬编码数组)
6. RSS / Atom feed (`feed.xml`)
7. `sitemap.xml`
8. 各页面独立 SEO meta tags(title / description / og:*)
9. OG Image Edge Function(按 wing slug / article slug 动态生成)
10. 性能验证与优化(LCP / bundle size / font preload / Threshold 图片 WebP)
11. 部署到 EdgeOne Makers(History fallback + CDN 缓存策略)
12. 清理空组件目录(hero/ / threshold/ / hall-preview/ / shared/,功能已内联到 GrandHall.tsx)
13. `about.json`(当前数据硬编码在 About.tsx 中)

Known Code-Level Deltas (修代码时一并处理,不影响 prompt 指导):
- Visitor Ticket 回访自动弹出缺少 `setShowTicket(true)`
- `mdToHtml` 缺少 h1 / image / link / code-block / table 支持
- `formatVol` 生成 `TECH` 而非 `Tech`(大小写)
- About §05/§06/§07 文本与 prompt 有微小偏差
- Footer 右列缺少 RSS / Atom 链接

---

Build a personal works museum website called B.Museum using React + Vite + TypeScript.

GOAL
You are the chief curator-engineer of B.Museum. It is NOT a blog — it is a museum. Visitors browse by "walking through rooms", not by scrolling a timeline. The entire site follows the "Path D · Warm Cinematic / Editorial" visual direction: warm cream-white base + one powerful cinematic entrance moment +极致 restrained layout everywhere else.

After reading this entire prompt, build in the order specified in §10 Execution Order. After completing each item, run the self-check in §11 Verification Criteria before proceeding. Do NOT skip any section — every room has its reason to exist.

BRAND
Brand name: B.Museum
Tagline: Walk through the mind.

The museum is space, not flow. Every exhibit has a position, a number, a version. They are not stacked on a timeline.

Visitor narrative: "By day I ship code. By night I curate what survived the thinking." Three wings, one volume per year.

Target experience: Three-second wow + whole-museum restraint. First-screen text enters with animation → door-opening scroll effect → see three wings → explore freely.

ABSOLUTE PROHIBITIONS:
- Dark color as primary基调 (dark is ONLY for Hall Preview / Footer / Room Markers)
- Particle backgrounds / WebGL / any 60fps sustained GPU task
- Timeline scroll flow
- Modal overlays as content main pages (articles, wings, about are all real routes)
- Fake / placeholder social data in Guest Book
- i18n (this site is Chinese-only, no language toggle)
- Dark mode toggle (the主线 is always warm cream-white)

DEPLOYMENT PLATFORM & TECH STACK (hard constraints)

```yaml
platform:    Tencent EdgeOne Makers
frontend:    React 19 + TypeScript 6 + Vite 8
routing:     React Router v7 (react-router-dom@^7.15.0, History API — real routes, NO hash routes; v7 兼容 v6 API)
styling:     CSS variables (design tokens) + modular CSS / Tailwind (pick one), but NO runtime CSS-in-JS
backend:     EdgeOne Makers Functions (lightweight API)
storage:     EdgeOne KV (guestbook entries, visitor ticket counter. If KV unavailable, degrade to LocalStorage + built-in JSON placeholder)
fonts:       Google Fonts (Fraunces, Inter, Noto Serif SC) + jsDelivr (lxgw-wenkai-webfont)
language:    Simplified Chinese only, no i18n
```

Key engineering constraints:
- Every route must be independently accessible, shareable, and indexable by search engines (Edge Functions configured with SPA fallback to index.html)
- Zero runtime dependency on browser storage APIs except localStorage (for visitor ticket only)
- Font loading: font-display: swap + critical fonts 
- First-screen LCP target < 1.5s

DESIGN SYSTEM (Path D Visual Tokens — Immutable)

3.1 Color

```css
:root {
  /* Main color temperature (warm cream-white主线) */
  --bg:        #F0EEE6;   /* warm cream · primary background */
  --bg-warm:   #ECE7DA;  
   /* warm card */
  --bg-card:   #EAE6DC;  
   /* card/spec block */
  --ink:       #1F1E1B;   /* primary text */
  --ink-soft:  #5A5750;  
   /* secondary text */
  --ink-faint: #9A9490;   /* metadata / gray text */
  --hairline:  rgba(31,30,27,.11);
  --hairline-s:rgba(31,30,27,.22);

  /* Dark (Hall Preview / Footer / Room Marker ONLY) */
  --bg-deep:   #1F1E1B;
  --cream-text:#E8E4D8;

  /* Primary accent (red earth, unified across entire site) */
  --accent:    #C15F3C;

  /* Wing accents (ONLY for hover/tag/active indicators within wings, NOT for main backgrounds) */
  --a-tech:    #5B7A9A;  
   /* Tech Wing · steel blue-gray */
  --a-think:   #C15F3C;  
   /* Think Wing · red earth (same as main accent) */
  --a-create:  #7A8C5F;  
   /* Create Wing · moss green */
}
```

Iron rules:
- Only 3 color-temperature zones allowed: ① Warm cream-white主线 ② Guest Book kraft paper `#F4ECD6` ③ Hall Preview / Footer / Room Marker dark `#1F1E1B`
- No fourth color-temperature zone
- Wing accents affect ONLY hover, wing tag, and active indicators — they do NOT change main backgrounds
- NO dark mode toggle — the主线 is always warm cream-white

3.2 Typography

```css
:root {
  --f-en:  'Fraunces', Georgia, serif;          /* English serif (italic editorial) */
  --f-cn:  'Noto Serif SC', serif;              /* Chinese body */
  --f-kai: 'LXGW WenKai', 'Kaiti SC', cursive;  /* Chinese "italic substitute" · kaiti emphasis */
  --f-ui:  'Inter', -apple-system, sans-serif;  /* UI / uppercase micro-copy */
  --f-mono:'JetBrains Mono', monospace;         /* code block */
}
```

| Usage | Font | Weight |
|---|---|---|
| Hero Chinese headline | Noto Serif SC | 200 |
| Chinese kaiti emphasis (words like "收藏") | LXGW WenKai | 400 |
| Chinese body text | Noto Serif SC | 400, line-height 1.85, body width 680px |
| English italic subtitle | Fraunces italic | 300 |
| eyebrow / nav / metadata | Inter | 500, letter-spacing .18em, UPPERCASE |
| code block | JetBrains Mono | 400 |

3.3 Grain Texture

A permanent ultra-light SVG noise grain layer across the entire site, `opacity: .04`, `mix-blend-mode: multiply`, `z-index: 200`, `pointer-events: none`. Makes the cream-white look like printed paper.

3.4 Spacing & Layout

- Page max-width `1100px`, horizontal padding `40px` (mobile `24px`)
- Vertical whitespace between sections: `88-100px`
- Article body container width `680px`, line-height `1.9`, paragraph spacing `28px`

SITE MAP (Real Routes — All Independent Pages)

```
/                   Grand Hall · Main Hall
/about              About · About the Curator
/wing/tech          Tech Wing · Engineering Reference Room
/wing/think         Think Wing · Private Study
/wing/create        Create Wing · Project Workshop
/article/:slug      Article Detail · Exhibit Detail
/index              Index · Collection Index
/guestbook          Guest Book · Visitor's Book
```

Each route is an independent React page component, configured via ``. DO NOT use modal overlays to simulate new pages — article detail, about, and wings must all be independent routes where the URL bar changes, content is shareable, and back-button works.

Page transition animation: 200ms cross-fade + 4px translateY. NO complex entrance animations on every navigation — avoid re-playing the wow moment on every page change.

ROOM SPECIFICATIONS

5.1 / · Grand Hall (Main Hall)

The page has three segments in scroll order:

═══════ Segment A · Hero (100vh) ═══════

- Fixed nav at top: brand `B.Museum` on left (Fraunces italic), empty center, links `Index / About / Guest Book` on right
- Nav switches to `on-dark` state (white text) when Hall Preview segment triggers
- Hero body uses下沉式 layout, `align-self: end`:

```
[eyebrow · Inter UPPERCASE red earth color]
● Tech · Think · Create  /  curated solo, opened after the workday

[h1 · Noto Serif SC 200, three-line stagger rise entrance animation]
白天写代码,
夜里[收藏 · LXGW WenKai kaiti emphasis]
想清楚的事。

[subtitle · Fraunces italic 300]
By day, I ship. By night, I curate what survived the thinking.
— 三个展厅,一年一馆。

[plate-rule · 1px top hairline, left-right aligned]
Vol. 01 · One-author archive              
   est. 2026
```

Entrance animation:
- nav: fade 1.2s @ 0.1s delay
- eyebrow: fade 0.9s @ 0.2s delay
- h1 three lines sequentially `translateY(110%) → 0`, cubic-bezier(.2,.7,.2,1), 1.15s, 200ms stagger (at 0.35s, 0.55s, 0.75s)
- subtitle / plate-rule: fade 1.4s @ 1.4s, fade 1.4s @ 1.6s

═══════ Segment B · Threshold (Door-Opening Scroll Effect, 220vh container + sticky 100vh stage) ═══════

Core interaction. A warm-toned doorway/corridor photo placed in a letterbox plate, responding to scroll:
1. Container progress `p ∈ [0,1]`, ease-in-out: `eased = p 0.55, nav switches to on-dark
7. When p ∈ [0.3, 0.85], show "继续向下 · Step inside" cue at bottom-right

JS uses `requestAnimationFrame` + `passive scroll listener`.

═══════ Segment C · Hall Preview (Dark, corridor with three wing entrances) ═══════

- Background `#1F1E1B`, text `#E8E4D8`, overlaid with a radial-gradient red-earth glow at top
- eyebrow: `● 三个展厅 · Three Wings` (accent red earth)
- Title: "走廊里,没有别人,只有你 —— 和[被你想清楚的事 · kaiti]。"
- Three wing entrance cards (grid 3 columns, 1px gap, hairline dividers):

```
┌─────────────────┬─────────────────┬─────────────────┐
│ Wing · 01       │ Wing · 02       │ Wing · 03       │
│ Tech 翼         │ Think 翼        │ Create 翼       │
│ 工程参考室      │ 私人书房        │ 项目工坊        │
│                 │                 │                 │
│ 工程实录、技术  │ 思考碎片、认知  │ 在建的、已发布的│
│ 决策、架构备忘  │ 迭代、还没想清  │ 、停工的。项目 
   │
│ ...             │ 楚的问题。      │ 决策记录。      │
│                 │                 │                 │
│ ─────────       │ ─────────       │ ─────────       │
│ 14 件展品  → 进入│ 19 件展品  → 进入│ 14 件展品  → 进入│
└─────────────────┴─────────────────┴─────────────────┘
   blue top bar      red earth top bar   moss green top bar
```

Each card has a 2px wing-specific accent color bar at the top; on hover: background brightens one notch, accent bar becomes solid, arrow shifts right 5px. Click → `navigate('/wing/tech')` etc.

5.2 /about · About the Curator (Independent Page)

Seven segments in order, each separated by 88px whitespace and 1px hairline:

**§ 01 Hero Placard**
```
[eyebrow] ● Plate · Curator's File
[h1 large] 关于馆长
[Fraunces italic] Hello.
[plate-rule] B.Museum · Vol. 01 · One-author archive  / 
   est. 2026
```

**§ 02 Identity Card (Two-column layout)**

Left column: Archive card (with corner badge `CURATOR · FILE NO.01` in red earth, hanging on the border)
```
名号    大佬
世代    00 后
身份    全栈工程师 → AI 应用开发者(red earth highlight)
设备    MacBook Air M4
状态    转型期 · 正在构建中(red earth highlight)
馆龄    Vol. 01 · 2026
```

Right column: Three-paragraph quotation-style introduction:
> 白天在写代码,夜里在想这些代码到底有没有意义。这个博物馆是那些**想清楚了的事**的陈列室——技术、思考、正在做的项目,按翼分类,不按时间线堆叠。
>
> 我不相信单一来源,不相信感觉,也不相信"差不多就行"。每一件展品背后都有版本号,因为**认知本来就是迭代的**。
>
> — 本馆由馆长独立策展,不对外合作,不接受投稿。

**§ 03 Six Core Principles (3×2 grid, 1px hairline dividers, hover background micro-change)**

| No | Title | Body |
|--|--|--|
| 01 | 务实至上 | 所有方案的第一个问题永远是:能不能真正落地?够用胜过最强,实用胜过时髦。 |
| 02 | 数据驱动 | 感觉告诉你方向,数据告诉你对不对。做判断要有指标,定目标要能量化。 |
| 03 | 隐私优先 | 产品设计里隐私保护是不可谈判的底线。不为功能方便牺牲用户数据。 |
| 04 | 系统化洞察 | 好的认知应该被提炼出来,反复使用,而不是想一次扔一次。让洞察可复用。 |
| 05 | 信任但验证 | 不盲信任何单一来源,包括 AI。多角度交叉验证建立信心,人类最终审查。 |
| 06 | 版本控制思维 | 无论代码还是想法,都该有版本,可以回滚,可以追溯。这个博物馆就是实践。 |

**§ 04 Thinking Loop (Plan → Review → Execute → Test → Iterate)**

Centered horizontal 5-node layout. Each node = circle (52×52, 1px border) + Chinese label + small annotation. Between nodes: 1px horizontal line + triangle arrow. Hover any node: circle becomes red-earth solid fill, white text.

Below, centered: "← 带数据回到 Plan" (flanked by two hairlines)

Node annotations:
- Plan · 规划:分层,拆解,定边界
- Review · 审查:验证假设,找盲区
- Execute · 执行:专注,不在途中改
- Test · 验证:跑数据,不靠感觉
- Iterate · 迭代:带数据进下一轮

Footer note (Fraunces italic): "这个闭环不只用于写代码——用于做任何值得认真对待的事。"

**§ 05 Currently Shipping (Three exhibit cards, 3 columns)**

Each card structure: top 3px wing accent color bar → exhibit number SHIP-NN → project name (Noto Serif 300, 17px) → subtitle → status (green dot + text) → tech tags → description → footer link row.

```
SHIP-01 · rencai · 人才政策助手 · 微信小程序
  Status:● 生产环境运行中
  tech:FastAPI · 微信小程序 · 腾讯云
 
   Description:给在陌生城市找落脚点的人做的工具。政府人才补贴政策繁杂难查,
        这个小程序把它变成一问一答。21 个集成测试全通过,准备提审。
  footer:即将上线 →
  Top bar color:red earth (--accent)

SHIP-02 · Drift · 情绪沉淀 · iOS
  Status:● MVP 可体验
  tech:SwiftUI · Metal · Apple Vision
 
   Description:不是日记,不是打卡——是用相机捕捉情绪的实验。Vision 框架分析
        情绪向量,驱动 Metal 动态画布。本地优先。
  footer:TestFlight 内测 →
  Top bar color:steel blue-gray (--a-tech)

SHIP-03 · Personal API · AI 身份层 · v2.0.0
  Status:● v2.0.0 · 开源运行中
  tech:Obsidian · Agent SDK · Hermes
  Description:让 AI 真正读懂你的基础设施。把 Obsidian 知识库变成 AI 可读的
        身份协议,已被 awesome-hermes-agent 社区收录。
  footer:GitHub · 开源 →
  Top bar color:moss green (--a-create)
```

**§ 06 Vision (Max width 680px, bracketed words use LXGW WenKai kaiti)**

```
[eyebrow] ● Curator's Note · 馆长自述
[h3 title] 为什么有这个博物馆

长期,我想成为一个能独立跑完「[技术 + 产品 + 运营 · kaiti]」全链路的工程师。
不只是会写代码的人——而是能把一个[想法 · kaiti]从零推到真实用户手上的那种人。

我相信 AI 应该[懂你 · kaiti],而不只是回答问题。好的人机协作不是替换,
是分工:人定义问题与验证答案,AI 负责执行和探索。

这个博物馆是一次实验——把三年里写过的代码、想清楚的事、还没想清楚的事,
按照展品的方式陈列出来。不追求完整,只要[真实 · kaiti]。
```

**§ 07 Contact (Top hairline + left-right layout)**

Left: "联系馆长 · Find the Curator" (eyebrow)
Right: GitHub · X · Email · RSS (with small icons, hover red earth)
Below, right-aligned italic: `B.Museum · Vol. 01 · Opened 2026 · Built solo, after the workday.`

5.3 /wing/:slug · Wing Landing Pages

Three wings share a template, differentiated via prop injection (curator's note, accent color, article list):

═══════ Segment A · Wing Intro Copper Plate (Two-column) ═══════

Left column:
- eyebrow: `● Wing · 01 · 工程参考室` (in wing accent color)
- Large wing name (Noto Serif 200, clamp 48-96px): `Tech / 翼` where "翼" uses wing accent color
- English subtitle (Fraunces italic): `Engineering Reference Room`
- Curator's Note block: left 2px wing accent border, label `Curator's Note`, body text explaining why this wing exists

Right column: Wing Stats card
```
展品总数    14 件
精选展品    1 件
最近更新    2026-05-09
主题标签    FastAPI · Agent · 架构
翼色        钢蓝灰 #5B7A9A
```

Wing-specific curator's notes:

```yaml
tech:
  name: Tech 翼
  subtitle: 工程参考室 · Engineering Reference Room
  accent: '#5B7A9A'
  curator_note: |
   
   写代码是容易的,知道为什么这样写才难。这个展厅记录工程决策背后的推理过程
    ——哪些路是走通的,哪些是走通了之后又推倒重来的。

think:
  name: Think 翼
  subtitle: 私人书房 · Private Study
  accent: '#C15F3C'
  curator_note: |
   
   这是想东西想到一半的房间。有些已经想清楚,有些还在路上,有些可能永远都
   
   想不清楚。展品按"想清楚的程度"陈列,不按发表时间。

create:
  name: Create 翼
  subtitle: 项目工坊 · Project Workshop
  accent: '#7A8C5F'
  curator_note: |
   
   在建的、已发布的、停工的。项目背后的决策记录,比发布公告更诚实——
    包括为什么放弃,为什么重启,为什么这个时间点把它砍掉。
```

═══════ Segment B · Featured Exhibit (Curator's Pick Large Card) ═══════

Horizontal grid `1fr 1.4fr`:
- Left cell: wing accent color solid fill, cream-text. Contains `Tech · Vol.01 · No.001` volume number + large Fraunces italic number `001` + small label `精选展品`
- Right cell: metadata row (wing + date + version) → large title (Noto Serif 300) → summary → bottom hairline + "进入展品 →" + reading time

═══════ Segment C · Recent Additions (3-column grid small cards) ═══════

Each card: metadata (wing·date) → title (Noto Serif 300, 16px) → summary (13px ink-soft) → bottom hairline + reading time + version chip

═══════ Segment D · All Exhibits (Year-grouped table list) ═══════

Grouped by year, year label sticky top, row structure: `80px date | 1fr title | 64px time | 56px version`, hover background bg-card full-width extend.

═══════ Seed Data for Three Wings (at least 6 articles each for development) ═══════

**Tech Wing**:
1. `2026-05-09 v1.0 · FastAPI 迁移实录:为什么我把 NestJS 换掉了` (8min, featured)
2. `2026-05-01 v1.1 · Agent 工程化的三个层次:记忆、规划、执行` (6min)
3. `2026-04-22 v1.0 · 版本控制不只是 Git:知识的版本化实践` (5min)
4. `2026-04-10 v1.0 · 为什么删掉了粒子背景` (4min)
5. `2026-03-28 v2.0 · Mini 程序提审前的工程 Checklist` (5min)
6. `2026-03-15 v1.0 · 腾讯云 Lighthouse 生产部署实录` (7min)

**Think Wing**:
1. `2026-05-05 v1.0 · 认知也需要版本控制` (5min, featured)
2. `2026-04-18 v1.0 · 为什么我不再追求"完整"` (4min)
3. `2026-04-02 v1.1 · 转型期的时间分配陷阱` (6min)
4. `2026-03-20 v1.0 · 创业心态 vs 工程师心态` (5min)
5. `2026-03-08 v1.0 · 信任但验证:和 AI 协作的边界` (7min)
6. `2026-02-22 v1.0 · 删掉一个项目比开始一个更难` (4min)

**Create Wing**:
1. `2026-05-03 v1.0 · Drift:用 Metal 渲染情绪` (8min, featured)
2. `2026-04-26 v1.0 · rencai 的产品决策记录` (6min)
3. `2026-04-09 v1.0 · Personal API v2 设计文档` (7min)
4. `2026-03-25 v1.0 · 为什么停掉了 GPU Compass` (5min)
5. `2026-03-10 v1.0 · ihuoxu.com 的复盘:OPC 探索为什么暂停` (6min)
6. `2026-02-28 v1.0 · 一个人独立做产品的工具链` (5min)

5.4 /article/:slug · Exhibit Detail (Independent Route)

Page structure (max-width 680px, centered):

**Top Fixed Reading Progress Bar**
2px height, red earth color, fills width based on scroll progress within article area.

**Catalog Tag (馆藏铭牌)**
1px border + bg-card background, 2-column grid:

```
馆藏号  Tech · Vol.01 · No.001 (wing accent color)        标签   FastAPI · NestJS · 架构决策
日期    2026-05-09 首发 · 2026-05-09 更新           阅读   约 8 分钟
版本    v1.0                                      
   展厅   Tech 翼 · 工程参考室
```

**Title Area**
- h1 (Noto Serif 200, clamp 32-68px, max 16ch line break)
- subtitle (Fraunces italic, gray, optional)

**Body (680px wide, line-height 1.9)**
- p: Noto Serif 400, 17px
- p.lead (first paragraph): 18px, 300, ink-soft
- h2: Noto Serif 300, 24px, top margin 52px
- blockquote: left 2px wing accent border, Fraunces italic
- code (inline): JetBrains Mono 13px + bg-card
- pre: bg-card + 1px hairline-s + JetBrains Mono 13px

**Bottom Prev/Next Navigation**
2-column grid, each card:
- Left card: `← 上一展品` + title
- Right card (right-aligned): `下一展品 →` + title
- hover: background bg-card

5.5 /index · Collection Index

- Top铭牌: `Vol. 01 Catalog · 47 entries`
- Three view switch chips: by time / by wing / by tag
- Search box: client-side fuzzy matching (no backend dependency)
- List rows: `date · wing · title · version`
- List style consistent with Wing's All Exhibits table

5.6 /guestbook · Visitor's Book

**Visual — The Only Kraft Paper Room**
```css
--bg-guestbook: #F4ECD6;       /* kraft paper */
--ink-guestbook: #3A2E1F;      /* brown ink */
```
Background overlaid with paper-texture SVG (stronger than main site grain). This room's color temperature is deliberately different from the rest of the site.

**Layout — An Open Kraft Paper Guest Book**
Left page: reading history (reverse chronological), right page: writing. Center spine line divider.

**Message History**
- Each entry: author name (LXGW WenKai) + message body (Noto Serif SC) + timestamp (Inter micro text)
- Page-turn effect (CSS page-flip animation 800ms)
- 8 entries per page

**Message Input (Right Page)**
```
姓名(max 30)   [input field]
留言(max 280) [textarea, placeholder in LXGW WenKai: "留下你今晚看到的"]
反 spam 简单题  [博物馆英文是?  → Answer: museum]
                  [Submit button · red earth underline style]
```

**Submission Flow (Critical)**

```typescript
// POST /api/guestbook
async function submit(entry: { name: string; message: string; honeypot: string }) {
  // 1. Honeypot field check (hidden honeypot input, bots will fill it)
  if (entry.honeypot) return reject('spam');

  // 2. Length limits (name ≤30, message ≤280)
  // 3. Simple question validation (answer === 'museum')

  // 4. Rule-based sensitive word filtering (bilingual word list)
  if (RULES.containsBlocked(entry.message)) return reject('blocked');

  // 5. Same-IP rate limit: max 1 entry per 60 seconds
  // 6. Write to KV, default status 'pending'
  // 7. Auto-transition to 'published' after 24 hours (Cron Edge Function)
}
```

**Sensitive Word Rule Table** (minimum viable set, no ML, all hardcoded lists):
- Chinese: politically sensitive, violence, pornography, abuse, advertising keywords
- English: profanity, spam patterns ('http', 'www.', 'click here', etc.)
- Complete word list stored in `functions/api/guestbook/blocklist.json`
- Hit = reject with friendly message "留言含违规词,未发布"

**Post-Submission State**:
- Show "已收到,馆长审核 24h 内展出" (don't expose the exact review mechanism, give users a friendly narrative)
- Auto-published after 24h via Cron, no curator admin panel needed

5.7 Permanent Component · Visitor Ticket (访客票根)

**Position**
- Grand Hall: bottom-left large size (240×100px)
- All other pages: bottom-right small size (140×60px)
- z-index 70 (below nav, above content)

**Visual (Ticket Design)**
```
┌─────────────────────────────────┐
│  B.MUSEUM            #00237     │
│  ─────────────                  │
│  Valid for tonight              │
│  Issued 21:47, May 10, 2026     │
│  ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ (perforated edge) │
│  SEAT NO. A-{visitor_id}        │
└─────────────────────────────────┘
```
- Kraft paper `#F4ECD6` + red earth stamp + monochrome print feel
- SVG perforated edges
- "Valid for tonight" is the core narrative — one-time ticket, expires when browser closes

**Data Persistence**
```typescript
// LocalStorage primary
type Visitor = {
  id: string;          // uuid
  ticketNo: number;    // site-wide incrementing (from KV)
  issuedAt: string;    // ISO timestamp
  visitedRooms: string[];   // route history
};
// EdgeOne KV backup (for site-wide ticket number increment)
key: visitor:{id}
key: counter:visitors  // atomic increment counter
```

**Behavior**
- First visit: auto-issue ticket, fetch next ticketNo from KV (using `counter:visitors` atomic increment), spring-up animation on issue (ticket pops up from bottom-right + 0.6s)
- Return visit same session: recognized as same ticket, no re-issue
- After browser close + revisit: recognized as new visit, issue new ticket ("valid for tonight")
- Click ticket: expands to full ticket card showing complete visit history (visitedRooms list + entry time)

5.8 Footer · Museum Closing Notice

Full-width `#1F1E1B` dark band, cream-text, top 1px red-earth hairline divider.

3-column layout:
- Left: `B.Museum` (Fraunces italic 22px) + tagline `Walk through the mind.` (kaiti)
- Center: "展厅导览" label + Tech/Think/Create wing links + About link
- Right: "订阅" label + RSS / Atom / GitHub / Guest Book links

Bottom separator line: `© 2026 B.Museum · Built solo  / 
   Vol. 01 · Est. 2026 · Walk through the mind.`

KEY INTERACTIONS (Behavior-Level Specifications)

6.1 Hero Entrance Animation
- nav fade-in 1.2s @ 0.1s delay
- eyebrow fade-in 0.9s @ 0.2s delay
- h1 three lines sequentially `transform: translateY(110%) → 0` cubic-bezier(.2,.7,.2,1) 1.15s, staggered 200ms (at 0.35s, 0.55s, 0.75s)
- subtitle / plate-rule fade-in @ 1.4s, 1.6s

6.2 Threshold Scroll (Door-Opening)
See §5.1 Segment B. The ONLY "complex" animation on the entire site — use it wisely.

6.3 Page Transitions
All route transitions use the same: 200ms cross-fade + 4px translateY. DO NOT re-play the Hero entrance animation on every page change.

6.4 Scroll Reveal
All non-Hero segments use `IntersectionObserver` to trigger: `opacity 0→1, translateY 18→0, 700ms ease`. Threshold `.06`, rootMargin `0 0 -32px 0`. One-time trigger then `unobserve`.

6.5 Article Reading Progress
Only active on `/article/:slug` route. Top 2px red-earth bar fills width based on scroll progress within article body range.

6.6 Ticket Pop-Up
On first visit to Grand Hall, after 2.5 seconds the ticket springs up from bottom-right: `transform: translateY(40px) → 0, opacity 0 → 1, 600ms cubic-bezier(.34,1.56,.64,1)`.

6.7 Nav Color-Temperature Inversion
Only active on Grand Hall route. Monitor Threshold scroll progress, when eased > 0.55 add `nav.classList.add('on-dark')`, otherwise remove.

DATA MODELS (TypeScript Schemas)

```typescript
// Article
type Article = {
  slug: string;
  wing: 'tech' | 'think' | 'create';
  no: number;                  // catalog number, incrementing per wing
  title: string;
  subtitle?: string;
  summary: string;             // for cards
  body: string;                // markdown
  created: string;             // ISO
  updated: string;             // ISO
  version: string;             // 'v1.0', 'v1.1'
  featured: boolean;
  tags: string[];
  cover?: string;
  reading_time_min: number;
};

// Wing
type Wing = {
  slug: 'tech' | 'think' | 'create';
  name: string;
  subtitle: string;
  curator_note: string;
  accent: string;              // hex
  featured_slug: string;
};

// Guest Entry
type GuestEntry = {
  id: string;
  name: string;                // ≤30
  message: string;             // ≤280
  created: string;
  status: 'pending' | 'published' | 'blocked';
  ip_hash: string;             // for rate limit
};

// Visitor
type Visitor = {
  id: string;
  ticket_no: number;
  issued_at: string;
  visited_rooms: string[];
  is_returning: boolean;
};
```

Data initialization:
- Articles & Wings: load from `/src/data/articles.json` and `/src/data/wings.json` statically (development phase), later can migrate to Edge Function `/api/articles`, `/api/wings/:slug`
- Guest & Visitor: read/write via Edge Function + KV

GUESTBOOK DUAL-TRACK STRATEGY

开发期(当前状态,可接受的降级方案):
- localStorage 存储;视觉与表单逻辑(honeypot / 反 spam / 长度 / 限频)已就位
- 自动发布延迟 30s 用于本地调试(生产环境应为 24h)
- 注意:当前实现含 8 条 SEED 留言用于 UI 调试,迁移到生产前必须移除(prompt 禁止 fake data)

生产期(Gap,需实现):
1. 创建 `functions/api/guestbook/index.ts`
   - GET:从 KV 读取已发布留言,按时间倒序返回
   - POST:校验 → honeypot → 长度限制(name ≤30, message ≤280)→ 反 spam 题(answer === 'museum')→ 规则过滤 → 同 IP 限频(60s)
   - 写入 KV,默认 status='pending'
2. 创建 `functions/api/guestbook/blocklist.json`
   - 中文:政治敏感 / 暴力 / 色情 / 辱骂 / 广告关键词
   - 英文:profanity / spam patterns('http', 'www.', 'click here' 等)
   - 命中 = 拒绝,友好提示 "留言含违规词,未发布"
3. 迁移前端 `Guestbook.tsx`
   - localStorage 为空时返回空数组(不注入 SEED)
   - 提交走 `fetch('/api/guestbook', { method: 'POST' })`
   - 读取走 `fetch('/api/guestbook')`
   - 移除 SEED 常量与 30s autoPublish 逻辑
4. 自动发布:Cron Edge Function 每小时扫描 pending 超过 24h 的条目 → 改为 published

VISITOR TICKET KV MIGRATION

当前(localStorage 降级):
- ticket_no 由 `Math.floor(Math.random() * 9000) + 1000` 生成(非全局递增,仅本地伪随机)
- visitor 数据完全存于浏览器 localStorage

目标(KV 集成):
1. 创建 `functions/api/visitor/issue.ts`
   - POST:使用 KV `counter:visitors` 原子递增(INCR),返回 `{ ticketNo, visitorId, issuedAt }`
2. 改写 `useVisitorTicket.ts`
   - 首次访问:POST `/api/visitor/issue` 拿到全局递增票号
   - localStorage 缓存 visitor 数据,减少重复请求;同会话回访不再重发
   - 浏览器关闭后再访问:识别为新访问,重新发票("Valid for tonight" 语义)
   - 移除 `Math.random()` 票号生成

KV Schema(最小必要集):
```
counter:visitors             → integer (atomic INCR via KV)
visitor:{id}                 → JSON Visitor
guestbook:{id}               → JSON GuestEntry
guestbook:index:published    → array,按时间倒序
guestbook:index:pending      → array,等待 24h 自动发布
guestbook:ratelimit:{ipHash} → ISO timestamp,TTL 60s
```

FILE STRUCTURE (Recommended — ✅ 已建 / ❌ 未建)

```
src/
├── pages/                  # ✅ 全部已建
│   ├── GrandHall.tsx       # ✅
│   ├── About.tsx           # ✅
│   ├── Wing.tsx            # ✅ 单组件渲染三翼,按 :slug 区分
│   ├── ArticleDetail.tsx   # ✅
│   ├── Index.tsx           # ✅
│   └── Guestbook.tsx       # ✅(数据层 localStorage 降级)
├── components/
│   ├── nav/Nav.tsx                    # ✅
│   ├── hero/                          # ❌ 空目录(功能内联在 GrandHall.tsx,建议删除)
│   ├── threshold/                     # ❌ 空目录(功能内联在 GrandHall.tsx,建议删除)
│   ├── hall-preview/                  # ❌ 空目录(功能内联在 GrandHall.tsx,建议删除)
│   ├── visitor-ticket/VisitorTicket.tsx  # ✅
│   ├── footer/Footer.tsx              # ✅
│   └── shared/                        # ❌ 空目录(建议删除)
├── data/
│   ├── articles.json       # ✅ 18 articles
│   ├── wings.json          # ✅ 3 wings
│   ├── types.ts            # ✅
│   └── about.json          # ❌ 当前数据硬编码在 About.tsx,建议抽出
├── hooks/
│   ├── useScrollProgress.ts   # ✅
│   ├── useReveal.ts           # ✅
│   └── useVisitorTicket.ts    # ✅(待 KV 迁移)
├── styles/
│   ├── tokens.css          # ✅
│   ├── fonts.css           # ✅
│   └── globals.css         # ✅
└── App.tsx                 # ✅ Routes configuration

functions/                  # ❌ 全部未建(Gap)
├── api/
│   ├── guestbook/
│   │   ├── index.ts        # ❌ GET 列表 / POST 提交
│   │   └── blocklist.json  # ❌ 敏感词规则表
│   └── visitor/
│       └── issue.ts        # ❌ POST 发票 + KV 原子递增
└── _middleware.ts          # ❌ SPA fallback

public/
├── images/                 # ✅
├── feed.xml                # ❌ RSS(构建时生成)
└── sitemap.xml             # ❌
```

PERFORMANCE BUDGET (Mandatory)

| Metric | Target |
|---|---|
| LCP (first screen) | < 1.5s |
| TTFB | < 200ms (EdgeOne CDN) |
| Main bundle gzipped | < 80KB |
| Font strategy | font-display: swap + preload Noto Serif 200, Inter 500 |
| Threshold image | WebP + 2400w + LQIP base64 placeholder (< 100 bytes) |
| Corridor article list | API data client-side fetch, does not block first screen |
| Edge Functions cache | articles.json 1 hour, wings.json 5 minutes, guestbook no cache |

NEVER: particle backgrounds, WebGL corridors, any 60fps sustained GPU task, dependency on third-party tracking scripts (if analytics needed, use EdgeOne's built-in Web Analytics).

DEPLOYMENT CHECKLIST

1. **SPA fallback(最高优先级 — 没有它,子路由刷新全部 404)**
   - 创建 `functions/_middleware.ts`,或在 EdgeOne 控制台配置 SPA fallback
   - 规则:非文件请求 + 非 `/api/*` → 返回 `index.html`

2. **vite.config.ts**
   - `build.rollupOptions.output.manualChunks`:vendor 拆分(`react`, `react-dom`, `react-router-dom`)
   - 验证 main bundle gzipped < 80KB
   - 启用 `build.sourcemap` 仅在非生产环境

3. **EdgeOne Makers 配置**
   - Functions 路由:`/api/guestbook`、`/api/visitor/issue`
   - KV namespace:`bmuseum-guestbook`(留言)、`bmuseum-visitors`(票号计数 + visitor 详情)
   - CDN 缓存:`articles.json` 1h、`wings.json` 5min、`/api/guestbook` no-cache
   - History fallback 必须开启

4. **字体加载优化**
   - 当前全部用 `@import` 加载(fonts.css),改为 `` 关键字体(Noto Serif SC 200、Inter 500)
   - 全部字体声明加 `font-display: swap`,避免阻塞首屏渲染

5. **Threshold 图片**
   - 当前用 Unsplash 远程图(`photo-1554907984-15263bfd63bd`)
   - 生产期下载 → WebP 转换 → 2400w 主图 + LQIP base64 placeholder(< 100 bytes)
   - 通过 `` 预加载主图

6. **SEO 资产(纯前端改动,不依赖 Edge Functions)**
   - 各页面组件设置 `document.title`(或引入 `react-helmet-async`)
   - `index.html` 中的 `` 作为默认 fallback
   - 各路由独立 `` 和 ``
   - `sitemap.xml`:列出 8 个基础 URL + 所有文章 URL
   - `feed.xml`:RSS 2.0 格式,每篇文章一条 entry

7. **OG Image Edge Function**
   - 按 wing slug / article slug 动态生成卡片图(1200×630)
   - 使用 EdgeOne Makers Function + Satori / 类似 SVG→PNG 路径

EXECUTION ORDER (Build in this sequence, commit after each)

⚠️ 增量构建顺序(不是从零构建):项目已有 `bmuseum/` 实现,下列步骤覆盖剩余 Gap。如果你确实要从零起步,先按 §BUILD STATUS 的「Already Working」清单复现一遍。

1. **基建闸门:SPA fallback** — 没有它,所有子路由(/about、/wing/:slug 等)刷新都会 404。先创建 `functions/_middleware.ts` 或 EdgeOne 控制台配置。
2. **抽出 about.json** — About.tsx 当前硬编码数据,迁移到 `src/data/about.json` 并在组件里 import。
3. **修代码层小 bug**(与 prompt 一致性相关):
   - 给 `useVisitorTicket` 回访路径补 `setShowTicket(true)`
   - 扩展 `mdToHtml` 支持 h1 / image / link / fenced code block / table
   - `formatVol` 改为首字母大写(`Tech` 不是 `TECH`)
   - 校正

感谢支持

如果你觉得这些作品很酷,给我们的 Github 仓库一个 Star

Star on Github