Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active September 8, 2017 20:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JoshCheek/1e2824f1270da94fe50881d4f39ef98a to your computer and use it in GitHub Desktop.
Save JoshCheek/1e2824f1270da94fe50881d4f39ef98a to your computer and use it in GitHub Desktop.
Coffee and Cream
# Video: https://twitter.com/josh_cheek/status/832215561841033216
# Related: https://gist.github.com/JoshCheek/445fb5cda04b579305c59350fe0c1ca7
#
# You might need to already understand how bezier curves work to understand this.
# This one is probably a reasonable way to explore it:
# https://gist.github.com/JoshCheek/9139ff5f2764493a69675268e5e9556d
require "graphics"
class CoffeeAndCream < Graphics::Simulation
# I should soooo make one called "fruit flies ponder a pond where the bg is
# like [10, 21, 36], and there is a circle at the end of the bezier
CLEAR_COLOR = [36, 30, 10]
def initialize
super 800, 450, 24
@points = 200.times.map { rand_point }
@delayed_draw = []
color.default_proc = -> h, k { k } # so we don't have to rely on named colours
end
def draw(ticks)
# return if ticks % 2 == 0 # slow it down a bit
clear
# randomly swap out some of the points so the lines change across frames
rand(20).times do
idx = rand(@points.length)
@points[idx] = rand_point
end
end_clip = (@points.length*0.4).to_i
num_frames = @points.length-end_clip
color = [rand(255), rand(255), rand(255)]
color = [255, 255, 255]
if ticks % 40 == 1
points = @points
num_frames.times do |i|
(i.zero? ? end_clip : 1).times do
points = percentages_between points, 0.5
end
# since `points` changes across iterations
crnt_points = points
# place it backwards since each iteration we run it through another time
# each time through will cause it to lose one point, so by the time we
# get to the beginning, it's just 1 point long, then as it goes forwards
# it gets longer and longer
(@delayed_draw[num_frames-i] ||= []) << lambda do
# invert the percentage since we're drawing them backwards
crnt_clr = dim(color, 1-i.to_f/num_frames)
draw_lines_between crnt_points, crnt_clr
draw_lines_between crnt_points.map { |x, y| [x+1, y] }, crnt_clr
draw_lines_between crnt_points.map { |x, y| [x, y+1] }, crnt_clr
draw_lines_between crnt_points.map { |x, y| [x+2, y] }, crnt_clr
draw_lines_between crnt_points.map { |x, y| [x, y+2] }, crnt_clr
end
end
end
(@delayed_draw.shift||[]).each(&:call)
end
def white
@white ||= [255, 255, 255]
end
def dim((r, g, b), percent)
end_r, end_g, end_b = CLEAR_COLOR
[ r + (end_r-r)*percent,
g + (end_g-g)*percent,
b + (end_b-b)*percent,
]
end
def draw_lines_between(points, color)
points.each_cons 2 do |(x1, y1), (x2, y2)|
line x1, y1, x2, y2, color
end
end
# feels like if I think about calculus for a little bit, I might be able to
# come up with an equation for htis so that we don't have to repeatedly invoke it
def percentages_between(points, percent)
points.each_cons(2).map do |(x1, y1), (x2, y2)|
[x1+(x2-x1)*percent, y1+(y2-y1)*percent]
end
end
def rand_point
[rand(5*w)-2*w, rand(5*h)-2*h]
end
end
CoffeeAndCream.new.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment