%unimsg 0 board-presentation/chess/v0 -- How to draw a position of @ruleset/chess/v0, in @vocab/board-presentation/v0. -- -- THE THIRD DOCUMENT, AND THE SMALLEST. A ruleset says what is legal and never -- what it looks like; a graphic is a resolved picture and cannot change when a -- piece moves. What is missing between them is the function from a position to -- a scene — and for a game played on a grid that function is not a program, it -- is this table. -- -- SO NOTHING HERE IS CHESS-SPECIFIC MACHINERY. A square size, two fills, a -- glyph per piece kind, and where a baseline sits. tools/boardview reads it -- beside the ruleset and draws any position: -- -- (cd ../unimsg && go run ./tools/boardview -board examples/chess-board.umsg \ -- -ruleset examples/chess-ruleset.umsg -o /tmp/scene.umsg) -- -- and the same table inverts, so a point on the picture resolves to a square -- and a square to the moves the ruleset allows from it. Drawing and pointing -- are one binding read in two directions. board-presentation @board-presentation/chess/v0 { title "A chess board" summary "Eight files by eight ranks, dark on a1, pieces as the Unicode chess glyphs, and a frame carrying the file and rank names. It is a presentation of one ruleset and it knows none of its rules: nothing here mentions a legal move, a check or a capture, because none of those is a fact about what the board looks like." status :draft at 2026-08-26 presents "@ruleset/chess/v0" geometry { square 64 margin 28 y-axis :up } -- PARITY IS (file + rank), and a1 is file 0 rank 0, so :even is the dark -- square. Getting this backwards is the classic board bug and it is one row -- here rather than a condition somewhere in a renderer. squares [ | parity fill | :even "#b58863" | :odd "#f0d9b5" ] frame { fill "#312a24" stroke "#1a1613" width 1 } coordinates { font [ "Inter", :sans ] size 12 fill "#e6ddd1" } -- THE GLYPHS ARE TEXT, WHICH IS A CHOICE WITH A COST. Six paths per side -- would be exact and would not depend on a font being present; two columns of -- one character each are twelve rows a person can read and correct. The cost -- is declared rather than hidden: :font names the stack, and a host without -- any of them draws the wrong thing. glyphs [ | piece white black | :king "♔" "♚" | :queen "♕" "♛" | :rook "♖" "♜" | :bishop "♗" "♝" | :knight "♘" "♞" | :pawn "♙" "♟" ] glyph-style { font [ "Segoe UI Symbol", "Noto Sans Symbols 2", "DejaVu Sans", :sans ] size 46 fill "#141414" baseline 16 -- A PIECE ON A MARKED SQUARE IS DRAWN LARGER, which is how a person sees -- that the piece they touched is the one that will move. Fifteen percent is -- enough to read at a glance and small enough that the glyph stays inside -- its cell -- 46 becomes 53, against a square of 64. emphasis 115 } -- WHERE THE PIECES THAT ARE NO LONGER ON THE BOARD GO. A band above and -- below, so the picture is the board plus what it has cost. The size is well -- under a square's: a tray is read as a count and never pointed at, and a -- captured piece drawn at playing size reads as a piece that could move. tray { height 40 size 26 spacing 24 baseline 9 -- The light square's colour. A captured piece is drawn in :glyph-style's -- near-black, as a piece on the board is, so the band it stands on must be -- the ground that colour was chosen against -- see -- a-tray-glyph-keeps-its-own-colour. ground "#f0d9b5" } -- HOW A FINISHED GAME IS DECLARED. Over the board rather than beside it, -- because the board is what a person is looking at when it happens, and -- translucent so the position that produced the result is still readable -- underneath. outcome { height 84 size 38 ground "#1a1613" opacity 0.82 fill "#f0d9b5" baseline 13 -- THE SIDE NAME IS THE RULESET'S AND ARRIVES LOWERCASE, so the wording -- puts it where a lowercase word belongs. Capitalising it would be a rule -- about a language, and the module that substitutes it knows none. won "winner: {side}" drawn "drawn — no winner" } -- WHAT A HIGHLIGHT LOOKS LIKE, and the reason a presentation has any say in -- it: the squares that can be highlighted come from the RULESET — the moves -- legal from the square a person touched — and only how they are drawn is a -- presentation decision. The list is computed; the colour is declared. marks [ | mark fill opacity | :selected "#f4f169" 0.55 | :move "#6f9f4f" 0.55 | :capture "#c05a3e" 0.6 | :last "#c9c26a" 0.45 ] }