@@ -200,12 +200,13 @@ export function createDonny(scene, gradientMap) { |
| 200 | 200 | state.timer += delta |
| 201 | 201 | |
| 202 | 202 | // Calculate angle to face Doug |
| 203 | + // Model faces +X, so we offset by -PI/2 |
| 203 | 204 | let angleToDoug = 0 |
| 204 | 205 | if (doug) { |
| 205 | 206 | const dougPos = doug.getPosition() |
| 206 | 207 | const dx = dougPos.x - group.position.x |
| 207 | 208 | const dz = dougPos.z - group.position.z |
| 208 | | - angleToDoug = Math.atan2(dx, dz) |
| 209 | + angleToDoug = Math.atan2(dx, dz) - Math.PI / 2 |
| 209 | 210 | } |
| 210 | 211 | |
| 211 | 212 | switch (state.mode) { |
@@ -237,16 +238,16 @@ export function createDonny(scene, gradientMap) { |
| 237 | 238 | // Rise from the water |
| 238 | 239 | const emergeProgress = Math.min(state.timer / 1.5, 1) |
| 239 | 240 | const easeOut = 1 - Math.pow(1 - emergeProgress, 3) |
| 240 | | - group.position.y = -2 + easeOut * 2.3 // Rise to 0.3 above water |
| 241 | + group.position.y = -2 + easeOut * 1.8 // Rise so rear stays submerged |
| 241 | 242 | |
| 242 | | - // Tilt upward as emerging (nose up!) |
| 243 | | - group.rotation.x = -0.3 * easeOut |
| 243 | + // Tilt nose UP, rear submerged (positive X rotation) |
| 244 | + group.rotation.x = 0.45 * easeOut |
| 244 | 245 | |
| 245 | 246 | // Slowly turn toward Doug - lugubrious, not laser tracking |
| 246 | | - group.rotation.y = lerpAngle(group.rotation.y, angleToDoug, delta * 0.3) |
| 247 | + group.rotation.y = lerpAngle(group.rotation.y, angleToDoug, delta * 0.5) |
| 247 | 248 | |
| 248 | 249 | // Gentle rocking as emerging |
| 249 | | - group.rotation.z = Math.sin(state.timer * 4) * 0.1 |
| 250 | + group.rotation.z = Math.sin(state.timer * 4) * 0.08 |
| 250 | 251 | |
| 251 | 252 | if (emergeProgress >= 1) { |
| 252 | 253 | state.mode = 'surfaced' |
@@ -256,13 +257,13 @@ export function createDonny(scene, gradientMap) { |
| 256 | 257 | break |
| 257 | 258 | |
| 258 | 259 | case 'surfaced': |
| 259 | | - // Bob gently on the surface |
| 260 | | - group.position.y = 0.3 + Math.sin(elapsed * 2) * 0.08 |
| 261 | | - group.rotation.z = Math.sin(elapsed * 1.5) * 0.05 |
| 260 | + // Bob gently, rear stays in water |
| 261 | + group.position.y = -0.2 + Math.sin(elapsed * 2) * 0.06 |
| 262 | + group.rotation.z = Math.sin(elapsed * 1.5) * 0.04 |
| 262 | 263 | |
| 263 | | - // Keep tilted upward, slowly drifting gaze toward Doug |
| 264 | | - group.rotation.x = -0.25 + Math.sin(elapsed * 1.5) * 0.05 |
| 265 | | - group.rotation.y = lerpAngle(group.rotation.y, angleToDoug, delta * 0.2) |
| 264 | + // Keep tilted - nose up, tail submerged |
| 265 | + group.rotation.x = 0.4 + Math.sin(elapsed * 1.5) * 0.05 |
| 266 | + group.rotation.y = lerpAngle(group.rotation.y, angleToDoug, delta * 0.3) |
| 266 | 267 | |
| 267 | 268 | // Gentle flipper animation |
| 268 | 269 | leftFlipper.rotation.z = 2.2 + Math.sin(elapsed * 3) * 0.15 |
@@ -286,10 +287,10 @@ export function createDonny(scene, gradientMap) { |
| 286 | 287 | // Sink back down |
| 287 | 288 | const submergeProgress = Math.min(state.timer / 1.2, 1) |
| 288 | 289 | const easeIn = Math.pow(submergeProgress, 2) |
| 289 | | - group.position.y = 0.3 - easeIn * 2.5 |
| 290 | + group.position.y = -0.2 - easeIn * 2 |
| 290 | 291 | |
| 291 | | - // Tilt nose down as submerging |
| 292 | | - group.rotation.x = -0.25 + easeIn * 0.4 |
| 292 | + // Tilt nose down as diving back under |
| 293 | + group.rotation.x = 0.4 - easeIn * 0.6 |
| 293 | 294 | |
| 294 | 295 | // Add bubbles/ripples as submerging |
| 295 | 296 | if (Math.random() < delta * 4) { |