Part I — Draw the board¶
Before there is a game, there is a canvas and a few drawing commands. Start by
loading studio.draw: it is the small host-facing library that waits for a
canvas frame and submits a list of drawing commands to it.
The program below follows the complete first drawing path:
node/startkeeps one live drawing process running.draw/next-framegives that process its canvas turn.draw/rendersendsopening-commandsto the named canvas.
A canvas command is just data: [:line x1 y1 x2 y2 color width alpha]. Read
the first vector as: draw a vertical line from (220, 170) to (220, 470),
muted blue, two pixels wide, fully opaque.
draw/render is the only point at which those values become pixels. There is
no board widget hiding behind this example: the four :line vectors below are
the board.
Practicals — draw with commands¶
studio.draw is the Hara API for a kernel to communicate with the browser's
Canvas 2D API. It does not contain Tic Tac Toe rules. Instead, the kernel asks
for a frame with draw/next-frame, then uses draw/render to send explicit
command data through the declared canvas capability.
Run this first program. It imports studio.draw, starts one live kernel node,
and draws the four lines that make the board. Then change one command and run
it again.
(ns+
(:require [studio.draw :as draw]))
;; A value describing pixels—not pixels yet.
(defn opening-commands [width height]
[[:grid 48 "rgba(67,247,231,.12)" 1]
[:line 220 170 220 470 "#386779" 2 1]
[:line 380 170 380 470 "#386779" 2 1]
[:line 60 270 540 270 "#386779" 2 1]
[:line 60 370 540 370 "#386779" 2 1]])
;; This is where the command data becomes a visible board.
(node/start
(fn []
(loop []
(let [frame (co/await (draw/next-frame "canvas/background"))]
(co/await (draw/render "canvas/background"
{:type :canvas-2d
:background "#03070d"
:commands (opening-commands 960 600)}))
(recur)))))
Choose one exercise, or skip to organising the game.
Change both 220 values in the first line to 250. Run the file. The shared x keeps it vertical.
Replace "#386779" with "#ff78b3", then run again. The command is the whole instruction.
Copy one :line vector. Give its endpoints a shared x or y and observe the result.
Add [:circle 300 320 24 "#7dfff3" 1]. This is the same command-list idea, with a different primitive.
Drawing reference¶
[:line x1 y1 x2 y2 color width alpha]Draw a straight segment. Four lines make the board grid.
[:circle x y radius color alpha]Draw a filled circle. Later, two circles make an O.
[:rect x y width height color alpha]Fill a rectangle for a panel, button, or board background.
[:text label x y color size]Put a status label or instruction onto the canvas.
[:grid spacing color width]Draw a regular guide grid behind the game.
[:mist x y radius color alpha]Add a soft radial glow behind a piece or winning line.