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
|
#!/usr/bin/env ruby
require 'tins/go'
include Tins::GO
require 'term/ansicolor'
include Term::ANSIColor
Term::ANSIColor.true_coloring = ENV['COLORTERM'] =~ /\A(truecolor|24bit)\z/
include Math
# Generates a palette of 256 colors based on sine waves
#
# @return [Array<Array<Integer>>] An array of arrays, each containing
# three integers representing the RGB values of a color.
def generate_palette
(0..255).map { |i|
[
128 + 128 * sin(PI * i / 32.0),
128 + 128 * sin(PI * i / 64.0),
128 + 128 * sin(PI * i / 128.0),
].map { _1.clamp(0, 255).round }
}
end
# Resets the terminal to its original state, and assigns width $w and height
# $h.
def full_reset
$w, $h = Tins::Terminal.cols, Tins::Terminal.lines
$h *= 2
print reset, clear_screen, move_home, hide_cursor
end
# Generates a screen based on a plasma.
#
# @param plasma [Array<Array<Integer>>] An array of arrays, each containing
# three integers representing the RGB values of a color.
# @return [String] The string representation of the screen, each character
# representing a pixel on the screen with the corresponding color.
def generate_screen(plasma)
screen = ''
0.step($h - 1, 2) do |y|
0.upto($w - 1) do |x|
screen << color(plasma[y][x]) + on_color(plasma[y + 1][x]) + ?▀
end
end
screen
end
# Generates a plasma generated based on sine waves
#
# @param now [Float] A value based on the current time in seconds
# @return [Array<Array<Integer>>] An array of arrays, each containing
# three integers representing the RGB values of a color.
def generate_plasma(now)
plasma = Array.new($h) { [ nil ] * $w }
0.upto($h - 1) do |y|
0.upto($w - 1) do |x|
x, y = x.to_f, y.to_f
color = (
128.0 + (128.0 * sin((x / 7.0) - 3.0 * cos(now / 2.0))) +
128.0 + (128.0 * sin((y / 13.0) - 2.0 * sin(now))) +
128.0 + (128.0 * sin(hypot((x - $w / 3.0), (y - $h / 2.0)) / 5.0)) +
128.0 + (128.0 * sin((hypot(x, y) / 5.0) - sin(now / 3.0)))
) / 4.0
plasma[y][x] = $palette[(color + now).round % $palette.size]
end
end
plasma
end
$opts = go('n:')
$palette = generate_palette
begin
$full_reset = true
trap(:SIGWINCH) { $full_reset = true }
loop do
if $full_reset
$full_reset = false
full_reset
end
now = Time.now.to_f / ($opts[?n]&.to_f || 1)
plasma = generate_plasma(now)
print move_home, generate_screen(plasma), reset
if n = $opts[?n]&.to_f
sleep n
else
print move_to_column(1), erase_in_line, show_cursor
exit
end
end
rescue Interrupt
print reset, clear_screen, move_home, show_cursor
end
|