aboutsummaryrefslogtreecommitdiffstats
path: root/docs/chrome.md
blob: 45b223ae29a47c6428ae3046b8fdfca2b0987ba7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# Chrome shaders

A frame is a rect too, so it is a pass too. `where="chrome"` on any entry in
`shaders` or in a `states` block runs that pass over a pane's **frame** (border,
padding, title, buttons) instead of its contents.

```kdl
states {
    // a bell nobody has answered: a quarter-second flash, then gone
    bell { tint where="chrome" channel="fg" color="#ffcc00" amount="(since < 250) * 255" }
}
```

Nothing else changes: same shaders, same `amount`, same
[expressions](shaders.md#strength-as-an-expression), same chain order. One new
word.

## Positions are the whole frame's

`x`/`y` are counted from the frame's top-left corner, with `cols`/`rows` the size
of the pane's rect, not of one side. One pass over the whole ring, so an effect
can travel round a border instead of restarting at every corner.

For anything that _travels_, though, the coordinate you want is distance along
the ring, which the language can work out. Clockwise from the top-left:

```
(y == 0 ? x : x == cols-1 ? cols - 1 + y
 : y == rows-1 ? 2 * cols + rows - 3 - x : 2 * cols + 2 * rows - 4 - y)
```

There is no way to name a subexpression, so the formula is written out in full,
which is why a small effect is a long line.

Thirteen of them are ready to paste in
`contrib/chrome`:
a shine running round the border, a sine comet with softer shoulders, marching
ants, a standing wave, drifting sparkles, ripples leaving a corner in both
directions, etc.

## A border that says something

Depending on a pane's [state](config.md#pane-states), we can visually communicate
through it's chrome:

```kdl
states {
    // a dead pane's frame breathes red until you deal with it
    dead { tint where="chrome" channel="fg" color="#ff0033" amount="abs(t/8%510-255)" }
    // one that has not started yet is outlined, not filled
    suspended { tint where="chrome" channel="fg" color="#8a8a95" amount=160 }
    // and the panes you are not in recede, frame and contents together
    unfocused { dim amount=60; dim where="chrome" channel="fg" amount=90 }
}
```

`since` is what makes a _flash_ possible: it is how long the pane has been in
this state, where `t` only knows what time it is. The `bell` state ends when you
look at the pane, because that is what answering a bell is. :-)

## Animation costs a clock

Anything that reads `t` or `since` asks the session to keep painting, at
`anim_ms` (50ms, so 20fps) and only while such a pass is actually on screen.

`anim_ms 0` turns the clock off, which leaves an animated shader advancing only
when something else causes a frame.