Create folders for example programs

pull/2/head
Andreas Gysin 2020-09-25 12:00:20 +02:00
rodzic 8230941dc0
commit bb3605d02b
32 zmienionych plików z 691 dodań i 176 usunięć

Wyświetl plik

@ -49,7 +49,7 @@ export function mix(v1, v2, a){
}
// GLSL step
function step(edge, x) {
export function step(edge, x) {
return (x < edge ? 0 : 1)
}
@ -67,7 +67,7 @@ export function smootherstep(edge0, edge1, t) {
}
// GLSL modulo
function mod(a, b) {
export function mod(a, b) {
return a % b
}

Wyświetl plik

@ -1,8 +1,10 @@
#!/bin/zsh
#!/bin/bash
# Script to replace the [header] string of each .js script
# with the contents of the file 'header.txt'.
# Expects a valid path for the output of the files.
#
# > sh ./addheader.sh output_folder
if [ -z $1 ]; then
echo "Please specify an output folder."
@ -20,18 +22,29 @@ if [[ $SCRIPT_PATH -ef $TARGET_PATH ]]; then
exit 1
fi
mkdir -p $TARGET_PATH
RED='\033[0;31m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
NC='\033[0m'
echo "${PURPLE}Writing headers...${NC}"
cd $SCRIPT_PATH
EXPR_1="/\[header\]/r header.txt" # Insert the contents of _header.txt after [header]
EXPR_2="/\[header\]/d" # Delete the line with [header]
for f in ./*.js; do
P=$(echo $TARGET_PATH/$f | sed 's/\/.\//\//g') # prettier output
echo "Writing $P..."
sed -e "$EXPR_1" -e "$EXPR_2" "$f" > "$TARGET_PATH/$f"
done
for folder in `find ./ -mindepth 1 -type d`; do
# echo "creating $TARGET_PATH/$folder..."
mkdir -p $TARGET_PATH/$folder
for file in ./$folder/*.js; do
P=$(echo $file | sed 's/\.\///g') # prettier output
echo "Writing $P..."
sed -e "$EXPR_1" -e "$EXPR_2" "$file" > "$TARGET_PATH/$file"
done
done
echo "${PURPLE}...done!${NC}"
# Restore folder
cd $CURRENT_PATH

Wyświetl plik

@ -0,0 +1,17 @@
/**
@author No1
@title xy coordinates
@desc The smallest program possible?
[header]
*/
export function main(coord){
return String.fromCharCode((coord.y + coord.x) % 32 + 65)
}
import { drawInfo } from '/src/modules/drawbox.js'
export function post(context, cursor, buffers){
drawInfo(context, cursor, buffers, {
color : 'white', background : 'blue', shadowStyle : 'gray'
})
}

Wyświetl plik

@ -0,0 +1,17 @@
/**
@author No1
@title Simple output
@desc The smallest program possible?
[header]
*/
export function main(coord, context, cursor){
return '?'
}
import { drawInfo } from '/src/modules/drawbox.js'
export function post(context, cursor, buffers){
drawInfo(context, cursor, buffers, {
color : 'white', background : 'blue', shadowStyle : 'gray'
})
}

Wyświetl plik

@ -0,0 +1,21 @@
/**
@author No1
@title Simple output
@desc The smallest program possible?
[header]
*/
export function main(coord, context){
// Time can be measured in frames or in milliseconds
// const t = context.time * 0.01
const f = context.frame
return String.fromCharCode((coord.y + coord.x + f) % 32 + 65)
}
import { drawInfo } from '/src/modules/drawbox.js'
export function post(context, cursor, buffers){
drawInfo(context, cursor, buffers, {
color : 'white', background : 'blue', shadowStyle : 'gray'
})
}

Wyświetl plik

@ -1,60 +0,0 @@
/**
@author No1
@title Chroma Spiral
[header]
*/
import { map } from '/src/modules/num.js'
import { sort } from '/src/modules/sort.js'
import { vec2, rot, add, mulN, addN, subN, length } from '/src/modules/vec2.js'
const chars = '#Wabc:+-. '.split('')
const colors = ['deeppink', 'black', 'red', 'blue', 'orange', 'yellow']
export function main(coord, context, cursor, buffers){
const t = context.time * 0.0002
const a = Math.min(context.cols, context.rows)
const st = {
x : 2.0 * (coord.x - context.cols / 2) / a * context.aspect,
y : 2.0 * (coord.y - context.rows / 2) / a
}
for (let i=0;i<3;i++) {
subN(st, 0.5 + i * 0.005, st)
const o = i * 3.0
const v = vec2(Math.sin(t * 3.0 + o), Math.cos(t * 2.0 + o))
add(st, v, st)
mulN(st, Math.cos(t * 0.1), st)
addN(st, 0.5 - i*0.005, st)
const ang = -t + length(subN(st, 0.2))
subN(st, 0.5, st)
rot(st, ang, st)
addN(st, 0.5, st)
}
mulN(st, 0.6, st)
const s = Math.cos(t*1.0) * 2.0;
let c = Math.sin(st.x * 3.0 + s) + Math.sin(st.y * 21)
c = map(Math.sin(c * 0.5), -1, 1, 0, 1)
addN(st, 0.1 + t * 0.1, st);
c = Math.sin(st.x * 3.0 + s) + Math.sin(st.y * 21)
c = map(Math.sin(c * 0.5), -1, 1, 0, 1)
const index = Math.floor(c * (chars.length - 1))
const color = Math.floor(c * (colors.length - 1))
return {
// char : (coord.x + coord.y) % 2 ? chars[index] : '╲',
char : chars[index],
color : colors[color],
}
}
import { drawInfo } from '/src/modules/drawbox.js'
export function post(context, cursor, buffers){
drawInfo(context, cursor, buffers)
}

Wyświetl plik

@ -0,0 +1,36 @@
/**
@author Eliza
@title Color Waves
*/
const chars = "¯\_(ツ)_/¯.::.ᕦ(ò_óˇ)ᕤ ".split('')
export function main(coord, context, cursor, buffers){
const t = context.time * 0.0001
const x = coord.x
const y = coord.y
const a = Math.cos(y * Math.cos(t) * 0.2 + x * 0.04 + t);
const b = Math.sin(x * Math.sin(t) * 0.2 * y * 0.04 + t);
const c = Math.cos(y * Math.cos(t) * 0.2 + x * 0.04 + t);
const o = a + b + c * 20;
const colors = ['mediumvioletred', 'gold', 'orange', 'chartreuse', 'blueviolet', 'deeppink'];
const i = Math.round(Math.abs(x / 10 + y + o / 5)) % chars.length
return {
char : chars[i],
color : colors[i % colors.length],
background : 'white',
weight : '700',
}
}
import { drawInfo } from "/src/modules/drawbox.js"
export function post(context, cursor, buffers){
drawInfo(context, cursor, buffers)
}

Wyświetl plik

@ -0,0 +1,117 @@
/**
@author nkint
@title EQUAL TEA TALK, #65
@desc Inspired by Frederick Hammersley 1969
see http://www.hammersleyfoundation.org/index.php/artwork/computer-drawings/184-computer-drawings/331-equal-tea-talk
*/
import { map, step, mod } from "/src/modules/num.js"
import { vec2, mul, fract as fract2 } from "/src/modules/vec2.js"
const chars = "#BEFTI_".split('')
const wx = new Array(50).fill(0).map((_, i) => i);
const sumW = (n) => (n * 2 + 3) * 5
const getW = (cols) => {
let w = 0
for(let _wx of wx) {
const s = sumW(_wx)
if (cols <= s) {
break;
}
w = s;
}
return w
}
const blank = {
char : ' ',
color : 'black',
background : 'white',
weight : '100',
}
export function main(coord, context, cursor, buffers){
const t = context.time * 0.0001
// compute resolution to fit geometry, not the screen
// 🙏thanks andreas
let w = getW(context.cols);
// show blank if the resolution is too small
if(context.cols <= sumW(1)) {
return blank
}
// clamp the space to the resolution
if(coord.x >= w) {
return blank
}
// ----------------------------- st space
// -----------------------------
// -----------------------------
const st = {
x : (coord.x / w),
y : (coord.y / context.rows),
}
const _st = mul(st, vec2(5.0, 1.0));
const tileIndex = step(1, mod(_st.x, 2.0));
// make each cell between 0.0 - 1.0
// see Truchet Tiles from https://thebookofshaders.com/09/
// for reference/inspiration
const __st = fract2(_st);
const color = tileIndex === 0 ? (_st.y) : (1 - _st.y);
const i = Math.floor(
map(
color,
0, 1,
0, chars.length - 1
)
);
let char = chars[i];
// ----------------------------- pixel space
// -----------------------------
// -----------------------------
const unit = w / 5
const middle = Math.floor(unit/2) - 1;
const xPx = coord.x % unit
const isFirstOrLast = xPx !==0 && xPx !== unit
if(
isFirstOrLast &&
(((xPx) === middle) || ((xPx) === middle + 2))
) {
char = ' '
}
if(
isFirstOrLast &&
(xPx) === middle + 1
) {
char = '-'
}
// some debug utils
// throw new Error('dudee')
// if(coord.x === 0) { console.log() }
return {
char : char,
color : 'black',
background : 'white',
weight : '100',
}
}
import { drawInfo } from "/src/modules/drawbox.js"
export function post(context, cursor, buffers){
//drawInfo(context, cursor, buffers)
//console.log(JSON.stringify(buffers))
}

Wyświetl plik

@ -0,0 +1,61 @@
/**
@author nkint
@title oeö
@desc Inspired by Ernst Jandl, 1964, oeö
*/
import {dist, vec2, length, add, mulN} from '/src/modules/vec2.js'
import {map, smoothstep} from '/src/modules/num.js';
const {PI, atan2, floor, cos, max} = Math;
function polygon(center, edges, time) {
time = time || 0
// from https://observablehq.com/@riccardoscalco/draw-regular-polygons-by-means-of-functions
const p = center;
const N = edges;
const a = (atan2(p.x, p.y) + 2 + time * PI) / (2. * PI);
const b = (floor(a * N) + 0.5) / N;
const c = length(p) * cos((a - b) * 2. * PI);
return smoothstep(0.3, 0.31, c);
}
export function main(coord, context, cursor, buffers){
const a = max(context.cols, context.rows)
const st = {
x : 2.0 * (coord.x - context.cols / 2) / a,
y : 2.0 * (coord.y - context.rows / 2) / a / context.aspect,
}
const centerT = add(
st,
vec2(0, cos(context.time * 0.0021) * 0.5)
);
const colorT = polygon(centerT, 3, context.time * 0.0002)
const triangle = colorT <= 0.1 ? 1 : 0
const centerQ = add(
st,
vec2(cos(context.time * 0.0023) * 0.5, 0)
);
const colorQ = polygon(centerQ, 4, -context.time * 0.0004)
const quadrato = colorQ <= 0.1 ? 2 : 0
const i = triangle + quadrato;
const chars = [' ', 'e', 'o', 'ö']
const colors = ['white', '#527EA8', '#BB2A1C', '#DFA636']
return {
char : chars[i],
color : colors[i],
background : 'white',
weight : '100',
}
}
import { drawInfo } from "/src/modules/drawbox.js"
export function post(context, cursor, buffers){
drawInfo(context, cursor, buffers)
}

Wyświetl plik

@ -0,0 +1,64 @@
/**
@author Alex Miller
@title Game of Life
@desc Conway's Game of Life
see https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
Each frame of the animation depends on the previous frame. Code in the `pre()`
function saves the previous frame so it can be used in `main()`.
*/
import { dist, sub } from "/src/modules/vec2.js"
let prevFrame;
let initialized = false;
let width, height;
export function pre(context, cursor, buffers) {
if (!initialized) {
for (let i = 0; i < buffers.length; i++) {
buffers.state[i] = {char : Math.random() > 0.5 ? "▒" : " "};
}
initialized = true;
width = context.cols;
height = context.rows;
}
// Use the spread operator to copy the previous frame
// You must make a copy, otherwise `prevFrame` will be updated prematurely
prevFrame = [...(buffers.state)];
}
export function main(coord, context, cursor, buffers) {
if (cursor.pressed) {
if (dist(coord, cursor) < 3) {
return Math.random() > 0.5 ? "▒" : " ";
}
}
const { x, y } = coord;
const neighbors =
get(x - 1, y - 1) +
get(x, y - 1) +
get(x + 1, y - 1) +
get(x - 1, y) +
get(x + 1, y) +
get(x - 1, y + 1) +
get(x, y + 1) +
get(x + 1, y + 1);
const current = get(x, y);
if (current == 1) {
return neighbors == 2 || neighbors == 3 ? "▒" : " ";
} else if (current == 0) {
return neighbors == 3 ? "x" : " ";
}
}
function get(x, y) {
if (x < 0 || x >= width) return 0;
if (y < 0 || y >= height) return 0;
const index = y * width + x;
return prevFrame[index].char === " " ? 0 : 1
}

Wyświetl plik

@ -0,0 +1,112 @@
/**
@author Alex Miller
@title Pathfinder
@desc Click to spawn new path segments
*/
import { dist, sub } from "/src/modules/vec2.js"
import * as v2 from '/src/modules/vec2.js'
const vec2 = v2.vec2
let prevFrame;
let initialized = false;
let width, height;
const colors = [
'red',
'orange',
'yellow',
'green',
'blue',
'indigo',
'violet'
];
export const settings = {
fps : 30, // fps capping
background : '#000000', // background color of the container element
}
const roads = '┃━┏┓┗┛┣┫┳┻╋';
export function pre(context, cursor, buffers) {
if (!initialized && buffers.length > 0) {
for (let i = 0; i < buffers.length; i++) {
buffers.state[i] = Math.random() < 0.001 ? {
char: choose(roads),
color: 'white'
} : ' ';
}
initialized = true;
width = context.cols;
height = context.rows;
}
// Use the spread operator to copy the previous frame
// You must make a copy, otherwise `prevFrame` will be updated prematurely
prevFrame = [...buffers.state];
}
function choose(list) {
return list.charAt(Math.floor(Math.random() * list.length))
}
export function main(coord, context, cursor, buffers) {
const {x, y} = coord;
if (cursor.pressed &&
Math.floor(cursor.x) == x &&
Math.floor(cursor.y) == y &&
get(x, y) == ' ') {
return {
char: choose(roads),
color: 'white'
};
}
const last = get(x, y);
// '┃ ━ ┏ ┓ ┗ ┛ ┣ ┫ ┳ ┻ ╋';
if (last == ' ') {
let char = ' '
const top = get(x, y - 1);
const bottom = get(x, y + 1);
const left = get(x - 1, y);
const right = get(x + 1, y);
if ('┃┫┣╋┏┓┳'.includes(top)) {
char = choose('┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┗┫┣┻╋');
} else if ('┃┗┛┣┫┻╋'.includes(bottom)) {
char = choose('┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┏┓┣┫┳╋');
} else if ('━┏┗┣┳┻╋'.includes(left)) {
char = choose('━━━━━━━━━━━━━━━━━━━━┓┛┫┳┻╋');
} else if ('━┓┛┫┳┻╋'.includes(right)) {
char = choose('━━━━━━━━━━━━━━━━━━━━┏┗┣┳┻╋');
}
return {
char,
color: 'white'
};
}
return {
char: last,
color: 'white'
};
}
function get(x, y) {
if (x < 0 || x >= width) return 0;
if (y < 0 || y >= height) return 0;
const index = y * width + x;
return prevFrame[index].char;
}

Wyświetl plik

@ -0,0 +1,128 @@
/**
@author Alex Miller
@title Sand game
@desc Click to drop sand
*/
import { dist, sub } from "/src/modules/vec2.js"
let prevFrame;
let initialized = false;
let width, height;
function newParticle() {
return "sand".charAt(Math.random() * 4)
}
export function pre(context, cursor, buffers) {
if (!initialized) {
for (let i = 0; i < buffers.length; i++) {
buffers.state[i] = {char : Math.random() > 0.5 ? newParticle() : " "};
}
initialized = true;
width = context.cols;
height = context.rows;
}
// Use the spread operator to copy the previous frame
// You must make a copy, otherwise `prevFrame` will be updated prematurely
prevFrame = [...buffers.state];
}
export function main(coord, context, cursor, buffers) {
if (cursor.pressed) {
if (dist(coord, cursor) < 3) {
return {
char: Math.random() > 0.5 ? newParticle() : " ",
background: 'white',
color: 'rgb(179, 158, 124)',
weight: 500
}
}
}
const { x, y } = coord;
const me = get(x, y);
const below = get(x, y + 1);
const above = get(x, y - 1);
const left = get(x - 1, y);
const right = get(x + 1, y);
const topleft = get(x - 1, y - 1);
const topright = get(x + 1, y - 1);
const bottomleft = get(x - 1, y + 1);
const bottomright = get(x + 1, y + 1);
const frame = context.frame;
if (y >= context.rows - 1) {
return {
char: 'GROUND_'.charAt(x % 7),
background: 'rgb(138, 162, 70)',
color: 'rgb(211, 231, 151)',
weight: 900
}
}
if (x >= context.cols - 1 || x <= 0) {
return {
char: 'WALL'.charAt(y % 4),
background: 'rgb(247, 187, 39)',
color: 'white',
weight: 900
}
}
let char = ' '
if (alive(me)) {
if (alive(below) &&
((frame % 2 == 0 && alive(bottomright)) ||
(frame % 2 == 1 && alive(bottomleft)))) {
char = me;
} else {
char = ' ';
}
} else {
if (alive(above)) {
char = above;
} else if (alive(left) && frame % 2 == 0 && alive(topleft)) {
char = topleft;
} else if (alive(right) && frame % 2 == 1 && alive(topright)) {
char = topright;
} else {
char = ' ';
}
if ('WALL'.indexOf(char) > -1) {
char = ' ';
}
}
return {
char,
background: 'white',
color: 'rgb(179, 158, 124)',
weight: 500
}
}
function alive(char) {
return char != ' ';
}
function get(x, y) {
if (x < 0 || x >= width) return 0;
if (y < 0 || y >= height) return 0;
const index = y * width + x;
return prevFrame[index].char;
}

Wyświetl plik

@ -0,0 +1,41 @@
/**
@author Raurir
@title Stacked sin waves
noob at frag shaders.
*/
const chars = '█▓▒░ '.split('')
import { map } from '/src/modules/num.js'
export function main(coord, context, cursor, buffers){
const t = context.time * 0.002
const x = coord.x
const y = coord.y
const v0 = context.cols / 4 + wave(t, y, [0.15, 0.13, 0.37], [10,8,5]) * 0.9;
const v1 = v0 + wave(t, y, [0.12, 0.14, 0.27], [3,6,5]) * 0.8;
const v2 = v1 + wave(t, y, [0.089, 0.023, 0.217], [2,4,2]) * 0.3;
const v3 = v2 + wave(t, y, [0.167, 0.054, 0.147], [4,6,7]) * 0.4;
const i = x > v3 ? 4
: x > v2 ? 3
: x > v1 ? 2
: x > v0 ? 1
: 0;
const r = map(Math.sin(t + y * 0.1), -1.5, 1, 0x11, 0xff)
return {
char : chars[i],
color : `#0000${Math.round(r).toString(16)}`,
background : 'black'
}
}
function wave(t, y, seeds, amps) {
return (
(Math.sin(t + y * seeds[0]) + 1) * amps[0]
+ (Math.sin(t + y * seeds[1]) + 1) * amps[1]
+ (Math.sin(t + y * seeds[2])) * amps[2]
)
}

Wyświetl plik

@ -0,0 +1,54 @@
#!/bin/bash
# Script to generate a list of all the projects
SCRIPT_PATH=${0%/*} # path to this script
URL_PREFIX='/#/src'
# All folders
#FOLDERS=`find ./ -mindepth 1 -type d`
# Odered list of folders
FOLDERS=(basics sdf demos camera contributed)
for folder in ${FOLDERS[@]}; do
FIRST=1
for file in $SCRIPT_PATH/$folder/*.js; do
URL=$URL_PREFIX$(echo $file | sed -e 's/\.\///g' -e 's/\.js//g')
AUTHOR=$(sed -En 's/^@author[ \t](.*)$/\1/p' $file)
TITLE=$(sed -En 's/^@title[ \t](.*)$/\1/p' $file)
DESC=$(sed -En 's/^@desc[ \t](.*)$/\1/p' $file)
if [[ $FIRST == 1 ]]; then
FOLDER=$(echo $folder | sed -e 's/\.\///g' -e 's/\///g' -e 's/\.js//g' )
FIRST=0
printf "\t"
printf "<div>"
printf "$FOLDER"
printf "</div>"
printf "\n"
else
printf "\t"
printf "<div>"
printf "</div>"
printf "\n"
fi
printf "\t"
printf "<div>"
printf "<a target='_blank' href='$URL'>$TITLE</a>"
printf "</div>"
printf "\n"
printf "\t"
printf "<div>"
printf "$DESC"
printf "</div>"
printf "\n"
done
done

Wyświetl plik

@ -1,50 +0,0 @@
/**
@author No1
@title Sin Sin
@desc inspired by https://www.shadertoy.com/view/MdXGDH
[header]
*/
import {vec2, dot, add, sub, length} from '/src/modules/vec2.js'
import {map} from '/src/modules/num.js'
export const settings = {
fps : 60
}
const {sin, cos, floor, PI} = Math
const chars = '▅▃▁$?01abc+-><:. '.split('')
export function main(coord, context){
const t1 = context.time * 0.0009
const t2 = context.time * 0.0003
const a = Math.min(context.cols, context.rows)
let st = {
x : 2.0 * (coord.x - context.cols / 2) / a * context.aspect,
y : 2.0 * (coord.y - context.rows / 2) / a
}
const center = vec2(sin(-t1), cos(-t1))
const v1 = sin(dot(coord, vec2(sin(t1), cos(t1))) * 0.08)
const v2 = cos(length(sub(st, center)) * 4.0)
const v3 = v1 + v2
const idx = floor(map(v3, -2, 2, 0, 1) * chars.length)
// Colors are quantized for performance:
// lower value = harder gradient, better performance
const quant = 2
const mult = 255 / (quant - 1)
const r = floor(map(cos(v3 + t2), -1, 1, 0, quant)) * mult
const g = floor(map(sin(v3 + t2), -1, 1, 0, quant)) * mult
const b = floor(map(cos(t2), -1, 1, 0, quant)) * mult
return {
char : chars[idx],
color : 'black',
background : `rgb(${r},${g},${b})`,
}
}
import { drawInfo } from "/src/modules/drawbox.js"
export function post(context, cursor, buffers){
drawInfo(context, cursor, buffers)
}

Wyświetl plik

@ -1,56 +0,0 @@
/**
@author No1
@title Wobbly
@desc Draw donuts with SDF
[header]
*/
import { sdCircle } from '/src/modules/sdf.js'
import { sort } from '/src/modules/sort.js'
import { length, dot, rot } from '/src/modules/vec2.js'
import { map, fract, smoothstep } from '/src/modules/num.js'
const chars = sort('▀▄▚▐─═0123.+?'.split(''))
export function main(coord, context, cursor, buffer){
const t = context.time * 0.001
const a = Math.min(context.cols, context.rows)
let st = {
x : 2.0 * (coord.x - context.cols / 2) / a * context.aspect,
y : 2.0 * (coord.y - context.rows / 2) / a
}
st = rot(st, 0.6 * Math.sin(0.62 * t) * length(st) * 2.5)
st = rot(st, t * 0.2)
const s = map(Math.sin(t), -1, 1, 0.5, 1.8)
const pt = {
x : fract(st.x * s) - 0.5,
y : fract(st.y * s) - 0.5
}
const r = 0.5 * Math.sin(0.5 * t + st.x * 0.2) + 0.5
const d = sdCircle(pt, r)
const width = 0.05 + 0.3 * Math.sin(t);
const k = smoothstep(width, width + 0.2, Math.sin(10 * d + t));
const c = (1.0 - Math.exp(-3 * Math.abs(d))) * k
const index = Math.floor(c * (chars.length-1))
return {
char : chars[index],
color : k == 0 ? 'orangered' : 'royalblue',
// background : coord.y % 2 ? 'white' : 'cornsilk'
}
}
import { drawInfo } from '/src/modules/drawbox.js'
export function post(context, cursor, buffers){
drawInfo(context, cursor, buffers, {
color : 'white', background : 'blue', shadowStyle : 'gray'
})
}