What I Built
When someone dies, the memories that matter most are rarely the grand ones. They are the yellow cardigan, the Sunday porch, the way someone laughed in a thunderstorm. I wanted to build a small, quiet place to put those down.
Virtual Ofrenda & Story Alchemist is a private web app. You type or speak a few memories of someone you miss. A small open-weight model, running on your own device, turns them into a short tribute story and a poem, and builds a candlelit digital ofrenda (altar) from the things you mentioned: candles, marigolds, a favourite book, a hot mug of cider.
The theme asked for something that honors the past in the spirit of Día de los Muertos. The ofrenda tradition is much bigger than any app, so I borrowed only its simplest idea: that people stay with us while we tell their stories, and that we make small, physical places to hold them.
It has three parts:
- Voice-to-Memory. Record a memory in the browser and it is transcribed locally with whisper.cpp. You can edit the text, or just type.
- Story Alchemist. One tribute story and one poem, written from only what you said.
- Altar Decorator. The model picks the objects in your memory, and each one lands on a three-tier altar and fades in, one by one.
The page says "Runs on your device" because it does. There are no accounts, no cloud APIs and no tracking. I tested it in airplane mode.
Demo
The video shows the typing path from start to finish: a memory about a fictional woman named Eleanor, then the altar, the story and the poem. I recorded it on the same phone the app runs on, and the waiting in the video is shortened, because generating a tribute takes a few minutes on this hardware.
I left voice input out of the recording. It works, but on my phone Whisper needed about two minutes for an 11-second clip, so typing is the dependable path there.
Code
Virtual Ofrenda & Story Alchemist
A private web app for remembering someone you have lost. You speak or type a few memories of them, and a small open-weight AI running on your own device turns those memories into a tribute story and a short poem, then decorates a candlelit digital ofrenda (altar) with the things you mentioned: candles, marigolds, a favourite book, a bright yellow raincoat.
Nothing leaves the device. There are no cloud APIs, no accounts and no tracking. The whole project was built on a low-end device with 2 GB of RAM.
Built for the DEV Hacktoberfest 2026, Week 4 challenge ("Ghost in the Machine").
- Demo video: https://www.youtube.com/watch?v=wHRRkFlyoqc
What it does
-
Voice-to-Memory. Record a memory in the browser. It is transcribed locally with whisper.cpp (
tiny.en) and lands in a text box where you can edit it. Typing works just as well and is the main…
The repository is MIT licensed and has setup steps, the model list and the commands to start each server. The model files are not included, so the README tells you how to download them.
How I Built It
The constraint. I built this on an Android phone with 2 GB of RAM and a 32-bit ARM processor, using Termux. My first plan was a 7 to 8 billion parameter model, and then a tiny Gemma through Ollama. Ollama does not run on 32-bit ARM, and a 7B model would not have fit in that memory anyway.
The open pieces. So I went smaller and more direct:
-
Gemma 3 270M (instruction-tuned, Q8_0, about 300 MB) writes the story, the poem and the list of altar items. It runs through llama.cpp's
llama-server, built from source on the phone with-DGGML_NATIVE=OFF -DGGML_LLAMAFILE=OFF. It generates about 6.7 tokens per second. -
Whisper tiny.en through whisper.cpp's
whisper-serverturns speech into text. - Laravel with Blade, Tailwind and SQLite runs the app. A queued job calls the model, and the browser polls for the result, so the story, the poem and the altar items appear as they arrive.
Take the model away and the app has no story, no poem and no altar choices to show. Everything else is plumbing around it.
Making a tiny model behave. A 270M model will happily make things up, and in a tribute that matters. So the app does not trust it blindly:
- Every altar item the model suggests is checked against your own text. Candles and marigolds are always added.
- The poem is built line by line from your own sentences. A model rewrite is used only if it passes the same check.
- Near-duplicate items are merged, so "green shards" and "frosted green shards" become one.
- If a server is offline, you get a clear message and a retry button, not a crash.
What still goes wrong. I tested it on three memories of different lengths (about 38, 85 and 130 words). These are the honest results:
- The stories added no invented facts, but mostly because they repeat your own words. The small model stays very close to its input. On the Eleanor memory, the story was almost word for word what I had typed.
- It can get who did what wrong. On a short memory about a man named Marcus, the story began "I always carried a pocketful of sea glass" instead of "Marcus always carried…". In an earlier test it wrote that someone was "always ready with a smile and a gentle touch", which no one had said.
- The poem can add imagery. It invents no people or events, but it can add phrases like "secrets held tight" that were never in the memory.
- Altar items are sometimes ideas, not objects. The model picked "quiet invitation" as an item for Eleanor's altar, and it shows up with the default dove icon. It is in the screenshot above.
Here is Eleanor's poem, as the model wrote it:
Yellow cardigan scent
Lavender whispers on porch
Bird wings, watercolor splashes
Ending's a quiet invitation
Remembered with love.
It is not Rilke. But every image in it came from the person who typed the memory, and I would rather ship that than something more beautiful that was made up.
I built it between Oct 29 and the morning of Nov 1 (IST), before the contest deadline, and every commit was made in that window.
Why Does Open Innovation Matter?
A memory of someone you have lost is some of the most private writing a person will ever do. If this app had to call a hosted model, every one of those memories would leave the device and sit on someone else's server. I did not want to build that, and I would not want to use it.
Open weights made a different design possible. Gemma is small enough to run locally, and it is open enough that I could serve it myself, with no key, no account and no network. When the internet is off, it still works.
Open tools did the rest of the work. llama.cpp and whisper.cpp run on hardware that the friendlier tools do not support. My phone's 32-bit chip could not run Ollama, but it could run llama.cpp built from source. That is the difference between "this idea needs a data center" and "this idea fits in a pocket".
Openness also makes the project easy to improve. If you have a laptop, you can serve a larger open model with llama.cpp and point the same app at it by changing the model name and URL in .env. The app itself does not need to change. Nobody has to ask permission.
The Spirit of It
The constraint I started with turned out to be the idea. A small model cannot be trusted to be clever, so I made the app's promise modest: using only what you tell us. It does not try to write a beautiful eulogy for someone it never met. It gives your own words back, arranged with care, and puts a few candles around them.
There is plenty I would still like to do: a page that lists past tributes (today you return to one by its link), prompt starters for people who do not know where to begin, and a faster speech model. But the core is there, and it fits on a phone with 2 GB of RAM.
If you try it and it gets something wrong, I would like to hear about it.
Prize Categories
Gemma. The project is built around Google's open-weight Gemma 3 270M model, which does the writing and choosing in every tribute: the story, the poem and the altar items. It runs locally through llama.cpp, with no hosted API anywhere in the app.



Top comments (0)