Skip to content

Repository files navigation

agent-elysium

网页端的交互式动态立体绘本 Demo。画面是纸艺立体书,人物与系统沿用《极乐迪斯科》:警探哈里尔·杜博阿与搭档金·曷城在瑞瓦肖马丁内斯区勘察一间密室书房;固定选项的对话树、能力检定、掷骰子、内心声音,中英双语(中文名称采用官方简体中文版译名)。

文档

运行

需要 Node 20 以上。

npm install
npm run dev      # 开发服务器
npm run build    # 类型检查并构建到 dist/
npm run bake     # assets/art/*.svg 烘焙为 public/textures/*.webp 与 manifest.json
npm run fonts    # 按全部台词重新裁剪字体子集到 public/fonts(需要网络)
npm run shot     # 构建、在 Chromium 中渲染,截图到 docs/style-board-three*.png
npm run shot -- --lang en   # 英文版截图
npm run play     # 构建、无头通关第一章(固定骰子与路径),截图到 docs/m1-*.png
npm test         # 对话引擎的单元测试

打开页面即从 study.intro 开始游玩第一章,一直到「第一章 完」。

  • 画面:相机模拟坐在桌前读书:眼睛比桌面高约 47 cm,离书的中心约 64 cm,从书的中心看约 45° 仰角。书前留出一截桌面,桌面木板由近及远,和书的两条侧边汇向同一个消失点。整本书和立体书房完整入画,四周露出胡桃木桌面。左页顶层纸撕到约四分之一深度,撕口后方的地板上立着书架、壁炉、书桌与扶手椅,撕口以下是对话日志。右页顶层纸撕到接近页尾,房间地板一直铺到那里,哈里与金站在房间中央的地毯上:两人是低多边形的纸模型,四分之三侧身相对,折面各有深浅,折线分明。书右侧的桌面上从远到近放着线索卡堆与两枚圆角纸骰。窗外下着雪,雪只在窗洞里可见。

  • 冬日光线(默认,docs/look.md):低角度的冬日阳光从窗洞射入,带灰尘的光束横过房间,长而硬的蓝灰影落在房间与桌面上;台灯关着,蜡烛是唯一的暖色;降饱和的冷调色,墙纸、地板与桌面有污渍与磨损。?look=noir 为夜,?look=warm 为此前的暖色绘本。

  • 原作界面(默认,docs/ui.md):左页日志印在原作的深色对话面板上(白色衬线字、粗体说话者、按属性着色的技能名、检定纸条、青色「继续」条),字号较小,行距、段距与边距较宽;「你」的台词是浅橙色,与金的白色区分。画面四周是原作的 HUD,只放本章用得上的:左下哈里与金的圆形头像(说话者的外圈变亮),哈里头像上方是士气的蓝色十字数字框与四格;右下是时钟,现在的时间每出现一行台词前进一分钟,回忆时显示昨晚的时间。骰子停下时,骰子下方出现「检定成功 / 失败」横幅。书上不叠加平面的界面元素。?ui=book 为此前的书页排法:日志印在纸上,士气是桌上的四颗对折纸心,没有 HUD。

  • 质感:窗侧主光的影子在落脚处清晰、随距离变软(PCSS),墙在桌面上的影子是柔和的渐变。立着的纸片都有卡纸厚度,朝上的切边露出一条浅色纸芯。木桌由着色器按世界坐标绘制:木板、年轮、导管与板缝,任何分辨率都清晰。

  • 书页打开:立体书房先正面朝下折在书页上,露出素色纸背,再由后往前逐排翻起,纸偶最后立起。墙立起时窗扇打开、窗外开始下雪,书桌立起后蜡烛点亮。

  • 日志逐字打出:中文每字 55 毫秒,英文每字符 28 毫秒;逗号类标点后多停 120 毫秒(英文 80),句末标点后多停 260 毫秒(英文 180);内心声音在名字后停 0.3 秒。打字时点击补全当前一段。每段打完停下,面板下方出现「继续」条(?ui=book:左页右下角闪烁「▼ 继续」),点击、空格或回车进入下一段;玩家自己的「你 —」行、紧接选项的最后一段与掷骰行不停。

  • 选项:数字键 1–9 或点击选择。检定选项悬停时显示成功率与修正(「+1 指针被拨过」);失败待重试的白色检定置灰并提示原因;红色检定的标签前有红色菱形。

  • 掷骰:两枚纸骰子从右侧掷到桌面上,翻滚约 0.8 秒后停在掷出的点数上,再打出掷骰行(2 与 12 加「蛇眼。」「满贯。」)。失去士气时出现「士气受损 -1」横幅,HUD 的士气格逐个熄灭(?ui=book:桌上的纸心依次翻面)。

  • 新线索:日志里插入一行系统提示(绿色的「新线索:指针被拨过(1/3)」;?ui=book 为金色方框),右页前部落下一张贴着胶带的大卡片;点击后卡片缩小,飞到桌面的线索卡堆上。

  • 悬停提示:鼠标悬停书房里的人物与物件(座钟、窗户、书桌、蜡烛、衣帽架……还原时的楼梯、狗与马雷克)、桌面上的骰子与线索卡,或 HUD 的士气时,对象提亮,旁边出现原作的黑色横条,写一句描述,只看不点(?ui=book:纸签,写名称与描述)。描述随进度变化,例如得知指针被拨过之后的座钟;士气显示数值,线索卡列出已找到的线索。说话时对应的纸偶轻轻上下晃动。

  • 还原:逻辑思维还原成功后,画面转冷、烛光稍亮、雪停,窗扇合上,钟的指针倒回 22:30、钟摆重新摆动,HUD 的时钟显示真实时间(22:30 起,逐段推进到 23:30,后接「昨晚」;?ui=book 为顶部的时间标记)。壁炉与衣帽架之间立起一段楼梯,房东太太的狗趴在楼梯口。马雷克上楼(狗抬头又趴下),从楼梯后面走进房间,走到书桌前一记重击(烛火乱晃、全场暗一拍);再走到座钟前把指针拨到 23:40、按住钟摆;走到窗前,窗扇向屋内推开;随后原路下楼。雪重新落下,屋顶、防火梯和窗台积起雪。回到现在,楼梯与狗折回地板。

  • 结尾:选择「走吧,去二楼。」后,金转身、哈里跟上,两人向右走出房间,在页边折倒;蜡烛熄灭,日志末尾出现「第一章 完」。

  • 音乐:用户提供的录音(public/audio/elysium.mp3,约 3 分 49 秒,整首循环),播放音量比原文件低约 19 dB,低于骰子、检定等主要音效。第一次点击或按键后淡入;右上角「中 / EN」左边的音符按钮开关音乐,选择保存在浏览器里。回忆时像隔了一层(低通滤波、稍轻),回到现在时恢复,章节结尾淡出。详见 docs/music.md。

  • 音效:用 Web Audio 实时合成,没有音频文件:铅笔写字(日志逐字打出时,每个字两笔)、继续与选择的轻响、悬停选项、塑料骰子磕在桌上与弹跳、检定成功与失败、内心声音(按属性区分音高)、新线索落下与归档、纸心翻面与士气升降、纸片立起与折倒、窗扇、风、钟的指针与钟摆、脚步、重击书桌、进入与离开回忆、点蜡烛与熄蜡烛。声音按发生的位置左右声像,经一个小房间混响。右上角音乐按钮左边的喇叭按钮开关音效,第一次点击或按键后才会出声。

所有动画都走同一个虚拟时钟,系统设置「减少动态效果」时直接显示结束状态。

?still 是风格板:第一章 study.clock 节点的一个静止瞬间(见微知著检定成功、第一条线索已归入桌面卡堆、士气 3/4)。左页日志自下而上排列,旧行升入撕口处淡出,鼠标滚轮可在左页上翻看历史。鼠标移动时相机有几度的视差,悬停左页的当前选项会高亮。右上角可切换中英文,游戏中切换会立即补全正在打字的一行并重排日志与选项,不重置进度。

bake、shot、play 与 extract-art 通过 tools/chromium.mjs 选择浏览器(可用 CHROMIUM_PATH 覆盖):macOS 上用本机 Google Chrome 与 GPU;云端容器里用预装的 Chromium,没有 GPU 时由 SwiftShader 提供 WebGL 2。页面参数:?still 显示风格板并冻结雪、颗粒与光标,用于截图;?lang=en 以英文打开;?seed=N 固定骰子种子;?dice=4-5,3-3,5-6 依次强制之后几次掷骰的点数;?speed=N 以 N 倍速播放动画与打字(测试用);?debug 在 window.__debug 暴露场景对象。排法与氛围:?ui=book 书页排法(默认为原作的深色对话面板与 HUD,?ui=de),?look=noir|warm 夜或此前的暖色绘本(默认为冬日,?look=winter);?ui=book&look=warm 是第五轮之前的默认画面。候选方案:?view=0|1|2|3 相机取景(默认 2,0 为第三轮之前的取景),?style=1|2|3 原作风格预设(数字可组合,如 ?style=13;默认不启用;按书页排法设计,与 ui=book&look=warm 同用时是原来的样子)。参数可以组合,例如 ?look=noir&view=3。npm run play 通过 window.__play 读取选项(编号、id、状态)并用数字键按 id 选择,在指定时刻冻结虚拟时钟截图,断言没有控制台错误且到达结尾。

模块

  • src/scene/:table 着色器绘制的胡桃木桌面(木板、年轮、导管、板缝),book 布面书壳、书芯与书口纸线、底页上的地板、两张撕开的顶页(左页撕到约四分之一深度,右页撕到接近页尾),popup 背景板五层,puppets 站在地板上的哈里与金和纸质立脚,tabletop 桌面道具的摆放,dice 桌面上的圆角纸骰与掷骰动画,hearts 桌面上对折的士气纸心(?ui=book),lead 新线索卡片(落在右页,点击后归入桌面卡堆),hotspots 悬停提示的拾取(按纹理透明度的射线命中、各背景层内的区域)与提亮,cues 全部舞台指令(窗扇、钟的指针与钟摆、窗外与窗台的积雪、楼梯与狗、马雷克在房间里的行走、调色与灯光、时间标记、结尾的退场与熄烛)和开场时纸片从书页上逐排翻起,lights 灯光与阴影,penumbra 主光的软阴影(PCSS,改写 three.js 的阴影着色器片段),post 颗粒、暗角、调色与夜色,camera 候选取景(VIEWS)与视差,palette 风格预设 2 的灯光与调色,details 风格预设 3 在运行时绘制的原作细节(交互标记、检定纸条等),mood 冬日与夜两个氛围预设,shaft 窗洞的体积光束与浮尘,grime 运行时绘制的污渍与破败(墙纸水渍、地板积灰、书页霉斑、桌面刮痕),snow 窗外的雪,space 坐标、书页截面曲线与纸片工具,paper 纸纹、布纹、书口纸线、烘焙的接触阴影与卡纸厚度(纸芯切边与纸背)。
  • src/play/:clock 虚拟时钟(补间、等待、倍速、减少动态效果、测试用的冻结),director 逐个播放引擎给出的节拍,每段之后等待点击,并在等待玩家选择时接受输入,log 左页日志的逐字打出(按标点停顿)、滚动、选项、「▼ 继续」、读屏镜像与选项提示。
  • src/page/:layout 日志排版(说话者 + 破折号、结果标签、编号选项、置灰与红色检定标记;中文按字断行、避头尾,英文按词;自下而上锚定),painter 画布绘制(按取景纵向拉伸,默认 1.21 倍,抵消斜看纸面造成的字形压扁)、逐字显示、滚动窗口与撕口处的淡出,hit 射线命中选项。
  • src/audio/:music 背景音乐(<audio> 接入 Web Audio 的音量与低通滤波、开关、首次交互启动、剧情钩子),sfx 音效(合成配方、声像与混响、开关与首次交互启动)。
  • public/audio/:背景音乐录音。
  • src/style.ts:解析 ?style=,风格预设的开关;src/ui.ts:解析 ?ui=。src/play/hud.ts、portraits.ts:原作界面的 HUD(头像、士气、时钟与检定横幅)与自绘的圆形头像。
  • src/engine/:对话引擎(节点、检定、旗标、士气、白色重试与红色一次性),只产出节拍,不做动画。
  • src/content/:schema 类型(design.md 7.3),skills 九项技能、属性色、难度与标签格式,study 第一章全部节点,study-clock 风格板瞬间,ui 界面文字(时间标记、新线索、继续、第一章 完、成功率等),hotspots 悬停提示的名称与描述。
  • assets/art/*.svg:每张纸片一个矢量源文件,撕边与纸纹滤镜写在文件里,只在烘焙时运行。floor-papers.json 是地板上散落纸页的位置与大小,地板脚本与悬停提示共用。纸偶 harry.svg、kim.svg 由 tools/papercraft 生成(低多边形纸模型,npm run papercraft 生成并烘焙,不要手改),根元素的 data-* 属性给出脚底、立脚范围与烟头位置(docs/cast.md)。M1 新增的手绘纸片:casement 窗扇,clock-hour、clock-minute、pendulum 钟的指针与钟摆,stairs 楼梯与平台,dog、dog-head 房东太太的狗,marek 马雷克的剪影,heart、heart-empty 士气心形,lead-card 新线索卡片;far-snow、sill-snow 由 extract-art 从旧风格板拆出。地板(含地毯与散落纸页)与两张顶页的撕口也由 extract-art 生成,参数见脚本开头。
  • public/textures/:烘焙结果(WebP,透明通道无损,共约 1.8 MB);public/fonts/:字体子集。
  • tools/:bake 烘焙,shot 截图(--view 0,1,2,3 渲染各取景的对比图),play 无头通关(--view N --out 目录 在指定取景下通关,--query 加页面参数),papercraft 生成两个纸偶(一个小的低多边形渲染器:多面体、平面着色、折线与切边),subset-fonts 字体子集,extract-art 从旧风格板提取纸片(一次性迁移工具,重跑会覆盖它生成的纸片,不动纸偶)。

字体

npm run fonts(tools/subset-fonts.mjs)收集 src/content/**/*.ts、index.html 的界面文字与 docs/design.md 4.4 节的全部台词,按用途向 Google Fonts 的 text= 接口请求子集:思源宋体承担全部字符,粗体只取旁白,思源黑体只取说话者、技能、标签、界面标签、ui.ts 的界面文字与证据名,霞鹜文楷等宽只取选项与「你 —」行;EB Garamond、Inter、JetBrains Mono 取全部非中文字符。脚本会检查每个文件的字符表。黑体与等宽的字体栈以宋体收尾,漏收的字会以宋体显示而不是方块。第一章剧本定稿后无需再裁剪。

旧风格板

demo/index.html 是 M0 阶段的 CSS 3D 单文件页面,保留作对照,直接用浏览器打开即可,运行时不再使用。它内嵌的字体子集与台词、人物都停留在 M0 阶段,不再更新。

当前阶段

M1 最小 Demo:第一章可从开场完整玩到「第一章 完」,包括全部检定与骰子动画、旗标与士气、白色重试与红色一次性、还原成功的完整舞台动画与语言切换。M1 之后的第二次打磨调整了视角、文字尺寸与右页的作用(见 design.md 6.1);第三次打磨针对质感:软阴影、卡纸厚度、木桌、桌面道具、开场与纹理体积(见 design.md 8 节)。第四轮加入读者视角的取景、背景音乐与音效,以及纸偶版本与原作风格预设两组候选方案;第五轮尝试更大胆的原作界面、氛围与油画渲染;第六轮选定原作界面与冬日为默认,HUD 只留本章用得上的部分,油画渲染效果不好,已移除;纸偶从十个方向中选定低多边形纸模型。取景与第四轮的风格预设仍待选定。下一步是 M2。

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages