Spring Cleaning 2026 Day 3: h3 & fixing ascii boxes

H3 and Fixing ASCII Boxes

Smaller updates today.

H3

https://github.com/mattsta/h3

H3 has been either mostly complete, closed, or abandoned for a while, but there’s still room for improvement.

I’m forking it here with my own refactors and improvements: https://github.com/mattsta/h3

Performance — the headline numbers

Single-cell hot path

API upstream → optimized speedup
cellToBoundary 0.50 µs → 0.23 µs ~2.13×
cellToLatLng 0.12 µs → 0.08 µs ~1.55×
cellToVertexes (full ring) 19.5 µs → 15.1 µs ~1.29×
polygonToCellsExperimental (Full) varies ~1.65–1.76×
polygonToCellsExperimental (Overlapping) varies ~1.32–1.49×
polygonToCellsExperimental (Center) varies ~1.39–1.46×
polygonToCells (legacy polyfill) varies ~1.13–1.18×
gridDisk (k=10–40) varies ~1.17–1.22×
gridDisk pentagon paths (k=10–40) varies ~1.51–1.84×
Bulk cellToChildren (allCellsAtRes) varies ~1.84–2.15×

New bulk APIs (cellsToLatLngs, on top of single-cell wins)

For applications converting millions of cells (visualization, map rendering, analytics pipelines), the new SIMD-batched bulk APIs deliver another ~2× throughput multiplier over a per-cell loop:

batch size N per-cell loop batched speedup
16 1.48 µs 0.73 µs 2.03×
256 23.86 µs 11.45 µs 2.08×
1024 94.96 µs 45.22 µs 2.10×
8192 767.52 µs 388.09 µs 1.98×

Stacked end-to-end vs. upstream, the fastest paths reach ~2.18× cellToBoundary, ~1.80× polygonToCellsExperimental, and ~1.98× bulk cellToChildren on a single Apple Silicon core. Add H3_ENABLE_OPENMP=ON and the bulk APIs scale further across cores at batches above ~1024.

The improvements are not bit-identail to original H3 in every case, but the cost of the improvements is one bit difference for 2x faster speeds which amounts to 180 nm earth-surface difference in the encoding.


Fix ASCII Boxes

https://github.com/mattsta/fix-ascii-boxes

The hottest trend is computing is using agents to draw ascii art architecture diagrams then not auditing or fixing all the alignment problems in charts the agents draw with pipes and dashes and other fancy characters in potentially dozens or hundreds of files across a project.

so, i wrote/generated a thing to fix it: https://github.com/mattsta/fix-ascii-boxes

If you have markdown files with broken claude/codex style ascii art box diagrams, the fix-ascii-art system aligns:

  • outerborders
  • inner borders if there are nested boxes
  • can even re-flow or center nested ascii boxes and text inside other nested ascii boxes
# Install (uv / pip both work — only stdlib at runtime)
uv sync                                              # builds + installs entry points

# Common operations
uv run fix-ascii-boxes docs/architecture.md          # fix in place (align mode)
uv run fix-ascii-boxes --check docs/*.md             # CI gate: exit 1 if changes needed
uv run fix-ascii-boxes --diff docs/architecture.md   # preview the diff without writing
uv run fix-ascii-boxes --dry-run                     # show output, don't touch files
cat broken.md | uv run fix-ascii-boxes               # stdin → stdout

Five commands ship as entry points:

Command What it does
fix-ascii-boxes Repair / re-layout diagrams. Supports --mode, --layout-strategy, --check, --diff, --dry-run.
fix-ascii-boxes-audit Read-only inspection of boxes, suspect rows, per-pass convergence.
fix-ascii-boxes-validate Parse + round-trip every fenced block in a set of files via the AST pipeline.
fix-ascii-boxes-bench Throughput benchmark on synthetic input.

The two flags that change behavior the most:

--mode {align,reflow,distribute,layout}            # which engine + how aggressive
--layout-strategy {natural,distributed,centered,flush_left}   # for --mode layout

Run Modes

There are three basic run modes at various levels of complexity and features:

Each text-pipeline mode is a strict superset of the previous, so the behavior monotonically increases. layout (the AST pipeline) sits beside them and produces equivalent output on supported diagrams.

Mode Safe in CI? Re-flows widths? Re-distributes gaps? Round-trips?
align (default) yes — idempotent, never truncates no no only if source is already aligned
reflow yes yes — widens to fit overflow no no — overflow rows widen
distribute yes yes yes no — gaps re-balanced
layout + --layout-strategy natural yes — pure parse + re-render no no yes on supported shapes
layout + --layout-strategy distributed yes as needed yes — AST level no — equivalent to distribute

Layout strategies

Row.strategy controls how a band of siblings is positioned. Set via apply_strategy(tree, name) or the --layout-strategy CLI flag.

Strategy What it does Use when
natural Re-use source gaps exactly You want round-trip — preserve everything
distributed Re-allocate gaps evenly (lpad / between / rpad) You want consistent visual spacing
centered Single-pad on each side, MIN_GAP between You want the band centered in its parent
flush_left No leading pad, MIN_GAP between You want to pack tightly to the left

Example — same source band, three strategies:

source:        │   ┌─────┐ ┌─────┐ ┌─────┐                              │
natural:       │   ┌─────┐ ┌─────┐ ┌─────┐                              │
distributed:   │          ┌─────┐         ┌─────┐         ┌─────┐       │
centered:      │              ┌─────┐ ┌─────┐ ┌─────┐                   │
flush_left:    │┌─────┐ ┌─────┐ ┌─────┐                                 │

Examples

Example 1 — align mode repairs a misaligned right edge

Source:

┌──────────┐
│ Hello    │
│ World      │     ← right edge drifted past target
│ Foo      │
└──────────┘

uv run fix-ascii-boxes --mode align re-snaps the right edge:

┌──────────┐
│ Hello    │
│ World    │
│ Foo      │
└──────────┘

If “World” had been wider than └──────────┘ allows, the row would have been flagged as overflow instead of misaligned and align mode would refuse to touch it (reflow would widen the whole box).

Example 2 — overflow handling

Source has Coordinator (11 chars) crammed into a 10-wide declared box:

┌──────────┐
│Coordinator│
│  Agent   │
└──────────┘

--mode align refuses to touch it — the row is classified as overflow, not misaligned, and align won’t truncate. The diagram passes through unchanged with the misalignment flagged in --check output.

--mode reflow widens the box’s declared width by enough cols to fit the overflowing content (1 col here) and shifts every non-flush row to match:

┌───────────┐
│Coordinator│
│  Agent    │
└───────────┘

--mode layout produces the same output via the AST pipeline: the parser’s _slice_interior scans ±3 cols for the actual , and Container.compute_size widens to fit. Both modes are equivalent on this case.

Example 3 — distribute re-balances gaps across a band

Source has flush-left siblings:

┌─────────────────────────────────────────────────────────────────────┐
│ ┌──────────┐ ┌──────────┐ ┌──────────┐                              │
│ │   Foo    │ │   Bar    │ │   Baz    │                              │
│ └──────────┘ └──────────┘ └──────────┘                              │
└─────────────────────────────────────────────────────────────────────┘

uv run fix-ascii-boxes --mode distribute:

┌─────────────────────────────────────────────────────────────────────┐
│         ┌──────────┐        ┌──────────┐        ┌──────────┐        │
│         │   Foo    │        │   Bar    │        │   Baz    │        │
│         └──────────┘        └──────────┘        └──────────┘        │
└─────────────────────────────────────────────────────────────────────┘

Siblings re-distribute across the parent’s interior; any ┬│▼ vertical pipelines are repositioned to track their owning child.

Example 4 — layout mode with natural strategy round-trips

Same input as Example 3, but:

uv run fix-ascii-boxes --mode layout --layout-strategy natural < band.md

Returns the source byte-identical. Useful for confirming the AST parser handles your diagram, or as a regression check before committing edits.

Example 5 — programmatic manipulation

import layout_engine as le

tree = le.parse(text)

# Find the Operation box and rename it
for row in tree.contents:
    if isinstance(row, le.Row):
        for child in row.children:
            for content in child.contents:
                if isinstance(content, le.TextLine) and "Operation" in content.text:
                    content.text = "Execute"

# Re-distribute the bands and render
le.apply_strategy(tree, "distributed")
print(le.render(tree))

Validation & performance

uv run fix-ascii-boxes-validate FALSE_CASE.txt docs/*.md
uv run fix-ascii-boxes-bench --scale

Sample throughput:

   lines      chars   blocks   seconds         l/s          c/s
----------------------------------------------------------------
    1000      42192       72     0.012      74,997    3,377,026
   10000     419576      716     0.117      79,616    3,588,477
   50000    2093192     3572     0.576      80,643    3,635,090

conclusion

what else do you people want? you can’t complain about any of this because it’s all free.