import { useMemo, useState } from 'react'; import { ready, ink } from '../../lib/mrly.js'; import { mount, Page, Row, Slider, Btn, Stats, Stat } from '../../lib/app.jsx'; import { Grid, Markup } from '../../lib/draw.jsx'; import { useSeeds } from '../../lib/select.jsx'; import { useQuery, share } from '../../lib/query.js'; const m = await ready(); const colors = () => [ink.blue, ink.orange, ink.yellow, ink.green, ink.pink]; const COUNTS = m.counting_sequence(4).join(', '); const BASE3 = m.baseq_sequence(3, 2).join(', '); const WORLD = { 2: JSON.parse(m.universe(2)), 3: JSON.parse(m.universe(3)) }; const FIRST = { 2: '7', 3: '23' }; const BUDGET = 60000; const tint = (design) => colors()[design.degree % 5]; const drawn = (seed, designs) => designs[m.random_between(seed, [0], [designs.length - 1])[0]].code; function thumb(design, dimension) { const label = `design ${design.code}, ${design.anf}`; if (dimension === 2) return ; try { return ; } catch { return ; } } function grown(design, dimension, level) { const label = `${design.name} grown to level ${level}`; if (dimension === 2) return ; try { return ; } catch (error) { return
{String(error.message ?? error)}
; } } function App() { const s = useSeeds(); const [pick, set] = useQuery({ d: 2 }); const dimension = pick.d === 3 ? 3 : 2; const world = WORLD[dimension]; const [level, setLevel] = useState(3); const [code, setCode] = useState(() => (s.get() ? drawn(s.get(), world.designs) : FIRST[dimension])); const design = world.designs.find((one) => one.code === code) ?? world.designs[0]; const top = m.level_cap(3, dimension, BUDGET); const grow = Math.min(level, top); const cards = useMemo(() => world.designs.map((one) => [one, thumb(one, dimension)]), [dimension]); const swap = (d) => { set({ d }); setCode(FIRST[d]); setLevel(Math.min(level, m.level_cap(3, d, BUDGET))); }; const controls = (
swap(2)}>plane swap(3)}>cube
setCode(drawn(s.next(), world.designs))}>Randomize {dimension === 3 && open in the sponge}
); return ( A code is a bitmask over the corners of a hypercube. Rotations and reflections fold the codes into orbits, and one design per orbit is all there is: {COUNTS} distinct designs in dimensions 1 to 4. Click one to grow it.} foot={<>The distinct counts are Burnside averages over the hyperoctahedral group; the gallery enumerates the orbits outright and the two agree. In base 3 the same count runs {BASE3} for dimensions 1 and 2. The two moves this gallery enumerates, a rule on the corners and that rule substituted into itself, are written up in the core.}>

{world.distinct} designs from {world.total} codes

{cards.map(([one, art]) => (
setCode(one.code)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setCode(one.code); } }}> {art}
{one.code}
{one.anf}
))}

{design.name}

{grown(design, dimension, grow)} {design.orbit} {design.degree} {design.anf} {m.fills(design.code, 3, dimension, grow, 2)} of {m.grid_total(3, dimension, grow)} {m.ratio(design.code, 3, dimension, grow, 2).toFixed(4)} {m.dimension(design.code, 3, dimension, 2).toFixed(4)}
); } mount();