card-raytracer/README.md
Ole-Morten Duesund a18f68badb README: lead with the 1337-byte 'leet' fact
The exact byte count is the whole punchline — surface it explicitly with
a verifiable wc -c invocation rather than hiding it as '~1337 characters'
in a subordinate clause.
2026-05-28 13:52:13 +02:00

3.6 KiB

card-raytracer

A study of Andrew Kensler's "business card raytracer" — a complete recursive path-tracer with soft shadows, depth of field, anti-aliasing, reflections, a checker floor, and a sky gradient, all crammed into a single C++ source file small enough to print on the back of a business card.

card.cc is exactly 1337 bytes. Yes, leet. Verify it yourself:

$ wc -c card.cc
1337 card.cc

That is not a happy accident — Kensler golfed the source until it hit the magic number. Every typedef (i for int, f for float), every operator-overload trick on struct v, and every absent space exists to land on 1337.

The original code is preserved verbatim as card.cc. A de-obfuscated, heavily-annotated rewrite lives in card_explained.cc. Both produce the same image:

Rendered output: the letters "aek" as reflective spheres on a red and white checker floor under a blue-purple sky, with soft shadows and depth-of-field blur

The spheres spell a · e · k, Andrew Kensler's initials, encoded as a 9-column bitmap in the G[] array of the original source.

Quick start

Requires a C++14 compiler, CMake ≥ 3.16, and (optionally) netpbm for PPM → PNG conversion.

cmake -S . -B build
cmake --build build

# Render with the original (PPM, 786 KiB, ~6 s on a modern laptop)
./build/card > aek.ppm

# Or via the convenience target:
cmake --build build --target image            # → build/aek.ppm
cmake --build build --target image_explained  # → build/aek_explained.ppm

# View it (PPM is supported by most image viewers; or convert):
pnmtopng aek.ppm > aek.png

What's interesting about it

The whole renderer is built on operator overloading: a single struct v provides + (add), * (scale), % (dot product), ^ (cross product), and unary ! (normalise). Once those are in place, the entire rendering pipeline — sphere intersections, reflection vectors, Phong shading, checker-pattern tile lookup, camera basis construction — collapses into just a handful of expressions.

Other tricks worth admiring:

  • Soft shadows for free: the light position is jittered each call, so averaging 64 samples per pixel produces a real penumbra without any area-light formalism.
  • Depth of field for free: the camera origin is also jittered across a 99-unit "lens" each sample, so points off the focal plane go blurry.
  • Anti-aliasing for free: sub-pixel jitter on the ray direction.

The same 64-sample loop pays for all three at once.

A line-by-line walkthrough of the algorithm is the long-form comments inside card_explained.cc.

Layout

.
├── card.cc            # original, untouched — do not edit
├── card_explained.cc  # de-obfuscated, documented rewrite
├── CMakeLists.txt
├── docs/
│   └── aek.png        # published render
├── README.md
└── CLAUDE.md          # working notes for AI assistance

Credits

Licence

The original card.cc is reproduced as-is from publicly published material for educational purposes; credit and copyright belong to Andrew Kensler. The supporting files in this repository (CMake, README, de-obfuscated rewrite) are placed in the public domain by the repository author.