({ realm, niche, family, level, tier, seed, variant = 0, variants = 1 })
| 128 | * to recolour what stands in it. |
| 129 | */ |
| 130 | export function createRecorder({ realm, niche, family, level, tier, seed, variant = 0, variants = 1 }) { |
| 131 | const ops = []; |
| 132 | const keys = paletteKeys(realm); |
| 133 | const palette = Object.freeze(Object.fromEntries(keys.map((k) => [k, k]))); |
| 134 | |
| 135 | const add = (kind, args) => { |
| 136 | const spec = GEOM[kind]; |
| 137 | const a = spec.args.map(([name, min, max, dflt], i) => { |
| 138 | const raw = args[i] ?? dflt; |
| 139 | if (!isNum(raw)) { |
| 140 | throw new Fail(`${kind}(): argument "${name}" must be a finite number, got ${JSON.stringify(raw)}`, ops.length); |
| 141 | } |
| 142 | if (raw < min || raw > max) { |
| 143 | throw new Fail(`${kind}(): argument "${name}" is ${raw}, outside the allowed ${min} to ${max}`, ops.length); |
| 144 | } |
| 145 | return spec.args[i][3] !== undefined ? Math.round(raw) : raw; |
| 146 | }); |
| 147 | const op = { g: kind, a, m: 'stone', o: {}, p: [0, 0, 0], r: [0, 0, 0], s: [1, 1, 1] }; |
| 148 | ops.push(op); |
| 149 | return new Shape(op); |
| 150 | }; |
| 151 | |
| 152 | const api = { |
| 153 | P: palette, |
| 154 | palette: keys, |
| 155 | realm, |
| 156 | niche, |
| 157 | family, |
| 158 | level, |
| 159 | tier, |
| 160 | /* Which of the recorded variants this run is, and how many there are. |
| 161 | This is the ONLY spread an author can rely on. Five draws from `rnd()` |
| 162 | will cluster by chance however well the generator is seeded — two of five |
| 163 | landing within 0.005 of each other is ordinary luck, not a bug — and an |
| 164 | archetype chosen that way silently collapses variants onto one form. An |
| 165 | index divides evenly by construction: `w.variant % 3` is three forms, |
| 166 | always. Branch shape on this, and spend `rnd()` on proportion. */ |
| 167 | variant, |
| 168 | variants, |
| 169 | rnd: rngOf(seed), |
| 170 | lerp: (a, b, t) => a + (b - a) * t, |
| 171 | TAU, |
| 172 | }; |
| 173 | for (const kind of GEOM_KINDS) api[kind] = (...args) => add(kind, args); |
| 174 | |
| 175 | return { api, ops }; |
| 176 | } |
| 177 | |
| 178 | /** Everything the validator needs that only the recorder can know. */ |
| 179 | export function measure(ops) { |
no test coverage detected