Sketching States Before Screens #
Exploring how plain-text state sketching and behavior-first design help clarify complex UI interactions before visual design, improving collaboration and product flow.
After a few years away from publishing, I’m rebooting this site with something I’ve been quietly exploring: a plain-text way to sketch product flows and UI behavior before jumping into visual design.
This started a while back when I was designing a handheld Android barcode scanner used by warehouse workers. The interface was straightforward, but the system logic wasn’t. I kept hitting the same question: “What happens now? What happens next?”
Statecharts helped me map out the complexity — user input, errors, retries, edge cases — but the tooling felt scattered. I had diagrams in one place, design files in another, and notes everywhere. I tried Sketch.systems and other tools, but I still ended up stitching things together manually.
Visual design tools are great at showing how an interface looks — but not how it behaves.
And yet, behavior is where so many product decisions live. These moments — when something fails, changes, or surprises the user — shape the actual experience.
State thinking helps expose those questions early. It gives designers and developers a shared language for what the app does, not just what it shows.
So I started tinkering with a lightweight DSL (domain-specific language) to describe app behavior in text. Something expressive but not overly technical. Here's a simplified example:
Repository Page
keypress "/" -> CommandPalette:active
CommandPalette
query_scope: repo:owner/repo
Inactive*
Active&
type "test" -> Suggestions / "Jump to" updated w/ params
keypress "Enter" => SERP w/ query_scope
This lets me describe screens, components, parameters, nested states, and user interactions in a clear and readable way — kind of like writing a narrative sequence like a screenplay.
I’ve also been converting this DSL into a flattened XState machine that works with the Stately visualizer. Seeing the behavior mapped out visually helps me validate the logic early, even before I start drawing screens.
Here’s how the DSL elements map to XState structures:
DSL Element | DSL Syntax | XState Representation |
---|---|---|
Page / Screen | Repository Page | Top-level state (e.g., RepositoryPage ) |
Component | CommandPalette | Nested state inside parent (e.g., RepositoryPage.states.CommandPalette ) |
Parameter | query_scope: repo:owner/repo | Stored in context |
Initial State | Inactive* | initial: 'Inactive' |
Parallel State | Active& | type: 'parallel' inside XState |
User Action / Event | keypress "/" | Event (e.g., KEYPRESS_Slash ) |
Transition | -> | Internal transition (e.g., on: { KEYPRESS_Slash: ... } ) |
Navigation | => | target with absolute path or external screen state |
Nested Selector | Suggestions / "Jump to" | Nested state paths |
And here’s a matching snippet from the XState machine:
import { createMachine } from 'xstate';
const appMachine = createMachine({
id: 'App',
initial: 'RepositoryPage',
states: {
RepositoryPage: {
id: 'RepositoryPage',
initial: 'CommandPalette',
states: {
CommandPalette: {
id: 'CommandPalette',
initial: 'Inactive',
states: {
Inactive: {
on: {
KEYPRESS_Slash: 'Active'
}
},
Active: {
type: 'parallel',
states: {
Suggestions: {
id: 'Suggestions',
initial: 'JumpTo',
states: {
JumpTo: {
id: 'JumpTo',
initial: 'Idle',
states: {
Idle: {
on: {
TYPE_test: 'UpdatedWParams'
}
},
UpdatedWParams: {
id: 'UpdatedWParams',
on: {
SELECT_helper_js: '#App.FilePage_helper_js'
}
}
}
}
}
}
},
on: {
KEYPRESS_Enter: '#App.SERP_w_query_scope'
}
}
}
}
}
},
SERP_w_query_scope: {
type: 'final'
},
FilePage_helper_js: {
type: 'final'
}
}
});
This isn’t a product or a full-blown tool — at least not yet. I’m not a developer, so most of this is prototyped by hand. But I’m curious where it might go.
Some ideas I’m thinking about:
Interactive prototypes that simulate the state machine behavior
A web editor that lets you type the DSL and preview the flow
Figma plug-ins or integrations that bring state logic into screen design
For now, it’s just a side project — but one that’s helped me think more clearly about interaction design.
If you’re a designer, developer, or curious hybrid who’s felt limited by UI-first tools, I’d love to hear what you’ve tried — or what you’ve wished existed.
Acknowledgments #
This exploration builds on the work and ideas of others who’ve helped me think differently about interaction design:
- Ryan Singer — for his shorthand approach to UI flows that values behavior before visuals
- Kevin Lynagh — whose work on Sketch.systems first showed me the power of plain-text state modeling
- David Khourshid — for XState and the broader movement to bring clarity and visual tooling to complex state machines
Big thanks to them for pushing the field forward.
🙏🙏🙏
Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated 💖! For feedback, please ping me on Twitter.
Published