3  Kindly kinds

Kindly is a convention from the Clojure ecosystem for annotating values with rendering intent. Babqua supports Kindly metadata, so the same code patterns work in both Babashka+Quarto and Clojure+Clay.

Without an annotation, results display as code output:

(let [people [{:name "Alice" :scores [85 92 78]}
              {:name "Bob"   :scores [91 88 95]}
              {:name "Carol" :scores [76 80 89]}]]
  (map (fn [p]
         {:name (:name p)
          :avg  (/ (apply + (:scores p)) (count (:scores p)))})
       people))
({:name "Alice", :avg 85} {:name "Bob", :avg 274/3} {:name "Carol", :avg 245/3})

One exception: (def x ...) returns the var (#'user/x), which is noise rather than information. Babqua suppresses var results by default, so a setup block like (def magic-number 42) is hidden without needing #| output: hidden. Reference the binding in a later block to display its value.

Add Kindly metadata to control how a value is rendered.

3.1 ^:kind/hiccup — HTML from data

Converts a hiccup vector to HTML. Hiccup represents HTML as nested Clojure vectors:

^:kind/hiccup
[:svg {:width "100" :height "100" :xmlns "http://www.w3.org/2000/svg"}
  [:circle {:cx "50" :cy "50" :r "40" :fill "coral"}]]

The vector [:tag {:attr "value"} content] becomes <tag attr="value">content</tag>. Babashka has hiccup2.core built in, so the HTML rendering happens on the Babashka side, not in the Lua filter.

3.2 ^:kind/html — raw HTML

Renders a string as raw HTML. Since strings can’t hold metadata in Clojure, wrap the expression in a vector:

^:kind/html
["<b>bold</b> and <em>italic</em>"]
bold and italic

The vector is automatically unwrapped — Babqua extracts the first element for rendering.

3.3 ^:kind/md — markdown

Renders a string as markdown. Same wrapping rule as kind/html:

^:kind/md
["| a | b |\n| --- | --- |\n| 1 | 2 |"]
a b
1 2

3.4 ^:kind/hidden — suppress output

Evaluates the code but hides the result. The code itself is still shown. Useful for setup like defining helper functions:

^:kind/hidden
[(def my-data [1 2 3])]

3.5 ^:kind/mermaid — Mermaid diagrams

Renders a string as a Mermaid diagram. The Mermaid JS library is loaded automatically from a CDN (content delivery network):

^:kind/mermaid
["graph LR\n  A[Start] --> B{Decision}\n  B -->|Yes| C[OK]\n  B -->|No| D[Cancel]"]

3.6 ^:kind/graphviz — Graphviz diagrams

Renders a string as a Graphviz DOT diagram. The viz-js library is loaded from CDN; no local Graphviz install needed:

^:kind/graphviz
["digraph { rankdir=LR; A -> B -> C; A -> C; }"]

3.7 ^:kind/tex — LaTeX formulas

Renders a string as a LaTeX formula via MathJax:

^:kind/tex
["\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}"]

\[\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}\]

3.8 ^:kind/code — code display

Renders a string as syntax-highlighted Clojure code (for display, not evaluation):

^:kind/code
["(defn hello [name]\n  (str \"Hello, \" name \"!\"))"]
(defn hello [name]
  (str "Hello, " name "!"))

3.9 ^:kind/vega-lite — Vega-Lite charts

Renders a map as a Vega-Lite chart. The JS library is loaded automatically from CDN:

^:kind/vega-lite
{:data {:values [{:x "A" :y 28} {:x "B" :y 55} {:x "C" :y 43}]}
 :mark :bar
 :encoding {:x {:field :x :type :nominal}
            :y {:field :y :type :quantitative}}}

3.10 ^:kind/plotly — Plotly charts

Renders a map as a Plotly.js chart. The spec should have :data and :layout keys:

^:kind/plotly
{:data [{:x [1 2 3 4] :y [10 15 13 17] :type "scatter" :mode "lines+markers"}]
 :layout {:title "Simple Plotly Chart"}}

3.11 ^:kind/echarts — ECharts charts

Renders a map as an ECharts chart. The JS library is loaded automatically from CDN. The map is passed through to echarts.setOption:

^:kind/echarts
{:xAxis {:type "category" :data ["Mon" "Tue" "Wed" "Thu" "Fri"]}
 :yAxis {:type "value"}
 :series [{:type "bar" :data [12 19 8 15 22]}]}

ECharts refuses to render to a size-less container, so Babqua applies a default of 600 × 400 pixels. Override with width=/height= fence attributes or :kindly/options.

3.12 ^:kind/cytoscape — Cytoscape graphs

Renders a map as a Cytoscape graph. The spec needs :elements (nodes and edges); Babqua sets the container automatically:

^:kind/cytoscape
{:elements [{:data {:id "a"}}
            {:data {:id "b"}}
            {:data {:id "c"}}
            {:data {:id "ab" :source "a" :target "b"}}
            {:data {:id "bc" :source "b" :target "c"}}
            {:data {:id "ca" :source "c" :target "a"}}]
 :style [{:selector "node"
          :style {:label "data(id)"
                  :background-color "steelblue"
                  :color "white"
                  :text-valign "center"
                  :text-halign "center"}}
         {:selector "edge"
          :style {:width 2
                  :line-color "#aaa"
                  :curve-style "bezier"}}]
 :layout {:name "circle"}}

Cytoscape also needs an explicit container size; the default is the same 600 × 400 pixels.

3.13 ^:kind/highcharts — Highcharts charts

Renders a map as a Highcharts chart. The map is passed straight to Highcharts.chart:

^:kind/highcharts
{:chart {:type "column"}
 :title {:text "Highcharts demo"}
 :xAxis {:categories ["A" "B" "C" "D"]}
 :yAxis {:title {:text "Count"}}
 :series [{:name "Counts" :data [10 20 15 25]}]}

3.14 ^:kind/table — HTML tables

Renders tabular data as an HTML table. Two value shapes are accepted:

A sequence of maps (header derived from union of keys):

^:kind/table
[{:lang "Clojure"  :year 2007}
 {:lang "Babashka" :year 2020}
 {:lang "Jank"     :year 2019}]
:lang:year
Clojure2007
Babashka2020
Jank2019

Or a column-vector form:

^:kind/table
{:column-names ["x" "x²" "x³"]
 :row-vectors  [[1 1 1]
                [2 4 8]
                [3 9 27]]}
x
111
248
3927

The table is rendered on the Babashka side (via hiccup) and inserted as raw HTML, so styling can target it the same way as any other HTML table.

3.15 Annotating in library functions

The ^:kind/... reader syntax attaches metadata at the call site. But metadata can also be attached programmatically with with-meta or vary-meta, which means library functions can annotate their return values. The caller doesn’t need to know about the rendering — the function handles it.

For example, a function that builds an SVG bar chart and tags it as hiccup:

(defn bar-chart [labels values]
  (let [bar-width 40
        gap       10
        max-val   (apply max values)
        height    120
        bars      (map-indexed
                    (fn [i [label val]]
                      (let [x          (+ 10 (* i (+ bar-width gap)))
                            bar-height (* (/ val max-val) height)]
                        [:g
                         [:rect {:x x :y (- height bar-height)
                                 :width bar-width :height bar-height
                                 :fill "steelblue"}]
                         [:text {:x (+ x (/ bar-width 2)) :y (+ height 15)
                                 :text-anchor "middle" :font-size "12"}
                          label]]))
                    (map vector labels values))
        total-width (+ 20 (* (count labels) (+ bar-width gap)))]
    (with-meta
      (into [:svg {:width total-width :height (+ height 25)
                   :xmlns "http://www.w3.org/2000/svg"}] bars)
      {:kindly/kind :kind/hiccup})))

Now simply calling the function renders the chart — no annotation needed at the call site:

(bar-chart ["a" "b" "c"] [10 20 15])
abc

This is a key idea behind Kindly: rendering intent lives in the metadata of values, not in the document markup. Libraries can provide visualization functions that render correctly in any Kindly-aware tool — Babqua, Clay, Janqua, or others.

3.16 Why wrap strings in vectors?

In Clojure (and Babashka), metadata can only be attached to collections — vectors, maps, sets — not to primitive types like strings or numbers. So ^:kind/html "hello" won’t work.

The convention is to wrap the value in a vector:

^:kind/html ["<b>hello</b>"]
hello

Babqua automatically unwraps the vector for all string-valued kinds (kind/html, kind/md, kind/mermaid, kind/graphviz, kind/tex, kind/code), extracting the first element for rendering.

3.17 Summary of kinds

Kind Value type Renders as
^:kind/hiccup vector (hiccup) HTML
^:kind/html [string] raw HTML
^:kind/md [string] markdown
^:kind/hidden any nothing (evaluates silently)
^:kind/mermaid [string] Mermaid diagram
^:kind/graphviz [string] Graphviz diagram
^:kind/tex [string] LaTeX formula
^:kind/code [string] syntax-highlighted code
^:kind/vega-lite map Vega-Lite chart
^:kind/plotly map Plotly chart
^:kind/echarts map ECharts chart
^:kind/cytoscape map Cytoscape graph
^:kind/highcharts map Highcharts chart
^:kind/table map or seq-of-maps HTML table
(none) any code output (vars from (def …) are suppressed)