3  Kindly kinds

Kindly is a convention from the Clojure ecosystem for annotating values with rendering intent. Janqua supports Kindly metadata, so the same code patterns work in both Jank+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})

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>.

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 — Janqua 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 CDN:

^: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 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})))
#'user/bar-chart

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 Jank forms or values, not in the document markup. Libraries can provide visualization functions that “just work” in any Kindly-aware tool — Janqua, Clay, or others.

3.12 Why wrap strings in vectors?

In Clojure (and Jank), 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

Janqua 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.13 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
(none) any code output