From aded9ae25629c08bdf84c297b08b78926fe5c234 Mon Sep 17 00:00:00 2001 From: Christian Johannesen Date: Wed, 21 Oct 2026 23:17:21 +0200 Subject: [PATCH] Add Infinite Road demo --- README.md | 3 +- infinite-road/infinite-road.asm | 797 ++++++++++++++++++++++++++++++++ infinite-road/infinite-road.prg | Bin 0 -> 12353 bytes programs.json | 6 + scripts/build-machine-code.sh | 3 +- 5 files changed, 807 insertions(+), 2 deletions(-) create mode 100644 infinite-road/infinite-road.asm create mode 100644 infinite-road/infinite-road.prg diff --git a/README.md b/README.md index 472466e..b9b8c29 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # C64 Program Collection -Thirty-two small, polished programs for the Commodore 64, written in stock Commodore BASIC V2 and 6502 machine code. The collection mixes arcade action, puzzles, simulations, creative tools, music, utilities, and visual effects. Every entry is self-contained and runs on an ordinary PAL or NTSC C64 without a cartridge or BASIC extension. +Thirty-three small, polished programs for the Commodore 64, written in stock Commodore BASIC V2 and 6502 machine code. The collection mixes arcade action, puzzles, simulations, creative tools, music, utilities, and visual effects. Every entry is self-contained and runs on an ordinary PAL or NTSC C64 without a cartridge or BASIC extension. Browse and run the collection at [c64.p20.dev](https://c64.p20.dev). @@ -40,6 +40,7 @@ Browse and run the collection at [c64.p20.dev](https://c64.p20.dev). | Fifteen Puzzle | 2026-10-16 | Puzzle | Machine Code | `W`, `A`, `S`, `D`, `R`, `Q` | Slide numbered tiles until the classic four-by-four board is restored. | [ASM](fifteen-puzzle/fifteen-puzzle.asm) | [Run](https://c64.p20.dev/program/fifteen-puzzle) | | Plasma Grid | 2026-10-16 | Demo | Machine Code | `1`-`3`, `C`, Space, `Q` | Fill the screen with a flowing field of color generated in real time. | [ASM](plasma-grid/plasma-grid.asm) | [Run](https://c64.p20.dev/program/plasma-grid) | | Neon Rift | 2026-10-16 | Demo | Machine Code | `1`-`3`, `C`, `M`, Space, `Q` | Enter a neon-colored world of orbiting sprites, a scrolling message, and a three-voice SID score. | [ASM](neon-rift/neon-rift.asm) | [Run](https://c64.p20.dev/program/neon-rift) | +| Infinite Road | 2026-10-21 | Demo | Machine Code | `A`, `D`, `1`-`3`, `C`, `M`, Space, `Q` | Cruise along an endless synthwave highway with sweeping curves and a driving three-voice SID score. | [ASM](infinite-road/infinite-road.asm) | [Run](https://c64.p20.dev/program/infinite-road) | ## Running the programs diff --git a/infinite-road/infinite-road.asm b/infinite-road/infinite-road.asm new file mode 100644 index 0000000..9f365b5 --- /dev/null +++ b/infinite-road/infinite-road.asm @@ -0,0 +1,797 @@ +!cpu 6510 + +; INFINITE ROAD +; Double-buffered pseudo-3D highway, custom character set and three-voice SID. +; Self-starting BASIC line: 10 SYS4096 +* = $0801 +!word basic_end +!word 10 +!byte $9e +!text "4096" +!byte 0 +basic_end: !word 0 + +* = $1000 +GETIN = $ffe4 +CHROUT = $ffd2 + +start: + jsr save_state + lda #0 + sta $d020 + sta $d021 + jsr show_splash + jsr initialize_demo + lda #250 + jsr wait_raster + +main_loop: + jsr read_controls + lda quit_flag + beq keep_running + jmp exit_demo +keep_running: + lda paused + bne paused_frame + jsr update_scene + lda music_muted + bne skip_music + jsr update_music +skip_music: + jsr render_back_buffer + lda #250 + jsr wait_raster + jsr flip_buffers + jmp main_loop +paused_frame: + lda #250 + jsr wait_raster + jmp main_loop + +save_state: + lda $d020 + sta old_border + lda $d021 + sta old_background + lda $d011 + sta old_d011 + lda $d016 + sta old_d016 + lda $d018 + sta old_d018 + lda $dd00 + sta old_dd00 + lda $d015 + sta old_sprite_enable + lda $d010 + sta old_sprite_msb + lda $d017 + sta old_sprite_expand_y + lda $d01d + sta old_sprite_expand_x + lda $d01b + sta old_sprite_priority + lda $d000 + sta old_sprite_x + lda $d001 + sta old_sprite_y + lda $d027 + sta old_sprite_color + lda $07f8 + sta old_sprite_pointer + ldx #0 +save_sid_loop: + lda $d400,x + sta old_sid,x + inx + cpx #25 + bne save_sid_loop + rts + +initialize_demo: + lda #0 + sta $d020 + sta $d021 + sta curve_phase + sta road_phase + sta music_tick + sta music_step + sta paused + sta music_muted + sta quit_flag + sta front_buffer + lda #6 + sta view_index + lda #2 + sta road_speed + lda #0 + sta palette + lda old_dd00 + ora #3 + sta $dd00 + lda old_d011 + and #$9f + ora #$10 + sta $d011 + lda old_d016 + and #$e8 + ora #8 + sta $d016 + lda #136 + sta $d000 + lda #76 + sta $d001 + lda $d010 + and #$fe + sta $d010 + lda $d017 + ora #1 + sta $d017 + lda $d01d + ora #1 + sta $d01d + lda $d01b + ora #1 + sta $d01b + lda #$e0 + sta $07f8 + sta $0ff8 + lda #1 + sta $d015 + lda #$1c + sta $d018 + jsr prepare_buffers + jsr apply_palette + jsr initialize_sid + rts + +prepare_buffers: + lda #$04 + sta screen_base_hi + jsr clear_buffer + jsr draw_sky + lda #$0c + sta screen_base_hi + jsr clear_buffer + jsr draw_sky + lda #$0c + sta screen_base_hi + jsr render_road + lda #$04 + sta screen_base_hi + jsr render_road + lda #$0c + sta screen_base_hi + rts + +clear_buffer: + lda #0 + sta $fb + lda screen_base_hi + sta $fc + ldx #3 + ldy #0 +clear_full_pages: + lda #0 + sta ($fb),y + iny + bne clear_full_pages + inc $fc + dex + bne clear_full_pages + ldy #0 +clear_tail: + lda #0 + sta ($fb),y + iny + cpy #232 + bne clear_tail + rts + +draw_sky: + ; Stars, a striped sun and a jagged horizon are identical in both buffers. + ldx #0 +sky_star_loop: + lda star_rows,x + tay + lda row_lo,y + sta $fb + lda row_hi,y + clc + adc screen_base_hi + sta $fc + ldy star_columns,x + lda #5 + sta ($fb),y + inx + cpx #22 + bne sky_star_loop + ldy #9 + lda row_lo,y + sta $fb + lda row_hi,y + clc + adc screen_base_hi + sta $fc + ldx #0 +mountain_loop: + lda mountain_chars,x + ldy mountain_columns,x + sta ($fb),y + inx + cpx #40 + bne mountain_loop + rts + +render_back_buffer: + lda front_buffer + beq render_to_second + lda #$04 + bne set_render_base +render_to_second: + lda #$0c +set_render_base: + sta screen_base_hi + jmp render_road + +render_road: + ldx #0 +road_row_loop: + stx row_index + txa + clc + adc #10 + tay + lda row_lo,y + sta $fb + lda row_hi,y + clc + adc screen_base_hi + sta $fc + ldy #0 +clear_road_row: + lda #0 + sta ($fb),y + iny + cpy #40 + bne clear_road_row + + ldx row_index + lda curve_offsets,x + clc + adc curve_phase + and #63 + tay + lda curve_centers,y + clc + adc view_index + sec + sbc #6 + cmp #8 + bcs center_not_low + lda #8 +center_not_low: + cmp #32 + bcc center_ready + lda #31 +center_ready: + sta road_center + ldx row_index + sec + sbc road_half_width,x + bcs left_ready + lda #0 +left_ready: + sta road_left + lda road_center + clc + adc road_half_width,x + cmp #40 + bcc right_ready + lda #39 +right_ready: + sta road_right + + ldy road_left + lda #2 + sta ($fb),y + iny +fill_road_loop: + cpy road_right + bcs place_right_edge + lda row_index + clc + adc road_phase + and #3 + bne road_surface + tya + sec + sbc road_center + beq center_dash +road_surface: + lda row_index + and #1 + clc + adc #6 + bne store_road_char +center_dash: + lda #4 +store_road_char: + sta ($fb),y + iny + bne fill_road_loop +place_right_edge: + lda #3 + sta ($fb),y + ldx row_index + inx + cpx #15 + beq road_render_done + jmp road_row_loop +road_render_done: + rts + +update_scene: + lda curve_phase + clc + adc road_speed + and #63 + sta curve_phase + lda road_phase + clc + adc road_speed + and #7 + sta road_phase + rts + +flip_buffers: + lda front_buffer + eor #1 + sta front_buffer + beq show_first + lda #$3c + bne store_screen_select +show_first: + lda #$1c +store_screen_select: + sta $d018 + rts + +read_controls: + jsr GETIN + bne control_available + rts +control_available: + cmp #81 + bne check_left + lda #1 + sta quit_flag + rts +check_left: + cmp #65 + bne check_right + lda view_index + beq controls_done + dec view_index + rts +check_right: + cmp #68 + bne check_color + lda view_index + cmp #12 + bcs controls_done + inc view_index + rts +check_color: + cmp #67 + bne check_mute + inc palette + lda palette + cmp #3 + bcc apply_new_palette + lda #0 + sta palette +apply_new_palette: + jsr apply_palette + rts +check_mute: + cmp #77 + bne check_pause + lda music_muted + eor #1 + sta music_muted + bne mute_now + jsr initialize_sid + rts +mute_now: + jsr silence_sid + rts +check_pause: + cmp #32 + bne check_speed_one + lda paused + eor #1 + sta paused + bne pause_now + lda music_muted + bne controls_done + jsr initialize_sid + rts +pause_now: + jsr silence_sid + rts +check_speed_one: + cmp #49 + bne check_speed_two + lda #1 + sta road_speed + rts +check_speed_two: + cmp #50 + bne check_speed_three + lda #2 + sta road_speed + rts +check_speed_three: + cmp #51 + bne controls_done + lda #3 + sta road_speed +controls_done: + rts + +apply_palette: + ; Blank the display while color RAM is refreshed, avoiding a partial frame. + lda $d011 + sta display_d011 + and #$ef + sta $d011 + lda palette + asl + asl + tax + lda palette_colors,x + sta sky_color + inx + lda palette_colors,x + sta horizon_color + inx + lda palette_colors,x + sta road_color + inx + lda palette_colors,x + sta sun_color + ldx #0 +color_row_loop: + stx row_index + cpx #8 + bcc use_sky_color + cpx #10 + bcc use_horizon_color + lda road_color + bne color_selected +use_horizon_color: + lda horizon_color + bne color_selected +use_sky_color: + lda sky_color +color_selected: + sta row_color + lda color_row_lo,x + sta $fb + lda color_row_hi,x + sta $fc + ldy #0 +color_columns: + lda row_color + sta ($fb),y + iny + cpy #40 + bne color_columns + ldx row_index + inx + cpx #25 + bne color_row_loop + lda sun_color + sta $d027 + lda display_d011 + sta $d011 + rts + +initialize_sid: + jsr silence_sid + lda #$08 + sta $d402 + lda #$08 + sta $d403 + lda #$09 + sta $d405 + lda #$88 + sta $d406 + lda #$04 + sta $d40c + lda #$a6 + sta $d40d + lda #$02 + sta $d413 + lda #$84 + sta $d414 + lda #$0f + sta $d418 + rts + +update_music: + inc music_tick + lda music_tick + cmp #5 + bcc music_done + lda #0 + sta music_tick + ldx music_step + lda #0 + sta $d404 + sta $d40b + sta $d412 + lda lead_sequence,x + tay + lda note_lo,y + sta $d400 + lda note_hi,y + sta $d401 + lda #$41 + sta $d404 + lda bass_sequence,x + tay + lda note_hi,y + lsr + sta $d408 + lda note_lo,y + ror + sta $d407 + lda #$11 + sta $d40b + lda drum_sequence,x + beq no_drum + lda #$26 + sta $d40e + lda #$19 + sta $d40f + lda #$81 + sta $d412 +no_drum: + inc music_step + lda music_step + and #15 + sta music_step +music_done: + rts + +silence_sid: + lda #0 + sta $d404 + sta $d40b + sta $d412 + sta $d418 + rts + +wait_raster: +wait_raster_enter: + cmp $d012 + bne wait_raster_enter +wait_raster_leave: + cmp $d012 + beq wait_raster_leave + rts + +show_splash: + lda #147 + jsr CHROUT + lda #splash_text + sta $fc +print_splash: + ldy #0 + lda ($fb),y + beq wait_for_space + jsr CHROUT + inc $fb + bne print_splash + inc $fc + jmp print_splash +wait_for_space: + jsr GETIN + cmp #32 + bne wait_for_space + rts + +exit_demo: + jsr silence_sid + ldx #0 +restore_sid_loop: + lda old_sid,x + sta $d400,x + inx + cpx #25 + bne restore_sid_loop + lda old_sprite_enable + sta $d015 + lda old_sprite_msb + sta $d010 + lda old_sprite_expand_y + sta $d017 + lda old_sprite_expand_x + sta $d01d + lda old_sprite_priority + sta $d01b + lda old_sprite_x + sta $d000 + lda old_sprite_y + sta $d001 + lda old_sprite_color + sta $d027 + lda old_sprite_pointer + sta $07f8 + lda old_dd00 + sta $dd00 + lda old_d018 + sta $d018 + lda old_d016 + sta $d016 + lda old_d011 + sta $d011 + lda old_border + sta $d020 + lda old_background + sta $d021 + lda #147 + jsr CHROUT + rts + +splash_text: +!byte 13,13,13,154 +!text " INFINITE ROAD" +!byte 13,13,5 +!text " AN ENDLESS SYNTHWAVE NIGHT DRIVE" +!byte 13,13,13,153 +!text " CONTROLS" +!byte 13,13,158 +!text " A/D" +!byte 5 +!text " VIEW " +!byte 158 +!text "1-3" +!byte 5 +!text " SPEED " +!byte 158 +!text "C" +!byte 5 +!text " COLOR" +!byte 13 +!text " " +!byte 158 +!text "M" +!byte 5 +!text " MUSIC " +!byte 158 +!text "SPACE" +!byte 5 +!text " PAUSE " +!byte 158 +!text "Q" +!byte 5 +!text " QUIT" +!byte 13,13,13,5 +!text " HTTPS://C64.P20.DEV" +!byte 13,13,152 +!text " RELEASED 21 OCTOBER 2026" +!byte 13,13,13,158 +!text " PRESS SPACE TO START" +!byte 0 + +; Perspective and scene tables. +road_half_width: !byte 2,3,4,5,6,7,8,9,10,11,13,15,17,18,19 +curve_offsets: !byte 0,1,2,3,5,7,9,12,15,18,21,24,27,30,33 +curve_centers: +!byte 20,20,20,21,21,21,22,22,22,23,23,23,23,23,23,23 +!byte 23,23,23,23,23,23,23,22,22,22,21,21,21,20,20,20 +!byte 20,20,20,19,19,19,18,18,18,17,17,17,17,17,17,17 +!byte 17,17,17,17,17,17,17,18,18,18,19,19,19,20,20,20 + +star_rows: !byte 1,1,2,2,3,3,4,4,5,5,6,6,7,7,2,3,5,6,1,4,6,7 +star_columns: !byte 3,34,8,28,16,37,5,31,12,25,2,35,18,38,21,1,33,9,24,19,29,14 +mountain_columns: +!byte 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 +!byte 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 +mountain_chars: +!byte 19,19,18,19,18,18,19,19,18,19,19,18,18,18,19,19,18,19,18,19 +!byte 19,18,19,19,18,18,19,18,19,19,19,18,18,19,19,18,19,18,19,19 + +palette_colors: !byte 3,4,11,7,14,6,12,1,10,2,9,8 +note_lo: !byte $c4,$22,$81,$e1,$4b,$b8,$2a,$a1 +note_hi: !byte $10,$13,$15,$18,$1b,$1e,$22,$26 +lead_sequence: !byte 0,2,4,5,4,2,7,5,0,2,4,6,5,4,2,1 +bass_sequence: !byte 0,0,0,0,3,3,3,3,5,5,5,5,3,3,1,1 +drum_sequence: !byte 1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0 + +row_lo: +!for row,0,24 { !byte <(row*40) } +row_hi: +!for row,0,24 { !byte >(row*40) } +color_row_lo: +!for row,0,24 { !byte <($d800+row*40) } +color_row_hi: +!for row,0,24 { !byte >($d800+row*40) } + +screen_base_hi: !byte 0 +front_buffer: !byte 0 +curve_phase: !byte 0 +road_phase: !byte 0 +road_speed: !byte 0 +view_index: !byte 0 +palette: !byte 0 +paused: !byte 0 +music_muted: !byte 0 +quit_flag: !byte 0 +music_tick: !byte 0 +music_step: !byte 0 +row_index: !byte 0 +road_center: !byte 0 +road_left: !byte 0 +road_right: !byte 0 +sky_color: !byte 0 +horizon_color: !byte 0 +road_color: !byte 0 +sun_color: !byte 0 +row_color: !byte 0 +display_d011: !byte 0 + +old_border: !byte 0 +old_background: !byte 0 +old_d011: !byte 0 +old_d016: !byte 0 +old_d018: !byte 0 +old_dd00: !byte 0 +old_sprite_enable: !byte 0 +old_sprite_msb: !byte 0 +old_sprite_expand_y: !byte 0 +old_sprite_expand_x: !byte 0 +old_sprite_priority: !byte 0 +old_sprite_x: !byte 0 +old_sprite_y: !byte 0 +old_sprite_color: !byte 0 +old_sprite_pointer: !byte 0 +old_sid: !fill 25,0 + +; Custom 8x8 character set at $3000. Only the scene glyphs are populated. +* = $3000 +!fill 8,0 ; 0 blank +!byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff ; 1 solid +!byte $80,$c0,$e0,$f0,$f8,$fc,$fe,$ff ; 2 left road edge +!byte $01,$03,$07,$0f,$1f,$3f,$7f,$ff ; 3 right road edge +!byte $00,$00,$18,$18,$18,$18,$00,$00 ; 4 lane marker +!byte $00,$10,$54,$38,$fe,$38,$54,$10 ; 5 star +!byte $88,$22,$88,$22,$88,$22,$88,$22 ; 6 road texture A +!byte $22,$88,$22,$88,$22,$88,$22,$88 ; 7 road texture B +!byte $3c,$7e,$ff,$ff,$ff,$ff,$7e,$3c ; 8 sun solid +!byte $3c,$7e,$ff,$00,$00,$ff,$7e,$3c ; 9 sun stripe +!byte $00,$00,$01,$03,$07,$0f,$1f,$3f ; 10 sun top left +!byte $00,$00,$ff,$ff,$ff,$ff,$ff,$ff ; 11 sun top middle +!byte $00,$00,$80,$c0,$e0,$f0,$f8,$fc ; 12 sun top right +!byte $3f,$7f,$ff,$ff,$ff,$ff,$7f,$3f ; 13 sun left +!byte $fc,$fe,$ff,$ff,$ff,$ff,$fe,$fc ; 14 sun right +!byte $3f,$1f,$0f,$07,$03,$01,$00,$00 ; 15 sun bottom left +!byte $ff,$ff,$ff,$ff,$ff,$ff,$00,$00 ; 16 sun bottom middle +!byte $fc,$f8,$f0,$e0,$c0,$80,$00,$00 ; 17 sun bottom right +!byte $00,$08,$1c,$3e,$7f,$ff,$ff,$ff ; 18 mountain peak +!byte $00,$00,$00,$08,$1c,$3e,$7f,$ff ; 19 low mountain +!fill 1888,0 + +; 24x21 striped sun sprite, displayed double width and height. +* = $3800 +!byte $00,$7e,$00,$01,$ff,$80,$03,$ff,$c0,$07,$ff,$e0 +!byte $0f,$ff,$f0,$1f,$ff,$f8,$3f,$ff,$fc,$3f,$ff,$fc +!byte $00,$00,$00,$3f,$ff,$fc,$00,$00,$00,$1f,$ff,$f8 +!byte $00,$00,$00,$0f,$ff,$f0,$00,$00,$00,$07,$ff,$e0 +!byte $00,$00,$00,$03,$ff,$c0,$01,$ff,$80,$00,$7e,$00 +!byte $00,$3c,$00,$00 diff --git a/infinite-road/infinite-road.prg b/infinite-road/infinite-road.prg new file mode 100644 index 0000000000000000000000000000000000000000..f938b4fcdcac5d3339944d59a7de1bfb2ca6cee8 GIT binary patch literal 12353 zcmeHMTWr%+82|tK@4uIAUGM!mF79jytR}*kgiJ#mb*rvgwy~BeFQzXhVl**6@giU% z32KfR@j*0kB0<%*%wMG66hfI>hapb$_9{7(=dPxzQdiJ(n_yc{B>w`Q@ z6&l3P*|}WlUZDGcjsP76`U%hjKsnHlfjKAxW~0M^n)`vD0k=W5@Aw47K6Lx2U+^5n zrra(X5o|lv1WQp}U`nw&)F&`0w@yJ|TDUJ1m>BN!1uIZYW!lSh8WwB;jS8~HPr8F- zBA8`%x(CRMezL>Q>h3vS^H-&~OA#i&t;F}hwwc|=E{$nBN>{{h*JnNzw`XsYQ{vYw zzIRh(czg|PD~)e}=u1+6;_V1Cca)|I5pivo`)(QPe-@e86OrN;aVyI|hN7L>g{=}Z zb#2ugX*%ZFcO#*PwtoGN&+&3^D_`Cc>`#ssjmd|&nK#2U*7C3P$q7{{B!|1UMPqN3d`GZw@|-FpR*+sGJhJMQbe@uyQ^a9@l_s*0>9(Zm~Fuas-(!c#^s-l)XTm7W1Qe zt`&-2wuIJOtbuwh_8QvX90fiKF)vP}9Md_sGVbRAAxgLuOIh{~`KrvE+e$1fUwE)o ztV722lDKt!CiQ9v3yUTAO+F19I}aadR%P({B;f4vvmnRx9LOO(4{}5=01ha>h-nLc z3DXw*as{C)fHRBZFNgm$V9(&-Wcqtk zX^&@!#FuxOWFVP%nvkIt4?bj)bYCLTg_lkf^-{h4o>}9ewI*4+KAr4DS-LOYnJ`IT ze0@5B*L5aYw?3J{NHU>W>ds{P(vK`(-nnY!vc9&~WnGB@k7wtcv_Fwb#M2n4Z3XG= z%=A8%=qGKhZL847(3}qG>#w{@1|ykXlFr2YGn&n?n+~VTT~q7v`U62tw;86>UFQvi zqx0`;3WY-9a5xf)z+Hq4WTOx%7z_pi0smcu3}mBF*KIb#u-i@3;cz<9wL`Z%oJO;2 zfp4+dSl3`%6j&10o7~ah!g?8cE|)q_z1N57gu)SsHq4v9VBvj@q^Wt){fn0@#dsJ| zt}<}tHhYn*SrMKLd#$tHQK#3~+^!4FuYLd2i3dLN1?97vmuNP-X}38|+#Pt(<(~lt zl8Iy(x-J=daJ4?Oby!T3?w5B?N<$>HK(bXyIx_yz;%b$? zuFyAC`c_ialUfx53ITy)5Kssx1QY@a0fm4dq$%Cod}vQV6!xl`5+r?;_VOIg#RNa)L#X}{B+@ojIeerC7rt2ax-&8uy)5Kssx1pXBQn>D?>)hJIo%LQ+_*jS$KD9_*z+E!QO;2A}@q7JU8j3(Mz Fe*#!*Fa7`k literal 0 HcmV?d00001 diff --git a/programs.json b/programs.json index a5d2f6f..0055663 100644 --- a/programs.json +++ b/programs.json @@ -190,5 +190,11 @@ "description": "Enter a neon-colored world of orbiting sprites, a scrolling message, and a three-voice SID score.", "controls": [{"keys":["1","2","3"],"description":"Select slow, medium, or fast motion"},{"keys":["C"],"description":"Change the visual palette"},{"keys":["M"],"description":"Mute or restore the SID track"},{"keys":["SPACE"],"description":"Pause or resume the demo"},{"keys":["Q"],"description":"Return to BASIC"}], "path": "neon-rift/neon-rift.prg", "source": "neon-rift/neon-rift.asm" + }, + { + "title": "Infinite Road", "category": "Demo", "language": "machine-code", "releaseDate": "2026-10-21", + "description": "Cruise along an endless synthwave highway with sweeping curves and a driving three-voice SID score.", + "controls": [{"keys":["A","D"],"description":"Shift the viewpoint left or right"},{"keys":["1","2","3"],"description":"Select slow, medium, or fast cruising speed"},{"keys":["C"],"description":"Change the color palette"},{"keys":["M"],"description":"Mute or restore the SID track"},{"keys":["SPACE"],"description":"Pause or resume the demo"},{"keys":["Q"],"description":"Return to BASIC"}], + "path": "infinite-road/infinite-road.prg", "source": "infinite-road/infinite-road.asm" } ] diff --git a/scripts/build-machine-code.sh b/scripts/build-machine-code.sh index 5eb6474..6239638 100644 --- a/scripts/build-machine-code.sh +++ b/scripts/build-machine-code.sh @@ -13,7 +13,8 @@ for source in \ petscii-aquarium/petscii-aquarium.asm \ fifteen-puzzle/fifteen-puzzle.asm \ plasma-grid/plasma-grid.asm \ - neon-rift/neon-rift.asm + neon-rift/neon-rift.asm \ + infinite-road/infinite-road.asm do output="${source%.asm}.prg" echo "Assembling $source -> $output"