diff --git a/frontend/src/lib/zen/aquarium.js b/frontend/src/lib/zen/aquarium.js index 11531d1..e29d3ec 100644 --- a/frontend/src/lib/zen/aquarium.js +++ b/frontend/src/lib/zen/aquarium.js @@ -26,7 +26,8 @@ const MODEL_URL = '/models/ub-angelfish.glb'; export const DEFAULTS = { yaw: Math.PI / 2, // ub.rotation.y — side-on-ish (tune live; head faces ±Z) pitch: 0, // ub.rotation.x — nose up/down - scale: 1, // multiplier on the auto-fit size + scale: 1.2, // multiplier on the auto-fit size (a touch bigger = more presence) + speed: 0.7, // swim playback rate — <1 = calmer glide finTranslucent: false, // false = opaque alpha-tested (coherent); true = blended finSide: 'double', // front | back | double (fins are thin → double reads fuller) finOpacity: 0.9, // only when translucent @@ -124,7 +125,8 @@ export async function createAquarium(canvas, initial = {}) { const baseClip = mixer.clipAction(gltf.animations[0]); // the trimmed swim loop baseClip.play(); const baseDuration = baseClip.getClip().duration || 1; - mixer.timeScale = reduced ? 0.6 : 1; // calmer when reduced-motion + const applySpeed = () => { mixer.timeScale = (params.speed ?? 0.7) * (reduced ? 0.7 : 1); }; + applySpeed(); // calm glide by default; extra-calm under reduced-motion resize(); // The canvas lives in a responsive container; a ResizeObserver catches layout @@ -153,6 +155,7 @@ export async function createAquarium(canvas, initial = {}) { Object.assign(params, next); applyMaterials(); applyTransform(); + applySpeed(); return { ...params }; }, getParams() { return { ...params }; }, diff --git a/frontend/src/routes/zen/+page.svelte b/frontend/src/routes/zen/+page.svelte index ccfb62d..f8f9300 100644 --- a/frontend/src/routes/zen/+page.svelte +++ b/frontend/src/routes/zen/+page.svelte @@ -95,6 +95,8 @@ +
Fins & tail