diff --git a/src/apps/basic/Basic/index.html b/src/apps/basic/Basic/index.html index 5b50433..4e51920 100644 --- a/src/apps/basic/Basic/index.html +++ b/src/apps/basic/Basic/index.html @@ -5,10 +5,30 @@ My Drawing +
+ +

My Drawing

diff --git a/src/apps/basic/BouncyBall/bouncy_ball.js b/src/apps/basic/BouncyBall/bouncy_ball.js index c5c6060..665125b 100644 --- a/src/apps/basic/BouncyBall/bouncy_ball.js +++ b/src/apps/basic/BouncyBall/bouncy_ball.js @@ -1,6 +1,12 @@ const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d'); +// Respect the user's "reduce motion" OS/browser setting (accessibility). When +// it's on, we draw the ball once and don't start the bouncing loop. +const reducedMotionQuery = + window.matchMedia?.('(prefers-reduced-motion: reduce)'); +let rafId = 0; + // Ball properties const ballRadius = canvas.width * 0.1; const ballColor = 'red'; @@ -43,7 +49,25 @@ function animate() { drawBall(); moveBall(); - requestAnimationFrame(animate); + rafId = requestAnimationFrame(animate); +} + +// Draw the ball once, without moving it (used when motion is reduced). +function drawStaticFrame() { + ctx.fillStyle = bgColor; + ctx.fillRect(0, 0, canvas.width, canvas.height); + drawBall(); +} + +// Start bouncing — or, if the user prefers reduced motion, just draw the ball +// as a single static frame instead of animating. +function start() { + cancelAnimationFrame(rafId); + if (reducedMotionQuery?.matches) { + drawStaticFrame(); + } else { + rafId = requestAnimationFrame(animate); + } } function resizeCanvas() { @@ -61,8 +85,15 @@ function resizeCanvas() { maxSpeed = Math.max(3, canvas.height * 0.01); xSpeed = Math.random() * maxSpeed * initialDir; // Random x velocity ySpeed = Math.random() * maxSpeed * initialDir; // Random y velocity + + // No loop runs under reduced motion, so repaint the static frame ourselves. + if (reducedMotionQuery?.matches) drawStaticFrame(); } window.addEventListener('resize', resizeCanvas); resizeCanvas(); -animate(); +start(); + +// If the user toggles "reduce motion" while the page is open, react live +// (start bouncing, or freeze to the static frame) without a reload. +reducedMotionQuery?.addEventListener?.('change', start); diff --git a/src/apps/basic/BouncyBall/index.html b/src/apps/basic/BouncyBall/index.html index 23e6d11..68a972f 100644 --- a/src/apps/basic/BouncyBall/index.html +++ b/src/apps/basic/BouncyBall/index.html @@ -11,6 +11,10 @@
+ +

Bouncy Ball

diff --git a/src/apps/basic/BouncyBall/style.css b/src/apps/basic/BouncyBall/style.css index b82bbbd..c3dfe50 100644 --- a/src/apps/basic/BouncyBall/style.css +++ b/src/apps/basic/BouncyBall/style.css @@ -15,3 +15,18 @@ canvas { margin: 20px; height: calc(100vh - 40px); /* Subtract 20px from top and 20px from bottom */ } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/graphics/LineSegment1-Basic/index.html b/src/apps/graphics/LineSegment1-Basic/index.html index 400238a..9075eec 100644 --- a/src/apps/graphics/LineSegment1-Basic/index.html +++ b/src/apps/graphics/LineSegment1-Basic/index.html @@ -18,6 +18,10 @@
+ +

Line Segment 1: Basic

diff --git a/src/apps/graphics/LineSegment1-Basic/style.css b/src/apps/graphics/LineSegment1-Basic/style.css index 39d8794..994668f 100644 --- a/src/apps/graphics/LineSegment1-Basic/style.css +++ b/src/apps/graphics/LineSegment1-Basic/style.css @@ -9,3 +9,18 @@ canvas { width: 400px; height: 400px; } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/graphics/LineSegment2-Interactive/index.html b/src/apps/graphics/LineSegment2-Interactive/index.html index 7bd3afa..d4995e9 100644 --- a/src/apps/graphics/LineSegment2-Interactive/index.html +++ b/src/apps/graphics/LineSegment2-Interactive/index.html @@ -18,6 +18,10 @@
+ +

Line Segment 2: Interactive

diff --git a/src/apps/graphics/LineSegment2-Interactive/style.css b/src/apps/graphics/LineSegment2-Interactive/style.css index 39d8794..994668f 100644 --- a/src/apps/graphics/LineSegment2-Interactive/style.css +++ b/src/apps/graphics/LineSegment2-Interactive/style.css @@ -9,3 +9,18 @@ canvas { width: 400px; height: 400px; } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/makelogo/MakeabilityLabLogo-AutoResize/index.html b/src/apps/makelogo/MakeabilityLabLogo-AutoResize/index.html index c5e5101..226f4d8 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-AutoResize/index.html +++ b/src/apps/makelogo/MakeabilityLabLogo-AutoResize/index.html @@ -18,6 +18,10 @@
+ +

Makeability Lab Logo: Autoresize

diff --git a/src/apps/makelogo/MakeabilityLabLogo-AutoResize/style.css b/src/apps/makelogo/MakeabilityLabLogo-AutoResize/style.css index 83bdbfe..7d426db 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-AutoResize/style.css +++ b/src/apps/makelogo/MakeabilityLabLogo-AutoResize/style.css @@ -16,3 +16,18 @@ canvas { width: 100%; height: 100%; } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion/index.html b/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion/index.html index 9d38b47..f63648a 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion/index.html +++ b/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion/index.html @@ -19,6 +19,10 @@
+ +

Makeability Lab Logo: Reverse Explosion

diff --git a/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion/style.css b/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion/style.css index 565e3a3..06088d7 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion/style.css +++ b/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion/style.css @@ -9,3 +9,18 @@ canvas { width: 1000px; height: 1000px; } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion2/index.html b/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion2/index.html index a15f6e0..da532d4 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion2/index.html +++ b/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion2/index.html @@ -19,6 +19,10 @@
+ +

Makeability Lab Logo: Reverse Explosion 2

diff --git a/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion2/style.css b/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion2/style.css index 565e3a3..06088d7 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion2/style.css +++ b/src/apps/makelogo/MakeabilityLabLogo-ReverseExplosion2/style.css @@ -9,3 +9,18 @@ canvas { width: 1000px; height: 1000px; } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/index.html b/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/index.html index 016951b..3772c6e 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/index.html +++ b/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/index.html @@ -18,6 +18,10 @@
+ +

Makeability Lab Logo Santa Morph

diff --git a/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/sketch.js b/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/sketch.js index 4d9e4e0..d0294a7 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/sketch.js +++ b/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/sketch.js @@ -90,6 +90,13 @@ let originalSantaTriangles = null; /** @type {number} Current mouse/touch x-coordinate relative to the canvas. */ let mouseX = 0; +// Respect the user's "reduce motion" OS/browser setting (accessibility). The +// Santa→logo morph is mouse-driven, so it's only ever in motion while the user +// moves the pointer; the one thing that animates on its own is the holiday +// text's pulsing glow, which we hold steady when reduced motion is requested. +const reducedMotionQuery = + window.matchMedia?.('(prefers-reduced-motion: reduce)'); + // --------------------------------------------------------------------------- // Initialization & Layout // --------------------------------------------------------------------------- @@ -317,8 +324,11 @@ function drawHolidayMessage() { const textColor = lerpColor(COLOR_SANTA_SUIT_RED, COLOR_SANTA_BELT, lerpAmt); // 4. Holiday Styling: Dynamic Sparkle/Glow - // We use a sine wave based on time to make the glow pulse - const sparkle = 5 + Math.sin(Date.now() / 300) * 5; + // We use a sine wave based on time to make the glow pulse — unless the user + // prefers reduced motion, in which case we hold the glow steady. + const sparkle = reducedMotionQuery?.matches + ? 5 + : 5 + Math.sin(Date.now() / 300) * 5; ctx.shadowColor = 'rgba(255, 255, 255, 0.9)'; ctx.shadowBlur = sparkle; diff --git a/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/style.css b/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/style.css index 63162f9..66dfc41 100644 --- a/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/style.css +++ b/src/apps/makelogo/MakeabilityLabLogo-SantaMorph/style.css @@ -23,4 +23,19 @@ canvas { max-height: 100%; width: 100%; height: 100%; +} + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; } \ No newline at end of file diff --git a/src/apps/makelogo/MakeabilityLabLogo/index.html b/src/apps/makelogo/MakeabilityLabLogo/index.html index 092b68d..aa0576e 100644 --- a/src/apps/makelogo/MakeabilityLabLogo/index.html +++ b/src/apps/makelogo/MakeabilityLabLogo/index.html @@ -18,6 +18,10 @@
+ +

Makeability Lab Logo

diff --git a/src/apps/makelogo/MakeabilityLabLogo/style.css b/src/apps/makelogo/MakeabilityLabLogo/style.css index 39d8794..994668f 100644 --- a/src/apps/makelogo/MakeabilityLabLogo/style.css +++ b/src/apps/makelogo/MakeabilityLabLogo/style.css @@ -9,3 +9,18 @@ canvas { width: 400px; height: 400px; } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/makelogo/MakeabilityLabLogoGridFade/index.html b/src/apps/makelogo/MakeabilityLabLogoGridFade/index.html index d35838c..b4f6589 100644 --- a/src/apps/makelogo/MakeabilityLabLogoGridFade/index.html +++ b/src/apps/makelogo/MakeabilityLabLogoGridFade/index.html @@ -17,6 +17,10 @@
+ +

Makeability Lab Logo — Grid Fade

Press R to replay · G toggle grid · H toggle logo

diff --git a/src/apps/makelogo/MakeabilityLabLogoGridFade/sketch.js b/src/apps/makelogo/MakeabilityLabLogoGridFade/sketch.js index 19e0c21..db11621 100644 --- a/src/apps/makelogo/MakeabilityLabLogoGridFade/sketch.js +++ b/src/apps/makelogo/MakeabilityLabLogoGridFade/sketch.js @@ -33,6 +33,16 @@ const ctx = canvas.getContext('2d'); let makeLabLogo; let gridFade; let animationStartMs = 0; +let rafId = 0; + +// Respect the user's "reduce motion" OS/browser setting (accessibility). When +// it's on, we skip the reveal animation and just show the finished logo. +const reducedMotionQuery = + window.matchMedia?.('(prefers-reduced-motion: reduce)'); + +// A timestamp well past the end of the reveal. Every piece clamps its progress +// to 1, so updating with this settles the whole animation to its final frame. +const SETTLE_MS = 10_000_000; /** * (Re)builds the canvas, logo, and animation for the current window size. @@ -95,7 +105,30 @@ function frame(now) { gridFade.update(elapsedMs); gridFade.draw(ctx); - requestAnimationFrame(frame); + rafId = requestAnimationFrame(frame); +} + +/** Draws the finished logo as a single static frame (no motion). */ +function drawSettledFrame() { + ctx.fillStyle = BACKGROUND_COLOR; + ctx.fillRect(0, 0, window.innerWidth, window.innerHeight); + gridFade.update(SETTLE_MS); + gridFade.draw(ctx); +} + +/** + * Plays the reveal animation — or, if the user prefers reduced motion, draws + * the finished logo as one static frame instead of animating. + */ +function start() { + cancelAnimationFrame(rafId); + gridFade.reset(); + animationStartMs = 0; + if (reducedMotionQuery?.matches) { + drawSettledFrame(); + } else { + rafId = requestAnimationFrame(frame); + } } // Rebuild on resize (debounced). The clock keeps running, so an already-revealed @@ -103,7 +136,11 @@ function frame(now) { let resizeTimer; window.addEventListener('resize', () => { clearTimeout(resizeTimer); - resizeTimer = setTimeout(buildScene, 150); + resizeTimer = setTimeout(() => { + buildScene(); + // No loop runs under reduced motion, so repaint the static frame ourselves. + if (reducedMotionQuery?.matches) drawSettledFrame(); + }, 150); }); // --- Interaction --- @@ -139,4 +176,8 @@ document.addEventListener('keydown', (event) => { }); buildScene(); -requestAnimationFrame(frame); +start(); + +// If the user toggles "reduce motion" while the page is open, react live +// (start animating, or settle to the static frame) without a reload. +reducedMotionQuery?.addEventListener?.('change', start); diff --git a/src/apps/makelogo/MakeabilityLabLogoGridFade/style.css b/src/apps/makelogo/MakeabilityLabLogoGridFade/style.css index 9373db3..bd79cb1 100644 --- a/src/apps/makelogo/MakeabilityLabLogoGridFade/style.css +++ b/src/apps/makelogo/MakeabilityLabLogoGridFade/style.css @@ -57,3 +57,18 @@ kbd { display: block; } } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/makelogo/MakeabilityLabLogoLeafFall/index.html b/src/apps/makelogo/MakeabilityLabLogoLeafFall/index.html index 740b5bd..8a103e0 100644 --- a/src/apps/makelogo/MakeabilityLabLogoLeafFall/index.html +++ b/src/apps/makelogo/MakeabilityLabLogoLeafFall/index.html @@ -17,6 +17,10 @@
+ +

Makeability Lab Logo — Leaf Fall

Press R to replay · F drop leaves · T toggle leaf fade · G toggle grid · H toggle logo

diff --git a/src/apps/makelogo/MakeabilityLabLogoLeafFall/sketch.js b/src/apps/makelogo/MakeabilityLabLogoLeafFall/sketch.js index b37e74b..e8a1599 100644 --- a/src/apps/makelogo/MakeabilityLabLogoLeafFall/sketch.js +++ b/src/apps/makelogo/MakeabilityLabLogoLeafFall/sketch.js @@ -34,6 +34,16 @@ const ctx = canvas.getContext('2d'); let makeLabLogo; let leafFall; let animationStartMs = 0; +let rafId = 0; + +// Respect the user's "reduce motion" OS/browser setting (accessibility). When +// it's on, we skip the falling animation and just show the finished logo. +const reducedMotionQuery = + window.matchMedia?.('(prefers-reduced-motion: reduce)'); + +// A timestamp well past the end of the fall. Every piece clamps its progress +// to 1, so updating with this settles the whole animation to its final frame. +const SETTLE_MS = 10_000_000; /** * (Re)builds the canvas, logo, and animation for the current window size. @@ -94,7 +104,30 @@ function frame(now) { leafFall.update(elapsedMs); leafFall.draw(ctx); - requestAnimationFrame(frame); + rafId = requestAnimationFrame(frame); +} + +/** Draws the finished logo as a single static frame (no motion). */ +function drawSettledFrame() { + ctx.fillStyle = BACKGROUND_COLOR; + ctx.fillRect(0, 0, window.innerWidth, window.innerHeight); + leafFall.update(SETTLE_MS); + leafFall.draw(ctx); +} + +/** + * Plays the falling animation — or, if the user prefers reduced motion, draws + * the finished logo as one static frame instead of animating. + */ +function start() { + cancelAnimationFrame(rafId); + leafFall.reset(); + animationStartMs = 0; + if (reducedMotionQuery?.matches) { + drawSettledFrame(); + } else { + rafId = requestAnimationFrame(frame); + } } // Rebuild on resize (debounced). The clock keeps running, so an already-revealed @@ -102,7 +135,11 @@ function frame(now) { let resizeTimer; window.addEventListener('resize', () => { clearTimeout(resizeTimer); - resizeTimer = setTimeout(buildScene, 150); + resizeTimer = setTimeout(() => { + buildScene(); + // No loop runs under reduced motion, so repaint the static frame ourselves. + if (reducedMotionQuery?.matches) drawSettledFrame(); + }, 150); }); // --- Interaction --- @@ -144,4 +181,8 @@ document.addEventListener('keydown', (event) => { }); buildScene(); -requestAnimationFrame(frame); +start(); + +// If the user toggles "reduce motion" while the page is open, react live +// (start animating, or settle to the static frame) without a reload. +reducedMotionQuery?.addEventListener?.('change', start); diff --git a/src/apps/makelogo/MakeabilityLabLogoLeafFall/style.css b/src/apps/makelogo/MakeabilityLabLogoLeafFall/style.css index 9373db3..bd79cb1 100644 --- a/src/apps/makelogo/MakeabilityLabLogoLeafFall/style.css +++ b/src/apps/makelogo/MakeabilityLabLogoLeafFall/style.css @@ -57,3 +57,18 @@ kbd { display: block; } } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/makelogo/MakeabilityLabLogoZoomFade/index.html b/src/apps/makelogo/MakeabilityLabLogoZoomFade/index.html index 56a3560..f2ad99d 100644 --- a/src/apps/makelogo/MakeabilityLabLogoZoomFade/index.html +++ b/src/apps/makelogo/MakeabilityLabLogoZoomFade/index.html @@ -17,6 +17,10 @@
+ +

Makeability Lab Logo — Z-Zoom

Press R to replay · G toggle grid · H toggle logo

diff --git a/src/apps/makelogo/MakeabilityLabLogoZoomFade/sketch.js b/src/apps/makelogo/MakeabilityLabLogoZoomFade/sketch.js index e4de334..3880b1f 100644 --- a/src/apps/makelogo/MakeabilityLabLogoZoomFade/sketch.js +++ b/src/apps/makelogo/MakeabilityLabLogoZoomFade/sketch.js @@ -34,6 +34,16 @@ const ctx = canvas.getContext('2d'); let makeLabLogo; let zoomFade; let animationStartMs = 0; +let rafId = 0; + +// Respect the user's "reduce motion" OS/browser setting (accessibility). When +// it's on, we skip the zoom animation and just show the finished logo. +const reducedMotionQuery = + window.matchMedia?.('(prefers-reduced-motion: reduce)'); + +// A timestamp well past the end of the zoom. Every piece clamps its progress +// to 1, so updating with this settles the whole animation to its final frame. +const SETTLE_MS = 10_000_000; /** * (Re)builds the canvas, logo, and animation for the current window size. @@ -96,7 +106,30 @@ function frame(now) { zoomFade.update(elapsedMs); zoomFade.draw(ctx); - requestAnimationFrame(frame); + rafId = requestAnimationFrame(frame); +} + +/** Draws the finished logo as a single static frame (no motion). */ +function drawSettledFrame() { + ctx.fillStyle = BACKGROUND_COLOR; + ctx.fillRect(0, 0, window.innerWidth, window.innerHeight); + zoomFade.update(SETTLE_MS); + zoomFade.draw(ctx); +} + +/** + * Plays the zoom animation — or, if the user prefers reduced motion, draws the + * finished logo as one static frame instead of animating. + */ +function start() { + cancelAnimationFrame(rafId); + zoomFade.reset(); + animationStartMs = 0; + if (reducedMotionQuery?.matches) { + drawSettledFrame(); + } else { + rafId = requestAnimationFrame(frame); + } } // Rebuild on resize (debounced). The clock keeps running, so an already-revealed @@ -104,7 +137,11 @@ function frame(now) { let resizeTimer; window.addEventListener('resize', () => { clearTimeout(resizeTimer); - resizeTimer = setTimeout(buildScene, 150); + resizeTimer = setTimeout(() => { + buildScene(); + // No loop runs under reduced motion, so repaint the static frame ourselves. + if (reducedMotionQuery?.matches) drawSettledFrame(); + }, 150); }); // --- Interaction --- @@ -140,4 +177,8 @@ document.addEventListener('keydown', (event) => { }); buildScene(); -requestAnimationFrame(frame); +start(); + +// If the user toggles "reduce motion" while the page is open, react live +// (start animating, or settle to the static frame) without a reload. +reducedMotionQuery?.addEventListener?.('change', start); diff --git a/src/apps/makelogo/MakeabilityLabLogoZoomFade/style.css b/src/apps/makelogo/MakeabilityLabLogoZoomFade/style.css index 9373db3..bd79cb1 100644 --- a/src/apps/makelogo/MakeabilityLabLogoZoomFade/style.css +++ b/src/apps/makelogo/MakeabilityLabLogoZoomFade/style.css @@ -57,3 +57,18 @@ kbd { display: block; } } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} diff --git a/src/apps/makelogo/TriangleArtMorphTest/index.html b/src/apps/makelogo/TriangleArtMorphTest/index.html index 408cbbe..b1f03c8 100644 --- a/src/apps/makelogo/TriangleArtMorphTest/index.html +++ b/src/apps/makelogo/TriangleArtMorphTest/index.html @@ -28,6 +28,10 @@
+ +

Makeability Lab Shape Morph

diff --git a/src/apps/makelogo/TriangleArtMorphTest/style.css b/src/apps/makelogo/TriangleArtMorphTest/style.css index ad2df32..8614eca 100644 --- a/src/apps/makelogo/TriangleArtMorphTest/style.css +++ b/src/apps/makelogo/TriangleArtMorphTest/style.css @@ -38,4 +38,19 @@ canvas { font-family: 'Segoe UI', sans-serif; } label { font-weight: bold; margin-right: 8px; } -select { font-size: 14px; padding: 6px; border-radius: 4px; border: 1px solid #ccc; } \ No newline at end of file +select { font-size: 14px; padding: 6px; border-radius: 4px; border: 1px solid #ccc; } + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; +} \ No newline at end of file diff --git a/src/apps/makelogo/TriangleArtMorphTest2-MorphLib/index.html b/src/apps/makelogo/TriangleArtMorphTest2-MorphLib/index.html index be2c503..45fdf9c 100644 --- a/src/apps/makelogo/TriangleArtMorphTest2-MorphLib/index.html +++ b/src/apps/makelogo/TriangleArtMorphTest2-MorphLib/index.html @@ -105,6 +105,10 @@
+ +

Makeability Lab Shape Morph

diff --git a/src/apps/makelogo/TriangleArtMorphTest2-MorphLib/style.css b/src/apps/makelogo/TriangleArtMorphTest2-MorphLib/style.css index e6b319a..2ec6995 100644 --- a/src/apps/makelogo/TriangleArtMorphTest2-MorphLib/style.css +++ b/src/apps/makelogo/TriangleArtMorphTest2-MorphLib/style.css @@ -153,4 +153,19 @@ select { #playbackControls.disabled { opacity: 0.4; pointer-events: none; +} + +/* Visually hidden: removed from view but kept in the accessibility tree so the +

page heading is available for screen-reader navigation. */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + white-space: nowrap; } \ No newline at end of file