HTML, SVG and CSS in a patch
A patch can show more than sound and graphics. Any top-level call in a patch that is an HTML or SVG element becomes part of what the patch shows, beside its audio and graphics. The same elements render in the browser on the web and as native views in the iOS and Android apps, so a patch looks the same on a phone as on a desktop.
Elements
Section titled “Elements”Elements are named the way the web platform names them, under a namespace: html.div, html.p, html.button, svg.svg, svg.circle. Attributes are spelled as in markup, such as class, aria-label or viewBox. The children of an element are other elements and plain text, in order.
html.div( html.p("Turn ", html.strong("Cutoff"), " to open the filter."),) .class("panel")Text is always text: nothing a patch writes is ever run as code or read as markup.
An element’s style sets CSS properties by their CSS names, such as display, gap or background-color. Values are written as CSS writes them, as strings like "8px" or "var(--gray-11)", or as typed values like css.px(8).
A css.stylesheet holds rules with selectors, media and container queries, keyframes and custom properties, scoped to the patch:
css.stylesheet(css.rule(".panel p", { color: "var(--gray-11)", margin: "0px" }))Colours come from the app’s theme variables, such as var(--accent-9) or var(--gray-11), so a patch follows the light and dark themes.
Minima supports a closed set of HTML, SVG and CSS: every element, attribute, property and value that renders the same on the web and in the apps. Anything outside that set is refused when the patch is saved, with a message that says where.
Handlers
Section titled “Handlers”An element’s on maps an event, such as pointerdown, click or input, to handlers. A handler writes values to named channels, which the patch’s sound and graphics read, and can play haptic feedback. dom.event reads a field of the event, such as where the pointer is.
The eight controls
Section titled “The eight controls”Minima ships eight controls, each built from the same elements a patch can use, so a control travels inside the patch that uses it:
buttonControl, a momentary button;toggleControl, an on and off switch;dialControl, a dial for a continuous value or a list of options;xyControl, a pad for two linked values;fieldControl, a number field or a choice;meterControl, a level meter;scopeControl, a waveform;spectrogramControl, a scrolling spectrum.
Each takes one record of settings, such as the channel it writes, its range and its label.
Example
Section titled “Example”dialControl = fn().name("dialControl")
meterControl = fn().name("meterControl")
html.div( css.stylesheet(css.rule(".panel p", { color: "var(--gray-11)", margin: "0px" })), dialControl({ channel: "cutoff", label: "Cutoff", max: 8000, min: 80, taper: "log", value: 800 }), meterControl({ label: "Master", tap: "master" }), html.p("Turn ", html.strong("Cutoff"), " to open the filter."),) .class("panel") .style({ display: "grid", gap: "8px", "grid-template-columns": "repeat(2, 64px)" })This is the patch as the in-app agent writes it: the first two lines name the controls it uses, and the agent’s patch tools put each control’s full definition in their place when it saves the patch. In the editor, adding a control from the palette inserts its definition directly.