Skip to content
Possibility-HePublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

竹知了 · 3D 仿真玩具

一只会"唱歌"的竹雕蝉。像儿时一样,在手心搓动竹竿,竹蝉随之旋转;转得够快,蝉翼振动,唱出夏天的蝉鸣。支持触控、鼠标、键盘,还能用摄像头对着镜头搓手来玩。

技术栈 依赖 交付 兼容


目录

  1. 项目简介
  2. 核心玩法流程
  3. 功能特性
  4. 快速开始
  5. 玩法说明
  6. 系统架构与运行流程
  7. 技术实现
  8. 项目结构
  9. 兼容性与无障碍
  10. 隐私说明
  11. 验证与测试
  12. 完整开发历程
  13. 自定义与扩展
  14. License

项目简介

「竹知了」(竹蝉)是一种传统民间玩具:一根竹签顶端插着一只竹片削成的蝉,用双手手心快速搓动竹签,竹蝉飞转,蝉翼振动发出酷似蝉鸣的声音。本作把这个童年夏天的手艺,做成了 3D 仿真网页游戏。

设计理念

  • 仿真优先:搓动 → 旋转 → 翼振 → 蝉鸣,环环相扣,转速、音高、音量、翼振频率、残影、地面拖尾都随同一个物理量 ω 联动
  • 一种手感,四种输入:触控 / 鼠标拖拽、键盘按住、摄像头搓手,都换算成同一个角速度模型,手感一致
  • 夏日竹影:暖阳、竹林、光尘、高枝上停着的蝉,营造盛夏氛围;楷体题字 + 等宽数据 + 蝉翼白面板,克制而有意境

核心玩法流程

一个完整的操作闭环:

  搓动(触屏/鼠标/键盘/摄像头)
        │  输入 → 角加速度 ω̇
        ▼
  竹竿旋转(ω 积分,摩擦衰减)
        │  ω 超过起唱阈值
        ▼
  蝉翼振动 + 蝉鸣(音调/响度随 ω)
        │  松手
        ▼
  转速自然衰减 → 停唱
  • 挑战模式在这个闭环上叠加目标:连鸣挑战看「连续鸣叫多久」、极速挑战看「冲到多高转速」、冲分挑战看「连击刷多少分」,各有实时计分与最高纪录。

功能特性

功能 说明
🎋 竹质立体质感 MeshStandard 材质 + 颜色/凹凸双贴图 + 程序化环境反射:真实几何竹节凸起、镜面光泽、木纹节疤
🔄 360° 旋转观察 「🔄 视角」一键切换,360° 环绕 + 顶部到底部无死角俯仰,滚轮/双指缩放近看
🌀 真实旋转物理 搓动加能、摩擦衰减、转速上限、进动晃动,转速表实时显示 RPM
💫 高速旋转可视化 蝉翼残影 + 翼扫环形模糊盘 + 地面螺旋拖尾光纹,随转速旋转显现,直观感受转速快慢
☀️ 太阳实影 方向光(太阳)投射真实阴影,竹竿/蝉身/蝉翼在地面投出残影,随旋转转动
🦗 蝉鸣合成 零音频文件,Web Audio 实时合成:锯齿波 + 翼振 AM 调制 + 气声;载波/颤音频率与响度随转速连续变化,停转自然衰减消失
🎮 四种模式 禅意(无限时)+ 连鸣挑战(连续鸣叫时长)+ 极速挑战(30 秒冲最高转速)+ 冲分挑战(60 秒连击冲分),各有实时计分与最高纪录
📷 摄像头搓手 轻量帧差 + 运动振荡检测,零模型依赖,灵敏度滑块可调;画面仅本地处理
🔊 环境音 + 事件音 夏日风 + 远处虫鸣底噪,可单独静音;起唱/连击/结束音效
📱 多端兼容 手机 / 平板 / 桌面响应式,触控 + 鼠标 + 键盘 + 摄像头
♿ 无障碍 键盘可操作、:focus-visible、prefers-reduced-motion 减弱动效
⚡ 性能自适应 按设备自动分高/中/低三档(粒子、竹林、阴影、DPR),页面隐藏自动暂停

快速开始

方式一:直接打开(最简单)

双击 index.html,即可在任意现代浏览器(Chrome / Edge / Firefox / Safari)中打开。无需安装、无需联网、无需构建——Three.js 已内置在 vendor/ 目录。

摄像头功能建议通过本地服务器方式(方式二)使用,见下方说明。

方式二:本地 HTTP 服务器(推荐,摄像头 + 局域网分享)

# Python 3
python -m http.server 8090 --directory . --bind 0.0.0.0

# 或 Node.js
npx serve .

访问:

  • 本机:http://127.0.0.1:8090/index.html
  • 局域网(同一 Wi-Fi 的手机/平板):http://<你的局域网IP>:8090/index.html

💡 摄像头需要「安全上下文」:http://localhost / http://127.0.0.1 或 https:// 均可。直接双击 file:// 时,多数现代浏览器同样视为安全上下文,摄像头通常可用。


玩法说明

怎么"搓"

在画面任意位置快速来回搓动(横向往复或画圈皆可),竹蝉就会转起来:

  • 触屏 / 鼠标:按住拖动,搓得越快转得越快
  • 键盘:按住 A / D 或 ← / → 持续搓动
  • 摄像头:点右上角「摄像头」,对着镜头快速搓手(拇指搓食指等往复动作),可拖灵敏度滑块调节

转速与蝉鸣

  • 转速表(RPM)实时显示;速度条上的竖线是起唱阈值
  • 转速超过阈值 → 蝉翼振动、唱出蝉鸣,音高音量随转速升高
  • 松手后摩擦自然减速,低于阈值即"蝉鸣中断"

旋转观察

  • 点右上角「🔄 视角」进入观察模式:拖动旋转视角(360° 环绕、上下俯仰),滚轮(桌面)/ 双指(触屏)缩放
  • 再点一次回到搓动模式,两种手势互不干扰

四种模式

  • 禅意:无限时,随心搓听,记录蝉鸣累计时长与巅峰转速
  • 连鸣挑战:让蝉连续鸣叫尽可能久;一停唱(0.8 秒宽限)即结算,记录「最长连续鸣叫」
  • 极速挑战:30 秒内冲到最高转速,记录「巅峰转速」与「平均转速」
  • 冲分挑战:60 秒冲分。得分 = 速度加成 × 连击倍率;连续蝉鸣每 3 秒升一档倍率(×1→×5),停唱即清零

三种挑战各有实时计分与最高纪录(localStorage 持久化)。


系统架构与运行流程

总体架构

单文件、零构建、无框架。index.html 内按职责分段,运行时各模块通过共享状态协同:

输入(Pointer/键盘/摄像头)──┐
                             ├─→ 物理(ω)─┬─→ 3D 玩具动画 + 特效
                             │              ├─→ 音频合成(蝉鸣/环境)
                             │              ├─→ 游戏计分/模式
                             │              └─→ UI(RPM/得分/提示)
                             └─────────────────→ localStorage(最高纪录)

主循环(每帧 tick)

requestAnimationFrame(tick)
  ├─ 物理:ω += (输入角加速度 − ω·摩擦系数) · dt,上限 45 rad/s
  ├─ 游戏:模式计时 / 计分 / 连击 / 连鸣宽限结算
  ├─ 音频:载波频率、翼振颤音频率、响度随 ω 连续更新
  ├─ UI:RPM、得分、倒计时、提示文案更新
  ├─ 玩具:旋转、翼振、残影、模糊盘、地面拖尾、进动晃动
  ├─ 相机:观察旋转 / 视差 / 天空跟随 / 渲染
  └─ 渲染:renderer.render(scene, camera)

输入 → 物理

触屏/鼠标拖拽 ── 指针速度 × 0.05 ──┐
键盘 A/D / ←→ ── 固定 22 rad/s² ───┤→ 角加速度 ω̇ ─→ 积分得 ω(上限 45)
摄像头搓手 ──── 搓动强度 × 80 ─────┘          └─ 摩擦 0.55·ω(自然衰减)

渲染流程

场景:天空渐变球 + 竹林 + 地面 + 光尘粒子 + 太阳光晕
玩具:竹竿 + 竹节凸起 + 竹雕蝉(身/眼/颈环/双翼)
光照:太阳方向光(投射阴影)+ 半球光 + 轮廓光 + 程序化环境反射
特效:翼残影(偏移∝ω)+ 翼扫模糊盘 + 地面螺旋拖尾(随ω旋转)
阴影:PCFSoftShadowMap,玩具各部件 castShadow,地面 receiveShadow

音频合成流程

锯齿波载波(3.3k + ω·50 Hz) → 带通滤波 → 响度(smoothstep·0.55) → 主增益
正弦 LFO(72 + ω·1.9 Hz) → 增益 → 调制载波幅度(蝉鸣颤音)
白噪声 → 低通 → 气声增益 → 叠加
环境:白噪声低通(风) + 带通噪声开关门(虫鸣)
全程零音频文件,全部振荡器 + 噪声实时合成

摄像头检测流程

getUserMedia → 视频帧 → 降采样 96×72 灰度
  → 帧差运动能量(噪声门限 0.005,×16 增益×灵敏度)
  → 一维块匹配估计位移 → 方向反转频率
  → 综合搓动强度(快起慢放平滑)→ 注入物理

计分与持久化流程

ω > 阈值 ─→ 蝉鸣中 ─→ 按模式计分(连鸣时长/巅峰转速/连击得分)
  └─ 回合结束 ─→ 比较最高纪录 ─→ localStorage 持久化
localStorage:zhuchan.best(得分)/ zhuchan.bestStreak(连鸣)/ zhuchan.bestRPM(转速)/ zhuchan.muted(静音)

技术实现

技术栈

  • HTML5 + CSS3 + 原生 JavaScript(ES2020)——无框架、无构建
  • Three.js r160(UMD,本地内置 vendor/three.min.js,缺失时自动回退 CDN)
  • WebGL:3D 场景、程序化纹理、阴影、粒子
  • Web Audio API:蝉鸣、环境音、事件音全部实时合成,零音频文件
  • getUserMedia + Canvas 帧差:摄像头动作检测,零模型依赖
  • localStorage:最高纪录、静音偏好持久化(隐私模式下降级为内存)

关键设计

模块 实现要点
物理模型 ω += 输入角加速度·dt,ω -= ω·摩擦系数·dt,上限 45 rad/s;拖拽速度→角加速度系数 0.05
蝉鸣合成 零音频文件;锯齿波载波(3.3k + ω·50 Hz) → 带通 → 翼振频率(72 + ω·1.9 Hz) AM 调制 + 低通气声;载波/颤音频率、颤音深度与响度(smoothstep) 均随 ω 连续变化、自然衰减
程序化纹理 Canvas 2D 生成:竹节纹理(渐变+节环+纤维)、蝉翼(外形+翼脉 alpha)、竹叶、地面斑驳、光晕
玩具模型 竹竿圆柱 + LatheGeometry 蝉身 + Torus 蝉红颈环 + 两侧 PlaneGeometry 蝉翼(绕体侧枢轴上下扇动)
竹质质感 MeshStandardMaterial + 颜色/凹凸双贴图 + PMREM 程序化环境反射;真实几何竹节凸起(Torus 节点)+ 主光/轮廓光
旋转观察 球坐标相机(方位角 360° + 俯仰角 0.05→π-0.05 无死角),拖动旋转、滚轮与双指缩放,经「视角」模式与搓动手势解耦
旋转残影/模糊 三对半透明"影翼"随转速拖后(偏移 ∝ ω)+ 环形模糊盘(透明度 smoothstep ∝ ω),静止时完全隐藏
地面拖尾 玩具正下方地面圆形螺旋光纹,随 ω 旋转(转速越快转越快)并淡入,把旋转速度呈现在地面
太阳实影 renderer.shadowMap + PCFSoftShadowMap;太阳方向光 castShadow、地面 receiveShadow、玩具各部件 castShadow
摄像头检测 降采样 96×72 灰度 → 帧差能量(×16 增益,噪声门限) + 一维块匹配位移 → 方向反转频率放大搓动强度,快起慢放平滑,灵敏度可调
状态机 menu → playing → result;禅意/连鸣/极速/冲分四模式;visibilitychange 暂停循环/音频/摄像头
质量档 按 deviceMemory / 核数 / 屏宽自动分三档,控制粒子数、竹林数量、阴影与 DPR

项目结构

project2/
├── index.html          # 唯一交付文件:设计系统 + HUD + 全部逻辑(约 1900 行,按注释区块分段)
├── vendor/
│   └── three.min.js    # Three.js r160 UMD(本地内置,离线可用)
├── README.md           # 本文档
├── LICENSE             # MIT
└── .gitignore          # 忽略 .pwtools/ .shots/ .npm-cache/ 等本地开发辅助目录

index.html 内部按注释区块清晰分段:设计系统 / 音频引擎 / 程序化纹理 / 3D 场景 / 玩具模型 / 物理与输入 / 游戏状态机 / 摄像头 / UI / 主循环,便于直接定位修改。


兼容性与无障碍

能力 支持情况
浏览器 Chrome / Edge / Firefox / Safari(近 5 年版本,需支持 WebGL)
设备 320px 手机 → 1920px 桌面;触控 + 鼠标 + 键盘 + 摄像头
摄像头 需安全上下文 + 用户主动授权;无摄像头/拒绝授权有友好降级
减弱动效 ✅ prefers-reduced-motion: reduce(光尘静止、相机视差瞬时、过渡瞬时)
键盘操作 A/D、←/→ 搓动;所有按钮可 Tab / Enter 操作
性能 DPR 上限自适应;页面隐藏自动暂停动画、挂起音频、关闭摄像头
深色/浅色 画面为固定夏景主题,UI 面板蝉翼白,不随系统深色模式切换

隐私说明

摄像头功能默认关闭,仅在用户点击「摄像头」按钮并授权后开启。视频画面仅在本地处理(用于计算"搓动"动作),不会上传、不会保存、不会录制。关闭按钮或切换后台时立即停止摄像头。


验证与测试

开发过程中使用 playwright-core + 系统 Chrome 进行了自动化浏览器验证(file:// 与本地 HTTP 两种方式)。

自动化断言(47 项全过)

  • 加载/渲染:three.js 加载、WebGL canvas 渲染、调试钩子暴露、开始屏可见
  • 核心玩法:进入 playing、冲分模式生效、拖拽转速上升、达到蝉鸣、得分累计、键盘搓动
  • 音频:停转响度=0、载波/响度随转速单调升高、实际载波与 ω 精确对应、停转响度自然衰减
  • 旋转可视化:静止无残影/模糊/拖尾、高速残影/模糊/地面拖尾出现
  • 旋转观察:开启/关闭、俯仰上下限(近顶部↔近底部)、拖动旋转、滚轮缩放
  • 摄像头:预览出现、按钮点亮、可关闭、检测到往复搓动(合成帧)、静止不误触发、搓手强度越大转速越高
  • 模式:禅意切换、连鸣 HUD/计时/中断结算、极速 HUD/倒计时递减、成绩面板
  • 移动端:竖屏触摸搓动、横竖屏无水平溢出
  • 稳定性:全程零控制台错误、零页面异常

专项

  • file:// 双击离线:✅
  • prefers-reduced-motion:✅
  • WebGL 缺失降级:✅
  • 像素级采样:非黑屏、竹林绿主导、暖阳光晕、玩具居中

复测方式:cd .pwtools && npm i playwright-core && node test.js(另 node filetest.js 验证离线/减弱动效,本机需已装系统 Chrome)。


完整开发历程

项目按「需求 → 实现 → 验证」迭代推进,每个版本都通过自动化测试回归:

版本 需求/反馈 实现 验证
v1.0 3D 竹知了仿真网页游戏,响应式多端 Three.js 场景 + 玩具模型 + 旋转物理 + 蝉鸣合成 + 双模式 + 摄像头动作检测 20 项
v1.1 竹质立体质感 + 旋转观察 Phong 材质 + 凹凸贴图 + 竹节高光 + 球坐标相机旋转观察 24 项
v1.2 竹子不够立体、旋转角度过小 真实几何竹节凸起 + PMREM 环境反射 + MeshStandard;俯仰 0.05→π-0.05 无死角 28 项
v1.3 必须实时合成、零音频、音调响度随转速连续变化 载波/翼振/响度随 ω 连续 + 颤音深度加深 + 自然衰减 34 项
v1.4 高速旋转可视化(运动模糊/残影) 三对影翼残影 + 翼扫环形模糊盘 37 项
v1.5 地面拖尾呈现转速 地面螺旋光纹随 ω 旋转淡入 38 项
v1.6 太阳照着竹子形成残影 太阳方向光投射真实阴影(PCFSoft) 39 项
v1.7 摄像头识别不到搓手 检测算法重写:分辨率/能量增益/往复阈值/平滑 41 项
v1.8 摄像头不按强度增大转速 ×16 增益 + 噪声门限 + 灵敏度滑块 + CAM_RATE 80 42 项
v1.9 加可玩挑战(连续鸣叫秒数/冲转速)+ 实时计分 + 最好成绩 连鸣/极速/冲分三挑战,各自实时计分与最高纪录 47 项

自定义与扩展

调节参数

编辑 index.html 中 <script> 顶部的 CONFIG 对象即可全局调参:

var CONFIG = {
  OMEGA_MAX: 45,        // 转速上限 rad/s
  FRICTION: 0.55,       // 摩擦衰减系数(越大停得越快)
  SING_THRESHOLD: 6,    // 起唱阈值 rad/s
  FULL_SING: 18,        // 满唱阈值
  DRAG_K: 0.05,         // 拖拽速度 → 角加速度
  KEY_RATE: 22,         // 键盘搓动角加速度
  CAM_RATE: 80,         // 摄像头满强度角加速度
  RUSH_SEC: 30,         // 极速挑战时长
  SCORE_SEC: 60         // 冲分挑战时长
};

加新模式

  1. 在 MODE_ORDER / MODE_NAME 中加入新模式的 key 与名称
  2. 在 Game.update 中按模式添加计分/计时逻辑,在 Game.endRound 中添加结算分支
  3. 在 UI.refreshMode / UI.update 中添加对应 HUD 区块的显隐与数值更新
  4. 在开始屏 .mode-grid 中添加一个 <button data-mode="...">

调音色/视觉

  • 音色:改 Sound.update 中的 carrier = 3300 + omega * 50、wingRate = 72 + omega * 1.9
  • 残影/拖尾:改 tick 中 ghostWings 的对数/偏移/透明度、wingFan 与 groundTrailMat 的 smoothstep 区间
  • 配色:改 <style> 顶部 :root 的 CSS 变量(竹青/竹黄/蝉翼白/墨/日金/蝉红)

License

MIT License © 2026 — 自由使用、修改与分享。

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages