mlmihjaz Claude Opus 4.8 commited on
Commit Β·
044f11b
1
Parent(s): ffc6336
Even lake color, remove shark, smaller tree tops, crane dip, grass flowers, slower waves
Browse files- Water: flatten surface gradient so the lake is one even colour (a strong
light->dark gradient made half look lighter); slow the wave motion and
texture scroll.
- Scene3D: disable the shark (kept the class/import).
- Forest: shrink the two upper cone puffs and pull them down so tree tips
are smaller and less tall.
- Crane: deepen the head dip so the beak reaches the water surface.
- Ground: scatter ~280 tiny yellow/red wildflowers through the grass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- src/scene/Crane.js +3 -2
- src/scene/Forest.js +6 -5
- src/scene/Ground.js +25 -0
- src/scene/Scene3D.js +3 -2
- src/scene/Water.js +10 -9
src/scene/Crane.js
CHANGED
|
@@ -127,8 +127,9 @@ export class Crane {
|
|
| 127 |
// Occasional head dip β slow sine; the neck pivot rotates around Z to swing the head down
|
| 128 |
this.dipPhase += dt * 0.6;
|
| 129 |
const dipCurve = Math.sin(this.dipPhase) * 0.5 + 0.5; // 0..1
|
| 130 |
-
// Mostly stays raised; every cycle dips for a brief moment
|
| 131 |
-
|
|
|
|
| 132 |
this.neckPivot.rotation.z = -dipAmt * 1.2;
|
| 133 |
// Trigger a crane call on the rising edge of each dip (when it bends to eat).
|
| 134 |
const dipping = dipAmt > 0.6;
|
|
|
|
| 127 |
// Occasional head dip β slow sine; the neck pivot rotates around Z to swing the head down
|
| 128 |
this.dipPhase += dt * 0.6;
|
| 129 |
const dipCurve = Math.sin(this.dipPhase) * 0.5 + 0.5; // 0..1
|
| 130 |
+
// Mostly stays raised; every cycle dips for a brief moment. Deeper now so
|
| 131 |
+
// the beak actually reaches the water surface instead of stopping short.
|
| 132 |
+
const dipAmt = Math.pow(dipCurve, 6) * 1.4;
|
| 133 |
this.neckPivot.rotation.z = -dipAmt * 1.2;
|
| 134 |
// Trigger a crane call on the rising edge of each dip (when it bends to eat).
|
| 135 |
const dipping = dipAmt > 0.6;
|
src/scene/Forest.js
CHANGED
|
@@ -96,12 +96,13 @@ export class Forest {
|
|
| 96 |
// so the puff silhouettes fuse cleanly instead of leaving a tapered gap.
|
| 97 |
const trunkGeo = new CylinderGeometry(0.07, 0.10, 0.35, 8);
|
| 98 |
const coneA = new ConeGeometry(0.55, 1.05, 10); // bottom puff
|
| 99 |
-
const coneB = new ConeGeometry(0.
|
| 100 |
-
const coneC = new ConeGeometry(0.
|
| 101 |
-
// Vertical offsets β
|
|
|
|
| 102 |
const Y_A = 0.85; // bottom puff sits on the trunk top
|
| 103 |
-
const Y_B = 1.
|
| 104 |
-
const Y_C = 1.
|
| 105 |
|
| 106 |
const pickMat = () => this.foliageMats[Math.floor(Math.random() * this.foliageMats.length)];
|
| 107 |
|
|
|
|
| 96 |
// so the puff silhouettes fuse cleanly instead of leaving a tapered gap.
|
| 97 |
const trunkGeo = new CylinderGeometry(0.07, 0.10, 0.35, 8);
|
| 98 |
const coneA = new ConeGeometry(0.55, 1.05, 10); // bottom puff
|
| 99 |
+
const coneB = new ConeGeometry(0.36, 0.72, 10); // mid puff (smaller)
|
| 100 |
+
const coneC = new ConeGeometry(0.19, 0.42, 10); // tip (smaller)
|
| 101 |
+
// Vertical offsets β tops pulled down + shrunk so the triangle tips are
|
| 102 |
+
// smaller and sit closer to the tree body (less tall/pointy).
|
| 103 |
const Y_A = 0.85; // bottom puff sits on the trunk top
|
| 104 |
+
const Y_B = 1.18; // pulled down so coneB base hides inside coneA
|
| 105 |
+
const Y_C = 1.52; // pulled down so the smaller tip sits close to coneB
|
| 106 |
|
| 107 |
const pickMat = () => this.foliageMats[Math.floor(Math.random() * this.foliageMats.length)];
|
| 108 |
|
src/scene/Ground.js
CHANGED
|
@@ -331,9 +331,34 @@ export class Ground {
|
|
| 331 |
this.scene = scene;
|
| 332 |
this._buildGround();
|
| 333 |
this._buildGrassBlades();
|
|
|
|
| 334 |
this._buildGoats();
|
| 335 |
}
|
| 336 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
_buildGround() {
|
| 338 |
const geo = new PlaneGeometry(200, 80, 1, 1);
|
| 339 |
this.groundTexture = makeGroundTexture();
|
|
|
|
| 331 |
this.scene = scene;
|
| 332 |
this._buildGround();
|
| 333 |
this._buildGrassBlades();
|
| 334 |
+
this._buildGrassFlowers();
|
| 335 |
this._buildGoats();
|
| 336 |
}
|
| 337 |
|
| 338 |
+
_buildGrassFlowers() {
|
| 339 |
+
// Tiny wildflowers scattered through the grass β half yellow, half red.
|
| 340 |
+
const COUNT = 280;
|
| 341 |
+
const geo = new SphereGeometry(0.055, 8, 6);
|
| 342 |
+
this.flowers = new InstancedMesh(geo, new MeshLambertMaterial(), COUNT);
|
| 343 |
+
const o = new Object3D();
|
| 344 |
+
const yellow = new Color(0xffd23a);
|
| 345 |
+
const red = new Color(0xe5392b);
|
| 346 |
+
for (let i = 0; i < COUNT; i++) {
|
| 347 |
+
const x = (Math.random() * 2 - 1) * 58;
|
| 348 |
+
const z = -3 - Math.random() * 14; // same band as the grass tufts
|
| 349 |
+
const s = 0.7 + Math.random() * 0.8;
|
| 350 |
+
o.position.set(x, 0.18, z);
|
| 351 |
+
o.scale.set(s, s * 0.7, s); // slightly flattened bloom
|
| 352 |
+
o.rotation.set(0, Math.random() * Math.PI, 0);
|
| 353 |
+
o.updateMatrix();
|
| 354 |
+
this.flowers.setMatrixAt(i, o.matrix);
|
| 355 |
+
this.flowers.setColorAt(i, Math.random() < 0.5 ? yellow : red);
|
| 356 |
+
}
|
| 357 |
+
this.flowers.instanceMatrix.needsUpdate = true;
|
| 358 |
+
if (this.flowers.instanceColor) this.flowers.instanceColor.needsUpdate = true;
|
| 359 |
+
this.scene.add(this.flowers);
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
_buildGround() {
|
| 363 |
const geo = new PlaneGeometry(200, 80, 1, 1);
|
| 364 |
this.groundTexture = makeGroundTexture();
|
src/scene/Scene3D.js
CHANGED
|
@@ -63,7 +63,8 @@ export class Scene3D {
|
|
| 63 |
// Coral/seaweed/rocks built BEFORE fish + shark so they layer correctly underneath.
|
| 64 |
this.aquariumDecor = new AquariumDecor(this.scene, bounds);
|
| 65 |
this.fish = new Fish(this.scene, bounds);
|
| 66 |
-
|
|
|
|
| 67 |
// Surface life β lily pads, frogs, jumping fish (gravity-accurate arcs)
|
| 68 |
this.lakeLife = new LakeLife(this.scene, bounds);
|
| 69 |
// One crane per side β smaller, mirrored so they face each other.
|
|
@@ -179,7 +180,7 @@ export class Scene3D {
|
|
| 179 |
this.water.update(dt, el);
|
| 180 |
this.aquariumDecor.update(dt, el);
|
| 181 |
this.fish.update(dt, el);
|
| 182 |
-
this.shark.update(dt, el);
|
| 183 |
this.lakeLife.update(dt, el);
|
| 184 |
for (const cr of this.cranes) cr.update(dt, el);
|
| 185 |
this.penguins.update(dt, el);
|
|
|
|
| 63 |
// Coral/seaweed/rocks built BEFORE fish + shark so they layer correctly underneath.
|
| 64 |
this.aquariumDecor = new AquariumDecor(this.scene, bounds);
|
| 65 |
this.fish = new Fish(this.scene, bounds);
|
| 66 |
+
// Shark disabled for now (not wanted). Keep the import/class for later.
|
| 67 |
+
this.shark = null;
|
| 68 |
// Surface life β lily pads, frogs, jumping fish (gravity-accurate arcs)
|
| 69 |
this.lakeLife = new LakeLife(this.scene, bounds);
|
| 70 |
// One crane per side β smaller, mirrored so they face each other.
|
|
|
|
| 180 |
this.water.update(dt, el);
|
| 181 |
this.aquariumDecor.update(dt, el);
|
| 182 |
this.fish.update(dt, el);
|
| 183 |
+
if (this.shark) this.shark.update(dt, el);
|
| 184 |
this.lakeLife.update(dt, el);
|
| 185 |
for (const cr of this.cranes) cr.update(dt, el);
|
| 186 |
this.penguins.update(dt, el);
|
src/scene/Water.js
CHANGED
|
@@ -25,12 +25,13 @@ function makeSurfaceTexture() {
|
|
| 25 |
const c = document.createElement('canvas');
|
| 26 |
c.width = 1024; c.height = 1024;
|
| 27 |
const ctx = c.getContext('2d');
|
| 28 |
-
// Professional lake blue β
|
|
|
|
|
|
|
| 29 |
const g = ctx.createLinearGradient(0, 0, 0, 1024);
|
| 30 |
-
g.addColorStop(0, '#
|
| 31 |
-
g.addColorStop(0.
|
| 32 |
-
g.addColorStop(
|
| 33 |
-
g.addColorStop(1, '#0A3A60');
|
| 34 |
ctx.fillStyle = g;
|
| 35 |
ctx.fillRect(0, 0, 1024, 1024);
|
| 36 |
// Tiny zigzag/feather wavelets β short, irregular, multi-directional.
|
|
@@ -272,16 +273,16 @@ export class Water {
|
|
| 272 |
applyPalette(_p) { /* could tint water colour by time-of-day later */ }
|
| 273 |
|
| 274 |
update(dt, elapsed) {
|
| 275 |
-
// scroll the surface ripples
|
| 276 |
-
this.surfTex.offset.x = (elapsed * 0.
|
| 277 |
-
this.surfTex.offset.y = (elapsed * 0.
|
| 278 |
// Open-sea idle vertex waves β five layered sinusoids with different
|
| 279 |
// directions, frequencies, and time speeds. The mixed directions break
|
| 280 |
// up the parallel-ridge look of a single-axis sin/cos and read as small
|
| 281 |
// irregular wavelets, not straight lines.
|
| 282 |
const pos = this.surfGeo.attributes.position;
|
| 283 |
const segX = 111; // 110 segments + 1
|
| 284 |
-
const t = elapsed;
|
| 285 |
for (let i = 0; i < pos.count; i++) {
|
| 286 |
const xi = i % segX;
|
| 287 |
const yi = Math.floor(i / segX);
|
|
|
|
| 25 |
const c = document.createElement('canvas');
|
| 26 |
c.width = 1024; c.height = 1024;
|
| 27 |
const ctx = c.getContext('2d');
|
| 28 |
+
// Professional lake blue β kept nearly uniform across the sheet so the lake
|
| 29 |
+
// reads as one even colour (a strong top-to-bottom gradient made one half of
|
| 30 |
+
// the surface look noticeably lighter than the other).
|
| 31 |
const g = ctx.createLinearGradient(0, 0, 0, 1024);
|
| 32 |
+
g.addColorStop(0, '#3C8BBE');
|
| 33 |
+
g.addColorStop(0.5, '#357FB0');
|
| 34 |
+
g.addColorStop(1, '#2E72A2');
|
|
|
|
| 35 |
ctx.fillStyle = g;
|
| 36 |
ctx.fillRect(0, 0, 1024, 1024);
|
| 37 |
// Tiny zigzag/feather wavelets β short, irregular, multi-directional.
|
|
|
|
| 273 |
applyPalette(_p) { /* could tint water colour by time-of-day later */ }
|
| 274 |
|
| 275 |
update(dt, elapsed) {
|
| 276 |
+
// scroll the surface ripples (slow drift)
|
| 277 |
+
this.surfTex.offset.x = (elapsed * 0.015) % 1;
|
| 278 |
+
this.surfTex.offset.y = (elapsed * 0.010) % 1;
|
| 279 |
// Open-sea idle vertex waves β five layered sinusoids with different
|
| 280 |
// directions, frequencies, and time speeds. The mixed directions break
|
| 281 |
// up the parallel-ridge look of a single-axis sin/cos and read as small
|
| 282 |
// irregular wavelets, not straight lines.
|
| 283 |
const pos = this.surfGeo.attributes.position;
|
| 284 |
const segX = 111; // 110 segments + 1
|
| 285 |
+
const t = elapsed * 0.4; // slow, gentle wave motion
|
| 286 |
for (let i = 0; i < pos.count; i++) {
|
| 287 |
const xi = i % segX;
|
| 288 |
const yi = Math.floor(i / segX);
|