How Quake’s 162 normals were made
Every model in Quake is lit using a table of 162 directions that shipped in 1996 without an explanation, and the game’s own fan documentation said there was no formula for it. There is one. It starts from an icosahedron printed in a 1993 OpenGL textbook and reproduces id Software’s file line for line.
anorms.h from id Software’s source release. The recipe in fullSummary
- Question
- Quake (id Software, 1996) stores each model vertex’s lighting direction as one byte, an index into
anorms.h, a list of 162 unit vectors. The file has no comment saying where they came from; a 1996 fan specification called it a table with “no known formula”, and later writers knew only its rough shape. - Answer
- Take the icosahedron table from the OpenGL Programming Guide (1993), cut each edge of each face into four, giving 16 small triangles, without moving points onto the sphere along the way, normalise each point once in 32-bit floating point, and print with six decimals. All 162 lines come out identical to id’s file, in order.
- How sure
- The match is exact, and each near-variant tested fails. That id’s tool worked from the Red Book’s table is strongly supported, since the order of corners and faces matches it. Who wrote the tool is not known. We found no earlier exact reconstruction.
1The question
Quake’s character models are animated by storing every vertex again for every frame. To keep that affordable, each vertex takes four bytes: three for its position and one for the direction its surface faces, which the renderer needs to light it. That fourth byte cannot hold a direction, so it holds an index into a fixed list of 162 directions in a source file called anorms.h.1 Every Quake model, and every Quake II model after it, points its surfaces using that list.
The list itself is a bare block of numbers with six decimals each. Within months of the game’s release, the community’s reference document, the Unofficial Quake Specs, printed it in full and gave up on explaining it: “Since it doesn’t seem to be derived from a regular polygon, there is no known formula to calculate it, so we can only list here all the values.”2 When id released the source in 1999 the file came with it, still without a comment, and it has since been copied into model viewers, converters and engines that read Quake’s formats.
Its shape was guessed later. 162 is the number of corners on an icosahedron whose faces are each split into 16 smaller triangles, and a 2009 Stack Overflow answer said as much: “It seems the set of 162 vectors are the corners of a subdivided icosahedron.”3 The shape alone does not fix the file, though. The order of the 162 lines and their last digits depend on choices nobody had pinned down: which icosahedron, in what orientation, split how, rounded how. Section 3 shows how much each one matters.
This figure needs WebGL, which this browser has turned off.
2The answer
The recipe is short. The OpenGL Programming Guide, the “Red Book” (1993 and later editions), gives an icosahedron as two tables in its example code: 12 corners (vdata, built from the constants 0.525731… and 0.850650…) and 20 triangular faces (tindices).4 Starting from those tables, in their printed order:
anorms.hfor each face (A, B, C) of the Red Book icosahedron, in order: AB, BC, CA ← midpoints of its edges // not normalised for each small triangle (A,AB,CA), (B,AB,BC), (C,CA,BC), (AB,BC,CA): for each point p, mid(p,q), mid(p,r), q, mid(q,r), r: n ← point / length(point) // once, in 32-bit floats if n is not already in the list: append n print each n as {%f, %f, %f}
That cuts every edge into four, giving each face 15 flat points and 16 small triangles, pushes each one out to the sphere exactly once, and keeps them in the order they are first met. The Red Book’s own subdivision example does something slightly different: it pushes each midpoint onto the sphere before splitting again. That small difference moves most of the points, and it is why the obvious approach never reproduced the file.
3Verification
Algorithm 1 reproduces all 162 lines of anorms.h as printed, in order. Figure 3 runs it in your browser alongside two near misses and shows every line that differs.
anorms.h, in orderThis figure requires JavaScript. The reproduction script performs the same three runs.
Change any step and the match breaks. In 64-bit floating point the same steps match 138 lines. The textbook method matches 78. An icosahedron in the more common orientation, with corners at (0, ±1, ±φ), matches only 30, and only as a set. A second implementation, written by a different AI model from a plain-English description of the recipe, also produced all 162 lines.
4The question over the years
- 1993The Red Book prints the icosahedron tables used here, as example code for drawing a sphere in OpenGL.4
- 1996Quake ships with
anorms.hcompiled in. The fan-written specification lists all 162 values: “there is no known formula to calculate it.”2 - 1999id releases the source under the GPL. The table now has a file name, and still no explanation.1
- 2009A Stack Overflow answer on Quake II’s model format identifies the shape: “the corners of a subdivided icosahedron.”3
5Discussion
Established by computation: Algorithm 1 regenerates the file exactly, and the near variants tested do not. Strongly supported: the generator started from the Red Book’s tables or a copy of them, because the 12 corners and 20 faces are met in the book’s order, which a hand-built icosahedron would be unlikely to share. It also ran in 32-bit floating point, the usual precision for C graphics code of the time. Not known: who wrote it, in what language, and why the midpoints were left off the sphere. Averaging corners and normalising once is simply less code, which may be the whole reason.
Nothing here changes how Quake works; any 162 well-spread directions would have lit its models about as well. What the reconstruction adds is the exact path from a textbook to a file that many programs have copied as an opaque block, and a small confirmation of how id’s tools were put together in 1996. The full list of directions now has a three-line explanation instead of 162 lines of numbers.
6A note on method
This came from the same experiment as the notes on RC2’s π table and Office’s password tables: AI agents (Claude) searching for numbers that shipped without an explanation, where a proposed answer can be checked exactly. A checker agent suggested anorms.h as a candidate. The count was the first clue, since 162 = 10 × 4² + 2 is the corner count of an icosahedron split four ways; the order of the 12 corners pointed to the Red Book; and the last digits pointed to 32-bit floats. OpenAI’s Codex wrote the independent check. An independent prior-art search in October 2026 found no earlier exact reconstruction.
References
- [1]id Software. Quake source code,
WinQuake/anorms.handQW/client/anorms.h(GPL release, December 1999). github.com/id-Software/Quake. - [2]O. Montanuy and others. The Unofficial Quake Specs, versions 3.3–3.4, Appendix B. 1996. gamers.org/dEngine/quake/spec/quake-spec34/qkspec_b.htm.
- [3]sellibitze. Answer to “The Quake 2 MD2 file format (theory)”. Stack Overflow, November 2009.
- [4]J. Neider, T. Davis and M. Woo. OpenGL Programming Guide (the “Red Book”), Addison-Wesley, 1993, chapter 2, the icosahedron example and its code (
vdata,tindices), as widely reproduced.
Citing this note
Hamadeh, K. (2026). How Quake’s 162 normals were made. https://khalidhamadeh.com/writing/quake-anorms