Tweakit

Quick tour

The schema is the whole API. Every property becomes a control, inferred from the shape of its value — no registration, no builders. This page is the grammar.

One schema, one scene

Six values, six different shapes, six controls. Everything driving the tile on the left is plain data on panel.params.

Shorthands
const card = target.querySelector(".qt-card");
const panel = tweaks("Scene", {
  size: [140, 60, 240, 1],   // [value, min, max, step] → slider
  blur: 0,                   // bare number → slider over a sensible range
  caption: "Shorthands",     // string → text input
  show: true,                // boolean → checkbox
  blend: ["normal", "screen", "overlay", "multiply"], // array → list
  glow: "#7C5CFF",           // color string → wide-gamut picker
});
mount.append(panel.el);

const apply = (p) => {
  card.style.width = `${p.size}px`;
  card.style.height = `${p.size}px`;
  card.style.filter = `blur(${p.blur * 24}px)`;
  card.style.mixBlendMode = p.blend;
  card.style.background = p.glow;
  card.style.boxShadow = `0 0 70px ${p.glow}`;
  card.style.opacity = p.show ? 1 : 0.06;
  card.querySelector("span").textContent = p.caption;
};
panel.on(apply);
panel.ready.then(() => apply(panel.params)); // color is lazy on the split build

mount is the panel's slot inside the stage; target is the demo surface it controls. In your own page you'd just document.body.append(panel.el).

The inference table

Everything the inference understands, in one place:

You writeYou getparams value
24slider over a sensible rangenumber
[1.2, 0, 3, 0.1]slider with min / max / stepnumber
[[20, 80], 0, 100]interval (dual-handle range)[lo, hi]
truecheckboxboolean
"Hello"text inputstring
"#7C5CFF"wide-gamut color pickercolor string
["a", "b"]dropdown liststring
{ action: fn }button
{ x: 0, y: 10 }folder (collapsible group)nested object
{ type: "…", … }that control, verbatimper control

The { type } forms unlock everything the shorthands can't say — the heavy controls (gradient, spring, cubic-bézier, plot, monitors…) and per-control options.

The verbose escape hatch

Any control can be written as { type, … } to reach options the shorthand can't express — and every object form accepts render, disabled and hint (covered in the panel API). Hover the ⓘ beside “Opacity”.

const tile = target.querySelector(".qt-tile");
const panel = tweaks("Verbose", {
  opacity: { type: "slider", value: 1, min: 0, max: 1, step: 0.05,
             hint: "Alpha blend of the tile" },
  zoom: { type: "number", value: 100, min: 25, max: 400, step: 5 },
  fit: { type: "segmented", options: ["cover", "contain", "auto"] },
});
mount.append(panel.el);

const apply = (p) => {
  tile.style.opacity = p.opacity;
  tile.style.transform = `scale(${p.zoom / 100})`;
  tile.style.backgroundSize = p.fit;
};
panel.on(apply);
apply(panel.params); // every control here is built-in → params are live already