← Lab
interfaces·In progress·2026

Nimbus

What if the weather had personality?

Logbook · 51 entries ↓Ver demo ↗
03

Logbook

51 entries
Implementation
Milestone

On the web, signing in with Google takes two taps and zero drama. On Android it was a full-blown K-drama 🫶.

The button opened Chrome on its own, asked for your account and left you stranded outside: a one-way ticket, no return to the app. We swapped it for the system’s native sign-in and the second surprise arrived: you picked your account, the picker bowed out with flawless manners, and Nimbus kept swearing with a straight face: "You’re not signed in".

Oh, it signed in. The catch is that two sessions were living in parallel worlds on the phone: Android’s and the app’s. The plugin only told the first one, while the screen in charge kept waiting for news that was never coming. We had to introduce them by hand so they’d finally talk.

But the heartbreak came back through the side door: you tapped "Sign out" and absolutely nothing happened. It closed one door and left the other wide open. Two entities sharing the same roof without ever talking never end well. Not in software, not in couples.

Infrastructure
Completed

On September 21st I turned off my GPS on purpose to test Nimbus’s pride. If you asked for your location by hand, it dropped a generic error under the weather of a city you weren’t even in anymore. I logged it as pending and there it slept, gathering dust with the patience of a city-hall line.

Seventeen days later, debt settled. When you ask for your location and the phone can’t give it, Nimbus stops pretending: it clears the ghost weather and greets you with the welcome screen, designed precisely not to lie.

Well, half settled, to be honest. In the background it still clings to the last known location without a peep. But that’s no longer a bug: it’s a design decision. If it doesn’t know where you are, it should have the decency to admit it; for making up realities, we already have more than enough politicians.

Interface
Decision

Looking at the panel on my own phone, the switch swore alerts were "on". Android hadn’t granted a single permission. The toggle was lying with the nerve of a politician on the campaign trail.

We rebuilt it from the ground up. Now the switch doesn’t trust its local memory: it asks the operating system in real time every time you look at it. And on the home screen we added a civilized invitation card: tapping "Not now" doesn’t burn the system permission. It asks up to three times, fourteen days apart; if you keep ignoring it, it takes the hint and goes quiet forever.

An app can insist if it has reasons. What’s unforgivable is lying to your face.

Testing
Progress

First time Nimbus lands on my phone as a real app, not a browser shortcut with delusions of grandeur (hello, PWA).

Three welcome surprises. It installed under the alias "AppClima" (the repo’s generic name, zero elegance). The "Use my location" button died silently because nobody had told the Android manifest we’d be asking for it. And browser notifications are useless in a native environment: it asked for permission into the void and just waited. Now it talks straight to the system’s manager.

It’s called Nimbus now. It knows exactly where you’re standing. That same night it told me, on its own, that the weather had changed its mind. In English, because that’s how I asked it to.

Infrastructure
Failure

I built Nimbus’s first APK and was greeted by a blank screen. No red error, no distress signal, nothing. It looked like the engine simply refused to start.

Oh, it started. The catch is that it was looking for its resources in /nimbus/, the path where it lives on my website; and of course, inside a phone’s file system that folder exists only in my imagination. Android now has its own packaging and its own root.

A blank screen isn’t the absence of a failure. It’s a failure too proud to speak.

Content
Decision

The notification texts lived straight in the code. One per event, generic, and not even written by me. Tragic.

Now they live in Olimpo: I tweak them, test them, and they go live without a single deploy. Nimbus picks one at random and has the decency not to repeat the last one it put on your screen.

That same day I built a mood monitor on my site with rotating phrases. Two different fronts, same lesson: a joke told twice stops being funny; three times, it’s spam.

Implementation
Progress

Alerts no longer depend on someone pressing a button like a telegraph operator.

Every half hour, Nimbus checks the sky for everyone who asked for alerts and warns them if rain is coming or the temperature takes a sudden turn. It doesn’t question users one by one: it groups them into grid cells of about 11 kilometers so as not to burn through quotas. It respects sleeping hours and won’t tell you the same joke twice in a day.

By noon the first crack appeared: if you traveled, the alert kept watching the weather in the city you’d left behind. Now it follows your real coordinates.

Telling Lima it’s hailing in Cusco was not in the script.

Infrastructure
Insight

With Nimbus open in the foreground, the notification arrived and nobody bothered to draw it. A classic: there was no listener on duty while the app was awake. Ten minutes to fix.

The mystery came after: on my desktop browser, dead silence. I spent half an hour hunting ghosts in the code, but the code was innocent. The culprit was Brave: its shields assume Firebase is a spy and execute it without trial.

On Chrome and Android, app awake or asleep, it lands without blinking. For once, the bug wasn’t mine. That deserves a celebration.

Infrastructure
Lesson

The key to the notifications lived in a file that never got uploaded anywhere. Flawless for security; a disaster for memory.

It was tucked inside the test folder. I deleted the folder and the key went with it. I shipped two deploys in complete peace: the build passed, the console smiled, and in production nothing moved. I only noticed when a real phone went silent.

What doesn’t travel with the repo doesn’t survive the move.

Milestone
Milestone

Nimbus can now talk to you without anyone giving it the floor.

I tested the whole chain: permission, phone registration, Firebase, and the notification on the lock screen. It arrived. Sounds like paperwork, but it’s the first time Nimbus opens its mouth on its own.

Two survival decisions. Firebase instead of reinventing the wheel with a homemade backend: Android only respects that dialect, and I don’t have enough life left to maintain two systems. And no forced Google sign-in: for the average user, that account doesn’t even exist. Nimbus recognizes the phone and skips the interrogation.

Now comes the genuinely hard part: making sure what it has to say isn’t a monumental waste of time.

Idea
Hypothesis

I think Nimbus is coming out too tame. I’m thinking about sharpening its personality: right now it’s sarcastic but healthy, and I wonder if it should be much more sarcastic, almost a toxic relationship with my own app. Not like Duolingo, which flat-out stalks you. Although, thinking about it, maybe something close to that.

It’s not a decision yet, just an idea circling. If I try it, I’ll try it carefully.

Infrastructure
Lesson

I turned off my phone’s GPS on purpose, just to see what Nimbus would do. The answer: it kept believing it was still where it used to be. In the background it doesn’t say a word, it just holds on to the last location it had.

When I ask for the location by hand, it does tell me something failed, but with a generic error, not the welcome screen I already have in mind for when it doesn’t know where I am. There’s something to adjust there.

Product
Hypothesis

It occurred to me that "Nimbus recommends" is a bit bland. I like eating well, so I thought about pairing it with food: if it’s hot, a good ice cream; if you’re in Piura, a typical Piura dish.

For now it’s just an idea, not even fully decided. I put together a database of typical dishes by Peruvian department to have something to start from, if I go ahead with it. The food would replace the line under "Nimbus recommends"; the title stays.

En of the day
Pause

For today, phrase curation. Push notifications are staying for tomorrow or the day after. It’s been several days in a row on this, and today it’s time to stop. I do want to build push properly, client and back end both, and that’s not something you build with a tired head.

Product
Decision

Now that I have two references, it’s time to curate phrases. I still don’t trust an LLM to write them for me: I’d rather hand-pick the ones that already get the most interaction, and someday feed an engine of my own with those, one that generates phrases on its own.

I’m not building that engine soon. I’d need either a machine to run it locally, or the nerve to play with some cheaper Chinese AI. For now, I’m still the one deciding what Nimbus says.

Product
Insight

The beta is ready and I’ve tested it myself. I think I can pass it to a few close friends — I badly need their feedback.

But I noticed something: for "Winter is coming" or any other reference to show up, the user has to have picked that preference, and today it’s hidden in Settings. I have mine set from the start, obviously. Someone new doesn’t, and they can end up seeing something too niche to make sense of.

(I thought about building an onboarding for the first time someone opens the app, but I dropped it: I don’t want someone trying it out for the first time to leave before they even get to use it. It stays on the pending list, for now.)

Design system
Doubt

I already have a first order for special dates: the event comes first, then the moment, then the weather, and if none of that applies, neutral. That’s how Halloween, Valentine’s Day, Chinese New Year and whatever comes next already work.

Now I want to go further and define those dates by calendar, right from the pose admin itself. I have a doubt I haven’t solved yet: the same day isn’t the same day everywhere. I’ll iterate on this first, before promising something a time zone could make me regret.

Content
Progress

Nimbus’s references are starting to get a face. Before, "Winter is coming" pulled up the same generic cold-weather image; now I grabbed Game of Thrones illustrations so the image matches the phrase.

I added a second reference: Pokémon. Pikachu for lightning, because it’s the obvious pick, and Charmander for heat and fire. They’re parodies with legs, not copyrighted characters getting nervous.

I already know which reference wins in each weather extreme: Winter is coming for cold, Dracarys for heat. The second one, for now, only lives in my head.

Process
Milestone

Nimbus reached a version I can finally call stable. Not because it’s finished, but because I can touch something without wondering what else I just broke.

Along the way I ended up with two folders, two branches and two Claudes, each working wherever it saw fit. It worked surprisingly well until it stopped working. So I tidied the house, fixed a couple of things I’d been dragging along and left a single way of working.

Now I can go back to what matters: finishing giving Nimbus a face of its own. Lima, the beach, its poses and everything that still doesn’t come out of an automated test.

Those are mine to draw.

Interface
Progress

Today I realized I was designing a search tool when what I actually needed was to help someone make a decision.

So I changed the screen. Once you choose the weather you want and how far you’re willing to go for it, Nimbus stops asking you things and sticks its neck out: it recommends a place. There’s one main option and a couple more in case you don’t fully trust a cloud with legs. The map is there to check that Nimbus isn’t making it up.

I also cleaned up quite a bit. Distances, headings, airports and other data that technically could be there, but didn’t help anyone decide, are gone.

I still need to see it working with real data and, above all, make the reasons sound truly like Nimbus. For now it knows how to find the weather. It still has to learn to sell you the getaway.

Product
Progress

New feature: Explore other places. The person picks the weather they feel like (cold, hot, mild or rain), how far they’re willing to go and for when, and Nimbus says where to find it.

Inside, it’s a grid of points around where you are. I fetch each one’s weather from Open-Meteo, score them against the chosen weather and give the best ones a name using reverse geocoding. If nothing beats what’s here, the answer is "stay". Nimbus being able to tell you there’s no need to leave the house strikes me as a virtue.

The range started as driving time, from 30 minutes to 4 hours, and I changed it to straight-line kilometers, from 50 to 1,000. I dropped real routes: traffic is better calculated by the maps app. "Another date" also came in, up to 15 days. "See on maps" points to the town and not to the grid point, because Google won’t calculate a route to a hillside, and "Find flights" only shows up from 250 km and with an airport at both ends.

The expensive part is quotas: every point counts as a call, so a 1,000 km search is 97. If they run out, the screen says "overloaded" instead of lying with a "there’s no town here".

Infrastructure
Decision

Big features are now tested separately, at /nimbus-beta/<name>/, without touching what already works at /nimbus. Each beta is built with its own base and a "BETA" label, with no service worker and not indexed, and it’s uploaded with a script that simulates first and only then touches anything.

It lives outside /nimbus because the production service worker has that scope, and a beta in there would end up cached as if it were the real version.

The honest warning: a beta shares its origin with production. Same Firestore, same session, same localStorage. It’s a lab, but with the door open to the dining room.

Infrastructure
Doubt

Push notifications, for now, are a document and not a feature. I wrote down the design and the types, without a single line of subscription or sending code.

What’s missing isn’t technical, it’s mine. Deciding between FCM on the Blaze plan or my own Web Push, whether there will be anonymous sessions, how to segment, what limits to set and what the automatic ones say. Five decisions.

An app that notifies you whenever it feels like it is an app people uninstall. I’d rather think it through before bothering anyone.

Content
Progress

Now I write what the "new version available" notice says. One block per language, with a title, a message and an expiry date, plus a button to remove it if I change my mind. It lives in Firestore, with no new server. If there’s no message, or it has expired, the notice goes back to the usual loose phrase.

There’s also a history of what I’ve published, with "Use again". An archive of my own notices: the smallest possible version of nostalgia.

There are two rules worth learning the first time: publish the message before deploying, and remember that it is drawn by the version the person already has installed, not the new one. I also fixed the text getting squashed on narrow phones: the buttons now drop to another row.

Interface
Progress

I named the admin panel Olimpo. I picked the name myself: "admin" sounded like an intranet menu. Only I can see it, at /olimpo.

It started as a table of phrases and grew into a full panel, with a live preview in Nimbus, multi-select and a separate section for permissions and messages. The rule that cost me the most, and that I like the most: editing a phrase means retiring the old one and adding a new one. If the old one already had positive reactions, it stays active, and the corrected version comes in as a separate phrase.

Nobody loses their likes because I felt like fixing a comma at midnight.

Interface
Milestone

Before letting anyone edit what Nimbus says, I had to build the foundation: content lives locally with a patch in Firestore, the rules are versioned, and there’s a diagnostics screen that tells apart two things that look alike but aren’t —unpublished rules, and an email that isn’t an admin. One small fix along the way: Google now always shows the account picker, since guessing which one I’d signed in with had become a sport.

With that foundation in place, Nimbus can now be curated from inside the app itself: audit, retire, restore, add and publish phrases, no code editor required. The last fix was to the rules: the administrator had to be me. Now it is. The app not recognizing me as its owner was an exercise in humility I hadn’t asked for.

Infrastructure
Progress

The PWA started to have a personality. The install bar rotates Nimbus phrases and, if you say "Not now", it stays quiet for seven days. For once, someone who respects a no.

The new-version notice also uses Nimbus phrases. The service worker waits for confirmation before updating and checks for changes every hour, so the app doesn’t restart itself in the middle of whatever you’re reading.

Content
Progress

The Daily forecast became a compact list, with rain per day, a temperature range and a comment from Nimbus on every row. On top of that came a new block, "Nimbus · This Week": it detects patterns over the coming days, picks a pose and gives a general read. It’s the closest I’ll get to having a meteorologist friend, without having to buy him a coffee.

The voice also grew up. I added six pop references for daily use and twenty for the weekly summary, in Spanish and English —the grey week quotes Fifty Shades of Grey; if we’re going to suffer Lima’s sky, might as well do it with some irony—. And "it’s raining" or "it’s cold" is no longer enough: now it reacts to intensity, trend and dense fog.

One small fix along the way: the Daily view only shows full days. No more showing half a Tuesday.

Content
Progress

Nimbus no longer speaks from memory. I loaded the curated bank of phrases, tags, conditions and recommendations that came from a few spreadsheets.

Everything it says now is read from Firestore, with a local copy as a backup in case the cloud has a bad day. And if the last phrase is in a different language than the interface, Nimbus asks for a new one. Speaking two languages at once suits a poet, not a weather app.

First, it has to have something to say. Then, where to keep it.

Infrastructure
Decision

What comes next is turning Nimbus into a PWA. It’s not a pivot: the architecture was always designed for it.

There’s already a manifest, a service worker, icons, an "Install Nimbus" button and an offline mode. What’s missing is the boring and important part: deploying the dist/, testing it on a real phone and checking the Apache headers. So far all of this works on my machine, which as a guarantee is worth what it’s worth.

There are also poses not yet connected, the PWA icon still showing the old Nimbus (yellow 3D hoodie) and a phrase engine that still needs ranking, memory and about 500 phrases. The Nimbus tab is still almost empty. Yes, the one with its name on it. I know.

Product
Decision

Decisions that remain from today, so I don’t argue with myself about them a month from now.

Light by default. The purple #7C3AED is just the brand, not a theme. Local first, cloud later. The illustration is independent of the theme. Time of day overrides the sky, and the weather overrides mood poses. Celebration is only for holidays (equinoxes don’t count, sorry equinoxes). Evolution points use tags, not branches.

None of them is spectacular. That’s exactly why they’re worth writing down.

Product
Milestone

Nimbus v2.0 is stable. Fifty commits, from 00:18 to 22:08, on a single branch. One day. I don’t recommend it as a method.

Early morning, from scratch: three tabs (Home, Forecast and Nimbus), the engine that decides when Nimbus has something new to say, the layered hero and the "Nimbus · Now" card. After that, the journal, favorites, today’s forecast with its hourly curve, "Nimbus recommends" and sharing as an image.

Morning, the skin: a Light, System or Dark selector, with a neutral liquid glass in dark mode and no purple. One folder, one branch, and the rule written down so there are never two versions of the same project again.

Midday and afternoon, the foundations: refreshing no longer gives a 404, restructured settings, weather that updates itself every 10 minutes, AA contrast and the PWA with its manifest, service worker and offline mode.

Night, the voice: the 59 poses and conditions that speak according to their range and intensity.

Part of this was done by other Claude instances on the same branch. I set the direction. They made the commits.

Design system
Decision

Nimbus’s illustrations are not random.

There are 59 poses and none of them shows up just because. Each one has a trigger, an expression, a pose and, when needed, an outfit. Sunny: clear sky, daytime, between 5 and 32 °C. Nimbus is thrilled, arms up. Strong heat: feels like 33 °C or more. Lying on the floor, no jacket. Rain: annoyed, resigned, mouth open.

The image is a fragment of the table where all of that lives. Yes, it’s a spreadsheet. Behind every adorable character there’s a spreadsheet with strong opinions. Cuteness is a discipline.

To decide which one to show, nimbusPose.ts follows an order. The weather comes first. If the weather has nothing to say, then thermal crisis, night or insomnia, joy over an improvement, dawn, dusk, a fed-up Monday and, at the end, a "meh" rotation. Special dates override everything else.

And the illustration doesn’t change with the theme. Nimbus is Nimbus, whatever the background.

It’s the same bet as always: personality without generative AI. Rules can have character too.

Interface
Progress

Nimbus changed its skin: liquid glass.

I updated the interface visually. Translucent surfaces that let the sky and the weather show through, instead of cards competing with them.

If the weather is the raw material, the least the interface can do is not cover it up.

Research
Lesson

To know what kind of place the user is in, for now I don’t use any API.

It’s a hand-written table in places.ts. It compares the city name, without accents or capital letters, with the one OpenWeather already provides. It works, but only for the cities I wrote down.

The free API I mentioned before was a fallback idea, not something implemented. Today I checked it with real calls: Open-Meteo Geocoding, free and no key. It returns elevation, population, place type and country. For Cusco: 3312 m and 428,450 inhabitants.

That could classify the cities that aren’t in my table: low population, countryside; high elevation, Andean. It doesn’t detect beaches.

What I learned from the test: it also returns namesakes. There’s another Cusco in San Martín, at 262 m and with no registered population.

A Cusco at 262 meters is a good reason not to let an API decide on its own where Nimbus is.

Product
Exploration

Nimbus has been living on a fairly generic background for a while.

It does the job.

But it could also be in Lima, Tokyo or Gotham City and probably nobody would notice much of a difference.

So another question came up: how much should Nimbus know about the place it is in?

I don’t want to try to represent every city on the planet. That road quickly ends in a folder with 847 backgrounds and someone wondering why we are drawing a square in Moldova at three in the morning.

The idea is to start with something more structural.

First, detect what kind of place it is:

city, coast, highlands, jungle, countryside, beach.

That alone would let the environment go along better with the weather.

And then, on top of that system, some cities could have an identity of their own.

Lima can have a recognizable skyline.

Arequipa can hint at the Misti volcano.

Cusco can use elements from its own landscape and architecture.

Without turning Nimbus into a tourist postcard with a weather widget stuck on top.

The intention is not to represent the place literally.

It’s to make the app know where it is.

Because 12 °C doesn’t feel the same everywhere.

And an app that claims to interpret the weather should understand something more than latitude, longitude and temperature.

For now the order is starting to look pretty clear:

1. Build a system of places and environments. 2. Make memory and humor part of the same engine. 3. Turn the current phrases into more flexible templates.

It doesn’t look like a huge list.

But that’s probably where a good part of what will make Nimbus stop feeling like a weather app with a character, and start feeling simply like Nimbus, lives.

Idea
Insight

Today an idea showed up that will probably end up defining a lot of how Nimbus works on the inside: giving it brains.

Not several Nimbuses or interchangeable personalities. More like small layers of judgment.

One understands the weather.

Another knows something about the context.

Another remembers certain things about the user.

Another decides the tone.

And one will have to stop Nimbus from turning a light drizzle into the climate apocalypse of the century.

The idea comes from a fairly simple problem.

I don’t want to end up with hundreds of rules like: if temperature < 15 → show phrase 37.

That would work technically, but after a while Nimbus would basically be a spreadsheet with eyes.

I want a small engine that can combine signals and decide what makes sense to say at that moment.

Not just: "It’s 14 °C."

But something closer to: "It’s 14 °C, you’re heading out early, you tend to feel cold, and today Nimbus is particularly unimpressed with the weather."

The answer should come out of that.

This would also let memory and humor stop being separate features glued on top of the product, and become parts of the same decision.

The handwritten phrases would still exist. In fact, I want to keep them, because a good part of Nimbus’s voice lives there.

The difference is that they would stop being rigid phrases.

They could become templates with variables, context and small variations.

Less catalog of answers.

More judgment machine.

I still don’t know how many brains Nimbus will end up having.

But at least I know that a single one full of ifs probably won’t be enough.

Implementation
Decision

That also changes how I’m thinking about the technology.

I could plug in an LLM right now and have it generate endless comments. It sounds nice until Firebase, APIs and company start sending invoices with the ambition of a rent payment.

For now I prefer something harder, but also more interesting: testing whether Nimbus can have personality without relying on generative AI.

Rules, context, moods, variables and phrases written with intent.

Later there will surely be a model behind it. Probably a small, cheap one, because I don’t need Nimbus to discover a new branch of physics every time it’s 18 degrees.

But I want the order to be this: first build Nimbus, then give it more capacity to speak.

Not build an AI first and then wonder who it’s supposed to be.

Product
Decision

Today I finished closing an idea that had been circling the project for a while: Nimbus shouldn’t be an app you open just to check whether it will rain tomorrow.

Plenty of apps already do that. And, to be honest, several do it quite well.

What interests me is something else: someone opening Nimbus thinking "let’s see what it says today".

That small change moves the whole product.

Weather is still useful, obviously. Nimbus has to say whether it’s cold, whether it will rain, or whether leaving without sunscreen is a questionable decision. But that data is the raw material. The reason to come back should be Nimbus interpreting it.

Process
Decision

To get to v2.0 I split the work into phases: first the structure and the logic, then what you actually see.

I chained the first ones together in a single night. Navigation got sorted into three tabs —Home, Forecast and Nimbus—, with the Journal tucked under Forecast and Settings behind the gear icon. Then came the brain, with no interface yet: the logic for when Nimbus has something new to say, plus a log of its phrases in Firestore. Only at the end did something show up that you could actually see: a hero built in layers —sky, weather, scenery and Nimbus— with the "Nimbus · Now" card.

It’s the first time v2 starts to look like what I had in my head.

Implementation
Decision

With that balance in place, I’m rebuilding the architecture and the interface from scratch for version 2.0.

v1 was there to validate the idea. v2 isn’t built on what was left of it, but on what I learned by breaking it.

Interface
Lesson

Interface v1 was simple on purpose: I wanted to see it working before deciding anything else. Then came heavier iterations, and that’s where the risk showed up: ending up as just another weather app.

The interface went through a simplification process more than three times. Each round removed something that seemed important and wasn’t.

In the end I found a balanced point. It isn’t the most complete version; it’s the one that lets me stop iterating.

Interface
Progress

Back to Nimbus, starting with the character. I restructured it and tested simpler versions, with future animation in mind.

A character that looks good today but can’t move tomorrow is an illustration, not a mascot.

Infrastructure
Milestone

First release on a public URL: Nimbus v1.0 is now available for anyone who wants to try it.

Publishing it didn’t mean it was finished; it just meant my mistakes now had an audience.

Learning
Lesson

The session was lost on page reload. The problem was not Firebase. It was the order in which the auth listener was updating the initial state.

Implementation
Completed

Firebase Auth. Google login. Session persistence. The goal was not access control — it was preserving preferences and personality across devices.

Product
Milestone

First functional MVP deployed. Nimbus can now fetch the weather, interpret the context, and generate personalized responses.

Implementation
Progress

Initial integration with OpenWeather. Dynamic message generation based on temperature, weather condition, and time of day.

Interface
Exploration

First visual explorations for the mascot. Discarded overly cartoonish approaches. Looking for something that conveys character without feeling childish.

Product
Decision

Defined the first personality modes for interpreting the same weather. Geek. Philosophical. Night owl. Gamer. Team Cold. Team Heat. Same temperature. Different narratives.

Idea
Hypothesis

What if weather had personality? The initial hypothesis emerged from noticing that weather apps seem designed for meteorological stations, not for people.

04

Current status

In progress
Ver demo ↗