User sketched a near-horizontal red line in the upper third of the
viewport, slightly higher on the left than on the right. Mapping
that to world coords with the camera at z=22 and 40° vfov:
- right end (entrance): y ≈ +3.5
- left end (exit): y ≈ +5
So the plane keeps cruising in the upper portion of the frame and
climbs ~1.5 world units across 40 horizontal units — about 2° of
slope. Pitch follows: rotation.z = -0.06 - p·0.01 (3.5–4° nose-up,
matching the slope). Roll softened to 0.04 ± 0.02 since the path is
nearly straight.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reroute the plane: it now enters from the upper-right (y=+6) and
exits at the lower-left (y=-10), so the path slopes downward as a
~22° descent (slope = -16/40 in world units). Pitch reversed to
match — rotation.z = +0.32 + p·0.05 (≈18-21° nose-down) so the
plane's body aligns with the descent line. Roll and yaw unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The labels in the previous commit were swapped. With the wrapper
rotated -π/2 around Y so the nose points -X, the plane's longitudinal
axis is world X (so rotation.x is roll) and its lateral axis is
world Z (so rotation.z is pitch). Earlier code applied "roll"
(positive 0.18) to .z, which was actually pitching the nose down —
no amount of tweaking rotation.x could compensate, hence the user
seeing the plane go forward+down even after sign flips.
Now:
- rotation.z = -0.30 - p·0.05 (nose up ~17–20°, climb attitude)
- rotation.x = 0.12 + small variation (subtle roll)
- rotation.y = 0 (no yaw, plane already heading the right way)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After the wrapper's -π/2 yaw, applying positive rotation.x to the
planeHolder rotates the plane around world X with the nose dropping,
not lifting (visible in the user-supplied screenshot). Flipping to
-0.18 (≈10°) puts the nose where the trajectory says it should go.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The +0.20 (≈11°) climb angle from last commit looked cartoonishly
steep. Real airliners climb at maybe 3–5° once they've cleaned up
after takeoff. Cut targetPitch to 0.06 + p·0.02 (3.5° → 4.6°).
Roll/yaw untouched.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
py was descending +7→+2, now ascending -1→+12 so the plane gains
altitude across the traversal. px stretched 18→-22 (was 16→-16) so
both endpoints sit clearly outside the visible frustum (camera at
z=22 + 40° vfov gives ~28 world-units of visible width on a 16:9
viewport). Pitch flipped from negative to +0.20 + p·0.10 to read
as nose-up for the climb. Roll/yaw unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Poly by Google airplane's default orientation in the GLB is the
opposite of what I assumed: at wrapper.rotation.y = +π/2 the nose
ended up pointing into the direction the plane was moving away from
(it looked like it was flying tail-first). Switch to -π/2 so the
nose actually leads the trajectory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two adjustments to the intro plane:
1. Autonomous cruise speed. Adds BASE_SPEED (1/28 per second of
wallclock) to targetProgress on every frame, so the plane crosses
the screen on its own in ~28 s without any input. Mouse motion
still adds a boost (one full traversal per ~4500 px of cursor
travel), which feels like the plane "speeding up" when the user
interacts. Time delta clamped to 0.1 s so the plane doesn't jump
forward after the tab returns from background.
2. Reverse direction. Plane now enters from upper-right (x = +16),
traverses to upper-left (x = -16), nose pointing -X. Wrapper rot.y
flipped to +π/2; px formula flipped; banking angles inverted so
the plane still rolls "into the turn" along its new direction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Old behaviour: plane.x mapped 1:1 to cursor.x — moving the mouse left
made the plane reverse. New behaviour: every pixel of cursor travel
(any direction) increments a progress counter from 0 to 1, the plane
position is derived from progress, and progress saturates at 1 — so
once the plane has exited stage right, it stays gone.
FULL_DISTANCE = 3500 px of cursor travel for a full traversal. The
existing lerp (0.06) still smooths the rendered position. Background
parallax still uses raw cursor X/Y (independent of plane progress).
deviceorientation handler updated symmetrically — gamma+beta deltas
push progress forward on mobile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Background was inadvertently the wrong Gemini export (an unrelated
airliner-over-mountains photo) — sorted out and replaced with the
intended aerial illustration of Antananarivo (Lake Anosy + Rova
hill + city, 487 KB, 1920px wide).
Also lifted the plane's trajectory: y goes from +7 (offscreen
upper-left) to +2 (still upper half, exiting right) instead of
+5..-2. The plane now stays clearly in the upper third of the
viewport, leaving room for the centered CTA button and the city
detail at the bottom.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
User-supplied aerial illustration of Antananarivo (Lake Anosy + Rova
hill + surrounding city, 1920px wide JPG, 241 KB) replaces the
parachute-drop video as the static intro backdrop. The video files
are deleted from /videos.
The plane no longer orbits a scroll timeline. Now:
- Page is a single viewport, no scroll, no act labels, no scroll hint.
- Mouse X (0..1) drives plane.position.x from -16 (offscreen left) to
+16 (offscreen right), with plane.position.y descending from +5 to
-2 — so the plane enters from the upper-left and exits lower-right.
- Pitch/roll/yaw lerp toward small targets that depend on mouse X, so
the plane banks naturally as it crosses.
- Background image gets a softer mouse parallax (-16/-10px) via the
existing --mx/--my CSS vars, now updated from intro-scene.js.
- Three.js cloud spheres are gone; the photo is the entire backdrop.
- ScrollTrigger + the GSAP timeline are removed; the page no longer
needs gsap at all (the script tag stayed for now in case it comes
back, but the dependency could be dropped on a future pass).
- CTA button is back to plain visible/centered, no reveal animation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drops the cylinder+box airplane built last commit in favor of a CC-BY
3D commercial airliner from Poly by Google (188 KB GLB, 11.3k tris,
hosted in assets/airplane.glb). Loaded at runtime via three/addons
GLTFLoader; importmap extended to expose the addons subpath.
Bug worth noting: a naive setFromObject + position.sub(center) +
scale.setScalar pipeline leaves the model offset by -center after
scaling because position is in pre-scale units. Fix is to wrap the
model in a Group, apply the centering offset to the inner model,
then scale the outer Group — the whole transform stays consistent.
Attribution added in two places per CC-BY 3.0:
- HTML header comment with creator + source URL + license link
- JS file header in intro-scene.js
Tone-mapping bumped to ACES filmic for a slightly nicer render.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restructure the page so the first 4 viewports of scroll drive a
Three.js scene composited on top of the Antananarivo parachute video.
What's there:
- Three.js (ESM, r158 via importmap) renders a low-poly cargo airliner
built from primitives: cylinder fuselage, cone nose, sphere cockpit
(dark glass + emissive), box wings/tail/fin, cylinder engines with
torus intakes, gold trim band, navy fin with gold logo box. No
external model file.
- Hemisphere + directional + ambient lights tuned for golden-hour fill.
- 14 cloud spheres scattered around the plane, slowly rotating.
- GSAP + ScrollTrigger drive a single progress value scrubbed against
scroll position. Inside the rAF loop, the camera arcs from rear-left
(-0.6 rad) to front-right (+1.1 rad), radius dipping mid-flight, and
the plane rolls slightly with scroll.
- Three act labels (Paris CDG / Vol cargo / Antananarivo) cross-fade at
20%/40%-60%/72% scroll positions via a chained gsap timeline.
- Gold CTA button stays opacity:0 + pointer-events:none until the last
~10% of scroll, then fades and scales in. Hover transform rebuilt
without the old mouse-parallax tilt (fights the scroll animation).
- Scroll hint pill (chevron + "Faites défiler") at the bottom of the
first viewport, fades out on first scroll event.
- prefers-reduced-motion shortcut: scroll stage hidden, CTA visible,
no animation. Page reverts to a static screen with the video bg.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>