What Inspired Me

The idea for InCharacter came from my love of interactive fiction and collaborative storytelling tools—places where readers don’t just consume a story, but step inside it. I was fascinated by narrative engines like Twine and other sandbox-style editors, and I kept wondering:

What if writing, role-playing, and play-testing all happened in the same space?

I wanted something that felt less like a static editor and more like a living stage: a place where scenes could unfold in real time, characters could speak back, and creators could instantly test alternate paths. That vision pushed me toward building a hybrid experience—part creative writing tool, part chat interface, part live performance platform—with visual flourishes and animations to make stories feel immediate and alive.


How I Built the Project

I built InCharacter as a React + Vite web application so I could iterate quickly and experiment freely with UI ideas.

At the core are the main entry points (App.tsx, index.tsx) and a growing ecosystem of components inside components/. I split the interface into focused surfaces—story boards, journey carousels, play platforms, and editor panels—so each part of the experience could evolve independently while still feeling cohesive.

Behind the scenes, I organized integrations into a dedicated services/ layer. That’s where things like persistence, storage helpers, and role-play or generation services live. Keeping those concerns isolated helped the UI stay expressive while the backend logic remained swappable and testable.

For development speed, I leaned heavily on Vite and TypeScript, tuning the configuration so I could move fast, refresh often, and keep the feedback loop tight while experimenting with layouts, flows, and narrative mechanics.


What I Learned

Building the project taught me a lot about turning a creative idea into a real, evolving application.

I learned how to structure a medium-sized React codebase around small, purposeful components rather than monoliths—and how to let orchestration logic live separately from presentation.

The editor, in particular, forced me to think deeply about state management. Drafts, saved versions, undo and redo stacks, and synchronization between panels all had to coexist. Designing hooks like useNovelState made me appreciate how subtle interactive tools can be, and how easily small state bugs can ripple across an experience.

I also became much more comfortable wrapping external systems—APIs, storage, and generation services—behind clean interfaces. That separation made it possible to experiment with new role-play engines or backends without rewriting the front end every time.

Most of all, I learned how much polish and iteration it takes to make a creative tool feel good, not just function correctly.


Challenges I Faced

The hardest part was balancing responsiveness with powerful but slow external services.

LLM-driven features introduced latency and rate limits, which meant saves could stall, drafts could drift from persisted state, and conflicts could appear if users kept editing while results were still streaming in. Keeping the editor fluid under those conditions required careful orchestration, defensive state updates, and strategies for merging delayed responses back into a fast-moving UI.

There was also a constant tension between experimentation and stability. Because the project was so exploratory, the architecture had to stay flexible—but not so loose that it collapsed under new features.


Looking Back

InCharacter became more than a technical exercise. It was a way to explore how stories, interfaces, and AI systems can intertwine—and how tools can empower people not just to write narratives, but to inhabit them.

What started as curiosity about interactive fiction turned into a deep dive into product design, state orchestration, and creative tooling—and it left me excited to keep pushing the idea further.

Built With

Share this project:

Updates