Armada - RISC OS 256 bytes

A 256 bytes real-time intro for RISC OS 3.5+ (RISC PC+ / RPI, 640x512, 32
bpp), released at NOVA
2026.
It shows running XOR patterns behind a tumultuous
"fog" that come and go.
The "fog" effect is powered by drifting HAKMEM 149
patterns plus a separate "blur" pass, the HAKMEM pattern is then
XOR shaded.
This started from an early 2025 p5js accidental
sketch where i was trying to do nice noise with the HAKMEM 149
algorithm, i decided to port this effect on RISC PC after
X-87 to
support some RO stuff at NOVA.
The port took few hours, it was close to 256
bytes without much effort, only had to fix top / bottom boundary
artifacts and optimizing the blur pass / looking at the RISC OS API
to replace some costly calls. (e.g. OS_ReadVduVariables
by
OS_ReadDynamicArea)
The combination of the cheap post processing pass
and the unstable patterns + XOR shading adds the illusion of a
depth effect.
The API dive was interesting as i didn't know
that some of the mode
flags can setup a greyscale palette (only RO 5.21+ though) or
do some transforms (rotations), many bytes could be saved by going
for 256 colors (with greyscale flag) but i prefered older RO
compatibility so...
Assembled on RISC PC (RPCEmu) with a
custom
ARMv2 Forth /
assembler, kinda served as a test bed for the tool as
well.
ARM code
\ ARMADA \ 256b RISC OS intro
\ ---------> by grz / The Orz
: OS_Byte $6 ; immediate
: OS_ReadMonotonicTime $42 ; immediate
: OS_ScreenMode $65 ; immediate
: OS_ReadDynamicArea $5c ; immediate
: OS_RemoveCursors $36 ; immediate
: OS_ReadEscapeState $2c ; immediate
: OS_Exit $11 ; immediate
variable mode_block
variable l1
variable l2
create ARMADA_ARMv2_CODE
$0 imm r0 mov
mode_block r1 adr
OS_ScreenMode swi
$2 imm r0 mov
OS_ReadDynamicArea swi
r0 r14 mov
OS_RemoveCursors swi
\ compute offset
$a0000 imm r11 mov
$500 imm r11 r11 add
l1 ->
$13 imm r0 mov
OS_Byte swi \ vsync
OS_ReadMonotonicTime swi
$10000 imm r1 mov
l2 ->
\ x
$16 asr r2 r8 mov
$2 lsl r8 r8 r4 add
\ y
$17 asr r3 r5 mov
$2 lsl r5 r5 r12 add
\ i
$9 lsl r12 r11 r7 add
$1 asr r4 r7 r7 add
\ osc
$80 imm r1 r8 and
r7 r8 r8 add
[] r8 r14 r6 ldrb
$15 lsl r6 r2 r2 sub
$2 asr r3 r2 r2 sub
$1 asr r2 r3 r3 add
$2 asr r3 r2 r2 sub
$14 lsl r0 r2 r2 sub \ animate
\ color
r3 r2 r8 eor
$18 lsr r8 r8 mov
$150 imm r8 r8 rsb
\ clamp
$ff imm r8 cmp
$ff imm r8 movgt
\ fix top + bottom artifacts due to "blur"
pass
$fe imm r5 r9 adds
$1fc imm r9 cmp
$8 lsl r8 r8 r8 orr
$10 lsl r8 r8 r8 orr
[] r7 r14 r8 strls
$1 imm r1 r1 subs
l2 <- bne
\ "blur" pass
$a00 imm r14 r1 add
$140000 imm r14 r10 add
$a00 imm r10 r10 sub
l2 ->
[] $4 negate imm r1 r6 ldrb
[] $4 imm r1 r7 ldrb
[] $a00 imm r1 r8 ldrb
[] $a00 negate imm r1 r9 ldrb
r7 r6 r6 add
r8 r6 r6 add
r9 r6 r6 add
$2 asr r6 r6 mov
$8 lsl r6 r6 r6 orr
$10 lsl r6 r6 r6 orr
$4 imm [] r1 r6 str
r10 r1 cmp
l2 <- bmi
OS_ReadEscapeState swi
OS_Exit swics
l1 <- b
\ screen_mode --> \ X640 Y480 C16M F60 (mode string is
shorter than mode block but not compatible with old RO)
\ $58 c, $36 c, $34 c, $30 c, $20 c,
\ $59 c, $34 c, $38 c, $30 c, $20 c,
\ $43 c, $31 c, $36 c, $4d c, $20 c,
\ $46 c, $36 c, $30 c, $0 c,
mode_block -->
$1 l,
$280 l, \ 640
$200 l, \ 512
$5 l, \ C16M
$1 negate l, \ default refresh rate
$1 negate l,
ARMADA_ARMv2_CODE here $ff8 dump
p5js code
function setup() {
createCanvas(640, 512)
background(0)
}
let x = 0
let y = 0
function draw() {
loadPixels()
for (let l = 0; l < 16384*4; l += 1) {
let i = (0xa0500 + ((((y >> 23) * 5) <<
9) + (((x >>> 22) * 5) >>> 1))) & ~3
x -= pixels[i + 0 + (l & 128)] << 21
x -= y >> 2
y += x >> 1
x -= y >> 2
x -= frameCount << 22
let c = 336 - ((x ^ y) >>> 24) // can also
remove the sub for a darker / busier version
pixels[i + 0] = pixels[i + 1] = pixels[i + 2] = c
}
for (let i = 0; i < width * height * 4; i += 4) {
let c = pixels[i + 4] + pixels[i - 4] + pixels[i +
width * 4] + pixels[i - width * 4] >> 2
pixels[i + 0] = pixels[i + 1] = pixels[i + 2] = c //
+ 4 on index is cool
}
updatePixels()
}
back to top
