Merge branch 'main' into kimi/issue-430
This commit is contained in:
@@ -55,7 +55,7 @@
|
||||
camera.position.set(0, 2.0, 4.5);
|
||||
|
||||
// --- Build scene elements ---
|
||||
const { crystalBall, fireLight } = buildRoom(scene);
|
||||
const { crystalBall, crystalLight, fireLight, candleLights } = buildRoom(scene);
|
||||
const wizard = createWizard();
|
||||
scene.add(wizard.group);
|
||||
const familiar = createFamiliar();
|
||||
@@ -93,13 +93,24 @@
|
||||
familiar.update(dt);
|
||||
controls.update();
|
||||
|
||||
// Crystal ball subtle rotation
|
||||
// Crystal ball subtle rotation + pulsing glow
|
||||
crystalBall.rotation.y += dt * 0.3;
|
||||
const pulse = 0.3 + Math.sin(Date.now() * 0.002) * 0.15;
|
||||
crystalLight.intensity = pulse;
|
||||
crystalBall.material.emissiveIntensity = pulse * 0.5;
|
||||
|
||||
// Fireplace flicker
|
||||
fireLight.intensity = 1.2 + Math.sin(Date.now() * 0.005) * 0.15
|
||||
+ Math.sin(Date.now() * 0.013) * 0.1;
|
||||
|
||||
// Candle flicker — each offset slightly for variety
|
||||
const now = Date.now();
|
||||
for (let i = 0; i < candleLights.length; i++) {
|
||||
candleLights[i].intensity = 0.4
|
||||
+ Math.sin(now * 0.007 + i * 2.1) * 0.1
|
||||
+ Math.sin(now * 0.019 + i * 1.3) * 0.05;
|
||||
}
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
|
||||
@@ -7,10 +7,13 @@
|
||||
|
||||
import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js";
|
||||
|
||||
const WALL_COLOR = 0x1a1a2e;
|
||||
const WALL_COLOR = 0x2a2a3e;
|
||||
const FLOOR_COLOR = 0x1a1a1a;
|
||||
const DESK_COLOR = 0x3e2723;
|
||||
const DESK_TOP_COLOR = 0x4e342e;
|
||||
const BOOK_COLORS = [0x8b1a1a, 0x1a3c6e, 0x2e5e3e, 0x6e4b1a, 0x4a1a5e, 0x5e1a2e];
|
||||
const CANDLE_WAX = 0xe8d8b8;
|
||||
const CANDLE_FLAME = 0xffaa33;
|
||||
|
||||
/**
|
||||
* Build the room and add it to the given scene.
|
||||
@@ -33,6 +36,7 @@ export function buildRoom(scene) {
|
||||
const wallMat = new THREE.MeshStandardMaterial({
|
||||
color: WALL_COLOR,
|
||||
roughness: 0.95,
|
||||
metalness: 0.05,
|
||||
});
|
||||
const backWall = new THREE.Mesh(wallGeo, wallMat);
|
||||
backWall.position.set(0, 2, -4);
|
||||
@@ -105,6 +109,8 @@ export function buildRoom(scene) {
|
||||
thickness: 0.3,
|
||||
transparent: true,
|
||||
opacity: 0.7,
|
||||
emissive: new THREE.Color(0x88ccff),
|
||||
emissiveIntensity: 0.3,
|
||||
});
|
||||
const crystalBall = new THREE.Mesh(ballGeo, ballMat);
|
||||
crystalBall.position.set(0.15, 1.01, -0.3);
|
||||
@@ -121,10 +127,97 @@ export function buildRoom(scene) {
|
||||
base.position.set(0.15, 0.9, -0.3);
|
||||
scene.add(base);
|
||||
|
||||
// Crystal ball inner glow
|
||||
const innerLight = new THREE.PointLight(0x88ccff, 0.3, 2);
|
||||
innerLight.position.copy(crystalBall.position);
|
||||
scene.add(innerLight);
|
||||
// Crystal ball inner glow (pulsing)
|
||||
const crystalLight = new THREE.PointLight(0x88ccff, 0.3, 2);
|
||||
crystalLight.position.copy(crystalBall.position);
|
||||
scene.add(crystalLight);
|
||||
|
||||
// --- Bookshelf (right wall) ---
|
||||
const shelfMat = new THREE.MeshStandardMaterial({
|
||||
color: DESK_COLOR,
|
||||
roughness: 0.7,
|
||||
});
|
||||
|
||||
// Bookshelf frame — tall backing panel
|
||||
const shelfBack = new THREE.Mesh(
|
||||
new THREE.BoxGeometry(1.4, 2.2, 0.06),
|
||||
shelfMat
|
||||
);
|
||||
shelfBack.position.set(3.0, 1.1, -2.0);
|
||||
scene.add(shelfBack);
|
||||
|
||||
// Shelves (4 horizontal planks)
|
||||
const shelfGeo = new THREE.BoxGeometry(1.4, 0.04, 0.35);
|
||||
const shelfYs = [0.2, 0.7, 1.2, 1.7];
|
||||
for (const sy of shelfYs) {
|
||||
const shelf = new THREE.Mesh(shelfGeo, shelfMat);
|
||||
shelf.position.set(3.0, sy, -1.85);
|
||||
scene.add(shelf);
|
||||
}
|
||||
|
||||
// Side panels
|
||||
const sidePanelGeo = new THREE.BoxGeometry(0.04, 2.2, 0.35);
|
||||
for (const sx of [-0.68, 0.68]) {
|
||||
const side = new THREE.Mesh(sidePanelGeo, shelfMat);
|
||||
side.position.set(3.0 + sx, 1.1, -1.85);
|
||||
scene.add(side);
|
||||
}
|
||||
|
||||
// Books on shelves — colored boxes
|
||||
const bookGeo = new THREE.BoxGeometry(0.08, 0.28, 0.22);
|
||||
const booksPerShelf = [5, 4, 5, 3];
|
||||
for (let s = 0; s < shelfYs.length; s++) {
|
||||
const count = booksPerShelf[s];
|
||||
const startX = 3.0 - (count * 0.12) / 2;
|
||||
for (let b = 0; b < count; b++) {
|
||||
const bookMat = new THREE.MeshStandardMaterial({
|
||||
color: BOOK_COLORS[(s * 3 + b) % BOOK_COLORS.length],
|
||||
roughness: 0.8,
|
||||
});
|
||||
const book = new THREE.Mesh(bookGeo, bookMat);
|
||||
book.position.set(
|
||||
startX + b * 0.14,
|
||||
shelfYs[s] + 0.16,
|
||||
-1.85
|
||||
);
|
||||
// Slight random tilt for character
|
||||
book.rotation.z = (Math.random() - 0.5) * 0.08;
|
||||
scene.add(book);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Candles ---
|
||||
const candleLights = [];
|
||||
const candlePositions = [
|
||||
[-0.6, 0.89, -0.15], // desk left
|
||||
[0.7, 0.89, -0.4], // desk right
|
||||
[3.0, 1.78, -1.85], // bookshelf top
|
||||
];
|
||||
const candleGeo = new THREE.CylinderGeometry(0.02, 0.025, 0.12, 6);
|
||||
const candleMat = new THREE.MeshStandardMaterial({
|
||||
color: CANDLE_WAX,
|
||||
roughness: 0.9,
|
||||
});
|
||||
|
||||
for (const [cx, cy, cz] of candlePositions) {
|
||||
// Wax cylinder
|
||||
const candle = new THREE.Mesh(candleGeo, candleMat);
|
||||
candle.position.set(cx, cy + 0.06, cz);
|
||||
scene.add(candle);
|
||||
|
||||
// Flame — tiny emissive sphere
|
||||
const flameGeo = new THREE.SphereGeometry(0.015, 6, 4);
|
||||
const flameMat = new THREE.MeshBasicMaterial({ color: CANDLE_FLAME });
|
||||
const flame = new THREE.Mesh(flameGeo, flameMat);
|
||||
flame.position.set(cx, cy + 0.13, cz);
|
||||
scene.add(flame);
|
||||
|
||||
// Warm point light
|
||||
const candleLight = new THREE.PointLight(0xff8833, 0.4, 3);
|
||||
candleLight.position.set(cx, cy + 0.15, cz);
|
||||
scene.add(candleLight);
|
||||
candleLights.push(candleLight);
|
||||
}
|
||||
|
||||
// --- Lighting ---
|
||||
|
||||
@@ -150,5 +243,5 @@ export function buildRoom(scene) {
|
||||
overhead.position.set(0, 3.5, 0);
|
||||
scene.add(overhead);
|
||||
|
||||
return { crystalBall, fireLight };
|
||||
return { crystalBall, crystalLight, fireLight, candleLights };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user