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 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
- const dipAmt = Math.pow(dipCurve, 6) * 1.1;
 
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.40, 0.85, 10); // mid puff
100
- const coneC = new ConeGeometry(0.25, 0.55, 10); // tip
101
- // Vertical offsets β€” tightened to remove visible gaps between the triangle layers.
 
102
  const Y_A = 0.85; // bottom puff sits on the trunk top
103
- const Y_B = 1.30; // pulled down (was 1.65) so coneB base hides inside coneA
104
- const Y_C = 1.85; // pulled down (was 2.30) so coneC base hides inside coneB
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
- this.shark = new Shark(this.scene, bounds);
 
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 β€” less green/teal, deeper toward the bottom
 
 
29
  const g = ctx.createLinearGradient(0, 0, 0, 1024);
30
- g.addColorStop(0, '#7CC0E4');
31
- g.addColorStop(0.35, '#3F8FC2');
32
- g.addColorStop(0.7, '#1F6398');
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.04) % 1;
277
- this.surfTex.offset.y = (elapsed * 0.025) % 1;
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);