Skip to content

Commit df18047

Browse files
authored
examples: add vmatrix.v showing a Matrix like terminal screen effect (#21814)
1 parent 587fb72 commit df18047

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

examples/vmatrix.v

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import os
2+
import rand
3+
import term
4+
import term.termios
5+
import time
6+
7+
const snooze = time.millisecond * 70
8+
const symbols = '0123456789!@#$%^&*()-_=+[]{}|;:,.<>?¡±¥£¶ÿ'
9+
10+
struct RainColumn {
11+
mut:
12+
col int
13+
len int // length of the rain column
14+
head int = 1 // y position of the head of rain column
15+
}
16+
17+
fn main() {
18+
init_terminal()!
19+
rain() // ctrl-c to exit
20+
}
21+
22+
fn rain() {
23+
mut rain_columns := []RainColumn{}
24+
width, height := term.get_terminal_size()
25+
26+
for {
27+
// gradually add more rain columns
28+
if rain_columns.len < width {
29+
rain_columns << random_rain_column(width, height)
30+
}
31+
// update and print all rain columns
32+
for mut rc in rain_columns {
33+
update_rain_column(mut rc, width, height)
34+
print_rain_column(rc, height)
35+
}
36+
time.sleep(snooze)
37+
}
38+
}
39+
40+
fn update_rain_column(mut rc RainColumn, width int, height int) {
41+
rc.head += 1
42+
if rc.head >= height + rc.len + 1 {
43+
rc = random_rain_column(width, height)
44+
}
45+
}
46+
47+
fn random_rain_column(max_col int, max_height int) RainColumn {
48+
return RainColumn{
49+
col: rand.int_in_range(1, max_col + 1) or { 1 }
50+
len: rand.int_in_range(4, max_height / 4 * 3) or { 4 }
51+
}
52+
}
53+
54+
fn print_rain_column(rc RainColumn, height int) {
55+
// print head in white
56+
if rc.head <= height {
57+
print_at(random_symbol(), rc.col, rc.head)
58+
}
59+
// print the char above the head in green to remove
60+
// white color of the previous head. Dim chars
61+
// randomly to add more interest to the effect
62+
if (rc.head - 1) <= height {
63+
symbol := random_dim(term.green(random_symbol()))
64+
print_at(symbol, rc.col, rc.head - 1)
65+
}
66+
// remove tail by printing a space
67+
t := rc.head - rc.len + 1
68+
if t >= 0 && t <= height {
69+
print_at(' ', rc.col, t)
70+
}
71+
}
72+
73+
fn print_at(s string, x int, y int) {
74+
term.set_cursor_position(term.Coord{ x: x, y: y })
75+
print(s)
76+
}
77+
78+
fn random_symbol() string {
79+
idx := rand.int_in_range(0, symbols.len) or { 0 }
80+
return symbols[idx].ascii_str()
81+
}
82+
83+
fn random_dim(s string) string {
84+
i := rand.int_in_range(0, 10) or { 0 }
85+
return if i == 1 { term.dim(s) } else { s }
86+
}
87+
88+
fn init_terminal() ! {
89+
mut old_state := termios.Termios{}
90+
termios.tcgetattr(0, mut old_state)
91+
// restore cursor, exit alternate buffer mode on Ctrl+C
92+
os.signal_opt(os.Signal.int, fn [mut old_state] (sig os.Signal) {
93+
println('\e[?1049l\e[?25h')
94+
termios.set_state(0, old_state)
95+
exit(0)
96+
})!
97+
// turn off cursor, enter alternate buffer mode
98+
print('\e[?1049h\e[?25l')
99+
mut new_state := old_state
100+
new_state.disable_echo()
101+
termios.set_state(0, new_state)
102+
}

0 commit comments

Comments
 (0)