The Problem
Encoding text as an image usually means a QR code or a barcode—machine-readable but visually sterile. Graphglyph instead renders text as a unit-distance graph, a mathematical object studied in discrete geometry, so the payload is hidden in the structure of the graph itself. The result is a reversible, aesthetic image that is also a functional data carrier.
What This Does
graph_cipher.py (884 lines, 39 functions) is the encoding/decoding engine. It normalizes text (NFKC), compresses long payloads with zlib, and distributes payload nibbles across a seeded graph where each cell encodes four bits by strengthening one edge in a candidate pair. analyze_reference.py (10 functions) is a separate analysis tool for reading PNGs and computing statistics like percentiles and histograms.
The README documents a CLI: python3 graph_cipher.py encode "text" -o output.svg and python3 graph_cipher.py decode output.svg. SVG and JSON outputs are decodable; PNGs are presentation-only.
How It Is Wired
Execution starts at main in analyze_reference.py:372, which reaches 10 functions. That file is the analysis front-end. The core encode/decode logic lives entirely in graph_cipher.py, which is imported by analyze_reference.py. Neither module imports the other's internals—there are zero import edges between the two.
The internal call graph shows 58 resolved call edges. The busiest functions are Node (called from 5 places), percentile (3), add_visual_edge (3), stable_unit (3), and project_coeffs (3). build_graph is the hub: it calls add_visual_edge 7 times, nearest_indices 3 times, Edge 3 times, and bytes_to_nibbles 2 times. analyze calls percentile 15 times—the hottest edge in the repo.
The wiring is two isolated clusters: graph_cipher.py owns all encoding/decoding, and analyze_reference.py owns all PNG analysis. There is no shared hub, so changing one does not ripple into the other. The downside is that graph_cipher.py is a monolith—all 39 functions in one file—so any change to the encoding logic touches a file that is already hard to hold in one head.
How To Use It
From the README, verbatim:
python3 graph_cipher.py encode "you are loved immensely" \
-o examples/you_are_loved_immensely.svg \
--json examples/you_are_loved_immensely.json
python3 graph_cipher.py decode examples/you_are_loved_immensely.svg
No dependencies, no config files, no environment variables. Python 3 with standard library only. The --variant-strength flag (default 0.75) controls visual variation; 0 gives the exact algebraic box.
Real-World Use
Artistic data embedding: encode a poem, a license key, or a provenance string into a visually appealing graph that can be printed, shared as an image, and later decoded to recover the original text. The zlib compression means even long payloads fit in a single image. The PNG previews are not decodable, so production use requires keeping the SVG or JSON.
Code Health & Issues
Static analysis found 2 medium findings, both in graph_cipher.py:
- Med - Deep nesting - max indentation depth 7, control flow hard to follow. Flatten with early returns or guard clauses.
- Med - Oversized file - 884 code lines, hard to hold in one head; changes ripple widely. Split into cohesive units.
The code health audit adds one medium finding:
- Med - Large binary in repo -
examples/meditations_on_moloch.pngis 10.8MB. Move to Git LFS or object storage; every clone pays for this blob.
SDLC gaps: no tests, no CI/CD pipeline, no license file. The README states "All code written by GPT 5.5," which raises provenance questions for production use.
The Bottom Line
Graphglyph is a clever, self-contained proof of concept for reversible text-to-graph encoding. The math is sound and the CLI is clean, but the single 884-line module, missing tests, and absent license make it unsuitable for production without significant hardening. Use it for artistic or experimental projects where the visual output matters more than maintainability.