Cool, I just uploaded. I know we don’t want spoilers, so I’ve included it here using the forum’s handy “Hide details” thing.

##
Click to expand code for Snake 2D

```
/*
Snake - Generate a serpentine path around a matrix
This pattern relies on functions present in Pixelblaze v3 (hypot(),
mod(), arrayMutate()) but can be adapted to v2.
Demo on 16x16: https://youtu.be/RfDidPGp3Vg
Jeff Vyduna 2021 / MIT License
*/
// User-adjustable parameters
var width = 16 // Width of matrix, in pixels
var edgePct = .15 // Edge width, in percentage of the lesser of width or height. Snake tries to avoid edges.
var radius = sqrt(pixelCount) * 3/16 // Radius of the snake head in pixels. 3 on a 16x16
var nominalDecay = .98 // Fade each pixel per frame. Adjusted for speed and delta.
var maxDeflection = .2 // Radians per frame when escaping a boundary (edge)
var nominalDeflection = .1 // Radians per frame when slithering
var nominalSpeed = 0.02, speed = nominalSpeed
export function sliderSpeed (_v) {
speed = 2 * nominalSpeed * _v
}
var height = pixelCount / width // Height of matrix, in pixels
var posX = 0, posY = 0 // Positon of snakehead, in pixels. Set initial position.
var bearing = PI / 4 // Direction of travel, in radians
var deflection = nominalDeflection // Turn by deflecting the bearing each frame (radians)
var adjSpeed // User-commanded speed modified by the wandering fn and proximity to edges
var adjDeflection // Deflection angle modified for the adjusted speed
var thisTurn // Accumulated radians in the current slither / turn
var nominalDelta = 15 // A reference delta used to adapt turns for running speed (e.g. number of pixels)
var cx = width / 2, cy = height / 2 // Centers in x and y, in pixels
var cornerDist = hypot(cx, cy) // Distance from center to a corner
var edge = min(width, height) * edgePct // Edge border thickness, in pixels
var escapeDeflection = 0 // The current corrective deflection to escape edges or corners
var matrix = array(width) // Array of pixels in matrix, [width][height]. Stores "heat".
matrix.mutate((v) => array(height))
export function beforeRender(delta) {
t1 = time(6 / 65.535) // Hue modifier
t2 = time(30 / 65.535) // Speed wandering period
changeDirRandomly(delta)
avoidWalls()
// Speed wanders around the user-specified speed, and gets faster when near the edges
adjSpeed = speed * wander(t2) * (.5 + hypot(posX - cx, posY - cy)/cornerDist)
// Adjust the bearing deflection (curve) for speed input and delta
adjDeflection = deflection * adjSpeed / nominalSpeed * delta / nominalDelta
bearing = mod(bearing + adjDeflection, PI2) // Make the turn, keep bearing in 0..PI2
slither() // Reverse the turn so it doesn't normally eat its own tail
posX += adjSpeed * delta * cos(bearing)
posY += adjSpeed * delta * sin(bearing)
bounceOffWalls()
prerender()
}
// Moody snake doesn't always slither predictibly
function changeDirRandomly(_delta) {
// At 100FPS, this is roughly reversing once within 3 seconds
if(random(30 * _delta) < 1) deflection *= -1
}
function avoidWalls() {
var towardsVecX = 0, towardsVecY = 0
if (width - posX < edge) towardsVecX = 1
if (height - posY < edge) towardsVecY = 1
if (posX < edge) towardsVecX = -1
if (posY < edge) towardsVecY = -1
// If set, (towardsVecX, towardsVecY) is now the vector to the closest edge or corner
if (towardsVecX == 0 && towardsVecY == 0) { // Not near an edge
if (escapeDeflection) { // Was just in an edge (but now not)
deflection = nominalDeflection * ((random(2) > 1) ? -1 : 1)
thisTurn = escapeDeflection = 0
}
return
}
// If we get here, we're in range of an edge or corner.
// Angle towards nearest wall or corner, 0..PI2
towardsAngle = (atan2(towardsVecY, towardsVecX) + PI2) % PI2
if (towardsVecX * towardsVecY != 0) {
// In a corner; keep an existing turn going or set one up
escapeDeflection = escapeDeflection || maxDeflection
} else {
// Near an edge. Deflect away from it.
deviation = angleDiff(bearing, towardsAngle)
escapeDeflection = deviation > 0 ? maxDeflection : -maxDeflection
}
// We will escape if our bearing is within 45 degrees of the vector away from edge of corner
var willEscape = abs(angleDiff(towardsAngle + PI, bearing)) < PI / 8
deflection = willEscape ? 0 : escapeDeflection // End turns if headed away from the edge
}
// Pseudo gradient noise
// https://www.desmos.com/calculator/rvtrkskoqa
function wander(t) {
t *= 49.261 // Define period for t in 0..1; see graph
return .6 + 3 * wave(t/2)*wave(t/3)*wave(t/5)*wave(t/7)
}
// Turn the other direction if it's been a half turn
function slither() {
thisTurn += adjDeflection
if (abs(thisTurn) > PI) {
deflection *= -1
thisTurn = 0
}
}
// Return (angle - targetAngle) within -PI..PI
function angleDiff(angle, target) {
return mod(angle - target + PI, PI2) - PI
}
// Bounce like a billiard ball
function bounceOffWalls() {
if (posX <= 0 || posX >= width) {
bearing = -bearing + PI
posX = clamp(posX, 0, width)
}
if (posY <= 0 || posY >= height) {
bearing *= -1
posY = clamp(posY, 0, height)
}
}
// A 2D array holds each pixel's heat. Cool each pixel, and heat pixels
// within `radius` of head (posX, posY). Since the inner loop runs as
// much as render(), there are modifications for speed over readability.
function prerender() {
// Adjust the exponential decay (tail cooling) for the speed of travel
var decay = pow(2, log2(nominalDecay) / (nominalSpeed / adjSpeed))
var speedFactor = adjSpeed / nominalSpeed
// Heat up pixels near the snake's head
for(x = 0; x < width; x++) {
for(y = 0; y < height; y++) {
matrix[x][y] *= decay
var distanceToHead = hypot(posX - x, posY - y)
if (distanceToHead > radius) continue // Boosts FPS
proximity = 1 - distanceToHead / radius
matrix[x][y] = min(1, matrix[x][y] + pow(proximity, 6) * speedFactor)
}
}
}
export function render2D(index, x, y) {
v = matrix[x * width][y * height]
s = 1 - pow(v, 8)
h = v / 4 + t1
hsv(h, s, v * v)
// Uncomment to see a line showing the current commanded bearing.
// Helpful when debugging edge avoidance. Costs half your FPS though!
// plotAngle(bearing, x * width, y * height)
}
// Utility to plot an angle from the center of the matrix to the
// boundary of the border `edge`. Can be called from within prerender() or render()
// Usage: plotAngle(bearing, x * width, y * height)
function plotAngle(a, x, y) {
x -= cx; y -= cy
var pixelAng = atan2(y, x)
var ad = abs(angleDiff(a, pixelAng)) // Angle difference between a and this pixel
var hc = (width - 2 * edge) / 2 // Horizontal center box height
var vc = (height - 2 * edge) / 2
var bx = cos(a), by = sin(a)
var dist = abs(x * by - y * bx) / hypot(bx, by) // Distance from pixel to the line to be plotted
if (abs(x) < hc && abs(y) < vc && ad < PI/2) hsv(0, 0, 1 - dist * 2)
}
```