Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ======================================================
- // GLOBAL TOGGLES
- // ======================================================
- // Orbit ON/OFF for everyone:
- let GLOBAL_ORBIT_ENABLED = true;
- // Pick formation:
- // "circle", "polygon5", "polygon6", "star5", "star8",
- // "infinity", "spiral", "snowflake", "jitter",
- // "wave", "heart", "polygon:N"
- let GLOBAL_FORMATION = "infinity";
- // ======================================================
- // USER FOLLOWER DEFINITIONS
- // Each user gets their own emoji + inherits global toggles
- // ======================================================
- const userFollowers = {
- "nbf641": { char: "hello" },
- "falling23": { char: "🐍" },
- "guest7": { char: "⭐" }
- };
- // ======================================================
- // FORMATION MATH ENGINE
- // returns {x, y} offset for angle θ
- // ======================================================
- function formationOffset(theta, formationName) {
- switch (formationName) {
- case "circle":
- return { x: Math.cos(theta), y: Math.sin(theta) };
- case "polygon5":
- return polygon(theta, 5);
- case "polygon6":
- return polygon(theta, 6);
- case "star5":
- return star(theta, 5);
- case "star8":
- return star(theta, 8);
- case "infinity":
- return infinity(theta);
- case "spiral":
- return spiral(theta);
- case "snowflake":
- return snowflake(theta);
- case "jitter":
- return jitter(theta);
- case "wave":
- return wave(theta);
- case "heart":
- return heart(theta);
- default:
- // polygon:N
- if (formationName.startsWith("polygon:")) {
- const n = parseInt(formationName.split(":")[1]);
- return polygon(theta, n);
- }
- return { x: Math.cos(theta), y: Math.sin(theta) };
- }
- }
- // ========= SHAPE FUNCTIONS =========
- function polygon(theta, sides) {
- // Map continuous angle onto polygon vertices
- const step = (Math.PI * 2) / sides;
- const index = Math.floor(theta / step) % sides;
- const angle = index * step;
- return { x: Math.cos(angle), y: Math.sin(angle) };
- }
- function star(theta, points) {
- const inner = { r: 0.5 };
- const outer = { r: 1.0 };
- const step = Math.PI / points;
- const i = Math.floor(theta / step) % (points * 2);
- const radius = (i % 2 === 0 ? outer.r : inner.r);
- const angle = i * step;
- return { x: Math.cos(angle) * radius, y: Math.sin(angle) * radius };
- }
- function infinity(theta) {
- return { x: Math.cos(theta), y: Math.sin(theta) * Math.cos(theta) };
- }
- function spiral(theta) {
- const r = 0.2 + (theta % (Math.PI * 2)) / (Math.PI * 2);
- return { x: Math.cos(theta) * r, y: Math.sin(theta) * r };
- }
- function snowflake(theta) {
- const r = 1 + 0.3 * Math.cos(6 * theta);
- return { x: r * Math.cos(theta), y: r * Math.sin(theta) };
- }
- function jitter(theta) {
- return {
- x: Math.cos(theta) + (Math.random() - 0.5) * 0.5,
- y: Math.sin(theta) + (Math.random() - 0.5) * 0.5
- };
- }
- function wave(theta) {
- const r = 1 + 0.4 * Math.sin(theta * 3);
- return { x: Math.cos(theta) * r, y: Math.sin(theta) * r };
- }
- function heart(theta) {
- // classic parametric heart curve
- const x = 16 * Math.pow(Math.sin(theta), 3);
- const y = -(13 * Math.cos(theta) - 5 * Math.cos(2 * theta)
- - 2 * Math.cos(3 * theta) - Math.cos(4 * theta));
- return { x: x / 16, y: y / 16 };
- }
- // ======================================================
- // PHYSICS FOLLOWER — fully upgraded
- // ======================================================
- function physicsLagFollower(options) {
- const followChar = options.char;
- const targetName = options.targetName;
- const accel = 0.18;
- const friction = 0.88;
- const maxSpeed = 0.2;
- const lagDistance = 4;
- const orbitRadius = 4;
- const orbitSpeed = 0.04;
- let orbitAngle = 0;
- const lifetime = 10000;
- const startTime = performance.now();
- let dead = false;
- let fx = 0, fy = 0;
- let vx = 0, vy = 0;
- let lx = null, ly = null;
- let initialized = false;
- function findCursorByName(name) {
- for (const [key, c] of w.cursors.entries()) {
- if (c && c.n === name) return c;
- }
- return null;
- }
- function clearBetween(x1, y1, x2, y2) {
- if (x1 === null || y1 === null) return;
- const minX = Math.min(x1, x2);
- const maxX = Math.max(x1, x2);
- const minY = Math.min(y1, y2);
- const maxY = Math.max(y1, y2);
- for (let y = minY; y <= maxY; y++) {
- for (let x = minX; x <= maxX; x++) {
- writeCharAt(" ", null, x, y);
- }
- }
- }
- function kill() {
- if (dead) return;
- dead = true;
- if (lx !== null && ly !== null) writeCharAt(" ", null, lx, ly);
- }
- function tick() {
- if (!dead && performance.now() - startTime >= lifetime) return kill();
- if (dead) return;
- const c = findCursorByName(targetName);
- if (!c || !c.l) return kill();
- const tx = c.l[0];
- const ty = c.l[1];
- if (!initialized) {
- fx = tx;
- fy = ty;
- initialized = true;
- }
- let targetX, targetY;
- if (GLOBAL_ORBIT_ENABLED) {
- orbitAngle += orbitSpeed;
- const f = formationOffset(orbitAngle, GLOBAL_FORMATION);
- targetX = tx + f.x * orbitRadius;
- targetY = ty + f.y * orbitRadius;
- } else {
- // Physics lag fallback
- const dxFull = fx - tx;
- const dyFull = fy - ty;
- const dist = Math.hypot(dxFull, dyFull);
- if (dist < 0.001) {
- targetX = tx - lagDistance;
- targetY = ty;
- } else {
- const nx = dxFull / dist;
- const ny = dyFull / dist;
- targetX = tx + nx * lagDistance;
- targetY = ty + ny * lagDistance;
- }
- }
- // Physics step
- const dx = targetX - fx;
- const dy = targetY - fy;
- vx += dx * accel;
- vy += dy * accel;
- vx *= friction;
- vy *= friction;
- const speed = Math.hypot(vx, vy);
- if (speed > maxSpeed) {
- const scale = maxSpeed / speed;
- vx *= scale;
- vy *= scale;
- }
- fx += vx;
- fy += vy;
- const rx = Math.round(fx);
- const ry = Math.round(fy);
- if (rx !== lx || ry !== ly) {
- clearBetween(lx, ly, rx, ry);
- writeCharAt(followChar, null, rx, ry);
- lx = rx; ly = ry;
- }
- requestAnimationFrame(tick);
- }
- requestAnimationFrame(tick);
- }
- // ======================================================
- // SPAWN FOLLOWERS FOR ALL USERS
- // ======================================================
- Object.entries(userFollowers).forEach(([username, data]) => {
- physicsLagFollower({
- char: data.char,
- targetName: username
- });
- });
Advertisement
Comments
-
- Update 0.1: Added: const lifetime = options.lifetime || 18000; // ms until death
Add Comment
Please, Sign In to add comment