2026-06-06 To Type a Tale devlog
Rework inception almost complete
published: Sat 06 June 2026Posting today as I'll be busy all of Sunday.
The big news this week is that I've finished the nested rework (separating save files) and I am almost done with the main rework (adding graphics). The save rework involved complete rewrites of a lot of my code, but it provides a lot of benefits moving forward. There were also some nice user-facing changes which resulted from that.
Unfortunately, I have to start with the bad news: the save rework will have erased all your progress if you played on older versions. This was necessary due to the sheer number of logic changes I had, but I don't foresee ever having to do this again. The big good news is that typing progress is now saved! So if you type a few words, quit, and reopen, those words will remain typed/collected. Because of how these are stored, I also got the side benefit that I can write out a plaintext version of the story with your choices when you reach an ending, allowing you to reread your version of the story at your leisure. You can find these in %APPDATA%\To Type a Tale\saves. Completed paragraphs on repeat playthroughs also behave much better due to these changes: they are only collected once, instead of every time the paragraph is viewed; if you have the 30% option set, the words that were not collected (and all challenge words!) remain typeable; this pre-collection no longer affects WPM/LPM; and the words fly to the bank from the center of the screen, rather than some point offscreen.
The graphics for the unrolled portion of the scroll are now complete, and you can see the scrolling animation whenever you move to the next page or previous. Speaking of, the previous page command will now try to cram in a full screen's worth of text, rather than just the small amount that was collected previously. The downside to these two new features is that I had to disable typing during animations, as there are a lot of weird edge cases that arise from that. I began work on the rolled-up portions of the scroll and those should be available in Monday's build, or Tuesday's at the latest.
The backend has massive changes all over the codebase, so I'll only mention a few standout cases that might help other developers. Paragraphs (the base form of text content in the game) are now handled by 3 different classes: ParagraphGenerator takes raw tiac text, processes inventory and text replacement, and builds a Paragraph object to hand off to the main code; Paragraph handles communication between input, display, and storage while acting as the container for the Control nodes which actually display the text; finally, GeneratedParagraph acts as the storage pickler for the save files, holding the generated text as well as which words were typed. This separation of concerns allows me to quickly know where each belongs in my codebase.
Since the addition of table-of-contents pages, I've been struggling with special cases where a Chapter object is not loaded, requiring null handling and separate logic for such cases. I finally bit the bullet and transformed all the special cases into their own Chapter objects: the intro message is now part of the tutorial chapter, the chapter TOCs are automatically generated via inheritance, and the story list is a chapter in the menus story.
Due to how the save file objects (e.g. ChapterProgress) handle their own saving/loading, I've been able to add immediate saving for a number of actions. Previously, progress wouldn't save until the save timer (set to every 5 minutes) looped or the player quit. Now, changing chapters or other big actions will immediately save off progress in case of a crash or power outage.
Finally, the stories themselves had a minor rework. I was finding the various methods of breaking up pages (join, pageable, etc.) to have overlapping duties and generally be confusing. I wrote down each of my use cases and came up with four that I need: pageable (determines whether the player can use next page to gather more text from the chapter), pausebefore & pauseafter (interrupt chapter's gathering of paragraphs before/after the given paragraph, to allow suspense or readability), and pagebreak (acts the same as pausebefore, but also performs the same when viewing previous pages, again for readability and story reasons). This means I no longer have the join command, as I only ever really used it in the same way as pausebefore or pauseafter. The choice command remains as a helper that sets both pauses and disables paging.
My main task next week is finishing the graphics rework and putting together better QA practices. Too many bugs slip by me and I don't learn about them until my friends (thank you, Matthew, Squish, and Brittany!) notify me, which could be several days of that build sitting out there in a buggy state. This would be unacceptable for a public release, so I need to put together proper QA test scenarios and run through them every time I plan to push to Steam/itch.