/* IMPORT */ import {$, render, untrack, For, If, useAnimationLoop, useMemo} from 'voby'; import type {Observable, ObservableReadonly} from 'voby'; /* HELPERS */ const COUNT = 400; const LOOPS = 6; /* MAIN */ const Cursor = ({ big, label, x, y, color }: { big: Observable, label: boolean, x: ObservableReadonly, y: ObservableReadonly, color?: ObservableReadonly }): JSX.Element => { return (
{x},{y}
); }; const Spiral = (): JSX.Element => { const x = $(0); const y = $(0); const big = $(false); const counter = $(0); window.addEventListener ( 'mousemove', ({ pageX, pageY }) => { x ( pageX ); y ( pageY ); }); window.addEventListener ( 'mousedown', () => { big ( true ); }); window.addEventListener ( 'mouseup', () => { big ( false ); }); useAnimationLoop ( () => counter ( counter () + 1 ) ); const max = useMemo ( () => COUNT + Math.round ( Math.sin ( counter () / 90 * 2 * Math.PI ) * COUNT * 0.5 ) ); const makeCursor = ( i: number ) => ({ x: (): number => { const f = i / max () * LOOPS; const θ = f * 2 * Math.PI; const m = 20 + i; return (untrack ( x ) + Math.sin ( θ ) * m) | 0; }, y: (): number => { const f = i / max () * LOOPS; const θ = f * 2 * Math.PI; const m = 20 + i; return (untrack ( y ) + Math.cos ( θ ) * m) | 0; }, color: (): string => { const f = i / max () * LOOPS; const hue = (f * 255 + untrack ( counter ) * 10) % 255; return `hsl(${hue},100%,50%)`; } }); const cache = []; const cursors = useMemo ( () => Array ( max () ).fill ( 0 ).map ( ( _, i ) => cache[i] || ( cache[i] = makeCursor ( i ) ) ) ); return (
{({ x, y, color }) => { return }}
); }; /* RENDER */ render ( , document.getElementById ( 'app' ) );