---
title: "Style anything"
description: "Every part a wrun indicator draws can be styled. A line, a column, a docked profile, a card in a corner, a label, a strike board and a pane each take their…"
order: 31
section: "presentation"
---

<!-- source: docs/indicators/presentation/style-anything.md; generated by packages/cli/scripts/gen-indicator-docs.ts, do not edit -->

# Style anything
![The desk on two chart cells: on the left, BTCUSDT 5m with the GEX by expiry board docked against the price axis, teal and violet cells with signed dollars, the at-the-money row outlined, the per-strike bars left of the board and the dashed gamma flip level with its label; on the right, BTCUSDT 1h with the eight tiles, the Deribit GEX curve with its spot marker, point callouts and the long gamma badge, and the rolling CVD histogram at the bottom](/wrun/images/style-anything/overview.png)

Every part a wrun indicator draws can be styled. A line, a column, a
docked profile, a card in a corner, a label, a strike board and a pane
each take their look as words in the declaration, and the chart draws
what the words say; the code only writes numbers. This page walks one
real indicator part by part, an options desk: a strike matrix docked on
the price axis, a dashboard of tiles, a gamma curve and a cumulative
volume delta. Each part shows its picture, the lines of the desk that
style it, the words that matter most, and the page that lists every
word.

The two files are cookbook recipes and template cards of their own:
[Strike Matrix](../cookbook/strike-matrix.md) is the left cell (the
board, the per-strike bars and the levels, under **On price**) and
[Options Dashboard](../cookbook/options-dashboard.md) the right (the
tiles, the gamma curve and the rolling CVD, under **Beyond the time
axis**); each compiles as written, on a chart of a coin with a listed
options chain.

The whole desk is eight declarations, two files on two chart cells; the
frames, outputs and slots they read come first:

```typescript
const board = frame("board", { max_bytes: 32768 });
const gexRows = frame("gex_rows", { max_bytes: 16384 });
const tileRows = frame("tile_rows", { max_bytes: 4096 });
const gexCurve = frame("curve_rows", { max_bytes: 16384 });
output("t_prev", none, overlay);
output("t_last", none, overlay);
output("flip_price", none, overlay);
output("cvd_sign", none, lower);
string("flip_text", { max_bytes: 32 });
plot.matrix({ name: "gex_board", frame: board, dock: "right", column_width: 66, row_max_px: 22, price_column: true, header: true, palette: ["theme.down", "theme.bg", "theme.up"], center: 0, scale: "sqrt", opacity: 0.95, format: "usd", signed: true, decimals: 1, font_size: 10, font_weight: "medium", align: "center", text_color: "theme.text", cell_padding: 3, grid_color: "theme.bg", grid_width: 2, grid_style: "solid", grid_lines: "all", highlight_color: "#f8c000", label: "GEX by expiry", tooltip: "{{column}}: {{value:usd}} net GEX at {{price}}" });
plot.levels({ name: "gex_by_strike", frame: gexRows, dock: "right", width_px: 100, baseline: "center", labels: false, opacity: 0.95, thickness_px: 10, format: "usd", signed: true, hover: true, offset: [340, 0] }); // offset: the board's width (4 columns of 66 px plus the price column), so the bars sit left of it instead of under it
draw.line("flip_line", { x1: "t_prev", y1: "flip_price", x2: "t_last", y2: "flip_price", color: "theme.text", width: 1, line_style: "dashed", extend: "both" });
handles.label({ anchor: "right", align: "right", style: "knockout", font_weight: "medium" });
panel.tiles({ name: "tiles", title: "Options, Deribit", x: "category", place: "below", frame: tileRows, columns: 4, accent: "auto", positive_color: "theme.up", negative_color: "theme.down", format: "usd", signed: true, hover_card: true, height_frac: 0.18 });
panel.line({ name: "gex_curve", title: "Deribit GEX (Hypothetical Spot)", x: "number", place: "below", frame: gexCurve, series: [{ name: "Net GEX", color: "theme.text", width: 2 }], chrome: "grid", smooth: true, fill_mode: "signed", fill_positive_color: "theme.up", fill_negative_color: "theme.down", fill_fade: true, x_format: "usd", x_decimals: 1, format: "usd", signed: true, decimals: 0, x_title: "Spot", y_zero: true, legend_style: "none", hover_card: true, height_frac: 0.25, maximize: true, stats_row: true });
output("cvd", histogram, lower, { pane: "cvd", color_by: "cvd_sign", colors: ["theme.down", "theme.up"], width: 0.7, label: "Agg. Rolling CVD", format: "si", description: "Rolling cumulative volume delta: aggressive buys minus sells over the window" });
pane("cvd", { height_frac: 0.12, format: "si" }); // the Indicator's home pane: it carries the Indicator's name, so no title here
```

## The map

| Part | What you see | The words that matter most | Full page |
| --- | --- | --- | --- |
| Side charts | a small chart of its own below the candles: the gamma curve | `chrome`, `legend_style`, `smooth`, `glow`, `fill_mode`, `markers`, `badge`, `height_frac` | [Frames, panels and compact widgets](cards-frames-panels.md#frames-panels-and-compact-widgets) |
| Levels and profiles | bars docked on the price axis, one per strike | `dock`, `width_px`, `baseline`, `thickness_px`, `offset`, `hover`, `poc`, `opacity` | [Docked profiles](cards-frames-panels.md#docked-profiles) |
| Cards and HUDs | the dashboard: eight tiles below the chart | `columns`, `accent`, `positive_color`, `negative_color`, `format`, `look`, `chrome`, `background_color` | [Panel words](cards-frames-panels.md#panel-words), [HUD cards](hud-and-hover-cards.md#hud-cards) |
| Labels and drawings | a line across the chart at the gamma flip, its label just left of the strike bars | `style`, `align`, `valign`, `font_weight`, `line_style`, `extend`, `sticky_right`, `axis_label` | [Drawing objects](drawing-objects.md) |
| Lines over time | the rolling CVD as columns, one number per bar | `color_by`, `colors`, `width`, `label`, `format`, `split`, `fill_color`, `glow` | [Styling](styling.md), [Plotting](plotting.md) |
| Price canvases | the strike matrix: a row per strike, a column per expiry | `palette`, `center`, `scale`, `column_width`, `highlight_color`, `grid_lines`, `format`, `font_weight` | [Price canvases](price-canvases.md) |
| Panes | the tiles, the curve and the CVD stacked under the chart | `height_frac`, `format`, `title`, `place`, `scale`, `invert`, `padding`, `min` | [Panes](plotting.md#panes) |
| Theme and the Style page | the same desk on a light chart, with the user's own colours | `theme.*` tokens, `"@name"`, `param.color`, `param.choice`, `contrast_guard`, `stack_handles` | [Theme colours](styling.md#theme-colours), [The Style page](../settings/style-page.md) |

## Side charts

A side chart is a small chart of its own, in a pane below the candles
or in the strip beside them. The desk's gamma curve is a `panel.line`
over a decimal x, the hypothetical spot; its dashboard of tiles is a
`panel.tiles` (the next part). Reach for one when the picture is not one
value per bar: a curve over strikes, a count per weekday, a board of
numbers. The module writes the rows as a frame; the look is the
declaration's words, and the per-run chrome (the markers, the caption,
the badge chip) rides in the frame beside the rows.

![The gamma curve panel: a smooth teal line with a halo over a dollar spot axis, its fill fading downward, the dashed Spot marker with its chip, two point callouts pinned on the curve at the trough and the peak, and the LONG GAMMA badge chip on the title row](/wrun/images/style-anything/side-charts.png)

```typescript
const gexCurve = frame("curve_rows", { max_bytes: 16384 });
// The gamma curve: a smooth line in the chart's text ink over hypothetical spot, filled in the up colour above zero
// and the down colour below, both axes in dollars; the spot marker, the point callouts (the flip, the peak, the trough)
// and the regime badge chip are written per run into the frame. The one series needs no legend chip: the title names
// it and the hover card reads it.
panel.line({ name: "gex_curve", title: "Deribit GEX (Hypothetical Spot)", x: "number", place: "below", frame: gexCurve, series: [{ name: "Net GEX", color: "theme.text", width: 2 }], chrome: "grid", smooth: true, fill_mode: "signed", fill_positive_color: "theme.up", fill_negative_color: "theme.down", fill_fade: true, x_format: "usd", x_decimals: 1, format: "usd", signed: true, decimals: 0, x_title: "Spot", y_zero: true, legend_style: "none", hover_card: true, height_frac: 0.25, maximize: true, stats_row: true });
```

The frame the module writes beside the rows, with the chrome of this
run: the spot marker, three point callouts pinned on the curve, the
caption and the badge chip (the flip callout is written only when the
curve crosses zero):

```json
{
  "rows": [
    [76726.8, 65600],
    [76932.9, 787123],
    [93776.5, 398200000]
  ],
  "markers": [
    { "x": "spot", "label": "Spot", "badge": true, "wash": true },
    {
      "x": 76820.4,
      "valign": "point",
      "series": "Net GEX",
      "label": "Gamma flip",
      "color": "theme.text",
      "badge": true,
      "show_value": true
    },
    {
      "x": 93776.5,
      "valign": "point",
      "series": "Net GEX",
      "label": "+$398.2M @ $93776",
      "color": "theme.up",
      "badge": true
    },
    {
      "x": 76726.8,
      "valign": "point",
      "series": "Net GEX",
      "label": "+$65.6K @ $76726",
      "color": "theme.down",
      "badge": true
    }
  ],
  "caption": "live chain",
  "badge": { "text": "LONG GAMMA - DAMPENED", "color": "theme.up" }
}
```

The words that matter:

- `chrome` picks the frame: `"box"`, `"grid"` or `"none"`; the rich words
  of a line (`smooth`, `glow`, `animate`, the fills, `markers`) need
  `"grid"` or `"none"`.
- `legend_style` (`"none"`, `"title"`, `"pane"`, `"chips"`) and
  `legend_latest` put the series names and their last values on the
  panel; `hover_card` is the readout under the pointer.
- `height_frac` is the pane's share of the chart; `place: "side"` with
  `width_px` and `height_px` moves the panel into the strip beside the
  price pane.
- `fill_mode: "signed"` with `fill_positive_color` and
  `fill_negative_color` shades a line around zero and `fill_fade` fades
  the fill away from the line; `stroke_fade` fades the stroke away from
  a pivot; `markers` rule off an x of note.
- `badge` puts a chip on the panel's title row (`text`, a `color` that
  defaults to `theme.accent`, a `text_color` that defaults to whichever
  of light or dark reads on the fill); a marker with `valign: "point"` is
  a callout pinned to the curve, at the value of the declared `series` it
  names (the first series by default) or at an exact `y`. Both are frame
  keys too, so the module can rewrite the chip and point at the peak it
  found on every run.
- `x_title`, `y_title`, `x_format` with `x_decimals`, `y_zero` and
  `y_min`, `y_max` dress the axes; `maximize` and `stats_row` add the
  fullscreen button and the strip.

Every panel word, kind by kind, is on
[Panel words](cards-frames-panels.md#panel-words); the strip beside the
chart is on
[The strip beside the chart](price-canvases.md#the-strip-beside-the-chart).

## Levels and profiles

A docked profile is one bar per price along the price axis, drawn from a
frame the module writes. On the desk it is net gamma by strike: zero
sits mid-dock, positives grow one way and negatives the other, each row
in its own colour from the frame, a hover card per row. Reach for it
when a number lives at a price rather than at a time: open interest by
strike, volume by price, a liquidation map. `plot.profile` draws the
same shape from the chart's own volume cells with no frame. Two canvases
docked on the same side overprint and no word stacks them: `offset:
[340, 0]`, the board's width, pushes the bars inward so they sit left of
the board instead of under it.

![The per-strike net GEX bars in a narrow column left of the board: teal bars growing one way from the centre baseline and violet bars the other, one per strike, the dashed flip level running through them](/wrun/images/style-anything/levels.png)

```typescript
const gexRows = frame("gex_rows", { max_bytes: 16384 }); // the bars: net GEX per strike, the board's row sums
// The per-strike net GEX bars beside the board: zero mid-dock, positives one way and negatives the other, each row
// in its own colour from the frame, a hover card per row, pushed inward past the board (both dock right), 100 px wide.
plot.levels({ name: "gex_by_strike", frame: gexRows, dock: "right", width_px: 100, baseline: "center", labels: false, opacity: 0.95, thickness_px: 10, format: "usd", signed: true, hover: true, offset: [340, 0] }); // offset: the board's width (4 columns of 66 px plus the price column), so the bars sit left of it instead of under it
```

The frame carries one price, one value, one colour and one hover hint
per row:

```json
{
  "prices": [84000, 84250, 84500],
  "values": [-1200000, 350000, 2400000],
  "colors": ["theme.down", "theme.up", "theme.up"],
  "tooltips": [
    "C +$1.2M | P -$2.4M",
    "C +$0.9M | P -$0.5M",
    "C +$2.6M | P -$0.2M"
  ]
}
```

The words that matter:

- `dock` and a fixed `width_px` (or `width_frac`) place the profile;
  `offset` and `beside` nest one profile inside another.
- `baseline: "center"` grows positive rows one way and negative the
  other; `series` splits a row into stacked segments, each with its
  colour.
- `thickness_px` caps a bar's height and `step` gives every row a price
  band of its own (a strike ladder).
- `labels`, `label_place`, `format` with `signed`, `text_color` and
  `font_size` print the rows; `hover` opens the chart's card on a row,
  with the frame's `tooltips` as its hint.
- `poc`, `poc_color`, `poc_width`, `poc_line_style`, `poc_extend` and
  `poc_label` draw the point of control; the `value_area_*` words rule
  off the value area and `outside_opacity` fades the rows beyond it.
- `opacity`, `gradient`, `border_color`, `shape: "outline"` and
  `behind_candles` change how the bars paint.

Every word, with its range, is on
[Docked profiles](cards-frames-panels.md#docked-profiles); a profile over
the chart's own cells is on
[Profiles anchored in time](price-canvases.md#profiles-anchored-in-time).

## Cards and HUDs

A dashboard is a panel of tiles below the chart, or a card pinned at one
of the nine anchors that never moves with price. The desk's eight tiles
are a `panel.tiles`: a label, a value, a caption and a colour per tile,
written per run into the frame; the panel prints signed dollars, a
tile's own format word or text wins, and the accent tints a numeric tile
by its sign. Reach for a tiles panel when the numbers need room; for a
readout that floats over the candles, a `render.hud` card picks a whole
`look` at once, and a status card (`draw.card`), a ladder, a feed and a
meter take the same surface and chrome words.

![The eight tiles in two rows of four: live net GEX in teal, the gamma flip and max pain in the text colour, the dealer regime in teal, the P/C ratio and net VEX in teal, the 25D skew and the dealer delta in rose, each with a caption under its value](/wrun/images/style-anything/cards.png)

```typescript
const tileRows = frame("tile_rows", { max_bytes: 4096 });
// Eight tiles in two rows of four: the panel prints signed dollars, a tile's own format word or text wins, and the
// accent tints a numeric tile by its sign (the chart's up colour above zero, its down colour below); a tile with its own
// colour keeps it. The tiles, the curve and the CVD pane take 0.55 of the chart, so the candles keep the rest.
panel.tiles({ name: "tiles", title: "Options, Deribit", x: "category", place: "below", frame: tileRows, columns: 4, accent: "auto", positive_color: "theme.up", negative_color: "theme.down", format: "usd", signed: true, hover_card: true, height_frac: 0.18 });
```

The rows as the module writes them, `[label, value, caption, color,
spark, format]` with `null` to skip an element; the neutral values carry
`theme.text`, so they read on the light chart too:

```json
{
  "rows": [
    ["Live net GEX", 235182438, "@ $85.2K | chart", null, null, "usd"],
    ["Gamma flip", "$87,526", "+2.7% from spot", "theme.text"],
    ["Max pain", "$79,000", "-7.3% from spot", "theme.text"],
    ["Dealer regime", "Positive Gamma", "Dips bought, rallies sold", "theme.up"],
    ["P/C ratio", "0.63", "Calls favored", "theme.up"],
    ["25D skew", "+0.1pp", "Puts bid (downside)", "theme.down"],
    ["Dealer delta", "-62.1K", "Net short delta, in coins", "theme.down"]
  ]
}
```

The words that matter:

- A tiles panel: `columns` (1 to 8), `accent` (`"auto"` tints a numeric
  tile by its sign, `"neutral"` leaves it), `positive_color` and
  `negative_color`, `format` with `signed`, `decimals` and `unit` for
  every value it prints, `hover_card`, `height_frac` and `title`; a row's
  own `color`, `spark` and `format` win over the panel's.
- A HUD card: `look` is one of twelve presets (`glass`, `terminal`,
  `cockpit`, `phosphor` and the rest) and any word beside it wins;
  `chrome` the frame (`"card"`, `"none"`, `"brackets"`, `"rules"`,
  `"tag"`, `"title_bar"`, `"window"`, `"cover"`); `texture:
  "scanlines"` the finish.
- The surface: `background_color` with `background_opacity`, or
  `background_gradient` with `gradient_direction`; `border_color`,
  `border_width`, `border_style`; `corner_radius`, `padding`, `shadow`,
  `opacity`.
- The type and the accent: `font_family`, `text_color`,
  `title_text_color`, `title_case`, `label_case`, `text_glow`;
  `accent_color`, or `accent_color_by` with `accent_colors` so the whole
  card follows an output per bar.
- Size and place: `width`, `offset`, `z`, `safe_area`, `mobile`; each
  tile's `draw`, `color` or `color_by` with `colors`, `headline`,
  `font_size`, `height`.

The tiles words are on [Panel words](cards-frames-panels.md#panel-words)
and the rows on
[Panel rows, kind by kind](cards-frames-panels.md#panel-rows-kind-by-kind);
every HUD word is on [HUD cards](hud-and-hover-cards.md#hud-cards) and
the twelve looks on [Looks](hud-and-hover-cards.md#looks); the card,
ladder, feed and meter words on
[Status cards](cards-frames-panels.md#status-cards) and
[Ladder, feed and meter](cards-frames-panels.md#ladder-feed-and-meter).

## Labels and drawings

A drawing is one object placed from the newest bar. The desk draws each
of its levels as a dashed line across the whole pane and a knockout
label that ends just left of the strike bars, so it never covers a cell
of the board; the gamma flip is the pair below, and the largest GEX
strike, max pain and the put wall repeat it in their own colours. The
line is a `draw.line`; the label is a handle the live bar places in
pixels from the price axis at the level's price, its text a slot the
live bar writes. Reach for `draw.*` when one declaration is one object;
for a mark on every signal bar use `render.text` or `render.shape`, and
for an object the module moves and deletes later, a handle. Every look
word is optional, and absent keeps the object's usual look.

![The gamma flip level: a violet dashed line across the price pane with its knockout label, #3 $88K | GF $87.5K, ending at the last candle, the line running on through the board's cells](/wrun/images/style-anything/labels.png)

```typescript
output("t_prev", none, overlay);
output("t_last", none, overlay);
output("flip_price", none, overlay);
string("flip_text", { max_bytes: 32 });
// The gamma flip: one dashed line across the whole pane, placed from the newest bar.
draw.line("flip_line", { x1: "t_prev", y1: "flip_price", x2: "t_last", y2: "flip_price", color: "theme.text", width: 1, line_style: "dashed", extend: "both" });
// Its knockout label: a label handle placed in pixels from the price axis (x) at the level's price (y), right-aligned
// so its right edge sits just left of the bars.
handles.label({ anchor: "right", align: "right", style: "knockout", font_weight: "medium" });
const tags: LabelHandle[] = [draw.label(0), draw.label(1), draw.label(2), draw.label(3)]; // the wall, the flip, max pain, the put wall; handle objects allocate once
// On the live bar, with the text built in the line buffer; inset is the board's and the bars' width in pixels.
tags[1].set(inset, flipPrice).text(str_flip_text_sb).color(theme.TEXT);
```

The words that matter:

- A line: `width`, `line_style`, `extend` (`"none"`, `"left"`,
  `"right"`, `"both"`), `arrow`, `glow` with `glow_color`,
  `sticky_right`, `axis_label` and `opacity`.
- A label: `style` from eight words (`plain`, `box`, `knockout`,
  `emblem`, `pill`, `badge`, `callout`, `price_label`; `knockout` hides
  what is behind the text), `align` (which edge of the text sits on x),
  `valign`, `background_color`, `border_color`, `border_width`,
  `corner_radius`, `padding`, `font_weight`, `font_family`,
  `emblem_shape` with `emblem_color`, `max_width` and `angle`.
- A label handle: `handles.label(...)` takes the label words as the
  defaults every label handle starts from; `anchor: "right"` measures
  its x in pixels from the price axis while its y stays a price, and the
  setters (`set`, `text`, `color`) place, word and paint each one per
  run.
- A box: `color` is the fill, then `border_*`, `shape: "ellipse"`,
  `gradient` with `gradient_direction`, and `text` with its `text_color`,
  `font_size`, `align`, `valign` and `padding`.
- A renderer mark takes the same label `style` words plus
  `label_position`, `size`, `size_by` and a `color_by` ladder; `tooltip`
  is a template shown on any of them.

The drawings are on [Run-level drawings](drawing-objects.md#run-level-drawings),
every setter a handle takes on
[Every look a handle takes](drawing-objects.md#every-look-a-handle-takes),
the pixel anchors on
[Pane pixel placement](cards-frames-panels.md#pane-pixel-placement),
and the renderer marks on
[Labels, tooltips, badges](labels-and-tooltips.md).

## Lines over time

A line over time is an output: one number per bar that the chart draws
as a line, an area, columns or marks. The desk's rolling CVD is a
`histogram` coloured by a sign ladder, columns in the chart's down colour
below zero and its up colour above, in a pane of its own that prints K and M on its axis. Reach
for the output words first: they are the cheapest look, and every drawn
output can carry an alert once the indicator is published.

![The rolling CVD histogram in its pane: violet columns below zero on the left turning green above zero on the right, the legend reading the indicator's name and the last value, the axis tag in green](/wrun/images/style-anything/lines.png)

```typescript
input("buy", trades.volume, { side: "BUY", missing: "zero", description: "Aggressive buy volume" });
input("sell", trades.volume, { side: "SELL", missing: "zero", description: "Aggressive sell volume" });
output("cvd_sign", none, lower, { description: "0 while the rolling CVD is negative, 1 while positive: the histogram's palette index" });
output("cvd", histogram, lower, { pane: "cvd", color_by: "cvd_sign", colors: ["theme.down", "theme.up"], width: 0.7, label: "Agg. Rolling CVD", format: "si", description: "Rolling cumulative volume delta: aggressive buys minus sells over the window" });
pane("cvd", { height_frac: 0.12, format: "si" }); // the Indicator's home pane: it carries the Indicator's name, so no title here
```

The words that matter:

- The static look: `color`, `width`, `opacity`, `line_style`, `glow`,
  `z`; the per-bar ladders `color_by` with `colors` (or
  `color_packed_by`) and `width_by` with `widths`; `label` and `format`
  for the legend and the axis tag.
- A line's shape: `smooth`, `step`, `gradient`, and `split` with
  `up_color`, `down_color`, `split_level`, `split_fill`, `split_base`.
- An area's fill: `fill_color`, `fill_opacity`, `fill_gradient` with
  `gradient_mode`, or `fill_color_by` with `fill_colors`.
- Columns: `width` as a share of the bar slot, `base`, `grading`,
  `stack`; a candle group: `candle_style`, `border_colors`,
  `wick_colors`, `border_width`.
- Marks: `shape`, `location`, `char`, `fill`, `fill_opacity`; a level:
  `role: "guide"` with `align`, `pill_style`, `font_size`, `axis_label`.

Every output word is on [Styling](styling.md); the looks each plot kind
takes are the table on
[Lines, areas, columns, dots, marks](plotting.md#lines-areas-columns-dots-marks)
and [Candles](plotting.md#candles); a band between two lines is a
`range()` or a `fill()` ([Decisions to looks](styling.md#decisions-to-looks)).

## Price canvases

A price canvas is drawn on the price chart from cells the chart already
serves or from a frame the module writes. The desk's strike matrix is a
`plot.matrix`: one row per strike on the price axis, one column per
expiry, each cell tinted on a diverging scale around zero. Heatmaps,
footprints, TPO letters and anchored profiles are the other four. Reach
for a canvas when the picture is a grid over price: a cell per bar and
price row, or a cell per strike and expiry. The board sits on its
strikes' prices, so strikes outside the candles' own range stay clipped
until you zoom the price axis out by dragging it, as the original's
author did; no word widens the range.

![The GEX by expiry board docked against the price axis: the expiries 0DTE, 06OCT, 07OCT and 08OCT across the header, the strikes down the price column, every cell a signed dollar amount tinted teal for calls and violet for puts by size, the at-the-money row outlined in amber](/wrun/images/style-anything/canvases.png)

```typescript
const board = frame("board", { max_bytes: 32768 }); // the matrix: one row per strike, one column per expiry
// The strike by expiry board against the price axis: a diverging palette centred on zero, puts in the chart's down
// colour and calls in its up colour, the tint by the square root of the cell's size, signed dollars in every cell, the
// at-the-money row outlined in amber.
plot.matrix({ name: "gex_board", frame: board, dock: "right", column_width: 66, row_max_px: 22, price_column: true, header: true, palette: ["theme.down", "theme.bg", "theme.up"], center: 0, scale: "sqrt", opacity: 0.95, format: "usd", signed: true, decimals: 1, font_size: 10, font_weight: "medium", align: "center", text_color: "theme.text", cell_padding: 3, grid_color: "theme.bg", grid_width: 2, grid_style: "solid", grid_lines: "all", highlight_color: "#f8c000", label: "GEX by expiry", tooltip: "{{column}}: {{value:usd}} net GEX at {{price}}" });
```

The frame the module sends is `{ prices, cells, cols, title, highlight }`:
the strikes ascending, one cell row per strike with `null` where an
expiry lists no open interest, the column names (`"0DTE"`, `"05OCT"`,
...), the board's title and the at-the-money row to outline.

The words that matter:

- The scale: `palette` with `min`, `max`, `center`, `auto_quantile` and
  `scale` (`"linear"`, `"sqrt"`, `"log"`); `opacity` over every fill.
- The grid: `column_width`, `row_max_px`, `header`, `price_column`,
  `cell_padding`, `grid_color`, `grid_width`, `grid_style`, `grid_lines`,
  the `border_*` words and `highlight_color`.
- The type and numbers: `font_size`, `font_family`, `font_weight`,
  `align`, `text_color`, `header_text_color`, `format` with `decimals`,
  `signed` and `unit`; `tooltip` and `label` for the readout.
- A heatmap adds `row_height`, `floor`, `cell_gap`, `behind_candles` and
  `labels`; a footprint `mode`, the `imbalance_*` words, `hide_zero`,
  `cell_metric`; a TPO `display`, `color_mode`, `letter_minutes` and
  `single_prints_color`; an anchored profile `span`, `mode`, `naked`
  and `extend`.

Every canvas, word by word, is on [Price canvases](price-canvases.md);
the matrix on [Strike matrices](price-canvases.md#strike-matrices).

## Panes

A pane is a scale of the indicator's own: below the chart for a number
with its own range, or over the candles on a hidden scale with
`place: "price"`. The desk's right cell stacks three under the chart:
the tiles at 0.18 of the chart, the curve at 0.25 with a maximize button
and a stats row, and the indicator's own CVD pane at 0.12, mounted last
beside the time axis; the three take 0.55, so the candles keep the
rest, and the home pane carries the indicator's name, so it takes no
title. Reach for a pane when a small-magnitude series would hug
the axis floor on the price pane, or when two studies need scales of
their own.

![The right cell top to bottom: the candles, the BTC Options tiles panel, the Deribit GEX curve panel with the Spot marker, callouts and badge, and the Options Dashboard CVD pane next to the time axis](/wrun/images/style-anything/panes.png)

```typescript
const tileRows = frame("tile_rows", { max_bytes: 4096 });
const gexCurve = frame("curve_rows", { max_bytes: 16384 });
output("regime_sign", none, overlay);
output("cvd_sign", none, lower);
string("regime_text", { max_bytes: 48 });
output("cvd", histogram, lower, { pane: "cvd", color_by: "cvd_sign", colors: ["theme.down", "theme.up"], width: 0.7, label: "Agg. Rolling CVD", format: "si", description: "Rolling cumulative volume delta: aggressive buys minus sells over the window" });
pane("cvd", { height_frac: 0.12, format: "si" }); // the Indicator's home pane: it carries the Indicator's name, so no title here
render.legend("regime_entry", { text: "regime_text", color_by: "regime_sign", colors: ["theme.down", "theme.up"] });
panel.tiles({ name: "tiles", title: "Options, Deribit", x: "category", place: "below", frame: tileRows, columns: 4, accent: "auto", positive_color: "theme.up", negative_color: "theme.down", format: "usd", signed: true, hover_card: true, height_frac: 0.18 });
panel.line({ name: "gex_curve", title: "Deribit GEX (Hypothetical Spot)", x: "number", place: "below", frame: gexCurve, series: [{ name: "Net GEX", color: "theme.text", width: 2 }], chrome: "grid", smooth: true, fill_mode: "signed", fill_positive_color: "theme.up", fill_negative_color: "theme.down", fill_fade: true, x_format: "usd", x_decimals: 1, format: "usd", signed: true, decimals: 0, x_title: "Spot", y_zero: true, legend_style: "none", hover_card: true, height_frac: 0.25, maximize: true, stats_row: true });
```

The words that matter:

- `title` heads the pane's legend, and `{{name}}` reads a setting; the
  indicator's home pane carries its name instead.
- `place: "below"` stacks the pane under the chart in declaration order;
  `place: "price"` draws its outputs over the candles on a hidden scale.
- `height_frac` is the pane's share of the chart, on a pane and on a
  panel alike; `padding: [top, bottom]` sets the autoscale margins;
  `min` and `max` hold either end.
- `scale` is `"linear"`, `"log"`, `"percent"` or `"indexed"`, and
  `invert: true` flips the axis.
- `format`, `decimals`, `signed` and `unit` print the axis ticks; `pane:
  "<name>"` on an output puts it in the pane.

Every pane word is on [Panes](plotting.md#panes).

## Theme and the Style page

Every colour word takes a theme token beside a hex colour, and a token
follows the chart: the board's zero cell takes `theme.bg`, the legend
entry `theme.muted` and the neutral tile values `theme.text`, so the
desk reads on a dark and a light chart alike, re-resolved on a theme
switch with no rerun, while every hex colour stays as written on both.
A `"@name"` in place of a colour, a line style or a docked profile's key
hands that spot to a setting, and the dialog's Style page draws the
user's own controls for every drawn output without a declaration. Two
chart-level flags finish the set.

![The same eight tiles on a dark chart and on a light chart side by side: the panel surface follows the theme, the neutral values read white on dark and black on light, and the teal and rose values keep their colours](/wrun/images/style-anything/theme.png)

```typescript
string("spot_text", { max_bytes: 32 });
const board = frame("board", { max_bytes: 32768 });
const tileRows = frame("tile_rows", { max_bytes: 4096 });
// The words that follow the chart's theme: theme.muted on the legend entry; theme.down and theme.up at the palette's
// ends around theme.bg (the board's zero cell takes the chart background, dark or light); theme.up and theme.down on
// the tiles' signed values, theme.text on the neutral ones in the frame.
render.legend("spot_entry", { text: "spot_text", color: "theme.muted" });
plot.matrix({ name: "gex_board", frame: board, dock: "right", column_width: 66, row_max_px: 22, price_column: true, header: true, palette: ["theme.down", "theme.bg", "theme.up"], center: 0, scale: "sqrt", opacity: 0.95, format: "usd", signed: true, decimals: 1, font_size: 10, font_weight: "medium", align: "center", text_color: "theme.text", cell_padding: 3, grid_color: "theme.bg", grid_width: 2, grid_style: "solid", grid_lines: "all", highlight_color: "#f8c000", label: "GEX by expiry", tooltip: "{{column}}: {{value:usd}} net GEX at {{price}}" });
panel.tiles({ name: "tiles", title: "Options, Deribit", x: "category", place: "below", frame: tileRows, columns: 4, accent: "auto", positive_color: "theme.up", negative_color: "theme.down", format: "usd", signed: true, hover_card: true, height_frac: 0.18 });
```

The badge chip in the curve's frame takes a theme word per run,
`{ "text": "SHORT GAMMA - AMPLIFIED", "color": "theme.down" }` or
`{ "text": "LONG GAMMA - DAMPENED", "color": "theme.up" }`, and the chart
picks the ink that reads on it.

The words that matter:

- The seven tokens: `theme.up`, `theme.down`, `theme.text`,
  `theme.muted`, `theme.bg`, `theme.grid`, `theme.accent`; every colour
  key on this page takes one, and so does a colour string inside a
  frame.
- `"@name"` binds a spot to a setting: a `param.color` behind a colour,
  a `param.choice` behind a line style or a docked profile's word key, a
  `param.number`, `param.int` or `param.bool` behind a profile's number
  or switch.
- `label`, `format`, `legend` and `visible` on an output shape its row
  on the Style page; every HUD gets a Look row of its own.
- `chart.contrast_guard(false)` keeps the author's colours as written on
  a light chart; `chart.stack_handles(true)` stacks the indicator's
  corner groups under other indicators' groups.

The tokens are on [Theme colours](styling.md#theme-colours), the
bindings and the rows on [The Style page](../settings/style-page.md),
and the packed form a module writes on
[Colors kit](../functions/colors-kit.md#theme-tokens).

## Every word

The deep pages list every word with its range and what refuses:

- [Plotting](plotting.md) and [Styling](styling.md): outputs, panes,
  ranges, fills, boxes and segments
- [Drawing objects](drawing-objects.md) and
  [Labels, tooltips, badges](labels-and-tooltips.md): drawings, handles
  and renderer marks
- [Cards, frames and panels](cards-frames-panels.md): tables, cards,
  panels, docked profiles, ladders, feeds and meters
- [HUD and hover cards](hud-and-hover-cards.md) and [Legend](legend.md):
  the three surfaces that read the newest values
- [Price canvases](price-canvases.md): heatmaps, footprints, TPO
  letters, anchored profiles and strike matrices
