vector-kernel STEP 1: columnar events (engine/columns.js) behind buildEvents, byte-identical

docs/NEXT.md 5b, Paul's directive: rebuild the kernel toward lists of vectors run through streaming transformations, APL-style. This step introduces the struct-of-arrays substrate and converts the first two passes; the randomness tape (step 2) and the combinator DSL (step 3) build on it.

• toColumns(events, fields[, {view}]) -> { n, :Float64Array, mask:{:Uint8Array}, keys, rest } - numeric fields become columns, everything else (strings, bend objects, solo flags, undefined-valued keys)…

• fromColumns(cols) -> rows JSON.stringify-identical to the input: key insertion order preserved, present-with-undefined vs absent preserved

• writeBack(cols, events[, fields]) - mask-gated assignment into the ORIGINAL row objects (columns as a compute view, zero re-materialization risk)

• map/scale/shift (elementwise, in-place, optional mask, scalar or per-row array operands) + where/and mask builders

Verified: columns.test.js (NEW): 6 gates - adversarial round-trip (key order, absent-vs-undefined, NaN/±0, nested objects), compute round-trip, helper semantics, mask-gated writeBack + view mode +…

▶ Play it: Stationary Weather — the accessible text version, where the same music arrives as prose https://stellate.app/access.html?genre=ambient&seed=1744

1ebf2a8 https://github.com/aboard-io/stellate/commit/1ebf2a88645876da74f383e5db802a1e1e0fcd85