SOURCE / PINNED RELEASE
Made of little things.
Safe Sand · Material studies
- Release
- 9101a9cd9fb4…
- Author-recorded commit
- 75d98e1b8edb…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-7682e55a791
Archive hash verified: 6c8ddabeb31100e1…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { runInNewContext } from 'node:vm';
import test from 'node:test';
import ts from 'typescript';
import { PRESETS, PRESET_ORDER } from '../src/engine/presets.js';
const code = ts.transpileModule(await readFile(new URL('../src/setup.ts', import.meta.url), 'utf8'), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
}).outputText;
const module = { exports: {} };
runInNewContext(code, { module, exports: module.exports });
const { parseSetup } = module.exports;
const valid = { version: 1, material: 'iron', surface: 'slate', radius: 7, amount: 0.35 };
test('setup round-trip and untrusted host values', () => {
assert.equal(JSON.stringify(parseSetup(JSON.stringify(valid), PRESET_ORDER)), JSON.stringify(valid));
for (const patch of [{ version: 2 }, { material: '__proto__' }, { surface: 'invalid' }, { radius: -1 }, { radius: 100 }, { radius: '4' }, { amount: 0 }, { amount: '0.8' }, { pitch: 90 }, { yaw: -90 }, { tool: 'invalid' }, { speed: 2 }, { flowRate: 1e9 }, { pourHeight: -1 }]) {
assert.throws(() => parseSetup(JSON.stringify({ ...valid, ...patch }), PRESET_ORDER));
}
for (const raw of ['null', '[]', '"text"', '{bad']) assert.throws(() => parseSetup(raw, PRESET_ORDER));
});
test('all eleven materials have safe GPU parameters and normalized palettes', () => {
assert.equal(PRESET_ORDER.length, 11);
for (const key of PRESET_ORDER) {
const p = PRESETS[key];
assert.equal(p.palette.length, 32, key);
let previous = 0;
for (let k = 0; k < 8; k++) {
const total = p.palette[k * 4 + 3];
assert.ok(total >= previous && total <= 1.00001, `${key}: valid CDF`);
previous = total;
}
assert.equal(previous, 1);
assert.ok([...p.size, ...p.size2, ...p.fric, ...p.material, ...p.palette].every(Number.isFinite), key);
assert.ok(p.size[0] > 0 && p.material[2] >= 0 && p.material[2] <= 1, key);
}
});
test('bounded camera projection inverts at every tray aspect', async () => {
const { TrayCamera } = await import('../src/engine/camera.js');
const camera = new TrayCamera();
for (const world of [[207, 138], [57.6, 135], [330, 90]]) {
for (const pitch of [-35, 0, 35]) for (const yaw of [-35, 0, 35]) {
camera.set(pitch, yaw);
for (const [u, v] of [[0, 0], [.2, .7], [.5, .5], [1, 1]]) {
const projected = camera.project(u * world[0], v * world[1], 0, world);
const restored = camera.unproject(projected[0], projected[1], world);
assert.ok(Math.abs(restored[0] - u * world[0]) < 1e-8);
assert.ok(Math.abs(restored[1] - v * world[1]) < 1e-8);
assert.ok(projected[0] >= 0 && projected[0] <= 1 && projected[1] >= 0 && projected[1] <= 1, 'tray remains in view');
}
}
}
camera.set(500, -500); assert.equal(camera.pitch, 35); assert.equal(camera.yaw, -35);
const floor = camera.project(100, 60, 0, [200, 120]);
const raised = camera.project(100, 60, 10, [200, 120]);
assert.notEqual(floor[0], raised[0]); assert.notEqual(floor[1], raised[1]);
});
