| author | Alan Dipert
<alan@tailrecursion.com> 2026-02-20 20:12:27 UTC |
| committer | Alan Dipert
<alan@tailrecursion.com> 2026-02-20 20:12:27 UTC |
| parent | c25558c2d78c5538735373d4336f183632d66eb5 |
| md/_GridCalc.md | +94 | -0 |
| md/_GridCalc/byte_gridcalc.png | +0 | -0 |
| md/_GridCalc/clp_calc.png | +0 | -0 |
| md/_GridCalc/gridcalc_3-0.png | +0 | -0 |
| md/_GridCalc/notebook_idea.jpg | +0 | -0 |
| tools/gen_index.py | +3 | -1 |
diff --git a/md/_GridCalc.md b/md/_GridCalc.md new file mode 100644 index 0000000..2acc38d --- /dev/null +++ b/md/_GridCalc.md @@ -0,0 +1,94 @@ +<figure style="float: right; margin: 0 0 1rem 1rem; width: 260px;"> + <img src="./_GridCalc/gridcalc_3-0.png" alt="GridCalc UI" width="100%" /> + <figcaption style="font-size: 0.9em; font-style: italic;">GridCalc in its current layout.</figcaption> +</figure> + +# GridCalc + +An [RPN](https://en.wikipedia.org/wiki/Reverse_Polish_notation) Spreadsheet for iOS + +Created Friday 20 February 2026 + +- [Demo video](https://youtu.be/M0HwzrGGuyc) +- [App Store](https://apps.apple.com/no/app/gridcalc/id6759011187) + +I built GridCalc because I wanted a spreadsheet that felt native to a phone and native to my brain, combining the efficiency of RPN with the reusability of spreadsheets. + +What follows is a retrospective on how that happened, why it looks the way it does, and what is going on inside the app. + +## The seed: Forth and touchscreens + +I learned [Forth](https://en.wikipedia.org/wiki/Forth_(programming_language)) around 2011, and what stuck with me was not just the stack but the flatness of the syntax: words, space-separated, linear, no parentheses, no precedence, a stream of tokens in plain sight. + +It felt like a language that wanted to be handled like physical tokens, where you drag words around, reorder them, insert one between two others, and treat the code as something you can literally move with your hands. I never prototyped that idea, but it never went away. + +## The notebook sketch + +Then, in early February 2026 I woke up and drew a sketch in a tiny 3x5 notepad. The idea was a grid that represents time. Left to right, top to bottom, every entry or operation becomes a persistent cell. The grid is not a table. It is a linear program with a 2D view so references are easy. + +The sketch shows the basics: inputs and operations flow left to right and then top to bottom, and because the program sits on a 2D grid you can reference earlier results by cell coordinates the same way you do in a spreadsheet. + +<figure style="float: left; margin: 0 1.5rem 1rem 0; width: 306px;"> + <img src="./_GridCalc/notebook_idea.jpg" alt="GridCalc notebook sketch" width="100%" /> + <figcaption style="font-size: 0.9em; font-style: italic;">The original 3x5 notebook sketch.</figcaption> +</figure> + +That sketch gave me the core unification: + +- RPN for clarity and lack of parentheses. +- Spreadsheet-style references for reusability. +- A visible, persistent history of computation. + +GridCalc is a calculator, but the program is the sheet. You do not toggle between "value view" and "formula view." The grid is both the data and the formula. + +## Why mobile spreadsheets feel wrong + +Spreadsheets are reactive systems. Change a cell and everything downstream recomputes. That is the good part. A classic use case is scratch forecasting. You have a small formula for a rate, a payment, a tip, or a physical quantity. You want to reuse the work you already did so you can tweak the inputs and see new results without retyping the whole thing. + +Technically, spreadsheets on phones deliver this. Unfortunately, traditional spreadsheets are punishing as mobile interfaces. You tap into a formula bar. You scroll sideways. You lose context. The sheet is there, but the program is buried, and editing an infix formula on a phone keyboard can be particularly frustrating. I've only ever used mobile spreadsheets for data entry, or to refer to existing sheets with formulas I made on my desktop. + +In contrast, GridCalc keeps the program visible because the grid *is* the formula. It economizes the creation of formulas on the go. Every input, and every operation, inhabit a visible cell. The grid provides a coordinate system that can be used to refer to previous values, linking them to new calculations. Much of the power of a spreadsheet is thus delivered directly to the mobile user. + +## Mobile UI evolution + +My first UI model appended two cells for every operation: one cell for the op label and a second cell for the numeric result. It was clear, but it wasted precious space. + +My friend Micha Niskin pushed me to combine them, so that every operation shared a cell with its result. That gave the grid a lot more breathing room. Later, another friend, Jesse Lundberg, suggested putting the op in a small badge that lives in the gutter between cells. That kept the value legible and made the grid readable at a glance. The combination of these two visual enhancements gave me the compact but legible layout I had been groping toward. + +## Where RPN fits + +<figure style="float: right; margin: 0 0 1rem 1rem; width: 312px;"> + <img src="./_GridCalc/clp_calc.png" alt="CLP’s Nice Calculator" width="100%" /> + <figcaption style="font-size: 0.9em; font-style: italic;">CLP’s Nice Calculator, which inspired the editable expression idea.</figcaption> +</figure> + +If you have not used [RPN](https://en.wikipedia.org/wiki/Reverse_Polish_notation), the mental model is simple. You push values and then apply operators. For example, instead of typing `(3 + 4) * 5` you type `3 4 + 5 *`. + +That model is fast and easy, once it clicks. A linear instruction stream maps cleanly onto a grid. A similar scheme is the basis for [stack machines](https://en.wikipedia.org/wiki/Stack_machine), which is probably where I first encountered the idea (many of the first Lisp compilers targeted virtual or "bytecoded" stack machines. The JVM is the world's most successful stack machine). + +But it wasn't until I encountered Christian Lawson-Perfect’s excellent [Nice Calculator](https://somethingorotherwhatever.com/items/clp-s-nice-calculator/) web app that I started to use an RPN calculator day to day. It renders expressions as editable bubbles in a tree, which is a beautiful UI idea. I wanted that same editability, but with a layout that uses screen space better on a phone, any with a way to refer symbolically to previous values and results. + +## Under the hood + +- Exact arithmetic using [Constructive Reals](https://chadnauseam.com/coding/random/calculator-app) in native Swift. I learned about Constructive Reals years ago and could not not use them. The engine evaluates lazily and caches precision requests instead of relying on floating-point shortcuts. +- Spec-generated state machines. The interaction modes, file workflows, and save states are modeled as [hierarchically nested states](https://en.wikipedia.org/wiki/UML_state_machine#Hierarchically_nested_states) with generated runtime and tests. I credit the introduction of this approach to an early tester, my son William, who is three years old. Within 10 seconds of my handing him the phone, he spammed the screen with enough keypresses that the UI entered some kind of deadlock, making it clear I needed a better approach. +- Aggressive unit testing with [XCTest](https://developer.apple.com/documentation/xctest) and [Maestro](https://maestro.mobile.dev/). + +## Note on AI and execution + +This project stalled for years because the idea only ever lived in conversations and notebooks. The advent of AI coding tools made it affordable for me to turn it into a working product and iterate quickly. That created a virtuous loop where I could see and share the app, feel the friction, and fix it. The core unification is still human. The speed of execution changed, not the need for taste or intent. + +## Closing + +GridCalc is small and opinionated. It is not Excel. It does not try to be. It is a phone-native tool for scratch modeling with a visible program. If you ever wanted RPN on your phone but also wanted to reuse your own work, I encourage you to give GridCalc a try. + +## References + +- [Constructive Reals background](https://chadnauseam.com/coding/random/calculator-app) +- [creal.js](https://github.com/christianp/creal.js) +- [CLP’s Nice Calculator (inspiration)](https://www.chrisl.org/calculator/) + +<figure style="margin: 1.5rem 0 0 0; max-width: 520px;"> + <img src="./_GridCalc/byte_gridcalc.png" alt="GridCalc magazine cover mockup" width="100%" /> + <figcaption style="font-size: 0.9em; font-style: italic;">A Byte-style mockup I made while thinking about how GridCalc might be introduced.</figcaption> +</figure> diff --git a/md/_GridCalc/byte_gridcalc.png b/md/_GridCalc/byte_gridcalc.png new file mode 100644 index 0000000..4332b02 Binary files /dev/null and b/md/_GridCalc/byte_gridcalc.png differ diff --git a/md/_GridCalc/clp_calc.png b/md/_GridCalc/clp_calc.png new file mode 100644 index 0000000..26f37f3 Binary files /dev/null and b/md/_GridCalc/clp_calc.png differ diff --git a/md/_GridCalc/gridcalc_3-0.png b/md/_GridCalc/gridcalc_3-0.png new file mode 100644 index 0000000..b9e410a Binary files /dev/null and b/md/_GridCalc/gridcalc_3-0.png differ diff --git a/md/_GridCalc/notebook_idea.jpg b/md/_GridCalc/notebook_idea.jpg new file mode 100644 index 0000000..e9fe8de Binary files /dev/null and b/md/_GridCalc/notebook_idea.jpg differ diff --git a/tools/gen_index.py b/tools/gen_index.py index cba9256..9dc5959 100755 --- a/tools/gen_index.py +++ b/tools/gen_index.py @@ -39,10 +39,12 @@ def parse_args() -> argparse.Namespace: def is_temp_path(path: Path) -> bool: - """Return True for editor swap/backup files that shouldn't appear in the index.""" + """Return True for files that shouldn't appear in the index.""" for part in path.parts: if part.startswith(".#"): return True + if part.startswith("_"): + return True if part.endswith("~"): return True return False