Home
Admin | Edit

Archimedean Echoes - RISC OS 256 bytes

link

A 256 bytes real-time intro for RISC OS (RISC PC+, 3MB+), released at Lovebyte 2025.

It show 8 greyscale "Apollonian gasket" layers with horizontal parallax scrolling.

Works on any RISC OS but is a slideshow on Acorn Archimedes machines... best speed starts with RISC PC.

This started after Dreamelt ~3 days before the deadline, i got the layering idea from a Twitter post by RavenKwok which show an animated and layered Apollonian gasket, this was combined with past memory of cool intros that were similarly layered or using a similar setup such as Gespensterwald 64 / Murkwood, 3D cube part in Inflorescence demo.

My main motivation was that i already had needed knowledge / materials to produce similar patterns as the Twitter post by generating them with the integer circle algorithm, it was the perfect opportunity as it can generate these patterns in few instructions.

The JS prototype took one evening, same for the ARM port, 4 layers at first since my initial target was Acorn Archimedes machines, it was too slow though even with aggressive optimizations so i ditched this target, i didn't like it as much as the prototype anyway due to low amount of layers / low resolution. A version that write a dword instead of a byte may works at acceptable speed on high end Archimedes machines though, low colors mode could also help although this add few bytes for palette setup etc. so i don't know if it is possible at this size.

early prototype version (not taking all screen space due to algorithm variations)

Target changed to RISC PC+ so the code was adapted for mode 21 (640x512 256 colors) to approach the prototype prettiness.

It was fairly fast to do as i already tinkered with precomputed layers in Moirisc and refined the integer circle algorithm on past releases, only had minor issues such as addressing the non linear greyscale colors of the default palette, it was solved by doing a small lookup.

Could not have ESCAPE support in time (+8 bytes), may be possible without breaking stuff though.

p5js code (ARM code in .adf)

let layers = []

// layers colors
let colors = [224, 192, 160, 128, 92, 64, 32, 0]
let layersCount = colors.length

function generateLayers() {
  // clear
  for (let f = layersCount; f >= 0; f -= 1) {
    for (let i = 0; i < width * height; i += 1) {
      layers[f + i * layersCount] = 0
    }
  }
 
  // generate layers
  let offset = ((height >> 1) * width)
  for (let l = 0; l < 4194304 * layersCount; l += 1) {
    if ((l & 4194303) == 0) {
      x = 640 << 24
      y = 0
    }

    x -= y >> 2
    y += x >> 1
    x -= y >> 2

    let f = l >>> 22
    x += (8 - f) << 27

    let px = x >>> 23
    let py = (y >> 23)
    let index = offset + px + py * width

    layers[f + index * layersCount] = 1
  }
}

function setup() {
  createCanvas(640, 512)
  background(255)

  generateLayers()
}

function draw() {
  let frame = frameCount

  loadPixels()
  let iy = 0
  for (let y = width * (height - 1); y >= 0; y -= width) {
    for (let x = width - 1; x >= 0; x -= 1) {
      let c = 255
      for (let f = layersCount - 1; f >= 0; f -= 1) {
        let xof = (frame << f) >> 5
        let lx = ((x + xof) & 511)
        let b = layers[f + (lx + y) * layersCount]
        if (b) {
          c = colors[f]
          break
        }
      }

      let index = (x + y) << 2
      pixels[index + 0] = c
      pixels[index + 1] = c
      pixels[index + 2] = c
    }
  }
  updatePixels()
}

back to topLicence Creative Commons