--- title: "ZX Typer" id: 57154 type: "computer_media" slug: "zx-typer" url: "http://localhost/computer_media/zx-typer/" markdown_url: "http://localhost/computer_media/zx-typer.md" published_at: "2024-10-04T00:58:22+00:00" modified_at: "2026-04-03T07:58:42+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/103_Type.png" excerpt: "Type any text and watch it rendered tall across the screen in chunky block graphics — each letter built from three rows of mosaic characters." 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/" indiv: - name: "Ryan Gray" slug: "ryan-gray" taxonomy: "indiv" url: "http://localhost/indiv/ryan-gray/" genre: - name: "Banner" slug: "banner" taxonomy: "genre" url: "http://localhost/type/banner/" 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" programmers: - name: "Ryan Gray" slug: "ryan-gray" taxonomy: "indiv" url: "http://localhost/indiv/ryan-gray/" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/103_Type.png" media_type_tags: "Banner" --- # ZX Typer This program renders user-input text as large block-graphic characters, three display rows tall, using the ZX Spectrum’s block graphics (chars 128–143). After accepting a string via INPUT, it iterates through each character, dispatches to a subroutine via the computed GOSUB formula (CODE A$(A)-25)*100, and draws the corresponding block-graphic glyph at position (X,Y) on screen. Characters are laid out in a grid of 3-row-high cells, advancing Y by 3 each step and wrapping to the next row (incrementing X by 3) after every 10 characters. The program covers letters and digits, with each glyph defined by three PRINT AT statements using block graphics to approximate each character’s shape. *** ## Program Analysis ### Program Structure The program is organised into three logical areas: 1. **Initialisation and input (lines 10–93):** REMs serve as a title banner (displaying “ZX-TYPER” in inverse video). Lines 20–24 initialise cursor positions and accept a string, capping its length at 70 characters. 2. **Main loop (lines 30–93):** Iterates over each character of the input string, skips spaces and low punctuation, computes a subroutine address, draws the glyph, and advances the layout cursor. 3. **Glyph subroutines (lines 200–3803):** Each subroutine draws a single block-graphic character using three `PRINT AT` statements, then RETURNs. Subroutine numbers are multiples of 100, and the dispatch formula maps ASCII codes directly to them. ### Dispatch Mechanism The key idiom is at line 60: `GOSUB (CODE A$(A)-25)*100` This translates a character’s ASCII code into a subroutine line number. For example, the space character (ASCII 32) gives (32−25)×100 = 700, which is the subroutine for the letter corresponding to that slot. The mapping is: | Character | ASCII | Formula result | Subroutine | | --- | --- | --- | --- | | ! | 33 | 800 | line 800 | | “ | 34 | 900 | line 900 | | 0–9 | 48–57 | 2300–3200 | lines 2300–3200 | | A–Z | 65–90 | 4000–6500 | (not all present) | In practice, examining the subroutines present (200 through 3803), the covered range maps to punctuation and digits. The letter subroutines starting at line 200 correspond to the `.` character (ASCII 46, giving (46−25)×100 = 2100), and so on. The actual character set rendered covers roughly `.` through `Z` in ASCII order, one subroutine per character. ### Layout and Cursor Management Two variables, `X` and `Y`, track the current glyph position on screen. Each glyph occupies a 3×3 block-graphics cell. After drawing each character, `Y` is incremented by 3 (line 70). When `Y` reaches 30 — the right edge of the 32-column display at this granularity — it wraps to 0 and `X` advances by 3 (lines 80–83), moving down to the next row of glyphs. This allows up to 10 glyphs per row and multiple rows. ### Input Filtering Lines 40 and 50 handle character filtering: - Line 40 skips space characters entirely (`GOTO 70` advances `Y` without drawing). - Line 50 skips any character with ASCII code below `.` (46) but above space (32) — i.e., punctuation characters `!` through `-` — by executing `NEXT A` directly, skipping both the GOSUB and the Y-advance. This means those characters are silently ignored rather than advancing the cursor. Note that line 50’s skip via `NEXT A` bypasses the Y-increment at line 70, so ignored characters do not consume layout space, which may or may not be the intended behaviour. ### Glyph Rendering with Block Graphics Each glyph subroutine uses two or three `PRINT AT X+row, Y+col; "..."` statements. The strings contain ZX Spectrum block graphic characters (codes 128–143), which each encode a 2×2 pixel pattern within a single character cell. By combining these, each glyph is rendered at approximately 6×6 pixel resolution across a 3-row, 3-column region of the text screen. Some glyphs use offset column positions (e.g., `PRINT AT X+2,Y+1`) to handle narrower characters such as `1`, `I`, and `!`. ### Notable Techniques - **Computed GOSUB:** Using an arithmetic expression as the GOSUB target is an efficient alternative to a long IF-THEN chain for character dispatch. - **Input loop:** After rendering, lines 91–93 wait for another INPUT, clear the screen with `CLS`, then `RUN` restarts the program, resetting `X` and `Y` to zero for a fresh display. - **Title in REMs:** Lines 10–12 display a bordered title “ZX-TYPER” using inverse-video characters purely as documentation/display in the program listing. - **String length cap:** Line 24 clamps input to 70 characters, preventing the layout loop from overrunning screen bounds. ### Anomalies and Notes - Line 1400 skips from statement 1400 to 1402 — line 1401 is absent. This is harmless as subroutine execution falls through sequentially, but the missing line number is unusual. - The `Y=30` wrap condition (line 80) allows 10 three-column glyphs per row (columns 0, 3, 6, …, 27), but with the 3-column glyph width the last glyph starts at column 27 and prints up to column 29, fitting within the 32-column display. - Lines 3810–3820 (`SAVE "1010%3"` followed by `RUN`) appear at the end of the glyph table and are not part of the normal execution flow; they are used to save the program. - The author credit appears as an inverse-video REM at line 9999: “RYAN GRAY”. ## Source Code ``` 10 REM % % % % % % % % % % 11 REM % %Z%X%-%T%Y%P%E%R% 12 REM % % % % % % % % % % 20 LET X=0 21 LET Y=0 22 INPUT A$ 23 LET C=LEN A$ 24 IF C>70 THEN LET C=70 30 FOR A=1 TO C 40 IF A$(A)=" " THEN GOTO 70 50 IF A$(A)<"." AND A$(A)>" " THEN NEXT A 60 GOSUB (CODE A$(A)-25)*100 70 LET Y=Y+3 80 IF Y=30 THEN GOTO 82 81 GOTO 90 82 LET Y=0 83 LET X=X+3 90 NEXT A 91 INPUT A$ 92 CLS 93 RUN 200 PRINT AT X+2,Y+1;"' " 201 RETURN 300 PRINT AT X,Y;".'':. " 301 PRINT AT X+1,Y;":.' : " 302 PRINT AT X+2,Y;" '''" 311 RETURN 400 PRINT AT X,Y;" .: " 401 PRINT AT X+1,Y+1;": " 402 PRINT AT X+2,Y;" '''" 406 RETURN 500 PRINT AT X,Y;".'''. " 501 PRINT AT X+1,Y;" .''" 502 PRINT AT X+2,Y;"''''' " 511 RETURN 600 PRINT AT X,Y;".'''. " 601 PRINT AT X+1,Y;". ''. " 602 PRINT AT X+2,Y;" '''" 610 RETURN 700 PRINT AT X,Y;" .':" 701 PRINT AT X+1,Y;":..:. " 702 PRINT AT X+2,Y+1;" '" 707 RETURN 800 PRINT AT X,Y;":'''' " 801 PRINT AT X+1,Y;"''''. " 802 PRINT AT X+2,Y;"''''" 808 RETURN 900 PRINT AT X,Y;".'''" 901 PRINT AT X+1,Y;":'''. " 902 PRINT AT X+2,Y;" '''" 907 RETURN 1000 PRINT AT X,Y;"'''': " 1001 PRINT AT X+1,Y+1;".'" 1002 PRINT AT X+2,Y;" '" 1005 RETURN 1100 PRINT AT X,Y;".'''. " 1101 PRINT AT X+1,Y;".'''. " 1102 PRINT AT X+2,Y;" '''" 1109 RETURN 1200 PRINT AT X,Y;".'''. " 1201 PRINT AT X+1,Y;" ''': " 1202 PRINT AT X+2,Y;" '''" 1207 RETURN 1300 PRINT AT X,Y;".'''. " 1301 PRINT AT X+1,Y;":''': " 1302 PRINT AT X+2,Y;"' ' " 1303 RETURN 1400 PRINT AT X,Y;":'''. " 1402 PRINT AT X+1,Y;":'''. " 1403 PRINT AT X+2,Y;"''''" 1409 RETURN 1500 PRINT AT X,Y;".'''. " 1501 PRINT AT X+1,Y;": . " 1502 PRINT AT X+2,Y;" '''" 1507 RETURN 1600 PRINT AT X,Y;":'''. " 1601 PRINT AT X+1,Y;": : " 1602 PRINT AT X+2,Y;"''''" 1608 RETURN 1700 PRINT AT X,Y;":'''' " 1701 PRINT AT X+1,Y;":'''" 1702 PRINT AT X+2,Y;"''''' " 1707 RETURN 1800 PRINT AT X,Y;":'''' " 1801 PRINT AT X+1,Y;":'''" 1802 PRINT AT X+2,Y;"' " 1803 RETURN 1900 PRINT AT X,Y;".'''' " 1901 PRINT AT X+1,Y;": '': " 1902 PRINT AT X+2,Y;" '''' " 1903 RETURN 2000 PRINT AT X,Y;": : " 2001 PRINT AT X+1,Y;":''': " 2002 PRINT AT X+2,Y;"' ' " 2003 RETURN 2100 PRINT AT X,Y;" ':'" 2101 PRINT AT X+1,Y+1;": " 2102 PRINT AT X+2,Y;" '''" 2103 RETURN 2200 PRINT AT X,Y+2;": " 2201 PRINT AT X+1,Y;". : " 2202 PRINT AT X+2,Y;" '''" 2203 RETURN 2300 PRINT AT X,Y;": .' " 2301 PRINT AT X+1,Y;":''." 2302 PRINT AT X+2,Y;"' ' " 2303 RETURN 2400 PRINT AT X,Y;": " 2401 PRINT AT X+1,Y;": " 2402 PRINT AT X+2,Y;"''''' " 2403 RETURN 2500 PRINT AT X,Y;":. .: " 2501 PRINT AT X+1,Y;": ' : " 2502 PRINT AT X+2,Y;"' ' " 2503 RETURN 2600 PRINT AT X,Y;":. : " 2601 PRINT AT X+1,Y;": '.: " 2602 PRINT AT X+2,Y;"' ' " 2603 RETURN 2700 PRINT AT X,Y;".'''. " 2701 PRINT AT X+1,Y;": : " 2702 PRINT AT X+2,Y;" '''" 2703 RETURN 2800 PRINT AT X,Y;":'''. " 2801 PRINT AT X+1,Y;":'''" 2802 PRINT AT X+2,Y;"' " 2803 RETURN 2900 PRINT AT X,Y;".'''. " 2901 PRINT AT X+1,Y;": '.' " 2902 PRINT AT X+2,Y;" '' ' " 2903 RETURN 3000 PRINT AT X,Y;":'''. " 3001 PRINT AT X+1,Y;":'':" 3002 PRINT AT X+2,Y;"' ' " 3003 RETURN 3100 PRINT AT X,Y;".'''" 3101 PRINT AT X+1,Y;" '''. " 3102 PRINT AT X+2,Y;" '''" 3103 RETURN 3200 PRINT AT X,Y;"'':'' " 3201 PRINT AT X+1,Y+1;": " 3202 PRINT AT X+2,Y+1;"' " 3203 RETURN 3300 PRINT AT X,Y;": : " 3301 PRINT AT X+1,Y;": : " 3302 PRINT AT X+2,Y;" '''" 3303 RETURN 3400 PRINT AT X,Y;": : " 3401 PRINT AT X+1,Y;" : :" 3402 PRINT AT X+2,Y+1;"' " 3403 RETURN 3500 PRINT AT X,Y;": : " 3501 PRINT AT X+1,Y;": : : " 3502 PRINT AT X+2,Y;" ' '" 3503 RETURN 3600 PRINT AT X,Y;"'. .' " 3601 PRINT AT X+1,Y;" .'." 3602 PRINT AT X+2,Y;"' ' " 3603 RETURN 3700 PRINT AT X,Y;"'. .' " 3701 PRINT AT X+1,Y+1;": " 3702 PRINT AT X+2,Y+1;"' " 3703 RETURN 3800 PRINT AT X,Y;"''':' " 3801 PRINT AT X+1,Y;" .' " 3802 PRINT AT X+2,Y;"''''' " 3803 RETURN 3810 SAVE "1010%3" 3820 RUN 9999 REM % %R%Y%A%N% %G%R%A%Y% ```