Topology imaging kernel (distributed-inference)
Rust-first primitives for topology-guided masking, minimal compositing, Lambert relighting, and a mesh-governed depth field plus extrusion. TypeScript hosts should treat these as FFI/WASM callers, not duplicate the pipeline.
Parity scope (editor vertical)
Priority vertical: photo retouch and compositing (local pixel edits, layered blends, matte-driven adjustments). Typography, vector-heavy design tools, PSD I/O, and full color-management are explicitly out of scope for this crate; they belong in separate editor stacks.
Native modules
| Module | Role |
|---|---|
topology_mask |
Interest planes → multi-scale super-level sieve → soft alpha [0,1] + TopologyMaskProvenance (JSON via serde). |
imaging_composite |
Source-over and multiply blending with per-pixel alpha; mask_multiply_rgb for mask-linked tonal adjustments. |
imaging_relight |
Finite-difference normals from a scalar plane × Lambert-ish shading; topology_alpha gates where relight replaces source RGB. |
mesh_depth_field |
Mesh-governed depth: fuses classical proxy depth + topology alpha (+ optional ONNX prior) with per-pixel confidence and MeshDepthProvenance (schema_version: mesh_depth_provenance/v1). |
depth_monocular_cues |
Five-level dyadic luma bands + cheap Gibsonian proxies (texture gradient, aerial perspective, horizontal-dominant structure, luminance edges). Optional blend via MeshDepthConfig::monocular_cue_blend. Not transformer standing_wave_pinning (attention Q/K/V); same “multi-scale admission” pattern, different signal. |
depth_metric_anchor |
SI / metric anchors after a ratio-scale field: known mask + extent (scale_meters_per_relative_unit_from_known_extent), CameraIntrinsics → m/px at Z, stereo Z=f·B/d, Sim3-style scale from world vs unit translation (depth_metric_anchor.rs). MeshDepthMetricAnchor + MetricAnchorFire integrate into build_mesh_depth_field (optional 6th arg); provenance metric_anchor + parallel values_meters. |
depth_extrusion |
Classical proxy estimate_depth_classical_normalized; optional native ONNX via depth-onnx feature + depth_onnx; extrude_depth_heightfield_rgb and extrude_depth_heightfield_rgb_weighted (Z × confidence). |
text_topology |
Not-quite-OCR: domain-neutral ink topology extraction for handwriting and line art. Emits stroke components, graph-ish shape facts, text-likeness priors, Rosetta bridge entries, and optional cleared-image previews. Language decoding belongs to aeon-communication / rosetta-datacore; training belongs to open-source/buleyean-rl. |
Text topology: not quite OCR
The _why handwriting work is intentionally not OCR first. OCR starts with a
language target and asks which pixels spell it. This crate starts one layer
lower: text as topology.
The mesh extractor sees arbitrary ink shapes and reports:
- connected stroke components;
- bounding boxes and normalized page positions;
- density, endpoints, junctions, coarse loop estimates, and aspect;
- a text-likeness prior that only says "this shape participates in a language-like stroke topology";
- render-layer hints (
text,unknown,art) for removal/rewrite previews.
It does not decide that a component is an a, fox, or Chunky bacon!!.
Those are language-domain claims. The handoff is:
image ink
-> distributed-inference/text_topology: arbitrary stroke mesh
-> rosetta-datacore: symbols, candidates, anchors, collisions, mesh display
-> aeon-communication: language-specific decoding and Rosetta pressure
-> buleyean-rl: rejection ledgers for "not this glyph / not safe to erase"
-> image mesh projection: clear and rewrite the recovered text manifoldThe first art-project side effect is a cleared preview: high-confidence
text-like ink components can be filled into a new PNG while the full topology
JSONL remains available for Rosetta/Buleyean training. Clearing is background
aware at the component level: each erased stroke is replaced with a local
non-ink fill sampled around its bounding box, preserving transparent or off-white
page backgrounds better than a hard white stamp. Admission is intentionally
more conservative than raw ink detection: candidate strokes are grouped into
baseline-like bands, and clearing only happens when a band has enough glyph-sized
repetition to look language-shaped. This protects small drawing marks such as
eyes and mouths, which can share the same local topology as punctuation. The
clearer then runs a second, bounded artifact cleanup pass inside admitted text
bands to remove anti-aliased residue. When --clear-iterations N is greater
than one, the topology pass reruns on the current preview until it reaches a
fixed point or the cap is hit. Primary black ink that survives stabilization is
treated as an unresolved semantic artifact rather than erased blindly unless an
explicit --clear-residual-threshold admits it. The same admitted text bands can
also be emitted as source-resolution alpha assets: a grayscale text-region mask
and a transparent text-region cutout. Those alpha assets use a Teddy-style stroke
envelope: admitted component pixels are dilated and lightly closed so the layer
hugs the written marks instead of filling the whole baseline rectangle. These
layers share the original image coordinate frame, so the cleared base and cutout
can recompose exactly or be transformed independently for mesh/image mashups. The
preview is not the final inpainted page; it is the visual falsification surface
for whether the mesh chose the right text layer.
Native CLI:
cargo run -p distributed-inference --bin why-text-topology -- \
--input /path/to/__why \
--out /tmp/why-text-topology \
--candidate-limit 500 \
--emit-cleared \
--emit-region-masks \
--emit-text-cutouts \
--emit-depth-probes \
--emit-pixel-moa-probes \
--emit-surface-probes \
--clear-threshold 0.55 \
--clear-radius 1 \
--clear-iterations 3 \
--clear-region-radius 6 \
--monocular-cue-blend 0.6Operational _why run used during development:
cargo run -p distributed-inference --bin why-text-topology -- \
--input ./tmp/why-text-project/__why \
--out ./tmp/why-text-project/rust-full-filament-set \
--candidate-limit 500 \
--emit-cleared \
--emit-region-masks \
--emit-text-cutouts \
--emit-depth-probes \
--emit-pixel-moa-probes \
--emit-surface-probes \
--clear-threshold 0.55 \
--clear-radius 1 \
--clear-iterations 3 \
--clear-residual-threshold 0.5 \
--clear-region-radius 6 \
--clear-pixel-moa-recovery \
--monocular-cue-blend 0.6Outputs:
text-topology-corpus.jsonl— full stroke topology corpus;rosetta-import-payload.json— compact datacore import payload, including stroke candidates,textLineCandidatesfor language-shaped band admission, andresidualTextArtifactsfor primary ink fragments that need semantic review before cleanup.residualReviewQueuegroups those fragments by line and ranks the lines that most need semantic admission/protection.meshTextAdmissionLedgerrecords each component as a subject/object/verb FRFVI operation, distinguishing admitted text, measured non-text, unresolved unknowns, and active demotions;cleared/*.cleared.png— optional erased-text previews;cleared/*.text-region-mask.png— optional reusable alpha masks for admitted text regions;cleared/*.text-region-cutout.png— optional transparent source cutouts for recomposition or independent text-layer transforms;cleared/*.depth-probe.pngandcleared/*.depth-confidence.png— optional mesh-governed monocular probe layers for testing whether surface/depth cues can separate speech-bubble text from drawing contours before they influence admission;cleared/*.pixel-moa-probe.png— optional pixelwise mixture-of-attention probe. It forks local darkness, stroke-density, horizontal-cadence, and surface ownership heads, then folds them into a per-pixel admission prior for visual debugging before the result is allowed to erase anything;cleared/*.surface-mask-probe.png— optional mesh/surface ownership probe. Bright pixels are eroded background/speech-surface interiors; dim pixels are protected near-boundary interiors. This is the current “where may text live?” contract for recovery experiments;cleared/*.surface-fragment-probe.png— optional clipped-fragment probe. It paints ink fragments with nearby eroded surface support, then marks fragments that the opt-in recovery classifier would admit. Punctuation is treated as a small-fragment outlier class: it may lack letter rhythm but still belongs to a nearby admitted language band or speech surface. Use this probe to distinguish missing surface support from rejected semantics before changing thresholds.
--clear-pixel-moa-recovery is deliberately opt-in. It clips candidate ink to
surface-supported fragments before erasure, but the current failure mode is still
semantic attachment: bubble contours can have nearby surface support, while
connected letters such as descenders may need word-level attachment evidence.
Text recomposition CLI
why-text-recompose writes new text back into cleared images. It is a local,
programmatic compositor: no OCR, no external font dependency, no AI call. It
expects a cleared PNG plus the matching *.text-region-mask.png emitted by
why-text-topology.
Single image:
cargo run -p distributed-inference --bin why-text-recompose -- \
--image /tmp/why-text-topology/cleared/the.foxes-4c.cleared.png \
--mask /tmp/why-text-topology/cleared/the.foxes-4c.text-region-mask.png \
--out /tmp/why-recomposed \
--layout surface \
--text "MESH SEES WORDS|TEXT AS TOPOLOGY"Full directory:
cargo run -p distributed-inference --bin why-text-recompose -- \
--image /tmp/why-text-topology/cleared \
--mask /tmp/why-text-topology/cleared \
--out /tmp/why-recomposed/full-set \
--layout surface \
--text "MESH SEES WORDS|TEXT AS TOPOLOGY"Useful output locations from the _why working set:
./tmp/why-text-project/recomposed-first-pass/full-set
./tmp/why-text-project/recomposed-contained-pass/full-set
./tmp/why-text-project/recomposed-compact-pass/full-set--layout mask draws inside the old text footprint. It is conservative and
useful as a falsification control: if text appears in the wrong place, the mask
admission is wrong.
--layout surface derives speech-bubble-like surfaces from white enclosed
regions, intersects them with text-mask anchors, rejects broad panel whitespace,
erodes each candidate slot to a clean mostly-white interior, and then fits text
inside the remaining rectangle. This is the preferred art-project mode.
--text accepts either plain sentences or explicit slot separators:
one sentence only
first bubble|second bubble|third bubble
The mesh sees the words. The bubble keeps the shape.Explicit | separators are preserved as semantic units. Without |, sentence
punctuation (., !, ?) is used for ranked placement.
Random ranked recomposition
For a fun exploration loop, --random-ranked chooses one image from a directory
instead of recomposing every file. It ranks candidate images by physical fit and
then randomly selects among the top tier.
cargo run -p distributed-inference --bin why-text-recompose -- \
--image ./tmp/why-text-project/rust-full-filament-set/cleared \
--mask ./tmp/why-text-project/rust-full-filament-set/cleared \
--out ./tmp/why-text-project/recomposed-random-eroded \
--layout surface \
--random-ranked \
--text "The mesh sees the words. The bubble keeps the shape."The command prints:
ranked_random_choice=<image id>
ranked_random_score=<0..1 physical fit>
ranked_random_slots=<usable slot count>
recomposed=<output png>Ranking is topology-aware, not semantic OCR:
- sentence/unit count is compared to usable slot count;
- slot capacity is estimated from the clean interior rectangle and compact font metrics;
- slot balance rewards images where multiple bubbles have comparable capacity;
- one sentence is penalized when the image has multiple separate bubbles;
- two sentences are rewarded when the image has two usable bubbles.
Recomposition renderer
The renderer has two built-in bitmap fonts:
- normal: 5x7 glyphs with 1-pixel tracking, scaled by integer factors;
- compact: 3x5 glyphs, used when the normal font cannot fit a narrow slot.
The fitter chooses the largest complete rendering that fits the slot. It wraps
words, breaks long words only when needed, and falls back to compact glyphs for
small or vertical bubbles. --scale N can force a maximum scale, but operational
use usually leaves scale unset so the fitter can choose.
Containment rules are intentionally biased toward false negatives:
- broad white panel interiors are rejected as surfaces;
- slots whose background contains too much dark artwork are skipped;
- dirty borders are eroded away before text is placed;
- if no clean slot remains in
--layout surface, the image is emitted unchanged rather than drawing into uncertain space.
This means some valid bubbles will be skipped. That is preferable to writing replacement text over characters, trees, antlers, panel art, or open contours.
Recommended operation loop
- Unpack or stage source images into a directory such as
/tmp/why-text-project/__why. - Run
why-text-topologywith--emit-cleared --emit-region-masks --emit-text-cutouts --emit-surface-probes. - Inspect a few
*.cleared.png,*.text-region-mask.png, and*.surface-fragment-probe.pngfiles. - Run
why-text-recompose --layout surfaceon a focused image. - Run
why-text-recompose --layout surface --random-rankedfor exploration. - Run the full directory only after the focused sample looks sane.
Focused sample command:
cargo run -p distributed-inference --bin why-text-recompose -- \
--image ./tmp/why-text-project/rust-full-filament-set/cleared/the.foxes-4c.cleared.png \
--mask ./tmp/why-text-project/rust-full-filament-set/cleared/the.foxes-4c.text-region-mask.png \
--out ./tmp/why-text-project/recomposed-sample \
--layout surface \
--text "MESH SEES WORDS|TEXT AS TOPOLOGY"Full recomposition command:
cargo run -p distributed-inference --bin why-text-recompose -- \
--image ./tmp/why-text-project/rust-full-filament-set/cleared \
--mask ./tmp/why-text-project/rust-full-filament-set/cleared \
--out ./tmp/why-text-project/recomposed-compact-pass/full-set \
--layout surface \
--text "MESH SEES WORDS|TEXT AS TOPOLOGY"Tuning guide
| Symptom | First knob / check |
|---|---|
| letters remain after clearing | inspect *.text-region-mask.png; if the mask contains them, tune clearing/envelope; if not, tune admission/recovery |
| a connected glyph is glued to a bubble line | use --clear-pixel-moa-recovery and inspect *.surface-fragment-probe.png |
| text is too large or vertical | leave --scale unset so compact font fallback can engage; shorten the semantic unit or split with ` |
| text draws over art inside a bubble | inspect surface mode; dirty-slot erosion should skip or shrink it; if it still draws, the clean-background threshold is too permissive |
| random picker chooses a one-bubble image for two sentences | check ranked_random_slots; if slots are low, surface detection rejected candidate bubbles as unsafe |
| good image is skipped | run --layout mask as a control to determine whether the mask exists; surface mode may be rejecting open contours |
Verification
For source changes in this area:
cargo fmt
cargo check --bin why-text-topology
cargo check --bin why-text-recompose
cargo test text_topology --libFor Markdown-only edits, no code check is required; read the touched docs and verify command examples still match the current CLI usage strings.
Mesh-governed depth field (Monster Mesh operator pattern)
Monster Mesh in this repo maps to the Pleromatic / transport layer (PleromaticFrame, SovereignSieve, …) used for logic and fingerprint reassembly—not literal Monster-group depth inversion. For imaging, we reuse the same engineering roles: multiple views (priors), sieve admission (agreement + topology gate), and JSON provenance.
- Priors (views):
Classical(deterministic luma/contrast proxy indepth_extrusion.rs),TopologyAlphafrombuild_topology_alpha, optionalOnnxwhen compiled with--features depth-onnxand a weights path is supplied at runtime, optionalMonocularCueswhenMeshDepthConfig::monocular_cue_blend> 0 (depth_monocular_cues.rs). - Cue stack (human-style heuristics): Gibsonian texture gradient, aerial perspective (cool / desat + coarse luma), linear-perspective proxy (horizontal-vs-vertical gradient dominance), and occlusion / boundary support (Sobel on luma—complements topology T-junctions). Metric depth is not automatic:
MonocularCueProvenance::scale_ambiguityrecords ratio-scale honesty; applydepth_metric_anchorwhen the host has known extent + mask, intrinsics + reference Z, stereo(f_px, B, d), or world translation vs Sim units. - Output:
MeshDepthField:valuesandconfidencein[0,1], plusMeshDepthProvenance(fragments, nestedtopology,degraded_mode,schema_version). - Sieve: Per pixel, classical and ONNX (if present) are blended when they agree within
MeshDepthConfig::agreement_threshold; disagreement scales confidence down. Topology alpha gates towardneutral_depthwhere contours are unstable so edges do not solo-drive extrusion. - Tile summaries (optional):
build_mesh_depth_tile_summariespacks tile means intoPleromaticDepthTileSummary(level,phase = level % 3,media: "Image") for Forge/logging—not full 4K×4K×Z voxels throughSovereignSieve(out of scope until an explicit sizing policy exists).
Non-goals
- Full-resolution holographic voxel sieve for every RGB frame.
- Any claim that Lean Monster representation theory is monocular depth; alignment is vocabulary and provenance structure only.
- Paid or worker-bound external inference: ONNX stays native-only, behind
depth-onnx; wasm builds omitort.
Cross-cutting spec (contracts and gates)
| Topic | Contract |
|---|---|
| Uncertainty grammar | Use confidence / admission consistently: topology alpha, mesh depth sieve, and weighted extrusion read the same “why trust this pixel” shape. |
| Color | Buffers are linear RGB in [0,1], row-major RGBRGB…. Classical and topology paths assume this; ONNX models must match training (often sRGB in the wild—document and convert at the host if needed). |
| Degraded mode | MeshDepthProvenance::degraded_mode: full, onnx_disabled, onnx_shape_mismatch, or onnx_err_* when the third prior fails; fusion continues on classical + topology where possible. |
| ONNX I/O (pinned) | See depth_onnx.rs: NCHW float [1,3,H,W] input; env DEPTH_ONNX_INPUT_NAME / DEPTH_ONNX_OUTPUT_NAME (defaults input / output); float output [1,1,H,W] or [1,H,W]; min–max normalize to [0,1]. |
| Provenance schema | mesh_depth_provenance/v1 in JSON; additive optional monocular_cues and metric_anchor (MetricAnchorFire). Bump schema_version if fragment semantics change incompatibly. |
| Ship gates (suggested) | Default cargo test: finite depth, [0,1], two-fragment bootstrap, extrusion index counts, weighted Z strictly below full extrusion when confidence < 1. Optional: MAE vs raw ONNX on smooth synthetics (#[ignore] until DEPTH_ONNX_MODEL is set). |
| Safety (untrusted images) | Enforce max megapixels / timeouts at the host; this crate does not allocate beyond width*height; callers must cap dimensions. |
| CI | Default features do not enable ort. ONNX regression: DEPTH_ONNX_MODEL=/path/to/model.onnx cargo test -p distributed-inference --features depth-onnx mesh_depth_onnx -- --ignored. |
Wasm contract (wasm32 build)
Exported from wasm_topology_mask.rs:
wasmTopologyMaskBuildRgbF32(rgb: Float32Array, width, height) -> WasmTopologyMaskResultalpha:Float32Arraylengthwidth*heightprovenanceJson: JSON string matchingTopologyMaskProvenance
wasmMeshDepthConfidenceRgbF32(rgb, width, height, monocular_cue_blend) -> WasmMeshDepthStyleResultconfidence:Float32Arraylengthwidth*height(frombuild_mesh_depth_field)provenanceJson: JSON string matchingMeshDepthProvenance
wasmCompositeMaskedRgb(bg, fg, alpha, width, height, blendMode)→Float32Arraylengthwidth*height*3blendMode:0= source-over,1= multiply
wasmMaskMultiplyRgb(src, alpha, width, height)→Float32ArraywasmRelightLambertMasked(rgb, plane, topologyAlpha, width, height, lightX, lightY, lightZ, diffuseStrength, ambient)→Float32Array
Mesh depth on wasm: follow-on wasm_bindgen entry mirroring the above (buffers + JSON provenance) once the native API is frozen; native consumers use build_mesh_depth_field / mesh_depth_to_heightfield today.
All RGB buffers are row-major linear light in [0,1], sequential RGBRGB….
Tests
Synthetic coverage: topology_mask/tests_internal.rs, imaging_composite unit tests, mesh_depth_field unit tests, tests/mesh_depth_pipeline.rs, and optional tests/mesh_depth_onnx_validate.rs.
cargo test -p distributed-inference --lib mesh_depth
cargo test -p distributed-inference --test mesh_depth_pipeline
# Release timing (native)
cargo run -p distributed-inference --release --bin bench-mesh-depth -- --w 512 --h 512 --iters 24
# With vendored weights (native only):
DEPTH_ONNX_MODEL=/path/to/model.onnx cargo test -p distributed-inference --features depth-onnx mesh_depth_onnx -- --ignored