Inspiration

We kept picturing someone like an aspiring game developer who wants to make a simple 2D RPG and gets stuck as soon as an NPC needs to talk back. Branching dialogue is the heart of a good RPG, but writing it as nested if-statements or hand-written JSON is miserable and easy to break. We wanted dialogue design to feel like sketching a flowchart, not debugging.

What it does

Questline is a visual studio for designing branching NPC conversations.

Node canvas: each node is a line of dialogue. Drag from a player choice onto another node to connect them. The canvas zooms, pans and fits to your nodes, and right-click menus let you duplicate, rename or add linked nodes. Preview Player: play through the conversation instantly beside the editor, with typewriter text, so you can test every branch as you write. AI co-writer: describe an NPC and Gemini drafts a whole branching conversation. You can also right-click any node to "Expand with AI" and get new player replies and answers. Export: download the tree as JSON or copy it as a JavaScript object, ready to drop into a game. Questline Village: a small top-down game where you walk around and talk to villagers who speak your exported dialogue, so you can playtest it in an actual game. Named saves, light and dark themes, accent colours, and a phone-friendly preview mode.

How we built it

Questline is plain HTML, CSS and JavaScript, with no framework and no build step, hosted on GitHub Pages. The editor draws its connections as SVG over a scrollable, zoomable canvas, and everything is saved in the browser's local storage. For AI, we wrote one shared module for prompts and output formats. It runs in the browser for people who bring their own Gemini key, and is bundled into a Cloudflare Worker that keeps our key secret for everyone else. Questline Village is a single self-contained HTML file that draws the village and characters in code on a canvas, with no image files.

Challenges we ran into

AI output that doesn't line up. The model sometimes returned choices pointing at nodes that didn't exist. We added a structured output format, then validate everything that comes back and lay it out automatically before it reaches the canvas. Keeping the API key safe on a static site. We solved it by routing requests through a small Cloudflare Worker that only accepts calls from our site. Editor feel. Getting dragging, connecting, edge-scrolling and zooming to work together took many rounds. For example, arrows broke when the editor was drawn while hidden, and renaming a node had to update every link pointing to it. Getting dialogue into the game. The game only works if a tree made in the studio loads cleanly, so it accepts both the exported JSON and the copy-as-JS format. It also flags broken links instead of crashing.

Accomplishments that we're proud of

You can go from a one-sentence NPC idea to a playable branching conversation in under a minute. The full loop works end to end: design, preview, export, and talk to the NPC in a real game. It's lightweight: a static site with no build, free to host, and the AI features cost nothing on Gemini's free tier. It looks and feels like a creative tool, not a form, from the animated title screen to themes and typewriter dialogue.

What we learned

How to make AI output reliable: strict output formats plus validating everything the model returns. How to keep secrets out of a static site with a serverless proxy. How much detail goes into direct-manipulation UI: dragging, zoom, scrolling, hit areas and focus states. Testing in a real game showed us problems the preview didn't, like dead-end choices and links to missing nodes.

What's next for Questline

Game logic in dialogue: conditions, variables and flags, so NPCs remember choices, check quest progress or give items. Exporters for popular engines such as Godot, Unity, GameMaker and RPG Maker. Characters: portraits, voice and mood per speaker, and multiple NPCs in one project. Collaboration: sharing links and real-time co-editing. Playtest stats: see which branches players actually take, and catch unreachable nodes automatically.

Built With

Share this project:

Updates

Submission history