Skip to content
Game 5 Unit 18 of 128 1 hr learning time

Cursor Animation

Animate the cursor with colour cycling for better visibility and a more engaging visual experience.

14% of Ink War

A static cursor is functional but forgettable. An animated cursor draws the eye and feels alive.

Run It

Assemble and run:

pasmonext --sna inkwar.asm inkwar.sna

Unit 18 Screenshot

Version shows “PHASE 2 V0.2”. Start a game to see the cursor pulsing.

Animation Philosophy

Simple animations create immediate polish:

TypeEffectCost
Colour cyclingEye-catching, visibleMinimal CPU
Brightness pulseSubtle, professionalMinimal CPU
Position wobblePlayful, distractingHigher complexity

We’ll use colour cycling for empty cells and brightness pulsing for claimed cells.

Frame Counter

Animations need timing. A frame counter increments every game loop:

main_loop:
            halt

            ; Increment frame counter for animations
            ld      a, (frame_counter)
            inc     a
            ld      (frame_counter), a

            ; ... rest of game loop

With HALT syncing to the 50Hz interrupt, this gives us 50 increments per second.

Cursor Animation Logic

Use different bits of the frame counter for different animation speeds:

get_cursor_anim_attr:
            ; Cycle: White → Cyan → White → Yellow
            ld      a, (frame_counter)
            and     %00110000           ; Bits 4-5 cycle every 16 frames
            rrca
            rrca
            rrca
            rrca                        ; Now 0-3 in low bits

            ; Map to colour
            or      a
            jr      z, .white
            cp      1
            jr      z, .cyan
            cp      2
            jr      z, .white
            ; else yellow

.yellow:    ld      a, %01110000        ; Yellow paper + BRIGHT
            ret
.cyan:      ld      a, %01101000        ; Cyan paper + BRIGHT
            ret
.white:     ld      a, %01111000        ; White paper + BRIGHT
            ret

The cycle completes in 64 frames (about 1.3 seconds at 50Hz).

Brightness Pulsing

For cells already claimed, toggle BRIGHT to avoid colour confusion:

apply_cursor_pulse:
            ld      b, a                ; Save base attribute

            ; Toggle BRIGHT every 8 frames
            ld      a, (frame_counter)
            and     %00001000           ; Check bit 3
            jr      z, .bright_on

            ; BRIGHT off
            ld      a, b
            and     %10111111           ; Clear BRIGHT bit
            ret

.bright_on:
            ; BRIGHT on
            ld      a, b
            or      %01000000           ; Set BRIGHT bit
            ret

This toggles every 8 frames—a gentle pulse at about 3Hz.

Continuous Redraw

The cursor must be redrawn every frame for animation:

state_playing:
            ; Update cursor animation every frame
            call    draw_cursor

            ; ... rest of playing state

This costs some cycles but keeps the animation smooth.

Animation Speed Guidelines

SpeedFramesHzUse for
Very fast2-412-25Urgent feedback
Fast8-163-6Active elements
Medium321.5Background effects
Slow64+Less than 1Subtle ambient

Our cursor uses 16-frame colour cycles (3Hz) and 8-frame brightness toggles (6Hz).

The Complete Code

What You’ve Learnt

  • Frame counting - Track time for animation timing
  • Bit masking for speed - Different bits give different frequencies
  • Colour cycling - Cycle through attribute colours
  • Brightness pulsing - Toggle BRIGHT for subtle animation
  • Continuous redraw - Animation requires per-frame updates

What’s Next

Unit 19 adds claim animation—a satisfying flash when cells are captured.

What Changed

Unit 17 → Unit 18