Every calendar app you've ever used looks roughly the same.
A grid. Seven columns. Rows of days marching left to right, week by week. It feels natural because it's familiar — but familiar isn't always the best fit.
That grid didn't come from careful thinking about how people actually use their time. It came from paper. From the kind of calendar you'd hang on a wall or slip into a diary — a format designed around how best to print them, not around how ideas and projects actually work.
And that made sense for paper. Time is linear — one day follows another — so a grid that moves left to right, day by day, week by week, reflects that honestly enough. The problem isn't that time is linear. It's that the grid treats that rigid time as the only thing worth organising your tasks by.
So when software came along, nobody questioned it. The grid just... moved across.
And it doesn't matter which view you're in.
Day view, week view, month view. The scale changes. The grid never does. Every day still gets exactly the same space. The assumption travels with it, whatever you click.
Monday gets the same space as Saturday.
The calendar doesn't know the difference. And neither does any tool built on top of it.
Now, for a lot of people that's fine — if your day runs on a schedule, a grid works. But there's a whole category of person it was never really built for. Someone planning a wedding alongside a full time job.
Someone writing a novel chapter by chapter. Someone whose project has days so different from each other they barely feel like the same job.
Most tools, printed calendars and diaries only ever offered the grid. After all, if an hour can't stretch — why should the grid? So people found themselves bending to fit it.
I wanted to build for those people. So we asked a different question.
What if the user decided everything?
So that's the assumption we're going to remove — that time dictates everything. Now — what do you do with it?
Most people get to this point, realise there's a problem that can be solved and then simply just bolt something on. A feature that patches the problem.
Productivity software does this a lot. Priority field — decide now, before you've done anything. Tags — build a whole system before you've worked out what you're organising. Due date, assignee, flags, badges, custom views. Every one a micro-decision arriving before you've worked out what you're trying to do.
And that feels like progress — it genuinely does, that version with the bolt ons now does something that none of the others do. But what they've made is the same app with an extra room on the side. The foundation is still the same assumption, just with more stuff stacked on top of it.
And the symptoms are always the same. Existing users might find the new bolt on useful, or a hindrance, some new set of microdecisions they have to make or a new system they now have to maintain. But new users to the app hit every bolt-on at once — and there's no easing in.
And then there's language. Every app decides what things are called. Epics. Stories. Habits. Entries. Those words made sense to the person who built it, for the user they had in mind. But if you're planning a wedding or writing a novel — you're translating. Every single time you open the app.
Most tools try to do too much because they were defined too early. A structural replacement doesn't do that. When the foundation changes, a lot of that complexity just stops being necessary. The decisions dissolve because the structure is handling them — spatially, visually, or just by making them optional and getting out of the way.
So instead of patching in new features — we follow a method. Four steps.
Find it — find the assumption nobody named. The thing so embedded in the category it stopped looking like a choice. For calendars — every day is equal. Or everything has a time and a duration.
Follow it — ask what's natural to build once that assumption is gone. Not what features you want. What the structure now demands.
Feel it — use the thing. Properly. Not as a demo, not as a test. As a tool you actually need. Because some decisions only reveal themselves once the thing exists and you're living with it.
And then look back. Because if you did the first three right — features will have fallen out of the gaps that you never planned for. That's not luck. That's the signal you replaced the right thing.
Great so — let's follow it and build out this calendar app.
Most calendars give you views. Day view, week view, month view. You pick one and the app reorganises itself. Want detail, go closer. Want the big picture, zoom out. But you're always choosing. Always trading one thing for another. Even scrolling to the next month often hides the current one.
So we wanted one surface. Time runs left to right. You scroll sideways through your weeks and months. What you can see is what exists. No modes, no switching, no tradeoffs. You should be able to see the end of March and the beginning of April at the same time.
The columns — each one holds one or more days. Sometimes a single important day deserves its own column. Sometimes some quiet days can be just two small cards sharing one whole column. The column is yours to decide. But the most important thing about this surface — the thing that makes everything else possible — is that it has no opinions. No fixed day sizes. No time slots. No rules about what goes where. That blankness is deliberate. Because what fills it, and how, is entirely up to the user — and that's the whole point. Over time they stop shaping their project and just simply, arrive at it.
Now — a surface with no fixed structure raises an immediate question. Where are you, when is now? On a traditional grid the answer is obvious — the shape of the week tells you. On a free canvas you need something else.
Today's day card carries a permanent dashed golden border. Always there, never fading. However far you scroll in either direction, one glance tells you exactly where now is relative to everything else. Small detail.
Simple idea. But the implementation nearly went badly wrong.
The original plan was a chip system — drag the card to a size, let go, and it snaps to the nearest preset. The thinking was that a normalised value might be more useful later. It felt smart. It felt forward thinking.
The problem was that every single time someone let go of the drag handle, the card jumped. Not to where they left it. To where the app decided they meant to leave it. Like being corrected. And it felt wrong every single time.
Dropping the chip system and just storing the exact height — two lines of code. And suddenly the drag did exactly what a drag should do.
Two principles came from this. If the user can feel your data model, something's wrong. And don't build for a future that hasn't arrived. You can always add it later. You can't unfeel a bad drag.
Now — every day card has two buttons. But they don't sit on the card permanently.
Hover over a day and they appear. Move away and they're gone. Hide this day. Add item. Two actions, always available, never in the way. Permanent visibility is for permanent information. Contextual actions belong to the moment you need them.
Some days you don't need to see at all. Maybe you never work Mondays. Maybe weekends don't belong to this project. So you can hide them — individually, or globally. Hide every Monday in one go if Mondays just aren't yours. The canvas becomes the shape of your actual project, not the shape of the month. And if you've hidden Mondays across the board but one particular Monday needs to come back — you can unhide just that one. The intentional always overrides the automatic — the user always knows what they want better than we can. So global settings are just defaults, they're not rules. And if you ever give someone the ability to hide something, make it just as easy to find it again.
And hiding days creates a new problem. With day cards of different heights and hidden days scattered across the canvas, a new month can start partway down a column — not at a clean boundary like a traditional grid would give you. So each month gets a slightly different background colour, and a heading at the top of its section marking where it begins.
This is worth pausing on — because it might look like we borrowed something from the original model. We did. Deliberately. Replacing an assumption doesn't mean rejecting everything that came before it. If something genuinely helps orientation, it earns its place regardless of where it came from. The test is always whether it serves the user, not whether it's new.
So if days can be different based on how heavy they are, then an item should be as well. A tall day card is a statement. This day is heavy, give it room. A short one is a statement too — there's not much here, or what's here doesn't need space. Your users aren't filling in a form about how busy a day is. They're just shaping it. And the canvas remembers the shape. Come back tomorrow, it's exactly as you left it.
An item only needs a title. That's it. No time required, no category to assign before you've worked out what the thing even is. Everything else — notes, colour, a time if it actually has one — is optional. The app doesn't demand precision your users don't have yet. And if you never add anything beyond the title, that's a perfectly valid item.
Now that we have day cards with items in them — there's a decision I almost made here that I'm glad I didn't. I toyed with the idea of day cards spanning multiple columns — one important day taking up two or three columns worth of width. Technically interesting. But when I asked honestly who actually needs a day card spanning three columns sitting next to a column with seven days in it — I couldn't find a convincing answer. So I didn't build it.
And that's worth naming. Because not building something doesn't feel like a decision — it feels like just not getting round to it. But choosing not to build something is as deliberate as choosing to build it. Every feature you add is a surface area someone has to understand. Every feature you don't add is a complexity someone never has to face. And because this is open source — the person who needs it enough to build it is probably exactly the right person to build it.
One last thing about the canvas before we move on. The DOM loads with the current month in view. You can scroll back two months, or forward two months.
But at each end, there's a button. Plus two months. Because nobody wants a scrollbar thumb the size of a pixel trying to navigate four years of work. The canvas grows when you ask it to, and only then. Another place where the structure is handling a decision so you don't have to.
Now look at what we have. The day card's height says something about the day. The item card's height says something about the task. A tall item in a tall day — something significant in a heavy period. A small item in a quiet day — a light touch. Days that don't belong to your project can disappear entirely. The canvas communicates density and weight at a glance — not because the app calculated it, but because the user shaped it.
So, we now have a spatial app with a horizontal canvas — but no way to orient yourself. With a grid there's a solid structure to orient yourself from, but with a canvas that hides days and has days of different heights, it's not always clear where you are. No way to see where today is, what's coming up, what's already passed. That gap wasn't planned for. It just became visible the moment the canvas existed.
So the sidebar was always going to exist. What we didn't know upfront was exactly what it needed to contain. So we asked the question the method demands — what does this kind of tool need to show, for the widest possible range of people using it? And then we built the answers.
At the top — calendar management. Because you might not just have one project. You might have a work calendar and a project one. A client you're working with alongside something you're building on the side. Each gets its own canvas, its own shape. Switch between them in one click. Add a new one just as fast.
And delete. Which needed more thought than you'd expect. After clicking confirm and typing delete, you reach a final confirmation. Everything on screen darkens slightly. The calendar you're about to lose stays visible in the dropdown — and turns the same red as the Delete button. That change draws your eyes to it, giving one last visual clue as to what will soon be gone. The interface holds the weight of what you're doing for just a moment before it's done. Some actions deserve a moment of friction. This is one of them. That detail cost almost nothing to build. But your users will feel it every single time.
Below the calendar selector — the mini calendar. And it needed to communicate two things at once — which days have items, and which days are hidden. A day with items gets a golden coloured bottom border. At a glance you can see where work lives across the month and where the free days are.
But hidden days needed their own answer. If you click a hidden day in the mini calendar, nothing happens because there's nothing on the canvas to scroll to. So should we automatically unhide the day? No — that changes the shape the user deliberately built. Should we just do nothing? Also no — that's confusing, it would feel like a bug.
Simplest solution. Hidden days get a red coloured bottom border in the mini calendar. You know immediately — that day exists, it's just not on your canvas right now. And when you click a mini calendar day to navigate to a day that is on the canvas, the day card in both the canvas and the mini calendar briefly flashes its golden border — then fades. That flash is the bridge between two different ways of seeing the same information. The mini calendar is abstract. The canvas is spatial. Without the flash, navigating feels slightly disorienting. With it, you always know exactly where you landed. If you take away something familiar, make sure what replaces it closes that gap as well as — or better than — the original.
And the mini calendar doesn't just sit there showing you this month either. As you scroll the canvas, it follows. April in the centre of the canvas — the mini calendar switches to April. The abstract and the spatial stay in sync automatically. You never have to think about which month the mini calendar is showing, because it's always showing you exactly where you are.
Now — up until this point, every item has been the same colour. And that was fine for building the structure. But once the sidebar existed and the canvas started filling up, colour became the obvious next question.
Colour has no predetermined meaning here. So who decides what it means? The user does — and it can work however they need it to. Project type. Energy level. Client. Priority. Mental category. Eight named slots, fully yours to define. And there's a none option too — no colour, no pressure to organise before you're ready.
This is a recurring pattern — wherever we can offload a structural decision to the person actually using the tool, we should. It almost always produces something more useful than whatever we would have decided for them.
And once colour exists as a system the user built themselves — filtering by it is just the natural next step. Below the mini calendar, the items list. Search, filter by colour, filter by calendar, scan everything in order. For the moments when you want to find something specific rather than browse spatially.
And there are two toggles worth mentioning. Include notes — so if the detail you're looking for is buried in an item's notes rather than its title, you'll still find it. And include past items. Imagine four years of work on this canvas. Search for the word sprint and you might get hundreds of results — most of them irrelevant to right now. Toggle past items off and you're only looking at what's current. Toggle it on when history is genuinely useful context. None is also a filter, so you can find everything you haven't categorised yet if that's useful. Your users decide, based on what they need in that moment.
And the items list has its own moment worth mentioning. Hover over any item in the list and two buttons appear — edit item, and go to.
Go to jumps the canvas to that item's day card and flashes its border gold — the same bridge logic as the mini calendar click, just in reverse. You started in the abstract list and landed on the spatial canvas. The flash tells you exactly where you arrived. The same solution, appearing naturally in a second place. When you find yourself solving the same problem the same way twice, that's not repetition. That's a design principle revealing itself.
None of it is noise. Every sidebar element answers a question someone using this tool would actually ask. And it's always visible — not a menu, not a panel you open and close. A permanent part of the surface, because the information it contains is permanently relevant.
The canvas shaped by the user. The sidebar reflects that shape back — showing you exactly what you've built, what's in it, and what still needs a home.
So while using the app it was obvious we needed undo and redo along with the normal keyboard shortcuts. On a canvas like this it matters more than in a standard app — you're not undoing typed text, you're undoing moves. A drag that went somewhere wrong, a resize you didn't mean, a day you accidentally hid. One button, one step back.
Next to it — show hidden days. You've already seen this but it's just one toggle to bring everything back into view globally. Useful when you need to check something you'd deliberately set aside, without having to remember which days you hid or go hunting for them one by one.
And then — column widths. Three options. Narrow, normal, wide.
Most people will pick one and leave it there. But there's something worth understanding about what these three settings actually are — because they add another level of flexibility to the user's ability to shape their canvas.
On the wide setting, a single day that fills its column isn't far from what a day view looks like in a traditional calendar. And on the narrow setting, you might have seven days in every column — that starts to feel a lot like month view. But here's the difference. You're not switching views and losing everything you shaped — just simply changing the column widths, not the day cards or the items or their heights. A heavy week coming up — go wide, give it room. A quiet stretch a few months out — go narrow, keep it in peripheral vision. Your users decide what to emulate, and when, and for which part of their project. Which is, of course, the whole point.
And zooming works too. Ctrl+ and Ctrl- don't just scale the page — the canvas reflows completely on each step, filling the available space from top to bottom again rather than just getting bigger and spilling off screen.
At fifty percent zoom you can see roughly eight months at once. Paired with column widths, that's two very distinct ways to control how much of your shape you can see at any one time. Wide columns at full zoom for deep focus on one week. Narrow columns at fifty percent for a bird's eye view of an entire project. Once again, the canvas adapts to whatever question you're asking of it right now.
And then there's a fourth column width option. One that only makes sense once you understand what the first three are doing.
Glance. One button. The canvas compresses. Column widths tighten beyond the narrowest normal setting. Day card heights — all the ones you carefully shaped — temporarily set aside. Everything collapses to show its contents. Not because your statements about those days were wrong. Just because right now the only question is — what's actually here?
It's still live. You can still drag items or open modals. It's not a preview — it's still your canvas, ignoring a few things to show you as much as it can all at once. Simply return to one of the normal column widths and everything — the day and card heights, the notes, everything — comes back just as you left it.
Four levels of zoom on a canvas you own. No switching, no trading, no losing your shape.
This one wasn't planned.
I was actually using the app — to plan the build of the next project, more on that later — and I needed to rejuggle a bunch of tasks. I didn't know exactly where they'd land yet so I just dragged them to an empty day the following week, out of the way. Halfway through I got distracted — as you do — came back, and spent a good few minutes going where are those items? Which day did I dump them on? They were just... lost in the canvas. And my own app couldn't handle it properly.
So the Later sidebar appeared. A holding area at the right edge of the canvas. Drop something in there and it leaves the canvas entirely — no date, no pressure, just held. Same card, same colour, same height. No sense of it being archived or buried — it's the same item, just parked.
The way it opens is worth a second too. When you start dragging an item, the sidebar appears on its own. If you drop the item there it stays open. If you drag somewhere else instead it quietly disappears again. It only shows up when it's needed. Like discovering a drawer at exactly the moment you're holding something and wondering where it goes.
Problem solved. Except — I kept using it. And I kept forgetting what I'd put in there. I'd scan the canvas looking for something, convinced it was on a day somewhere, and it just wasn't anywhere. Because it was in Later. And there was nothing to remind me.
The count. Small addition. But Later (3) became the reason your users will open it — not to add something, but to find something they'd forgotten they'd parked.
And then I noticed something else. Before anyone had ever dragged anything in — before they'd even discovered what the button did — it already said Later (0). That little zero was doing a job I never planned for. It was telling people what the button was for before they'd used it once. A clue hiding in plain sight. Nobody planned that.
The feature found its own purpose. And then asked a bigger question.
What if someone hadn't just mislaid a few tasks — what if they'd been called away? Missed a few days, got behind, and now everything downstream is in the wrong place. You could drag items forward one by one but that's not a solution, that's an afternoon.
And that's how Push appeared. One button on any item modal. Two questions — just this item, or everything scheduled after it too? And by how many days? Confirm and the canvas updates.
The Later sidebar didn't just solve its own problem. It asked a question that led directly to another feature. That's what falling out of the gaps actually looks like.
And you might wonder — once Push existed, did Later still need to? Push handles the structured slip. You know you're behind, you know by how many days, you move everything forward. But Later is for the other thing. The task you genuinely don't know when you'll get to. The thing with someday written next to it. I've still got year old notes with exactly that word on them. Push can't help with someday. Later can.
Now — open any item modal and something reflects back at you immediately.
Along the top of the modal runs a bar. The colour the item has been assigned. The title, live — updating on every keypress if you're editing it, changing instantly if you swap the colour. It sounds small. But it means every modal feels like the item it belongs to, not a generic form that could be for anything. The card has a colour. The modal should too. Follow the abstraction all the way through — the moment you stop, the user feels it.
The status bar at the bottom has a spatial logic that mirrors everything else. Left side — stable, structural, permanent. Right side — live, transient, fading. A single line of text that confirms actions and then fades after three seconds. Item moved to Later. Three items pushed forward. Day hidden. Undo successful. No icons, no stacking, no noise. Just a quiet confirmation that the thing you just did worked.
On the left — two things that are always true and never go away.
We chose local first. No server, no cloud, no auth. SQLite running entirely in the browser. Powerful for accessibility and simplicity — but it comes with a real implication. If there's no server holding a copy of your data and the browser decides it needs space, your data could go with it. Nobody is catching that for you. So the responsibility landed with us.
The export nudge. If you haven't exported recently a little notice lets you know using an amber colour. Once you do export, it turns green. Not a modal, not a notification. Just a subtle hint to keep a recent backup of your data.
When you make a structural decision, follow it all the way. The gaps it creates are your responsibility too. Do everything you reasonably can to protect your users. After that, the responsibility becomes theirs.