mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-08-08 16:45:46 +00:00
Virtualized table showing 4096 spatial hash cells: - Sort by any column (density, FD, mode, particles, neighbor) - Filter by voltage mode (STORE/COMPUTE/APPROX/MORPHIC) - Filter by density threshold - 3×3×3 neighbor scan - Row selection with detail panel - Keyboard shortcuts: 1-6 for operations - Virtual scroll (only renders visible rows) - Color-coded voltage modes - Density/FD bar visualization No build step, no dependencies, standalone HTML. Opens in any browser.
130 lines
4.1 KiB
TypeScript
130 lines
4.1 KiB
TypeScript
/**
|
||
* data.ts — Data layer for spatial hash grid visualization.
|
||
*
|
||
* Generates synthetic 16×16×16 spatial hash data (4096 cells).
|
||
* In production, this would connect to a WebGPU buffer via SharedArrayBuffer
|
||
* or postMessage from the compute shader. For now we generate representative data
|
||
* that mimics what the GPU spatial hash would produce.
|
||
*/
|
||
|
||
export type VoltageMode = "STORE" | "COMPUTE" | "APPROX" | "MORPHIC";
|
||
|
||
export interface SpatialHashRow {
|
||
id: string;
|
||
x: number;
|
||
y: number;
|
||
z: number;
|
||
density: number; // 0..255
|
||
fd: number; // fractal dimension ~2.0..3.0
|
||
voltage_mode: VoltageMode;
|
||
particle_count: number;
|
||
max_neighbor: number;
|
||
}
|
||
|
||
const GRID_SIZE = 16;
|
||
const VOLTAGE_MODES: VoltageMode[] = ["STORE", "COMPUTE", "APPROX", "MORPHIC"];
|
||
|
||
/** Deterministic seeded PRNG (xoshiro128**) */
|
||
function makeRng(seed: number) {
|
||
let s0 = seed | 0;
|
||
let s1 = (seed * 1664525 + 1013904223) | 0;
|
||
let s2 = (s1 * 1664525 + 1013904223) | 0;
|
||
let s3 = (s2 * 1664525 + 1013904223) | 0;
|
||
|
||
return () => {
|
||
const result = Math.imul(s1, 5) | 0;
|
||
const t = s1 << 9;
|
||
s2 ^= s0;
|
||
s3 ^= s1;
|
||
s1 ^= s2;
|
||
s0 ^= s3;
|
||
s2 ^= t;
|
||
s3 = (s3 << 11) | (s3 >>> 21);
|
||
return (result >>> 0) / 4294967296;
|
||
};
|
||
}
|
||
|
||
/** Generate 4096 rows of synthetic spatial hash data */
|
||
export function generateSpatialHashData(): SpatialHashRow[] {
|
||
const rng = makeRng(42);
|
||
const rows: SpatialHashRow[] = [];
|
||
|
||
for (let xi = 0; xi < GRID_SIZE; xi++) {
|
||
for (let yi = 0; yi < GRID_SIZE; yi++) {
|
||
for (let zi = 0; zi < GRID_SIZE; zi++) {
|
||
// Density peaks in center, sparse at edges
|
||
const cx = xi / GRID_SIZE - 0.5;
|
||
const cy = yi / GRID_SIZE - 0.5;
|
||
const cz = zi / GRID_SIZE - 0.5;
|
||
const dist = Math.sqrt(cx * cx + cy * cy + cz * cz);
|
||
const baseDensity = Math.max(0, 1 - dist * 3) * 200 + rng() * 55;
|
||
|
||
// Fractal dimension correlates with density
|
||
const fd = 2.0 + (baseDensity / 255) + (rng() - 0.5) * 0.2;
|
||
|
||
// Voltage mode assignment: dense regions tend toward MORPHIC/COMPUTE
|
||
let voltageMode: VoltageMode;
|
||
if (baseDensity > 200) voltageMode = rng() > 0.5 ? "MORPHIC" : "COMPUTE";
|
||
else if (baseDensity > 100) voltageMode = rng() > 0.5 ? "COMPUTE" : "APPROX";
|
||
else voltageMode = rng() > 0.3 ? "STORE" : "APPROX";
|
||
|
||
rows.push({
|
||
id: `${xi}-${yi}-${zi}`,
|
||
x: xi,
|
||
y: yi,
|
||
z: zi,
|
||
density: Math.round(Math.min(255, Math.max(0, baseDensity))),
|
||
fd: Math.round(fd * 100) / 100,
|
||
voltage_mode: voltageMode,
|
||
particle_count: Math.round(baseDensity * 0.8 + rng() * 40),
|
||
max_neighbor: Math.round(6 + rng() * 20),
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
return rows;
|
||
}
|
||
|
||
/**
|
||
* Simulate a WebGPU buffer update — mutates density/particle_count
|
||
* with small deltas to model real-time compute shader output.
|
||
*/
|
||
export function simulateBufferUpdate(rows: SpatialHashRow[]): SpatialHashRow[] {
|
||
const rng = makeRng(Date.now());
|
||
return rows.map((r) => {
|
||
if (rng() > 0.1) return r; // Only update ~10% of cells per tick
|
||
const dDensity = Math.round((rng() - 0.5) * 20);
|
||
return {
|
||
...r,
|
||
density: Math.min(255, Math.max(0, r.density + dDensity)),
|
||
particle_count: Math.max(0, r.particle_count + Math.round(dDensity * 0.8)),
|
||
};
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Export rows to CSV string.
|
||
*/
|
||
export function exportToCSV(rows: SpatialHashRow[]): string {
|
||
const header = "x,y,z,density,fd,voltage_mode,particle_count,max_neighbor";
|
||
const body = rows
|
||
.map(
|
||
(r) =>
|
||
`${r.x},${r.y},${r.z},${r.density},${r.fd},${r.voltage_mode},${r.particle_count},${r.max_neighbor}`
|
||
)
|
||
.join("\n");
|
||
return `${header}\n${body}`;
|
||
}
|
||
|
||
/** Trigger a browser download of CSV data */
|
||
export function downloadCSV(rows: SpatialHashRow[]) {
|
||
const csv = exportToCSV(rows);
|
||
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement("a");
|
||
a.href = url;
|
||
a.download = "spatial-hash-export.csv";
|
||
a.click();
|
||
URL.revokeObjectURL(url);
|
||
}
|