plasma
[github]soft interference blobs drifting and pulsing
generative 64×22 24 fps 1.9 kB
,,.,-~:;=++*##%%@@@@@@%%%#**+==;:~~-,...,,--~~~:::::::::::~~~--, ..,-~:;=+*#%@@@@@@%@@@@@@%%#**+=;;:~--,....,,,-------------,,,.. .,-:;=+*#%@@@%%%####%%%@@@%%#*++=;::~--,,......,,,,,,,,,........ ,~:;=+*#%@@%%########%%@@@%%#*++=;::~--,,..................,,,,, -:;=+*#%@@%###****###%%@@@%#*++=;::~--,,..............,,,,,----- ~:=+*#%@@%%###**###%%@@@%%#*+=;;:~--,,...............,,,----~~~~ ~;=+*#%@@%%######%%@@@%%#*+==;:~--,....,,,,,,,,,.....,,,---~~~~: :;=+*#%@@@%%%%%%@@@@%%#*+==;:~-,,...,,---~~~~---,,....,,,--~~~~: ~;=+*#%%@@@@@@@@@%%##*+=;;:~-,...,--~~:::::::::~~--,....,,--~~~~ ~:;=+*#%%%@@@%%%##*++=;::~-,...,-~~:;;;=======;;::~--,...,,---~~ -~;=++*########**+==;:~~-,...,--~:;;=+++******++=;;:~--,...,,--- -~:;==++*****++==;;:~~-,,..,,-~~:;==+**##%%%###**+=;;:~-,...,,,- ,-~:;;==++++==;;::~~-,,...,,--~:;;=+*##%%@@@@@%%#**+=;:~-,,...,, .,-~::;;===;;;::~~-,,....,,--~~:;==+*#%@@@@@@@@@%%#*+=;:~--,.... .,--~::;;;;:::~~--,....,,,---~~~:;=*#%@@@%%%%%@@@@%#*+=;:~--,... ..,-~~:::::::~~--,,...,,,---~~~~:;+*#%@@%%%##%%@@@%#*+=;;:~-,,.. ..,--~~:::::~~~-,,....,,--~~~~::;=+*#@@@%%####%%@@%%#*+=;:~--,,. ..,--~~::::::~~--,,...,,--~~::;;=+*#%@@@%%###%%@@@%#**+=;:~--,,. ..,-~~:::;;:::~~--,....,--~~:;;=+**#%@@@%%%%%%@@@%%#*+=;:~~-,,,. ..,-~::;;;;;;;::~~-,,...,--~::;=+**#%%@@@@@@@@@@%%#*+=;;:~--,,.. .,-~::;========;;:~~-,,..,,-~:;;=+**##%%@@@@@%%##**+=;::~--,,... .,-~:;=+++***+++==;::~-,,..,--~:;==+***#######**++=;;:~~-,,.....%%@%#*+=;::~--,,......,,,-~~:;;=+**#%@@@%%##***+++++++++++***##% @@%#*+=;:~-,......,......,,-~~:;==+*##%@@@@%%%#############%%%@@ @%#+=;:~-,...,,,----,,,...,,-~::;=++*##%%@@@@@@%%%%%%%%%@@@@@@@@ %*+=;:~-,..,,--------,,...,,-~::;=++*##%%@@@@@@@@@@@@@@@@@@%%%%% #+=;:~-,..,---~~~~---,,...,-~::;=++*##%%@@@@@@@@@@@@@@%%%%%##### *+;:~-,..,,---~~---,,...,,-~:;==+*##%%@@@@@@@@@@@@@@@%%%####**** *=;:~-,..,,------,,...,,-~:;;=+*##%@@@@%%%%%%%%%@@@@@%%%###****+ +=;:~-,...,,,,,,....,,-~:;;=+*#%%@@@%%###****###%%@@@@%%%##****+ *=;:~-,,.........,,--~:;==+*#%@@@%##**+++++++++**##%@@@@%%##**** *+=;:~-,,,...,,,--~::;=++*#%@@@%#**+===;;;;;;;==++*##%@@@%%###** #*=;::~--------~~:;;=+**#%@@@%##*+==;:::~~~~~~::;==+*##%@@@%%### #*+=;;::~~~~~::;;==+**#%%@@%%#**+=;;:~~--,,,---~~:;==+*#%@@@%%%# %#*+==;;::::;;==++**#%%@@@%%##*+==;:~--,,.....,,-~~:;=+*#%%@@@%% @%#*++==;;;===++**#%%@@@@%%##**+=;;:~-,.........,,-~:;=+*##%@@@@ @%##*++====+++**##%@@@@%%%###***+=;~-,...,,,,,....,-~:;=+*##%@@@ @@%#**+++++++**##%%@@@%%%###****+=:~-,..,,,--,,...,-~:;==+*#%%@@ @@%##**+++++***#%%@@@@%%##****++=;:~-...,,----,,..,,-~:;=+*##%%@ @@%##**++++++**##%%@@@%%##**++==;:~-,...,,---,,...,-~~:;=+*##%%@ @@%#**+++==+++**##%@@@@%##**+==;:~~-,...,,,,,,...,,-~:;=+**#%%%@ @@%#*++=======++**#%%@@@%##*++=;:~~-,,..........,,-~:;==+*##%%@@ @%#*++=;;;;;;;;==+**#%%@@%%#*+==;:~~--,,.....,,--~~:;=++*##%%@@@ @%#*+=;:::~~~:::;;=++*#%%@@%##*+=;;:~~~-------~~::;==+**#%%@@@@@
use it
html
<script type="module" src="https://ascii.rest/ascii.js"></script> <ascii-art piece="plasma"></ascii-art>
No install and no build step. ascii.js defines the <ascii-art> tag, loads the piece from ascii.rest, plays it while it is on screen, and holds the first frame for anyone who prefers reduced motion.
react
// npm install github:bas3line/ascii
import { Ascii } from "ascii.rest/react";
import { plasma } from "ascii.rest/pieces";
<Ascii piece={plasma} /> A client component, so it works in the Next.js app router as it is. Pass the name instead, piece="plasma", to fetch the piece only when it mounts.
astro
--- // npm install github:bas3line/ascii import Ascii from "ascii.rest/astro"; --- <Ascii piece="plasma" />
Renders the first frame on the server, so the page is whole before any script runs, then plays the piece once it loads.
typescript
// npm install github:bas3line/ascii
import { mount } from "ascii.rest";
import { plasma } from "ascii.rest/pieces";
const el = document.querySelector<HTMLPreElement>("pre")!;
const stop = mount(el, plasma); mount plays a piece in a <pre>, or on a <canvas> for the coloured ones, and returns a function that stops it. Every piece, option and frame is typed.
/*
* plasma: the old demo-scene effect. Four sine fields, one a set of rings
* round a wandering centre, summed and read as soft blobs of density.
*/
import type { Frame, Meta } from "../types.ts";
export const meta = {
name: "plasma",
category: "generative",
note: "soft interference blobs drifting and pulsing",
cols: 64,
rows: 22,
fps: 24,
} satisfies Meta;
const RAMP = ".,-~:;=+*#%@";
const P = 30; // seconds; every term turns a whole number of times in one loop
const W = (2 * Math.PI) / P;
const GAIN = 0.32; // ramp sweeps per unit of the summed field: low, so the blobs are broad
export default function plasma(): Frame {
const { cols, rows } = meta;
const N = RAMP.length;
const out = new Array<string>(cols);
// Cell centres in cell widths, the rows stretched to their true height.
const X = Float32Array.from({ length: cols }, (_, c) => c + 0.5 - cols / 2);
const Y = Float32Array.from({ length: rows }, (_, r) => (r + 0.5 - rows / 2) * 2);
return (t, { paper = false } = {}) => {
const a = W * t;
const ca = Math.cos(a), sa = Math.sin(a);
const cx = 14 * Math.sin(a), cy = 9 * Math.cos(2 * a); // the rings' centre
const lines: string[] = [];
for (let r = 0; r < rows; r++) {
const y = Y[r];
for (let c = 0; c < cols; c++) {
const x = X[c];
let v = Math.sin(x * 0.11 + 3 * a);
v += Math.sin(y * 0.13 - 2 * a);
v += Math.sin((x * ca + y * sa) * 0.09 + 4 * a);
v += Math.sin(Math.hypot(x - cx, y - cy) * 0.17 - 5 * a);
// Up the ramp and back down, evenly, drifting through it once a loop.
const u = v * GAIN + a / Math.PI;
const k = Math.abs(u - 2 * Math.floor(u / 2 + 0.5));
const i = Math.min(N - 1, Math.floor(k * N));
out[c] = RAMP[paper ? N - 1 - i : i];
}
lines.push(out.join(""));
}
return lines.join("\n");
};
}