加载中…
创作者 · MotionSites
查看原始来源 ↗复刻提示词保留原文,另附运行环境、素材与验收要求;附加说明不是原作者原话。
# Plinth — "Shared Interiors":精确复刻说明
为 **Plinth** 构建一个独立完整的 HTML 页面(单文件,原生 HTML/CSS/JS,无框架,无构建步骤),这是一本以虚构建筑为内容的深色编辑风格图集。首页纵向堆叠三个区块——(1) hero,包含巨大的双行衬线标题、搜索框,以及一条**漂移的 3D 纸质“书卡”带**,从左下角巨大而模糊的卡片延伸至右侧的小卡片;(2) **书架**,排列着直立的 3D 书脊,其中一本书正面朝外;(3) **页脚**,带有巨大的排线描边字标。点击任意清晰卡片(或任意书架图书)会启动一次 **3D 飞行动画**:图书一边完整旋转一周,一边飞向中央,然后放大,直到其颜色铺满屏幕,接着淡入简洁的阅读视图。浏览器的返回操作会让它飞回原位。以下内容均为精确要求;请严格照做。
---
## 1. 素材
### 1.1 图片(所有照片均来自五张 2×2 照片拼图;不要裁剪文件——使用 CSS 裁剪)
每张拼图都是 2336×1744(4:3)的灰度建筑照片网格,无间隙;每个四分之一区域是一张照片。使用以下确切 URL:
| 拼图 | URL | TL (0) | TR (1) | BL (2) | BR (3) |
|---|---|---|---|---|---|
| 0 | https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20261108_192006_dd6f50c5-96f1-4366-a0b9-0e4a09cf5b0d.png&w=1600&q=85 | 带深拱廊的混凝土住宅 | 悬挑塔楼 | 倒影水池上的玻璃亭 | 阶梯式混凝土广场 |
| 1 | https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20261108_192017_98626c26-3f57-4237-9f43-c2098c60f4d6.png&w=1600&q=85 | 折叠混凝土立面 | 从山脊悬挑而出的住宅 | 湖畔玻璃工作室 | 带柱廊的新月形大厅 |
| 2 | https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20261108_192017_5e2e7057-6f42-43b7-b901-d9a05410bfcf.png&w=1600&q=85 | 山坡上的阶梯式石砌住宅 | 顶部带雉堞的纤细塔楼 | 从下方仰望的混凝土螺旋楼梯 | 木模板纹理挑檐下的图书馆 |
| 3 | https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20261108_192016_3cfaf615-9452-411f-82d8-efce7d4ac496.png&w=1600&q=85 | 嵌入采石场的礼拜堂 | 带方形开口的庭院 | 带圆形天窗的浴场 | 锯齿形屋顶工作室 |
| 4 | https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20261108_192005_ce70ee97-86d4-49ce-9eb5-dc2a3ca1cd00.png&w=1600&q=85 | 仅有一道狭缝窗的整体建筑 | 带竖向翼片的塔楼 | 带栅列柱廊的住宅 | 果园中的木亭 |
照片通过一个绝对定位、填满容器的 `<i>` 显示,设置 `background-image: url(sheet)`、`background-size: 200% 200%`、`background-repeat: no-repeat`,以及 `background-position` = 单元格 0 → `0% 0%`,1 → `100% 0%`,2 → `0% 100%`,3 → `100% 100%`。
### 1.2 字体
从 Google Fonts 加载(或自行托管 latin woff2 文件):https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,300..500&family=Geist:wght@300..600&family=Geist+Mono&display=swap
- `--serif`:"Newsreader", Georgia, serif——所有展示文字,字重 400,光学尺寸自动。
- `--sans`:"Geist", ui-sans-serif, system-ui, sans-serif——正文/UI。
- `--mono`:"Geist Mono", ui-monospace, monospace——书架标签和图注。
仅在 `document.fonts.ready` 完成后启动图库(需要测量 hero 文字块)。
### 1.3 颗粒
`body::before`:`position:fixed; inset:0; z-index:1000; pointer-events:none; opacity:.06; mix-blend-mode:overlay;` 背景 = 160×160 的内联 SVG data URI,使用 `feTurbulence type="fractalNoise" baseFrequency=".9" numOctaves="2" stitchTiles="stitch"` 填满矩形。
---
## 2. 设计变量、文档头与主题
- `<title>` "Plinth — Shared Interiors"、`<html lang="en" data-theme="dark">`、viewport meta。
- 深色(默认):`--bg #111111`、`--fg #ededed`、`color-scheme: dark`。浅色(`[data-theme=light]`):`--bg #ffffff`、`--fg #0a0a0a`、`color-scheme: light`。
- 派生变量:`--fg-muted = color-mix(in srgb, fg 64%, bg)`、`--fg-subtle = 50%`、`--border = 12%`、`--border-strong = 22%`、`--bg-muted = 8%`。卡片墨色 `--ink #171614`。
- `--scene-h: clamp(640px, calc(80svh - 48px), 900px)`(宽度小于 640px 时为 660px)。
- `body`:Geist,抗锯齿,`overflow-x:hidden`,背景/颜色过渡 .3s。`.wrap`:max-width 1180px,居中,内边距 0 24px(内容列 = 1132px)。
- 卡片配色(9 种粉彩色,按图书索引 mod 9 依次使用):#f0b0ae、#edbb99、#e8d194、#d1da9a、#a9d1b0、#a4ced0、#adc3e4、#c1b6df、#ddb0cc。
- 书架图书材质——深色:书本颜色 #161618,墨色 #050506,墨色渐变 `linear-gradient(125deg,#050506 5%,#29292c 24%,#77777c 33%,#202023 42%,#080809 58%,#505055 78%,#0b0b0d 94%)`,墨色阴影 `0 -.5px 0 #ffffff26, 0 .5px 0 #000000b3`,材质线条 #ffffff14,图片滤镜 `grayscale(1) brightness(.32) contrast(1.15)`,混合模式 `screen`,书页条纹 #222225/#0e0e10/#19191b,接触阴影 #000000a6,投影 #00000047。浅色:书本 #ededea,墨色 #fff,渐变 `linear-gradient(125deg,#fff 5%,#dedee2 24%,#fff 33%,#e9e9ec 42%,#fff 58%,#d0d0d5 78%,#fff 94%)`,墨色阴影 `0 -.5px 0 #fffffff2, 0 .5px 0 #00000038`,线条 #00000012,图片滤镜 `grayscale(1) invert(1) brightness(.32) contrast(1.15) invert(1)`,混合模式 `multiply`,条纹 #f8f8f6/#d9d9d6/#e7e7e4,接触阴影 #1112163d,投影 #1112161a。
---
## 3. 内容
### 3.1 Hero 图书(20 本;按顺序编号 Nº 01–20;颜色 = palette[i mod 9])
| # | 标题 | 引题 | 阅读 | 拼图/单元格 | 简介 |
|---|---|---|---|---|---|
| 01 | Arches House | 档案 | ~2 分钟导览 | 0/0 | 一座低矮的混凝土住宅,正面五道深拱让房间在漫长的夏日午后保持阴凉。 |
| 02 | Cantilever Tower | 档案 | ~3 | 0/1 | 一座上层楼面向外扩展的住宅塔楼,由狭窄竖向主体上方倾斜的混凝土托架支撑。 |
| 03 | Glass Pavilion | 笔记 | ~2 | 0/2 | 薄钢屋顶下的一间玻璃房,坐落在平静的倒影水池边缘。 |
| 04 | Steps Plaza | 深入探访 | ~3 | 0/3 | 一处嵌入坡地的市民广场,由宽阔而低缓的连续台地构成,也可供人坐憩。 |
| 05 | The Fold | 档案 | ~1 | 1/0 | 一座被倾斜混凝土平面包裹的美术馆,开合之间仿佛一张折过的纸。 |
| 06 | Ridge House | 档案 | ~2 | 1/1 | 一个从岩石平台悬挑而出的木与玻璃盒子,一扇长窗将整个山谷框入其中。 |
| 07 | Lakeside Studio | 笔记 | ~2 | 1/2 | 一间建在石砌基座上的画室,玻璃墙朝北,面向开阔水面。 |
| 08 | Crescent Hall | 深入探访 | ~4 | 1/3 | 一座由一圈凹槽柱支撑的弧形集会厅,屋顶朝开放的一侧抬升。 |
| 09 | Stone Terrace | 档案 | ~3 | 2/0 | 沿山坡逐级而下的住宅,每一层平屋顶都是上方住户的花园。 |
| 10 | Slender Tower | 笔记 | ~1 | 2/1 | 一座顶部带雉堞的狭长公寓塔楼,建在一块宽度仅相当于联排住宅的地块上。 |
| 11 | Spiral Stair | 深入探访 | ~2 | 2/2 | 一座独立的混凝土楼梯,在三层通高的中庭中盘旋,没有中央支柱。 |
| 12 | Board Library | 档案 | ~3 | 2/3 | 一间位于深挑檐下的阅览室,挑檐保留木模板纹理,四面玻璃引入均匀日光。 |
| 13 | Quarry Chapel | 笔记 | ~2 | 3/0 | 一座凿入废弃采石场岩壁的小礼拜堂,仅由岩石上的一道切口采光。 |
| 14 | Courtyard Block | 档案 | ~3 | 3/1 | 一所围绕绿植庭院布局的学校,立面由深邃方形开口组成网格。 |
| 15 | Skylight Baths | 深入探访 | ~3 | 3/2 | 厚重屋顶下的公共浴场,圆形天窗让光斑在水面上移动。 |
| 16 | North Atelier | 档案 | ~2 | 3/3 | 锯齿形屋顶下的工坊,朝北的玻璃整日提供没有阴影的光线。 |
| 17 | Monolith | 笔记 | ~1 | 4/0 | 一个无窗体块,仅由一道通高狭缝切开,黄昏时化作一道光刃。 |
| 18 | Fin Tower | 档案 | ~3 | 4/1 | 一座包覆竖向混凝土翼片的办公塔楼,为玻璃遮挡低角度的西晒。 |
| 19 | Palisade House | 档案 | ~2 | 4/2 | 一座修长的单层住宅,花园边缘排列的纤细柱列形成屏障。 |
| 20 | Orchard Pavilion | 深入探访 | ~2 | 4/3 | 一座坐落在老果树间的木亭,外露椽木承托着平缓的双坡屋顶。 |
阅读标签格式:"~N 分钟导览"。Slug:小写,非字母数字字符 → "-"。
### 3.2 书架图书(15 本;Nº 21–35;引题循环使用档案 / 笔记 / 深入探访;分钟数 = 1 + (i·7 mod 4);高度循环使用 310、326、300、318 px)
Marrow House (0/0)、Cistern Hall (1/3)、Granary Loft (2/0)、Weir Station (3/2)、Kiln Studio (4/0)、Saltern Court (0/3)、Lantern Tower (4/1)、Basalt Rooms (2/3)、Tannery Lofts (3/1)、Ferry Terminal (1/2)、Belvedere (0/1)、Sluice House (3/3)、Aqueduct Rooms (1/0)、Signal Box (2/1)、Concrete Almanac(0/2,加载时展开的那一本)。每本简介:"<Title> 是图集中较为静谧的一篇:一座实用建筑,在这里,它的平面、光线与材料得到如同纪念性建筑般细致的解读。"
卡片背面使用的标语:"经久建筑的田野指南"。
---
## 4. 导航栏(首页和文章页)
粘性定位,top 0,z-index 50,背景 = 页面背景。内部 `.wrap` 高 48px,flex,space-between。
- 标志(链接,aria-label "Plinth 首页"):Newsreader 22px/1,letter-spacing -.01em,gap 8px;文字前的环形符号 = inline-block 14×16 椭圆,边框 2.1px currentColor(左侧 1.6px,右侧 2.6px),radius 50%,translateY(1px)。文字 "Plinth"。
- 主题胶囊(右侧,仅首页):flex,内边距 2px,1px `--border-strong` 边框,radius 999px,Geist 12px。两个按钮 "Paper"(data-t light)和 "Noir"(data-t dark),各有 7px 12px 内边距,radius 999,颜色 fg-muted;选中按钮的颜色 = bg。一个滑动 `<i>` 指示器(absolute,top/bottom 2px,radius 999,背景 fg),通过将 `left`/`width` 设置为按钮的 offsetLeft/offsetWidth 移到选中按钮下方,left/width 过渡 .35s cubic-bezier(.23,1,.32,1)。在 localStorage "plinth-theme" 中保存选择(用 try/catch 包裹)。
---
## 5. Hero 区块
`.hero`:relative,全宽,`min-height: calc(var(--scene-h) + 160px)`,`overflow-x: clip`(y 可见),isolation isolate。
### 5.1 标题块 `#heroContent`
Absolute,z-index 2,`top: clamp(48px, 8svh, 96px)`,`left: 50%`,`translateX(-50%)`,宽度 `calc(100% - 48px)`,max-width 450px,左对齐,`container-type: inline-size`。
- H1,两个不换行的块级 span:"共享" / "室内空间"。Newsreader 400,`font-size: 26.2743cqi`(450px 时约 118px),line-height .96,letter-spacing -.025em。
- 段落:"一本静静记录我们所爱建筑的图集。" margin-top 24px,`clamp(15px, 1.2vw, 17px)`/1.5,颜色 fg-muted。
- 搜索(margin-top 24px):一个表单(role search)= flex 横排,gap 12px,min-height 48px。
- 输入框:左侧 14px 放大镜 SVG(circle r 4.75 + 手柄,stroke 1.5,fg-muted,垂直居中);input type search,min-height 48px,除底部 1px `--border-strong` 外无边框(聚焦时为 fg-muted),透明,16px/1.5,padding 12px 0 12px 26px,placeholder " "。
- 轮换占位文字:absolute `inset: 0 0 1px 26px`,flex 居中,fg-muted 16px,nowrap,输入框聚焦或非空时隐藏。内部使用带 `perspective: 320px` 的 inline-grid;所有名称共用 grid-area 1/1,`transform-origin: 50% 50% -.6em`,背面隐藏。列表 = 全部 35 个标题,随机打乱一次(Fisher–Yates)。每 2400 ms 步数递增:前一个名称使用动画 **nameOut**(.62s cubic-bezier(.22,1,.36,1) both:从 opacity 1 → opacity 0、blur 2px、translateY(-.9em) rotateX(80deg)),新名称使用 **nameIn**(从 opacity 0、blur 2px、translateY(.9em) rotateX(-80deg) → none)。第一个名称直接显示,无动画。
- 提交按钮:40×40 圆形,flex 0 0 40px,align-self flex-end,margin-bottom 4px,1px `--border-strong` 边框,背景为页面背景,折角箭头路径 "m6 3.5 4.5 4.5L6 12.5",stroke 1.5,圆角。Hover:边框 fg-muted,背景 `--bg-muted`;active scale(.94);过渡 .16s。
- 输入时筛选卡片带(见 6.8)。提交时打开第一个标题与查询完全相同的条目,否则打开第一个包含查询的条目(直接进入阅读视图,无飞行动画)。
### 5.2 图库舞台 `#gallery`
Absolute,left/right 0,top 0,高度 `--scene-h`,z-index 0,`pointer-events:none`(清晰卡片重新启用)。内部 `.layer`(absolute inset 0,overflow visible)容纳卡片;启动时播放 **galleryEnter**(opacity 0 → 1,.6s cubic-bezier(.23,1,.32,1))。一条视觉隐藏的提示:"最新条目。· 缓慢移动 · 向下滚动页面,随意探索"。
---
## 6. 漂移卡片带——精确数学规则
符号:`u` = 舞台宽度,`d` = 舞台高度(scene-h),`A` = 卡片宽度 230(640px 以下为 200),`L` = 卡片高度 310(640px 以下为 280),卡片厚度基准 `BT` = 26,`N` =(筛选后的)图书数量,`ss(x)` = 带 clamp 的 smoothstep(`x=clamp(x,0,1); x²(3−2x)`),pitch 常量 `PITCH = −0.065` rad。`cb` = 标题块相对于舞台的矩形(left、right、搜索行的 bottom)。
### 6.1 卡片立体模型(卡片带、书架图书和飞行动画共用)
一个 `.vol`(absolute,尺寸 `--w`×`--h`,`transform-style: preserve-3d`,原点居中),包含六个面,每个面均为 absolute、`--w`×`--h`、背面隐藏、背景 `--c`、overflow hidden:
- 正面 `translateZ(t/2)`;背面 `rotateY(180deg) translateZ(t/2)`;
- 书脊(左侧边)宽度 `t`,left `50% − t/2`,`rotateY(-90deg) translateZ(w/2)`;书页(右侧边)相同,但使用 `rotateY(90deg)`;
- 顶面高度 `t`,top `50% − t/2`,`rotateX(90deg) translateZ(h/2)`;底面相同,但使用 `rotateX(-90deg)`。
每个正面/背面/书脊还包含一个 `.paper` 覆盖层(absolute inset 0,z 5,background `var(--paper, var(--c))`,`opacity: calc(1 − var(--co,1))`),用于在飞行动画中淡出内容。
**卡片带各面**(`--w 230px --h 310px --t 26px`,墨色 #171614):
- 书脊 = `color-mix(in srgb, --c 78%, #000)`。书页/顶面/底面 = 纸边条纹 `repeating-linear-gradient(#f8f4ea 0 1px, #ded7c8 1px 2px, #eee8db 2px 3px)`(书页为 90deg,顶面/底面为 0deg),边缘为 2px 的 `--c` 色带;底面 brightness .82,书页 .9。
- 正面(flex 纵列):页眉高 35.5px,padding 12px 16px 0,Geist 9px:左侧 "Plinth",右侧 "Nº 07"。照片区域 flex 1(`<i>` 使用滤镜 `grayscale(1) contrast(1.08)`,以 `mix-blend-mode: multiply` 叠加在卡片颜色上)。文字块 padding 12px 16px 10px:引题 Geist 9px(margin-bottom 10.5px);标题 Newsreader 25px/1.04,letter-spacing −.01em,最多 2 行;底部行 margin-top 14px,padding-top 8px,顶部 1px 分隔线 rgba(23,22,20,.2),Geist 9px:左侧 "~2 分钟导览",右侧 "打开 ↗"。
- 背面:页眉高 57.5px(相同标签);标题 Newsreader 27px/1.08,padding 0 20px,最多 3 行;简介 Geist 12px / 18.6px,padding 12px 20px 0,最多 6 行;页脚位于底部(padding 0 20px 20px,Geist 9px/13.5px):阅读时长、"探访于 2026 年 10 月 12 日",然后是标语(margin-top 12px,max-width 150px)。
- 正面和背面的装订条纹:左边缘 7px 条带 = `linear-gradient(90deg, rgba(23,22,20,.15) 0 2.5px, rgba(23,22,20,.07) 2.5px 5px, transparent 5px 6px, rgba(23,22,20,.1) 6px 7px)`。
### 6.2 每张卡片的投影
每张卡片都有中心 `(x, y)`、缩放 `s`、yaw、pitch、rotation、blur。DOM:外层 `<a class="gcard">`(absolute,位于 0,0,尺寸 A×L),设置 `transform: translate3d(x − A/2, y − L/2, 0) rotate(rotation)`,当 b > .05 时设置 `filter: blur(b px)`;内部 `.vol` 设置 `transform: perspective(P px) rotateX(pitch) rotateY(yaw) scale3d(s,s,s)`,其中 `P = max(900, A·s, L·s)`。(将 blur 留在 2D 外层,将 3D 留在内层,可避免被压平。)绘制顺序 = 按 depth 升序排序,再按 slot 排序;z-index = 排名。
边界框使用相同投影:将局部点按 yaw 旋转(`x' = x cosθ + z sinθ`,`z' = −x sinθ + z cosθ`),再按 pitch 旋转(`y'' = y cosφ − z' sinφ`,`z'' = y sinφ + z' cosφ`),`w = max(.1, 1 − z''/P)`,屏幕坐标 = 中心 + rotate(rotation)·(x'/w, y''/w)。
### 6.3 沿卡片带的位置(桌面端,`u ≥ 640`)
对于从左向右的屏幕 x 坐标为 `S` 的卡片:
- `r = ss(S/u)`;`a = clamp(d/1050, .85, 1.2)`;**缩放** `= (0.34 + (2.4 − 0.34)·(1 − r)³)·a`;**抬升** `= −0.8·d·(r − 0.4)²`;**排序值** `= (1 − r)·100 + 1`。
- **Yaw** `= 0.35 − ss(S/u)·0.24`。Pitch −0.065。Rotation 0。
- **景深模糊**:`n = clamp(S/u,0,1)`;`lft = 1 − ss(n/.38)`;`rgt = 1 − ss((1 − n)/.035)`;若 lft > rgt,则 side 为 left,否则若 rgt > 0,则为 right;`v` = 对应侧的值;blur = `round(v·(left ? 60 : 3)·10)/10`,上限 60。只有 blur 恰好为 0 的卡片可点击("hot",cursor pointer,可通过 Tab 聚焦)。
- 卡片尺寸 `A·scale × L·scale`,厚度 `26·scale`。排序用 depth = order + 0.7 + 0.25·(bookIndex mod 3)。
### 6.4 间距、边距和基线(调整尺寸时重新计算)
- 边距:取 `l = 2.88`、`o = 0.408`、`e(w,h,θ) = |cosθ|·w + |sinθ|·h`:`left = max(520, e(A·l/2+193, 1.4·A·l/2+193, 5.4°), bboxRight(card A·l × 1.4A·l, thickness 26·l, yaw .35, pad 193))`,`right = max(96, e(A·o/2+13.25, 1.4·A·o/2+13.25, 14.2°), −bboxLeft(card A·o, yaw .11, pad 13.25))`。(1440px 时约为 left 584、right 96。)
- **间距** `T = max(A − 135, ceil((u + left + right)/22))`(1440 时约 97px)。
- **基线** `R`:从 `p = −3A` 到 `u + 3A` 遍历 128 步。对于每一对(上一步 `dp`,当前步 `p`),其缩放状态为 `f = along(dp)`、`g = along(p)`:如果任一项 blur 为零,或两者跨越 `u/2`,则纳入计算。令 `lx = A·f.scale/2 + 13`、`oy = L·f.scale/2 + 13`、`st = 26·f.scale/2`、`r = yaw(p)`、`a = yaw(dp)`;`cx = lx cos r + st sin a`;`hz = lx sin a + st cos r`;`k = 1/max(.1, 1 − (oy·0.0649542 + 0.9978882·hz)/900)`;投影半尺寸为 `(cx·k, (0.9978882·oy + hz·0.0649542)·k)`。如果 `p + x ≥ cb.left − 10` 且 `dp − x ≤ cb.right + 10`,则 `R = max(R, cb.bottom + 24 + y − min(f.rise, g.rise))`。最后 `R += 24`。这样会尽可能抬高卡片带,同时让每张清晰卡片与搜索行保持 24px 间距。
### 6.5 每一帧存在哪些卡片
`B = mod(phase, N·T)`。第一个槽位 `C = ceil((B − A/2 − left)/T)`,最后一个 `J = floor((B − A/2 + u + right)/T)`,从 C 开始最多 24 个槽位。槽位 `n` 显示图书 `mod(n, N)`,位置为 `S = n·T + A/2 − B`、`y = R + rise(S)`。按槽位作为键复用 DOM 节点(仅当槽位中的图书发生变化时重建);移除已离开的槽位节点。
### 6.6 运动:漂移、滚动、滚轮、拖动
- **phase = drift + wheel + drag + 0.8 · window.scrollY.** 因此,滚动页面会让卡片带以滚动距离的 0.8× 向左滑动,同时 hero 向上滚出。
- **漂移**:每帧 `drift += T · dt / 10`(每 10 s 移动一个卡片间距),`dt = min(.05, frame delta s)`。飞行动画运行时、标签页隐藏时或启用 reduced motion 时暂停。仅在 hero 距视口 200px 范围内运行循环工作(IntersectionObserver)。
- 舞台上的**横向滚轮 / shift+wheel**(`preventDefault`):将增量加入待处理池(行模式 ×16,页模式 ×宽度);每帧将平滑后的部分计入 `wheel`:`a = −expm1(−12·dt)`,`pending' = pending·(1 − a)`(低于 .01 时归零),`wheel += pending − pending'`。
- **拖动**:在卡片上 pointerdown 时记录起点;移动 ≥ 6px 后锁定轴向。横向时:实时 `drag = −(x − startX)`;释放后将 `drag` 合入 `drift`。拖动后禁止触发点击。
### 6.7 手机卡组(`u < 640`)
卡片围绕中央扇形展开,替代卡片带。`g = mod(phase, N·T)/T`,`v = floor(g)`,`q(e) = e³(e(6e − 15) + 10)`,`b = v + q(q(g − v))`(因此每一步通过双重 smootherstep 吸附)。`y0 = min(1.15, .46u/A)`;中心线 `E = cb.bottom + 24 + L·y0/2 + 24`。对于 b 周围 ±3 范围内的每个槽位 e:`t = e − b`、`n = |t|`、`o = sign(t)`;在 n 处按表插值(整数 0–3 之间线性插值):X [0,.118,.22,.2]、Y [0,.045,.105,.11]、ROT° [0,6,7,7]、SCALE [1,.92,.86,.78]、YAW [0,.07,.12,.12]。卡片:x = u/2 + o·X·u,y = E + Y·u,scale = y0·SCALE,yaw = −o·YAW,rotation = o·ROT°,仅当 n < .5 时可点击,depth = −n。这里 `T` 为 `max(A − 135, ceil((u + left + right)/22))`,left/right 使用 l = 1.7、o = .45 计算。
### 6.8 搜索筛选
输入时:180 ms 防抖 → 舞台设置 `data-filter=out`(图层 opacity 0、translateY(14px) scale(.985),.16s)→ 160 ms 后替换图书列表(标题+简介包含查询,不区分大小写),清空所有卡片 → `data-filter=in`(**filterIn** .52s cubic-bezier(.22,1,.36,1):从 opacity 0、translateY(18px) scale(.985) 开始)→ 520 ms 后移除。无匹配时:在高度 62% 处居中显示文字 "没有与“query”匹配的条目。",fg-muted 15px。
---
## 7. 图书飞行动画(打开)
时间线:**0–600 ms "居中"**、**600–1060 ms "放大"**,然后切换至阅读视图,进行 **220 ms 显现**。
点击清晰卡片时:隐藏该槽位的卡片(飞行期间保持隐藏),暂停漂移,`history.pushState` 至 `#/b/<slug>`。创建固定覆盖层(inset 0,z-index 2147483000,role dialog,获得焦点,阻止 wheel/touchmove;Escape 取消,Tab 焦点被限制在内部)。内部放置 `.flight` div(absolute,`preserve-3d`,原点居中,`left: −n/2`、`top: −o/2`、尺寸 n×o),其中包含该书新建的 `.vol`。变量:模型尺寸 `n×o×a` = 230×310×26;起始框 = 卡片未旋转的屏幕框(中心,`width = A·s`、`height = L·s`);姿态 = 卡片的 yaw/pitch/rotation,厚度 `26·s`;光学参数:perspective `Pp = max(900, A·s, L·s)`,camera/pivot/translate 偏移均为 0。在 t=0 首次绘制后,测量飞行对象正面矩形与源卡片正面矩形的差异,并据此平移起点,确保无缝衔接。
对于时间 t(ms,限制在 0–1060):
- `f = ss(min(1, t/600))`,`h = ss(max(0, (t − 600)/460))`。
- `p = origin.width/n`,`m = origin.height/o`,`g = min(.46·vw/origin.width, .58·vh/origin.height, 340/origin.width)`(卡片最大约增至 340px 宽)。
- `x = lerp(originCentreX, vw/2, f)`,`y = lerp(originCentreY, vh/2, f)`。
- `yaw = lerp(yaw0, K, f)`,其中 `K = (floor(yaw0/2π) + 1)·2π` → **完整旋转一周**后正面朝前。`pitch → 0`、`rotation → 0`,均按 f 插值。
- `scaleX = p·lerp(1, g, f)`,`scaleY = m·lerp(1, g, f)`,`scaleZ = thickness/a`。
- `w = 1.08·max((vw + 8)/(n·p·g), (vh + 8)/(o·m·g))`;`zTarget = Pp − thickness/2 − Pp/w`;`z = lerp(tz·(1 − f), zTarget, h)` → 卡片增大,直到覆盖视口的 ×1.08。
- 内容淡出:覆盖层 `--co = 1 − f`(每个面的 `.paper` 覆盖层逐渐显现为书本颜色,因此最后正面成为纯粹的卡片色块)。
- `.flight` 的变换:`translate3d(x, y, 0) rotateZ(rotation) translate(camX·σ, camY·σ) perspective(Pp) translate(−camX·σ, −camY·σ) translate3d(tx·σ, ty·σ, z) translate(pivX·σ, pivY·σ) rotateX(pitch) rotateY(yaw) scale3d(scaleX, scaleY, scaleZ) translate(−pivX·σ, −pivY·σ)`,其中初始影响系数 `σ = 1 − f`。
在 t ≥ 1060 时:在下方显示阅读视图(页面背景变为卡片颜色,滚动到顶部),等待两个动画帧,为覆盖层添加 `.revealing`(在 220 ms cubic-bezier(.23,1,.32,1) 内过渡至 opacity 0 和 `scale(1.02)`),然后移除覆盖层。
**书架图书**使用相同飞行动画,参数如下:模型 = 该书的立体模型(n = 210,o = 其高度,a = 38);姿态从模型的 computed matrix 读取(`yaw = atan2(−m13/sx, m33/sz)`、`pitch = asin(m23/sy)`、`rotation = atan2(−m21/sy, m22/sy)`);起点由其边界框中心和未投影尺寸确定;光学参数:perspective 1200,camera offset = perspective-origin(50% 100%)减去模型中心,pivot = transform-origin(50% 100%)减去中心,translate = m41/m42/m43;书本展开时源面为封面,否则为书脊。纸张颜色 = 页面背景(阅读视图保持页面颜色)。
**Reduced motion**:直接跳到 t = 1060,不进行显现过渡。
## 8. 返回飞行动画(返回)
从阅读视图触发 `popstate` 时(或点击调用 `history.back()` 的 "← 所有建筑" 链接):以最终放大状态(t = 1060)创建覆盖层,opacity 0,并在 200 ms linear 内淡入至 1("重新浮现")。然后显示首页,恢复打开时保存的滚动位置,并重新对准:对于卡片带,调整 `drift`,让该书的一个槽位落在打开时相同的 x 位置(以舞台宽度比例表示,限制在距边缘 24px 以内;选择最接近当前 phase 的槽位);对于书架图书,使用该书当前的 rect。然后以状态 `flight(1060 − r)` 执行 r = 0 → 1060 ms 动画(缩小 460 ms,然后旋转返回 600 ms),移除覆盖层,取消隐藏卡片,恢复漂移。关闭原生滚动恢复(`history.scrollRestoration = "manual"`)。
---
## 9. 阅读视图(简洁)
替换首页视图(隐藏首页,滚动至顶部)。背景 `--abg` = 卡片颜色(书架图书为页面背景);彩色页面文字使用 `#171614`,否则使用 fg。文档标题 "<Title> — Plinth"。
- 导航:标志(充当返回按钮)和 "← 所有建筑"(Geist 13px,hover 时 opacity .7 → 1)。
- 标题区(padding-top 72px):H1 Newsreader `clamp(48px, 6.4vw, 84px)/1`,letter-spacing −.025em;下方放置含引题的胶囊标签(margin-top 22px,7px 14px,radius 999,1px 边框 currentColor 30%,14px)。
- 网格(顶部 padding 40px,底部 120px;列为 152px | 1fr | 264px,gap 32px;820px 以下为单列,隐藏目录列):
- 目录:小标签 "章节"(11px,opacity .6)及链接 "概述"(active:左侧 2px 边框、7% 色调)、"平面与光线"、"材料"。
- 正文:H2 "概述",Newsreader 32px/1.15;第 1 段 = 简介;第 2 段 = "与本图集的每个条目一样,<Title> 是一座虚构建筑,描述方式如同田野指南介绍一个标本:它由什么建成,光线如何进入房间,以及它如何坐落于场地之上。右侧图片是为本页制作的研究照片。"(Geist 18px/1.65,max 640px)。
- 侧栏:一张 4:3 图版,显示该书照片(以 multiply 叠加在卡片颜色上;书架/纯色页面使用 normal 混合、灰度);1px 分隔线上方为 Geist Mono 11px 图注 "图 01 · 研究照片 · Nº 07";然后在一条 1px 分隔线上方(margin-top 28px,padding-top 22px),显示 "速览"(Newsreader 26px/1.1)及 "<reading time> · 探访于 2026 年 10 月 12 日"(Geist 14px/1.5,opacity .85)。
- 页面加载时若带有 `#/b/<slug>` hash,直接打开对应阅读视图。
---
## 10. 书架区块
`section.shelfsec`(aria-label "推荐阅读书架"):relative,z-index 10,页面背景(用于遮住 hero 的溢出部分),margin-top 32px,padding-top 24px。一个横向滚动容器(overflow-x auto,细滚动条)容纳 `ul.shelf`:flex,居中,`align-items: flex-end`,gap 4px,`width: max-content; min-width: 100%`,padding 64px 32px 24px。640px 以下,列表设置 `zoom: .6`,padding 40px 40px。
每个 `li.slot`(`--t 38px`、`--w 210px`、`--h` = 书本高度):宽度 `--t`,高度 `--h`,width 过渡 .8s cubic-bezier(.22,.8,.25,1)。展开槽位(`data-open="true"`,z 2):宽度 `calc(210px + 38px·.65)`。
内部 `a.sbook`(填满尺寸,`perspective: 1200px`、`perspective-origin: 50% 100%`)包含立体模型(`left: calc(50% − 105px)`,高度 100%,`transform-origin: 50% 100%`,transform 过渡 .8s,使用相同曲线):
- 合拢:`translateZ(−105px) rotateY(90deg)`(书脊朝向你);
- 展开:`translateZ(24px) rotateY(−4deg)`(封面朝向你)。
阴影:`::before` 投影(以 42% 20% 为中心、使用投影颜色的径向椭圆,高 12px,宽 t+14,bottom −6px);展开时:宽 224px,高 18px,bottom −14px,opacity .75,`translate(−50%) translate(8px) skew(−10deg)`。`::after` 为书下方 3px 高的接触阴影(宽度 t → 展开时 210)。
各面(材质见第 2 节;所有面均有 1px 材质线边框和淡纹理 `repeating-linear-gradient(0deg,#ffffff02 0 1px,#0000 1px 3px), linear-gradient(115deg,#ffffff05,#0000 45%,#0000001a)`):
- 书脊:纵列,居中,gap 18px,padding 16px 3px 12px,内阴影 `1px 0 #ffffff0d` 和 `−3px 0 5px #00000038`,距右边缘 5px 处有 1px 线;编号 Geist Mono 9px;标题 Newsreader 18px,`writing-mode: vertical-rl`,旋转 180°(从下向上阅读),nowrap,ellipsis。
- 封面:纵列;页眉 Geist Mono 9px("Plinth" / "Nº 35",padding 12px 16px 10px);照片区域 flex 1(图片滤镜/混合模式来自主题);文字 padding 12px 16px 14px:引题 Geist Mono 9px,标题 Newsreader 25px/1.04(−.02em,最多 3 行),页脚分隔线 + "~N 分钟导览" / "打开 ↗"。左边缘有一条 7px 深色装订条。所有封面/书脊文字均使用金属墨色:渐变裁切到文字,宽度 160%,再加墨色阴影。
- 书页/顶面/底面:使用主题的三种书页色调制作书页条纹渐变,边缘为 3px 书本颜色。
- **Hover**:pointermove 移到另一本书上时(仅鼠标、支持 hover 的设备,忽略重复的相同坐标),在 **100 ms** 后将 `data-open` 移到该书。聚焦时立即执行。
- **光泽**:指针位于展开的封面上时,一个径向高光(`circle at pointer`:白色 .16 → 28% 处 .04 → 55% 处透明,screen 混合;浅色主题为白色 .7/.2)淡入(.25s)并跟随指针。
- 点击任意图书 → 书架飞行动画(第 7 节)。
## 11. 页脚
`footer.foot`:relative,z 10,页面背景,顶部 1px `--border` 边框,overflow hidden。横排(`.wrap`,padding 20px):左侧 "使用 ◆ Studio 构建",右侧 "2026",Geist 12px fg-muted。下方为 SVG 字标,宽度 `calc(100% − 48px)`(max 1360px),margin 24px auto 0,颜色 fg-subtle,viewBox 0 0 1000 250(顶部对齐),使用旋转 45° 的线条图案(7×7 图块,1.1px 线条,currentColor)。文字 "Plinth",Newsreader 400px,x 500 居中锚定,y 318(由 viewBox 底部裁切),letter-spacing −8,fill = 排线图案,stroke currentColor 1.2px。
## 12. 验收清单
- 在 1440×900、深色主题下:标题两行为 "共享" 和 "室内空间",字号约 118px;卡片带从左下角巨大、60px 模糊的卡片向上弯曲,延伸至右边缘的小卡片,清晰卡片与搜索行保持 24px 间距。
- 卡片每 10 s 向左漂移一个间距;向下滚动时,以滚动距离的 0.8× 进一步左移;shift-wheel 和拖动也能控制其位置。
- 点击清晰卡片:600 ms 飞向中央并完整旋转一周,460 ms 放大至卡片颜色铺满屏幕,220 ms 淡入阅读视图;返回时反向播放,卡片落回原位。
- 书架:hover 书脊 → 100 ms 后开始,在 .8s 内转出至正面朝前;点击时以相同方式飞出打开。
- 占位名称每 2.4 s 翻转一次;输入时通过淡出/淡入筛选卡片带。
- Paper/Noir 切换主题;手机宽度显示扇形卡组,无横向滚动;reduced motion 冻结漂移并跳过飞行动画。适用模型与稳定度
建议模型
继续探索

3D 创作者 Jack 的作品集落地页,React + TypeScript + Framer Motion,#0C0C0C 暗底。
提示语
使用 React、TypeScript、Tailwind CSS、Framer Motion 和 Lucide React,为「Jack」构建一个 3D 创作者作品集落地页。页面采用深色主题(背景为 #0C0C0C),字体使用 Kanit(Google Fonts,字重 300-900)。页面标题为「Jack -- 3D Creator」。 全局样式 html、body、#root 和主容器的背景:#0C0C0C 字体族:'Kanit', sans-serif 全局重置:b

提示语
为一家名为“NEXOVA”的托管公司构建一个全屏 404 错误页面。整个页面采用单视口高度布局,包含循环播放的背景视频、导航栏、居中的 hero/404 区域和多栏页脚。使用 React + Tailwind CSS + Lucide React icons。不要使用其他 UI 库。 --- **字体** 在 `index.html` 中通过以下样式表加载“Helvetica Now Var”: ``` <link href="https://db.onlinewebf

ADHD 友好的日程应用 Drift 落地站,React + Vite + TypeScript + Tailwind,安静低刺激的视觉方向本身就是产品卖点。
提示语
为 "Drift" 构建一个单页落地网站——这是一款平静、对 ADHD 友好的规划应用。使用 React + Vite + TypeScript + Tailwind CSS + lucide-react 提供图标。不要使用其他 UI 库。 ### 字体 通过 Google Fonts 在 `index.css` 中导入: - **Inter**(字重 400、500、600)——用作基础正文字体 - **Instrument Serif**(仅斜体)——用于首屏标题中的
Case 详情页把原帖效果、Prompt 与复测证据放在同一条阅读路径里。