Flora Servers: Brainstorm
Backend services for the zone ecosystem. UI handled by canopy (~/git/canopy); these are headless servers.
The Absurd Moonshot
The real, fundamental goal: subsuming virtually all interaction with a computer.
- Of course it'll never happen
- Of course it won't take off
- Of course there's tradeoffs
- But what if? What would it look like?
This is the "what if?" question carried to its logical extreme. Not "this will win" but "if it did, what would it be?"
Everything else in rhizome is in service of this question:
- Structure for agents → computers understand themselves
- Tags not hierarchies → everything findable
- Interaction graphs → affordances are explicit, not hidden
- Hyper-modularity → compose what you need
- MOO substrate → programmable everything
- Multi-frontend → same model, any interface
It's absurdly ambitious. But the exploration itself is valuable, even if the destination is unreachable.
Why this conversation exists:
Infinite things we can do. Finite time per week. Also infinite ways to spend too much time doing things wrong.
So it doesn't hurt to sit down and just... plan. Refine. Question assumptions. Backpropagate insights. Figure out what we actually care about before building the wrong thing.
This document is that: thinking before doing. Not because doing is bad, but because doing the wrong thing is expensive.
But also: some things exist just because they're neat.
Example: resin (procgen primitives).
- Has a bit of everything: textures, audio, meshes, noise, etc.
- Intended to be living/comprehensive
- First-class WGSL/GLSL compilation
- Fully serializable graphs
- Extensibility first-class
Do I plan to use it? Not really - averse to gamedev, ideas require too much investment to validate. But resin is neat. It's neat to have all these primitives in one place, properly designed.
Not everything needs immediate personal utility. Sometimes "this should exist, so I'll make it exist" is enough.
Multiple motivations at once:
| Motivation | Example |
|---|---|
| Scratch own itch | MOO - want inventory in Tavern cards |
| Should exist | resin - procgen primitives should be comprehensive |
| Spun out of need | burn-models - conceptualized for lotus image-gen plugin |
| What if? | The whole ecosystem - what if we could subsume all interaction? |
Things don't have single reasons. burn-models was practical (need image gen), but learning happened along the way. The motivations stack.
Projects spin out of projects:
rhizome (ecosystem)
└→ cambium (format→format, neat to have even if not strictly needed)
└→ rescribe (like pandoc - but pandoc isn't perfect, missing binary = failure mode)
└→ ooxml (where is Rust's ooxml support?!)Each step is: "wait, we need X for Y, and X doesn't exist / has problems."
Why not pandoc? Opus 4.5 pointed out it's not perfect. Also: missing a binary is a failure mode. Dependencies you don't control can break.
Why ooxml? Because it doesn't exist in Rust. Genuine gap.
And while building ooxml, invented more work:
- Language-agnostic fixtures
- Machine-readable specs for OOXML
- Because MS Office has enjoyed its dominance for too long
- Making OOXML easier to implement helps everyone, not just Rust
This is "scope creep that's actually good" - while solving immediate problem, notice meta-problem that would help the whole ecosystem.
Reality check though:
- OOXML is a 5,000+ page spec
- Look at how stc (TypeScript typechecker by dudykr) went - "only" ~30k lines, still massive
- Even with LLM support, actually finishing? Good luck. Your bank account is already crying.
- Some things are just too big.
But: partial solutions have value. "Can read/write basic docx" beats "nothing exists." The machine-readable specs might help someone else finish what you can't.
What's actually wanted:
Velocity is cool, but at the end of the day: want to finally just have something usable.
Favorite projects are ones where you can go: "take this, and this, and this, voila - it works!"
Example: ~/git/lua/cli/ (public: github.com/pterror/lua)
- Some are placeholders for things I'd really like
- But most: composed in less than a day from other parts of the repo itself
- Small pieces that combine into working tools
Sample of what's there:
cloc.lua (7k) - count lines of code
dns_lookup.lua - DNS queries
find.lua, grep.lua - file search
fs_watch.lua - file watching
http_static.lua - static file server
lua2js.lua - transpiler
mud_client.lua - MUD client (!)
repl.lua, replx.lua - REPL tools
serve*.lua - various serversActual line counts:
6 lines args.lua
12 lines grep.lua
18 lines mud_client.lua
34 lines find.lua
57 lines http_static.luaMost are under 100 lines. Many under 20. This is the power of good composition - when you have solid libraries, useful tools are tiny.
The underlying libraries are also small:
~/git/lua/lib/http/
client.lua 17 lines
server.lua 33 lines
serverx.lua 67 lines
format.lua 133 lines
status.lua 146 lines (HTTP status codes)
─────────────────────────
Total: 442 lines for entire HTTP libraryWhich builds on luajitsocket (~1k lines) for platform-agnostic sockets. But that's amortized over every protocol that uses sockets.
Fractal composition: each layer is small, they compose together.
Cursed but illustrative example: ~/git/lua/example/http_chatx.lua (197 lines)
- Full-stack chat app
- Server HTML/CSS via Lua DSL
- Client-side Lua that compiles to JavaScript
- WebSocket server, file drag-drop, MIME detection
- One language, both sides, under 200 lines
This is what's possible when composition is good enough.
The goal isn't impressive LOC counts. If anything, lower is better - more understandable, better separation.
But: don't split until you need to read N files to understand a single subsystem. There's a balance. The goal is things to reach for and combine, not minimum LOC for its own sake.
More thinking: are existing tradeoffs the right ones?
Lots of software makes tradeoffs. Some do things well (Procreate). But in general:
| Pain point | Why? |
|---|---|
| Multi-app workflows | Use X then Y then Z for one task. Why not integrated? |
| Twine, RPG Maker, Renpy | Authoring tools that kinda suck |
| Settings sprawl | MS Word, SillyTavern - dialog after dialog after dialog |
| Notion dying on 100 rows | Ctrl+C 100 rows → freeze. It's just data! |
| Notes ≠ todos ≠ calendar | Why are they different apps? (Notion tried, kinda worked?) |
| Excel formulas vs visual | Text formulas vs pillboxes + dropdowns - which is right? |
These are all "accepted" tradeoffs that maybe shouldn't be accepted.
The question isn't "can we make software" - it's "can we make software that doesn't make these tradeoffs?" Or at least makes different ones.
(Note: Notion "kinda worked" at unifying notes/todos/databases because it treats them as the same thing - blocks with properties. Sound familiar? { id } & Record<string, unknown>)
Excel formulas: a case study in tradeoffs
- They "work" - for power users
- But: documentation is all over the place
- But: so many functions, how do you find the right one?
- But: is it discoverable? (No)
- But: who has the time/ability to become an Excel power user?
- But: has anyone tried hunting for bracket mismatches in Excel?
The formula bar is a single-line text box. No syntax highlighting. No bracket matching. Error messages are cryptic. And this is the world's most-used programming environment.
The tradeoff was "text is universal" but the cost is "text is hostile to non-programmers (and even programmers)."
Excel goes deeper:
- Freeform grid. Why? Now tables can be anywhere.
- "Why is the table here and not there?"
- Dollar sign syntax for absolute references (
$A$1). Two different syntaxes.- (Not even counting R1C1 notation - who even uses that?)
- Cells can have rich text - technically - but good luck editing it in the formula bar
- Conventional method: type → apply formatting → remember what you did → type next section → apply different formatting → repeat
- A careful dance for something that should be trivial
- (Arguably some people like the complexity - job security for the office Excel wizard)
- People build Cthulhu-like spreads of references for tracking things Excel was never made for.
- Sticky headers help, but then there's another table floating to the right...
- "It should be in its own sheet" but:
- Who has mental capacity to keep 5 sheet names + contents in mind?
- Tab bar is horizontal - bye bye that other sheet you needed
- Navigating sheets is janky
Freeform seemed like flexibility. It created chaos. Sheets seemed like organization. The UI makes them impossible to navigate.
What if: tables were first-class, not cell ranges? What if: sheets had real navigation, not a tiny horizontal tab bar?
This is what the minimal entity substrate enables:
- Small pieces (just
{ id } & Record<string, unknown>) - Conventions (property names everyone understands)
- Views (interpret conventions into useful interfaces)
- Compose in a day, not a month
Backpropagating Insights
Now to ML the frick out of this and apply insights to actual architecture.
Is the ecosystem architecture still valid?
Given everything above (structure, tags, hyper-modularity, fractal decomposition), does the current rhizome split make sense?
Current decomposition:
- pith - interfaces/stdlib
- moonlet - Lua runtime
- reed - TS → IR → Lua
- moss - code intelligence
- zone - apps (this repo)
- etc.
What's good:
- Clear separation of concerns
- Each piece usable independently
- Fractal structure (same pattern inside each)
What might need rethinking:
- Is the boundary between pith and moonlet right?
- Does reed belong as separate, or should it be part of moonlet?
- Where does MOO fit? Is it zone (app) or something more fundamental?
Is MOO what we actually want?
Honest question: is MOO the right model, or just the "easy path" because LambdaMOO exists?
Arguments for MOO:
- Proven model (30+ years)
- Simple substrate (entities, props, verbs)
- Already understood how it works
- Programmable by design
Arguments against / for questioning:
- Are we just copying homework?
- Is "objects with verbs" the right primitive?
- Does the room/containment model make sense for everything?
- Is there something simpler or more general?
Alternative primitives to consider:
| Primitive | What it is | Pros | Cons |
|---|---|---|---|
| Entities + props + verbs (MOO) | Objects with methods | Proven, intuitive | Room metaphor forced? |
| Entities + relations (graph) | Nodes and edges | More flexible | Less intuitive? |
| Facts + rules (datalog) | Logic programming | Very queryable | Steep learning curve |
| Documents + links (wiki) | Pages with references | Simple | Limited programmability |
| Capabilities + resources | Tokens that grant access | Secure by design | Abstract |
Maybe MOO is right. Maybe we should prototype alternatives. The time to question is now, before we've built it.
Why is there a distinction between notes, fs, objects?
This is the real question. If we have:
- Objects with properties and verbs
- Tags instead of hierarchies
- Everything queryable
Then what IS the difference between:
- A "note" (text content, tags, links)
- A "file" (binary content, path, metadata)
- An "object" (properties, verbs, containment)
They're all just entities with different properties.
| "Type" | What it actually is |
|---|---|
| Note | Entity with content: text, tags: [...] |
| File | Entity with content: blob, path: string (legacy compat) |
| Object | Entity with verbs: [...], location: entity_id |
| Room | Entity with contents: [entity_id, ...] |
| Player | Entity with inventory: [...], location: entity_id |
The distinction is artificial. A note IS an object. A file IS an object. The "types" are just different property shapes.
Implication: Maybe we don't need "Notes app" and "FS app" and "MOO". We need:
- Entity substrate (things with properties)
- Standard property shapes (note-like, file-like, room-like)
- Views that understand those shapes (notes view, file browser view, world view)
The views are projections. The substrate is one thing.
┌─────────────────────────────────────────────┐
│ Entity Substrate │
│ (id, properties, tags, verbs, relations) │
└─────────────────────────────────────────────┘
↑ ↑ ↑
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│ Notes │ │ FS │ │ World │
│ View │ │ View │ │ View │
└─────────┘ └─────────┘ └─────────┘This is simpler. One substrate, multiple views. Not three apps pretending to be different things.
The Maximally Minimal Entity
Entity = { id: unique } & Record<string, unknown>That's it. An entity is just an ID plus arbitrary key-value pairs.
- Tags?
{ id, tags: ["foo", "bar"] } - Verbs?
{ id, verbs: { look: "..." } } - Relations?
{ id, parent: other_id, children: [...] } - Note content?
{ id, content: "..." } - File data?
{ id, blob: binary, path: "/..." }
Everything is just properties. The "schema" is conventions about property names. Views interpret conventions.
Is this too minimal? Maybe. You might want:
- Indexed properties (for fast queries)
- Reserved properties (id, created_at, updated_at)
- Type hints (for validation)
But: start minimal, add structure only when needed.
This is simpler than MOO. MOO has opinions about rooms, containment, verbs. This has no opinions. It's just... things with properties.
Note: Lotus originally had a MOO-like entity interface. Then it got gradually picked apart. This isn't theoretical - it's learned from iteration. The "why are these separate concepts" question came from actually building MOO-like structures and realizing the distinctions were artificial.
(Clarification: MOO as prior art/inspiration was the original idea. But the specific MOO-like property structure was what Gemini suggested. Had to iterate back to simplicity. Even AI can over-engineer when interpreting inspiration.)
Key insight: extra required properties are limitations, not features.
Every required field constrains what entities can be. { id, parent, children, verbs } means everything MUST have parent/children/verbs. But what if something doesn't have a parent? What if it's not programmable?
{ id } & Record<string, unknown> has no constraints. Anything can be anything. Add structure through conventions, not requirements.
Why doesn't this exist already?
One reason: we don't have common conventions.
"But we have JSON!" Yes, JSON is the format. But:
- Is it
nameortitle? - Is it
descriptionordescorsummary? - Is it
tagsorlabelsorcategories? - Is it
parentorparent_idorparentId? - Is it
created_atorcreatedAtorcreatedortimestamp?
Everyone invents their own property names. Every app, every API, every database. JSON solved the syntax, not the semantics.
HTTP existed before REST conventions. JSON exists without property conventions.
Maybe what's needed isn't a new format, but conventions:
- schema.org tried this (for SEO mostly)
- JSON-LD tried this (linked data)
- ActivityPub has conventions (for federation)
None became universal for "entities in general." The convention problem is unsolved.
But: these are valuable prior art! They represent years of iteration from many people (and yes, some bureaucracy). Don't reinvent from scratch - learn from what they figured out:
- schema.org: rich vocabulary for describing things
- JSON-LD: linking/context mechanisms
- ActivityPub: conventions for actors, activities, objects
Maybe rhizome conventions should borrow heavily rather than invent.
Overview
Three distinct projects that could relate:
- MOO-style object system - Persistent programmable object database. Standalone value.
- Notes / Knowledge base - Standalone OR as a MOO app
- Filesystem service - Standalone OR as a MOO app
Each has value independently. But if MOO exists, notes/fs become natural apps within it - built using objects/verbs, getting persistence and programmability for free, with interop (a note could reference a file, etc.).
Option A: Standalone servers Option B: MOO as platform
┌─────────┐ ┌─────────┐ ┌────┐ ┌─────────────────────────┐
│ Notes │ │ FS │ │MOO │ │ MOO │
│ Server │ │ Server │ │ │ │ ┌─────┐ ┌────┐ ┌───┐ │
└─────────┘ └─────────┘ └────┘ │ │Notes│ │ FS │ │...│ │
│ └─────┘ └────┘ └───┘ │
└─────────────────────────┘Not mutually exclusive - could have standalone notes server AND notes-as-MOO-app.
Key distinction:
- Standalone Notes/FS - "Real" implementations for people who just want notes/files
- MOO - Programmable object platform, interesting in its own right
- Notes/FS in MOO - Fun MOO-native apps, showcasing the paradigm ("look what you can build with programmable objects + verbs + inheritance")
The MOO versions aren't wrappers around standalone versions. They're different paradigms that happen to solve similar problems. MOO-native apps are toys/demos/explorations.
Where Things Live
pith = Stdlib. Stable interfaces, WASI foundation, seldom changes. "What are the primitives?"
zone = Full-stack apps composing rhizome libraries. "What can we build with them?"
Flora already contains:
- iris - Session analysis (uses moonlet + sessions + llm)
- wisteria - Autonomous tasks (uses moonlet + moss)
Flora could contain:
- MOO - Programmable objects (uses pith-sql, pith-fs, moonlet, reed) - future rebuild of lotus
- Notes - Knowledge base (uses pith-sql, maybe moonlet)
- FS service - File operations (uses pith-fs, pith-sql)
Architecture (Common)
Any Client (canopy, CLI, other) ←→ Flora Server ←→ Storage
↑
Lua or RustProtocol
Principle: Simplest possible for arbitrary consumers. Not canopy-specific.
Options to consider:
- HTTP/JSON (universal, simple, stateless)
- WebSocket (real-time, bidirectional)
- Unix socket (local, fast)
Language Choice
Prior art: lotus (MOO-style system), reed (language→IR→language), moonlet (Lua runtime)
The stack:
TypeScript (author verbs here - great DX, types, LLM-familiar)
↓ reed (compile)
Restricted IR (safe, serializable, no dangerous primitives)
↓ reed (emit)
Lua (executes on moonlet with native plugin capabilities)| Layer | Language | Rationale |
|---|---|---|
| Verb authoring | TypeScript | Type safety, IDE support, LLMs know it |
| IR | S-expressions | Universal, serializable, inspectable |
| Execution | Lua on moonlet | Fast (LuaJIT), sandboxed, plugin ecosystem |
| Plugins | Rust | Performance, safety, native capabilities |
| Core DB | Rust | Persistence needs perf |
Extensibility: MOO core is minimal (entities + verbs + capabilities). Domain features (notes, fs, AI) are moonlet plugins that expose capabilities. TypeScript SDKs wrap those capabilities with types.
Project: MOO-Style Object System
A standalone persistent programmable object database. Other projects could build on it, or not.
Original Motivation
The itch: Tavern/SillyTavern ccv2 character cards are limited by linear conversational history.
Problems with chat-log-only context:
- Amnesia: Context falls off, character "forgets" things
- No persistent state: Clothing, inventory, location not tracked
- No descriptions: Things in the world aren't properly described
This is a known problem. Smaller models especially struggle tracking outfit, pose, location.
Existing partial solutions:
| Solution | What it does | What it lacks |
|---|---|---|
| Lorebooks (ccv2) | Static knowledge injection | No state, no logic |
| SillyTavern extended lorebooks | Injection at arbitrary points | Still no logic, no persistence |
| Exotic plugin combos | Hacky state tracking | Fragile, not composable |
The gap: programmable logic + persistence + structured state. Can't do inventories. Can't "select 2 things from bag" without exotic plugin combinations.
What MOO solves - inject world state as context, not just chat:
You are in [Room: Kitchen].
You see: [Table], [Chair], [Alice (wearing: sundress, holding: coffee cup)].
Your inventory: [keys, phone].
Recent events: [Alice entered 5 minutes ago].
---
[conversation continues here]Intentional Generalization
While the origin was AI roleplay, the primitives (entities, props, verbs, persistence) were intentionally made generic. Same bones, different flesh:
| Use Case | Entities | Props | Verbs |
|---|---|---|---|
| AI roleplay | Characters, rooms, items | Clothing, inventory, mood | say, move, take |
| Kanban | Boards, columns, cards | Status, assignee, due date | move, archive |
| MUD | Rooms, NPCs, items | Health, stats, descriptions | look, fight, talk |
| Wiki | Pages, links | Content, tags, backlinks | edit, link, search |
What Made MOO Interesting
- Everything is an object: Rooms, players, items, even verbs
- Inheritance: Objects can inherit from parents
- Properties: Key-value data on objects
- Verbs: Programmable methods on objects
- Persistence: Database survives restarts
- Multi-user: Multiple connections, shared world
- Text-based: Core interaction is text (UI optional)
Modernizing MOO
What to keep:
- Object model with properties/verbs
- Persistence
- Programmability
- Text as first-class
What to reconsider:
- Single-server architecture → distributed?
- Custom scripting language → Lua?
- Telnet protocol → modern protocols?
- Global namespace → scoped/namespaced?
Object References
Question: How do objects reference each other?
| Option | Pros | Cons |
|---|---|---|
Numeric IDs (#123) | Simple, fast | Opaque, fragile |
Paths (/room/kitchen/table) | Human-readable | Implies hierarchy, renames break |
| UUIDs | Globally unique, stable | Opaque |
| Content-addressed (hash) | Immutable, dedupes | Awkward for mutable |
Named + scoped (@user/project/obj) | Readable, namespaced | More complex |
| Hybrid (UUID internal, path display) | Best of both | More complexity |
To decide: What operations matter most? Rename? Move? Link? Copy?
Answers from Lotus
| Question | Lotus Answer |
|---|---|
| Storage backend | SQLite (libSQL) - simple, embedded, sufficient |
| Object references | Numeric IDs internally, prototype chain for inheritance |
| Permissions | Capability-based - unforgeable tokens checked by verbs |
| Schema | Free-form JSON props - no migrations needed |
| Verbs | S-expressions stored in DB, executed by kernel |
Open Questions (MOO)
- Versioning: Do objects have history? (Lotus: no, but could add)
- Distribution: Single-server or multi-node? (Lotus: single)
- Authentication: Identity tied to what? (Lotus: entity ownership)
- What's different from Lotus?: Is this just "lotus v2" or something new?
Project: Notes / Knowledge Base
Persistent notes with rich linking. Could be:
- Standalone: Simple document store with linking
- On MOO: Notes as objects, links as references, queries as verbs
Requirements
- Create, read, update, delete notes
- Link notes to each other
- Search / query
- Maybe: tags, hierarchy, backlinks
Open Questions (Notes)
- Flat or hierarchical?
- Block-based (Notion) or document-based (Obsidian)?
- Plain text? Markdown? Rich text?
- Is MOO overhead worth it, or overkill?
Project: Filesystem Service
High-performance file operations. Could be:
- Standalone: Direct FS access with watching/indexing
- On MOO: Files as objects, directories as containers
Requirements
- Watch for changes
- Index contents
- Search by name/content
- Virtual FS abstractions?
Open Questions (FS)
- Scope: Just watching? Or full VFS abstraction?
- Performance: Definitely Rust for the core
- Is MOO overhead worth it here? Probably not?
Naming
Flora uses botanical names. Server candidates:
- Taproot - Deep, central storage
- Tuber - Underground storage organ
- Bulb - Storage + regeneration
- Corm - Similar to bulb, underground storage
Or project-specific names (more flowers).
Prior Art
Lotus (~/git/lotus) - Decomposed
Was a MOO-style monolith. Removed from ecosystem and decomposed into parts.
Has comprehensive docs at ~/git/lotus/docs/ - carefully evaluated, insights below.
Decomposed into:
- pith - Capability-based interface libraries (fs, sql, http, etc.)
- moonlet - Lua runtime with plugin system
- reed - TS → IR → Lua compiler
Lotus Vision (4 Pillars)
- Deep Simulation - Entity system, scripting, persistence (MUD/game roots)
- AI-Native - Context injection for LLMs, NPC agency, memory systems
- Ubiquitous Access - Headless, API-first, multi-platform (web, tui, discord)
- Knowledge/Productivity - Graph structure, vector search, programmable workflows
Technical Decisions (from rust-port.md)
| Decision | Choice | Why |
|---|---|---|
| Execution | LuaJIT | Tracing JIT, table shape optimization, FFI, 500KB, iOS-compatible |
| Plugins | Dynamic libs | Need full system access; WASM too restrictive |
| Plugin interface | Native Lua C API | No serialization overhead, can return userdata |
| Binary format | Cap'n Proto | Cross-language, zerocopy, schema evolution |
| TS parsing | tree-sitter | Fast, Rust-native, no Node dependency |
Trust model: Scripts sandboxed (IR restricted), plugins trusted (installed by admin).
Challenges & Mitigations
- Performance → JIT compilation
- Schemaless querying → Hybrid ECS (structured for hot paths, JSON for flex)
- AI context costs → Caching static context, RAG for retrieval
- Frontend fragmentation → Headless core, leverage existing ecosystems
Capability System Insights
- Unforgeable tokens, not role-based
- Minting (create new), delegation (restricted copy), transfer (change owner)
- Wildcards for admin, scoped params for users
- "Possession proves authorization"
Automation Patterns
- Bots = entities + scheduled verbs
- Triggers:
on_enter,on_leave, etc. - Examples: janitor bot, greeter, kanban column auto-archive
Lotus Layering (good)
App logic (notes: backlinks, search, linking)
↓ built on
Primitives (fs, sql, etc.)
↓ provided by
PluginsThe monolith trap (bad): App logic had to be MOO objects → MOO became the only host → monolith.
Decomposed philosophy: Keep the layering, remove the host requirement:
App logic (host-agnostic library)
↓ built on
pith-* (primitives)
↓ hosted by
MOO / standalone server / CLI / WASM / whateverThe "built up functionality" layer exists independently. Hosts are thin wrappers.
Reed (~/git/reed)
Language→IR→language compiler. Key insights:
- Intentionally restricted IR: No classes, async, metaprogramming
- Domain ops are function calls: Runtime (moonlet) resolves them
- TypeScript reader, Lua writer: Best of both worlds
- S-expr serialization: Same format as lotus verbs
LambdaMOO
The original MOO. Single-server, custom language. Still running after 30+ years.
Key insight: LambdaMOO is simple, arguably trivial, because it's fully programmable.
- The implementation is just the substrate (entities, props, verbs, persistence)
- The entire "game" is the LambdaMOO "core" - user-space code
- Same philosophy as Lisp/Smalltalk: minimal substrate, everything built on top
- The "complexity" lives in user-space, not the implementation
Implication for our MOO:
- Don't bake features into the core
- Build the substrate: entities, props, verbs, persistence, capabilities
- Let user-written code (or a "core" db) define the actual application
- Notes, FS, inventory, roleplay - all user-space, not implementation features
CouchDB
Document database. HTTP API, JSON documents. Multi-master replication.
Notion / Roam / Obsidian
Modern notes with linking. Block-based or page-based. Graph structure.
Plan 9 / 9P
Everything is a file. Network-transparent filesystem. Simple protocol.
Things That Dared To Be Different
Prior art not because they're all good or relevant, but because they tried something other than the mainstream.
| System | What's Different | Status |
|---|---|---|
| Plan 9 | Everything is a file, network-transparent FS, simple protocol | Influential but niche |
| Oberon | Tiled text UI, no hidden state, everything visible | Academic, preserved |
| Smalltalk/Pharo | Live object system, image-based, everything is an object | Active (Pharo), influential |
| Arcan (letoram) | Rethinking display server from scratch, scriptable compositor | Active, ambitious |
| Uxn/Varvara (100 Rabbits) | Minimal VM, personal computing, off-grid capable | Active, intentionally constrained |
| Lisp Machines | Hardware + OS built around one paradigm | Dead, influential |
| HyperCard | Anyone can build interactive things, low floor | Dead, mourned |
Common threads:
- Coherence: One paradigm carried through (files, objects, text, images)
- Simplicity: Fewer concepts, more orthogonal
- Introspection: System can examine/modify itself
- Different tradeoffs: Sacrificed mainstream compatibility for internal consistency
Why they didn't win:
- Network effects (everyone else uses X)
- Ecosystem (where are the apps?)
- "Good enough" incumbents
- Sometimes: genuinely worse at common tasks
But: they proved alternatives exist. The current way isn't the only way.
Where Did HyperCard Go?
HyperCard (1987) - 39 years ago. "Anyone can make interactive things."
It worked. Regular people made things. Then Apple killed it.
And in 39 years, where did its paradigm go? Nowhere.
| Attempt | What it is | Why it's not HyperCard |
|---|---|---|
| Flash | Multimedia authoring | Dead, was proprietary, web-only |
| Scratch | Visual programming for kids | "For kids" - ceiling too low |
| Snap! | Scratch + macros, first-class functions | Actually good! High ceiling. But niche, academic |
| PowerPoint | Slides with interactions | Seriously? |
| No-code tools | Bubble, Webflow, etc. | Vendor-locked, web-only, limited |
| Notion | Blocks + databases | Closer, but not programmable |
| Excel | Everyone's accidental programming | Not interactive artifacts |
We've had 39 years to reinvent it. To stand on shoulders of giants. To make something better.
Instead: professional developers vs everyone else. The gap widened, not narrowed.
Why?
- Apple killed it (business reasons)
- Web won, but web is for consuming not creating
- The early web was for creating! GeoCities, personal pages, view source → learn
- Where did it go? Platforms ate it. Now you post on Facebook, not on your site
- "Real programming" gatekeeping?
- No financial incentive (users as creators don't pay subscription fees?)
- Complexity creep (modern apps are too complex to build simply?)
The early internet was neat. How do we bring it back?
Not literally the early web. Not using LLMs as a bridge (that's a crutch, not a solution). The question is: what was the essence that made it good, and how do we capture that?
What the early web had (the spirit):
- Ownership - your space, your rules
- Tinkering - view source → learn → make your own
- Low floor - HTML in notepad was enough to start
- Weird creativity - personal, messy, no brand consistency required
- Connection - links to other weird pages, webrings, discovery
- No gatekeepers - no algorithm, no platform approval
What killed it wasn't technology - it was incentives:
- Platforms centralized attention (easier to post on something than make something)
- Professionalism expectations ("your site looks amateur")
- Mobile shifted to apps (walled gardens) - though PWAs exist, not a full paradigm shift
- Attention economy rewards feeds, not exploration
The tools exist. Static hosting is free. The culture shifted.
The question isn't "how do we make websites easy again" - that's solved. The question is: what would make people want to create their own spaces instead of posting on platforms?
Fascinating prior art: nightfall.city
A text-based community structured as a fictional metropolis. Accessible via telnet (nc nightfall.city 1900). Districts like "Writers-Lane" (cafes and bookstores), "Dusk's End" (contemplative hilltop), "Shore" (waterfront). Community features wrapped in narrative fiction - citizenship, classifieds, postal services, subway.
What it gets right:
- Atmosphere over technology - telnet is ancient, but the vibe is intentional
- Narrative structure - it's not "a forum," it's "a city you explore"
- Intentional retreat - explicitly stepping away from mainstream web
- Low-tech accessibility - if you have a terminal, you're in
- Community functions disguised as world elements - classifieds are classifieds, but they're in the city
This is the MOO/MUD spirit alive in 2026. Small, weird, intentional, atmospheric.
Also: Counterfeit Monkey by Emily Short
Interactive fiction, 2012 - not ancient history, not brand new. Consistently ranked #1 on IFDB. Set in Anglophone Atlantis where linguistic manipulation reshapes reality. Core mechanic: a letter-remover that transforms objects by removing letters from their names. Apple → ale. It's wordplay as world-mechanic.
Importantly: made during the "platforms ate everything" era. The IF community kept producing excellent work while the mainstream web was being consumed by Facebook and Twitter. Proof that the spirit never fully died - it just went underground.
Honest admission: Part of all this is missing the spirit of an era I never really got to experience. Nostalgia for something I only know secondhand. I'm sure plenty of things sucked (slow connections, bad UX, scams, no search, broken links everywhere). But before megacorps became the internet... things were different. More chaotic, more personal, more yours.
Maybe it's romanticized. Probably. But the romanticism points at something real that got lost.
The core questions:
Why did it disappear?
- Convenience won. Platforms are easier. One login, one interface, audience built-in.
- Network effects. Your friends are on Facebook, not on your RSS reader.
- Mobile. Apps, not URLs. Walled gardens by default.
- Money. Ad-driven attention economy rewards engagement, not exploration.
- Discovery died. Without curation (webrings, directories), how do you find the weird stuff?
- Professionalization. "Your site looks amateur" became an insult, not a badge of authenticity.
Can we bring it back?
- The spirit never fully died (nightfall.city, IF community, neocities, small web movement)
- But "back" to what? The conditions that created it (scarcity, novelty, no incumbents) can't be recreated
- Maybe the question is: can we create new spaces with that spirit, not resurrect the old ones?
How?
- Don't compete with platforms on their terms - they win on convenience, audience, network effects
- Offer something platforms can't - ownership, weirdness, depth, persistence, yours
- Lower the floor - Discord bots, not new apps to download
- Raise the ceiling - programmable, not just templates
- Connect the islands - federation, discovery, webrings-but-modern
- Make creation the point - not consumption with a "post" button
Open question: is this even possible at scale? Or is "small and intentional" the only way it works?
But also: Little corners exist - SCP, AO3, Tumblr, Neocities. They're thriving in their way. But can we make them big corners?
Not trying to be a platform. But it's genuinely sad that the spirit became so niche. "Tumblr user" is talked about like some exotic species, despite that exotic species being the source of like half of all internet culture (4chan is the other half, somehow).
The creative weirdos aren't gone. They're just... marginalized? Siloed? Talked about like they're a curiosity rather than the actual engine of anything interesting online.
Maybe the question isn't "how do we scale the spirit" but "why did the spirit get pushed to the margins, and can it reclaim some territory without becoming what it replaced?"
The real problem isn't being marginalized. It's discoverability.
Fine with staying niche. But: people can spend their entire lives without knowing these communities exist. Without knowing this was something they could participate in. Not just consume - create, contribute, belong.
The early web had webrings, directories, "links" pages. You'd stumble onto things. Discovery was built into browsing.
Now? Algorithms surface what optimizes engagement. The weird creative corners don't optimize for engagement. So they stay invisible. Someone who would love SCP or IF or MOOs or Neocities might never encounter them.
It's not that the spirit needs to go mainstream. It's that the path to finding it got paved over.
So: how do we lower the barrier to entry as far down as possible?
Yes, this creates restrictions. But the payoff: "you can find a place where you build things piece by piece and have something you value in a day, an hour, or less."
What's the minimum viable "start creating" experience?
| Barrier | Early web | Platforms | Ideal |
|---|---|---|---|
| Account | None / free host | Required, tracked | Optional? Pseudonymous? |
| Tools | Notepad | Built-in editor | Already have (Discord, browser) |
| Knowledge | HTML basics | None (templates) | Minimal but real (not just templates) |
| Time to first creation | Hours | Minutes | Minutes, but yours not cookie-cutter |
| Discoverability | Webrings, links pages | Algorithm (maybe) | ? |
The trap: lowering barriers often means templates, which means cookie-cutter, which loses the "yours" feeling.
The goal: low floor (start fast) + high ceiling (grow into complexity) + ownership (it's yours, not a template you filled in).
What would this look like concretely?
- Discord bot where you just... start describing a room? An object? And it exists?
- "Here's a thing. It has a name and a description. Done. You made something."
- Then later: "Want it to do something? Here's how to add a verb."
- Then later: "Want to connect it to other things? Here's how."
- Incremental complexity, but the first step is trivially easy.
The 12-line grep.lua energy, but for world-building. Compose small pieces into something meaningful. First piece takes a minute.
Broader than web/MOO - creative output in general.
The question applies everywhere:
| Domain | Current barrier | What "trivially easy start" could look like |
|---|---|---|
| Music | DAW learning curve, theory | Hum/tap something → it's a loop you can build on |
| Visual art | Tools, technique | Describe/sketch → something exists, refine from there |
| Writing | Blank page paralysis | Fragments that accumulate into something |
| Games | Engines, code, assets | Describe a rule → it works, add more rules |
| Worlds | Everything above | Describe a place/thing → it exists, build from there |
The pattern: start with something tiny that exists, not a blank canvas.
A blank canvas is terrifying. "Here's a fragment, make it yours" is approachable.
This is why templates feel hollow - they're someone else's fragment, not yours. But a blank page is worse. The sweet spot: your tiny fragment, immediately real, with a path to grow it.
Rhizome angle: Resin (procgen) could be "describe a texture/sound → it exists." Frond could be "describe a behavior → it works." The pattern generalizes.
Maybe the through-line isn't "MOO" or "web" or any specific domain. It's: make the first creative step trivially easy across all domains, then let people compose upward.
Prior art that gets this right: Mario Maker, Dreams
Both let you start with something immediately playable/real, then build from there. Low floor, high ceiling. Your creation, not a template.
Constraints don't just "force cleverness" - they lower the quality bar.
The way constraints work isn't only "limitation breeds creativity." It's also: if you're restricted, you're not expected to do as well. That's accessibility.
- Dwitter: 140 characters? No one expects a masterpiece. Permission to be small.
- PICO-8: 128x128, 16 colors? Of course it's chunky. That's fine.
- Pixel art: The actual skill ceiling is absurdly high, but the perceived bar is "it's just pixels"
- Bytebeat: One line of math? Cool if it makes any interesting sound at all.
This removes the "blank canvas terror" in a different way. Not "here's a fragment to start from" but "here's a constraint that makes imperfection acceptable."
Both approaches work. Fragments lower the starting barrier. Constraints lower the quality expectation. Either way: you get to make something without the pressure of it being Good.
The bar is SO high now. Maybe that's the real problem.
The early web: personal pages were janky. That was fine. Expected, even.
Now: you see polished content everywhere. Professional YouTubers. Viral TikToks. AAA games. Your brain calibrates "normal" to the top 0.1%.
Then you try to make something and it's... not that. Of course it's not. But the comparison is internalized. "This isn't good enough to share."
The bar is partly a collective hallucination created by:
- Algorithmic feeds showing only hits
- Survivorship bias (you don't see the 99% that flopped)
- Professionalization of everything
- "Content creator" as job title
But also: some people are just unnecessarily harsh. The bar is sometimes enforced by real humans being mean. Gatekeeping. "Your art is bad." "This is amateur." "Why did you even post this."
That's harder to fight. It's not just internalized comparison - it's actual cruelty. And one harsh comment can undo a hundred kind ones.
Communities matter here. Some spaces are supportive. Some are brutal. Choosing where to share is part of the battle.
The early web had more natural isolation. Your corner was your corner. Harder for random people to butt in. You had to actively find a site to see it. No algorithm pushing content to people who'd hate it.
That isolation was a feature:
- Safe spaces existed because they were hard to find
- Trolls had to work to discover you
- "Going viral" wasn't really a thing (blessing and curse)
- Communities could be weird without constant outside scrutiny
Platforms destroyed that. Everything's in the feed. Anyone can find anything. "Discoverability" also means "discoverable by the worst people."
The small web / federation / Discord servers - maybe they're recreating that isolation? Private by default. You have to be invited or seek it out. The trolls don't find you because the algorithm isn't pointing them at you.
But is "don't feed the trolls" / isolation a real solution? Or a bandaid?
Hiding doesn't fix the underlying problem:
- The trolls still exist
- The platform dynamics that enable them still exist
- You're just... not in their path
It means creative communities are forever confined to small hidden corners. Can never grow without attracting the bad actors. "Success" becomes dangerous.
Maybe that's fine? Small is good anyway (three people and their dog). But it's a constraint imposed by hostile actors, not chosen freely.
No good answer here. Moderation is exhausting and doesn't scale. Isolation works but limits reach. Platform-level fixes don't happen because engagement (including toxic engagement) is profitable.
The honest take: there might not be a solution. Just trade-offs. Hide and be safe but small. Grow and face the horde. Pick your poison.
Deeper question: are humans naturally like that? Or is there an underlying problem?
Is cruelty online just... human nature? Or is it created/amplified by something?
Arguments for "it's environmental":
- Anonymity + audience + no consequences = permission to be cruel
- Screens dehumanize - you're not hurting a person, you're typing at text
- Platforms reward engagement, including negative engagement
- Hurt people hurt people - lots of people are miserable and it leaks out
- Boredom, lack of meaning, misdirected frustration
- Tribal dynamics amplified by algorithms (us vs them)
- Context collapse - you say something to friends, strangers attack
Arguments for "some of it is just people":
- Some percentage of people are genuinely cruel
- Trolling existed before the internet (just more local)
- Even in small communities, there's sometimes That Person
Probably both. Some people are just mean. But the environment takes normal human variance and amplifies the worst parts. A person who'd be mildly unpleasant IRL becomes relentless when there's no face, no consequences, and an audience.
Maybe the answer isn't "fix humans" but "don't build environments that reward cruelty." Platforms could deprioritize toxic engagement. They choose not to because it's profitable.
The problem might not be human nature. It might be capitalism optimizing for engagement at any cost.
Drama sells. Outrage is engagement.
Platforms don't distinguish good engagement from bad engagement:
- Argument in comments? Engagement. Algorithm boosts it.
- Hate-watching? Engagement. Recommended to more people.
- Rage-clicking? Engagement. Ad impressions go up.
- Dunking on someone? Engagement. Both sides keep coming back.
The metric is "time on platform" and "interactions," not "did this make anyone's life better?"
This is a choice platforms make. They could optimize for satisfaction. They could downrank conflict. They could measure "did users leave feeling good?" Some have tried (YouTube's "break reminders," Instagram hiding likes briefly). But they don't stick with it, because engagement metrics win internal arguments.
The cruelty isn't human nature leaking through. It's cruelty as a business model, because conflict is profitable.
Consider:
- A supportive comment gets a like. One interaction.
- A hostile comment gets a reply, then a counter-reply, then a pile-on, then screenshots, then a whole discourse. Dozens of interactions.
From the platform's perspective, the hostile comment was more valuable. That's the incentive structure.
Implication for alternatives:
If engagement-maximization creates toxicity, then alternatives need different metrics:
- Not "time on platform" but maybe "things created"
- Not "interactions" but "collaborations"
- Not "daily active users" but "people who made something they're proud of"
Or: no metrics at all. Small communities don't need growth. Three people and their dog don't need engagement analytics.
The old web worked partly because there were no metrics. Nobody was optimizing for anything. You made a page because you wanted to. The absence of measurement was freedom from optimization pressure.
Maybe the answer is: stop measuring. Or at least: measure different things. Or: be small enough that measurement doesn't matter.
But wait: do people actually want to be doomscrolling?
Probably not. The behavior looks more like addiction than choice:
- People report feeling worse after social media use
- They keep doing it anyway
- "I spent 3 hours scrolling and now I feel bad" is universal
- Nobody plans to doomscroll - it just happens
This suggests platforms aren't serving preferences - they're exploiting psychological vulnerabilities. Variable reward schedules (maybe this scroll will have something good). Social validation (likes as dopamine). Fear of missing out. Outrage as engagement.
People don't want to be angry and anxious. They're being manipulated into states that generate engagement. The "want" is manufactured.
So "unsolvable" doesn't mean "give up."
You can't fix Twitter. You probably can't fix the attention economy. But:
- You can build things that don't exploit those vulnerabilities
- You can create spaces with different incentive structures
- You can opt out, personally and by building alternatives
- Small doesn't need to become big - three people and their dog is enough
The early web wasn't "solved" - it just had different incentives (none). The answer might not be "fix platforms" but "don't be a platform."
The uncomfortable question: is "don't be a platform" enough?
If the doomscroll machines keep running, most people stay trapped. Building a nice garden doesn't help the people who don't know gardens exist.
But also: you can't save everyone. The best you can do is:
- Build the alternative
- Make it discoverable (but not algorithmic)
- Let people find it when they're ready
Maybe that's defeatist. Or maybe it's realistic.
But actually: "competing" is the wrong frame entirely.
"Competing head-on is futile" assumes you're playing the same game - trying to get users, market share, engagement. That's only true from a capitalist perspective. If you're not trying to "win" in that sense, there's no competition.
The platforms aren't competitors. They're a different thing. You're not building "Twitter but better" - you're building something with different values for different reasons. Success isn't measured in user counts.
This reframes everything:
- Not "how do we beat the platforms" but "what do we want to exist?"
- Not "how do we get users" but "who is this for, and will they find it?"
- Not "market share" but "does this serve the people who use it?"
The platforms can keep running. That's fine. They're not the enemy to defeat - they're just... not what we're building. Coexistence, not competition.
Not everyone. Just: some people. The ones who want something different.
But honestly? Wouldn't it be nice if the platforms lost?
Not competing doesn't mean not wanting them to shrink. There's a difference between:
- Strategy: "We're not trying to beat them" (true - different game)
- Wish: "I'd prefer a world where they're less dominant" (also true)
Is that delusional? Maybe examine what "platforms losing" would even look like:
| Scenario | Likelihood | Would it help? |
|---|---|---|
| Platforms die, nothing replaces them | Very low | Chaos, probably bad |
| Platforms die, new platforms replace them | Medium (has happened: MySpace → Facebook) | Same problem, different logo |
| Platforms shrink, small web grows | Low but possible | This is the dream |
| Platforms stay, alternatives coexist | Most likely | Good enough? |
The honest assessment: platforms probably aren't going anywhere. The structural forces that created them (network effects, convenience, capital) still exist. When one dies, another takes its place.
But: you don't need platforms to die for alternatives to thrive. The goal isn't "platforms lose" - the goal is "alternatives exist and are findable." Those can coexist.
Wanting a better world ≠ making "destroy the current world" your strategy. You can wish for platforms to shrink while building for the world as it is.
Is it delusional? More like... a hope that doesn't need to be the plan. Build the thing. Let people find it. If platforms shrink someday, great. If not, the thing still exists.
But wait. We already know it's possible.
This isn't theoretical. Massive successes exist that aren't traditional platforms:
| Thing | Scale | What it is | Why it's not a platform |
|---|---|---|---|
| Minecraft | 300M+ copies sold | Creative sandbox, servers | You buy it once. Servers are independent. No feed, no algorithm. |
| SCP Foundation | Millions of readers, thousands of authors | Collaborative horror wiki | Wiki, not platform. No engagement metrics. People create because they want to. |
| Terraria | 50M+ copies | Co-op building/survival | Same energy as Minecraft. Shared progress, persistent worlds. |
| Co-op games generally | Huge | Playing together | Not competing for attention. Shared goals. |
| AO3 | 12M+ works | Fanfiction archive | Non-profit, community-run. No ads, no algorithm. Thriving. |
These aren't niche. Minecraft is one of the best-selling games ever. SCP is a cultural phenomenon. AO3 won a Hugo Award.
What do they have in common?
- Not ad-driven - no incentive to maximize engagement
- Creation is the point - not consumption with a "post" button
- Ownership - you own what you make (or it's creative commons)
- No algorithmic feed - you find things by exploring, not by being fed
- Community, not audience - you're with people, not performing for them
- Persistence - things you build stay. Servers have history. Wikis accumulate.
The model works. At scale. Without toxic engagement dynamics. It's not wishful thinking - it already happened.
The question shifts from "is this possible?" to "what made these work, and can we learn from them?"
But what's actually missing?
Games, fiction, fanworks - those are niches. Platforms succeed because for their core use cases, there's no alternative.
| Platform niche | What it serves | Non-platform alternative? |
|---|---|---|
| General social ("what I'm up to") | Sharing life updates with friends | ...email? group chats? Christmas letters? |
| News/current events | Real-time information, discussion | RSS? But discovery is gone |
| Short-form content | Entertainment, quick hits | TikTok-without-TikTok doesn't exist |
| Professional networking | Jobs, industry connections | LinkedIn has no competitor |
| Dating | Finding partners | Apps dominate, no alternative |
| Local community | Events, neighbors, local info | Nextdoor, Facebook groups... still platforms |
| Marketplace | Buying/selling | Craigslist? Facebook Marketplace? Still platforms |
| Group coordination | Organizing people | Discord, Slack... arguably platforms |
For most of these, the "alternative" is either:
- Another platform (just different branding)
- Something way worse (email chains, phone trees)
- Nothing
Why did Minecraft/SCP/AO3 work but "general social" doesn't have an alternative?
Hypothesis: they have specific creative outputs.
| Success | The output |
|---|---|
| Minecraft | Builds, worlds, servers |
| SCP | Articles, canons, tales |
| AO3 | Fics |
| Terraria | Worlds, progression |
"General social" has no artifact. You're not making something - you're just... posting. Sharing. Reacting. The "output" is ephemeral engagement, not a persistent creation.
Maybe that's the gap? Platforms won "general social" because there's nothing to build. The alternatives that work are ones where you're building something together.
Tumblr as partial exception:
Tumblr is technically a platform, but it has more creation energy:
- Blogs are yours (customizable, persistent)
- Reblog culture means content spreads with attribution
- Fandoms build things (headcanons, AUs, art, fic)
- Less algorithmic (chronological feed, mostly)
- Community over audience (more conversation, less broadcasting)
It's still a platform, but it's closer to the "creation" end than Twitter/Facebook. Maybe that's why it survived while being "bad at business."
The uncomfortable question: is "general social" just... platformable by nature?
If there's no artifact to build, no persistent creation, maybe platforms are the natural solution? And the best we can hope for is:
- Better platforms (less toxic, less engagement-maximizing)
- Small communities for those who want out (Discord, group chats)
- Accept that "general social" will always be platform territory
Or: invent a new thing. What if "general social" did have artifacts? What if sharing your life wasn't ephemeral posts but... something else?
No idea what that would look like. But maybe that's the actual missing piece.
MOO is arguably that.
Social interaction that produces artifacts:
- You're not posting - you're building objects, rooms, worlds
- Conversations happen in a persistent space you created together
- The social activity is the creation
- Your "profile" isn't a bio - it's your room, your objects, your verbs
Instead of "here's what I'm thinking" (ephemeral post), it's "here's a thing I made" (persistent artifact). The social graph becomes a world graph.
Maybe that's why MOO feels relevant to this whole conversation - it's "general social" with artifacts baked in.
Tangent: what even is creativity?
A tutor once said (paraphrased): "Creativity is the ability to make connections between seemingly unrelated things."
But... isn't that just thinking? Forming thoughts? Making associations?
And isn't that also what LLM attention does - finding relevant connections between tokens, weighing which parts of the context matter for the next prediction?
Obviously oversimplified. But the question stands:
| Process | What it does |
|---|---|
| Creativity | Connect unrelated things → novel output |
| Thinking | Connect concepts → coherent thought |
| Memory | Connect cue → stored information |
| LLM attention | Connect tokens → predicted continuation |
If creativity is "just" connection-making... then:
- It's not magic, it's a process
- Tools that help make connections could assist creativity
- The "creative spark" might be: which connections you make, not that you make them
- Novelty comes from unexpected connections (obvious ones aren't creative)
This connects (heh) to the "fragments that accumulate" idea. Creativity isn't ex nihilo - it's connecting existing pieces in new ways. The more pieces you have access to, the more potential connections. The better your tools for surfacing unexpected connections, the more "creative" the output.
Implication for tools:
If creativity is connection-making, then tools should:
- Surface unexpected relationships (not just obvious ones)
- Let you accumulate fragments (more raw material = more possible connections)
- Make it easy to juxtapose things (put A next to B, see what happens)
- Not force linearity (thoughts aren't linear, connections are graphs)
This is why wikis/zettelkasten/graph notes appeal - they're connection-surfacing tools. Links are explicit connections. Backlinks reveal implicit ones.
Feeds are linear. You know what that means?
The platform controls what you think.
If creativity/thinking is connection-making, and connections depend on what's adjacent in your mind, then:
- Feed shows you A, then B, then C (in that order)
- Your brain connects A→B→C
- The platform chose that sequence
- Therefore: the platform is shaping which connections you make
This isn't just "engagement optimization." It's cognitive control. The algorithm decides what thoughts enter your mind, in what order, creating what associations.
| Interface | Who controls sequence? | Who makes connections? |
|---|---|---|
| Algorithmic feed | Platform | You, but with platform-chosen inputs |
| Chronological feed | Time (random-ish) | You, with semi-random inputs |
| Graph/wiki | You | You, with self-chosen paths |
| MOO/exploration | You | You, by moving through space |
Linear feeds are the most controlled. You scroll down. One thing after another. No choice in sequence. The platform picks what goes next based on what will keep you scrolling.
Non-linear tools (wikis, MOO, spatial interfaces) give you agency. You choose what to look at next. You make your own paths. The connections are yours.
This reframes "platforms are bad for attention" into something deeper: platforms are bad for cognition. They're not just wasting your time - they're shaping your thought patterns by controlling your input stream.
The "doomscroll trance" isn't just addiction - it's surrendering your cognitive agency to an algorithm.
But it's not all black and white.
Two framings:
- "It's just the algorithm bucketing you" - categorizing based on your behavior, showing you more of what you clicked
- "The algorithm reinforces your biases to unhealthy levels" - amplification loop that takes mild tendencies → extremes
Both are true. It's a feedback loop, not pure top-down control:
You have existing interests/biases
↓
Algorithm detects them from behavior
↓
Shows you more of what you engaged with
↓
Your tendencies get reinforced
↓
Algorithm detects stronger signal
↓
Shows you even more extreme versions
↓
Repeat until radicalized / addicted / trappedThe algorithm isn't choosing your thoughts arbitrarily - it's amplifying whatever you already are. That's arguably worse. It takes your mild curiosity about X and turns it into obsession. It takes your slight irritation at Y and turns it into rage.
Radicalization pipelines work exactly this way. You click one "interesting" video, algorithm notices, feeds you more, you go deeper, it goes deeper with you. The extremism was "in you" the whole time - the algorithm just found it and amplified it.
This is more insidious than pure control. You can't blame "the algorithm made me think this" - it just showed you things you engaged with. But you also can't claim full agency - the amplification was engineered.
It's a collaboration between your existing tendencies and a system designed to maximize engagement by exploiting them.
But linearity is also a weakness.
Linear feeds are effective for algorithms. But what if you break the linearity?
Case study: Pixiv recommendations
When you click an artist, Pixiv suggests multiple other artists in a modal. Follow one, and just that slot gets replaced - the other options remain.
Linear feed: A → B → C → D → E (no choice, just scroll)
Pixiv style: [B, C, D, E, F] (multiple directions at once)
↓ (follow C, just C replaced)
[B, G, D, E, F] (other options still there)The key value: multiple directions exist simultaneously. You're choosing from a set, not accepting a sequence. Even without dramatic branching, seeing options = agency.
To be fair: X/Twitter does this too - three "who to follow" suggestions, different per profile. You can rabbit-hole through them and end up navigating a closed-ish social circle of artists. Hopping from profile to profile, following the graph of who-knows-who.
That's not the algorithmic feed - that's graph exploration. The feed is linear, but profile-hopping is navigating a social graph. Same platform, different modes, different agency levels.
Maybe the insight isn't "Pixiv good, Twitter bad" but: graph navigation exists alongside feeds, and it's more agentic. The recommendations are still algorithmic, but you're traversing a network, not being conveyed down a stream.
The algorithm still recommends. But you're navigating, not being conveyed. The control dynamic shifts.
| Model | Who steers? | User agency |
|---|---|---|
| Linear feed | Algorithm | None (just scroll) |
| Pixiv branching | Both | Choice points at each step |
| Pure exploration (MOO/wiki) | User | Full (you choose what to look at) |
But: the feed wins on effort.
| Mode | Effort | Reward reliability |
|---|---|---|
| Feed scrolling | Zero (just scroll) | Guaranteed (algorithm optimizes for it) |
| Graph navigation | Active (click, choose, decide) | Gamble (might find gold, might hit dead ends) |
The feed isn't just the default - it's the path of least resistance. Graph navigation requires energy, attention, choice. And it's a gamble - you might discover an amazing artist circle, or you might click through five boring profiles.
The feed is passive + guaranteed dopamine. Navigation is active + uncertain reward.
This is why the feed wins even when alternatives exist on the same platform. Not UI dark patterns (though those help). Fundamental effort economics.
Design principle: break linearity, introduce branching.
If linear feeds enable algorithmic control, then non-linear interfaces might resist it. Give users choice points. Show options, not a stream. Let them navigate rather than scroll.
This doesn't eliminate recommendation algorithms - it changes the power dynamic. Algorithm suggests, user chooses. Collaboration rather than control.
But the uncomfortable truth: more agentic interfaces are more effort. And tired people choose low effort. The feed isn't imposed - it's chosen, because choosing is hard and scrolling is easy.
Can you make navigation as low-effort as scrolling? Or is the effort inherent to agency?
Wait: the feed doesn't have to be linear.
We've been treating "feed" and "linear" as synonymous. But what if the feed showed multiple options at once?
Pinterest does this. Grid of pins, not a single stream. You see many items simultaneously, click what catches your eye. Still algorithmic, still low effort (just look), but with visible branching.
| Feed type | Effort | Agency |
|---|---|---|
| Linear (TikTok, Twitter, Instagram) | Zero | None - accept sequence |
| Grid (Pinterest) | Low (just look + click) | Some - choose from visible options |
| Navigation (profile-hopping) | Active | High - but effortful |
A non-linear feed could get both: low effort consumption + visible choices. The algorithm still recommends, but you see multiple recommendations at once and pick.
Linear: [A] → [B] → [C] → [D] (one at a time, scroll to reveal)
Grid: [A] [B] [C]
[D] [E] [F] (all visible, click to choose)
[G] [H] [I]Pinterest is... not great for various reasons. But the interface pattern - showing options simultaneously instead of sequentially - might be underexplored.
Google Images does this too. Grid of results, you scan, you pick. Not a feed exactly, but the same principle: multiple options visible at once, you choose. Search results in general are more "grid of options" than "linear sequence" - and that's probably why search feels more agentic than feeds.
And: Google Images has per-image recommendations. Click an image, see related images. Both patterns in one interface:
- Grid of options (non-linear feed)
- Per-item recommendations (graph navigation)
You can rabbit-hole through related images the same way you profile-hop on Twitter. Browsing (grid) + exploration (recommendations) coexisting.
Why don't more feeds do this?
Possible reasons:
- Linear is simpler to implement
- Linear maximizes scroll-time (engagement metric)
- Grid requires more screen real estate / doesn't work on mobile as well?
- Linear creates "just one more" psychology (sunk cost, variable reward per scroll)
The linear feed might be deliberately chosen because it's more controlling, not despite it.
Back to Reality: What Can We Actually Do?
We've been on tangents about platforms, feeds, agency, creativity. But practically: if we don't want the headache of funding, building a platform, curating a community... what's left?
What we're NOT doing:
- Raising money (VC expectations, growth pressure)
- Building a platform (users, moderation, scale)
- Curating community (endless social labor)
- Competing with incumbents (they have billions)
What we CAN do:
| Approach | What it means | Examples |
|---|---|---|
| Build substrates | Tools others build on, not destinations | Rhizome projects - moss, moonlet, resin |
| Make things | Lead by example, create artifacts | Character cards, worlds, tools |
| Document ideas | Write it down, let others find it | This brainstorm doc |
| Open source everything | Others can build on it | GitHub, permissive licenses |
| Contribute to existing spaces | Don't reinvent, participate | SCP, AO3, wikis, existing MOOs |
| Small tools, big composability | Unix philosophy | grep.lua is 12 lines |
The Rhizome thesis: build substrate, not platform.
Don't try to be the destination. Be the infrastructure. Let others build the destinations on top.
- Minecraft isn't a platform - it's a substrate. Servers are the destinations.
- SCP wiki isn't a platform - the wiki software is substrate, the content is destination.
- AO3 isn't trying to be a social network - it's an archive. Infrastructure for fic.
If you build good substrate, others build the communities. You don't have to do the social labor.
Concretely for Rhizome:
| Project | Substrate for what? |
|---|---|
| moss | Code understanding |
| moonlet | Lua runtime with integrations |
| MOO/lotus | Programmable persistent worlds |
| resin | Procedural media generation |
| cambium | Format conversion pipelines |
These are tools. People use tools to make things. You don't have to build the things - just make the tools good.
But: you still need to build high enough up the stack.
"Just build substrate" fails if the substrate is too obscure. Nobody's going to build on a stack that 0 people and 1 LLM know.
| Level | Example | Problem |
|---|---|---|
| Too low | "Here's a VM bytecode spec" | Who's going to write a compiler for this? |
| Still too low | "Here's a Lua runtime" | Cool, now what do I do with it? |
| Usable | "Here's a MOO you can talk to via Discord" | Oh, I can try this right now |
| Reference impl | "Here's an example world with inventory, rooms, NPCs" | Oh, I see what's possible |
| Destination | "Here's a community, come join" | Now you're running a platform |
The balance:
- Too low: nobody uses it (obscure, no clear value)
- Just right: usable + demonstrable + extensible
- Too high: you're doing social labor
You need to build high enough that:
- People can try it immediately
- They can see what's possible
- But they can still build their own thing on top
Reference implementations matter. Not "the" community - but "a" demo that shows what the tools can do. Example worlds, example apps, example integrations. Enough to understand, not enough to be the destination.
The hope: someone uses moonlet + MOO to build a community. Someone uses resin to make procedural art. Someone uses moss to understand their codebase. You enabled it without running it.
The realistic version: we build the reference implementations ourselves, use them ourselves, and if others find them useful, great. If not, we still have tools we use.
Actually: building a community is fine.
The problem isn't "community" - it's being responsible for the singular destination. An unmoderated community? Fine. A self-moderating community? Even better.
"Moderation is unsolved" - okay, and? The halting problem is unsolved. Doesn't mean you can't solve 50%, 90%, 99% of cases. "Technically unsolvable" ≠ "can't make massive progress."
What would fundamentally self-moderating tooling look like?
Not human moderators at scale. Systems/structures that make bad behavior hard or undesirable by design:
| Approach | How it helps |
|---|---|
| Capability-based permissions | You can only do what you've been granted. No ambient authority. |
| Small isolated spaces by default | Toxicity can't spread. Your space, your rules. |
| No algorithmic amplification | Bad content doesn't get boosted. Drama doesn't "sell." |
| Technical limits on reach | Can't spam 1000 people. Broadcasting is expensive/earned. |
| Ownership is clear | Objects have owners. You can't mess with what isn't yours. |
| Federation with boundaries | Connect to others, but with firewalls. Authoritative handoff (Hypha). |
MOO already does some of this:
- Objects have owners
- Verbs have permissions
- Capabilities are explicit
- You can't do what you haven't been granted
The structure is the moderation. Not "rules + enforcers" but "the system doesn't let you do bad things easily."
This is why capability-based security matters. Not as an abstract security model - as a moderation strategy. If you can't do something without the capability, you can't abuse it.
Unsolved doesn't mean hopeless. Build systems where the 90% case is handled by structure, and human intervention is only needed for the edge cases.
What about bad actors?
Structure-as-moderation handles casual abuse. But what about adversarial attackers? People actively trying to break things?
Case study: why Matrix failed (in some ways)
Matrix federation has serious issues:
- Faking room state is too easy
- DoS attacks are trivial
- Trusts other servers too much
- State resolution is complex and exploitable
The protocol assumed good-faith participation. Adversarial actors found the cracks.
Hypha's answer: authoritative handoff
Instead of "everyone has a copy of state, resolve conflicts" (Matrix), Hypha says: one server is authoritative at a time.
- No conflicting state to resolve - there's one source of truth
- Handoff is explicit - you know who's authoritative
- Don't have to trust everyone's version
- DoS one server ≠ DoS the whole network
This is a different federation model. Not "everyone equals" but "clear ownership with transfer protocol."
| Model | Trust assumption | Failure mode |
|---|---|---|
| Matrix | All servers are good-faith | Bad server poisons state |
| Hypha | Authoritative server is canonical | Need handoff if server dies |
| Centralized | One server forever | Single point of failure |
Hypha trades "everyone can contribute state" for "clear authority prevents poisoning." Different tradeoff.
The broader point: architecture matters for adversarial resistance. "Self-moderating" isn't just about casual abuse - it's about making attacks structurally difficult.
Capabilities help here too:
- Can't forge capabilities (unforgeable tokens)
- Can't escalate beyond what you were granted
- Attacker with limited caps can only do limited damage
Defense in depth. Structure resists casual abuse. Architecture resists adversarial attacks. Human intervention for the truly novel.
Chat moderation specifically is hard.
Real-time, high-volume, low-latency. By the time moderation kicks in, the damage is done. Someone says something horrible, 50 people saw it, now what?
User-moderation is a partial solution:
| System | How it works | Limitations |
|---|---|---|
| Stack Overflow | Votes, flags, reputation gates privileges | Still reactive. Toxic comment exists until flagged. |
| VRChat | Block, personal space, vote-kick | Only protects you. Others still affected. |
| Discord | User mods, bots, automod | Mods are labor. Bots have false positives. |
| Twitch | User mods, automod, slow mode | Same issues. Scale makes it worse. |
Common problem: reactive, not proactive. The harm happens, then moderation responds.
What would faster/proactive look like?
| Approach | Tradeoff |
|---|---|
| Rate limiting | Slows everyone, not just bad actors |
| Reputation gates | New users punished, cold start problem |
| Personal blocking | You're safe, others aren't |
| Escalating trust | Earn capabilities over time - slow but maybe fair? |
| Pre-filtering | Censorship concerns, false positives, latency |
| Small spaces by default | Limits blast radius, but also limits reach |
Maybe the answer isn't "solve moderation" but "limit blast radius."
If your message can only reach 10 people before trust is established, the worst case is 10 people see something bad. Not 10,000.
| Reach model | Blast radius |
|---|---|
| Broadcast (Twitter) | Millions potentially |
| Followers-only | Hundreds to thousands |
| Room-based (Discord) | Room size |
| Small-by-default + escalation | Starts tiny, grows with trust |
MOO naturally has limited blast radius - you can only affect the room you're in, the objects you own. You can't broadcast to the whole world by default.
Not solved. But maybe 80% addressable through structure:
- Limited reach by default
- Escalating trust
- Clear ownership
- Easy blocking/muting
- Small spaces
The 20% that remains: determined bad actors, novel attacks, edge cases. That still needs humans. But 80% handled by structure is better than 0%.
So What Do We Actually Build?
After all this philosophy - what's the concrete thing?
Important: Rhizome is not MOO-specific. At all.
Lotus was one project that got grandfathered in, then discarded - because it's essentially just SQL with a ~50 line schema. Not worth maintaining as a separate thing.
Rhizome is a diverse ecosystem:
- moss - code intelligence
- moonlet - Lua runtime with plugins
- resin - procedural media (textures, audio, meshes)
- cambium - type-driven conversion pipelines
- liana - API binding generation
- reed - source-to-source translation
- frond - game primitives
- hypha - federation protocol
- etc.
None of these are MOO. MOO was explored, mostly discarded.
The discussion above was about "social with artifacts" as a concept. That's interesting! But it doesn't mean Rhizome = MOO. It means: if we wanted to build something in that space, what would it look like?
So what actually gets built?
The honest answer: whatever's interesting and useful. Current active things:
- moonlet - Lua runtime, actively used
- wisteria - task execution
- iris - session analysis
- moss - code intelligence
- Flora - this repo, seeds, docs
What's actually missing / wanted?
This is the real question. Not "what's missing for MOO" but "what would be useful?"
Some possibilities from this conversation:
- Tools for non-linear exploration (breaking feed linearity)
- Self-moderating systems (capabilities, limited blast radius)
- "Social with artifacts" substrate (if that direction is pursued)
- Better creative tools (low floor, high ceiling)
- Connection-surfacing tools (creativity as connection-making)
But also just: the existing projects need work. moss needs polish. moonlet needs features. resin needs... everything.
Yes, I do want to build a MOO. But let's be honest: MOOs are one paradigm. They're not the only thing missing from 2026.
What else is missing?
| Gap | What's wrong | What could exist |
|---|---|---|
| Code understanding | Codebases are huge, opaque | moss addresses this - but needs more |
| Format conversion | Hunt for tools, pray they work | cambium - type-driven pipelines |
| Procedural media | Expert tools only (Houdini, etc.) | resin - composable, accessible |
| Federation that works | Matrix has issues, ActivityPub is limited | hypha - authoritative handoff |
| API bindings | Write boilerplate or hope a lib exists | liana - generate from specs |
| Non-linear interfaces | Everything is feeds | Canvas exists (Excalidraw etc), structured = graphs (exist, just clunky) |
| Creative tools | Either toy (Scratch) or expert (Blender) | Low floor, high ceiling, missing middle |
| Understandable software | Can't read what you use | 100 Rabbits philosophy, Lua repo energy |
| Local-first | Cloud dependency, no ownership | CRDTs exist, adoption lagging |
| "Social with artifacts" | Platforms are ephemeral posting | MOO-ish thing, wiki-ish thing, ??? |
| Connection-surfacing | Notes are silos, no unexpected links | Graph tools exist but clunky |
| View source → learn | Web is minified blobs now | ??? |
MOO is one of these. Not the only one. Each is a rabbit hole.
On the MOO-ish thing specifically:
It's not a new primitive - it's a full-stack app that composes Rhizome primitives:
- Uses moonlet (Lua runtime)
- Uses pith via moonlet-pith (capability interfaces)
- Uses reed (if translation needed)
- Lives in zone (apps that demonstrate the ecosystem)
This is the right framing. Flora is where apps go - things built on the ecosystem, not new fundamentals. The MOO-ish thing belongs there precisely because it's not a primitive.
On "view source → learn" - is "source" even the right concept?
Early web: view source, see HTML. That worked.
But other systems did this differently:
- Smalltalk/Pharo: No "source" - everything is live objects. Inspect anything while it's running. No separation between code and runtime.
- LambdaMOO: @examine objects, @list verbs. The world is the source. You read it by being in it.
- Resonite: Live inspection of world objects (to some extent)
The thing we actually want might not be "source" but inspectability - seeing how things work while they're working.
| Paradigm | How you learn |
|---|---|
| Files + source | Read static text, imagine execution |
| Smalltalk | Inspect live objects, send messages, see what happens |
| MOO | Examine objects in-world, read verbs, modify and see |
| Web (old) | View source, copy, modify |
| Web (2026) | lol good luck, it's minified webpack |
| Resin / node graphs | See the graph, tweak nodes, watch output change |
Resin is another inspectability paradigm.
Procedural media: the "source" is a graph/recipe that produces output. Node graphs in Houdini, Substance Designer, Blender geometry nodes, shader graphs, modular synth patches (Max/MSP, Pure Data).
You see the structure. You poke at it. Output updates live. The "source" is the graph, and it's always running.
This is inspectability for media generation:
- Not reading static code
- Not imagining execution
- See the recipe, tweak a parameter, watch the texture/mesh/sound change
Resin should have this property. Composable procedural primitives where:
- You see how they compose
- You tweak them
- Results update
- The graph is the understanding
That's "view source → learn" for procedural media. Different domain, same principle.
"Source" is a file-based concept. Maybe the better question is: how do you make systems inspectable? Source is one answer. Live objects are another. Programmable worlds are another. Node graphs are another.
On "graphs are clunky" - are they though?
Structured non-linear = graphs. And graph tools are clunky. But is that innate?
Why graphs feel clunky:
- Visual complexity (hairball)
- Layout is hard
- No natural navigation order
- Doesn't scale
- Fiddly to edit
But wait:
- The web is a graph. We browse it fine.
- MOO is a graph (rooms + exits). Doesn't feel clunky.
- File trees are graphs. We manage.
- Obsidian link-following = fine. Obsidian graph view = hairball.
The pattern: graphs are clunky when you visualize them globally. Local navigation works.
And not just one node at a time - 2-3 levels of expansion, dynamic expand/collapse. File browsers do this. IDE call trees. Mind maps. Obsidian local graph. You see your neighborhood, expand what interests you, collapse what doesn't.
What doesn't work: "here's the whole graph, force-directed layout, good luck."
The real issue: affordances.
Graph tools dump nodes on screen and hope you figure it out. No clear affordances for:
- What's expandable?
- How do I navigate?
- What actions exist here?
- How do I filter/focus?
The data is a graph. The interaction (what can I do, how do I discover it) is the problem.
MOO solves this: verbs are explicit (look, examine, go north). Commands are discoverable (help, @commands). The world is a graph but the interaction affordances are clear.
Command palettes solve this: Ctrl+K surfaces the interaction graph, makes it searchable. Not "hunt through menus."
Graphs aren't innately clunky. Graph tools just don't try on affordances/discoverability.
What Even Are Interactions?
Bigger question: what are interactions? What makes them good? How do we design them? How do we diagnose when they're bad?
What is an interaction?
Simple model: user does thing → system responds.
But really it's a loop:
Perceive → Interpret → Decide → Act → Perceive result → ...System presents state + affordances. User perceives, decides, acts. System responds with new state + affordances. Repeat.
The "interaction graph" is: what actions are available, when, and what do they lead to?
What makes an interaction good?
| Property | What it means |
|---|---|
| Discoverable | You can find what's possible |
| Predictable | You can anticipate results before acting |
| Reversible | You can undo mistakes |
| Responsive | Feedback is immediate |
| Efficient | Low effort for common tasks |
| Learnable | You get better over time |
| Honest | System does what it says, no dark patterns |
Bad interactions fail on these. Hidden features (not discoverable). Surprising results (not predictable). Can't undo (not reversible). Lag (not responsive). Tedious (not efficient). Confusing (not learnable). Manipulative (not honest).
How do we design good interactions?
- Start with tasks/goals, not interface elements ("what are people trying to do?")
- Progressive disclosure (simple surface, depth available)
- Consistency (similar things work similarly)
- Make common case easy, edge cases possible
- Prototype and test with real people
- Steal from things that work
How do we diagnose bad interactions?
Watch people use it. Where do they:
- Get stuck?
- Make errors?
- Ask "how do I...?"
- Give up?
- Do something unexpected (they had a different mental model)?
The gap between what users expect and what happens = the diagnosis.
Relating this back to graphs:
Graph tools fail on discoverability ("what can I do?") and predictability ("what happens if I click this?"). The data is fine. The interaction loop is bad.
Good graph interaction would be:
- Clear affordances (this is expandable, this is clickable, this leads somewhere)
- Predictable navigation (click = go there, right-click = options, drag = rearrange)
- Discoverable actions (help, command palette, contextual hints)
- Reversible (undo, back, collapse)
- Responsive (instant feedback on hover, click, expand)
This is just... basic interaction design. Applied to graphs. Nobody does it?
Good design is invisible.
When design works, you don't notice it. It just feels natural. The door handle that you instinctively pull correctly. The app that does what you expect without thinking.
Problem: invisible = hard to copy.
People copy what they can see. They miss what they can't. Bad copies strip out the "invisible" parts that made the original work:
| Good design | What people copy | What they miss |
|---|---|---|
| Apple | Visual style, materials | Obsessive detail, animation timing, UX research |
| Nintendo | Characters, genres | Polish, game feel, "juice" |
| Notion | Blocks, slash commands | Information architecture, progressive disclosure |
| Original WIMP | Windows, menus, icons | The underlying interaction model, consistency principles |
The visible is surface. The invisible is substance. Copies get the surface, lose the substance.
Implication for design:
If good design is invisible:
- You can't just "look at good examples" - you'll miss what matters
- You have to use things deeply, notice what works, ask why
- Diagnosis requires attention: what did I NOT notice? (because it worked)
- Documentation matters: write down the invisible decisions
Implication for copying:
If you're copying something good, you probably don't know what makes it good. The parts you notice aren't the parts that matter. Be suspicious of your own understanding.
But also: are we copying the right thing?
Two failure modes:
- Copy good design badly (miss the invisible substance)
- Copy mediocre design faithfully (perpetuate the problems)
WIMP might be the second. It was genuinely innovative in the 1970s-80s. But we have 50 years of progress since then. Why are we still defaulting to it?
WIMP problems that persist:
- Menu hunting (where's that option?)
- Deep hierarchies (Settings → Advanced → More → ...)
- File dialogs (universally hated)
- Modal confusion (which window is active?)
- Window management (still unsolved)
People copy WIMP because it's familiar, not because it's optimal. "Nobody got fired for buying IBM" energy.
Better prior art exists. Domain-specific tools that figured out better patterns:
| Tool | What it does well |
|---|---|
| Aseprite | Pixel art editor. Beloved. Keyboard-driven, contextual tools, workflow-aware. |
| RPG in a Box | Game creation. Accessible, visual scripting, immediate feedback. Heavily modal - different modes for maps, tiles, scripts. |
| Blender (modern) | Reinvented itself. Context-sensitive UI, pie menus, modal but learnable. |
| Command palettes | Ctrl+K everywhere. Searchable actions, no menu hunting. |
| Vim/Emacs | Modal editing. Steep learning curve but efficient once learned. |
| VSCode | Not purely WIMP. Command palette, keybindings, tiling panel manager, extensions. Hybrid. |
Note: modality shows up in multiple of these (RPG in a Box, Blender, Vim - and VSCode too! Editing vs debugging vs git vs search are different modes with different tools/affordances). Modal gets a bad rap from WIMP's "modal confusion" (which dialog is active?) but task-based modality can reduce clutter - only show tools relevant to current task. The key is making modes discoverable and switching easy.
Even VSCode - mainstream as it gets - isn't purely WIMP. It's a hybrid that borrows from terminal editors, command palettes, extensibility models. And notably: VSCode is a tiling panel manager. Split editors horizontally/vertically, dock panels, sidebars. No floating window chaos - it's all spatial organization within one frame. That's not WIMP, that's tiling WM energy.
The successful modern tools are quietly moving beyond WIMP even while wearing its skin.
50 years of scattered progress. Not in mainstream OS design, but in specific tools that cared enough to try. Worth mining for patterns.
Meta-question: doing things well is hard and non-obvious. Is this solvable?
Good design is invisible. Copying is hard. Knowing what to copy is hard. Even recognizing good design is hard (because it's invisible). Every domain has this problem.
Is there hope? Or is "most things are mediocre" just... the default state?
Probably not "solvable" in the sense of making it easy. But maybe addressable:
| Approach | What it helps |
|---|---|
| Deliberate practice | Build intuition over time |
| Documentation of decisions | Make the invisible visible (for yourself, for others) |
| Deep study of prior art | Not just copying surface - understanding why |
| Testing with real users | See where your mental model diverges from reality |
| Iteration | Get it wrong, learn, try again |
| Apprenticeship/pairing | Tacit knowledge transfer |
The tacit knowledge problem:
Experts know things they can't articulate. "It just feels wrong" - but why? They can't always say. This is tacit knowledge.
Some domains have tried to codify:
- Architecture: Christopher Alexander's pattern language
- Software: Design patterns (GoF), principles
- UX: Nielsen's heuristics, various principles
But here's the thing: the good stuff exists and can be studied.
You don't need the expert to articulate it. The artifacts exist - the good designs, the good tools, the good interactions. Someone with the right mindset can:
- Study the artifacts deeply
- Figure out what makes them work
- Write it down for others
Christopher Alexander didn't build all those good buildings - he studied them and articulated what made them good. The original architects might not have been able to explain it. Doesn't matter. The buildings existed. He could study them.
Same opportunity exists for:
- Good tools (Aseprite, Blender, VSCode, etc.)
- Good games (Nintendo polish, game feel)
- Good interfaces (wherever they exist)
Someone - or multiple someones - can get into the mindset, study deeply, and document. The tacit becomes explicit through analysis, not just through the expert articulating it.
Meta: LLMs might actually help here.
LLMs have absorbed a lot of domain knowledge from training - design principles, tool patterns, what works, what doesn't. The knowledge is in there, but compressed/latent.
What's needed:
- Token space to reason (context window)
- Guidance to reason through it (prompts, conversation)
- Someone to push back, correct, refine ("not quite, what about X?")
This conversation is literally that process. Human provides direction and correction. LLM draws on absorbed knowledge. Together: distill insights, document them.
Not "LLM replaces expert" - but "LLM as reasoning partner with broad (if shallow) knowledge, human as guide with deep (if narrow) knowledge." The combination surfaces things neither would alone.
The document we're building right now is the output. Whether it's good is a different question - but the process is: guided reasoning over latent knowledge → explicit documentation.
And honestly: doesn't have to be good. Just better than nothing.
The bar isn't "definitive guide to interaction design." It's "captures something useful that wouldn't exist otherwise."
This connects to earlier themes:
- Constraints lower the quality bar
- "Good enough" is okay
- Done > perfect
- Three people and their dog
If this doc helps one person think through design better - or helps future-us remember why - it's already better than nothing. The perfect is enemy of the good. The good is enemy of "exists at all."
Maybe the honest answer:
- Accept that most things will be mediocre (including your own work)
- Recognize when something is great, even if you don't know why
- Protect great things from being "fixed" by people who don't understand them
- Try to learn deeply, not just copy
- Document decisions so future-you (and others) know why
- Iterate. Get it wrong. Learn. Try again.
"Doing well" may never be easy. But it can be practiced. And the trying matters.
What Makes Interaction Actually Good?
Let's think harder. Earlier I praised command palettes. But...
Command palettes are a crutch.
They're "discoverable" in that you can search for anything. But they're also:
- A dumping ground for everything
- Not contextual (same palette everywhere)
- Require knowing what you're looking for (or guessing keywords)
- Don't show what's relevant right now
Command palette = "we don't have a place for this, so put it in the giant bag of every other action."
Hierarchy of discoverability:
| Tier | What it looks like | Why |
|---|---|---|
| Best | Affordances so clear you don't need to search | Things are where you expect. Actions visible on relevant objects. |
| Good | Contextual actions | Right-click, hover reveals, actions appear near what they affect |
| Okay | Organized menus | At least categorized. Can browse if you don't know the term. |
| Crutch | Command palette | You can find it if you know what to search. Better than nothing. |
| Bad | Hidden/undiscoverable | Keyboard shortcuts with no hint. "Just know" the magic incantation. |
Command palettes are Tier 4 - better than hidden, worse than contextual.
What would actually good look like?
- Actions appear on the thing they affect (not in a global menu)
- Context determines what's available (not everything everywhere)
- Common actions are visible; rare ones are tucked but findable
- You can see what's possible without searching
- Spatial: things near each other are related
Example: MOO verbs
In a MOO, verbs are on objects. You examine the apple, see it has eat, throw, peel. Actions are discoverable in context. You don't search a global list of every verb - you look at the thing.
Compare to: "open command palette, type 'eat', hope it exists."
Example: direct manipulation
Drag file to folder = move. Obvious. Spatial. No search required.
Compare to: "open command palette, type 'move file', get dialog, pick destination."
The problem with command palettes (as typically implemented):
They're universal solvent. Everything dissolves into "type keywords, find action." But universality is also flattening - you lose context, spatial relationships, object-action binding.
They're a fallback for when you don't have better organization. Not a goal.
Important nuance: These problems aren't fundamental to command palettes as a concept. A palette could be:
- Context-aware (filter by what's relevant to current selection/mode)
- Priority-ranked (show likely actions first based on context)
- Object-scoped (palette on this object shows this object's actions)
But it doesn't come free. You have to:
- Know what context you're in
- Define relevance rules
- Build the ranking system
- Make scoping work
VSCode does this. Commands filter by active editor type, extension context, current mode. Git commands appear when you're in a repo. Language-specific commands appear for that language. Plus frecency - recently/frequently used commands bubble up. It's not perfect but it's context-aware.
And honestly? The extra effort is marginal. You already have context (what's selected, what's active, what mode). Filtering by it is straightforward. The real cost is deciding relevance rules, not implementing them. Most implementations don't bother not because it's hard, but because they don't think about it.
Personally curated is theoretically optimal.
Frecency + favorites + pinned items. See: Discord emoji picker, browser omnibars. The system learns what you use. On paper, can't beat it.
But: creates divergence between setups. "Just open the X panel" - "what X panel?" Collaboration friction when everyone's interface is different.
Command palette bridges this gap - it's a common vocabulary even when personalized. You can always type the canonical name even if it's not in your frecency top 10.
What about initial discoverability?
Personalization doesn't help day-one users. Frecency is empty. Favorites are unset.
But honestly? Initial discoverability isn't rocket science. Just dogfood the software. Use it yourself. Notice what's hard to find. Surface it. The problem isn't that discoverability is hard to design - it's that developers don't actually use their own tools as real users do.
But that's not the whole story.
Dogfooding helps you find what's hard to discover. It doesn't help you realize what shouldn't exist.
Moss had command sprawl - dozens of specialized commands. Discoverability wasn't the problem. The problem was: too many things to discover. The fix wasn't better surfacing - it was collapsing them into three primitives: view, edit, analyze. Now there's less to discover in the first place.
This is "Generalize, Don't Multiply" from the Rhizome philosophy. Fewer concepts that compose > many specialized concepts that don't. Discoverability is easier when there's less to discover.
What software actually does interaction well?
| Software | What it does right | Pattern |
|---|---|---|
| Figma | Objects are objects. Select thing, see its properties, manipulate directly. Constraints visible. Multiplayer just works. | Direct manipulation, visible state |
| tldraw | Minimal tools, each obvious. Overloaded modifiers (ctrl+click, shift+drag) - you discover by accident while doing normal things. | Constraint-based simplicity, accidental discovery |
| Blender (modern) | Modes are explicit and visible. Each mode has relevant tools. Consistent modifier stack pattern. (Still has discoverability issues - better than most, not solved.) | Task-based modality, composable primitives |
| Paint.NET | Not trying to be Photoshop. Familiar Windows-native feel. Layers visible, tools obvious, effects organized. Less stuff = easier to discover. | Constraint by scope, platform conventions |
| PICO-8 | Everything fits in your head. 128x128, 16 colors, simple API. Limits are the feature. | Intentional constraint |
| Obsidian | Markdown first - you already know it. Power features via plugins, not core bloat. Settings search. | Progressive disclosure, plugin architecture |
| Linear | Keyboard-first but mouse-discoverable. Cmd+K shows everything. Shortcuts shown inline. | Dual-path interaction |
| Notion | Slash commands in context. Blocks are objects with actions. Drag to rearrange. (Interaction patterns good; implementation choices bad - and no, it's not "Electron bloat." JS is fast: VSCode, tsc scaling to 100s of kLoC. Slow software is bad architecture, not bad runtime.) | Contextual actions, direct manipulation |
| Unity/Godot | Inspector shows selected object's everything. Actions near targets. Scene tree = structure visible. (Still overwhelming - dozens of properties per component. But the pattern is right - problem is showing all 50 at once instead of mode/context filtering.) | Object-oriented interaction |
Common patterns in good software:
- Immediate feedback - you see results as you act (Figma, Shadertoy, tldraw)
- Spatial consistency - things stay where you put them, layout is stable
- Undo everywhere - confidence to experiment without fear
- Visible state - current mode, selection, context always clear
- Actions near targets - right-click, inspector panels, inline controls
- Composable primitives - small pieces that combine (Unix pipes, Blender modifiers, Figma components)
- Keyboard AND mouse paths - neither forced, both work (Linear, VSCode)
- Search as fallback, not primary - good organization first, search for edge cases
- Accidental discovery - modifiers on actions you're already doing (tldraw). Not ideal in theory, but works because: (a) modifiers follow conventions from other software (ctrl = constrain, shift = extend), and (b) few enough features that modifiers can cover them. Wouldn't scale to 50 modifier behaviors.
- Scope constraint - just don't have that many features (Paint.NET, PICO-8). Less stuff = less to discover.
Discoverability at scale: interaction graph + modality
Maybe "discoverability doesn't scale" is wrong. The problem isn't having thousands of actions. It's showing thousands of actions.
If you have:
- Interaction graph - all actions exist as structured, queryable data
- Mode filtering - current task/mode determines which slice is relevant
- Context filtering - selection, state, recent actions narrow further
- Intelligent ordering - not alphabetical, not arbitrary. Frecency, relevance, likelihood. Just like command palette. (But tension with grouping: frecency within categories means icons move around, breaks spatial consistency. Frecency across categories? Within? Both have tradeoffs. And sometimes grouping IS right - 6 asset upload commands under one category isn't a mistake just because frecency exists. Appropriate choices depend on context.)
Then:
- Total actions: thousands
- Visible at any moment: 5-10
- Full graph available via search when needed
This is what Blender modes almost do. Edit mode shows edit tools, sculpt mode shows sculpt tools. But it's coarse - still dozens per mode. Finer-grained context filtering (what's selected, what operation is in progress) could narrow further.
Unity's inspector problem isn't "50 properties exist." It's "50 properties visible at once." A mode-aware inspector that shows physics properties when you're doing physics, rendering properties when you're doing materials, etc. - same data, different projections.
Caveat: this is hypothesis, not proven. No shipping software fully implements this pattern. Blender modes are coarse. VSCode's palette is close but still global-ish. We're reasoning from "these pieces work individually" → "combining them should work better." Maybe! Or maybe there's a reason nobody's done it. Would need to build it and see.
Deeper caveat: there's no universal recipe. Human intuition can't be distilled into "just do X." Good design requires factoring in:
- Gestalt patterns (how humans perceive grouping, proximity, similarity)
- Subitizing (humans can instantly count ~4-5 things, more requires effort)
- Icon recognizability (familiar shapes, consistent visual language)
- Short-term memory limits (~4 chunks, not 7±2 - that's been revised)
- Mental models (what users expect based on prior experience)
These are cognitive constraints that inform design but can't be reduced to a rule. You have to understand them AND apply judgment to the specific case. The recipe is "learn the constraints, then think."
That said: not pointless to write down how mental models translate to design choices. The knowledge part matters. Documenting "subitizing means toolbar groups should be ~4 items" or "gestalt proximity means related actions should be visually close" is valuable - it's just not sufficient on its own.
The documentation problem: It's sad that knowledge-sharing defaults to 3,000-word blog posts. Then another. Then another. Insights get buried in essays, scattered, unindexed, hard to find when you need them. This applies to basically all domains - not just software, not just design. Cooking, woodworking, music production, game design, parenting, whatever. The blog-post-ification of knowledge is everywhere.
Good examples of concise knowledge:
- Lu Wilson's "Just" - short, makes its point, done
- motherfuckingwebsite.com - makes the point by being the point
Examples that are good despite being long:
- Crafting Interpreters - excellent, thorough, a whole book
- fasterthanlime - famously deep and long
- Learn You a Haskell - great intro, still a book
The core insights could be extracted. The length is context, teaching-style, narrative - not essential. They succeed in spite of the format, not because of it. Where's the atomic version? "Here's how to write a parser in 2 paragraphs + code."
To be fair: length helps pacing/digestion. Gives time to absorb. But it optimizes for people with buttloads of time to sit and learn properly. Not everyone has 20 hours for one topic. Long-form limits how many things people can learn, even if fast = less comprehensive. Trade-off: depth on one thing vs breadth across many. The format chooses for you.
Video is even worse - same length problem, barely searchable. Can't ctrl+F a video. Can't skim. Have to sit through it linearly.
Alternative paradigm: interactive learning.
- incredible.pm - visual/interactive proofs
- Natural Number Game - learn Lean by doing
- nandgame - build a CPU from NAND gates
- Zachtronics / zachlikes (TIS-100, Shenzhen I/O, Silicon Zeroes) - programming as puzzles
Key value: doing forces you to think. You can't skim a puzzle. You have to solve it yourself. Can't passively consume - have to engage. Knowledge sticks because you constructed it, not absorbed it.
Why aren't there more? Interactive tutorials are rare. Writing a blog post = explain what you know. Designing interactive learning requires:
- Deep domain understanding (what are the core concepts?)
- Pedagogical sequencing (what order to introduce them?)
- Interaction design (what puzzles/tasks force engagement?)
- Implementation (actually build the thing)
Blog post: one skill. Interactive tutorial: four skills, and the fourth one is a whole project. Lack of domain expertise, lack of design expertise, lack of implementation capacity. Pick at least one.
Hot take: lower the barrier to entry.
If interactive tutorials require four skills, make tools that collapse them:
- Templates for common interaction patterns (drag-and-drop, fill-in-the-blank, build-the-thing)
- Visual puzzle designers (domain expert focuses on content, not implementation)
- Embeddable components (drop into a blog post, not a separate app)
- Shared infrastructure (evaluation, hints, progression)
Don't require everyone to be Zachtronics. Let the domain expert be a domain expert; let the tool handle the rest.
Why doesn't this exist? Game engines are everywhere. Things that come close:
- Twine (interactive fiction - text-focused)
- H5P (embeddable interactive content - limited/clunky)
- Jupyter notebooks (interactive code - not puzzles)
- Observable (reactive notebooks - requires JS)
- Exercism (code exercises - programming-specific)
- Scratch (visual programming - teaches programming itself)
- Quizlet/Kahoot/Anki (quizzes/flashcards - shallow interaction)
- Unity/Godot (full game engines - massive overkill)
The gap: something between "quiz platform" and "game engine." Designed for interactive learning specifically. Why isn't it filled?
- Fragmented market (each domain has different needs)
- Wrong buyer (schools buy from vendors, not indie tools)
- Vague category ("interactive learning" means many things)
- Wrong abstraction (game engines give you frame loops and entities; you want puzzles, hints, progression)
- Builder/user mismatch (educators want it; developers could build it; overlap is small)
Maybe the right abstraction hasn't been found. What ARE the primitives of interactive learning?
- Challenge - present a problem, evaluate a solution
- Progression - track what's learned, unlock next
- Hints/scaffolding - help when stuck without giving answer
- Feedback - immediate response to actions
- Sandbox - safe space to experiment
- Constraints - what's allowed in a solution
Feedback is the hard part. Programming puzzles: run it, check output. Easy. But:
- Math: symbolic equivalence (hard)
- Logic: proof verification (Lean does this, but specialized)
- Language learning: evaluate a sentence? Subjective.
- Design: even more subjective
- Music/writing: ???
Evaluation is domain-specific and often hard to automate. That's why programming puzzles are over-represented - feedback is tractable.
If you can't automate eval, your options:
- Human grading (doesn't scale)
- Multiple choice (shallow interaction)
- Constrained input that's checkable (limits expressiveness)
- LLMs??? (fuzzy eval, whole can of worms)
But: non-problem-solving interactivity is still valuable. Even without eval:
- Music theory: play notes, hear intervals. No "correct answer," just experience.
- Design: drag elements, see how it looks. Exploration, not grading.
- Writing: rearrange paragraphs, see flow change. Sandbox, not test.
- Color theory: adjust sliders, see results. Immediate feedback without judgment.
The eval barrier only matters for "did you solve it correctly?" Exploration and play don't need eval. Interactive sandbox >> static explanation, even without grading.
Prior art: Bartosz Ciechanowski - interactive explainers with 3D visualizations. Mechanical watches, GPS, curves, internal combustion engines. Drag things, see how they work. No puzzles, just exploration. Incredible quality - but also one person with all four skills, doing it as a labor of love. Not scalable. Proves it's possible, doesn't prove it's accessible.
Directions Crystallizing
Interaction graph as first-class citizen. Not just "UI has actions" but actions-as-data, queryable, composable. Projectional rather than structural - you edit the structure, it projects to views. The graph IS the system; views are projections.
Unified workspace, not single-responsibility apps. Don't want: separate todo app, separate notes app, separate calendar, separate timer. Want: everything together, customizable layout, no context switching. FS, notes, calendar, todos, timers - different sources of objects, but same space.
This is what Notion/Obsidian try to be. What tiling WMs approximate. What personal computing environments aspire to. What makes this attempt different?
Maybe:
- Object sources are pluggable (not hardcoded integrations)
- Views are ALSO pluggable (milkdown vs CodeMirror vs remark+rehype+contenteditable for markdown - don't make users choose, allow all)
- Interaction graph is explicit (not implicit in UI code)
- Views are projections (not the source of truth)
- Layout is user-controlled (not app-dictated)
Connects to Canopy (universal client, control plane for any data source) and the MOO idea (everything is objects with verbs).
What are notes, in spirit? Externalized thoughts. Thoughts made persistent, retrievable, connectable.
So in the unified object graph: thoughts aren't a separate app. They're just objects. First-class. Connected to everything else - other thoughts, files, todos, calendar events, MOO entities, whatever. The "notes app" dissolves. There's just the graph, and some objects in it happen to be thoughts.
This reframes everything:
- Note-taking → adding thought-objects to the graph
- Linking notes → connecting thoughts to other objects
- Retrieval → graph traversal (not folder navigation)
- Organization → tagging/connecting (not filing into hierarchies)
The graph IS your external mind. Zettelkasten intuition, but not siloed in a "notes app" - integrated with everything.
But: "second brain" is a crowded space. Tiago Forte, Roam, Obsidian, Notion, Logseq, RemNote... Everyone's selling this. Aren't we reinventing the wheel?
What might actually be different:
- Not just notes - Most second-brain tools are note-centric. This is everything: files, todos, calendar, MOO entities, notes. Notes aren't special, just one object type.
- Pluggable sources AND views - Not locked to one editor, one storage, one renderer.
- Interaction graph is explicit - Actions are data, not implicit in UI code.
- Multiplayer - MOO integration. Not just personal notes - shared worlds.
- Not selling anything - Building for ourselves, not for market fit.
Is that enough? Honestly unclear. Maybe we're just doing "Obsidian but more ambitious." Maybe the combination matters. Maybe it doesn't and we're fooling ourselves.
The honest test: would we use it? If yes, build it. If it turns out to be just another second-brain app, at least it's ours.
Fundamental units of popular notes apps:
| App | Unit | What it means |
|---|---|---|
| Obsidian | File (markdown) | Everything is a .md file. Links between files. Folders for hierarchy. |
| Notion | Block | Text, heading, todo, database - all blocks. Pages are block collections. |
| Roam/Logseq | Block (bullet) | Outliner. Everything is a bullet. Block-level references. |
| Workflowy | Bullet | Pure outliner. Infinitely nested bullets. That's it. |
| Apple Notes/Evernote | Note (document) | Rich text document. Folders/notebooks. Traditional. |
| Google Keep | Card | Sticky-note sized. Checklists, images. Lightweight. |
| Tana | Node + supertag | Nodes have types. More structured than outliners. |
Observations:
- Files = filesystem mental model (Obsidian)
- Blocks = Lego bricks, composable (Notion, Roam)
- Documents = traditional "note" (Apple, Evernote)
- Nodes with types = structured data (Tana)
What's ours? Objects. Not files, not blocks, not documents. Objects with types, properties, connections. The unit isn't "text I wrote" - it's "thing that exists."
A stopwatch is an object. Data representation is trivial:
stopwatch: { state: running|paused|stopped, startedAt: timestamp, accumulated: duration, laps: [duration, ...] }
timer: { duration: duration, remaining: duration, state: running|paused|stopped }Don't store "current time" - store when it started, compute the rest. Laps are recorded moments.
Calendar events are objects. Saved webpages are objects. Tagged images are objects. Bookmarks are objects. Todos are objects.
calendarEvent: { title, start: timestamp, end: timestamp, recurrence?, ... }
savedWebpage: { url, title, savedAt: timestamp, content?, tags: [...] }
taggedImage: { path, tags: [...], caption?, ... }These aren't "apps." They're objects. Different types, different views, same system. No artificial boundaries.
But: isn't it impossible to render them all?
If every type needs a custom view, we're back to building infinite apps.
Maybe not. Options:
- Discriminated unions - objects have a type tag. Pattern match on type → specific view.
{ type: "stopwatch", ... }vs{ type: "calendarEvent", ... }. Exhaustive matching for known types. - Fallback rendering - unknown types show as property list (key: value). Not pretty, but works. Covers the long tail. Prior art: JSON Editor Online - any object as expandable tree. Works for anything.
- Composable view primitives - text, list, table, progress bar, timestamp, duration. Most types compose from these.
- Pluggable views - add custom renderers as needed. Don't need all upfront.
- Only build what you use - not trying to support everything. Just what matters.
A stopwatch view is: state indicator + duration display + lap list. That's primitives. A calendar event is: title + time range + maybe recurrence indicator. Also primitives.
The hard part isn't rendering - it's defining the primitives well.
Multiple frontends (CLI, TUI, Discord, web): M types × N frontends = M×N views. Sounds bad.
But:
- N is small (4-ish frontends)
- Fallback (property list) works everywhere - even CLI can dump JSON
- Define views in terms of abstract primitives → each frontend implements primitives once
- Custom views are progressive enhancement, not requirement
So it's: N implementations of primitives + fallback + optional M×N polish. Tractable.
Stack? Rust because might as well?
- Core/backend: Rust (performance, safety, WASM target if needed)
- Web frontend: TS probably (React/Solid/whatever) - or WASM if ambitious
- CLI/TUI: Rust (ratatui, clap, etc.)
- Discord: Rust (serenity) or TS (discord.js)
Rhizome already has Rust (moss, etc.) and Lua (moonlet, zone). Fits.
But also: stack matters less than architecture. Get the object graph right, frontends can be rewritten. Don't overthink it.
Storage: pith-sql (libsql internally). Already in ecosystem. Fine.
Sync: MOO model + capability-based security. Server-authoritative, capabilities as access tokens. Niche but proven (MOOs existed, capability security is sound theory).
Perf characteristics - what do we need?
- Read-heavy? Write-heavy? (probably read-heavy for notes/workspace)
- Real-time sync? (for MOO parts, yes)
- Update frequency? (not game-level, probably)
ECS instead?
ECS (Entity Component System):
- Entities = IDs
- Components = data bags attached to entities
- Systems = logic operating on entities with certain components
Good for:
- Cache-friendly iteration (tight loops over components)
- Flexible composition (add/remove components dynamically)
- Game-like workloads (many entities, frequent updates)
For notes/workspace:
- Probably overkill
- Relationships matter more than iteration speed
- Not updating thousands of entities per frame
For MOO simulation:
- Maybe? If we have lots of NPCs/objects with behaviors
- Traditional MOO wasn't ECS... but also had harsh constraints:
- Gas limits / tick quotas (can't run expensive code)
- Single-threaded (one server, one process)
- Scaling limitations (can't easily distribute)
So "MOO worked fine" is misleading - it worked within restrictive limits.
ECS advantages for scale:
- Parallelization (systems run in parallel over component sets)
- Distributed simulation (entities can potentially shard)
- Predictable performance (no runaway user code)
Verdict: Depends on ambition.
- Personal workspace + small multiplayer → libsql is fine
- Massive shared world → probably need ECS or similar
- Can start simple, but architecture may need revisiting if scale matters
What's the actual impl cost of ECS?
Using existing libraries (bevy_ecs, hecs, legion in Rust):
- Not much code to integrate
- Well-tested, performant
- Learning curve for the mental model
Real costs:
- Mental model shift - components/systems vs objects/methods. Different way of thinking.
- Relationships are awkward - ECS is traditionally weak on entity references, parent-child, graphs. Some libs adding this (bevy relations) but not native.
- Persistence - ECS is usually in-memory. Syncing to DB adds complexity.
- Debugging - harder to inspect than "here's the object"
- Boilerplate - registering components, defining systems, queries
For notes/workspace:
- Costs (relationships, persistence, mental model) hurt
- Wins (cache efficiency, parallelism) don't matter much
For simulation layer specifically:
- Could use ECS just for that part
- Keep object graph for everything else
- Hybrid: objects in libsql, hot simulation in ECS, sync between
Realistically: ECS is cheap to add via library, expensive to make the right choice for the problem.
Wait - is notes/workspace really relationship-heavy?
All stopwatches have the same shape. All timers. All calendar events. That's ECS territory - many similar entities.
But:
- We don't iterate all stopwatches every frame
- We query by relationship/tag more than component type
- "Systems" aren't "update all X" but "render this specific X"
Weird hybrid?
- ECS-like: typed component storage, efficient by-type queries
- Graph-like: first-class relationships, navigate by reference
- No tick-based systems, just reactive/on-demand
This is what property graph databases do (Neo4j-ish). Or... what a relational DB already does?
- Tables = component types
- Rows = entities with that component
- Foreign keys = relationships
- Indexes = efficient queries
Maybe the "hybrid" is just SQLite/libsql used well, with a layer that makes it feel like objects. Not novel architecture - just good data modeling.
Alternative hybrid: lazy promotion
- Default: everything stored as objects in DB (simple, flexible)
- When needed: "promote" hot paths to ECS / in-memory / computed views
Like:
- Cold storage: libsql (all objects)
- Hot path: ECS or in-memory cache for simulation tick
- Computed views: materialized queries for common patterns
Promotion could be:
- Manual (developer marks hot paths)
- Automatic (based on access patterns)
- Domain-specific (simulation entities → ECS, notes → stay in DB)
Overkill to build upfront? Yes. But reasonable to design for:
- Start with everything in DB
- Profile, find actual hot paths
- Promote those when needed
For notes/workspace: probably never need it. For MOO simulation at scale: might need it.
But wait - they're the same app. That's the whole point. Unified object graph. Notes and MOO entities live together.
So it's not "this app needs ECS" - it's "these specific object types / query patterns need optimization." Granular promotion within one system.
Which actually argues FOR the lazy promotion architecture:
- Same graph, different performance characteristics per region
- Notes stay cold (DB), simulation entities go hot (ECS) when active
- Promotion is per-type or per-query, not per-app
Don't build it until you need it, but don't architecture yourself into a corner.
Ready to impl?
What's crystallized:
- Unified object graph (everything is objects with types)
- Discriminated unions, fallback rendering
- Pluggable sources AND views
- Interaction graph as first-class
- Storage: libsql (pith-sql)
- Sync: MOO model + capabilities
- Lazy promotion for hot paths (design for, build later)
- Multiple frontends: CLI, TUI, Discord, web
What's still fuzzy:
- Exact object schema / type system
- Query/relationship model details
- How capabilities work in practice
- First frontend to build
- Which object types first
Minimal viable start?
Frontend-agnostic. Focus on the core:
- Object storage in libsql
- Type system (discriminated unions)
- Relationships / edges / tags
- Query model
Object types are almost free - they're just data:
thought: { content, tags, ... }
stopwatch: { state, startedAt, accumulated, laps }
timer: { duration, remaining, state }
calendarEvent: { title, start, end, recurrence? }
savedWebpage: { url, title, content?, tags }Define all of them. The interesting work is the infrastructure:
- How objects are stored
- How types are discriminated
- How relationships work
- How queries find things
Decisions:
Storage: JSON blob. Not table-per-type. Schema is loose, not all data follows it.
CREATE TABLE objects (
id TEXT PRIMARY KEY,
data JSON NOT NULL
);
CREATE INDEX idx_type ON objects(json_extract(data, '$.type'));Type is just a property. Not special. Everything in the blob.
Timestamps, tags, relationships, type - all in blob. Promote to columns when query patterns demand. Minimal schema = maximum flexibility.
Is document store on SQLite a bad idea?
Arguments against:
- SQLite's strength is relational - ignoring that
- JSON parsing overhead on every query
- Indexes on json_extract less efficient than column indexes
- If you want document store, use a real one (Mongo, Couch)
- Lose type safety at DB level
Arguments for:
- SQLite is everywhere, embedded, zero-config, single file
- JSON support is actually good now (json_extract, json_each)
- At personal scale, perf difference is negligible
- Flexibility - schema in code, not migrations
- Local-first friendly, easy backup
- Can promote to columns when needed
- Don't need another dependency
Verdict: Tradeoff. Bad if you need relational power at scale. Fine for flexible personal tool. We're not building MongoDB competitor - we're storing objects in a file. SQLite + JSON is pragmatic.
But: "nothing more permanent than a temporary solution."
"We'll promote to columns later" → we never will. The JSON blob becomes the architecture. Is that actually fine?
Options:
- Accept it - JSON blob forever. If it works, it works. Don't pretend we'll migrate.
- Start with columns - type, created_at, common fields as columns now. Pay the design cost upfront.
- Abstract the storage - API doesn't expose structure. Can swap implementations without changing callers.
Option 3 might be the honest answer: if the API is create/get/query/update/delete, the storage is an implementation detail. JSON blob today, columns tomorrow, who cares. The abstraction protects us.
But also: are we overthinking this? It's a personal tool. If JSON blob works, ship it.
The real concern: query performance.
A graph without search is useless. Common queries:
- Find all objects of type X
- Find all objects tagged Y
- Find all children of object Z
- Full-text search across notes
- Traverse relationships
If every query parses all JSON blobs, that's O(n) parsing per search. Bad.
Solutions that coexist with JSON blob:
- Indexes on json_extract - helps for simple field queries
- Generated/computed columns - SQLite supports these
- Separate index tables - denormalized for query patterns
- FTS5 - SQLite's full-text search for content
So it's not blob OR columns. It's:
- Blob for storage (flexible, schemaless)
- Indexes/columns for query (fast, specific)
Blob is source of truth. Indexes are derived. Add indexes for patterns you actually use.
Remaining downsides of JSON blob:
- No schema at DB level - can insert malformed data. Enforce in code.
- Partial updates = read-modify-write - can't
UPDATE objects SET data.title = 'x'. Have to read blob, modify, write back. Race conditions possible. - No referential integrity - relationships in blob aren't enforced. Dangling references possible.
- Migrations are implicit - old objects have old shapes. Handle in code.
- Joins are awkward - can't easily join across JSON fields.
- Less compact - JSON is text. Typed columns are smaller.
Are these dealbreakers? Depends.
- Schema in code: fine if you're disciplined, validated types
- Partial updates: problem if concurrent writes matter. For personal tool, probably fine.
- Referential integrity: problem if you care about consistency. Can check on read/write.
- Migrations: problem at scale, fine for small data.
For personal object graph: probably all acceptable. For production multi-user: think harder.
But: concurrency is a solved problem. Don't invent. Pick from existing solutions:
| Approach | How it works | When to use |
|---|---|---|
| Last-write-wins | Latest timestamp wins | Personal, casual, don't care about lost writes |
| Optimistic locking | Version field, reject stale, retry | Multi-user, low contention |
| CRDTs | Conflict-free types, auto-merge | Real-time collab, offline-first |
| OT | Transform concurrent ops (Google Docs) | Real-time text editing |
| Event sourcing | Store events, derive state | Audit trail, complex merges |
For this project:
- Single user → last-write-wins (free)
- Casual multi-user → optimistic locking (version field)
- Real-time MOO → CRDTs if needed later
The problem isn't unsolvable. We just pick the right solution for the use case.
Or: this is a userspace decision.
Don't pick ONE global strategy. Let it be per-object or per-type:
- Notes (collaborative) → CRDT
- Stopwatch → last-write-wins (or owner-only)
- MOO room description → optimistic locking
- Calendar event → depends on sharing model
Storage layer just provides primitives (version field, timestamps). Application layer picks strategy per object/type. Concurrency policy isn't baked into storage - it's a layer above.
More flexible. Different objects have different consistency needs.
Edges/ownership: just properties. All relationships are data in the blob:
{
parent: "id", // ownership/containment
children: ["id", ...], // explicit if needed
links: ["id", ...], // outgoing references
backlinks: ["id", ...] // incoming (computed or stored)
}Backlinks could be:
- Computed on query (find where
linkscontains this id) - expensive - Stored explicitly (denormalized, sync on write) - faster reads
- Materialized view / index - best of both
Start with computed, cache/denormalize when perf matters. No separate edge table - edges are just properties.
Tags: just a component. { tags: ["foo", "bar"] } in the blob. Computed view or index for efficient tag queries:
-- or use json_each for tag lookups
CREATE INDEX idx_tags ON objects(json_extract(data, '$.tags'));API: capability-based = no raw SQL exposed. Interface is probably just CRUD:
create(type, data) → idget(id) → objectquery(filters) → objects(by type, by tag, by parent, etc.)update(id, data)delete(id)
That's probably enough to start. Frontends consume this API.
But even programming guides don't have interactivity. Eval is tractable for code. Still mostly blog posts. So eval difficulty isn't the only barrier - there's also:
- Tooling friction (setting up a runnable environment is work)
- Format expectations (people expect to write blog posts, not build apps)
- Effort/reward mismatch (interactive takes 10x effort, gets same engagement)
- "Good enough" syndrome (text tutorial works, why bother)
What's missing: a format for "here's the insight, here's how it applies" without the essay wrapper. Not polished think-pieces. Just... notes that are findable.
Obsidian is designed for exactly this - rough notes, atomic pages, cross-link. But knowing the tool exists doesn't mean you use it. Barriers:
- Self-doubt ("am I even right about this?")
- Bias ("this is just my opinion")
- Scope creep (keep expanding instead of finishing)
The thinking phase is fun. The extracting-and-organizing phase is tedious. Guess which one happens.
(Partial implementation exists at $dayjob: categorization + curated category/entry order, no frecency. But - actions are modal based on registered keybinds, and component tree determines scope: deeper components add actions to the top. So there's implicit context-awareness from the hierarchy. Personal preference, unproven whether it actually helps. N=1.)
Anti-patterns in bad software:
- Hidden features only in docs/forums ("just triple-click while holding shift"). Bonus points if docs are online-only.
- Modal confusion (which dialog is active? what mode am I in?) — though modality done right works: Kakoune's selection-first model makes state visible (you see what you're about to affect), not just a mode indicator in the status bar.
- Actions far from targets (menu bar for thing you're manipulating)
- Inconsistent patterns (sometimes drag works, sometimes doesn't)
- State invisible (did it save? is it processing? what's selected?)
- No undo, or partial undo
- Search as primary navigation (because nothing else works)
What's actually interesting right now?
Hard to say. Depends on mood, energy, what's frustrating at the moment. The honest answer: probably whatever's in front of you when you sit down to code.
The question remains genuinely open: what to build?
How do you fight it?
- Intentional constraints - gives permission to be limited
- Communities that celebrate "good enough" - Neocities, small web, zines
- Rejecting polish as a goal - "done is better than perfect"
- Small audiences being okay - three people and their dog, remember?
- Process over product - sharing WIPs, learning in public
- Nostalgia/retro aesthetics - pixel art, chiptunes, lo-fi as deliberate choice
But honestly? No idea if there's a systemic fix. Might just be: find your corner, ignore the algorithm, make things for yourself and the few who care.
The platform era raised the bar by showing everyone the highlights. Maybe the post-platform era (if it comes) lowers it again by hiding them.
Personal example: SillyTavern character cards
Writing character cards is a form of creative output that works this way:
- Don't follow rigid formats (no W++, ew)
- Intentionally "break the mold" - write as journal entries, voice notes, Obsidian fragments, pieces of a character's life
- Not trying to be a Great Writer - just conveying a vibe
- The cards end up relatively "complete" - and when run through an LLM, they convey the intended vibe
- LLMs can help flesh things out: "write me an intro message," "suggest a direction," or just interact with the card to figure out why it feels off
This is the pattern:
- Start with fragments (not a complete story, just pieces)
- They're immediately "real" (you can chat with the character)
- Iterate by interaction (talk to it, see what's off, adjust)
- Tools assist, not replace (LLM helps, but the vibe is yours)
No blank page. No rigid template. Fragments that accumulate into something with a feel.
Tangent: the NN elephant in the room
Common angle: "neural networks bad, steals jobs." And honestly? Valid concern. Malicious actors do what they do. Artists getting ripped off. Content farms. Deepfakes. Real harms.
But: are NNs (image diffusion, LLMs, etc.) a net negative? Who knows. Genuinely unclear.
What's clear:
- They can be tools that lower creative barriers (character cards, iteration, "what's off?")
- They can be tools that replace creative labor (content farms, "good enough" slop)
- The same technology enables both
- The outcome depends on who's using it and how
Not taking a strong stance. Just noting: the tooling conversation happens in this context. "LLMs help you iterate on character cards" coexists with "LLMs let corps fire writers." Both true. Uncomfortable.
A little sad that the vocal sides are so polarized. "AI will save everything" vs "AI is theft and destruction." But there are plenty of people with nuanced takes - pointing out specific harms without condemning the whole technology, or acknowledging benefits without ignoring costs. They just don't get the engagement that hot takes do.
The nuanced position is boring: "some uses good, some uses bad, depends on context, we should think carefully." Doesn't fit in a tweet. Doesn't generate outrage. Probably closer to true.
General stance: build up abstractions.
But the question remains: which abstractions? That's the hard part. Wrong abstractions are worse than no abstractions.
Hacker culture is cool. One advantage of the Lua repo: everything's small. Anyone could, if they wanted, just look at it. grep.lua is 12 lines. The HTTP library is 442 lines total. No magic. No "trust the framework." You can read it.
This is a form of accessibility that gets overlooked:
- Not just "easy to use" but "easy to understand"
- Not just "low barrier to start" but "low barrier to inspect"
- View source → learn → make your own (the early web energy)
Big frameworks are powerful but opaque. Small pieces are limited but transparent. The Lua repo optimizes for transparency. Anyone can become a contributor because anyone can read it.
Open question: can you have both? Powerful abstractions that are also transparent? Or is there a fundamental tradeoff?
Maybe the answer is: layers of small transparent pieces, where each layer is understandable on its own. You don't need to understand all 442 lines to use the HTTP client - just the 17 lines of client.lua. But if you want to go deeper, you can.
100 Rabbits follows this philosophy too. Uxn/Varvara is intentionally constrained and transparent - you can understand the whole thing. It's a choice to optimize for comprehensibility over power.
Related: todepond's "Just"
A piece critiquing "just" as a word that hides complexity:
- "Just use the command line"
- "Just rent a server"
- "Just use a framework"
Each "just" masks layers of prerequisite knowledge. What seems simple to experts is a learning cliff for others. The word is accidental gatekeeping.
The piece argues: instead of false reassurance ("just do X"), actually make things genuinely accessible. Acknowledge the barriers. Work to remove them, don't pretend they don't exist.
This connects to everything:
- "Just make a website" hides DNS, hosting, HTML, CSS, deployment...
- "Just write a character card" hides format knowledge, LLM quirks, prompt engineering...
- Low barriers should be real low barriers, not "just" hiding the cliff
Prior art collection moved to prior-art.md - a living document of things worth knowing about.
Why don't people just... spontaneously do these things?
The tools exist. The communities exist. Why isn't everyone making things?
Possible answers (probably all true to some degree):
Don't know it exists - Discoverability. You can't join what you've never heard of.
"I'm not a [creator/programmer/artist]" - Identity barrier. People sorted themselves into "creators" and "consumers" and don't cross.
Barriers are higher than they look - The "just" problem. Looks easy until you try.
No time/energy - Attention economy ate everything. People are exhausted. Creating takes surplus.
Social risk - "That's weird." Embarrassment. What if it's bad? What if people judge?
No path from consumer to creator - Platforms have "post" buttons, not "build" buttons. The affordances aren't there.
Reward loop mismatch - Platforms give instant dopamine (likes, notifications). Creation takes time before payoff. Hard to compete.
Learned helplessness - "I tried once and it was hard/bad, so I'm not a creator." One bad experience closes the door.
No community - Creating alone is hard. The communities exist but are invisible (see #1).
It's not the default - You have to actively seek it out. The default is consumption.
The tragic loop: people don't create → communities stay small → communities stay invisible → people don't know they could create → ...
Breaking the loop probably requires: lowering real barriers (not "just"), making communities visible, providing paths from consuming to creating, and somehow competing with platform dopamine.
The (unfortunate) exception: Roblox
Roblox actually got millions of kids creating. It proves the model can work at scale:
- Low floor (visual scripting, templates)
- High ceiling (Lua scripting, full games)
- Built-in audience (your friends are already there)
- Path from player to creator is visible
- Social reward loop (people play your thing!)
But the "unfortunate" part:
- Exploitative revenue share (creators get pennies)
- Robux economy designed to extract money from kids
- Child labor concerns (kids making content, platform profits)
- Walled garden (you don't own what you make)
- Enshittification trajectory (ads, monetization pressure)
Roblox proves it's possible to get mass creation. It also proves you can do it in deeply exploitative ways. The question: can you get the good parts (low floor, visible path, social rewards) without the extractive business model?
Maybe the answer is: not at Roblox scale, because that scale requires VC money, which requires extraction. The good version might only work smaller.
But we're not trying to be a platform.
Has anyone tried to make a non-platform creative substrate? Actually... yes, lots of niche things:
| Tool | Domain | What it is |
|---|---|---|
| Strudel | Music | Live coding music in browser |
| TidalCycles | Music | Algorithmic pattern-based music |
| Processing | Visual art | Creative coding, visual sketches |
| p5.js | Visual art | Processing for the web |
| PuzzleScript | Games | Puzzle games in ~100 lines |
| Twine | IF/narrative | Interactive fiction, no code needed |
| Ren'Py | Visual novels | Python-based VN engine |
| RPG Maker | Games | Make JRPGs |
| PICO-8 | Games | Fantasy console, intentional constraints |
| thi.ng/umbrella | Computational design | Massive toolkit for generative art, data structures |
| Sonic Pi | Music | Live coding, education-focused |
These exist! They're not platforms - they're substrates. You make things with them, you own what you make.
Common threads:
- Domain-specific - each is good at one thing
- Owned output - what you make is yours
- Community, not platform - forums, Discord, sharing, no algorithmic feed
- Often free/open source - not extractive
- Low floor, high ceiling - varying degrees, but the pattern is there
What they're NOT:
- Interconnected (PuzzleScript can't talk to Twine)
- General-purpose (each is its own silo)
- Discoverable to normies (niche communities)
The Rhizome question: what if the substrate was general? What if the domains could connect? What if the silo walls came down?
Not "one tool to rule them all" - that's hubris. But maybe: shared primitives, interoperable formats, composition across domains?
Honest assessment: many of these tools are... questionable.
| Tool | The good | The wtf |
|---|---|---|
| Twine | Low floor, IF accessible | Not extensible, save dialog is blech |
| RPG Maker | Huge community | It's just JSON + interpreter + awful settings UI. Why is it this big? |
| Ren'Py | Visual novels accessible | What even is that DSL |
| Game Maker | Actually quite decent | Proprietary, pricing changes |
| PuzzleScript | Elegant constraints | Very limited (by design, but still) |
These succeeded despite their flaws. The bar isn't as high as it seems? Or: filling a niche matters more than polish?
Better substrates for games exist:
- Godot - open source, general purpose, actually well-designed
- Bevy - ECS architecture, Rust, hyper-modular
- Both could be "substrate for multiple genres" rather than genre-specific tools
The pattern: well-designed general substrates (Godot, Bevy) vs poorly-designed niche tools (RPG Maker, Ren'Py). The niche tools won on accessibility/community, not on technical merit.
Implication for Rhizome: Maybe the goal isn't "better than Twine at IF" but "general substrate that makes Twine-like-things easy to build on top." Don't compete with the niches - be the layer they could build on.
What is a niche tool but an additional layer of abstraction?
| Niche tool | What it abstracts over |
|---|---|
| RPG Maker | JavaScript/JSON |
| Twine | HTML/JS |
| Ren'Py | Python |
| PuzzleScript | Custom engine |
| Strudel | Web Audio API |
They're all just... layers. Someone built an abstraction, it stuck, now it's "a tool."
The question: what's the right substrate to build those abstractions on?
Current reality: everyone picks their own base (JS, Python, custom). No shared primitives. Each niche tool reinvents persistence, state, UI, etc.
Alternative: shared substrate with good primitives. Niche tools become thin layers on top. The "RPG Maker layer" is just: preconfigured entity types + tile renderer + battle system. The substrate handles persistence, state, networking, etc.
This is the Bevy/Godot insight applied more broadly. They're substrates for games. What's the substrate for... everything?
(Actually not impossible - see thi.ng/umbrella. It's a substrate for... basically everything computational/generative. 190+ packages, all composable.)
The real constraint isn't "can you build a general substrate" - it's "can you expect to become the thing people use for everything." No. You can't. The ecosystem will stay fragmented.
But you can build a good substrate, use it yourself, let others use it if they want. It doesn't have to win. It just has to exist and be useful.
Why is software so big?
10k LOC. 100k. 1 million. 10 million. What do you mean?
grep.lua is 12 lines. The entire HTTP library is 442 lines. Uxn is intentionally tiny. LuaJIT is ~100k lines for an entire VM with JIT. So software can be small. Why isn't it?
Possible reasons:
| Reason | What it means |
|---|---|
| Accidental complexity | Cruft, legacy code, workarounds nobody removed |
| Essential complexity | The problem is genuinely hard (rare, but real) |
| Boilerplate | Languages/frameworks that require verbosity |
| Edge cases | Handling every possible situation, even rare ones |
| Dependencies | Pull in 10k LOC library for one function |
| Abstraction layers | Each layer adds code, often more than it saves |
| "Enterprise" patterns | Over-engineering for hypothetical future needs |
| Nobody deletes code | Only add, never remove. Fear of breaking things |
| Multiple platforms | Code for every OS/browser/config permutation |
| Defensive programming | Check everything everywhere, trust nothing |
| Tests | Good, but adds LOC (not a bad reason though) |
| NIH | Reinventing what already exists in dependencies |
| Job security | More code = more indispensable (cynical but real) |
The Lua monorepo is small because:
- LuaJIT is a good substrate (small, fast, embeddable)
- Intentional constraint (keep things small)
- One person's taste (no design-by-committee bloat)
- No backwards compatibility burden (can just change things)
- Composition over extension (small pieces that snap together)
The uncomfortable question: is most software big because it needs to be, or because the incentives reward bigness?
- More code = more "work done" = more justification for headcount
- Frameworks sell complexity as features
- Nobody gets fired for adding code, sometimes fired for deleting it
- Big codebases create moats (job security, vendor lock-in)
Maybe most software is big because small doesn't pay.
Case study: React vs Preact
| Library | Size | What it does |
|---|---|---|
| React | ~40KB+ (core) | Virtual DOM, components, hooks |
| Preact | ~3KB | ...basically the same thing |
Preact is 10-15x smaller and covers 95% of use cases. So why is React 40KB?
- More edge cases handled
- More features (concurrent mode, suspense, etc.)
- More abstraction layers
- Facebook scale requirements
- Legacy compatibility
- "Enterprise" needs
For most apps, Preact is fine. But React is the default because:
- It's what people know
- More tutorials/Stack Overflow answers
- "Nobody got fired for choosing React"
- Network effects
The 3KB version exists. People choose the 40KB version anyway. Size isn't the deciding factor. Ecosystem, familiarity, and safety are.
Oh, and React is now slow enough that it needs its own compiler (React Compiler, formerly "React Forget") just to make it perform well. The abstraction got so heavy they needed another layer of abstraction to optimize it.
Meanwhile Preact just... runs fast because it's small. No compiler needed.
Actually, it's not just size - it's architecture. React's model is "re-run the entire function every render." That's fundamentally wasteful. The compiler exists to work around a bad architectural decision.
Compare:
| Approach | How it works | Efficiency |
|---|---|---|
| React | Re-run everything, diff virtual DOM | O(tree size) every render |
| Vue | Fine-grained reactivity, track dependencies | Only update what changed |
| Solid | Signals, no virtual DOM | Only run code that depends on changed signals |
| Svelte | Compile away the framework | Minimal runtime, surgical updates |
Vue is bigger than Preact but still fast because the model is smarter. React is big AND uses a slow model. Worst of both worlds, "fixed" with a compiler.
The lesson: architectural decisions matter more than micro-optimizations. A smart small thing beats a dumb big thing with a compiler bolted on.
(Vue considered "Vapor mode" - compile-away like Svelte - but it became low priority. Why? Because Vue's reactivity is already good enough that the gains would be marginal. Good architecture upfront = less heroics needed later.)
Notably: Vue's reactivity (@vue/reactivity) is completely separate from the web framework. You can use it standalone. The primitives are decoupled from the application.
This is good decomposition - the substrate (reactivity) is independent of the layer on top (web components). React doesn't have this. React's model is inseparable from React.
The pattern again: good primitives, loosely coupled, compose upward.
Aside: Lua vs JavaScript accumulation
Feature-wise, they're pretty close. But:
- Lua's stdlib is intentionally barren
- JS's stdlib exists but... isn't even that good? Weird historical baggage, inconsistencies,
typeof null === "object"
The difference is accumulation:
- Lua: stays small, 5.1 → 5.4 is incremental, LuaJIT still on 5.1 and that's fine
- JS: keeps adding - classes, async/await, optional chaining, nullish coalescing, private fields, decorators, temporal, records & tuples...
Each JS addition makes:
- The spec bigger
- Implementations harder
- The "minimum viable JS engine" more work
Lua's barren stdlib is a feature - you add what you need via FFI/C, not via spec committee. JS's stdlib is a historical accident that keeps growing.
QuickJS is impressive (~80k lines for near-full ES2023) but it's an interpreter - no JIT. And it's still fighting uphill against a spec designed for browsers.
Corrections though:
- Lua is also designed by committee (PUC-Rio team) - but a small one with clear vision, not TC39 with a hundred stakeholders
- LuaJIT being small isn't just because Lua is small - it's a feat of engineering by Mike Pall. Lua helps, but the JIT itself is remarkable work
The difference might be: small focused committee (Lua) vs large stakeholder-driven committee (JS). And: one genius (Mike Pall) vs teams of hundreds (V8, SpiderMonkey).
Other examples:
- Moment.js (~300KB) vs day.js (~2KB)
- Lodash (~70KB) vs native JS + tiny helpers
- Express (~200 deps) vs bare http module
The small alternatives exist. They're often good enough. But "good enough and small" loses to "big and familiar."
What it demonstrates:
- Text can be incredibly deep - 4 years to build, near-inexhaustible combinations
- Constraints inspire innovation - text-only forced creative mechanics
- The IF community is alive - still producing, still ranking, still caring
- Systemic mechanics create emergence - the letter-remover isn't scripted puzzles, it's a system
Emily Short's work in general (Galatea, Savoir-Faire, the Versu engine) shows what's possible when you take text-based interaction seriously as a medium, not a limitation.
What would Rhizome's angle be?
- Not "make a website" but "make a world"
- Collaborative, not just personal (the SCP/wiki energy but interactive)
- Structured, not just text/HTML (queryable, composable)
- Programmable, not just static (things that do stuff)
- Discord as entry point (you're already there)
- Federatable (Hypha - your world, connected to others)
Maybe the early web's spirit isn't about websites specifically. It's about: personal creative spaces that you own and control, connected to others. That could be pages, or worlds, or objects, or whatever.
What makes people want to create?
- Seeing others create (inspiration, community)
- Having an audience (even small - three people and their dog)
- The creation being useful to them (scratching own itch)
- Low friction to start, high ceiling to grow
- Ownership (it's yours, not rented from a platform)
Platforms win on "audience" but lose on "ownership." Can you have both?
The adoption cliff: Maybe the reason things don't take off is brutal economics:
- You need to be nigh-impossibly better to overcome switching costs
- OR you need corporation-level funding for distribution/marketing
- "Slightly better" or even "significantly better" isn't enough
- Network effects protect incumbents
- "Good enough" wins over "great but different"
This is depressing but probably true. Rhizome doesn't have corporation funding. So: either be impossibly better, or don't compete head-on?
First-mover advantage: what succeeded primarily because it got there first?
| Software | First-mover element | Would it win today? |
|---|---|---|
| QWERTY | First popular typewriter layout | Demonstrably not optimal (Dvorak exists) |
| Excel | First killer spreadsheet on PC | Maybe? But VisiCalc/Lotus 1-2-3 came first |
| Windows | First "good enough" PC GUI for masses | Debatable - was it the best, or just pre-installed? |
| Word | First "good enough" word processor with network effects | Probably not on merit alone |
| Photoshop | First professional image editor | Has genuine technical depth, but also 30yr lock-in |
| JavaScript | First browser scripting language | Definitely not - it's famously flawed, but it's everywhere |
| x86 | First popular PC architecture | ARM is eating it now that the moat weakened |
| First universal document format | Genuine value, but also "just send me a PDF" inertia |
The pattern: technical merit gets you in the door, but staying power is often lock-in.
- File format lock-in (Word docs, Photoshop files)
- Ecosystem lock-in (Windows apps, JS libraries)
- Muscle memory lock-in (QWERTY, vim bindings)
- "It's what everyone uses" lock-in (Excel, PDF)
Implication for Rhizome: Doesn't matter. We're not here to compete or make money. We're here to explore. If something useful falls out of it, great. If not, we learned something.
Honest self-assessment: if we were optimizing for adoption, we picked literally the worst niches
| Project | Market reality |
|---|---|
| MOO | "What is that?" |
| Resin (procgen) | "Just use Godot's tooling/plugins" |
| Rescribe | "Pandoc is pretty solid" |
| OOXML | "Who parses docx? Just read them. Also other languages have decent support" |
| Canopy | "It's like Postman but different and too general - would it even be usable?" |
| Frond (game primitives) | "Too general. Everyone writes their own because they want to optimize for their usecase" |
| Reed (transpiler) | "Why? Just learn the other language" |
| Cambium (format conversion) | "ffmpeg/pandoc/imagemagick exist" |
Customer base: three people and their dog.
But that's fine. These are explored because they're interesting, not because they're marketable. The goal is understanding, not adoption.
Nuance: They all have value propositions - otherwise why start? But enough to be a moat / stand out from competition? Probably not. Though honestly, small niches are often enough. Don't gotta disrupt.
Contradiction: We've identified tons of software with room to improve (Excel, multi-app workflows, settings sprawl, interaction paradigms...). But is that why we're here? To fix those things? Or to explore interesting ideas that happen to touch on them?
The honest answer: mostly exploration. If improvement falls out of it, bonus. But "Excel is bad" isn't the motivation - it's an observation that informs the exploration.
So what IS the actual motivation?
Trying to articulate it honestly:
"What if?" - Contrarian questioning. What if interaction was structured? What if notes/files/objects were the same thing? What if we didn't accept these tradeoffs?
Understanding by building - NIH not for pride, but for learning. Can't truly understand something until you've built it (or tried).
Composition - The joy of small pieces that snap together.
grep.luais 12 lines because the libraries exist. That feeling of "take this + this + this = working thing."Scratching itches - MOO exists because of wanting inventory in Tavern cards. Rescribe exists because pandoc isn't perfect. Real needs, even if niche.
- Parallel MOO motivation: collaborative worldbuilding. ChatMUD gave a taste of this. Exploring things other people built. Creating in the same universe. Being able to interact with and create things in a shared persistent world. SillyTavern doesn't have this. Most AI RP sites have multiplayer maybe, but that's not the same thing. Multiplayer is playing together. Collaborative worldbuilding is building together, and then the builds persist for others to discover.
- Maybe this is part of why Minecraft and Terraria are so wildly successful? Not just "play together" but "build together, and it stays." The creations persist. Servers become places with history. You can stumble on something someone else made months ago. That's different from match-based multiplayer where nothing carries over.
- Barrier to entry matters hugely. Discord as a first-class frontend for MOO wasn't just "a nice option" - it was THE motivating factor. People are already there. No client download. No new interface to learn. Just... type in a channel you're already in. That's why text-based interfaces still have value despite being "primitive" - they meet people where they are.
- But collaborative worldbuilding DOES exist elsewhere: Orion's Arm, SCP Foundation, fanon wikis, AUs, CYOA wikis. These are thriving collaborative worlds. The difference? They're documentation-based, not interaction-based. You write an article about an SCP anomaly. You don't encounter it in a shared space. Both are valid, different experiences. Wiki worldbuilding is "here's lore." MOO worldbuilding is "here's a thing you can poke."
"Should exist" - Some things just should exist and don't. So make them exist.
The moonshot - Subsume all computer interaction. Absurd, probably impossible, but it's the north star that gives direction.
None of these are "make money" or "get users" or "beat the competition." They're all intrinsic.
The meta-motivation: Enjoying the process of exploring ideas and building things. The destination matters less than the journey being interesting.
But wait - things that DID take off without corp funding:
| Project | Creator(s) | Why it worked |
|---|---|---|
| Linux | Torvalds | Free Unix for PC, ideological momentum, filled real gap |
| Git | Torvalds | Scratched own itch (kernel dev), became essential |
| QEMU/TCC | Bellard | Single genius, infrastructure niches |
| FFmpeg | Bellard + community | Everyone needs media handling, became indispensable |
| LuaJIT | Mike Pall | Single genius, insane performance, filled real need |
Common threads:
- Infrastructure, not end-user apps - They enable other things
- Filled genuine gaps - Not "slightly better", but "this didn't exist / was unaffordable"
- Became dependencies - Hard to NOT use them once established
- Scratched own itch - Built for themselves first
- Single genius or tiny team - Not committees
- Technically extraordinary - Not just good, but "how did one person do this?"
Maybe the pattern: build infrastructure that becomes indispensable, not apps that compete for users.
Question: "It's 2026, why don't tons of things exist yet?"
Hypothesis: How many people could actually pull a Bellard, Pall, Torvalds, Gerganov?
- Before LLMs: vanishingly small pool of "single genius" builders
- These people are rare, busy, or working on other things
- Even with LLMs: how many can really build ambitious infrastructure?
- Gerganov (ggml, llama.cpp) is recent - proves it's still possible
- But the list of people who can is still very short
- Maybe things don't exist because the people who could build them are occupied elsewhere
This isn't defeatist - it's realistic. The question isn't "why hasn't someone built X" but "who specifically would have built X, and why didn't they?"
Maybe: human insight + LLM volume = ambitious things without singular genius?
Or maybe that's cope. Time will tell.
Honest self-assessment:
- Not a novice programmer, but not deeply experienced in any one domain
- Contrarian exploration = broad exposure, shallow depth in many areas
- No time/motivation to go deep everywhere - so what to focus on?
- Don't believe in "talent" - but experience? Absolutely limited.
- burn-models: vibe coded, don't actually know NN architectures
- resin: vibe coded, don't know blender/houdini/demoscene/procgen
- lotus: built on the backs of SO many failed prototypes
- Some weren't even failures - just didn't match the vision
The pattern: LLM-assisted lets you explore domains you don't have deep expertise in. You bring the vision + general programming sense, LLM brings domain knowledge at a basic level. Iterate until it works.
Whether this produces good code or just working code is an open question.
On "LLMs are just text predictors":
Common dismissal: "I'm so smart, I learned LLMs are 'just' text predictors, they can't make anything new."
Okay but... moss exists. 90k lines. It works.
"They're just reproducing if-statements they've seen before." Sure. But:
- Humans also don't create from nothing - we remix prior knowledge
- "New" is novel combinations, not ex nihilo creation
- Evolution is "just" random mutation + selection - yet here we are
- The "just" is doing a lot of heavy lifting in that dismissal
What matters: does the thing work? Not "is it philosophically novel?"
The dismissive framing mistakes mechanism for capability. Yes, it's "just" predicting tokens. And brains are "just" neurons firing. So what?
Holding both things at once:
- Yes, LLMs have real limitations (no persistent learning, debatable agency, hallucinations)
- AND: this entire ecosystem exists. moss, burn-models, lotus, all of it.
- That's not a trivial result.
- Limitations don't erase outputs. Outputs don't erase limitations.
- The honest position: "limited but useful" not "magic" or "useless"
- (Also: "limited but useful" describes lots of people too)
Underrated LLM strengths:
- Will Just Write Tests (people say "good tests are hard" then don't write them)
- Will do tedious refactoring without complaining
- Ecosystem knowledge - knows about libraries, APIs, conventions you'd have to learn
- Available at 3am when you have an idea
LLMs DO cut corners though:
- "I'll batch the rest..." (no you won't, do all 98 grammars)
- Placeholder code, TODO comments, "similar for the rest"
- Requires pushing to actually complete tedious work
- Different laziness, but still laziness
But: the same is true for "naturally programmed" codebases. Arguably even more true:
- Tech debt accumulates over time
- "The way we've always done it" calcifies
- Humans make the same mistakes repeatedly
- Organic growth → inconsistent architecture
- LLM-assisted might actually avoid some tech debt by not knowing the baggage
- Rapid iteration + no consumers = "just refactor without deprecation"
- No API stability guarantees yet = freedom to get it right
The bar isn't "is this perfect?" - it's "is this better than the alternative?"
Where is MOO's equivalent today?
LambdaMOO, ChatMUD - they exist, they're neat. But:
- Text-based is a high barrier
- Even for "okayish programmers" it's manageable, but for everyone else?
- Where's the modern equivalent?
| Platform | Programmable? | Shared worlds? | Barrier |
|---|---|---|---|
| LambdaMOO | Yes (verbs) | Yes | High (text, programming) |
| Roblox | Yes (Lua) | Yes | Medium (visual, but still code) |
| Minecraft | Kinda (redstone, mods) | Yes | Low base, high for creation |
| VRChat | Yes (Unity/Udon) | Yes | High (Unity knowledge) |
| Second Life | Yes (LSL) | Yes | Medium-high |
| Resonite | Yes (ProtoFlux) | Yes | Medium (visual programming, in-world) |
| Rec Room | Limited | Yes | Low |
Roblox is maybe the closest to "programmable shared worlds for everyone" - and it's massive. But:
- Game-focused (not general purpose)
- Corporate, proprietary
- Kid-oriented aesthetic
- You're building on their platform, not with general tools
Is there interest? Roblox proves yes. TikTok proves people want to create (short-form, but still). The interest exists.
What's missing: Open, general-purpose, low-barrier programmable object system. MOO philosophy + modern accessibility + not corporate-owned.
Is that what lotus/MOO-in-zone should be?
Can LLMs be the accessibility bridge?
The dream:
User → "I want a chest that only I can open"
↓
LLM → generates verb, explains what it did
↓
User → tweaks if needed
↓
Working thingBut: is this a bandaid?
Honest concern. Reed exists partly for this - write TS (familiar), compile to Lua (runtime). But:
- Hiding complexity ≠ removing complexity
- LLM generates wrong code sometimes → debugging something you didn't write
- Dependent on external services (API costs, availability)
- "Describe what you want" works until it doesn't, then you're stuck
- Doesn't solve fundamental complexity, just masks it
Counter-arguments:
- Even bandaids are useful (people ship with bandaids all the time)
- LLM + human review > human alone for many tasks
- Maybe masking complexity IS solving it for 80% of cases
Hot take: maybe the alternative IS "hope people learn to code"?
- Programming literacy could be like reading/writing literacy
- Instead of dumbing down tools, improve education
- Raise the floor of human capability, not lower the ceiling of tools
- "People can't learn" is a cop-out - people learn hard things all the time
- The problem might be teaching, not learning capacity
Hotter take: every programming language sucks. All of them.
- Not "teaching is bad" - the languages themselves are bad
- Every language is a pile of tradeoffs and historical accidents
- Syntax errors, type errors, null pointers, async hell, dependency hell
- Even "good" languages have foot-guns and gotchas
- We've been doing this for 70 years and it still sucks
- Maybe programming is just hard and we haven't found the right abstractions yet
- Or maybe text-as-code is fundamentally limited (see: reed's "no syntax errors" philosophy)
- But: visual/structure editors have existed forever. They haven't "won" either.
Essential vs accidental complexity:
- Some complexity is inherent to the problem domain (essential)
- Some is caused by bad tools/languages (accidental)
- Fred Brooks' "No Silver Bullet" (1986) - still relevant 40 years later
Counterpoint: abstraction (potentially recursive)
- You can't eliminate essential complexity, but you can layer it
- Build abstractions, hide details behind interfaces
- Work at the right level for the task
- Yes, abstraction is limited. But everything is a tradeoff.
- The question: what are the right abstractions? We clearly haven't found them yet.
Maybe there is no single "right" abstraction:
- Different problems want different abstractions
- The meta-skill is knowing which abstraction fits which problem
- So: tools that let you work with multiple abstractions, not tools that force one paradigm
This is why hyper-modularity matters. See: Bevy's mindset.
- Everything is a plugin
- ECS as composable substrate
- "Bring your own" for most features
- Pick the pieces you need, leave the rest
- Rhizome's decomposition (pith, moonlet, reed, etc.) aims for this too
- MOO's "substrate only, user-space everything else" is the same idea
Fractal modularity: the pattern repeats at every level
- Rhizome ecosystem: pith, moonlet, reed, moss, etc. - pick what you need
- Each monorepo: same structure internally (core + modules)
- Each module: small, focused, composable
- It's turtles all the way down
Unresolved: Is there a way to make programmable systems actually simple, not just LLM-assisted? Or is complexity irreducible and the best we can do is better interfaces to it?
Other experiments in "making programming easier":
| Project | Approach | Status |
|---|---|---|
| Hazel | Typed holes, structure editing, live programming | Research, active |
| Synquid | Synthesis from refinement types (write types → code generated) | Research |
| Sketch | Program synthesis from specs | Research |
| Codeium/Copilot | LLM autocomplete | Commercial, widespread |
| Snap!/Scratch | Visual blocks | Educational |
So many experiments. Some research, some commercial. None has "won" for general-purpose accessible programming. The search continues.
This is a failure. Not a technical impossibility. A collective failure of imagination or will.
Is this something rhizome should care about? "Anyone can make interactive things" as a goal?
Reality Check: Why Doesn't This Exist?
Skeptical question: If "structure for agents" is such a good idea, surely someone's done it?
Prior Art (it partially exists)
| Problem | Existing solution |
|---|---|
| API specs | APIs-guru/openapi-directory - 2000+ OpenAPI specs |
| Universal primitives | WASI - already standardized |
| Structured parsing | Tree-sitter - 100+ grammars |
| Code intelligence | LSP - protocol exists |
| Structured notes | Obsidian, Notion, Roam |
| Programmable objects | LambdaMOO - 30+ years old |
So What's Actually Novel?
Possible answers (guesses, being realistic):
Pieces exist, not unified - Tree-sitter exists, LSP exists, but "moss" combines them differently. OpenAPI directory exists, but "liana" does codegen. The composition might be novel.
"Agent" framing is new - Pre-LLM, "make things structured for agents" wasn't compelling. Now that AI agents are real, the framing matters more.
Not commercial - Infrastructure plays, hard to monetize. Big companies don't build this; hobbyists do.
Integration is the hard part - Making an OpenAPI directory is easy. Making it actually composable with code intelligence, format conversion, programmable objects, etc. is the real work.
NIH syndrome - Everyone builds their own slightly different version. No unified ecosystem.
Why This Is Hard
Scope creep - Look at the project list. Each one is ambitious on its own.
Massive LOC - Moss alone is substantial. Multiply by 14 projects.
Years of work (pre-vibe-coding) - Before LLM-assisted development, this would be years of solo work with no clear payoff.
No clear commercial usecase - Hard to pitch "structured interfaces for agents" to investors.
Chicken-and-egg - Need critical mass of integrations to be useful, but can't get adoption without being useful first.
Moving targets - APIs change, specs evolve, languages update. Maintenance burden compounds.
What Makes It Viable Now?
LLM-assisted development - Can write more code faster. Moss itself helps write moss.
Concrete examples:
Moss (code intelligence)
- 90k lines of Rust, 119k total
- Started: December 17, 2025 → functional in ~1 month
- Traditional estimate: "23.49 months with 15.47 people"
burn-models (ML inference)
- 44k lines of Rust (rest is tokenizer vocab)
- January 5–10, 2026 → functional in 5 days
- Traditional estimate: "21.63 months with 13.52 people"
Pre-LLM, this would be years of solo work. Now it's weeks.
Caveats (being honest):
- burn-models is mostly untested - "functional" is generous
- moss works, but value proposition for humans is unclear ("who needs a dedicated outline tool?")
- LOC ≠ quality, velocity ≠ correctness
- LLM-assisted code still needs human review, testing, iteration
The point isn't "this code is perfect" - it's "this code exists and can be iterated on."
Another superpower: parallel development
Traditional solo dev: one thread of execution. You work on one thing, then the next.
LLM-assisted: spin up multiple contexts. One session works on the parser, another on the renderer, another on tests. You switch between them, review, steer. Effectively multiplying your throughput.
It's not "10x developer" - it's "1 developer running 5 parallel workstreams." Different skill. More like project management than pure coding. But it works.
Counter-caveats:
- Human-written code has the same issues (untested, needs iteration)
- "You're one of those" / AI hype skepticism is valid, but so is pragmatism
- Environmental impact is real, but compare with the environmental impact of a human doing the same work over months/years
AI agents are real - The "agent" usecase now has concrete demand (Claude Code, etc.)
Decomposition - Not one monolith (lotus learned this). Independent pieces that compose.
Personal itch - Not trying to be a company. Solving own problems.
Why do this at all?
- Because I can. The barrier is low enough now.
- The alternative is N failed prototypes over years of free time.
- Frontier LLMs have absurd generalist + limited specialist knowledge.
- They're complementary to humans, not replacements - good at different things.
More Pragmatism
What do I really want out of this?
Value proposition by bucket:
| Bucket | Projects | Value for Humans | Value for AI Agents |
|---|---|---|---|
| Code understanding | moss, reed, liana | Don't read everything, query structure | Same, but with token limits |
| Format/data wrangling | cambium, reed | Don't hunt for converters | Reliable transformations |
| Creative/procedural | resin, dew, frond | Composable media generation | Could generate assets |
| Runtime/execution | moonlet, pith | Unified runtime, universal interfaces | Stable execution environment |
| Worlds/persistence | lotus, hypha | Persistent state, programmable | Context injection, not chat logs |
| UI/control | canopy | Universal client for anything | Could be controlled structurally |
| Preservation | siphon | Save dying software | Extract structure from legacy |
| Scaffolding | myenv, zone | Bootstrap projects fast | Consistent project structure |
What haven't we thought of?
Composition effects - What happens when moss + moonlet + canopy combine? Or liana + cambium + reed?
Template for LLM-era development - The ecosystem itself demonstrates "how to build ambitious things with AI assistance"
Education/teaching - Structured code intelligence could help people learn codebases
The meta-play - Building tools that help build tools. moss helps build moss.
Core value - what do I actually care about?
Honest answers (partial, can't think of everything at once):
I like making general frameworks - I'm terrible at making anything specific. The general-purpose thing is genuinely appealing, not just cope.
Lotus/MOO: SillyTavern sucks. I've wanted inventory management since the AI Dungeon days—literally years ago. On paper it's a trivial, basic feature. In practice, no one's built it properly because chat apps treat world state as an afterthought.
Notes: I don't use note-taking apps. Why? Laziness + unclear value.
- It's effort to reach over to a note-taking app
- What do they offer? Structure? What's the right structure?
- I have a 'notes' DM in Discord (others have notes servers). Mostly ephemeral stuff.
- The real problem: If I have a video/website/TV series on the tip of my tongue, how do I find it? I can't. The memory exists but there's no retrieval path.
FS: I don't use a file browser. What's the value over terminal? Is there even one?
- Folders suck for organization
- How do you find things in
homework/math1001/month/day/whatever? - Hierarchies are arbitrary and break down
NNs are flawed approximators: They're excellent at approximation but WHY are we encoding world knowledge as opaque weights that cost time to train?
- In what world will "skibidi rizz" be useful for reasoning?
- World knowledge should be structured and queryable, not baked into weights
- This is the "Structure for Agents" thesis: don't make agents interpret, give them structure
Synthesis:
- The common thread is retrieval and structure
- Notes problem = can't retrieve fuzzy memories
- FS problem = can't navigate arbitrary hierarchies
- MOO problem = can't inject world state into chat
- NN skepticism = world knowledge shouldn't be opaque
Maybe the core value is: make things findable and structured so you don't have to hold everything in your head
Tags, not hierarchies:
- Manual tagging is fine. LLM/embedding-assisted doesn't hurt either.
- The key insight: tags should be first-class, not an afterthought
- Even Obsidian/Dendron have hierarchies baked in. Filesystems are innately hierarchical.
- That's fundamentally the wrong mental model for how things relate
- Hierarchies force single-parent relationships. Tags allow many-to-many.
Thinking style:
- Contrarian not to be different, but because "what if?" is interesting
- NIH not because "I can do better", but to avoid "let's just use this because everyone does"
- Also: NIH to understand things deeply (you learn by building)
- This explains the ecosystem scope: not hubris, but exploration
Interaction paradigms have stagnated:
- WIMP (Windows, Icons, Menus, Pointer) - Xerox PARC 1970s, Mac 1984
- 50+ years of the same paradigm. Is it flawless?
- Problems: discoverability (menu hunting), mouse dependency (RSI, accessibility), window management (still unsolved), file dialogs (universally hated), deep hierarchies, modality confusion
- Touch/voice/VR emerged but WIMP still dominates desktop
- We're still doing "rectangles on screen, click on things"
It's not the UI, it's the interaction graph:
- Lotus was frontend-agnostic: web, Discord, TUI, CLI
- Same model, different projections
- The question isn't "what pixels" but "what's the shape of the affordances"
- When can you act?
- Where are actions available?
- What actions exist?
- How do you discover them?
- How do they compose?
Different frontends, same interaction graph:
| Frontend | Projection of affordances |
|---|---|
| Web | Buttons, forms, clicks |
| Discord | Threads, reactions, slash commands |
| TUI | Keys, modes, status lines |
| CLI | Commands, flags, pipes |
| MOO/text | Verbs, objects, natural language |
The "paradigm" is the graph, not the rendering. WIMP is one graph shape (hierarchical menus, modal dialogs). MOO is another (objects with verbs, contextual commands).
Implication: Canopy isn't "the UI" - it's a projection. The interaction graph lives in the backend (MOO verbs, entity affordances). Frontends just render it.
Reality check: what do common tasks look like today?
Trying to avoid bias - some things are easy:
| Task | Experience |
|---|---|
| Open browser | Fine |
| Watch video | Fine |
| Send message | Fine (if app already set up) |
But then...
| Task | Experience |
|---|---|
| Install software (Windows) | Store? .exe? .msi? Admin prompt? Where'd it go? |
| Find file you saved "somewhere" | Good luck |
| Change default app | Settings → Apps → Default apps → scroll → hope |
| Connect printer | Prayer-based computing |
| Uninstall cleanly | Registry ghosts forever |
| Transfer files between devices | AirDrop (Apple) / ??? (everyone else) |
| Set up new device | Hours of "just one more thing" |
| Manage notifications | Per-app, per-site, per-OS, good luck |
| Back up data | Do you? Really? |
50 years of WIMP and "install software" is still a mess. The interaction graph is implicit, inconsistent, varies by app, varies by OS. No wonder people just use web apps for everything.
Counterpoints:
- Web apps' advantage: barrier to entry. No install, just visit URL. That's real value.
- Nix + comma (nix-shell wrapper) can partly ease installation on Linux
comma ripgrepjust works, no "install" step- Declarative, reproducible, no system pollution
- But: learning curve, not mainstream
The web won partly because "installing things" is broken. Fix installation and the equation changes.
The "app for everything" problem:
- So many windows, so many apps
- Want to upscale an image? Install Upscayl.
- Want to convert a video? Install Handbrake.
- Want to edit a PDF? Install... something?
- Each task = find app, install app, learn app, context switch
Compare with Unix pipes: cat file | transform | output
- Operations compose
- No separate "app" per operation
- But: CLI learning curve, not discoverable
The dream: operations as composable verbs, not siloed apps. (This is partly what cambium is about - pipelines, not apps.)
But: web apps still use WIMP-esque paradigms. The web solved deployment, not interaction design.
- Same buttons, forms, menus - just in a browser
- Still implicit interaction graph
- Still varies by app
- Still not queryable or composable
Nothing stops us from making web apps with better interaction models. The transport is orthogonal to the paradigm.
Case studies in "learning curve":
| App | Power | Problem |
|---|---|---|
| vim | Extremely powerful | "Learning curve" (but: once learned, very fast) |
| blender | Industry-grade 3D | "Learning curve" (modal, dense UI) |
| krita/gimp/photoshop | Professional tools | "Learning curve" (toolbox overload) |
| SillyTavern | Feature-rich | Architectural mess: no SQL (everything is files), each card is a PNG, each chat is JSONL, search takes 15s to load taglist on 5GB/s NVMe |
The pattern: power requires learning, but also: maybe the interaction model itself creates unnecessary friction?
Maybe it's unsolvable. But:
- That won't stop us from trying
- At minimum we can diagnose - if it's unsolvable, understand why
- Negative results are still results
- "This is hard because X" is valuable knowledge
Command palettes: a partial solution that exists:
- Wonderful invention, frustratingly slow adoption
- Makes the interaction graph queryable (fuzzy search what you want)
- VSCode: can bind to commands arbitrarily - commands are first-class!
- Not perfect, but way better than menu hunting
Why this matters:
- Commands exist as data, not just UI elements
- You can search them (discoverability)
- You can bind them (programmability)
- You can script them (composability)
This is the interaction graph becoming explicit. WIMP hides commands in menus. Command palettes surface them.
What's missing from command palettes (typically)?
- Still app-specific (each app has its own palette)
- No cross-app composition
- No persistent state (can't "save this sequence of commands")
- No context-awareness (same commands everywhere, not object-dependent)
Note: context-awareness isn't fundamental to lack - a palette could be context-filtered and priority-ranked. VSCode does this. The extra implementation effort is marginal; the real cost is deciding what "relevant" means for your domain.
MOO verbs as "command palettes taken further"?
| Feature | Command Palette | MOO Verbs |
|---|---|---|
| Queryable | Yes (fuzzy search) | Yes (examine object) |
| Bindable | Yes (keybindings) | Possible |
| Scriptable | Limited | Yes (verbs are code) |
| Context-aware | Rarely (usually global) | Yes (verbs on objects) |
| Cross-app | No | Yes (same MOO everywhere) |
| Persistent | Yes (verbs saved in DB) |
But: MOO isn't the only way. Tradeoffs:
- MOO requires buying into the object model (everything is an entity)
- Learning curve to write verbs
- Single-server traditionally (distribution is hard)
- Traditional MOO is text-centric (GUIs bolted on)
- "Everything is an object" can be forced/awkward for some domains
Note: Lotus wasn't text-centric! It was structure/object-centric precisely because:
- Multi-frontend from the start (web, discord, tui, cli)
- Different frontends want to expose detail gradually
- Web especially needs structured data to render progressively
- Text is one projection; structure is the source of truth
Tangent (but related): Reed has no text representation. Why?
- Invalid syntax is a failure mode that doesn't need to exist
- If you work with structure directly, there's no "parse error"
- Text-based languages: string → parse → AST → compile
- Structure-first: AST is the artifact, text is optional projection
- (Everything is a tradeoff - text is human-writable, debuggable, diffable)
Other approaches to explicit interaction graphs:
- Datalog/query-based - affordances as facts, query what's possible
- Capability-based - tokens define what you can do
- Intent-based - declare what you want, system figures out how
- Reactive/stream-based - subscribe to affordance changes
Don't marry MOO. It's one approach to making interaction explicit.
Vibe-coding style:
- "Holding reins loosely" - but not zero technical knowledge (contrast with "pure vibe coders")
- Background: years of golfing, language design/impl (not compilers), frontend, Rust for AoC
- Knows what I'm looking at, understands perf characteristics at a basic level
- Don't read every line of 90k LOC - a lot is busywork
- Have some domain knowledge; LLMs have all the domain knowledge at a basic level
- The combination: I can evaluate/steer, LLM handles volume
- Prefer discussing SRP, generality, decomposition into fundamental concepts
- Hyper-modularity as a design goal
Revisiting Notes/FS in MOO:
- This insight (notes/fs as views into tag-based entity store) was already explored in lotus design phases
- That's why "notes-in-MOO" and "fs-in-MOO" felt appealing
- Standalone notes/fs = just another app, low ecosystem value
- Notes/FS-in-MOO = demonstrates the paradigm, higher value
- The standalone versions were always lower priority - they don't prove anything new
If the AI bubble bursts and LLMs disappear, what are we left with?
| Project | LLM-dependent? | Residual value |
|---|---|---|
| moss | No | Tree-sitter based code intelligence still works |
| pith | No | Universal interfaces, useful regardless |
| reed | No | Transpiler, works without LLMs |
| moonlet | Partially | Lua runtime works; LLM plugin less useful |
| lotus/MOO | No | Programmable objects, still works |
| liana | No | API codegen, useful regardless |
| cambium | No | Format conversion, still works |
| iris | Yes | Session analysis needs LLMs |
Most of the ecosystem is LLM-assisted in construction, not LLM-dependent in operation. The code exists and works. LLMs were the means, not the purpose.
Exception: iris (and similar "AI-native" tools) would lose core functionality.
Prioritization Analysis
Which project first? Think in terms of ROI and dependencies.
Dependency Graph
┌────────────────────────────────────────┐
│ canopy (UI) │
└───────────┬─────────────┬──────────────┘
│ │
┌──────────────┴──────┐ │
▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐
│ moonlet │◄───────────│ MOO │ │ other │
└───┬───┘ └───┬───┘ └───────┘
│ │
▼ ▼
┌───────┐ ┌───────┐
│ pith │ │ libsql│
└───────┘ └───────┘- canopy needs something to connect to
- MOO needs moonlet (Lua runtime) + libsql (storage)
- moonlet needs pith primitives
- pith is foundational
Project ROI Estimates
| Project | Effort | Immediate Value | Enables Other Work |
|---|---|---|---|
| pith-fs | Low | File watching, indexing | FS service, canopy |
| pith-sql | Low | SQLite bindings | Notes, MOO |
| MOO core | High | Programmable objects | Notes-on-MOO, FS-on-MOO |
| Notes standalone | Medium | Usable notes app | Nothing else |
| FS standalone | Medium | Usable file browser | Nothing else |
Observation: pith-* primitives have high ROI - low effort, enable everything else.
Minimal Viable Compositions
What's the smallest useful combination?
Option A: pith + canopy
canopy ←→ pith-fs- A file browser. Useful but not novel.
Option B: moonlet + pith + canopy
canopy ←→ moonlet ←→ pith-{fs,sql}
↑
Lua apps- Scriptable file browser / notes. Getting interesting.
Option C: MOO + canopy
canopy ←→ MOO ←→ libsql
↑
TS verbs (via reed)- Programmable objects with UI. The full vision (but more work).
What Would You Use Daily?
Honest question: which of these would actually get used?
| Tool | Would use daily? | Why / why not? |
|---|---|---|
| File browser (canopy + pith-fs) | Maybe | Already have good file browsers |
| Notes (standalone) | Maybe | Already have Obsidian |
| MOO (programmable objects) | ? | Depends on what apps exist |
| MOO + AI context injection | Yes | Original itch - Tavern cards |
The MOO + AI context is the unique value. Everything else has strong competitors.
Implication: Maybe start with MOO core, not the "safe" primitives?
Minimal MOO
If MOO is the unique value, what's the smallest MOO that demonstrates it?
Core Entities
-- Everything is an entity
entity = {
id = 123,
parent = 1, -- inheritance
props = { ... }, -- key-value
verbs = { ... }, -- callable code
}Minimal Verbs
-- Movement
entity:move(target)
-- Speech
entity:say(message)
-- Inspection
entity:look()
entity:examine(target)
-- Modification
entity:set(key, value)
entity:get(key)Minimal World
┌─────────────────┐
│ Root (#0) │
└────────┬────────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌─────────┐
│ Player │ │ Room │ │ Thing │
│ (#1) │ │ (#2) │ │ (#3) │
└─────────┘ └──────────┘ └─────────┘Minimal AI Context
What does "AI context injection" actually look like?
-- Given a player entity, produce LLM context
function make_context(player)
local room = player:location()
local contents = room:contents()
return {
location = room:describe(),
present = map(contents, function(e) return e:describe() end),
inventory = map(player:contents(), function(e) return e:describe() end),
recent_events = get_recent_events(player),
}
endOutput (structured, for injection):
WORLD STATE:
You are in: Kitchen - A warm room with copper pots hanging from hooks.
Present: Alice (sitting, holding coffee), Table (oak, four chairs), Window (open, morning light)
Your inventory: phone, keys
Recent: [5m ago] Alice entered from the garden.
---
CONVERSATION:
...This is the core insight: structured world state becomes LLM context.
Next Steps
Immediate (pick one)
MOO prototype: Minimal entity system in Lua/moonlet
- Storage: libsql
- No verbs yet, just entities + props
- Test: Can canopy display entity tree?
pith-fs: File watching primitive
- Rust, exposes via moonlet plugin
- Test: Can Lua script react to file changes?
Context injection POC: Skip MOO, test the core hypothesis
- Hardcode some "world state" JSON
- Inject into LLM context manually
- Test: Does this actually improve Tavern-style interactions?
Questions to Answer
- Is context injection the actual value? (Test with POC before building MOO)
- Do I want to build MOO again, or was lotus enough exploration?
- What's the minimal thing that would actually get used?
The State of Software (2026)
Why Good Things Don't Exist
Most missing tools are bridge problems - they require crossing between specializations, and specialists rarely cross.
Example: Trellis (composable derive macros) needs:
- Proc macro expertise (notoriously hard, most Rust devs avoid it)
- Deep understanding of HTTP, WebSocket, gRPC, CLI, MCP conventions
- API design taste (what's the right abstraction level?)
- The vision that this should exist
Interactive learning needs: domain expertise + pedagogy + interaction design + implementation. Four disciplines, one person (or a team that actually communicates).
The Venn diagram of "can build it" and "will build it" and "has time to build it" is nearly empty.
Plus incentives:
- Open source maintainers burn out
- Companies optimize for features, not polish
- Academia rewards novelty, not accessibility
- "Quality of life" improvements don't get funded
LLMs Change the Equation
LLMs collapse the skill barrier - you don't need to be a proc macro expert if you can collaborate with one. The "bridge" becomes walkable.
But motivation is still the bottleneck:
- Who sees that it should exist?
- Who cares enough to start?
- Who follows through past the prototype?
LLMs help with execution, not vision. The person still needs to notice the gap, believe it's worth filling, and sustain effort through the unglamorous parts.
The new scarcity isn't skill, it's taste + drive. Knowing what's worth building, and actually shipping it.
The Graveyard of Incomplete Implementations
OOXML is a perfect example. Many libraries exist. How many are complete? How many authors are competent? How many gain traction?
Failure modes stack:
- Started but abandoned - hit the hard parts, gave up
- Complete but wrong - implemented the spec, not the behavior (Word doesn't follow its own spec)
- Correct but obscure - good work nobody finds
- Found but untrusted - no proven track record, so nobody adopts, so no track record
The gap isn't "nobody tried." It's that trying isn't enough. You need skill + domain knowledge + completion + distribution. Each step filters out 90% of attempts.
Incumbents Aren't Competent
The uncomfortable truth: incumbents often won by showing up first, not by being good.
So the bar is actually low - but it looks high because:
- Incumbents seem authoritative (they're everywhere)
- Newcomers assume they need to be better to compete
- In reality, "finished and marketed" beats "better but obscure"
The real filter is:
- Showing up
- Finishing
- Telling people
Most projects fail at step 2 or 3, not step 1. The competition isn't as scary as it looks - they're just further along the "actually shipped it" axis.
How Good Is Software Actually?
The median software experience:
- Buggy (even flagship products)
- Bloated (Electron chat apps at 500MB)
- Half-finished (features that almost work)
- User-hostile (dark patterns, subscriptions, telemetry)
- Fragile (breaks on updates, dependency nightmares)
The stuff that's actually good:
- Core infrastructure (SQLite, PostgreSQL, Linux kernel)
- Focused tools by obsessives (ffmpeg, imagemagick, pandoc)
- Things with decades of polish
The uncomfortable truth: Most software we use daily is mediocre. We've just normalized it. "Good enough" captures the market and then coasts. Nobody rewrites Jira because Jira exists.
2026 and we still can't copy-paste reliably between apps.
So when building "silly projects" - the bar you're competing against is often shockingly low. The incumbent is a mass of tech debt held together by inertia and network effects.
Why It's Like This
Software advances in the directions that get funded. Capability ceiling? Way up. Performance? Massive gains. User respect, simplicity, longevity? Not a KPI.
Subscriptions, lock-in, engagement metrics, growth at all costs - these got optimized. "Does it respect the user?" didn't have a metric attached.
We use 1000x the hardware for 10x the experience. That's not incompetence - it's rational given the incentives.
The Dripfeed of Good Software
Good software does exist. It emerges from sheer talent + motivation - people who care enough to do it right, regardless of incentives.
But it's a dripfeed. The intersection of "has the skill," "has the motivation," and "picked this problem" is tiny. Most domains simply don't have the volume of talent + motivation to get any attention.
SQLite exists because D. Richard Hipp cared. ffmpeg exists because obsessives cared. Most problems don't get their Hipp or their obsessive. They get abandoned side projects and half-baked enterprise solutions.
The existence of good software is almost accidental - the right person happened to care about the right problem at the right time. Scale that up and you get... exactly what we have. Pockets of excellence in a sea of mediocrity.
Evaluating the LLM-Assisted Approach
Common critiques and honest responses:
"Using up compute/water"
Real concern, but needs context. Compared to what? A flight? Streaming video? The moral calculus is murky. If the output is useful, arguably justified. If it's wheel-spinning, less so.
Mitigation: Be intentional about what you use it for.
"Unclear benefit / too low-level"
Infrastructure doesn't show immediate value. SQLite wasn't obviously useful at first either.
The counterargument: are you building toward something, or just building? If there's a path to something you'd actually use, it's fine. Infrastructure for its own sake... maybe reconsider.
"Unclear reliability of LLM code"
Valid concern. But the comparison isn't "LLM code vs careful human code." It's "LLM code with tests vs human code shipped without tests because deadline."
LLMs write tests. Humans typically don't (over-generalization but true enough). LLM + tests might actually be MORE reliable than typical human code.
"LLMs hallucinate"
True for facts. Less relevant for code - you can run it and see. If it compiles and tests pass, the hallucination concern is moot. The real risk is subtle bugs, not fabrication.
"Next token predictors therefore useless"
Category error. Brains are "just neurons." The mechanism doesn't determine utility.
But staying grounded is fair - LLMs have real limits. Better at "how to do X" than "what X should I do." Which is why taste + drive is the bottleneck, not execution.
The Trust Problem
"How do I go to someone and say 'I vibe coded a quarter million lines of Rust' without sounding like a lunatic?"
You can't. The trust gap is massive.
Options:
- Don't chase adoption - Build for yourself, publish for portfolio, don't expect users
- Earn trust slowly - Small useful thing → people use it → credibility → larger things
- Attach to existing credibility - Contribute to established projects, build reputation there
- Radical transparency - Code is public, tests are public, judge for yourself
Preferred approach: Build for yourself, publish for portfolio, don't chase adoption.
This sidesteps:
- Marketing anxiety
- Maintenance burden for strangers
- The trust problem entirely
- Pressure to make it "general" instead of "good for you"
If it becomes genuinely useful to you, that's success. If someone else discovers it, bonus. If not, you still have a working tool.
Planning vs Building
"Planning forever" might sound like a failure mode, but it's better than spending years building the wrong thing, then more years building wrong thing #2.
The question is: is the planning converging or circling? Planning that narrows options, tests assumptions on paper, kills bad ideas early - that's cheap iteration. That's the point.
What Do I Actually Use?
Honest inventory:
- Firefox
- Discord (in Firefox)
- YouTube (in Firefox)
- VSCode
- Ghostty (terminal)
- Steam (occasionally)
That's it. Browser, terminal, editor, games.
This is intentional minimalism - preference for few tools, not missing something.
Where Does Lotus Fit?
If daily life is Firefox tabs and a terminal, what's the value proposition of a "unified object graph"?
Possible interpretations:
- Gap (for me) - Would use task management/etc if something good existed, but nothing does, so just... don't
- Building for imaginary need - Don't actually need this, just think it's neat
- Browser IS the object graph - Tabs are objects, bookmarks are storage, and that's actually fine
Why Not a Notes App?
"What's a notes app for? Writing down stuff I won't read?"
The dirty secret: most people write notes, never read them. The value (if any) is in the writing itself - clarifying thought in the moment. The artifact is a byproduct.
What IS worth storing?
- Things you'll actually retrieve - Rare. Passwords, reference docs, that one command you forget.
- Things that act on their own - Timers, reminders, scheduled events. They come to YOU.
- Things that integrate - Not "I wrote down X" but "X connects to Y connects to Z"
Objects, Not Documents
Hot take: Notes apps are paper skeuomorphism on the most interactive medium ever created.
Paper affordances:
- Static
- Linear
- You write, it sits there
- You have to remember it exists
- Organization is manual
What computers can do:
- Execute
- Respond
- Connect
- Trigger
- Compute views on the fly
- Come to you instead of waiting
Notes apps: "What if paper, but on a $2000 machine?"
We have the most interactive medium ever created and use it to simulate sheets of paper with text. Then we add "features" like backlinks and tags, which are just compensating for the base metaphor being wrong.
The right question isn't "how do I organize my notes?" It's "why am I taking notes at all when I have a computer?"
Lotus Was Never a Notes App
Looking back - Lotus was always about objects:
- Stopwatches (act, have state)
- Timers with laps (act, have history)
- Calendar events (trigger at times)
- Saved webpages (retrieval)
- Tagged images (searchable)
None of those are "write stuff down to maybe read later." They're things that exist and do things.
The "notes" framing was polluting the vision with expectations from a category that doesn't even fit.
Lotus thesis, clarified:
- Objects > Documents
- Things that live > things that sit
- Active > passive
- Comes to you > you go to it
Not a second brain. A living system.
Paper Dominance Was Lack of Choice
"Paper has been dominant for millennia" - but how much of that was lack of alternatives?
What did analogue interactivity look like when people could reach for it?
- Rolodexes (indexed, random access)
- Card catalogs (searchable)
- Filing cabinets (categorized retrieval)
- Commonplace books (indexed marginalia, cross-references)
- Slide rules (interactive computation)
- Physical dashboards, dials, gauges
People reached for interactivity whenever they could. Paper was the fallback, not the preference. The "linear notes" paradigm might just be the lowest common denominator that survived digitization - not the optimal form, just the familiar one.
Dopamine Arbitrage / Attention Economy Escape
Hypothesis: maybe the "notes don't work for me" thing isn't ADHD or neurodivergence. Maybe it's just... having found an environment where your brain works well.
The attention economy is designed to exploit dopamine - infinite scroll, notifications, engagement metrics. Most people are stuck in that environment.
Programming is an escape hatch. Hyperfocus is a feature, not a bug. The reward loops align with deep work instead of fighting it.
"Falling out of the attention economy into Visual Studio."
Maybe the question isn't "is my brain different" but "did I accidentally optimize my environment while others are stuck in environments designed to exploit them?"
The "I don't use notes apps" thing might not be a quirk. It might be: "I escaped the productivity theater that compensates for attention-hostile environments, because my environment isn't attention-hostile."
If your work IS the dopamine reward, you don't need elaborate capture systems to remember to do it.
WIMP Is Paper All The Way Down
Traditional GUI: Windows, Icons, Menus, Pointer.
What it actually is:
- Windows: pieces of paper
- Scrolling: long pieces of paper
- Menus: hidden pieces of paper
- Tabs: stacked pieces of paper
- Files: pieces of paper in folders
- Folders: boxes of paper
- Desktop: a desk with paper on it
- Clipboard: a clipboard (literally)
The entire GUI paradigm is "what if paper, but screen." We built the most powerful interactive medium in history and made it cosplay as an office supply store.
Half-Assed Skeuomorphism
Paper skeuomorphism is the uncanny valley of interfaces. You simulate flat surfaces with marks, but nothing else about reality.
The alternatives aren't just:
- Less skeuomorphism (terminal, code, abstraction)
- Paper skeuomorphism (WIMP, documents, rectangles)
There's a third option: 3. Full skeuomorphism - Simulate reality, not just paper
VRChat: You're somewhere. Objects have presence. Interaction is embodied. Skeuomorphic to reality itself.
MOO: Textual but spatial. Rooms, objects, verbs. You're IN a place. Things have behavior, not just content.
Paper skeuomorphism has neither the power of pure abstraction NOR the intuition of embodied space.
The 2D Desk That Could Have Been
I want a 2D/3D desk I can drag drawers out of to see my files. This isn't a novel idea.
Why doesn't it exist?
The "performance" excuse is bullshit. A 2D desk with drawers is just sprites. We solved that in the NES era.
The real reasons:
- Incumbency - File/folder won, everyone copied, done
- Risk aversion - OS vendors don't experiment with core UX
- "Professional" gatekeeping - Spatial looks like a game, rectangles look like work
- Toolkit laziness - File pickers are built-in, spatial desks aren't
- Never tried properly - Attempts were novelties, not serious replacements
The paradigm calcified not because spatial was worse, but because it wasn't "professional" enough. Some executive in 1985 wouldn't buy software that looked like his kid's Nintendo.
The spreadsheet won not because it's optimal but because it looks like work.
macOS: The Middle Ground
Apple was always more willing to be playful:
- Smiling Mac on boot
- Aqua (jelly buttons, transparency)
- Dock with bouncing, magnification
- Exposé / Mission Control
- Stacks (the yugioh deck thing - icons fan out from a folder)
- Full skeuomorphism era (leather, wood, felt)
Then iOS 7 flattened everything. The skeuomorphism backlash.
But not everything died:
- Dock magnification survived
- Genie effect (window slurps into dock)
- Rubber-band scrolling
- Inertial scrolling
- Window shadows
The line they found:
- Decorative skeuomorphism (leather texture, wood grain) → killed
- Behavioral skeuomorphism (momentum, magnification, elasticity) → kept
The stuff that does something survived. The stuff that just looked like something died.
Stacks is literally a tiny spatial interface - items have positions, animate into place, you pick from a physical spread. The proof of concept exists. Someone just never scaled it up to the whole filesystem.
This Isn't New
Spatial file management is the ORIGINAL concept. We had it and threw it away.
Spatial Finder (original Mac):
- Each folder = its own window
- Windows remembered position and size
- Opening a folder always opened the SAME window in the SAME place
- Spatial consistency - "the folder is over there"
Changed to browser model (one window, navigate in place) because "too many windows" and "confusing" and "power users wanted keyboard navigation."
Xerox Star (1981):
- Icons stayed where you put them
- Spatial arrangement was meaningful
- Desktop as literal space
HyperCard (1987):
- Cards in stacks
- Spatial navigation
- "Place" based, not "file" based
The spatial interface isn't a future concept. It's a past concept that got beaten out by "efficiency" and "power users."
We had it. We threw it away. Now it's retro.
Radial Menus Are Optimal
Hot take: a radial menu (optionally concentric) is optimal for both mouse distance and muscle memory.
Fitts's Law
Time to target = f(distance, target size)
Radial:
- All options equidistant from cursor
- Pie slices have "infinite" depth (extend to screen edge)
- Distance is minimized and uniform
Linear dropdown:
- Top items closer, bottom items farther
- All items same small height
- Distance varies, targets are constrained
Radial wins on both dimensions.
Muscle Memory
- Direction is more memorable than position
- "Up-right" vs "third item down"
- 8 directions is a natural set (cardinal + diagonal)
- Directions are categorical, positions are ordinal
Where It Works
- Blender pie menus (beloved)
- Clip Studio Paint / Krita
- Maya marking menus
- Game weapon wheels
- Mass Effect dialogue wheel
Why Didn't It Win?
Not because it's worse. Because of the toolkit.
Win32 gives you:
- Menu bars (built-in)
- Dropdown menus (built-in)
- Context menus (built-in)
- File dialogs (built-in)
Win32 doesn't give you:
- Radial menus (build it yourself)
If the toolkit has CreateMenu() but not CreateRadialMenu(), 99% of developers use CreateMenu(). Not because it's better - because it's there.
The entire Windows application ecosystem is shaped by what happened to be implemented in 1990.
Incumbency isn't just "people copied each other." It's "the platform only gave us one option and nobody questioned it."
The toolkit IS the paradigm.
"But Radial Doesn't Scale Past 8 Items"
Hot take: if you have >8 most-appropriate items, interaction design is the least of your worries.
The 8-item limit isn't a bug, it's a forcing function:
- Curate by context (what's actually relevant HERE?)
- Nest if needed (radial → sub-radial)
- Reconsider the feature set (do you need 50 actions?)
Linear menus "scale" to 50 items by making all 50 equally hard to find. That's not scaling, that's hiding the problem.
Radial's limit is honest. "You get 8. Choose wisely."
Linear menus let you pretend you're not making choices while actually making everything worse.
Node Editors Suck
Resin is a graph-based constructive anything toolkit. The problem: node editors are the standard interaction model for graphs, and they suck.
The Problems
| Pain point | Description |
|---|---|
| Spaghetti | Wire crossings become unreadable at scale |
| Manual positioning | Placing nodes is busywork |
| Navigation | Constantly zooming/panning, lost in the graph |
| Drawing connections | Tedious wire-drawing |
| Understanding flow | Can't follow which wire goes where |
| Undo terror | Did I break something? |
Every node editor has these problems. Blender, Houdini, Unreal Blueprints, Substance Designer, ComfyUI. Some mitigate with frames, colors, auto-layout. None solve it.
The Alternatives All Suck Too
| Approach | Problem |
|---|---|
| Text/code | Syntax errors, 1D representation of N-D structure |
| Node editors | Manual wiring tedium, spaghetti |
| Structural editors (Hazel, Darklang) | Valid but unproven at scale |
| CyberChef | Works but limited to linear pipelines |
Code IS a Graph
Wait. Variable references ARE edges.
a = noise(x, y)
b = threshold(a, 0.5) // reference to 'a' = edge from a to bSame with:
import foo→ edge from foo to this modulefoo.bar()→ edge to foo- Function calls → edges
Code has always been a graph. IDEs know this (go to definition, find references). We just serialize it linearly and let the parser reconstruct edges.
| Text | Nodes | |
|---|---|---|
| Underlying structure | Graph | Graph |
| Serialization | Linear (implicit edges) | 2D spatial (explicit edges) |
| Edge representation | Names/references | Wires |
The dichotomy is false. Both are views of the same thing.
Apply the Interaction Graph
Earlier insight: show the RIGHT actions, not ALL actions. Context-aware filtering.
Apply it to nodes:
- What nodes are relevant right now?
- What connections make sense from this port?
- What's the next likely operation?
Radial menu for node creation. Context-filtered. Frecency-ordered. Auto-suggest connections based on what's dangling.
The spaghetti isn't the problem. "Show everything always" is the problem.
Abstraction
Node editors are often flat. 200 nodes on one canvas.
Where's the equivalent of "extract function"? Some have it (Houdini HDAs, Blender node groups) but it's clunky, afterthought.
In text: extract_function() is reflexive. In nodes: select 40 nodes, hope I/O is inferred correctly, manually fix interface...
Real insight: If it's a function, it's already a subgraph. Call site = node. Definition = expanded graph. You don't need separate "create subgraph" ceremony. That's just compensating for not having real functions.
Projectional vs Structural
| Structural | Projectional |
|---|---|
| One true representation | Abstract structure, multiple views |
| You edit the structure | You edit through a projection |
| What you see IS the data | What you see is ONE VIEW of the data |
The problem with node editors isn't nodes. It's that they're the ONLY view.
If the underlying structure is a graph, why not:
- Text view for editing
- Node view for overview
- Pipeline view for linear parts
- Table view for data
One structure. Many projections. Pick the view for the task.
Don't Throw Away What Works
CyberChef is proven for pipelines. Why force pipeline-shaped subgraphs into node representation?
A graph isn't uniformly complex. Some parts are linear pipelines. Show those as CyberChef-style chains.
The projection should match the shape of that part of the graph:
- Pipeline-shaped → CyberChef/chain view
- Branchy/complex → Node view (context-filtered)
- Dense/algorithmic → Text view
- Tabular → Table view
All editing the same underlying structure.
But Broader Than "Match the Shape"
Matching local shape is still structural thinking.
Projection could match:
- Task: Debugging? Editing? Exploring?
- User: Expert wants density, novice wants guidance
- Intent: What am I trying to DO?
- Arbitrary: Whatever makes sense right now
Or projections that aren't graph-shaped at all: forms, wizards, natural language, 3D viewport.
The graph is the truth. The projection is whatever helps right now.
User-Defined Projections
The projection is whatever the user chooses it to be. The user can define their own.
Not "system picks based on heuristics." Not "choose from 5 presets."
The user defines projections. Custom sugar. Custom views.
The system provides:
- The underlying graph/objects
- Primitives for building projections
- Good defaults
The user/community provides:
- Domain-specific projections
- Personal preferences
- Novel views nobody anticipated
This is the Emacs model: Emacs doesn't decide how you edit - you define modes. Same here: you define projections.
Canopy Clarified
This is what Canopy was meant to be.
Canopy: User-definable views onto anything.
Not just "projections onto Lotus." Projections onto:
- Lotus object graph
- Filesystem
- APIs
- Databases
- Other apps
- Anything with a data source
Lotus is one source (the object graph with state, behavior, connections). Canopy is the projection layer that can sit on top of any source.
But: graph-first / interaction-graph-first as the foundational model makes sense. Everything can be modeled as objects with connections. Start there, extend to other sources.
Not "a notes app" or "a node editor" or "a file manager."
A platform for building projections onto anything.
- Want CyberChef-style pipelines? Build that projection.
- Want a 2D desk with drawers? Build that projection.
- Want spatial Finder? Build that projection.
- Want node editor for complex parts? Build that projection.
- Want to view your filesystem as a graph? Build that projection.
- Don't like any of them? Build your own.
The system doesn't prescribe how you see your data. It gives you:
- Data sources (Lotus, filesystem, APIs, whatever)
- Projection primitives (Canopy)
- Good defaults to start
- The ability to define your own
This is the escape from WIMP.
Not by picking a different paradigm. By making the paradigm user-defined.
Why Build This
Some people worry about idea theft. "Someone might steal my ideas."
Different mindset: "Why doesn't this exist yet? I just want to use it."
If someone else had built user-defined bidirectional pattern-matching projections that actually work, great. I'd use it. I don't care about credit. I care about having the tool.
But nobody has. The HN test: if this existed and worked well, it would have surfaced. The absence of an obvious "that project" suggests the space is still open.
Ideas aren't rare. The intuitions here are 5, 7, maybe more years old. Surely others have had them too. Thousands of people, probably.
Where did they all go?
- Gave up (too hard)
- Got practical (needed a job)
- Built it, nobody noticed
- Wrote papers nobody read
- Burned out
- Life happened
- Still going, somewhere, quietly
The ideas aren't the bottleneck. Completion is rare. Good completion is rarer.
The sadness isn't "someone might steal it." The sadness is: nobody has built it, so if you want it, you might have to do it yourself.
Years of work. Might never matter to anyone else.
But also: the dream is still available. Nobody's claimed it yet.
The Omnicompetent-ish
The Bridge Problem Revisited
Building something like Canopy requires:
- PL theory (projection/macro system)
- Systems programming (performance)
- Interaction design (UX)
- Visual design (aesthetics)
- Domain knowledge (per projection)
- Product sense (what to build)
- Distribution (so anyone finds it)
One person can't be expert in all of those. The dream always died in this gap.
LLMs Change the Equation
An LLM is trained on the sum total of documented human knowledge. MoE architectures are tens/hundreds of specialized sub-networks working together. That's structurally something humans can't be - a generalist made of specialists, all available simultaneously.
Not omnitalent. Omnicompetent-ish. Good enough at everything to unstick you, translate between domains, fill gaps while you provide taste and direction.
The ceiling moved. The dream was blocked by "requires a type of mind that doesn't exist." Now a weird approximation of that mind exists.
But Could a Human Do It?
Technically possible. For someone:
- Right genetic lottery
- Right upbringing and education
- Financial stability
- No major life disruptions
- Chose this problem specifically
- Sustained drive over years
- Didn't burn out or get comfortable
Each filter removes 90%+. Stack them: one-in-billions.
On "free time": Tons of people theoretically have the time. 100k+ messages on Discord. 10k+ hours on WoW. The time exists. Not judging - just noting that "lack of time" is often misattributed. The resource exists. The allocation doesn't.
The bottleneck isn't time. It's motivation and direction. Knowing what to build, caring enough to build it, sustaining that over years.
That person who could do it probably exists but got hit by a filter: became a specialist, chose different priorities, gave up, or never started. All valid choices. The dream just doesn't get built.
LLMs sidestep the skill-accumulation lottery. You don't need decades of cross-domain learning. But you still need the motivation. That part doesn't change.
What Skill Is Still Required?
Honest question: can anyone with an LLM do this? What's the actual floor?
What the LLM compresses:
- Ecosystem research (100 hours → one question)
- Syntax and idioms
- Boilerplate and ceremony
- "What's the best crate for X"
What you still need:
- Programming literacy (can read/write/evaluate code)
- Architectural sense (how should things fit together)
- Taste (is this good?)
- Vision (what should exist?)
- Evaluation (is this what I wanted?)
The LLM is a multiplier, not a replacement. Competent generalist + LLM = can play specialist. Non-programmer + LLM = probably still stuck.
Where Does the Architecture Brain Come From?
Not corporate experience. Not deep language expertise.
Often: a "dinky" personal project where you figured out how things should fit together. A Lua codebase. A side project. Something small where you could experiment without stakes.
That's where taste develops. The LLM doesn't give you architecture - it gives you the language. The architecture was already yours.
Skills transfer across languages. "Built a company-sized TS codebase from scratch" means the architecture brain is trained. LLM is just the Rust adapter.
Can This Be Codified?
Could you put the required judgment into a system prompt?
Partially. But system prompts are incomplete heuristics. "Split files over 500 lines" applied naively to tsc's 30,000-line checker.ts would be stupid. The complexity is inherent. Splitting it wouldn't help.
Real judgment knows when heuristics apply and when they don't. That's hard to codify because it requires understanding why the heuristic exists, not just what it says.
For now, the floor is: programming literacy + taste + vision + ability to evaluate. That's lower than "3 years corporate Rust" but higher than "anyone can do this."
Maybe the floor keeps dropping as models improve. Maybe not. Honest answer: we don't know yet.
Why Don't More People Do This?
The people who build cool software are, by any reasonable metric, stupid.
"Normal" time allocation:
- Social life
- Relationships
- Hobbies that don't produce artifacts
- Rest
- Touching grass
"Stupid" time allocation:
- Years building something that might never matter
- Debugging at 2am
- Reading documentation for fun
- Caring whether the abstraction is right
- Having long conversations with an LLM about project architecture
By external metrics it makes no sense. Expected value is terrible. Most projects fail. Nobody asked. Go outside.
But if this IS what you enjoy, then "having a life" assumes life means something specific. Maybe we're the weird ones. (We are. But weird isn't wrong.)
The LLM observation: Most people don't look at LLMs and think "great partner to discuss plans and help build ambitious things that may or may not find a use someday." They think "this can help me write emails faster."
The capability is available. The weird personality type that would use it this way is rare. LLMs democratize execution, but they can't give you the inexplicable desire to build things that don't need to exist.
That might be the actual bottleneck. Not skill, not time, not tools. Just: most people aren't broken in this specific way.
Programming as Creative Endeavor
Hot take: it's sad that programming isn't seen as creative. Engineering in general.
Programming IS:
- Making something from nothing
- Aesthetic choices (this abstraction vs that)
- Style (you can tell who wrote it)
- Literal creation
But it's framed as:
- "Technical" (not creative)
- Engineering (mechanical)
- A trade, not an art
The double standard: Years spent on ABRSM piano grades = dedication, cultured. Years spent getting good at programming = "get a life."
Same time investment. Same skill-building. Society just decided one is cultured and one is weird.
The "punk" movements: Demoscene, bytebeat, live coding (TidalCycles/Strudel), dwitter, shadertoy, generative art. But all except the hacker movement are literally audio or visual. The code is invisible - the output is the art.
Where's the movement that celebrates a beautiful abstraction, an elegant API, architecture as composition? That's "good engineering," not art.
The Crochet Comparison
Observation: people don't watch others crochet either.
| Crochet | Programming | |
|---|---|---|
| Primary motivation | Enjoy the process | Enjoy the process |
| Output | Object (maybe useful) | Software (maybe useful) |
| Audience needed? | No | No |
| Seen as | Hobby, cozy, valid | Weird, get a life |
Same shape. Different cultural framing.
Nobody asks a crocheter "but why though." The answer "because I enjoy it" is sufficient.
Programmer says "I make software for fun" and it's "but why? Is it for work? A startup? What's the point?"
The point is the same: because I like doing it.
When Did Programming Stop Being Cool?
If this IS a real difference: why? When did it diverge?
Once upon a time:
- BASIC on home computers, type in programs from magazines
- "POKE 10238,1" → "waow that's neat"
- Making games in your bedroom
- GeoCities, personal websites, "under construction" gifs
- Tinkering, hobbyist culture
What changed:
- Programming became economically valuable → became "work"
- "Learn to code" framed as economic necessity, not creative expression
- When it's "work", doing it for fun = unpaid labor / weird
- Professionalization displaced hobbyist framing
- Tools got complex (can't just POKE anymore)
- Barrier to entry shifted: was "type this, see result", now "install 47 dependencies"
- The magic got hidden behind abstraction layers
The "wow" moment got harder to access. The creative framing got displaced by the professional one.
Somewhere between BASIC and bootcamps, we lost "programming as play."
The Bifurcation: Creative vs Professional Track
The "barrier went up" narrative is only half true. There's a bifurcation:
| Track | Complexity | Vibe | Examples |
|---|---|---|---|
| Professional | NextJS, k8s, 47 deps | "Work" | Bootcamps, jobs |
| Creative | Pico-8, Scratch | "Play" | Game jams, personal projects |
The creative track is alive:
- Pico-8, PuzzleScript, Scratch, Blockly, Snap!
- Love2D, Godot (simple path)
- p5.js, Shadertoy, Dwitter
- Sonic Pi, TidalCycles/Strudel
- DevTools (free IDE in every browser)
- Bookmarklets, userscripts
The professional track gets attention because money. The "everything is complex now" is professional track propaganda leaking into hobbyist space.
Why Programming Feels Intimidating
Not blank canvas paralysis. Invisible landmines.
- 47 frameworks, pick wrong one → wall in 3 months
- Architecture decisions that seem fine → explode later
- You don't know you're wrong until you're deep in
- "Best practices" contradict each other
- The right answer depends on context you don't have yet
Failure modes are invisible, plentiful, and feel like personal failure rather than navigational hazard.
Guardrails Exist (Sort Of)
Syntax guardrails (we have):
- Linters (ESLint, Clippy, etc.)
- Type checkers
- Formatters
- Pre-commit hooks
Strategy guardrails (we don't):
- "You picked the wrong framework"
- "This architecture will explode at scale"
- "You're solving the wrong problem"
You can write perfectly linted, beautifully typed code that's architecturally doomed.
The Answer Is Abstraction
The guardrails aren't linters or LLMs. They're good abstractions.
Good abstraction:
- Hides landmines
- Makes wrong choices impossible or irrelevant
- Reduces decision space
- Pico-8: can't pick wrong framework (there's only one)
Bad/missing abstraction:
- 47 frameworks = 47 ways to choose wrong
- "Flexible" = "you figure it out"
- Leaky abstractions interacting unpredictably
The insight: Linting IS pattern matching on graphs. Architecture and syntax are the same thing at different abstraction levels.
- Syntax linting: pattern match on low-level AST graph
- Architecture linting: pattern match on high-level dependency graph
- Both are "this graph shape is bad"
The State Problem
But architectural graph shape isn't the whole story. For web frameworks:
It's not about the architecture. It's about the state.
- Where does state live?
- What can mutate it?
- What depends on it?
- What cascades from an update?
Architecture can be clean. State can be spaghetti. At scale, state spaghetti wins.
Why every generation reinvents state management:
- Redux → MobX → Zustand → Jotai → Signals → Server Components
- All trying to make the state graph visible and manageable
The hard question: How do we know if the framework will collapse at 2x scale?
You CAN Lint State Statically
Defeatist take: "You can't lint runtime state from static analysis."
Actually, you can. Systems that do it:
- Rust borrow checker (ownership graph is explicit)
- Elm (no side effects, forced MVU)
- Effect systems (track what can happen where)
- State machines / XState (explicit states + transitions)
- Signals (reactive graph is explicit)
- Linear types (state can't be aliased)
Requirements:
- Make state explicit, not implicit
- Restrict what can touch what
- Encode the graph in the type system
Why don't we (in mainstream):
- "Flexibility" (too lazy to encode constraints)
- Legacy codebases
- "That's too academic"
- Mainstream tools don't support it
Rust proved mainstream adoption of static state analysis is possible. Elm proved it for web. Signals are creeping in.
The question isn't "can we?" It's "why isn't this the default?"
Why Programming Lost Its Hobby Framing
The Namespace Pollution Problem
Search "programming" → Primeagen, Low Level Learning, career content. Search "drawing" → pikat, samdoesarts, telepurte, creative content.
Same activity shape (skill-building, creative, time-intensive). Different search results. Why?
The Inverted Economics
Most creative fields:
- Hobby = normal, expected, valid
- Career = rare, difficult, often exploitative (art, music, writing, sewing/sweatshops)
Programming:
- Hobby = "weird", "why though"
- Career = lucrative, prestigious, desirable
It's inverted. The only creative-ish field where the professional path is better than the hobby path.
Except game dev:
- Hobby = cool, make games for fun
- Career = crunch, underpaid, exploitation
Game dev reverts to the normal pattern. Note: game dev is the creative subset of programming.
The Pattern
| Field | Creative? | Professional track |
|---|---|---|
| Art | Yes | Struggle/exploitation |
| Music | Yes | Exploitation unless famous |
| Writing | Yes | Underpaid, gig work |
| Sewing | Yes | Sweatshops |
| Game dev | Yes | Crunch, exploitation |
| "Programming" | Framed as NO | Lucrative |
The more creative, the worse the professional path. Programming's prestige comes from the non-creative framing. "Engineering." "Technical." NOT art.
Why (Economics, Not Just Culture)
Not just "society values engineers more." Actual economics:
Supply and demand:
- Programming: high demand, constrained supply (learning curve)
- Art/game dev: high supply (dream job, everyone wants in), limited demand
Passion as exploitable resource:
- If people WANT to do it regardless of pay → employers can pay less
- "Do what you love" = "we can underpay you"
- Enterprise CRUD: nobody's passionate, so market rate required
Revenue proximity:
- Backend engineer at Stripe → enables billions in transactions
- Artist at studio → "cost center"
The creative framing makes supply explode (everyone wants in) while demand stays flat. Economics do the rest.
The Missing Word
There's no "doodling" for programming. No word that means "I make little programs for fun, not for work, don't ask about my career."
"I draw" → hobby until proven otherwise "I program" → "for work? a startup? why?"
The vocabulary got colonized. No escape hatch to the hobbyist framing.
Except we HAD a word.
Hacker.
"Hacker" used to mean exactly this:
- MIT hacker culture
- Tinkering with computers for fun
- Clever solutions, joy of building
- "I'm a hacker" = "I make things because I love it"
Then it got stolen:
- Media: "criminal who breaks into systems"
- Security industry: "penetration testing"
- Bootcamps: "growth hacker," "hackathon" (career-ified)
1980: "I'm a hacker" = I make things with computers for fun 2026: "I'm a hacker" = I break into systems / I do 24-hour startup sprints
The vocabulary didn't fail to exist. It was taken.
We lost the word. And with it, the framing.
On Fixing Things
"It's Impossible"
The question we don't want to answer: "oh well it's impossible." The question we want to answer: "it's impossible. so what? we don't care. what are the holes?"
That's the hacker mentality. The original one. "Can't be done" is irrelevant. "What are the obstacles, let's route around them."
Torvalds made Linux. Hipp made SQLite. Notch made Minecraft. One person starts something. It catches fire or it doesn't. But the starting is one person.
Linux didn't fix computing by arguing about computing. It fixed computing by being Linux.
The existence is the argument.
The Root Problem
Symptoms: discoverability, vocabulary, scattered tools, etc.
Root problem: There's no creative programming tool that is both accessible AND general-purpose.
| Accessible | General | |
|---|---|---|
| Pico-8, Scratch, etc. | Yes | No (restricted domains) |
| Professional tools | No | Yes |
| ??? | Yes | Yes |
The creative tools are accessible BECAUSE of restrictions. But restrictions mean you hit a ceiling. Professional tools are general but not accessible for play. The gap is real.
But Don't Overgeneralize
"Canopy will solve this" → No.
The problem isn't one missing piece of software. It's 2026 and the entire software landscape is in disrepair. Buildings on questionable ground. Occupied for 3 weeks then abandoned. Questionable architectures. 40 years of accidental decisions treated as inevitable.
Building one building doesn't make a city. Building one tool doesn't fix a broken landscape.
What actually helps:
- Understanding WHY things are this way (this conversation)
- Designing alternatives, even without building
- Documenting the diagnosis so it's not lost
- Small experiments to test assumptions
- NOT pretending one tool solves systemic problems
Honest Framing: What Rhizome Actually Is
Rhizome isn't:
- A master plan
- A city
- THE solution
- A polished product
Rhizome is:
- "I made some stuff"
- Hacky prototypes
- Based on conversations (some with LLMs giving questionable ideas)
- Experiments that might fail
- Things built to see what happens
ARPANET energy. "This technically works, we don't know if it scales, it's held together with duct tape and enthusiasm."
Not "we're building the future of creative programming." More "we're tinkering and writing down what we learn."
The original hacker spirit, actually. Before it got stolen. Just making things because you can. No grand claims. See what sticks.
Maybe some of it will be useful. Maybe it won't. But the making is the point.
Prior Art Is Everything
It's 2026. We have all the prior art in the world.
Not just research:
- All shipped software
- All the code ever written
- All tutorials, blog posts, Stack Overflow answers
- All hacky weekend projects and abandoned repos
- All the Discord messages explaining how to do X
- All the HN threads arguing about it
The LLM has seen it all. Compressed and queryable.
But prior art includes the status quo. Which often doesn't work.
The current broken landscape is ITSELF evidence:
- "This approach was tried and didn't scale"
- "This pattern became standard despite being broken"
- "This decision calcified before anyone questioned it"
WIMP is prior art. Lesson: accidental, calcified, not a solution. React churn is prior art. Lesson: state management is unsolved. The current mess is data.
Learning from prior art = learning from failures as much as successes. We're swimming in documented failure.
Interaction Graph (Clarified)
Every affordance is an edge in the graph.
Not just "actions you can take." EVERYTHING:
- Button → edge
- Tab → edge
- Context menu item → edge
- Keybind → edge
- Link → edge
- Drag target → edge
- Hover tooltip action → edge
The interaction graph is affordance structure - what can you DO at any moment, and what does it lead to.
This is NOT what Obsidian/Dendron show.
| Obsidian graph | Interaction graph |
|---|---|
| Data relationships | Affordance structure |
| "Your notes connect like this" | "From here, you can DO these things" |
| Static visualization | Navigational/action structure |
| Pretty but useless | Actually useful for filtering/discovery |
Obsidian rendered a graph. Cool. And? Visual noise, not insight. "Look, your notes are connected" → okay but what do I DO with that?
The interaction graph is about the UI itself. What's available NOW. What's contextually relevant. What should be surfaced vs hidden.
Graph Visualization IS Worth Exploring
That said: graphs as visualization (non-scrolling-page) ARE worth exploring.
The problem isn't "graphs are useless." The problem is:
- Obsidian's graph doesn't help you DO anything
- It's eye candy, not tool
- No filtering, no context-awareness, no action
A graph visualization that:
- Shows what's relevant NOW
- Lets you navigate by relationship
- Filters by context
- Connects to actions
...that would be valuable. Just not "here's all your notes as dots."
Extracting Insights from Prior Art
Specific examples → extract insights → distill patterns.
Quick Notes on Exemplars
Excel: Success in adoption. UX is genuinely problematic though. Not a pure exemplar.
Blender: At least they're actively trying. Node improvements, UI overhauls. Credit where due.
Flash: Killed ostensibly for "performance/security" but really... Apple controlling app ecosystem? Web standards coalition? Worth digging into as "why good things die."
Obsidian/Dendron: They work. Files as truth, plugins. But graph view is just... rendered graph. No insight, no action.
Pico-8: Constraints as guardrails. Clear what "done" looks like. Creative success story.
SQLite: One person, everywhere, just works. "Do one thing well" taken seriously.
HyperCard: Pioneered everything. Why did it die? Apple neglect? Didn't fit the business model?
Smalltalk: Invented OOP, GUI, IDE. Why didn't it win? Too different? Licensing? Timing?
(To be expanded with actual extraction work.)
WIMP: What Actually Sucks
Not just "paper analogy." Specific problems:
- Paper skeuomorphism
- Single cursor - one point of interaction
- Rectangles compete for space - zero-sum
- Hidden functionality - menus, hunting
- Mode-heavy - each app is isolated world
- No spatial memory - windows move, forget position
- Focus is binary - one active, rest background
- Apps don't know about each other - copy-paste only integration
- File-centric - everything must be a file
- Discoverability is terrible
- Everything neatly partitioned - is this optimal?
Neatly Partitioned Critique
Windows are isolated boxes. They don't:
- Overlap meaningfully
- Flow into each other
- Share context
- Relate visually
"Neat partition" solves: "where do I put this thing" Doesn't solve: "how do these relate" / "what's my context" / "what spawned what"
What would "structured but not partitioned" look like?
Alternatives Beyond First Step
Not just "what was tried" but "what's the NEXT iteration?"
Tiling Evolution
- Tiling WMs: windows don't overlap
- Workspaces: groups of windows, switch between
- PaperWM/Niri: horizontal scroll, spatial + infinite line
- Niri gaining traction - middle ground that works
Infinite Canvas (InfiniteGlass, etc.)
Tried: 2D infinite canvas with zoom. Why didn't it stick?
- Lost snapping (efficient placement matters)
- Lost efficient navigation (how to FIND things?)
- Niri works because it keeps structure
Spatial Memory / 2D Desk
The appeal: Not /documents/homework/2012/mar/10/ But "upstairs next to the aquarium"
Different mental model. Spatial memory is real - humans remember WHERE things are.
The problems:
- Limited space
- Doesn't scale
- Not guaranteed to be better
- Might just be a gimmick
The pragmatic alternative: Fuzzy search
- Don't remember WHERE, search for WHAT
- Works, but loses spatial/relational context
Maybe the answer is hybrid:
- Spatial for small, frequent, current
- Hierarchical for archive/organization
- Search for retrieval when you forget
- Structure that aids search (tags, relationships)
Prior Art: iTunes Coverflow
Not a grid, not a list. Spatial, scrollable, depth-based. Browse by feel, not coordinates. Beautiful but... actually useful? Or just pretty?
Rusty Lake / Escape Room UX
You're IN a space. Drawers you open. Objects you find and combine. Spatial memory matters. The desk IS the interface.
This exists in games. Why not productivity software?
Contrarian When Things Visibly Suck
Not contrarian for contrarian's sake.
Process:
- This specific thing sucks → why?
- What would not-sucking look like?
- Has anyone tried that?
- If yes, why didn't it work?
- If no, why not?
- What's the next iteration?
The goal: Diagnose → propose → check prior art → iterate.
The Meta-Pattern: Multiple Paradigms
"Showing Relationships" Isn't UI
Putting a data structure on screen ≠ good design.
- Obsidian's graph: "Look! Nodes and edges!" → okay, and?
- File tree: "Look! Hierarchy!" → okay, and?
vs.
- "This is most important → big, top-left"
- "This is secondary → smaller, below"
- "These relate → visually connected"
Structure informs design. It doesn't replace it.
The interaction graph isn't "render the relationship data." It's "use relationship data to determine importance, placement, affordances."
Finding Things: Not One Strategy
How do you find a friend's apartment in a building?
- Ask the doorman (query a person/system)
- Check the directory (index/map)
- Call your friend (direct query to source)
- Remember "3rd floor, end of hall" (spatial memory)
- Wander and look at numbers (browse)
- Combination of all of the above
Not spatial OR search. Not spatial THEN search.
Whatever works for this moment. Fluid switching between strategies.
Real life gives you: spatial, ask, remember, browse, index, shortcut... Filesystem gives you: hierarchy + search. That's it.
The poverty isn't "wrong paradigm." It's "only one paradigm."
The Meta-Pattern
This is the Canopy insight, generalized:
| Domain | One paradigm (bad) | Multiple paradigms (good) |
|---|---|---|
| Viewing data | One fixed view | Multiple projections, user-chosen |
| Finding things | Just search OR just browse | Spatial, search, browse, ask, remember... |
| Editing graphs | Just nodes OR just text | Nodes, text, CyberChef, whatever fits |
| Navigation | Just hierarchy | Spatial, shortcuts, search, recents... |
The insight that keeps applying:
"One paradigm" is always wrong. The answer is always "multiple, fluid, user-chosen."
Don't pick the right paradigm. Offer multiple. Let the user switch based on context, task, preference.
This is what Canopy is trying to be: not "the right view" but "the ability to have any view."
Users Aren't Monolithic
Same user, different moments:
- Sometimes keyboard, sometimes click
- Tired vs focused
- Familiar vs exploring
- Quick task vs deep work
Different users:
- Expert wants density
- Novice wants guidance
- Different mental models
"Know your user" is wrong. "Support multiple modes of being a user" is right.
One paradigm fails because it assumes one user, one need, one moment. Reality is plural.
Good Design vs Multiple Paradigms
Tension:
- Multiple paradigms → serves more users/contexts
- Cohesive design → works smoothly, constraints = clarity
Resolution: Maybe not "one infinitely flexible thing." Maybe "many small cohesive things, with ability to switch."
Each projection is a Pico-8 - constrained, cohesive, good. The platform lets you have many Pico-8s.
Too Connected = Bad Design
If the interaction graph is too connected, the problem isn't filtering. It's architecture.
A well-designed system has a clean graph:
- Not because you filtered a messy one
- Because the underlying structure is right
- Complexity is appropriate
If you NEED heavy filtering to make it usable → the design is bad.
Context filtering isn't a solution for bad design. It's a coping mechanism.
The real solution: design a graph that doesn't need heroic filtering. Keep connections meaningful. Keep complexity appropriate.
Case Study: Moss
Moss primitives, filtered down to:
- view
- edit
- analyze (compute metrics)
All using unified fuzzy search syntax.
Not 50 commands. Three verbs. One syntax. Clean graph.
The complexity went down not by runtime filtering, but by reducing the primitive set at design time.
The Ask
"I just like when my software isn't exotic and opaque. Is that too much to ask?"
Apparently yes, given the state of things. But it shouldn't be.