Matrix Data Model Progression Testing
by joshribakoff
Matrix data model verification using ASCII diagrams. Use when working with *Progressions.ts files, defineProgression(), or testing how 2D numeric grids evolve over time. Auto-apply when editing files matching *Progressions.ts or src/test-utils/ascii*.ts.
Skill Details
Repository Files
1 file in this skill directory
name: matrix-data-model-progression-testing description: Matrix data model verification using ASCII diagrams. Use when working with *Progressions.ts files, defineProgression(), or testing how 2D numeric grids evolve over time. Auto-apply when editing files matching Progressions.ts or src/test-utils/ascii.ts.
Matrix Data Model Progression Testing Skill
Verifies how 2D numeric matrices (the underlying data model) evolve over simulated time. Uses compact ASCII diagrams inspired by RxJS marble testing.
This is about data correctness, not rendering. The wave simulation uses matrices to represent:
- Bathymetry (depth values)
- Energy fields (wave energy at each cell)
- Foam density (foam amount at each cell)
When to Use This
- Editing
*Progressions.tsfiles (bathymetry, energy field, foam, etc.) - Designing new simulation behaviors
- Debugging why a layer produces unexpected data output
- Verifying time-series evolution of matrix values
Architecture
src/test-utils/
asciiMatrix.ts → ASCII encoding/decoding utilities
asciiMatrix.test.ts → Tests for the utilities themselves
progression.ts → defineProgression() framework
progression.test.ts → Tests for the framework
src/render/*Progressions.ts → Layer progression definitions
src/state/energyFieldProgressions.ts
ASCII Matrix Format
Each character represents a cell value (0.0-1.0):
| Char | Value Range | Meaning |
|---|---|---|
- |
< 0.05 | No energy / zero |
1 |
0.05-0.14 | Very low |
2 |
0.15-0.24 | Low |
3 |
0.25-0.34 | Low-medium |
4 |
0.35-0.44 | Medium-low |
A |
0.45-0.54 | Medium |
B |
0.55-0.64 | Medium-high |
C |
0.65-0.74 | High |
D |
0.75-0.84 | Higher |
E |
0.85-0.94 | Very high |
F |
>= 0.95 | Full energy / max |
Single Matrix Example
FFFFF ← Row 0: Full energy at horizon
----- ← Row 1: No energy
----- ← Row 2: No energy
----- ← Row 3: No energy
----- ← Row 4: No energy (shore)
Multi-Frame Progression Example
Shows energy propagating downward over time:
t=0s t=1s t=2s t=3s
FFFFF BBBBB 44444 22222
----- AAAAA AAAAA 44444
----- 22222 44444 44444
----- 11111 22222 33333
----- ----- 11111 22222
Core Utilities
import {
matrixToAscii,
asciiToMatrix,
progressionToAscii,
asciiToProgression,
matricesMatchAscii,
valueToChar,
charToValue,
} from '../test-utils/asciiMatrix';
// Single matrix
matrixToAscii([[1.0, 0.5], [0.0, 0.2]]) // → "FA\n-2"
asciiToMatrix("FA\n-2") // → [[1.0, 0.5], [0.0, 0.2]]
// Multi-frame progression
progressionToAscii(snapshots) // → side-by-side frames with headers
asciiToProgression(asciiString) // → array of {time, matrix}
// Comparison (tolerant to ASCII precision)
matricesMatchAscii(actual, expected) // → true if same when encoded
defineProgression() Framework
import { defineProgression } from '../test-utils/progression';
export const PROGRESSION_ENERGY_PROPAGATION = defineProgression({
id: 'energy-field/propagation',
description: 'Energy propagates from horizon toward shore',
initialMatrix: [
[1.0, 1.0, 1.0, 1.0, 1.0], // Horizon: full energy
[0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0], // Shore: no energy yet
],
updateFn: (matrix, dt) => propagateEnergy(matrix, dt),
captureTimes: [0, 1, 2, 3, 4, 5], // Capture snapshots at these times
});
// Access computed snapshots
PROGRESSION_ENERGY_PROPAGATION.snapshots[0].matrix // t=0
PROGRESSION_ENERGY_PROPAGATION.snapshots[3].matrix // t=3
Testing Progressions
Inline ASCII Assertions
import { describe, it, expect } from 'vitest';
import { progressionToAscii } from '../test-utils/asciiMatrix';
describe('PROGRESSION_ENERGY_PROPAGATION', () => {
it('produces expected time evolution', () => {
const ascii = progressionToAscii(PROGRESSION_ENERGY_PROPAGATION.snapshots);
expect(ascii).toBe(`
t=0s t=1s t=2s t=3s
FFFFF BBBBB 44444 22222
----- AAAAA AAAAA 44444
----- 22222 44444 44444
----- 11111 22222 33333
----- ----- 11111 22222
`.trim());
});
});
Point Assertions
it('energy reaches row 3 by t=3s', () => {
const snapshot = PROGRESSION_ENERGY_PROPAGATION.snapshots[3];
expect(snapshot.matrix[3][0]).toBeGreaterThan(0);
});
Workflow: Designing a New Progression
- Sketch ASCII first - Draw what you expect the evolution to look like
- Write the test - Use
progressionToAscii()with your expected ASCII - Implement the logic - Write the
updateFnthat produces this behavior - Run test -
npx vitest run src/render/myProgressions.test.ts - Iterate - Adjust coefficients until ASCII matches expectations
Design-first workflow:
Sketch ASCII → Write test → Implement → Verify
NOT trial-and-error:
Implement → Run → "Hmm, that looks wrong" → Tweak → Repeat
Why ASCII Over Vitest Snapshots?
| Aspect | ASCII | Vitest Snapshots |
|---|---|---|
| Readability | Visual pattern obvious | Wall of numbers |
| Size | 7 lines for 6 frames | 1000+ lines |
| Location | Inline in test | Separate file |
| Diffs | Shows exactly which cells changed | Hard to parse |
| Design | Can sketch expected output first | Must run to generate |
Relationship to Visual Testing
Progression tests verify the data (matrix values). Visual tests verify the rendering (pixels on screen).
Progression Test (this skill) Visual Test (visual-testing skill)
↓ ↓
Matrix data Screenshot
[1.0, 0.5, 0.2] [PNG pixels]
↓ ↓
ASCII: "FA2" Baseline comparison
Always verify data first. If the matrix is wrong, the visual will be wrong too. Don't debug rendering when the underlying data is the problem.
See visual-testing skill for screenshot-based regression testing.
Commands
# Run progression tests
npx vitest run src/render/bathymetryProgressions.test.ts
npx vitest run src/state/energyFieldProgressions.test.ts
# Run all test utilities (including ASCII)
npx vitest run src/test-utils/
# Watch mode for development
npx vitest src/render/foamProgressions.test.ts
Common Patterns
Testing Boundary Conditions
it('handles zero initial energy gracefully', () => {
const progression = defineProgression({
initialMatrix: createZeroMatrix(5, 5),
updateFn: propagateEnergy,
captureTimes: [0, 1, 2],
});
// Should remain zero (no energy to propagate)
expect(matrixToAscii(progression.snapshots[2].matrix)).toBe(
'-----\n-----\n-----\n-----\n-----'
);
});
Testing Conservation Laws
it('total energy decreases with damping', () => {
const snapshots = PROGRESSION_WITH_DAMPING.snapshots;
const totalEnergy = (m: number[][]) => m.flat().reduce((a, b) => a + b, 0);
expect(totalEnergy(snapshots[3].matrix))
.toBeLessThan(totalEnergy(snapshots[0].matrix));
});
Comparing Two Progressions
it('damped version has less energy than undamped', () => {
const damped = PROGRESSION_WITH_DAMPING.snapshots[3].matrix;
const undamped = PROGRESSION_NO_DAMPING.snapshots[3].matrix;
const sum = (m: number[][]) => m.flat().reduce((a, b) => a + b, 0);
expect(sum(damped)).toBeLessThan(sum(undamped));
});
Related Skills
Xlsx
Comprehensive spreadsheet creation, editing, and analysis with support for formulas, formatting, data analysis, and visualization. When Claude needs to work with spreadsheets (.xlsx, .xlsm, .csv, .tsv, etc) for: (1) Creating new spreadsheets with formulas and formatting, (2) Reading or analyzing data, (3) Modify existing spreadsheets while preserving formulas, (4) Data analysis and visualization in spreadsheets, or (5) Recalculating formulas
Clickhouse Io
ClickHouse database patterns, query optimization, analytics, and data engineering best practices for high-performance analytical workloads.
Clickhouse Io
ClickHouse database patterns, query optimization, analytics, and data engineering best practices for high-performance analytical workloads.
Analyzing Financial Statements
This skill calculates key financial ratios and metrics from financial statement data for investment analysis
Data Storytelling
Transform data into compelling narratives using visualization, context, and persuasive structure. Use when presenting analytics to stakeholders, creating data reports, or building executive presentations.
Kpi Dashboard Design
Design effective KPI dashboards with metrics selection, visualization best practices, and real-time monitoring patterns. Use when building business dashboards, selecting metrics, or designing data visualization layouts.
Dbt Transformation Patterns
Master dbt (data build tool) for analytics engineering with model organization, testing, documentation, and incremental strategies. Use when building data transformations, creating data models, or implementing analytics engineering best practices.
Sql Optimization Patterns
Master SQL query optimization, indexing strategies, and EXPLAIN analysis to dramatically improve database performance and eliminate slow queries. Use when debugging slow queries, designing database schemas, or optimizing application performance.
Anndata
This skill should be used when working with annotated data matrices in Python, particularly for single-cell genomics analysis, managing experimental measurements with metadata, or handling large-scale biological datasets. Use when tasks involve AnnData objects, h5ad files, single-cell RNA-seq data, or integration with scanpy/scverse tools.
Xlsx
Spreadsheet toolkit (.xlsx/.csv). Create/edit with formulas/formatting, analyze data, visualization, recalculate formulas, for spreadsheet processing and analysis.
