Lit QR panels
Cast opal acrylic, the dark QR modules printed onto the sheet in PETG, an LED strip behind. Daylight and backlight switch. They do not blend.
The software works. Its G-code is not print ready: this printer's start and end blocks are missing.
Full sun runs 10,000 to 100,000 lux. No backlight inside a panel this size competes with that, so daylight is the reflective mode and opal acrylic simply reads as a white card. After dark the LED carries it alone.
The strip is 12 V COB at 512 LED/m, warm white, run at roughly 15 percent of its output. Length buys uniformity, so the run is long and dim rather than short and bright, and a fine LED pitch reads as continuous at a 10 to 15 mm cavity depth. Dimming has to be PWM rather than analog for two separate reasons: a panel brighter than its surroundings makes a phone camera stop down and smear the module edges, and a power bank shuts off below roughly 50 to 200 mA, where PWM keeps the current peaks at full scale and the bank stays awake.
A QR is not a shape somebody models. The payload is encoded into a matrix of dark and light modules, and the matrix becomes toolpaths directly. Module edges land exactly on the extrusion grid, and every unit can carry a different code with no CAD step. That is the whole reason this is FDM rather than laser cut and masked.
A slicer takes a mesh and plans perimeters and infill over it. That pass rounds module corners and leaves gap-fill artifacts in precisely the geometry a decoder is reading. It also puts a CAD step in front of every unique code, which throws away the one thing FDM is good for here: variable data becomes a loop.
Two more things fall out of going direct. Z becomes trivial, because the printer probes the bare plate and the measured sheet thickness is simply added to every emitted Z, with no offset macros and with the bed mesh switched off. And each run of adjacent dark modules is drawn as one continuous pass, extended by half a bead at both ends so the corners come out square instead of rounded.
There is roughly one travel per extruding move, and not one retracts. On an opaque part that is cosmetic. On a backlit panel, plastic strung across a clear module is something a decoder can read as data.
Two checks, neither of them a program marking its own homework. The encoder's output is decoded back by zbarimg, an outside decoder sharing no code with ours. The emitter's numbers come from a second program that parses the file and never reads its summary line.
| File | Symbol | Moves | Path | PETG |
|---|---|---|---|---|
| 120 mm unit | v2, 25x25, 3.64 mm modules | 3 380 | 26 437 mm | 5.4 g |
| 290 mm symbol | v3, 29x29, 10 mm modules | 12 324 | 238 139 mm | 48.4 g |
They were parsed back out of two emitted files. A different payload prints a different pattern, so these are those two files' numbers rather than constants for the format.
You cannot re-derive these numbers, and that is worth saying here. Neither the two G-code files nor the generator that emitted them is public: the code sits in a private repository and no file from it has been published. So every count on this page rests on trust, which is the opposite of what the page is for.
The captions under the two drawings used to carry what looked like a command,
qr/the renderer the emitted file --layer 1. It was never runnable. The two
words standing in for a program name and a file name are exactly the two things the
publishing gate scans visible text for, and removing them is how a page passes that gate
without publishing anything. Corrected 2026-08-11 by saying it in plain words instead.
Moves and path length are counted. The grams are not: they come from the extrusion length the file commands, taken as PETG at 1.27 g/cm3.
Four layers of 0.2 mm make each module 0.8 mm thick. Corrected 2026-08-11: this sentence used to continue “which is the point where it stops leaking light when the panel is lit from behind. Three layers still leak.” Nobody has seen that. No panel has ever been backlit, and the list below has always said so on this same page, which is the part that should have caught it. The argument is that 0.6 mm of plastic passes light and 0.8 mm does not, and it is an argument, not a measurement. The first lit panel settles it, and the number gets re-derived from that panel rather than defended. The generator carries the same caveat at its own constant.
Sheet thickness is not a property of the design and the generator refuses to assume one: the printer probes the bare plate, so a wrong number prints into the sheet or into the air. At the 3 mm sheet these files were emitted for, layer 1 lands at Z 3.2 and every later Z carries the same offset.
A QR carries a mandatory margin of four blank modules on every side. On an opal panel that margin is unprinted sheet, a sheet-sizing decision rather than a toolpath one. Push the payload from a 25 module symbol to a 29 module one and the 10 mm showpiece needs 370 mm of acrylic. This printer's plate is 350 mm, so the 290 mm file measured above is one it cannot print. The symbol would fit. The margin is what does not. Payload length is a physical constraint, not a naming preference.
352.5 is stepper_x position_max, kinematic reach, and it includes travel
off the plate. The printable plate is 350.0. No conclusion here moves, because 370 fits
neither number and the 330 mm showpiece fits both. What moves is the boundary, and a
boundary is the whole job of a sizing rule. The project's own machine notes already said in
bold not to treat 352.5 as 350 plus margin, and added that a fixture jig under the sheet
eats into the 350 further, so 350 is an upper bound rather than a target. The generator
carried the same mistake in its own constant until the same morning.