Styling
How outputs draw. The rule that keeps a wrun indicator honest: outputs are numbers, some numbers are decisions, and declarations map decisions to looks.
Styling lives in the output(...) options and in the range(),
box() and segment() declarations at the top of the file, never in the
module's code: the chart reads the declaration and draws it, and Run
records it in the sheet it derives. A static look is one option per
output; a look that changes per bar is a ladder, a data-only output whose
floored value indexes a palette. What the user may change comes from the
same declarations: a param.color bound to an output by name, and
the Style page the dialog derives from the
outputs. This page is the wrun vocabulary for each look (size, tooltips,
z-order, palettes, gradients), and which looks have no form.
Every part a wrun indicator draws can be styled; for a part-by-part walk through one real indicator, start with Style anything and come back here for the vocabulary.
Placement, per output
plot:line,bar,area,histogram,candle,shape,scatter, ornonefor a data-only output: computed, never drawn, the building block for gates and palettes below. On the chartbarandhistogramboth draw as columns andshapeandscatteras marks;candletakes four consecutive outputs (open, high, low, close) that draw as one candle (Plotting).panel:overlay(the price chart) orlower(a pane below it). Put small-magnitude series (probabilities, oscillators) inlower; an odds-scale line on the price axis hugs the axis floor. Theloweroutputs of an indicator that also draws on price share one pane below the chart unlesspane: "<name>"sends them to a pane declared withpane(name, { title, place, height_frac, scale, invert, padding, min, max, format }): up to four named panes, below the chart or, withplace: "price", over the candles on a hidden scale of their own (Panes).z: the paint order inside a pane, an integer -10..10 on an output, arange, afillor abox. Absent, the engine's layer applies: tints 0, fills 1, lines, columns, bands, marks and boxes 2, text 3; ties keep declaration order.- Numbers:
formatnames how the output's value prints in the legend, the hover card and its axis tag:price(the chart's price digits, or a lower pane's own step digits on its axis),%(the value with a percent sign),si(K, M, B, T from 1,000),int,0,0.0,0.00,0.000(fixed digits),usd($with two decimals under 1,000, else$1.2K,$1.2M,$1.2B,$1.2Tat one decimal, the sign before the$) andauto(six significant digits with,thousands).decimals(0..8) overrides the word's digits,signed: trueputs a+on positives, andunitprints after the value onceformatis declared (an output'sunitis not bounded, as it never was; keep it short, a host may cut a long one);decimalsandsignedwithoutformatare refused ("decimals needs format"). Auniton its own is recorded in the sheet as before and never printed. Withoutformatthe chart formats numbers itself: a lower pane prints K, M and B from 1,000 and its own precision below that, a value on the price pane prints at the chart's price precision. A pane's axis ticks take the same four words onpane(...).
Static style, per output
One option per output, read from the declaration:
output("overbought", line, lower, { color: "#ff0000", width: 1, line_style: "dashed", description: "The 70 level, written on every bar" });
output("delta", histogram, lower, { color_by: "delta_sign", colors: ["#ef5350", "#26a69a"], description: "Fast minus slow as columns, colored by sign" });
// Red while the close is under the average, green (and three times as wide) while it is over.
output("mid", line, overlay, { color_by: "regime", colors: ["#ef4444", "#22c55e"], width_by: "regime", widths: [1, 3] });
// The band between the two edges: dotted edge lines and a slate interior.
range("band_hi", "band_lo", { color: "#94a3b8", edge_width: 1, edge_line_style: "dotted" });
// A curved line split around zero, shaded below it; a fill between the two edges with no edge lines of its own.
output("osc", line, lower, { smooth: true, split: "level", up_color: "theme.up", down_color: "theme.down", split_fill: true });
fill("band_hi", "band_lo", { color: "theme.accent", opacity: 0.15 });
// The 70 level as a guide: one full-width line, labelled on the line, out of the legend.
output("upper", line, lower, { role: "guide", align: "right", color: "theme.muted" });| Look | Option | What it draws |
|---|---|---|
| a color | color, or a colors palette | the line, column or mark color |
| a halo | glow | a soft halo in pixels on a line, an area, columns, candles, marks and scatter dots, and on a render.shape mark |
| rounded columns | corner | rounded column corners on a histogram, in pixels |
| transparency | opacity | 0..1 on an output, fading every colour it draws: a ladder's rungs, a packed colour, a column's sign pair, a candle's body, border and wick, marks and gradient stops; per box, per fill, per handle and per card too |
| thickness | width | the line width; widths the per-bar ladder, 1..10 entries, each 0.5..20; on columns a share of the bar slot, widths entries from 0.05 (1 = the columns touch) |
| a dash | line_style | solid, dashed, dotted; lines and areas take the dash, columns do not |
| curves | smooth | a line, or an area's edge, bent into curves |
| steps | step | a line as horizontal then vertical segments (a trailing stop, a funding step); never beside smooth |
| a stroke shaded by height | gradient on a line | 2 to 8 colours from the top of the pane to the bottom; never beside color_by or split |
| two colours around a level or by slope | split, up_color, down_color, split_level, split_fill, split_base | "level": up_color above split_level (default 0) and down_color below, split_fill shading down to split_base; "slope": up_color while rising, down_color while falling |
| an area's fill | fill_color, fill_opacity, fill_gradient, gradient_mode, fill_color_by plus fill_colors, fill_ | the fill's own colour (default the line's) at fill_opacity (0.4 flat, 1 on stops), or stops top to bottom over the pane, the fill or each column, or a colour per bar from its own ladder |
| a fill between two lines | fill(a, b, { color, opacity, opacity_by, color_by, colors, color_ | the interior only, no edge lines, between two drawn outputs on one pane, its opacity per bar from an output with opacity_by |
| a band's edges | edge_width, edge_line_style on a range() | both edge lines at an integer width 0..10 (0 = no edge lines), solid, dashed or dotted |
| a faded band | gradient on a range() | 2 to 8 colors, listed top to bottom, shading the interior vertically instead of a flat tint |
| where the stops lie | gradientMode | "pane" (the pane height, the default), "fill" (the band's own vertical extent) or "line" (per column, from upper down to lower) |
| a band's legend row | legend, label on a range() | legend: false drops the row; label names it |
| columns from a level | base | columns grow from base instead of zero, colors[0] at or above it and colors[1] below |
| columns faded by size | grading | "linear" or "square": each column's alpha follows its magnitude within the visible range |
| stacked columns | stack | bars sharing a stack name stack in declaration order, positives above zero and negatives below |
| a candle's style | candle_style, border_colors, wick_colors, border_width on a candle group's first output | "candle", "hollow", "ohlc" or "high_low"; border and wick colours as [both] or [up, down]; the border width 0..10 |
| the mark | shape, location, char, font_family, fill, fill_opacity | the shape (ten words, char one character in font_family); "absolute", "above_bar", "below_bar", "top" or "bottom"; the outline only, or a faded interior |
| a level | role: "guide", align, pill_style, font_size, axis_label | one full-width line at the output's last value, out of the legend; a label on the line ("left", "center", "right"; "filled" or "outlined"; 6..64 px) or on the axis |
| paint order | z | an integer -10..10 on an output, a range, a fill or a box; absent, the engine's layer (tints, fills, lines and columns and bands and marks and boxes, text) in declaration order |
| a theme colour | "theme.up", "theme.down", "theme.text", "theme.muted", "theme.bg", "theme.grid", "theme.accent" | the chart's own colour, resolved when it paints and again on a theme switch (Theme colours) |
| a color per bar | color_by plus colors, or color_packed_by | each bar's value indexes the palette, or carries a packed colour |
| a width per bar | width_by plus widths | the same ladder for line width |
| an inset strip's colours | color, colors, color_by, opacity on out.inset | colors without color_by is a sign pair (up at or above zero, down below); with color_by the bar's ladder colour |
| a HUD's look | look on render.hud | one of twelve presets, every word of which a declared word overrides (HUD cards) |
color (or a colors palette), width, opacity (0..1), line_style
(solid, dashed, dotted; lines and areas take the dash, columns
do not), glow (a soft halo in pixels on a line, an area, columns,
candles, marks and scatter dots), corner (rounded column corners, in
pixels), and description, which documents the output in the sheet. A
colour is "#rrggbb", "#rrggbbaa" (the alpha in the last byte), a CSS
colour name as before, or a theme token (below); opacity multiplies
every colour the output draws, a ladder's rungs, a packed colour, a
column's sign pair, a candle's border and wick and a gradient's stops
included. The legend's and the Style page's words for an
output come from label (the name read as words when absent) and its
numbers from format, decimals, signed and unit (above);
legend: false keeps an output out of the legend, visible: false
starts it hidden, price_line: true draws a dotted line across the pane
at its last value, axis_label: true tags that value on the price axis
and axis_name: true adds the indicator's name to the tag
(Plotting). The looks a plot kind takes beyond these
(step, smooth, gradient and split on lines; fill_color,
fill_opacity, fill_gradient and the fill ladder on areas; base,
grading, stack and width as a share of the bar slot on columns;
candle_style, border_colors, wick_colors and border_width on a
candle group; shape, location, char, fill and fill_opacity on
marks; role: "guide" for a level) are the table on
Plotting. The per-look
reading of this vocabulary, with the decision rule, is
Decisions to looks.
Theme colours
Every colour word accepts a theme token beside the hex forms:
theme.up and theme.down (the chart's candle colours), theme.text
(the axis text), theme.muted (that text at 55 percent), theme.bg
(the background), theme.grid (the grid lines) and theme.accent (the
app's accent). The chart resolves a token when it paints and again when
the theme switches, with no rerun, so a "theme.text" label reads on a
dark and a light chart alike. A token rides every colour key of this
page (outputs, ranges, fills, boxes, segments, renderers, drawings,
handles, cards, HUDs, docked levels and panels), the colour strings
inside a frame, and a packed colour the module writes
(toPacked(theme.UP) from ./sdk/color,
Colors kit). A param.color default or
preset stays a hex colour ("a colour param takes #rrggbb or #rrggbbaa;
put the token on the colour key"), and a theme. word outside the seven
is refused by name. Two chart-level flags ride beside the tokens:
chart.contrast_guard(false) keeps the author's colours as written on a
light chart (the chart otherwise darkens colours that would vanish
there), and chart.stack_handles(true) stacks this indicator's
corner-anchored handle groups below other indicators' groups instead of
overprinting them (Drawing objects).
The Style page
Every output you draw gets a row on the dialog's Style page without a
declaration, and a spot the file binds to a setting (color: "@basis_color", line_style: "@style") is that setting's row instead,
so a look never has two controls. The rows, the bindings and the
browser-or-cloud rule are on The Style page.
Decisions to looks
- Per-bar coloring: emit the decision as a data-only output (
none), then on the styled output setcolor_by: "<that output>"plus acolorspalette (at least 2 entries). Each bar's floored value indexes the palette; a finite value outside the palette takes entry 0, and a non-finite one draws the output's static color (entry 0 when the output declares nocolor). An output cannot color itself: the index expression is its own output. - Per-bar width: the color ladder's sibling. On the styled output set
width_by: "<data-only output>"plus awidthsladder (1..10 entries, each 0.5..20); each bar's value indexes the ladder (floor; a finite out-of-range index takes entry 0). A non-finite value on either ladder draws that bar in the static style. Both halves or neither, each refused by name without the other. An output cannot set its own width. - Gated markers: a
shapeoutput withshape_where: "<gate output>"renders only where the gate is nonzero. An output cannot gate itself. - Banded ranges:
range(upper, lower, options?)names two DIFFERENT drawn outputs (by name, as strings; anoneoutput is refused: "range references '', which is not a rendered output"). The chart draws a band: both edge lines at edge_width(an integer 0..10;0draws the band with no edge lines) andedge_line_style(solid,dashedordotted), with a tinted interior incolor. Acolorspalette pluscolor_by(a data-only output) tints the band per bar (floor; a finite out-of-range value takes entry 0);color_byrequirescolors.colorsWITHOUTcolor_byis the band's sign palette (a momentum fill): entry 0 whereupperplots abovelower, entry 1 where it plots below.gradient(2 to 8 colors, listed top to bottom) shades the interior vertically instead of a flat tint, laid overgradientMode:"pane"(the pane height, the default),"fill"(the band's own vertical extent) or"line"(per column, fromupperdown tolower).smoothis a boolean smoothing hint.legend: falsedrops the band's own legend row andlabelnames it (default: the upper edge's label);zsets its paint order. Declare as many ranges as needed; the same pair may repeat with different options. - Fills:
fill(a, b, options?)shades the interior between two drawn outputs on one pane and draws no edge lines, so each line keeps its own look. Options:color,opacity(0..1, default 0.25), thecolor_bypluscolorsladder orcolor_packed_byfor a colour per bar (a non-finite rung draws no fill that bar),opacity_byfor an opacity per bar, andz.opacity_bynames a declared output whose value on each bar is that bar's opacity (0..1), with any colour mode; a non-finite value keepsopacity. The two sides must be different drawn outputs on the same pane;colorswithoutcolor_by,color_bywithoutcolors,color_packed_bybesidecolor_by, and anopacity_bythat names no declared output are refused.
A setting reaches a fill's opacity through opacity_by: the file writes
the setting, scaled to 0..1, into a data-only output on every bar, and the
fill reads it there.
param.int("cloudOpacity", 40, { min: 0, max: 100, label: "Cloud opacity" });
output("cloud_alpha", none); // the cloud's opacity on each bar, 0..1
fill("span_a", "span_b", { color_by: "cloud_side", colors: ["#22c55e", "#ef4444"], opacity_by: "cloud_alpha" });
// in onBar(): out_cloud_alpha(p_cloudOpacity() / 100.0);A packed colour skips the palette: the module writes a colour per bar
into a data-only output (toPacked from the colour kit,
Colors) and the drawn output names it with
color_packed_by; an area's fill reads the same number through
fill_color_packed_by, so a heat that shifts smoothly needs no rungs.
// A heat area painted per bar from a colour the module computes: the edge and the fill both read it.
output("heat", area, lower, { color_packed_by: "heat_color", fill_color_packed_by: "heat_color", fill_opacity: 0.35, width: 2 });
output("heat_color", none, lower, { description: "A packed colour per bar, written with toPacked(...) in onBar()" });A per-bar box takes the same two ladders for its fill and its border,
under camelCase keys in the declaration (colorBy, borderColorBy,
borderColorPackedBy, borderStyle), with output handles for the By
keys (Boxes): a zone can follow the regime
with a dashed border while a second box, drawn only where the band
squeezes, takes its fill and border from one packed heat colour.
const hi = output("band_hi", line, overlay);
const lo = output("band_lo", line, overlay);
const regime = output("regime", none, overlay);
const heat = output("heat_color", none, overlay);
const squeezed = output("squeezed", none, overlay);
// The zone behind the last three bars: fill and border by the regime ladder, dashed, painted behind the lines.
box("zone", { top: hi, bottom: lo, from: -3, to: 0, colorBy: regime, colors: ["#ef444433", "#22c55e33"], borderColorBy: regime, borderColors: ["#ef4444", "#22c55e"], borderStyle: "dashed", z: -1 });
// The squeeze box: fill and border from one packed colour, where the gate is nonzero.
box("squeeze", { top: hi, bottom: lo, when: squeezed, colorPackedBy: heat, borderColorPackedBy: heat, opacity: 0.3, borderWidth: 2 });Every reference is checked as you type and when you press Run:
color_by, width_by, shape_where, and each range() side must name
a declared (and, where required, drawn) output, and none may name its own
output. A refusal points at the declaration in the editor's Console and
names the field (for example "Output 'mid' (color_by): ...").
Styling dresses per-output SERIES. When the indicator should also put
text, tables, shaped marks, or free-standing objects (lines, boxes,
polylines, labels) on the chart, that is the renderer and drawing
vocabulary: render.* and draw.* declarations over named outputs and
string slots (Plotting, Drawing objects).
Shapes that repeat on EVERY bar (a zone behind the last few bars, a
projection ray from each bar) are the box() and segment()
declarations over output handles
(Boxes, Segments).
Tags, the legend and the candle tint
Four looks belong to the indicator as a whole: whether it keeps a price
axis of its own, which plots tag their value on the price axis, the order
its plots join the legend, and the pane it lives in. One top-level
display({ ... }) declares them, at most once:
| Key | What the chart does | Absent |
|---|---|---|
axis: false | no price axis of its own: an indicator on the price pane rides the chart's scale | its own axis |
price_display: "per_output" | every plot tags its value on the price axis unless its show_ is false; a mark tags only when its show_ is true | the first output alone tags |
overlay: "offchart" | the indicator lives in its own pane below the chart; pane("lower", { format: "0.00" }) formats that pane's axis | the outputs' panels decide |
mount_order: "first_value" | plots join the legend, and paint within one layer, in the order they first draw a value | declaration order, every range after every output |
Five words sit on the plots themselves:
| Word | On | What it does |
|---|---|---|
show_ | an output, a range, a render.shape | the plot's tag on the price axis, read under price_display: "per_output": false drops it, true forces one |
show_ | an output | a declared output whose value on the last bar switches the tag: nonzero on, zero off, NaN keeps show_ |
omit_if_empty | an output, a range | true: a run that never drew it leaves it out, with no legend row and no tag (a plot drawn under an if) |
fill: false | a range | the two edge lines and no interior |
barcolor: true | a none output | the candles take its colour: each bar's value (floored) picks an entry of colors, or color_packed_by names a packed colour; a NaN or out-of-range value leaves the candle as it is; one per indicator |
Every colour bound to a setting also takes it at an alpha:
"@<param>/0.45" paints the setting's colour at 45 percent, and a
recolour keeps the 45; a panel series colour binds without one
(The Style page).
// No price axis of its own, a tag per plot, and plots listed in the order they first draw a value.
display({ axis: false, price_display: "per_output", mount_order: "first_value" });
param.int("length", 20, { min: 2, max: 200, label: "Length" });
param.color("bull", "#22c55e", { label: "Bull" });
param.color("bear", "#ef4444", { label: "Bear" });
param.bool("tag_basis", true, { label: "Tag the basis" });
// The basis tags its value while the setting is on; the edges never tag.
output("basis", line, overlay, { color: "@bull", show_price_display_by: "basis_tag" });
output("upper", line, overlay, { color: "@bull/0.5", show_price_display: false });
output("lower", line, overlay, { color: "@bear/0.5", show_price_display: false });
output("basis_tag", none);
// A mark on each breakout: a run with none leaves it out of the legend.
output("breakout", shape, overlay, { shape: "triangle_up", location: "below_bar", color: "@bull", omit_if_empty: true });
// The two edges as lines with no interior, untagged.
range("upper", "lower", { fill: false, show_price_display: false });
// The candles in the trend's colour at 45 percent: 0 below the basis, 1 above.
output("tint", none, overlay, { barcolor: true, colors: ["@bear/0.45", "@bull/0.45"] });
let sma = new Sma(20);
let stdev = new Stdev(20);
let tag: f64 = 1.0;
function onStart(): void {
sma = new Sma(i32(p_length()));
stdev = new Stdev(i32(p_length()));
tag = pb_tag_basis() ? 1.0 : 0.0;
}
function onBar(): void {
const close = bar.close();
const mid = sma.update(close);
const sd = stdev.update(close);
if (isNaN(mid) || isNaN(sd)) return;
const hi = mid + 2.0 * sd;
out_basis(mid);
out_upper(hi);
out_lower(mid - 2.0 * sd);
out_basis_tag(tag);
if (close > hi) out_breakout(bar.low());
out_tint(close > mid ? 1.0 : 0.0);
}Refused by name: a tag word on a none output ("show_price_display needs a
drawn output"), omit_if_empty on one ("omit_if_empty needs an output
that draws a value"), barcolor on a drawn output, without colors or
color_packed_by, beside color_by (its own value is the index) or on a
second output, a range with fill: false and a gradient, a
show_price_display_by that names no output, a second display(...) and
a word display does not take (overlay: "onchart").
Text size, tooltips, alignment, z-order, palettes
The styling vocabulary, item by item:
| You want | wrun form |
|---|---|
| text size | size, an integer pixel count 6..64, on render.text and render.label, or size_by for a size per bar from an output; font_size on a guide's label, a box's text and a card |
| type | font_weight (normal, medium, bold) and font_family (ui, the app font; mono; serif; rounded, each a system stack, nothing downloads) on renderer text, labels, box text, cards, HUDs and docked levels |
| a tooltip on a plot | tooltip on the output, a template over its own value and any output or string slot: "{{label}} {{value:price}} · {{state}}"; shown on the legend entry and when the cursor nears the line (Labels, tooltips, badges) |
| a tooltip on a cell, label, mark or drawing | tooltip on render.text, render.label, render.shape, draw.line, draw.box, draw.polyline and draw.label (one template per declaration, shown on its marks or object); a handle's tooltip(send) setter; a hover block list on an output or a label for a full card (HUD and hover cards); a table cell's tooltip in its styles entry, a string slot (Styled tables) |
| price tags, callouts, pills | style on render.text and render.label, eight words on both: plain, price_label (the price tag on the axis), pill (a rounded chip at the value), callout (a leader line to its bar), badge (a dot in the label's color), box, knockout (a box in the background colour) and emblem (a mark before the text); a tag look takes label_position, background_, border_color and corner_radius (Labels, tooltips, badges) |
| text alignment | align (left, center, right) and valign (top, middle, bottom) on plain render.text and render.label, on a handle or declared label, and on a box's text; the nine anchors (top_left ... bottom_right) are a table's, a HUD's or a corner render.label's position (Drawing objects) |
| z-order | z (-10..10) on an output, a range, a fill or a box, else the engine's layer in declaration order; a handle's zorder setter on lines, boxes, labels and polylines |
| a palette | a colors literal array on the output, box, range, fill, bgcolor, barcolor, stats row or shape renderer; bucket the driving value into its index (Colors); an entry may be a param.color by name; color_packed_by names an output that carries a packed colour per bar instead |
| per-element glow, opacity, gradients | glow per output, per renderer mark and per handle (glow_color picks its colour); opacity per output (every colour it draws), per box and per handle; a color_by ladder per bar; a line's gradient by height, an area's fill_gradient, a range() band's vertical gradient, a box handle's gradient; corner rounds histogram columns, corner_radius the corners of labels, boxes, cards and HUDs |
| a setting behind a look | "@<param>" in place of a colour, a colors or gradient entry, or a line style on an output, a range, a fill, a box, a segment, a legend entry or a docked plot.levels key; "@<param>/ for the setting's colour at an alpha; a param.color on every colour word of a panel (Panel words); a param.choice over the looks on a HUD card's look (Looks) (The Style page) |
| a table's fill, frame, lines and widths | the look keys on render.table: fills with opacity and gradients, a frame, the lines between cells, column widths, merged cells (Styled tables) |
Value-driven styling, computing the style from the data per element,
is the ladder: normalize the driving value,
floor it into a bucket, write the bucket to a none output, and index a
palette with it. The palette is finite, so the gradient is stepped, and
the decision stays a number you can read at the Console prompt or hand to
a declared alert.
A worked example
Bollinger-style bands with a regime-colored (and regime-widened) midline and a banded range. The declarations carry every look; the module computes four numbers per bar and never mentions a color:
param("period", 20, { min: 2, max: 400 });
param("band_width", 2, { min: 0.5, max: 4, description: "Stdev multiples" });
// Red while the close is under the average, green (and three times as wide) while it is over.
output("mid", line, overlay, { color_by: "regime", colors: ["#ef4444", "#22c55e"], width_by: "regime", widths: [1, 3] });
output("band_hi", line, overlay, { color: "#94a3b8", opacity: 0.6 });
output("band_lo", line, overlay, { color: "#94a3b8", opacity: 0.6 });
output("regime", none, overlay, { description: "0 below the average, 1 above: the palette and width index" });
// The band between the two edges: dotted edge lines and a slate interior.
range("band_hi", "band_lo", { color: "#94a3b8", edge_width: 1, edge_line_style: "dotted" });
let sma = new Sma(20);
let stdev = new Stdev(20);
let mult: f64 = 2.0;
function onStart(): void {
const period = i32(p_period());
sma = new Sma(period);
stdev = new Stdev(period);
mult = p_band_width();
}
function onBar(): void {
const close = bar.close();
const mid = sma.update(close);
const sd = stdev.update(close);
const regime = close > mid ? 1.0 : 0.0;
if (isNaN(mid) || isNaN(sd)) return;
out_mid(mid);
out_band_hi(mid + mult * sd);
out_band_lo(mid - mult * sd);
out_regime(regime);
}The regime output computes on every bar but never draws; it exists so
the palette (and the widths ladder) on mid has a decision to index.
The band is one range() over the two drawn edges, so the chart shades
it without a box per bar. The two params are number fields in the
overlay's settings dialog (a param.int would step by whole numbers,
and param.number with a step by that step), and changing one reruns
the compiled module without recompiling it; the three lines each get a
Style row.
The output(...) options carry color, colors, width, opacity,
line_style, glow, corner, z, color_by, color_packed_by,
shape_where, width_by, widths, displacement_bars,
displacement_bars_by, unit, description, the plot-kind looks of
Plotting (step,
smooth, gradient, split and its four companions, fill_color,
fill_opacity, fill_gradient, gradient_mode, fill_color_by,
fill_colors, fill_color_packed_by, base, grading, stack,
candle_style, border_colors, wick_colors, border_width, shape,
location, char, font_family, fill, role, align, pill_style,
font_size, pane), the presentation keys label, format,
decimals, signed, legend, visible, price_line, axis_label,
axis_name, tooltip, hover, badges, hint, and the chart words
show_price_display, show_price_display_by, omit_if_empty and
barcolor (Tags, the legend and the candle tint); ranges declare as
range(upper, lower, options?), fills as fill(a, b, options?), panes
as pane(name, options?), boxes and segments as box(name, options) /
segment(name, options) over output handles, and declaration order sets
the indexes (Declarations and the sheet).
Where the rules live
Every styling reference is validated as you type and when you press Run, and every refusal names the declaration and the field in the editor's Console; the messages are in Common errors. The module never draws: the chart reads the declarations, so the look is exactly what they describe, whatever the module computes.