# card-raytracer A study of [Andrew Kensler's "business card raytracer"][aek] — 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: > > ```sh > $ wc -c card.cc > 1337 card.cc > ``` > > That is suspiciously round — hand-golfed C++ rarely lands on a famous > leet number by accident. The compression tricks all show their work: > typedefs (`i` for `int`, `f` for `float`), operator overloads on > `struct v` that turn `+` / `%` / `^` / `!` into vector math, and not > a wasted space anywhere. The original code is preserved verbatim as [`card.cc`](card.cc). A de-obfuscated, heavily-annotated rewrite lives in [`card_explained.cc`](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](docs/aek.png) 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. ```sh 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`](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 - Original raytracer: [Andrew Kensler][aek-home] ("aek"). - Excellent walkthrough that inspired this study: Fabien Sanglard, [_Decyphering The Business Card Raytracer_][aek]. ## 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. [aek]: https://fabiensanglard.net/rayTracing_back_of_business_card/ [aek-home]: https://www.cs.utah.edu/~aek/