Compare commits

..

5 Commits

Author SHA1 Message Date
annieversary 57044bd9cd 19, 20, 21 2021-09-30 22:05:19 +02:00
annieversary f20a328784 subtitled #18: gay core 2021-09-18 13:50:29 +02:00
annieversary e89291202c subtitled #17: chaikin 2021-09-18 13:49:54 +02:00
annieversary 658093b77f utils 2021-09-18 13:49:13 +02:00
annieversary 8fe1852e55 m 2021-09-10 13:07:31 +02:00
15 changed files with 453 additions and 3 deletions

40
Cargo.lock generated
View File

@ -2422,6 +2422,30 @@ dependencies = [
"utils",
]
[[package]]
name = "subtitled17"
version = "0.1.0"
dependencies = [
"nannou",
"utils",
]
[[package]]
name = "subtitled18"
version = "0.1.0"
dependencies = [
"nannou",
"utils",
]
[[package]]
name = "subtitled19"
version = "0.1.0"
dependencies = [
"nannou",
"utils",
]
[[package]]
name = "subtitled2"
version = "0.1.0"
@ -2430,6 +2454,22 @@ dependencies = [
"utils",
]
[[package]]
name = "subtitled20"
version = "0.1.0"
dependencies = [
"nannou",
"utils",
]
[[package]]
name = "subtitled21"
version = "0.1.0"
dependencies = [
"nannou",
"utils",
]
[[package]]
name = "subtitled3"
version = "0.1.0"

View File

@ -2,6 +2,8 @@ use std::time::Duration;
use nannou::prelude::*;
// https://sighack.com/post/flood-fill-art-using-random-walks
const R: f32 = 2.0;
fn main() {
@ -46,7 +48,7 @@ fn model(_app: &App) -> Model {
}
fn update(app: &App, model: &mut Model, _update: Update) {
for _ in 0..20 {
for _ in 0..50 {
run(app, model)
}
}
@ -100,8 +102,10 @@ fn view(app: &App, model: &Model, frame: Frame) {
.color(hsl(h.fract(), 0.5, 0.5));
}
if frame.nth() < 50 {
// cause otherwise it goes too fast when recording and it can't save the frames in time lmao
std::thread::sleep(Duration::from_millis(5));
}
draw.to_frame(app, &frame).unwrap();
utils::record::record(app, &frame);

View File

@ -0,0 +1,8 @@
[package]
name = "subtitled17"
version = "0.1.0"
edition = "2018"
[dependencies]
nannou = "0.17"
utils = { path = "../utils" }

View File

@ -0,0 +1,54 @@
use nannou::prelude::*;
use utils::{curves::*, drawing::draw_soft_bg, *};
const POINTS: usize = 10;
const SIZE: f32 = 300.0;
fn main() {
nannou::app(model).update(update).simple_window(view).run();
}
struct Model {
curves: Vec<Chaikin>,
}
fn model(_app: &App) -> Model {
let curves = (0..10)
.map(|_| {
Chaikin::new(
(0..POINTS)
.map(|_| vec2_range(-1., 1.) * SIZE)
.collect::<Vec<_>>(),
)
})
.collect();
Model { curves }
}
fn update(app: &App, _model: &mut Model, _update: Update) {
let _t = app.elapsed_frames() as f32 / 60.0;
}
fn view(app: &App, model: &Model, frame: Frame) {
let t = frame.nth() as f32 / 60.0;
let draw = app.draw();
draw_soft_bg(&draw, app, SNOW, 0.01);
for (i, curve) in model.curves.iter().enumerate() {
let div = map_sin(t * 0.7 + (2 * i) as f32, 0.15, 0.35);
let h = map_sin(t * 0.3 + i as f32, 0., 1.);
draw.polyline().stroke_weight(1.5).points_colored(
curve
.points(div, 10)
.into_iter()
.enumerate()
.map(|(i, p)| (p, hsla((h + i as f32 / 10000.0).fract(), 0.5, 0.5, 0.5))),
);
}
draw.to_frame(app, &frame).unwrap();
utils::record::record(app, &frame);
}

View File

@ -0,0 +1,8 @@
[package]
name = "subtitled18"
version = "0.1.0"
edition = "2018"
[dependencies]
nannou = "0.17"
utils = { path = "../utils" }

View File

@ -0,0 +1,52 @@
use nannou::prelude::*;
use utils::{drawing::draw_soft_bg, *};
fn main() {
nannou::app(model).update(update).simple_window(view).run();
}
struct Model {}
fn model(_app: &App) -> Model {
Model {}
}
fn update(app: &App, _model: &mut Model, _update: Update) {
let _t = app.elapsed_frames() as f32 / 60.0;
}
fn view(app: &App, _model: &Model, frame: Frame) {
let t = frame.nth() as f32 / 60.0;
let draw = app.draw();
draw_soft_bg(&draw, app, BLACK, 1.0);
let count = 10;
for a in 0..360 {
for i in 1..=count {
let a = a as f32;
let fi = i as f32;
let r = 1500.0 * (t + 0.01 * a + fi).cos();
let r = r.powf(0.9 * fi / count as f32);
// alternate directions of spin for each layer
let s = if i % 2 == 0 { 1.0 } else { -1.0 } * map_sin(a * fi * fi, 0.1, 1.0);
let p = r * (s * t + fi + a).sin_cos().to_vec2();
// jitter
let p = p + map_sin(t * 0.3 + TAU * 0.75, 0., 7.0) * vec2_circ();
let sat = map_sin(t * 0.3 + TAU * 0.75, 0.4, 0.9);
let r = map_range(r, 0., 500.0, 0.5, 13.0).sqrt();
draw.ellipse()
.radius(r)
.xy(p)
.color(hsl(a / 360.0, sat, 0.5));
}
}
draw.to_frame(app, &frame).unwrap();
utils::record::record(app, &frame);
}

View File

@ -0,0 +1,8 @@
[package]
name = "subtitled19"
version = "0.1.0"
edition = "2018"
[dependencies]
nannou = "0.17"
utils = { path = "../utils" }

View File

@ -0,0 +1,66 @@
use nannou::prelude::*;
use utils::{drawing::draw_soft_bg, *};
fn main() {
nannou::app(model).update(update).simple_window(view).run();
}
struct Walker {
pos: Vec2,
vel: Vec2,
color: f32,
}
struct Model {
walkers: Vec<Walker>,
}
fn model(_app: &App) -> Model {
Model {
walkers: (0..100)
.map(|_| Walker {
pos: Vec2::ZERO,
vel: Vec2::ZERO,
color: random_range(0.0, 1.0),
})
.collect(),
}
}
fn update(app: &App, model: &mut Model, _update: Update) {
let _t = app.elapsed_frames() as f32 / 60.0;
for walker in &mut model.walkers {
walker.vel += vec2_range(-2.0, 1.0);
walker.vel = walker.vel.normalize();
walker.pos += walker.vel;
// wrap around the box
const SIZE: f32 = 100.0;
if walker.pos.x.abs() > SIZE {
walker.pos.x = -walker.pos.x;
}
if walker.pos.y.abs() > SIZE {
walker.pos.y = -walker.pos.y;
}
}
}
fn view(app: &App, model: &Model, frame: Frame) {
let t = frame.nth() as f32 / 60.0;
let draw = app.draw();
draw_soft_bg(&draw, app, SNOW, 0.01);
for walker in &model.walkers {
let h = (t * 10.0 + walker.color * 50.0) / 360.0;
draw.ellipse()
.xy(walker.pos)
.radius(1.0)
.color(hsl(h.fract(), 0.7, 0.5));
}
draw.to_frame(app, &frame).unwrap();
utils::record::record(app, &frame);
}

View File

@ -0,0 +1,8 @@
[package]
name = "subtitled20"
version = "0.1.0"
edition = "2018"
[dependencies]
nannou = "0.17"
utils = { path = "../utils" }

View File

@ -0,0 +1,60 @@
use nannou::prelude::*;
use utils::*;
// based on https://nbickford.wordpress.com/2011/04/03/the-minsky-circle-algorithm/
fn main() {
nannou::app(model).update(update).simple_window(view).run();
}
struct Model {
points: Vec<Vec2>,
base_hue: f32,
}
fn model(_app: &App) -> Model {
Model {
points: (0..1000).map(|_| Vec2::ONE * 6.0).collect(),
base_hue: 0.0,
}
}
fn advance(mut point: Vec2, t: f32) -> Vec2 {
let d = map_sin(t * 1.1, 0.01, 0.12);
let e = (t.sqrt() * 0.01 + 0.3).min(1.1);
point.x -= (point.y * d).floor();
point.y += (point.x * e).floor();
point
}
fn update(app: &App, model: &mut Model, _update: Update) {
let t = app.elapsed_frames() as f32 / 60.0;
// advance all points in list
let mut last = model.points.last().unwrap().clone();
for v in &mut model.points {
last = advance(last, t);
*v = last;
}
// move base_hue
model.base_hue += random::<f32>();
}
fn view(app: &App, model: &Model, frame: Frame) {
let t = frame.nth() as f32 / 60.0;
let draw = app.draw();
drawing::draw_soft_bg(&draw, app, BLACK, 0.01);
for &p in &model.points {
let h = random_range(model.base_hue, model.base_hue + 60.0) / 360.0;
draw.ellipse()
.radius(map_sin(p.x.powi(3) + p.y.powi(7) + t * 0.1, 1.0, 3.0))
.xy(p * 7.0)
.color(hsla(h.fract(), 1.0, 0.5, 0.1));
}
draw.to_frame(app, &frame).unwrap();
utils::record::record(app, &frame);
}

View File

@ -0,0 +1,8 @@
[package]
name = "subtitled21"
version = "0.1.0"
edition = "2018"
[dependencies]
nannou = "0.17"
utils = { path = "../utils" }

View File

@ -0,0 +1,97 @@
use nannou::prelude::*;
// use utils::*;
// from https://fabiensanglard.net/doom_fire_psx/
fn main() {
nannou::app(model)
.update(update)
.simple_window(view)
.size(800, 800)
.run();
}
struct Model {}
const BALL_SIZE: f32 = 3.0;
fn model(_app: &App) -> Model {
Model {}
}
fn update(app: &App, _model: &mut Model, _update: Update) {
let _t = app.elapsed_frames() as f32 / 60.0;
}
fn shader(i: usize, j: usize, w: usize, h: usize, t: f32) -> Rgb {
let x = i as f32 / w as f32;
let y = j as f32 / h as f32;
let pos = vec2(x, y);
// srgb(pos.x, pos.y, 0.0)
// let a = (pos - vec2(0.5, 0.5)).length();
// srgb(a, a, a)
creation(pos, t)
}
fn creation(pos: Vec2, t: f32) -> Rgb {
let mut l = t;
let mut z = t;
let mut c = [0.0; 3];
for i in 0..3 {
let mut uv = pos;
let mut p = pos;
p -= Vec2::splat(0.5);
z += 0.07;
l = p.length();
uv += p / l * (z.sin() + 1.) * abs((l * 9. - z * 2.).sin());
c[i] = 0.01 / ((vec2(uv.x.fract(), uv.y.fract()) - Vec2::splat(0.5)).abs()).length();
}
srgb(c[0] / l, c[1] / l, c[2] / l)
}
fn view(app: &App, _model: &Model, frame: Frame) {
let t = frame.nth() as f32 / 120.0;
let draw = app.draw();
draw.background().color(BLACK);
let (l, top, w, h) = app.window_rect().l_t_w_h();
let cols = (w / BALL_SIZE) as usize;
let rows = (h / BALL_SIZE) as usize;
for i in 0..cols {
for j in 0..rows {
let x = l + j as f32 * BALL_SIZE;
let y = top - i as f32 * BALL_SIZE;
let p = vec2(x, y)
+ (t * 0.4).min(5.0)
* 10.0
* vec2(
(t * 0.7 + (i * j) as f32).sin(),
(t * 0.9 + (2 * i * j) as f32).cos(),
);
let color = shader(i, j, cols, rows, t);
draw.quad()
.points(
p + BALL_SIZE * vec2(1., 1.),
p + BALL_SIZE * vec2(1., -1.),
p + BALL_SIZE * vec2(-1., -1.),
p + BALL_SIZE * vec2(-1., 1.),
)
.xy(p)
.color(color);
}
}
draw.to_frame(app, &frame).unwrap();
utils::record::record(app, &frame);
}

View File

@ -0,0 +1,31 @@
use nannou::prelude::*;
pub struct Chaikin {
pub points: Vec<Vec2>,
}
impl Chaikin {
pub fn new(points: Vec<Vec2>) -> Self {
Self { points }
}
pub fn points(&self, div: f32, n: usize) -> Vec<Vec2> {
let mut points = self.points.clone();
for _ in 0..n {
let first = *points.first().unwrap();
let last = *points.last().unwrap();
points = points
.windows(2)
.flat_map(|p| {
let a = p[0];
let b = p[1];
[a + div * (b - a), a + (1.0 - div) * (b - a)]
})
.collect();
points.insert(0, first);
points.push(last);
}
points
}
}

View File

@ -1,4 +1,5 @@
pub mod color;
pub mod curves;
pub mod drawing;
pub mod record;
pub mod sequences;
@ -49,3 +50,7 @@ pub fn vec2_range(min: f32, max: f32) -> Vec2 {
pub fn ivec2_range(min: i32, max: i32) -> IVec2 {
ivec2(random_range(min, max), random_range(min, max))
}
/// returns a random vector in the unit circle
pub fn vec2_circ() -> Vec2 {
random_range(0., TAU).sin_cos().into()
}

View File

@ -8,6 +8,7 @@ if [[ -z $1 ]]; then
echo -e "\t$0 packagename"
else
rm -rf "recordings/$1/frames"
mkdir -p "recordings/$1/videos"
cargo run --release --package $1 -- -record
filename="video$(( $(find recordings/$1/videos -type f -exec basename -s .mp4 {} \; | sed 's/^video//' | sort -n | tail -n1) + 1)).mp4"
ffmpeg -framerate 60 -i "recordings/$1/frames/%03d.png" -pix_fmt yuv420p "recordings/$1/videos/$filename"