Posters, packaging, business cards — QR is everywhere, and dropping a black-and-white square onto a design you spent weeks on has always stung. But QR looks the way it does for a reason: it is what you build when a 1994 camera and 1994 silicon have to read it at all.
Those constraints have largely lifted. Phone cameras and compute have room to spare now. So instead of chasing recognition alone, we spent that headroom on being worth looking at. This is not a replacement for QR — it is a seat next to it.
QR was the right answer for its moment. Two values, square modules, big finder patterns — every one of those choices existed so a weak camera could still read it. Under those constraints, giving up on looks was rational.
That premise changed. Phone cameras today are nothing like those, and real-time video processing runs inside a browser. So the headroom could go into density — or it could go into how it looks. That is why this exists.
Density was the trade. Rhombic cells are less area-efficient than square modules. This format does not compete on density. If you need to carry a lot, QR is the right tool.
Pick by where it will sit. All three share one data contract and differ only in silhouette. Every code below encodes https://tl.estre.so.
Three n×n faces. A single solid mark, good for signage and merch.
The base form. Rhombic cells tile outward from a central finder.
A hexagonal core plus corner patches, forming an equilateral triangle.
Net payload is at ECC-M. All three types can carry a fallback QR alongside, so there is still a path where a TL code cannot be read.
A rhombille tiling splits each hexagonal cell into T, L and R faces.
Ranking the three luminances gives 3! = 6 outcomes — one base-6 digit.
Reed–Solomon over the prime field GF(211) corrects errors.
Invariant under monotonic transforms. Global lighting shifts, gamma, and printer tone mapping are monotonic — they cannot change an ordering. If the order survives, the value survives.
The renderer stays free. The data contract is only "the order between faces, plus a minimum separation". Inside that, colour, texture, per-face gradients and animation are all open. That freedom is the point of the format.
It does not make anything pretty on its own. What opens up is the contract, not the outcome. What you draw inside it is still your work.
The decoder is under development. The numbers below come from photos taken on real phones — not synthetic test renders.
| Type | Real photos decoded | Decode time | Live scanning |
|---|---|---|---|
| Type Y — single cube | 3 / 3 | ~0.4 s | usable |
| Type O — hex field | 3 / 3 | ~1.1 s | improving |
| Type A — triangular silhouette | 2 / 3 | ~0.8 s | improving |
| Centre-QR variant (all three types) | 8 / 9 | — | improving |
Decode time dominates how live scanning feels. The scanner looks at a frame roughly every 0.3 s, so when one read takes several seconds the frames in between are dropped — and regardless of accuracy it feels like it “only reads once in a while”. Speed is the top priority right now.
Shooting conditions matter too. Measured, 9 pixels per cell was the decode floor, and at the same distance an ultra-wide lens frames the code smaller and drops below that line (ultra-wide 7.6 px failed / wide 9.1 px succeeded). That is why the scanner offers a lens picker.
In the centre-QR variant a QR block takes the place of the central finder. It was unreadable for a while because there was no entry point; a path that uses the QR’s own finder patterns as reference now handles it.
Measured 2026-08-11 · sample of 9 photos across three phone sensors (ultra-wide, wide, telephoto) · short side 1440 px. The sample is small — read this as a current state, not a success rate.
The format spec and reference implementation are published under the Apache License 2.0. Vanilla JavaScript, no build toolchain, zero runtime dependencies — it runs as a single HTML file.
Implementing only the decoder counts as a conforming implementation. Adoption starts with the reading side.
| Site | Role | State |
|---|---|---|
| tlcube.estre.so | Generator | live |
| tlscan.estre.so | Scanner | in development — status › |
| tl.estre.so | Overview hub | you are here |