How Twine 2 bubble maps are created, could be changed

In Twine 2 /, the story selection view shows a small colored bubble map for each story.

<div class="story-item grow-in-out-transition">
	<button class="preview" style="background: rgb(235, 250, 250);">	
	<svg xmlns="" version="1.1" xmlns:xlink="" viewBox="131.82901554404145 71.84715025906736 1032.8972366148532 737.8238341968912">

Those svgs are filled with little green, red, purple, or teal circles, like this:

<circle cx="857.1666666666667" cy="336.5" r="153.8860103626943" fill="hsla(2340, 90%, 60%, 0.5)" stroke="hsl(2340, 90%, 45%)" stroke-width="4px"></circle>

How is the color for each story chosen, and (where) is this saved by Twine? What code creates this svg?

I am interested in changing the color and styling of the maps – I’m working with importing and exporting large collections of works (40+) and want to use techniques such as more color options to help make them visually distinct.

1 Like

The color of the bubbles is decided based on the first letter of the story name, which will determine which of the four colors get used for the bubbles. (A… = green, B… = cyan, C… = purple, D… = red, E… = green, F… = cyan, etc…)

The color isn’t “saved by Twine”, it simply uses the first letter every time.

You can see the code which generates those previews in the Twine source here and in the “item-preview” subdirectory below that (the former code selects the hue, the latter generates the preview using that hue).

Hope that helps! :slight_smile:


HiEv’s explanation is mostly accurate, but Twine hashes the entire story name to try to determine a color— see

1 Like

Um…that code clearly only looks at the first character of the story name.

1 Like

Argh. That would be a long-standing bug. The intention was to sum the Unicode values of all characters in the name modulo 40, then multiply that value by 90 to spread it, in theory, across possible hue values in HSV notation. Which is obviously written incorrectly now that you point it out.

1 Like

Well, I guess 100% accurate is “mostly accurate”. :stuck_out_tongue: :grin:


I wish there was an egg-on-face emoji.


Ah this explains why when I loaded 40 student papers sorted by name there were so many long runs of the same color – way more than could be explained by randomness.

I think maybe (JavaScript is not my strength, and I’m no sure what target output you wanted, but assuming 0-359:

hue() {
	// A hue based on the story's name.
	return ('').reduce(
		(sum,letter)=> sum + letter.charCodeAt(0),0) % 360



If you actually want it 0-3599, (40*90) you could %3600 instead of %360.

There are also some good generic string-to-integer hashes here that you could %.


Cool, I added a task for the 2.4 project to fix this.

1 Like

Neat, thanks. I haven’t used project tasks on github, so I’m not quite sure how they work – only familiar with issues and PRs. Let me know if you want me to contribute anything.

I’m glad you’ve said that, there was me thinking if it was red colored bubbles / boxes there was some major spanner in the works going on for that story! LOL