

hy3似乎跑的很快,然后ox有点慢。
# 《微光大陆》—— 纯前端 Three.js 开放世界探索游戏 · 完整实施计划(交接版)
> 本文档面向**执行实现的 Agent / 开发者**,包含全部技术决策、模块规格、关键算法、参数数值与验收标准。
> 按本文档自上而下实施即可完成整个项目,无需额外上下文。
---
## 〇、当前项目状态
- 目录:`C:\Users\32382\Desktop\demo`(除下述文件外为空)
- 已存在:`package.json`(name=gleaming-continent,type=module,scripts: dev/build/preview)
- **依赖尚未安装**(安装操作被取消)。第一步必须执行:
```bash
npm install three simplex-noise
npm install -D vite
```
- 环境已验证:Node v24.17.0 / npm 12.0.2 / Windows (win32)
---
## 一、目标与视觉定位
- **玩法定位**:探索冒险。玩家在程序化无限大陆上自由漫游,发现生态群系,采集资源、猎杀/躲避生物、制作装备,无强制目标。
- **美术风格**:低多边形(Low-Poly)扁平着色 + 顶点色。全部资产由代码程序化生成(几何体拼装树木/岩石/角色),**零外部资源依赖**(无模型/贴图/音效文件)。
- **纯前端**:仅浏览器运行,无任何后端。
## 二、技术选型
| 项 | 选择 | 说明 |
|---|---|---|
| 构建 | Vite(devDependencies 最新稳定版) | 零配置即可,无需 vite.config.js |
| 渲染 | three(npm 最新稳定版) | 仅用核心包,**不使用 examples/addons** |
| 噪声 | simplex-noise v4 | API:`import { createNoise2D } from 'simplex-noise'`;`createNoise2D(rngFn)`,rngFn 返回 [0,1) |
| 随机 | 自写 mulberry32 种子随机 | 世界按 seed 完全可复现 |
| 语言 | 原生 JavaScript(ES2022,ESM) | 不用 TypeScript |
| UI | DOM 叠加层(HTML/CSS),非 canvas 绘制 | 程序化创建 DOM,无需前端框架 |
## 三、目录结构(实现必须遵循)
```
demo/
├─ index.html # 挂载点:<div id="app"> + <script type="module" src="/src/main.js">
├─ package.json # 已存在
├─ src/
│ ├─ main.js # 入口:装配 Game 并启动
│ ├─ config.js # 全局常量集中定义(见 §五.0)
│ ├─ style.css # 全部 UI 样式(由 main.js import)
│ ├─ core/
│ │ ├─ Game.js # 场景/渲染器/相机/时钟/主循环编排(见 §六)
│ │ ├─ Input.js # 键鼠状态 + Pointer Lock 管理
│ │ └─ EventBus.js # 极简 on/off/emit
│ ├─ world/
│ │ ├─ Noise.js # mulberry32 + WorldGen(高度/坡度/群系/颜色,见 §五.1)
│ │ ├─ Chunk.js # 单块地形网格(顶点色,世界坐标烘焙)
│ │ ├─ TerrainManager.js # chunk 流式加载/卸载调度
│ │ ├─ Vegetation.js # 每 chunk InstancedMesh 散布植被/岩石/资源点
│ │ └─ Water.js # 海平面水面
│ ├─ env/
│ │ ├─ SkyDome.js # 自定义渐变穹顶 ShaderMaterial + 日月盘 + 星星
│ │ ├─ DayNightCycle.js # 昼夜推进与光照/雾色插值
│ │ └─ Weather.js # 天气状态机 + 雨粒子
│ ├─ entity/
│ │ ├─ Player.js # 第三人称控制器:移动/跳跃/冲刺/游泳/相机
│ │ ├─ CharacterMesh.js # 程序化低模人形 + 行走/挥击动画
│ │ ├─ Creature.js # 生物基类:FSM + 受击/死亡
│ │ ├─ Animal.js # 被动动物(鹿)
│ │ └─ Monster.js # 敌对怪(史莱姆)
│ ├─ systems/
│ │ ├─ Spawner.js # 生物生成/回收 + 掉落物管理
│ │ ├─ Combat.js # 扇形命中判定、伤害、无敌帧、回血
│ │ ├─ Inventory.js # 物品数据与增删查、装备位
│ │ ├─ Crafting.js # 配方定义与合成校验
│ │ └─ Interaction.js # 准星目标查询 + E 键采集/拾取
│ └─ ui/
│ ├─ HUD.js # 血条/时钟/准星/交互提示/toast/受击红晕/死亡遮罩
│ ├─ InventoryUI.js # 背包面板(Tab) + 合成面板(C)
│ └─ LoadingScreen.js # 加载进度条 + 开始按钮 + 重置存档链接
```
## 四、核心技术决策(不可偏离)
1. **确定性高度函数**:`WorldGen.getHeight(x,z)` 直接采样噪声。chunk 网格顶点、玩家/生物贴地、相机避障、出生点选址**共用同一函数** → 全程无网格射线碰撞。
2. **Chunk 规格**:48m×48m、32×32 分段(33×33 顶点)、可视半径 5 chunk(≈240m),卸载半径 6;每帧最多构建 2 个新 chunk(队列按距离排序);几何体直接烘焙**世界坐标**(mesh 位于原点),卸载时 `geometry.dispose()`(材质共享不释放)。雾效终点 ~210m 掩盖加载边缘。
3. **顶点色代替贴图**:按高度带(水底深沙/沙滩/草地/岩石/雪顶)+ 群系色调 + 坡度混合着色,附加低频噪声做 ±6% 明度抖动;材质 `MeshLambertMaterial({ vertexColors:true, flatShading:true })`(现代 three 的 Lambert 支持 flatShading 与 vertexColors)。
4. **植被实例化**:每 chunk 用种子随机(hash(cx,cz,seed))采样 ~90 个候选点,按群系散布表生成;同类型合并为一个 `InstancedMesh`(**先统计数量再分配精确 count**);instanceColor 做色彩抖动;可采集资源(树/岩/浆果丛)登记到空间注册表;采集后把对应实例矩阵置零缩放隐藏。
5. **生物生命周期**:仅在玩家周围存活(上限 鹿12 + 史莱姆10),超出 180m 回收;生成环 40–130m 且必须在陆地(h>1)。不做对象池(实例创建成本低)。
6. **战斗手感**:左键挥击扇形判定 + 冷却 0.5s;受击闪红 + 无敌帧 0.6s;脱战 6s 后 +4HP/s;死亡在出生点重生不掉落。
7. **昼夜**:一天 = 现实 480 秒。t∈[0,1),小时数 = `(t*24+6)%24`(t=0 为清晨 06:00)。太阳仰角 `e = sin(t*2π)`。
8. **存档(轻量)**:位置/背包/时间/血量/装备每 5 秒 + beforeunload 时写入 localStorage;加载屏提供「重置存档」链接。
---
## 五、详细规格
### 5.0 `src/config.js` 全局常量
```js
export const CONFIG = {
SEED: null, // null=读存档或随机;实际值在 Game 里确定后传入各模块
CHUNK_SIZE: 48,
CHUNK_SEGS: 32,
VIEW_RADIUS: 5, // chunk 半径
UNLOAD_RADIUS: 6,
CHUNKS_PER_FRAME: 2,
SEA_LEVEL: 0,
FOG_NEAR: 60, FOG_FAR: 210,
DAY_LENGTH: 480, // 秒/游戏日
GRAVITY: 26,
PLAYER: {
HP_MAX: 100, WALK: 5.8, SPRINT: 9.2, SWIM: 3.2,
JUMP_V: 8.6, ACCEL_GROUND: 40, ACCEL_AIR: 12,
SWIM_DEPTH: -1.1, // 地面低于 SEA_LEVEL+此值 → 游泳
CAM_DIST: 7, CAM_MIN: 3, CAM_MAX: 12, CAM_TARGET_Y: 1.5,
PITCH_MIN: -1.2, PITCH_MAX: 0.55,
REGEN_DELAY: 6, REGEN_RATE: 4, IFRAME: 0.6,
},
COMBAT: {
COOLDOWN: 0.5, CONE_HALF_RAD: 35 * Math.PI/180, RANGE: 2.6,
FIST_DMG: 6, KNOCKBACK: 7,
},
SPAWNER: { TICK: 2, ANIMAL_CAP: 12, MONSTER_CAP: 10,
SPAWN_MIN: 40, SPAWN_MAX: 130, DESPAWN: 180 },
};
```
### 5.1 `world/Noise.js` —— WorldGen(核心算法)
```js
export function mulberry32(seed) { /* 标准实现:返回 ()=>[0,1) */ }
```
构造:`new WorldGen(seed)` 内部用 mulberry32(seed) 依次创建 6 个噪声场:
`h2D(基础起伏) d2D(山脊) c2D(大陆) t2D(温度) m2D(湿度) v2D(颜色抖动)`。
FBM 辅助:`fbm(n2d, x, y, octaves)`,lacunarity=2, gain=0.5,输出归一到约 [-1,1]。
```js
getHeight(x, z) {
const c = fbm(c2D, x*0.0007, z*0.0007, 3); // 大陆掩码
const b = fbm(h2D, x*0.004, z*0.004, 4); // 基础起伏
let h = (c*0.62 + b*0.38) * 14; // 丘陵 ±14
const r = 1 - Math.abs(fbm(d2D, x*0.0016, z*0.0016, 3)); // 山脊 0..1
const mMask = smoothstep(0.12, 0.50, c) * smoothstep(-0.05, 0.35, b);
h += Math.pow(r, 2.2) * 30 * mMask; // 山地最高约 +30
if (h < 0) h *= 1.35; // 海盆加深
return h;
}
slopeAt(x,z) { // 采样 ±0.6m 四点,梯度幅值 ≈ sqrt((hE-hW)^2+(hN-hS)^2)/1.2 }
getBiome(x, z, h) {
const temp = fbm(t2D, x*0.0008+37, z*0.0008-11, 2);
const moist = fbm(m2D, x*0.0008-53, z*0.0008+29, 2);
if (h > 18 || temp < -0.42) return 'snow';
if (temp > 0.42 && moist < 0) return 'desert';
if (moist > 0.12) return 'forest';
return 'plains';
}
```
**顶点配色** `getColor(biome, h, slope, x, z)`(返回 THREE.Color,写入顶点色):
- `h < -2`:水底深沙 `#3f5a52`
- `h < 1.1`:沙滩 `#d9c98e`
- `slope > 0.85 || h > 16`:岩石 `#8b8f96`
- `h > 20`:雪 `#eef3f6`
- 其余:群系草色 × (1 + v 抖动),v = `v2D(x*0.05, z*0.05)*0.06`
- plains `#6fae4e`,forest `#4c8a44`,desert `#d9c07e`,snow `#cfdde4`
群系表以 `{ id, grass, treeDensity... }` 形式导出供 Vegetation 使用。
### 5.2 `world/Chunk.js`
- 手工构建索引网格:33×33 顶点 positions/colors,索引两三角一 quad;`computeVertexNormals()`;材质共享全局一个 Lambert。
- 顶点世界坐标 = chunkOrigin + 局部步进(步长 48/32=1.5m)。
- `mesh.receiveShadow = true; castShadow = false`(性能)。
- 导出 `dispose()` 只释放 geometry。
### 5.3 `world/TerrainManager.js`
- `Map<key"cx,cz", Chunk>`;每帧:
1. 计算玩家所在 chunk 坐标;收集半径 5 内缺失 key,按距离排序入队;
2. 每帧最多构建 2 个(构建含植被);
3. 卸载距离 > 6 的 chunk(dispose + Vegetation 清理 + 资源节点注销)。
- 提供 `pregenerate(cx, cz, radius, onProgress)`:供加载屏逐帧批量预生成出生区(radius=3),配合进度条。
- 暴露 `resourceNodes` 注册表(数组):`{ type:'tree'|'rock'|'bush', x,y,z, harvested, hideInstance() }`。
### 5.4 `world/Vegetation.js`
原型几何体(类初始化时创建一次,跨 chunk 共享 geometry/material):
- 松树:双层 Cone + Cylinder 干;橡树:Icosahedron 冠 + 干;仙人掌:Capsule 绿色
- 岩石:Dodecahedron 压扁灰;浆果丛:小球深绿;花/草:微型 Cone(黄/粉随机 instanceColor)
每 chunk 散布(候选 90 点,跳过 h<1.2 或 slope>0.9):
| 群系 | 树 | 浆果丛 | 岩石 | 花/草 | 其他 |
|---|---|---|---|---|---|
| forest | 55%(松/橡混) | 8% | 6% | 6% | — |
| plains | 8% | 6% | 3% | 18% | — |
| desert | — | — | 5% | — | 仙人掌 10% |
| snow | 松 14% | — | 6% | — | — |
- 单类型单 chunk 上限 64 实例;scale 0.8–1.4 随机、Y 随机旋转;instanceColor 明度抖动。
- 资源登记:树→木头×3、岩→石头×2、丛→浆果×2。
- 采集实现:`hideInstance(im, idx)` 将该实例矩阵设为零缩放并 `instanceMatrix.needsUpdate=true`。
### 5.5 `world/Water.js`
600×600 Plane 跟随玩家(x/z 吸附到 10m 格避免纹理游移感),y = SEA_LEVEL−0.15 + sin(t)*0.05 微浮动;`MeshPhongMaterial({ color:#2e7fb8, transparent:true, opacity:0.72, shininess:120 })`,fog 保持开启。
### 5.6 `env/SkyDome.js`
- SphereGeometry(700) BackSide ShaderMaterial(`fog:false, depthWrite:false`),每帧同步 camera.position;camera.far=1200。
- Uniforms:`uTop uHorizon uSunDir uSunColor uNight uDim`(天气变暗 0..1)。
- Fragment 要点:
```glsl
vec3 dir = normalize(vWorldPos - cameraPosition);
float up = pow(clamp(dir.y,0.,1.), 0.55);
vec3 col = mix(uHorizon, uTop, up);
if (dir.y < 0.) col = mix(uHorizon, uHorizon*0.45, clamp(-dir.y*3.,0.,1.));
float s = max(dot(dir, uSunDir), 0.);
col += uSunColor * (pow(s,900.)*1.2 + pow(s,18.)*0.25); // 日盘+晕
float m = max(dot(dir, -uSunDir), 0.);
col += vec3(0.85,0.88,1.0) * pow(m,1600.) * uNight * 0.9; // 月盘
// 星星:dir 映射 floor(dir*220) hash,step(0.9985,h)*uNight 叠加白点
col *= (1.0 - uDim*0.35);
```
### 5.7 `env/DayNightCycle.js`
驱动:平行光 sunLight(castShadow,shadow 正交范围 ±60、mapSize 2048、bias −0.0005,`light.target` 必须加入场景并每帧指向玩家)、HemisphereLight、scene.fog 颜色、SkyDome uniforms。
按太阳仰角 e 分三段插值(用 smoothstep 过渡带):
| 参数 | 白天 e>0.25 | 日落带 e∈[−0.12,0.25] | 夜晚 e<−0.12 |
|---|---|---|---|
| 天顶 | `#4890e0` | →`#35507e` | `#0a1026` |
| 地平 | `#bcd8ea` | →`#ff9e5e` | `#16203a` |
| 雾 | `#cfe3ee` | →`#e8a76b` | `#10182b` |
- `sunLight.intensity = max(e,0)^0.6 × 1.25 × (1−cloudDim×0.6) + 0.02`;白天色暖白→日落橙 `#ffb36b`。
- **夜晚月光模式**:e<0 时将平行光转到 −sunDir 方向,色 `#7788bb`、强度 0.15(保留微弱阴影)。
- hemi 强度 `0.25 + max(e,0)*0.55`,天空色随天顶色、地面色随草绿。
- 对外暴露 `t`(0..1)、`hours`、`phase`('dawn'|'day'|'dusk'|'night') 供 HUD 显示 ☀️🌙 等。
### 5.8 `env/Weather.js`
状态机:每 50–140s 按权重切换 CLEAR .45 / CLOUDY .25 / RAIN .20 / FOG .10。参数组并整体向目标 lerp(速率 0.5/s):
| 状态 | cloudDim | greyMix | rain | fogFar倍率 | fogNear倍率 |
|---|---|---|---|---|---|
| CLEAR | 0 | 0 | 0 | 1.0 | 1.0 |
| CLOUDY | 0.45 | 0.25 | 0 | 0.85 | 0.9 |
| RAIN | 0.70 | 0.55 | 1 | 0.55 | 0.6 |
| FOG | 0.30 | 0.35 | 0 | 0.28 | 0.5 |
雨:Points 1500 顶点,盒 80×40×80 跟随相机,y -= 22*dt 循环回绕,PointsMaterial 尺寸 0.08、透明度 ∝ rain,`fog:false, frustumCulled=false`。greyMix 用于把天空 uniform 向灰色靠。
### 5.9 `entity/CharacterMesh.js`(人形)
Box 组合:躯干(0.55,0.65,0.32)、头(0.34³)+脸部贴片、双臂 Group(肩部轴点,长 0.55)、双腿 Group(髋部轴点,长 0.6)。肤色 `#e8b98a`、衣青 `#3aa6a0`、裤 `#4a5568`。所有 Mesh castShadow。
动画接口:`setWalk(phase, speedFactor)` 四肢摆动 sin(phase)*0.7(腿反相、臂反相);`playAttack()` 右臂 0.35s 抬起→劈下时间线;`update(dt)` 推进动画。
### 5.10 `entity/Player.js`
- 状态:pos(Vector3)、vel、yaw/pitch(鼠标)、grounded、swimming、hp、lastCombatTime、equippedWeapon。
- 相机:第三人称轨道,偏移 target=pos+(0,1.5,0);camDist 滚轮 3–12 默认 7;pitch 夹 [-1.2, 0.55] rad;**camY 至少高于地形 getHeight(camX,camZ)+0.5**。
- 移动:输入向量按相机 yaw 旋转;速度目标 = walk/sprint/swim;水平速度朝目标 lerp(地面 accel 40、空中 12,帧率无关写法 `1-exp(-k*dt)`)。
- 物理:vy -= GRAVITY*dt;groundH=getHeight(x,z);y ≤ groundH → 落地。游泳判定 groundH < SEA_LEVEL−1.1:y 收敛至 SEA−0.95、速度 SWIM、Space 给 +4 起跳力用于上岸。
- 身体朝向平滑转向移动方向;移动时推进 CharacterMesh.setWalk 相位(速度越快相位越快)。
- 受击 `takeDamage(n)`:无敌帧内忽略;hp−n;发总线事件 `player:hp`;触发 UI 红晕;hp≤0 → `player:death`。
- 死亡处理在 Game:黑屏 2.5s 后复位到 spawnPoint、满血、短暂无敌。
- 脱战回血:距上次受击/攻击 >6s 时 hp=min(max, hp+4dt)。
### 5.11 生物 FSM(`Creature.js` 基类 + 子类)
基类字段:mesh(Group)、hp、speed、state、stateTimer、knockbackVel、flashTimer。
`takeDamage(dmg, fromPos)`:闪红(遍历材质 emissive 置红 0.15s)、击退 impulse KNOCKBACK 远离 fromPos、hp≤0 → die()。
`die()`:掉落物交给 Spawner.spawnDrop(item,count,pos);自身下沉缩小 0.6s 后移除。
**鹿 Animal**(造型:躯干 box(0.9,0.5,0.45) 土黄 `#c08a5a`、颈+头、4 圆柱腿、雄性角锥;奔跑四腿摆动):
- HP30;idle(2–4s) ↔ wander(随机 8m 内目标点,速度 1.6);玩家 <9m → flee(远离方向速度 8.5,持续 4s);腿动画频率随速度。
**史莱姆 Monster**(压扁球 r0.45 绿 `#6fce6f` opacity .95 + 双黑眼;跳跃式位移:y=|sin|*0.3、挤压 scale):
- HP45;wander 1.6;玩家 <13m → chase 4.2;<1.9m 进入 attack:前摇 0.4s(放大蓄力)后若仍在 2.2m 内对玩家 takeDamage(12),冷却 1.2s。
- 掉落:粘液×1–2。鹿掉落:兽皮×2。
### 5.12 `systems/Spawner.js`
- 每 2s tick:统计现存鹿/怪数量,不足则补(生成点=玩家周围 40–130m 随机角度,要求 getHeight>1 且 slope<0.6,重试 8 次);>180m 的生物移除(dispose mesh)。
- `creatures` 数组;每帧 update 全部 `creature.update(dt, ctx)`(ctx 含 playerPos、getHeight 引用)。
- 掉落物管理 `drops[]`:OctahedronGeometry(0.22) 按 ITEM 颜色着色,悬浮 sin 波动+自转;提供 `nearestDrop(pos, range)`。
### 5.13 `systems/Combat.js`
- `playerAttack(player, spawner)`:冷却检查 → CharacterMesh.playAttack() → 遍历活体生物:水平距离 ≤RANGE(2.6) 且方向夹角 ≤CONE_HALF(35°) → `creature.takeDamage(weapon.dmg, playerPos)`。
- 武器伤害来源:Inventory.equipped('sword'→16 / 'axe'→11 / null→拳 6);斧头另有 chopBonus=2(采集加成,见 Interaction)。
### 5.14 `systems/Inventory.js` + `Crafting.js`
物品注册表(emoji 作图标,Windows 下渲染良好):
| id | 名称 | 图标 | 备注 |
|---|---|---|---|
| wood | 木头 | 🪵 | 色 `#8a5a33` |
| stone | 石头 | 🪨 | 色 `#9aa0a6` |
| berry | 浆果 | 🫐 | 食用 +15 HP |
| cooked_berry | 烤浆果 | 🔴 | 食用 +30 HP |
| hide | 兽皮 | 🟫 | 色 `#c9a86a` |
| slime | 粘液 | 🟢 | 色 `#7ee08a` |
| sword | 石剑 | ⚔️ | 武器 dmg16 |
| axe | 石斧 | 🪓 | 武器 dmg11 + chopBonus2 |
- Inventory:`counts Map`、堆叠上限 999、`add/remove/count/has`;每次变动 emit `inv:changed`。
- equipped 字段:'sword'|'axe'|null;装备/卸装备也发 `inv:changed`。
- 配方:`sword ← wood2+stone3`;`axe ← wood3+stone2`;`cooked_berry ← berry2`。
- Crafting.craft(id):校验材料 → 扣除 → 产物入库(武器类自动 equip)→ toast 反馈。
### 5.15 `systems/Interaction.js`
每帧查询最优目标并经总线 `prompt:update {text}|null`:
1. 掉落物 ≤2.6m → 「[E] 拾取 木头×3」
2. 资源节点 ≤3.4m 且未 harvest → 「[E] 砍伐 树木 / 采集 石头 / 采摘 浆果」(树需 yield×chopBonus 若装备斧)
3. E 键触发:资源 → 产物入包 + hideInstance + toast「+3 木头」;掉落物 → 入包并从 drops 移除。
### 5.16 UI 组件
- **HUD**:左上血条(红填充+数字);右上时钟(HH:MM + phase emoji 🌅☀️🌇🌙);中心准星圆点;底部中交互提示条;左下 toast 堆栈(2.5s 淡出);全屏红色内阴影 vignette(受击时闪现);死亡遮罩(渐黑 + 「你倒下了…」)。
- **InventoryUI**:Tab 切换背包面板:网格槽位(图标+数量徽标+名称 tooltip);可点击交互——berry/cooked_berry 点击食用、weapon 点击装备/卸下(高亮描边)。C 切换合成面板:配方行显示 图标+需求量(够绿/缺红)+ 合成按钮(材料不足 disabled)。打开面板时 `exitPointerLock`,关闭时尝试 `requestPointerLock()`。
- **LoadingScreen**:标题「微光大陆」+ 副标题 + 进度条(pregenerate 回调)+ 完成后变「点击进入世界」按钮 + 底部小字「重置存档」链接(清 localStorage 并 reload)。
- **暂停提示**:pointerlock 丢失且无面板开启时显示半透明「点击继续」,点击画布重新锁定。
- CSS 风格:深色玻璃拟态 `rgba(10,16,24,.55)` + backdrop-filter blur + 圆角 + 主色 `#57d9c9`;system-ui 字体。
### 5.17 EventBus 事件名约定
`inv:changed`、`toast(msg)`、`prompt:update`、`player:hp(hp,max)`、`player:death`、`time:tick(hours,phase)`、`weather:change(state)`。
### 5.18 存档格式
localStorage key `gleaming-continent-save`:
```json
{ "seed":12345, "px":0,"pz":0, "time":0.3, "hp":87,
"inv":{"wood":5,"stone":2}, "equipped":"sword" }
```
每 5s + beforeunload 写入;Game 启动时若有档则恢复(seed/位置/时间/背包/血量/装备),否则随机 seed 并螺旋搜索出生点(从原点步进 8m 找 h∈[2,8] 且 slope<0.5 的点)。
---
## 六、Game.js 编排与主循环
```
constructor(container):
renderer(WebGLRenderer antialias, setPixelRatio(min(dpr,2)),
outputColorSpace=SRGB, shadowMap PCFSoft)
scene(fog=Fog(#cfe3ee, 60, 210)) + camera(PerspectiveCamera 60°, far 1200)
bus, input(Input), worldGen(Noise)
sky, daynight, weather, water, terrain(TerrainManager), vegetation 由 terrain 内部使用
inventory, crafting, combat, interaction, spawner
ui: LoadingScreen → pregenerate 出生区(radius 3, 进度回调) → 放置玩家
→ HUD/InventoryUI 绑定总线 → 显示「点击进入世界」
loop(rAF): dt = min(clock.getDelta(), 0.05)
input 快照 → player.update(dt) → terrain.update(playerPos)
→ daynight.update(dt) → weather.update(dt)
→ spawner.update(dt)(内部更新生物与掉落物)
→ combat 冷却/interaction 目标查询 → hud 更新 → renderer.render
```
Input 要点:keydown/up 维护 Set;mousedown 左键→combat.tryAttack;mousemove 仅 pointerLock 时累加 yaw/pitch(movementX/Y);wheel 调 camDist;E/Tab/C 转发;`document.pointerlockchange` 驱动暂停提示。
index.html 最小骨架:
```html
<!doctype html><html lang="zh-CN"><head>
<meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>微光大陆 · Gleaming Continent</title></head>
<body><div id="app"></div><script type="module" src="/src/main.js"></script></body></html>
```
## 七、操作方式
WASD 移动 · Space 跳/游泳上浮 · Shift 冲刺 · 鼠标视角(Pointer Lock) · 滚轮缩放镜头 · 左键攻击 · E 采集/拾取 · Tab 背包 · C 合成 · Esc 解锁鼠标
## 八、实施顺序(建议按此分阶段提交,每阶段可独立运行验证)
1. 安装依赖 → index.html/style.css/main.js/config.js/core 三件套 → 空场景转起来(天空色背景即可)
2. Noise + Chunk + TerrainManager + Water:站在原点看地形流式加载
3. SkyDome + DayNightCycle + Weather:观察一轮完整昼夜与降雨
4. CharacterMesh + Player:能跑能跳能游,相机跟随
5. Vegetation:群系植被与资源点出现
6. Creature/Animal/Monster + Spawner:鹿逃逸、史莱姆追击
7. Combat + Interaction + Inventory + Crafting 数据层
8. HUD + InventoryUI + LoadingScreen + 暂停提示
9. 存档 + 出生点选址 + 数值打磨
10. 构建验证 + 验收清单
## 九、验收清单(实现完成后逐项人工核验)
1. `npm run dev` 无报错;浏览器控制台无错误;`npm run build` 成功产出 dist。
2. 出生点地形/植被/水面正常;四处奔跑 chunk 流式加载无明显卡顿(雾掩盖边缘)。
3. 观察一轮昼夜(≥8 分钟或临时改 DAY_LENGTH 加速验证):天空/光照/雾/星空变化正确。
4. 等待或调试触发四种天气:云量变暗、雨天粒子、浓雾可见度变化。
5. 接近鹿会逃逸;史莱姆发现玩家追击并造成伤害(血条下降+红晕)。
6. 左键击杀史莱姆 → 掉落物 → E 拾取入包;砍树/采石获得木头/石头(装备斧后砍树产量翻倍)。
7. Tab 背包可见物品并可食用浆果回血;C 合成石剑后攻击力提升。
8. 玩家死亡 → 黑屏过渡 → 出生点复活满血。
9. 刷新页面:seed/位置/背包/时间/血量恢复;「重置存档」生效。
10. 性能基准:中档笔记本 ~60fps(可视半径 5、阴影 2048、pixelRatio≤2 的前提下)。
## 十、风险、取舍与实现注意事项
**已知取舍**
- 无外部模型/音效:视觉全靠程序化几何与配色,风格化抽象表现;音效不在本期范围。
- 世界修改不持久:chunk 卸载即重置(砍掉的树重生成),原型可接受。
- 不做植被/角色物理碰撞(可穿树),仅地形高度碰撞。
**给实现 Agent 的 three/环境注意事项(易错点)**
- three 仅 ESM:`import * as THREE from 'three'`;本项目不需要 examples/jsm addons。
- 平行光阴影:`scene.add(light.target)` 必不可少,且每帧更新 target.position 到玩家处,否则阴影方向错。
- `MeshLambertMaterial` 在现代 three 中支持 `flatShading` 与 `vertexColors`,勿再引入 Phong(水面除外)。
- InstancedMesh 必须**先统计再精确分配 count**;批量写完矩阵/颜色后置 `instanceMatrix.needsUpdate` / `instanceColor.needsUpdate`。
- 卸载只 dispose 各 chunk 自有 geometry;共享材质/原型几何绝不 dispose。
- simplex-noise v4:`createNoise2D(rng)`,rng 是返回 [0,1) 的函数(mulberry32 兼容)。
- Pointer Lock:只能用户手势中请求;Esc 退出后 Chrome 有 ~1.25s 冷却,重锁失败属正常,用「点击继续」覆盖层兜底。
- 每帧 dt 上限 0.05 防止切标签页回来瞬移;lerp 用 `1-exp(-k*dt)` 保证帧率无关。
- Windows + Node 24 环境,命令均在 `C:\Users\32382\Desktop\demo` 下执行。
还要很久捏
各自用原生pi-agent和qwen code
Hy3版本:微光大陆 · Gleaming Continent
Ox Alpha Free版本:微光大陆 · Gleaming Continent