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. The result is a 3D barcode — printed flat, but read as solid.
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 five 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.
A separate format from planar Type Y, with H0…H8 grids and 1…6 unique data faces. Add images to blank faces, configure looping rotation, and export glTF, MP4 or Minecraft .schem structures, plus maker files for a physical cube: paper patterns (SVG, PNG, PDF or direct print) and 3MF/STL for 3D printing.
The base form. Rhombic cells tile outward from a central finder.
The 3 o’clock notch fixes both orientation and type in the silhouette. C0–C3 are for close-range scanning; bring C1 and above closer or zoom in.
A hexagonal core plus corner patches, forming an equilateral triangle.
A triangle unioned with its 180° image. Largest payload at the same k.
Net payload is at ECC-M. All five 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 works. All four types read from real-device photos; what is left is raising accuracy and speed. Each time below is one decode of one static photo taken on a real phone — not time to first lock or a live success rate.
| Type | Real photos decoded | One static-photo decode | Live validation |
|---|---|---|---|
| Type Y — single cube | 9 / 16 | ~1.8 s | more data needed |
| Type O — hex field | 29 / 48 | ~1.9 s | more data needed |
| Type A — triangular silhouette | 18 / 19 | ~2.4 s | more data needed |
| Type K — hexagram | 18 / 27 | ~3.1 s | more data needed |
| Centre-QR variant (all four types) · 2026-08-13 | 8 / 9 | — | more data needed |
One decode of one still photo. Type O is now the fastest; A, K and Y sit close together behind it. ⚠ An earlier version of this page said Type Y was the fastest — that was a 9-photo sample, and on a wider sample the order flipped. Do not read these as live first-lock times.
One static-photo decode time does not predict how live scanning feels. In the first real-device lab trace, a fast frame could still lead to a slow first lock when many frames were needed before one succeeded, and the type ranking differed from this static-photo table. That trace covers one device and a small sample, so we do not assign live usability grades yet.
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 replaces the central finder. Its finder patterns provide the position and orientation entry point used to decode the surrounding TL body. The generator now uses this validated path by default for Types O and A. By default the QR remains a reader-link fallback; the payload stays in the TL body.
Measured 2026-08-27 · sample of 110 photos (each tried at 960 · 1440 px short side). ⚠ Most of the sample is photographed off a monitor, so these are not print or in-situ numbers. And 123 of the 233 corpus frames are limit/experiment shots kept precisely because they do not decode yet — they are excluded here. Only the centre-QR row is from the older 2026-08-13 round.
The format spec and reference implementation are published under the Apache License 2.0. Vanilla JavaScript, in-repository Node.js build scripts, 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 | live — status › |
| tl.estre.so | Overview hub | you are here |