# Visualization & Diagrams Three levels of visualization in Typst, all mappable to hiccup. --- ## 1. Built-in Shapes Typst has basic shapes built-in. Simple and direct. ### Rectangle **Clojure:** ```clojure [:rect {:width "2cm" :height "1cm" :fill "blue"} "Label"] ``` **Typst:** ```typst #rect(width: 2cm, height: 1cm, fill: blue)[Label] ``` ### Square **Clojure:** ```clojure [:square {:size "1cm" :stroke "2pt + red"}] ``` **Typst:** ```typst #square(size: 1cm, stroke: 2pt + red) ``` ### Circle **Clojure:** ```clojure [:circle {:radius "0.5cm" :fill "green"}] ``` **Typst:** ```typst #circle(radius: 0.5cm, fill: green) ``` ### Ellipse **Clojure:** ```clojure [:ellipse {:width "2cm" :height "1cm"}] ``` **Typst:** ```typst #ellipse(width: 2cm, height: 1cm) ``` ### Polygon **Clojure:** ```clojure [:polygon {:fill "yellow"} [0 0] [1 0] [0.5 1]] ``` **Typst:** ```typst #polygon(fill: yellow, (0pt, 0pt), (1pt, 0pt), (0.5pt, 1pt)) ``` ### Line **Clojure:** ```clojure [:line {:start [0 0] :end [100 50] :stroke "2pt"}] ``` **Typst:** ```typst #line(start: (0pt, 0pt), end: (100pt, 50pt), stroke: 2pt) ``` ### Path **Clojure:** ```clojure [:path {:closed true :fill "blue"} [0 0] [10 0] [10 10] [0 10]] ``` **Typst:** ```typst #path(closed: true, fill: blue, (0pt, 0pt), (10pt, 0pt), (10pt, 10pt), (0pt, 10pt)) ``` ### Curve (Bézier) **Clojure:** ```clojure [:curve [:move [0 0]] [:cubic [10 20] [30 20] [40 0]]] ``` **Typst:** ```typst #curve( curve.move((0pt, 0pt)), curve.cubic((10pt, 20pt), (30pt, 20pt), (40pt, 0pt)), ) ``` --- ## 2. CeTZ - Canvas Drawing For complex custom drawings. Like TikZ for LaTeX. ### Basic Canvas **Clojure:** ```clojure [:cetz/canvas [:cetz/line [0 0] [2 2]] [:cetz/circle [1 1] {:radius 0.5}] [:cetz/rect [0 0] [2 1] {:fill "blue"}]] ``` **Typst:** ```typst #import "@preview/cetz:0.4.2" #cetz.canvas({ import cetz.draw: * line((0, 0), (2, 2)) circle((1, 1), radius: 0.5) rect((0, 0), (2, 1), fill: blue) }) ``` ### Line with Multiple Points **Clojure:** ```clojure [:cetz/line [0 0] [1 0] [1 1] [0 1] {:close true}] ``` **Typst:** ```typst line((0, 0), (1, 0), (1, 1), (0, 1), close: true) ``` ### Arc **Clojure:** ```clojure [:cetz/arc [0 0] {:start 0 :stop 90 :radius 1}] ``` **Typst:** ```typst arc((0, 0), start: 0deg, stop: 90deg, radius: 1) ``` ### Bezier Curve **Clojure:** ```clojure [:cetz/bezier [0 0] [1 1] [0.5 2] [0.5 -1]] ``` **Typst:** ```typst bezier((0, 0), (1, 1), (0.5, 2), (0.5, -1)) ``` ### Content Label in Canvas **Clojure:** ```clojure [:cetz/content [1 1] "Label here"] [:cetz/content [0 0] [:strong "Bold label"]] ``` **Typst:** ```typst content((1, 1), [Label here]) content((0, 0), [#strong[Bold label]]) ``` ### Architecture Boxes Example **Clojure:** ```clojure (defn box-with-label [pos size label] (let [[x y] pos [w h] size cx (+ x (/ w 2)) cy (+ y (/ h 2))] (list [:cetz/rect pos [(+ x w) (+ y h)] {:fill "lightblue" :stroke "black"}] [:cetz/content [cx cy] label]))) [:cetz/canvas (box-with-label [0 0] [3 2] "Frontend") (box-with-label [5 0] [3 2] "Backend") (box-with-label [10 0] [3 2] "Database") [:cetz/line [3 1] [5 1] {:mark {:end ">"}}] [:cetz/line [8 1] [10 1] {:mark {:end ">"}}]] ``` **Typst:** ```typst #cetz.canvas({ import cetz.draw: * // Frontend rect((0, 0), (3, 2), fill: lightblue, stroke: black) content((1.5, 1), [Frontend]) // Backend rect((5, 0), (8, 2), fill: lightblue, stroke: black) content((6.5, 1), [Backend]) // Database rect((10, 0), (13, 2), fill: lightblue, stroke: black) content((11.5, 1), [Database]) // Arrows line((3, 1), (5, 1), mark: (end: ">")) line((8, 1), (10, 1), mark: (end: ">")) }) ``` --- ## 3. Fletcher - Diagrams & Flowcharts High-level diagram DSL. Best for architecture, flowcharts, state machines. ### Basic Diagram **Clojure:** ```clojure [:fletcher/diagram {:node-stroke "1pt" :spacing "2em"} [:node [0 0] "Start"] [:edge "->"] [:node [1 0] "Process"] [:edge "->"] [:node [2 0] "End"]] ``` **Typst:** ```typst #import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge #diagram( node-stroke: 1pt, spacing: 2em, node((0, 0), [Start]), edge("-|>"), node((1, 0), [Process]), edge("-|>"), node((2, 0), [End]), ) ``` ### Node Shapes **Clojure:** ```clojure [:node [0 0] "Default"] [:node [1 0] "Circle" {:shape :circle}] [:node [2 0] "Diamond" {:shape :diamond}] [:node [3 0] "Pill" {:shape :pill}] [:node [4 0] "Hexagon" {:shape :hexagon}] [:node [5 0] "Cylinder" {:shape :cylinder}] ``` **Typst:** ```typst node((0, 0), [Default]), node((1, 0), [Circle], shape: circle), node((2, 0), [Diamond], shape: fletcher.shapes.diamond), node((3, 0), [Pill], shape: fletcher.shapes.pill), node((4, 0), [Hexagon], shape: fletcher.shapes.hexagon), node((5, 0), [Cylinder], shape: fletcher.shapes.cylinder), ``` ### Edge Styles **Clojure:** ```clojure [:edge "->"] ; simple arrow [:edge "->>"] ; double arrow [:edge "--"] ; no arrow (line) [:edge "<->"] ; bidirectional [:edge "hook->"] ; hook arrow [:edge "|->"] ; maps-to arrow ``` **Typst:** ```typst edge("-|>"), edge("-|>|>"), edge("--"), edge("<|-|>"), edge("hook-|>"), edge("|-|>"), ``` ### Directional Edges **Clojure:** ```clojure [:edge "r" "->"] ; go right [:edge "d" "->"] ; go down [:edge "u" "->"] ; go up [:edge "l" "->"] ; go left [:edge "r,d" "->"] ; right then down ``` **Typst:** ```typst edge("r", "-|>"), edge("d", "-|>"), edge("u", "-|>"), edge("l", "-|>"), edge("r,d", "-|>"), ``` ### Edge with Label **Clojure:** ```clojure [:edge [0 0] [1 0] "->" {:label "HTTP" :label-pos 0.5}] ``` **Typst:** ```typst edge((0, 0), (1, 0), "-|>", label: [HTTP], label-pos: 0.5), ``` ### Curved Edge **Clojure:** ```clojure [:edge [0 0] [1 0] "->" {:bend 20}] ``` **Typst:** ```typst edge((0, 0), (1, 0), "-|>", bend: 20deg), ``` ### Flowchart Example **Clojure:** ```clojure [:fletcher/diagram {:node-stroke "1pt" :node-fill "white" :spacing "3em"} ;; Nodes [:node [0 0] "Start" {:shape :pill}] [:node [0 1] "Input Data"] [:node [0 2] "Valid?" {:shape :diamond}] [:node [1 2] "Error" {:fill "red.lighten(80%)"}] [:node [0 3] "Process"] [:node [0 4] "End" {:shape :pill}] ;; Edges [:edge [0 0] [0 1] "->"] [:edge [0 1] [0 2] "->"] [:edge [0 2] [1 2] "->" {:label "no"}] [:edge [0 2] [0 3] "->" {:label "yes"}] [:edge [1 2] [0 1] "->" {:bend -40}] [:edge [0 3] [0 4] "->"]] ``` **Typst:** ```typst #import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge #diagram( node-stroke: 1pt, node-fill: white, spacing: 3em, // Nodes node((0, 0), [Start], shape: fletcher.shapes.pill), node((0, 1), [Input Data]), node((0, 2), [Valid?], shape: fletcher.shapes.diamond), node((1, 2), [Error], fill: red.lighten(80%)), node((0, 3), [Process]), node((0, 4), [End], shape: fletcher.shapes.pill), // Edges edge((0, 0), (0, 1), "-|>"), edge((0, 1), (0, 2), "-|>"), edge((0, 2), (1, 2), "-|>", label: [no]), edge((0, 2), (0, 3), "-|>", label: [yes]), edge((1, 2), (0, 1), "-|>", bend: -40deg), edge((0, 3), (0, 4), "-|>"), ) ``` ### Architecture Diagram Example **Clojure:** ```clojure [:fletcher/diagram {:spacing "4em" :node-stroke "1pt"} ;; Frontend layer [:node [0 0] "Web App" {:fill "blue.lighten(80%)"}] [:node [1 0] "Mobile App" {:fill "blue.lighten(80%)"}] ;; API Gateway [:node [0.5 1] "API Gateway" {:shape :hexagon :fill "green.lighten(80%)"}] ;; Services [:node [0 2] "Auth Service" {:shape :pill}] [:node [1 2] "User Service" {:shape :pill}] [:node [2 2] "Order Service" {:shape :pill}] ;; Data layer [:node [0 3] "PostgreSQL" {:shape :cylinder}] [:node [1 3] "Redis" {:shape :cylinder :fill "red.lighten(80%)"}] [:node [2 3] "MongoDB" {:shape :cylinder :fill "green.lighten(80%)"}] ;; Connections [:edge [0 0] [0.5 1] "->"] [:edge [1 0] [0.5 1] "->"] [:edge [0.5 1] [0 2] "->"] [:edge [0.5 1] [1 2] "->"] [:edge [0.5 1] [2 2] "->"] [:edge [0 2] [0 3] "->"] [:edge [1 2] [1 3] "->"] [:edge [2 2] [2 3] "->"]] ``` **Typst:** ```typst #import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge #diagram( spacing: 4em, node-stroke: 1pt, // Frontend layer node((0, 0), [Web App], fill: blue.lighten(80%)), node((1, 0), [Mobile App], fill: blue.lighten(80%)), // API Gateway node((0.5, 1), [API Gateway], shape: fletcher.shapes.hexagon, fill: green.lighten(80%)), // Services node((0, 2), [Auth Service], shape: fletcher.shapes.pill), node((1, 2), [User Service], shape: fletcher.shapes.pill), node((2, 2), [Order Service], shape: fletcher.shapes.pill), // Data layer node((0, 3), [PostgreSQL], shape: fletcher.shapes.cylinder), node((1, 3), [Redis], shape: fletcher.shapes.cylinder, fill: red.lighten(80%)), node((2, 3), [MongoDB], shape: fletcher.shapes.cylinder, fill: green.lighten(80%)), // Connections edge((0, 0), (0.5, 1), "-|>"), edge((1, 0), (0.5, 1), "-|>"), edge((0.5, 1), (0, 2), "-|>"), edge((0.5, 1), (1, 2), "-|>"), edge((0.5, 1), (2, 2), "-|>"), edge((0, 2), (0, 3), "-|>"), edge((1, 2), (1, 3), "-|>"), edge((2, 2), (2, 3), "-|>"), ) ``` --- ## 4. DSL Helpers Build higher-level abstractions on top. **Clojure:** ```clojure (defn service [id name & {:keys [x y color] :or {color "white"}}] [:node [x y] name {:id id :shape :pill :fill color}]) (defn database [id name & {:keys [x y color] :or {color "gray.lighten(80%)"}}] [:node [x y] name {:id id :shape :cylinder :fill color}]) (defn connects [from to & {:keys [label style] :or {style "->"}}] [:edge from to style (when label {:label label})]) [:fletcher/diagram {:spacing "3em"} (service :auth "Auth" :x 0 :y 0) (service :users "Users" :x 1 :y 0) (database :pg "PostgreSQL" :x 0 :y 1) (database :redis "Redis" :x 1 :y 1 :color "red.lighten(80%)") (connects :auth :pg) (connects :users :redis :label "cache")] ``` **Typst:** ```typst #diagram( spacing: 3em, node((0, 0), [Auth], shape: fletcher.shapes.pill, fill: white), node((1, 0), [Users], shape: fletcher.shapes.pill, fill: white), node((0, 1), [PostgreSQL], shape: fletcher.shapes.cylinder, fill: gray.lighten(80%)), node((1, 1), [Redis], shape: fletcher.shapes.cylinder, fill: red.lighten(80%)), edge((0, 0), (0, 1), "-|>"), edge((1, 0), (1, 1), "-|>", label: [cache]), ) ``` --- ## Summary | Use Case | Tool | Hiccup Prefix | |----------|------|---------------| | Simple shapes in content | Built-in | `:rect`, `:circle`, `:line` | | Custom drawings, illustrations | CeTZ | `:cetz/canvas`, `:cetz/line` | | Flowcharts, architecture | Fletcher | `:fletcher/diagram`, `:node`, `:edge` | ## Sources - [Typst Visualize Docs](https://typst.app/docs/reference/visualize/) - [Fletcher Package](https://typst.app/universe/package/fletcher/) - [CeTZ Package](https://typst.app/universe/package/cetz/) - [CeTZ Documentation](https://cetz-package.github.io/)