Inspiration
We started Cal Hacks with a question: What if creating an adventure could be as simple as describing a world you want to explore?
We grew up getting lost in fictional worlds, imagining different endings, and wondering what would happen if we could make our own choices inside them. We wanted to give players that same freedom without requiring them to know how to build a game.
Generative AI made that idea feel possible. But creating an engaging adventure takes more than generating paragraphs. Players need things to investigate, characters to connect with, and actions that leave consequences behind.
That became Unwritten: a platform for turning ideas into interactive stories and playable worlds.
The next chapter is yours.
What it does
Unwritten starts with a text box. Players describe their premise, protagonist, and world details, then choose or write their own story mood and art direction.
From there, they can explore two experiences:
Illustrated adventures
Players move through illustrated scenes, investigate objects, uncover clues, and choose what happens next.
Google’s Gemini API generates custom scenes using the player’s prompt, previous decisions, discoveries, and established story memory. Each adventure unfolds one chapter at a time, so later events can respond to earlier choices.
Playable 3D worlds
Players can also explore a 3D environment with movement, jumping, camera controls, and physical objectives.
For custom worlds, Gemini generates narrative content and structured world blueprints that our game engine translates into environments using supported assets and mechanics.
Both featured examples are prepared showcases, clearly distinguished from live custom generation.
How we built it
We built Unwritten as a web application using HTML, CSS, JavaScript, and Node.js, with Three.js and WebGL powering the 3D environments.
Gemini as the storytelling engine
Gemini turns the user’s setup into structured narrative data, including scenes, characters, choices, clues, and memory summaries. For custom 3D adventures, it also supplies world blueprints and narrative context for playable objectives.
We generate one scene at a time instead of creating every possible branch upfront. This reduces unnecessary API calls and allows the story to incorporate what the player actually did.
Persistent state and gameplay rules
We maintain structured story state containing previous decisions, discovered clues, character information, and important events. That context accompanies subsequent generation requests.
Object inspection happens locally using scene data already generated. Movement and physical interactions also run in the game engine, so walking, jumping, or investigating a clue does not require another model call.
The forest showcase uses authored simulation rules for fire, health, wetness, evacuation, tree falls, and changing water levels. This gives environmental interactions predictable consequences while the story journal records what happens.
Illustrations and presentation
Cloudflare Workers AI provides optional illustrations for custom stories. The featured train adventure uses bundled, AI-generated artwork prepared ahead of time, with carefully placed interaction targets, detailed characters, and animated scenery outside the train windows.
We also added browser save and resume, signed journey state, output validation, and retryable errors to help protect progress when external services fail.
Challenges we ran into
Our biggest challenge was connecting creative generation to consistent gameplay.
A model can describe an interesting action, but a playable experience needs clear rules about what that action changes. We had to decide which responsibilities belonged to Gemini and which belonged to the game engine.
Visual coherence was another challenge. Clickable objects needed to match their positions in the artwork, characters needed to remain recognizable, and scene transitions needed to feel connected.
In 3D, we learned that movement alone does not make an environment engaging. The world became more interesting when its systems affected one another: fire could cause a tree fall, a tree fall could block water, and flooding could extinguish nearby trees.
API latency, quotas, and image-generation reliability also pushed us to separate essential story progression from optional visual generation and preserve progress when requests failed.
Accomplishments that we're proud of
We’re proud of bringing two forms of interactive storytelling into one project.
Our illustrated experience combines detailed scenes, meaningful object exploration, persistent choices, and multiple endings. Our 3D showcase lets players create consequences through their movement and interactions with the environment.
We also built a working Gemini integration for custom adventures and 57 passing automated tests covering story progression, saved journeys, interactions, environmental mechanics, and API failures.
Most of all, we’re proud that our team of four turned a small train-story prototype into something people can read, explore, and influence.
What we learned
We learned that a convincing interactive world depends on continuity.
Players notice whether a character remembers a promise, whether a clue matters later, and whether a damaged environment stays damaged. Those details make their actions feel meaningful.
We also learned to build incrementally. Starting with a small playable story gave us a foundation for testing narrative memory, adding generation, and eventually developing more ambitious 3D interactions.
Working within a weekend taught us to prioritize the interactions that made the biggest difference to the player’s experience.
What's next for Unwritten
We want to expand the variety of environments and mechanics available to custom adventures, improve visual consistency between generated scenes, and build characters with richer long-term memory.
We also want to explore free-text player actions, longer campaigns, and eventually shared adventures where multiple players influence the same world.
Our goal is to make creating an interactive adventure accessible to anyone with an idea.
Unwritten — The next chapter is yours.
Log in or sign up for Devpost to join the conversation.