--- title: "Fire Works Black on White" id: 57145 type: "computer_media" slug: "fire-works-black-on-hite" url: "http://localhost/computer_media/fire-works-black-on-hite/" markdown_url: "http://localhost/computer_media/fire-works-black-on-hite.md" published_at: "2024-10-04T00:48:49+00:00" modified_at: "2026-03-30T21:19:31+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/94_FrWrk.png" excerpt: "A relentless display-file painter that floods three screen positions and their neighbours with cycling character codes, looping forever to animate the result." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" media_contents: - id: 56733 title: "Timex Sinclair Public Domain Library Tape 1002" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1002/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/94_FrWrk.png" media_type_tags: "Demo" --- # Fire Works Black on White This program continuously writes character codes into the ZX81/TS1000 display file to create a flashing visual effect across three fixed screen positions. It uses two parallel arrays: P holds three memory addresses within the display file (17531, 17210, 17484), and C holds three character codes (27, 23, 0) that are cycled through. For each combination of position and character, it also writes the same value to eight surrounding cells—horizontal neighbours (±Z columns) and vertical neighbours (±33*Z rows, since each display-file row is 33 bytes wide including the NEWLINE byte). The program loops infinitely via RUN at line 60, creating an animated pattern, and line 70 saves the program under a filename. *** ## Program Analysis ### Program Structure The program is divided into two phases: initialisation (lines 1–8) and execution (lines 10–80). Lines 1–4 populate a three-element array `P` with absolute addresses in the display file. Lines 5–8 populate a three-element array `C` with character codes to write. Lines 10–50 form a triple nested loop that POKEs values into the display file, and line 60 restarts the whole program via `RUN`, creating an infinite animation loop. ### Array Usage | Array | Index | Value | Role | | --- | --- | --- | --- | | `P` | 1 | 17531 | Display-file address, position 1 | | `P` | 2 | 17210 | Display-file address, position 2 | | `P` | 3 | 17484 | Display-file address, position 3 | | `C` | 1 | 27 | Character code (typically a block graphic or keyword token) | | `C` | 2 | 23 | Character code | | `C` | 3 | 0 | Character code 0 (space/clear) | ### Display File Geometry Each row in the ZX81/TS1000 display file occupies 33 bytes: 32 character cells plus a trailing `NEWLINE` (76H) byte. The program exploits this directly: horizontal neighbours are reached by `±Z`, and vertical neighbours by `±33*Z`. The eight POKEs in the inner loop (lines 31–38) therefore write to all eight cells in a diamond/square pattern around the central address, with `Z` ranging from 1 to 3, producing concentric rings of the same character. ### Notable Techniques - **Flat-address POKEing:** Rather than computing screen coordinates, the program stores pre-calculated display-file addresses directly in array `P`, avoiding any coordinate arithmetic at runtime. - **Eight-directional flood fill:** Lines 31–38 methodically cover all eight compass directions around the centre point, effectively stamping a filled square of side `2*Z+1` for each value of `Z`. - **Infinite loop via RUN:**`RUN` at line 60 reinitialises variables and restarts from line 1 each iteration, so the arrays are rebuilt every cycle. This means the visual effect is re-applied from scratch each loop rather than being incremental. - **No PAUSE or input:** The animation runs at full interpreter speed with no deliberate delay, so the cycling effect will be rapid. ### Bugs and Anomalies - **No boundary checking:** The POKE expressions `P(X)±Z` and `P(X)±33*Z` can potentially write into NEWLINE bytes or adjacent rows when a position is near the start or end of a display-file row, corrupting the display-file structure. - **Overwrite sequence:** Because the outer loop cycles through all three values of `C` for each position in a single pass, only the last value written (`C(3)=0`) will remain visible after the inner `Y` loop completes, effectively clearing everything before `RUN` restarts. The intermediate writes produce flicker rather than a lasting pattern. - **Line 80 unreachable:** The `SAVE` at line 70 and `RUN` at line 80 are never reached during normal execution because line 60 always loops back to the start. ## Source Code ``` 1 DIM P(3) 2 LET P(1)=17531 3 LET P(2)=17210 4 LET P(3)=17484 5 DIM C(3) 6 LET C(1)=27 7 LET C(2)=23 8 LET C(3)=00 10 FOR X=1 TO 3 20 FOR Y=1 TO 3 25 POKE P(X),C(Y) 30 FOR Z=1 TO 3 31 POKE P(X)+Z,C(Y) 32 POKE P(X)-Z,C(Y) 33 POKE P(X)-33*Z,C(Y) 34 POKE P(X)+33*Z,C(Y) 35 POKE P(X)-Z-33*Z,C(Y) 36 POKE P(X)-Z+33*Z,C(Y) 37 POKE P(X)+Z-33*Z,C(Y) 38 POKE P(X)+Z+33*Z,C(Y) 39 NEXT Z 40 NEXT Y 50 NEXT X 60 RUN 70 SAVE "1009%4" 80 RUN ```