diff --git a/hero.js b/hero.js index 0165d1f..45b10ca 100644 --- a/hero.js +++ b/hero.js @@ -18,18 +18,24 @@ // // prefers-reduced-motion freezes the field fully drawn either way. -import { makePaths, drawPaths } from './paths.js'; +import { makePaths, drawPaths, OVERSCAN } from './paths.js'; const STYLE_ID = 'redoal-hero-style'; const CYCLE_MS = 28000; const SEED = 7; const COUNT = 47; +const BLEED = `${((OVERSCAN - 1) / 2) * -100}%`; + const STYLE_TEXT = ` +/* The field bleeds 25% past the hero piece on every side; clip the + document sideways (clip, not hidden: no scroll container) so the + bleed can never cause horizontal scrolling. */ +html { overflow-x: clip; } .redoal-paths { position: absolute; - inset: 0; - overflow: hidden; + inset: ${BLEED}; + overflow: visible; pointer-events: none; --redoal-t: 0; --redoal-seed: ${SEED}; diff --git a/paths.js b/paths.js index 774409d..fc9c491 100644 --- a/paths.js +++ b/paths.js @@ -8,6 +8,11 @@ // engine likes, and unseeded randomness would reshuffle the picture on // every repaint. +// The field bleeds past its box: the painted element is this much +// larger than the hero piece on each axis (25% each side), and the +// drawing scales to the piece, not the element, so nothing grows. +export const OVERSCAN = 1.5; + export function mulberry32(seed) { let a = seed >>> 0; return () => { @@ -118,7 +123,7 @@ const smooth = (u) => u * u * (3 - 2 * u); export function drawPaths(ctx, width, height, paths, t, colors) { ctx.clearRect(0, 0, width, height); - const s = Math.min(width, height) * 0.9; + const s = (Math.min(width, height) / OVERSCAN) * 0.9; ctx.save(); ctx.translate(width / 2, height / 2); ctx.lineWidth = 1;