import { useRef, useState } from 'react'; import { ready, ink } from '../../lib/mrly.js'; import { mount, Page, Row, Pick, Slider, Check, Stats, Stat, Note, Group } from '../../lib/app.jsx'; import { Markup, Sketch } from '../../lib/draw.jsx'; import { useQuery } from '../../lib/query.js'; import { useSeeds, seeded, Picker } from '../../lib/select.jsx'; import { board, bars, axis } from '../../lib/chart.js'; const m = await ready(); const PAD = 12; function App() { const s = useSeeds(); const [pick, set] = useQuery({ code: seeded(s, 3, 2, '126'), level: 5 }); const [height, setHeight] = useState(null); const [both, setBoth] = useState(false); const [view, setView] = useState('points'); const shown = useRef(null); const top = m.level_cap(2, 1, view === 'section' ? 64 : 512); const level = Math.min(pick.level, top); const code = pick.code.trim(); let error = null, art = null, drawn = ''; try { const cut = JSON.parse(m.diagonal_profile(code, 2, level, 2)); const [low, high] = cut.support; const at = Math.min(high, Math.max(low, height ?? cut.central[0])); const heights = both ? cut.central : [at]; shown.current = { cut, low, high, at, heights, name: m.name_of(code, 3, 2), here: heights.map((h) => m.diagonal_count(code, 2, level, 2, h)).join(' and '), digits: heights.map((h) => m.diagonal_digits(code, 2, level, 2, h)).join(' and '), }; const svg = view === 'section' ? m.hex_svg(code, 2, level, 2, 'cut', Math.max(1, Math.round(256 / 2 ** level))) : m.diagonal_svg(code, 2, level, 2, heights, Math.max(1, Math.round(512 / 2 ** level))); if (svg.length > 4000000) throw new Error('that drawing is larger than this page serves; lower the level.'); art = svg; drawn = view === 'section' ? '-' : m.diagonal_total(code, 2, level, 2, heights); } catch (fault) { error = fault; } const chart = (canvas) => { const v = shown.current; if (!v) return; const b = board(canvas, 180, { pad: PAD, top: 12, bottom: 20 }); const counts = v.cut.counts.map(Number); bars(b, counts, { color: (i) => (v.heights.includes(v.low + i) ? ink.yellow : ink.blue) }); axis(b, [[0, v.low], [1, v.low + counts.length - 1]]); }; const onSeek = (frac) => { const v = shown.current; if (both || !v) return; setHeight(Math.min(v.high, Math.max(v.low, Math.round(v.low + frac * (v.high - v.low))))); }; const onView = (value) => { const cap = m.level_cap(2, 1, value === 'section' ? 64 : 512); setView(value); if (pick.level > cap) { set({ level: cap }); setHeight(null); } }; const v = shown.current; const controls = ( <> { set(patch); setHeight(null); }} /> { set({ level: value }); setHeight(null); }} /> ); return ( A plane x + y + z = s slides through the solid of bang dim 3, code 126 at the level and meets exactly 3^level cells at every height it meets at all. The binary digits of the height say which corners each scale may use, so every cut is a Sierpinski gasket, and the two central heights together fall into six of them tiling a hexagon. Drag the bar chart to move the plane.} foot={<>The profile is the coefficient list of the digit polynomial, so a height is counted without building a single cell; the points are enumerated on the plane itself and projected down the (1,1,1) axis in Rust, one circle per cell, coloured by height and by top-scale corner. The section view is the crate's own triangular mesh through the same solid. Why every one of these cuts is a gasket, and which one the height's binary digits pick, is in the cuts note.}> {v?.name} {v?.cut.side} {v && `[${v.low}, ${v.high}]`} {v && `${v.cut.nonempty} of ${v.cut.heights}`} {v?.here} {v?.cut.min} {v?.cut.max} {v && (v.cut.constant ? 'yes' : 'no')} {v?.digits} {drawn} ); } mount();