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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
#!/usr/bin/env python3
"""shaders -- colour passes over cells, with strengths written as expressions.
The left pane runs contrib/shader-repl -- the prompt from the docs -- and
what gets typed at it is exactly what a config file would say: a tint over
the frame, a spotlight whose strength is a distance from the cursor (so it
follows the typing), a ruler, scanlines. Then a shipped preset (`:load
shine`) animates a sheen along the frame -- sampled on the session's own
deadline clock -- and, calm restored, the neighbouring pane rings while
unfocused: the border flash is the same kind of pass, over the frame.
"""
import os
import shutil
import sys
import tempfile
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from castgen import ROOT, Recorder, out_path
ENV = {"PS1": "$ ", "ENV": "/dev/null"}
# Mono, not the house pink: this demo is about colour passes, so the base
# theme is the one without colour -- every hue on screen is a shader's. It
# also gives this cast its own look in the tour's theme rotation.
THEME = os.path.join(ROOT, "contrib", "themes", "mono.kdl")
work = tempfile.mkdtemp(prefix="slosh-demo-")
cfg = os.path.join(work, "config.kdl")
with open(cfg, "w") as f:
f.write(open(THEME).read())
f.write("\nin_band_shaders true\n")
# The bell, on a fuse: rings one real second after the nudge, so the focus is
# long gone by the time it goes off.
with open(os.path.join(work, "ring"), "w") as f:
f.write("read x\nsleep 1\nprintf '\\a'\nread y\n")
repl = os.path.join(ROOT, "contrib", "shader-repl")
lay = os.path.join(work, "demo.layout")
with open(lay, "w") as f:
f.write(
'layout {\n tab {\n pane focus=true command="python3 %s"\n'
' pane cwd="%s" command="sh ring"\n }\n}\n' % (repl, work)
)
r = Recorder(
["/bin/sh"],
cols=100,
rows=28,
title="colour passes over cells",
config=cfg,
env=ENV,
layout=lay,
)
r.capture(force=True, settle_ms=150)
r.pause(1.2)
# A pass over the frame: the chrome> prompt is aimed at it already.
r.run('tint color="#5fffaf" amount=140')
r.pause(1.8)
# Content: a spotlight, strength by distance from the cursor.
r.run(":content")
r.pause(0.6)
r.run('tint amount="255 - dist(x, y, curx, cury) * 14" color="#ff5fd7"')
r.pause(1.0)
# ...which is why it follows the next thing typed: a ruler.
r.run('ruler amount=120 at=50 color="#7aa2f7"')
r.pause(1.8)
# Scanlines: one built-in, one property.
r.run("zebra amount=110 band=1")
r.pause(1.8)
# A shipped preset, and an animated one: a sheen runs the frame. The pass
# reads the clock, so the session asks for frames and pause() samples them.
r.run(":chrome")
r.pause(0.5)
r.run(":load shine")
r.pause(2.4)
# Calm again before the finale; the sheen would talk over the bell.
r.run('tint color="#5fffaf" amount=140')
r.pause(1.0)
# Nudge the other pane's fuse, get the focus away, and let it ring.
panes = r.api("panes")["panes"]
other = next(p for p in panes if not p.get("focused"))
prev = next(p for p in panes if p.get("focused"))
r.api("focus", id=other["id"])
r.capture(dt=0.4)
r.send("\n", dt=0.2)
r.api("focus", id=prev["id"])
r.capture(dt=0.3)
r.wall(1.6) # real time: the fuse burns, the bell rings unfocused
r.pause(3.0) # the flash animates on the session's own deadline clock
r.save(out_path("shaders"), tail=2.0)
shutil.rmtree(work)
|