### Glowing spinner

My first ever attempt at ray marching (from scratch)

```Canvas.setpenopacity(-0.3);

const t = new Turtle();

const scrZ = 4.0;
const scrR = 1.0;

const eyeZ = 8.0;

const camRotX = -60 * Math.PI/180;

const step = 0.25;

const R = 1.0;
const R1 = 0.5;
const R2 = 0.15;

const Dmax = scrZ + 2 * scrR;
const INF = 2 * Dmax;

const EPS = 0.0001;

const MAX_N_STEPS = 256;

const glowR = 0.2 * R;

function plus(v1, v2) {
return [v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]];
}

function minus(v1, v2) {
return [v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]];
}

function multiply(a, v) {
return [a * v[0], a * v[1], a * v[2]];
}

function length(v) {
return Math.sqrt(v[0]**2 + v[1]**2 + v[2]**2);
}

function normalize(v) {
let L = length(v);
return [v[0] / L, v[1] / L, v[2] / L];
}

function torus_df(p, c, R, r) { // axis z
let pc = minus(p, c);
let px = pc[0], py = pc[1], pz = pc[2];

let dxy = Math.sqrt(px**2 + py**2);

let cx = px / dxy * R;
let cy = py / dxy * R;

let d = [px - cx, py - cy, pz];

return length(d) - r;
}

function cylinder_df(p, h, r) { // center (0, 0, 0), axis z
let px = p[0], py = p[1], pz = p[2];

let dxy = Math.sqrt(px**2 + py**2) - r;
let dz = Math.abs(pz) - h/2;

if (dxy > 0) {
if (dz > 0) {
return Math.sqrt(dxy**2 + dz**2);
}
else {
return dxy;
}
}
else {
if (dz > 0) {
return dz;
}
else {
return Math.max(dxy, dz);
}
}
}

// see https://iquilezles.org/articles/smin/
function smooth_min(a, b, k) {
let h = Math.max(k - Math.abs(a - b), 0) / k;
return Math.min(a, b) - h*h*h*k*(1/6);
}

function scene_df(p) {
let phi = -Math.PI / 12;
let phi1 = phi - Math.PI / 6, phi2 = phi - 5 * Math.PI / 6, phi3 = phi - 3 * Math.PI / 2;
let df1 = torus_df(p, [R * Math.cos(phi1), R * Math.sin(phi1), 0], R1, R2);
let df2 = torus_df(p, [R * Math.cos(phi2), R * Math.sin(phi2), 0], R1, R2);
let df3 = torus_df(p, [R * Math.cos(phi3), R * Math.sin(phi3), 0], R1, R2);
let df4 = cylinder_df(p, 4 * R2, 0.7 * (R - R1 - R2));
let df12 = smooth_min(df1, df2, 0.35);
let df123 = smooth_min(df12, df3, 0.35);
let df1234 = smooth_min(df123, df4, 0.75);
return df1234;
}

let x = 0;
let y = 0;

function walk(frame) {
let px = -scrR + 2 * scrR * (x / 200);
let py = -scrR + 2 * scrR * (y / 200);
let pz = scrZ;

[py, pz] = [py * Math.cos(camRotX) - pz * Math.sin(camRotX), py * Math.sin(camRotX) + pz * Math.cos(camRotX)];

let ex = 0, ey = 0, ez = eyeZ;

[ey, ez] = [ey * Math.cos(camRotX) - ez * Math.sin(camRotX), ey * Math.sin(camRotX) + ez * Math.cos(camRotX)];

let p = [px, py, pz];
let dir = normalize([px - ex, py - ey, pz - ez]);

let D = 0;
let d_min = INF;
var n_steps;

for (n_steps = 0; n_steps < MAX_N_STEPS; n_steps++) {
let d = scene_df(p);

d_min = Math.min(d_min, d);

if ((d < EPS) || (D > Dmax)) {
break;
}
else {
p = plus(p, multiply(d, dir));

D += d;
}
}

if (D < Dmax) {
let s = step * Math.max(0.1, (1 - n_steps / 50));

t.seth(360 * Math.random());

for (let i = 0; i < 4; i++) {
t.jump(x - 100, y - 100);
t.right(90);
t.forward(s);
}
}

if ((d_min > EPS) && (d_min < glowR)) {
let s = step * (1 - d_min / glowR)**2;

t.seth(360 * Math.random());

for (let i = 0; i < 4; i++) {
t.jump(x - 100, y - 100);
t.right(90);
t.forward(s);
}
}

x += step;
if (x > 200) {
y += step;
x = 0;
}

return (y < 200);
}```