Contents

Building a daily storytelling puzzle game

Building a daily privacy-first creative storytelling puzzle game

When I set out to create Stormoji, I wanted to combine the daily engagement of Wordle with the creative freedom of storytelling. The result is a single-page web application where players see four random emojis each day and weave them into imaginative narratives. What started as a simple idea evolved into a technical exploration of deterministic algorithms, privacy-first architecture, and the challenges of creating consistent experiences without a backend.

Stormoji main screen
Main Stormoji screen

The concept: daily creativity with shared challenges

Like Wordle, everyone sees the same emojis each day. But unlike Wordle’s single correct answer, every story is unique. The app presents four emojis selected from eight categories: smileys, people, animals, food, activities, objects, symbols, and travel. It challenges players to incorporate them all into a coherent narrative.

The privacy-first approach was fundamental from the start. No accounts, no servers, no data collection. Everything happens locally in the browser, with stories automatically saved to localStorage for up to six months. This creates an intimate creative space where users can express themselves without worries about their stories being stored or analyzed.

The core technical challenge: deterministic randomness

The biggest technical hurdle was ensuring that every user sees the same four emojis each day, regardless of when they visit or what device they use. With no backend to coordinate this, the solution had to be entirely client-side.

I implemented a deterministic random selection algorithm using date-based seeding. The process works like this:

  1. Date-based seed generation: Convert today’s date to a YYYY-MM-DD format string, which becomes the seed
  2. Seeded random function: Use a sine-based pseudo-random number generator that produces identical results for the same seed
  3. Category selection: Randomly select four different emoji categories using the seeded random function
  4. Emoji selection: Pick one emoji from each selected category
  5. Deterministic shuffle: Use a Fisher-Yates shuffle with the same seed to randomize the final order

This ensures that on any given day, all users receive identical emoji combinations, creating that shared daily experience that gives these games their social nature.

Stormoji history
Stormoji history

Building the CSV export feature

As users started accumulating stories, they wanted a way to preserve their stories in case they lost their phones, changed computers, or switched browsers. This led to implementing a CSV export feature, which proved slightly more complex than initially expected.

The main challenges were:

Proper CSV escaping: Stories can contain commas, quotes, and newlines—all characters that break CSV formatting. I created an escape function that wraps fields containing special characters in double quotes and escapes internal quotes by doubling them.

Browser compatibility: The export uses the Blob API to generate the file and a temporary anchor element to trigger the download. This works in all modern browsers but requires careful cleanup to prevent memory leaks.

User experience: The export needed to handle edge cases gracefully. If a user has no stories, they see a notification instead of triggering an empty download. Success and error states are clearly communicated through toast notifications.

I also redesigned the header menu, replacing the settings gear icon with a hamburger menu that provides access to both the About dialog and the new Export History option. The dropdown includes click-outside detection and responsive positioning for mobile devices.

Stormoji hamburger menu
Stormoji hamburger menu

Lessons learned

Building Stormoji reinforced several valuable lessons about modern web development:

Deterministic algorithms are powerful: Using date-based seeding solved the shared daily experience problem without requiring any server-side coordination. The same approach could be applied to other daily challenge applications. In fact, I later reused this basic algorithm for another project, SlightlyMoreAwesome.

Privacy-first doesn’t mean feature-poor: Despite being entirely client-side, the app includes story persistence, export functionality, and a rich user experience.

CSV is deceptively complex: What seems like a simple format has many edge cases. Proper escaping of special characters is crucial for generating files that work reliably in spreadsheet applications.

Vanilla JavaScript is still viable: The entire application runs without frameworks, build tools, or dependencies. This results in instant loading, zero overhead, and maximum compatibility. Sometimes the simplest solution is the best one.

Throughout development, I tried to maintain a clean architecture that keeps the code maintainable while delivering all the features that were planned.

The architecture: simplicity by design

The application follows a clean separation of concerns:

Data layer: localStorage with JSON serialization, handling story storage and automatic cleanup of entries older than six months

Business logic: Deterministic emoji selection, story management, and export functionality

Presentation layer: Responsive CSS with mobile-first design, semantic HTML, and accessible interactions

Event handling: Modular JavaScript with proper cleanup to prevent memory leaks

This architecture makes the code maintainable and easy to understand, while still providing features users expect from a modern web application.

Looking forward

Stormoji demonstrates that sophisticated web applications don’t always need complex infrastructures. Yet every implementation detail was an opportunity to learn or reinforce some detail of web development. Still, there remain several avenues for future improvement and exploration:

  • History import: Allow users to import previously exported CSV files to restore their story history across devices
  • Opt-in access to a read-only backend: For users who want to see an AI generated story based on the day’s emojis without storing any personal data. It could be annotated with information on how the story references each emoji. Think of it as a kind of “hint” system. The output could be cached an/d/or pre-coumputed.
  • Dark mdoe: Because all apps are better with dark mode… right?

If you’re interested in trying it out, visit stormoji.com to see today’s emoji challenge. Or dive into the source code to see how all these pieces come together in a single, dependency-free deliverable.