Occasionally on a long haul project, you need to remember you’re good at programming rapidly prototype another project.
My wife, a published author, played Dream Daddy and had a spark of creativity. She wanted to make a dating game about wizards dating other wizards in a magical town.
And I thought, wow, that sounds way easier to program than Skymagi.
In less than a few hours, I cludged together TypeScript, React ⚛️, vite, and Electron. Using Pixi.js for rendering on a webgl canvas and React to build a UI on top.
Modern web development tools are eons ahead of Game UI libraries. Unfortunately, the DOM overhead is a huge performance price, but that doesn’t matter for a wizard dating game!
So, it’s basically just dialogue, right?
Primarily, a dating game is about picking dialogue options. WxW also features D&D-style dice rolls and a map to navigate. I could’ve used Ren’py, but my wife knows TypeScript, and browser compatibility is a nice-to-have.
So, a dating game has…
- Dialogue choices
- Dialogue branches
- Scenes with different backgrounds, characters
- Some animations on specific cues
- Variables or simple functions like dice rolls
- Markdown support
While researching methods to write markdown with special markup for dialogue, I stumbled upon this gem, Ink 🐙
Ink is a domain specific language for narrative games. It has everything on my list and more:
- Choices, branches
- Full control flow with knots and diverts
- Variables, functions, listeners
- Includes, randomization
- Choice elimination
- VScode plugin
- Vite plugin for autocompiling/bundling
.ink
files
The ink runtime is usable in javascript (inkjs) and other languages (like… Java!?)
It’s everything I dreamed of.
Ink integration
Within just a few hours, I was able to parse an ink script that sets a scene’s background, has labels for individual characters, and has choices.
// story.ink
#background library
ravenna: Good morning.
dragon: I said hey, what's going on???
ravenna: Let's go to the classroom
#background classroom
Great hanging out with you. // default narrator
+ [Say hi] Hi there!
+ [Say bye] Bye now!
-> END
Ink’s tags worked perfectly for basic directives. Most of the code just called story.ContinueStory()
and parsed tags and displayed outputs (e.g. reading labels).
This demo shows off a few other tags. I created a #show
tag to add characters to a scene, set their positions.
#background library
#show ravenna left faceRight
#show dragon right
r: Good morning.
Similarly, there’s a set of variables created for skills that unlock special dialogue options. Ink made this incredibly simple.
d: Do you know how to brew a healing potion?
+ {knows_alchemy} [Yes, I've studied alchemy before.]
+ [No, I don't. Can you teach me?]
In TypeScript, I simply had to set parameters on the story when loading.
story = new Story(inkJson);
story.variablesState['knows_alchemy'] = true;
Character Creator
Of course, the best part of playing a dating game is picking your protagonist.
Using React to build out a few forms and menu structure, communicating to the game (and back) with a simple EventBus, and using Ink’s variables for main character artwork, a basic character creator was ready!
And with that, my wife can start writing (and updating features as-needed), and I can return to Skymagi development.
(And Wizard x Wizard gave me a really good idea…)