Skip to content
KelierPublic

About

mixtape 混音带

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

LAST SUMMER TAPE

一款受青春独立电影、复古录像带与定格动画启发的 Three.js 网页游戏(垂直切片)。 三个短章节、一个核心特色:MEMORY FRAME RATE —— 角色姿态按 1–60 FPS 逐格采样,而移动、相机、输入、音频和渲染保持流畅。

title

demo-preview.mp4

运行

npm install
npm run dev        # 开发
npm run build      # 类型检查 + 生产构建 → dist/
npm run preview    # 预览 dist/

构建产物是纯静态文件(base: "./"),可以直接部署到任意静态托管 / CDN。

操作

按键 作用
WASD / 方向键 移动
Space 跳跃
Shift 第一章:滑板;第三章:冲刺
E 互动 / 拾取 / 调查
鼠标拖拽 转动镜头(第一章)
F 打开/收起帧率面板
1 2 3 4 8 / 12 / 24 / 60 FPS 预设
Enter 跳过演出
Esc / P 暂停(窗口失焦也会自动暂停)

手机 / 平板

触屏设备自动切换为触控操作:左半屏任意位置按下出现浮动摇杆(模拟量,推一半慢走);右下角 跳 / 互动 / 滑板(第三章为冲刺) 按钮;右半屏滑动转镜头;顶部 ❚❚ 暂停,过场中出现 跳过 按钮。竖屏时提示横屏,点开始时尝试全屏并锁定横屏(iOS Safari 不支持锁定,会显示横屏提示)。手机默认 LOW 画质(关闭 Bloom 与阴影,像素比上限 1.25),可在暂停菜单切回 HIGH。需要支持 WebGL2 的浏览器(iOS 15+ / 近年 Android Chrome)。

已实现内容(按优先级)

P0

  • 完整流程:标题 → CH01 GOLDEN HOUR → CH02 STATIC DREAMS → CH03 THE LAST TRACK → 结尾 / Credits → 重玩、按章节重玩、回到标题
  • 主角控制:行走、滑板(带板)、奔跑 / 冲刺、跳跃(土狼时间 + 输入缓冲)、AABB 碰撞、台阶、可跳上的障碍
  • AnimationSampler:独立的单调动画时钟,只在采样边界计算骨骼;动作切换只在采样边界生效;脚步声绑定采样到的关键姿态
  • 核心交互:拾取磁带、调查、播放磁带、躲避障碍(Interactable + InteractionManager,同时只能执行一个交互)
  • 由 Timeline 驱动的章节转场、原创合成音乐、结尾演出、失败后从检查点恢复

P1

  • 胶片颗粒、暗角、色彩分级(每章一套)、Bloom、按帧率步进的胶片抖动(gate weave)
  • 电影镜头:开场摇镜、拾取特写 + 定格、推镜、照片闪回、列车经过的升降镜头
  • 照片墙闪回(回忆中的“她”以 8 FPS 运动)、空椅子(环境音变闷 + 音乐压低)、更多环境音(鸟、远处车辆、时钟、蟋蟀)
  • 帧率面板:1–60 滑块、8/12/24/60 预设、作用范围(仅角色 / 角色 + 演出镜头)、实测姿态/秒

P2(未做):换装、更多收集品、自由镜头、照片分享、隐藏结局。

架构

blender/
├── scripts/      build_all · common · textures · characters · environment · props(Blender Python)
├── characters/ environments/ props/   .blend 源文件
├── textures/     烘焙 / 渲染出的 T_*.png
└── previews/
public/assets/    Blender 导出的 GLB
src/
├── app/          main.ts · GameApp.ts(拥有全部系统,实现 GameContext)
├── core/         GameLoop · GameState(状态机 + 输入权限表)· Input · Physics · AssetManager(GLB 资产库)· dispose
├── player/       CharacterRig(Blender 蒙皮角色实例)· AnimationClips(ACT_* 剪辑索引)
│                 AnimationSampler · CharacterAnimator · PlayerController
├── chapters/     Chapter(基类)· GoldenHour · StaticDreams · LastTrack
├── cinematics/   Timeline(事件配置 + 处理器注册表)· CameraDirector
├── audio/        AudioManager(Web Audio 合成音效/环境声)· Music(步进音序器 + 三首原创曲)
├── rendering/    PostProcessing(Bloom → OutputPass → 胶片 Pass)· Sky
├── interaction/  Interactable · InteractionManager
├── world/        Kit(实例化 Blender 资产)· bake(静态模块按材质合批)
├── ui/           GameHud · FpsControl · Screens(标题 / 加载 / 暂停 / 结尾)
└── config/       chapters.ts(章节配置)· settings.ts(持久化设置)

三种“帧率”是分开的

  • 渲染帧率:GameLoop 每个 requestAnimationFrame 都渲染。
  • 物理 / 输入:PlayerController 每帧用真实 dt 更新,与动画采样率无关。
  • 动画采样率:每个角色的 AnimationSampler 维护自己的动画时钟,只有跨过 k / fps 边界时才调用 mixer.update(自上次采样以来的时间)。两次采样之间不做任何骨骼计算,姿态保持不变。

用 mixer.update(Δ) 而不是 mixer.setTime(),可以保留淡入淡出 / 混合权重的状态;每次采样后 mixer 内部时间与采样时钟完全一致。切章、暂停时调用 reset() 重新对齐,避免一次性补算很长的时间。

Timeline

章节里没有散落的 setTimeout()。所有演出都是 TimelineEvent[] 配置:camera / light / audio / postprocess / animation / dialogue / transition / call。

  • 时间只通过 update(dt) 推进 → 暂停游戏即暂停演出
  • 每个事件只触发一次;带 duration 的事件获得补间进度
  • skip() 补完所有补间并丢弃标记为 skippable 的音效;stop()(卸载章节)返回 false,章节代码据此不再恢复控制权

音乐同步

音乐由 AudioContext 时钟驱动:音序器提前约 120 ms 排程,并把每一拍的精确音频时间放进队列;游戏每帧只取出“音频时钟已经到达”的拍子(第三章的路灯闪烁、镜头震动、色差脉冲)。渲染帧率波动不会造成音画漂移。

Blender 美术管线

所有美术资产都在 Blender 4.2 中制作:角色、骨骼、动作、场景模块、道具、贴图,甚至照片、海报、磁带标签、窗外夜景。游戏代码里不生成任何网格或贴图,只负责摆放、打光、播放 Blender 导出的内容。

npm run assets              # = blender -b --factory-startup -P blender/scripts/build_all.py
BLENDER=/path/to/blender npm run assets
blender -b -P blender/scripts/build_all.py -- characters   # 只重建某一部分:textures / characters / environment / props

一次完整重建约 70 秒,结果完全可复现:

步骤 Blender 中的做法 产物
贴图 程序化着色器节点(Noise / Voronoi 映射在 4D 环面上,保证无缝平铺)→ Cycles EMIT 烘焙 blender/textures/T_Asphalt / T_Sidewalk / T_Grass / T_Siding_* / T_Shingles_* / T_Wood_* / T_Wallpaper / T_Hazard
2D 美术 平面几何 + 文字物体排版 → 正交相机 Cycles 渲染 T_Polaroid_0..5 / T_Poster_* / T_Cassette_Label / T_Rug / T_StopSign / T_Window_Night / T_Memory_Sunset
角色 见下方「三位主角」 blender/characters/{protagonist,friend,memory}.blend → public/assets/characters/*.glb
场景 40+ 个 ENV_* 模块:12 种房屋、车库(独立的卷帘门子物体)、道路 / 人行道 / 草地平铺块、围栏、3 种树、电线杆与电线、路灯、7 色汽车、路障、垃圾桶、锥桶、木箱、铁道口、列车、卧室、天台、天空球 blender/environments/environment_kit.blend → environment_kit.glb
道具 25 个 PRP_*:磁带、录音机(磁带轮为子物体)、滑板、信箱、自行车、篮球架、床、书桌、空椅子、台灯、地毯、唱片架、海报、6 张拍立得、串灯… blender/props/props_kit.blend → props_kit.glb

三位主角

参考风格:青春独立动画(长脸、厚重上眼睑、大虹膜、浓眉、长鼻梁)。

角色 造型
主角 protagonist 金色波波头 + 侧分刘海、橙色头戴耳机、青绿棒球夹克(罗纹领 / 门襟 / 袖口 / 下摆)、奶白 T 恤、牛仔裤、红色球鞋
阿森 friend 红色罗纹毛线帽、深色长卷发、浓眉、绿色眼睛、耳钉、灰色宽松 T 恤、卡其裤
她 memory 黑色长直发 + 齐刘海、深褐虹膜、深色高领毛衣、百褶短裙、短靴

制作流程(leads.py / faces.py / bodies.py / game_leads.py,运行 build_leads.py):

  1. SDF 雕刻(sdf.py):头骨、面部体块、颧骨、眉弓、鼻梁/鼻尖/鼻翼/鼻孔、嘴唇与口裂、耳廓、颈部、躯干、四肢、五指手、衣物(布料褶皱置换)、发型(发丝沟槽置换)、毛线帽罗纹、耳机,全部用平滑并集 / 差集 / 交集组合;Surface Nets 成网,再用牛顿步投影回等值面。雕刻姿势为 A-pose(手臂外展 15°),避免袖子与衣身粘连。
  2. 眼睛:独立眼球 + 程序化虹膜(瞳孔、放射纤维、角膜缘暗环、清漆高光),上下眼睑壳体,上眼睑边缘加厚成睫毛线,外眼角挑线;眉毛按皮肤表面贴合生成。
  3. 材质(looks.py):皮肤次表面散射 + 腮红 / 鼻尖 / 耳廓泛红 + 唇色遮罩;布料 sheen + 织纹;头发条纹 + sheen。
  4. 游戏网格:逐部件减面(每人约 3–4 万三角面),多物体 Smart UV 共享一张 2048 图集;Cycles 烘焙:程序材质颜色、逐部件高模→低模切线空间法线、AO,合成 BaseColor。
  5. 绑定:解剖朝向骨骼(与游戏内其他角色同名),按 SDF 部位归属(躯干 / 左右臂 / 左右腿)分区计算平滑权重;头部配件刚性跟随头骨,长发在颈部以下过渡到胸骨,裙子按高度在胯与大腿之间过渡。
  6. 表情 Shape Key:Blink / Wide / BrowUp / BrowSad / MouthOpen / Smile,游戏内自动眨眼并由剧情 Timeline 驱动表情。
  7. 姿势库:16 个 ACT_* 动作(行走、奔跑、跳跃、滑板、坐、举磁带、挥手、回头、摔倒……以及新增的 LookUp 仰望、Listen 听歌、Point 指向、Shrug 耸肩、Cheer 欢呼),已标记为 Blender 资产,可在 Asset Browser 的姿势库里直接套用。
  8. 展示渲染:render_leads.py -- portraits | lineup | poses | night → blender/previews/leads_*.png。

命名与组织遵循策划案 4.3:CHR_ / RIG_ / ACT_ / ENV_ / PRP_ / M_ / T_,Collection 为 CHARACTER / ENVIRONMENT / PROPS / LIGHTING / CAMERAS。导出时应用变换、统一米制与朝向(游戏空间 Y 朝上、角色面向 +Z),贴图打包进 .blend 和 GLB。

动作数据只存在于 Blender。游戏端的 AnimationSampler 以 1–60 FPS 对这些 Action 采样:12 FPS 时每秒恰好 12 个姿态,与渲染帧率无关。

预览图见 blender/previews/(贴图、动作姿态、场景模块、道具)。

已知限制

  • 需要 WebGL2;桌面用键盘 + 鼠标,手机 / 平板用触控(见上文)。
  • 画质菜单(暂停界面)可切到 LOW:关闭 Bloom 和阴影、像素比 1。
  • 天空渐变和胶片效果是渲染层的着色器(作用在 Blender 导出的天空球和画面上),不属于美术资产。

About

mixtape 混音带

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages