0 votes
by (180 points)
I have just recently started using twine and I made a lot of datamaps because I want a variety of items. Unfortunately, my passages are freaking out and the text is flying everywhere and my links don't work. I tried spreading the datamaps to multiple passages and it seemed to help a little for the first ones, but some links still don't work.

Any suggestions? Thank you!

1 Answer

0 votes
by (63.1k points)
selected by
Best answer

How many are we talking? 30? 200? 1000?

You should probably be using a startup-tagged passage to set up your data structures, not just throwing them in any old passage. 

Data maps are one of, if not the most expensive (in terms of both size and performance) of the data types supported by Harlowe. Using many of them (~50) could conceivably cause minor, but noticeable, slowdown. Using a whole lot will likely cause significant slowdown in the passage containing the code, but shouldn't otherwise impact the story. 

However, it shouldn't affect your text or links, so it seems far more likely that something else is going wrong. 

Please post your code, and tell us which version (1.2.4 or 2.0.1) of Harlowe you're using, as specific advice will vary based on the version. 

by (159k points)
edited by

Another way a Data-map can use system resources is due to how the whole of the data-map is cloned every time the value of one of it's properties is updated, and the cloning process may not be inexpensive due to the complexity of the data being stored within it.

(set: $var to (datamap: "first", "a", "second", "b")) <- original.

(set: $var's second to "c") <- data-map is cloned, then the property's value is changed.


by (180 points)
edited by

Okay, so I'll just put some of the datamaps in here. I can’t put them all though, since the character limit is 8000... Is it possible I just have something done twice or a typo?

I'll be honest.. I really just copied this setup for datamaps from VegetarianZombie's tutorial on YouTube. So far everything has worked perfectly... until I added ten times what I had before...twine 2, btw.

(set: $huntingKnife to (datamap: "name", "hunting knife", "description", "Hunting knives can be used as weapons or a gathering tool.", "pickupText", "You now have a hunting knife.", "isCarried", false))
(set: $waterSkin to (datamap: "name", "waterskin", "description", "Waterskins hold water so you stay hydrated.", "pickupText", "You now have a waterskin.", "isCarried", false))
(set: $roll to (datamap: "name","roll","description","Rolls are not very healthy, but they'll help you not starve.","pickupText","You now have a roll.","isCarried",false))
(set: $jarredVeggies to (datamap: "name", "jarred veggies", "description", "Jarred veggies are very healthy, but they don't taste very good.", "pickupText", "You now have jarred veggies.", "isCarried", false))
(set: $beefJerky to (datamap: "name","beef jerky","description","A very chewy and badly spiced piece of dried meat.","pickupText","You now have beef jerky.","isCarried",false))
(set: $axe to (datamap: "name","axe","description","Axes help you cut down trees and can be used in self-defense.","pickupText","You now have an axe.","isCarried",false))
(set: $bag to (datamap: "name","bag","description","You can carry a variety of hard-to-hold items with a bag.","pickupText","You now have a bag.","isCarried",false))
(set: $warmCloak to (datamap: "name","warm cloak","description","Warm cloaks keep you comfortable is cold weather.","pickupText","You now have a warm cloak.","isCarried",false))
(set: $leatherGloves to (datamap: "name","leatherGloves","description","Leather gloves may extend your usage time of work that is hard on your hands.","pickupText","You now have leather gloves.","isCarried",false))

<!-- The above are tutorial stage items, under are afterwards-->
<!-- WILD plants and *SUN GEM* -->

(set: $wildMushroom to (datamap: "name","wild mushroom","description","A fungus found in the forest. Probably poisonous.","pickupText","You now have a wild mushroom.","isCarried",false))
(set: $wildBerries to (datamap: "name","wild berries","description","An abundantly grown, commonly eaten, forest berry.","pickupText","You now have wild berries.","isCarried",false))
(set: $wildRoots to (datamap: "name","wild roots","description","Small roots with leaves that stick under the ground. Commonly eaten in salads.","pickupText","You now have wild roots.","isCarried",false))
(set: $sunGem to (datamap: "name","sun gem","description","A bright yellow gem used in magic and ceremonies.","pickupText","You now have a sun gem.","isCarried",false))
(set: $wildNuts to (datamap: "name","wild nuts","description","Wild forest nuts fallen from a tree. Best check for bugs and worms before consuming.","pickupText","You now have wild nuts.","isCarried",false))
(set: $wildBeans to (datamap: "name","wild beans","description","Small red beans, pulled from a pod. Edible only after cooking.","pickupText","You now have beans.","isCarried",false))
(set: $wildRice to (datamap: "name","wild rice","description","Rice gathered from tall grasses in still waters.","pickupText","You now have a sun gem.","isCarried",false))
(set: $edibleWeeds to (datamap: "name","edible weeds","description","A common weed found and consumed universally across the island.","pickupText","You now have edible weeds.","isCarried",false))
(set: $wildLeafyGreens to (datamap: "name","wild leafy greens","description","Leafy greens found in forests and meadows.","You now have leafy greens.","isCarried",false))
(set: $wildPeppers to (datamap: "name","wild peppers","description","A pepper of unknown spiciness found from a small plant.","pickupText","You now have a pepper.","isCarried",false))
(set: $wildPeas to (datamap: "name","wild peas","description","A pod of little green peas, picked from a vine.","pickupText","You now have peas.","isCarried",false))
(set: $wildCabbage to (datamap: "name","wild cabbage","description","A large bud bedded in a large-leafed plant. Commonly eaten in salads.","pickupText","You now have a cabbage.","isCarried",false))
(set: $wildOnion to (datamap: "name","wild onion","description","A strongly flavored bulb grass.","pickupText","You now have an onion.","isCarried",false))
(set: $wildSquash to (datamap: "name","wild squash","description","A common vegetable pulled from vines.","pickupText","You now have a squash.","isCarried",false))
(set: $wildPotato to (datamap: "name","wild potato","description","A common root pulled from under a stalk.","pickupText","You now have a potato.","isCarried",false))

<!-- These are Wood types-->

(set: $maple to (datamap: "name","maple","description","A log from a maple tree","pickupText","You now have a maple log","isCarried",false))
(set: $oak to (datamap: "name","oak","description","A log from an oak tree.","pickupText","You now have an oak log","isCarried",false))
(set: $cedar to (datamap: "name","cedar","description","A log from a cedar tree","pickupText","You now have a cedar log","isCarried",false))
(set: $pine to (datamap: "name","pine","description","A log from a pine tree","pickupText","You now have a pine log","isCarried",false))
(set: $birch to (datamap: "name","birch","description","A log from a birch tree","pickupText","You now have a birch log","isCarried",false))
(set: $cherry to (datamap: "name","cherry","description","A log from a cherry tree","pickupText","You now have a cherry log","isCarried",false))
(set: $mahogany to (datamap: "name","mahogany","description","A log from a mahogany tree","pickuoText","You now have a mahogany log","isCarried",false))
(set: $ash to (datamap: "name","ash","description","A log from an ash tree","pickupText","You now have an ash log","isCarried",false))
(set: $aspen to (datamap: "name","aspen","description","A log from an aspen tree","pickupText","You now have an aspen log","isCarried",false))
(set: $basswood to (datamap: "name","basswood","description","A log from a basswood tree","pickupText","You now have a basswood log","isCarried",false))
(set: $hemlock to (datamap: "name","hemlock","description","A log from a hemlock tree","pickupText","You now have a hemlock log","isCarried",false))
(set: $rainbow to (datamap: "name", "rainbow","description","A log from a rainbow tree","pickupText","You now have a rainbow log","isCarried",false))

And this is just my experiment game... If I could get my datamaps to work I would be so happy.


...I will count them so you have an exact number... ... ..81...plus an additional 15 that I have on a different browser.. So my erroring game had 96 datamaps on the first passage. That's probably too many, then.. That means if I have an error or not is irrelevant. I need to use this startup tagged passage thingy instead?

I would also like to mention that my previous version (without the 15 on the other browser) is actually working... Just something happened when I added that many more.

by (159k points)

Thank you for supplying examples of the types of data-maps that you were commenting on.

...my passages are freaking out and the text is flying everywhere and my links don't work...

Could you explain in greater detail what you mean by "freaking out", "flying everywhere", and "links don't work"? It would also help if you gave code examples of said Passages where these types of behaviours are occurring.

One thing I did note is that your data-map example was using line-breaks to make the code more readable, and generally each line-break within a Passage is automatically converted to a HTML br element. This behaviour could cause code like that within your example to appear as lots of blank lines due to the fact that the (set:) macros and the HTML comments within that Passage both generate no visual output themselves.

If you need to include code like that within a Passage whose content will be displayed to the Reader then I suggest you start using either Collapsing whitespace markup or Escaped line break markup to reduce the number of blank lines in the generated visual output.

On the other hand if you move that variable initiation code into a startup tagged special Passage then you will need to use CSS like the following within your story's Story Stylesheet area to suppress all that special passage's visual output.

tw-include[type="startup"] {
	display: none;


by (63.1k points)
edited by

I agree with @greyelf's assessment and suggestions, especially regarding using a startup passage.

Re: 96 datamaps

Using an up-to-date version of Chrome, and running 100 data maps similar* to yours in a startup-tagged passage, and using the performance.now() function** to see how long it took to process that code, I got a result of around 420 milliseconds on average; less than half a second.  The minimum I got across about ten tests was 386, the maximum was 437.

This is a noticeable lag, and during the first half second, it's possible that links or other elements of the story may be unresponsive.  However, that effect should go away in under half a second.

Going up to 200 data maps, and the performance numbers show an average of around 720 milliseconds.  Going to 300 gets us to around 1 whole second worth of lag.

These numbers are significant, but to see the sort of total breakdown of functionality you describe, due only to the use of data maps, would require probably at least 1000 or so data maps, as a very conservative estimate--in reality it would probably take many, many more than that to break Harlowe so completely.

As I said in my original answer, I believe the problems are not arising from the use of data maps specifically, but I agree that migrating the data maps to a startup tagged passage should be your next step.  If the problem continues after that, post the code of the offending passages and we'll try to help.

* I selected ten of yours at random and copy-pasted them ten times each, for a total of 100--since Harlowe recreates data maps for every change, as explained above in the thread by greyelf, this should be the same, performance-wise, as 100 unique data maps.

** I placed the starting performance.now() call in the story JavaScript area, which is processed early on; after Harlowe's engine has loaded, but before any passage code.  I placed the other call in the initial passage.  It's not a super accurate or scientific measurement, but it should be fairly close.  For comparison, omitting the startup passage and the data maps completely yielded results in the teens, usually around 14 to 16 milliseconds.

by (180 points)
Thank you guys for all of your help!


I have come back to my erroring game and it looks like something happened to my save (because it is missing all of those datamaps) and I think I will take some time off from this issue and focus on others. I run into so many technical problems...

Again, thanks a lot! I will post again should I run into the same problem.. but hopefully I won't because I'll use the startup tag and the css tip above.