1. I use a lot of $variables for things like character stats / dispositions / etc. Does it make more sense to group these into datamaps? Are those more performant for data that should be logically grouped together? Do they have less of an impact on Harlowe's history function?
This shouldn't have a major effect on performance one way or another, though datamaps are actually harder on the history system than normal variables. Story variables are already stored as properties on an object anyway, though. The syntax for accessing parts of a datamap is probably very, very slightly less performance friendly than a standard variable, but this is unlikely to be causing the issue. I suspect variables are the problem, if anything, but not really because of this. I'll explain more in a bit.
2. I use a significant amount of (either:"really long string","another really long string","another fairly long string") statements. What is the java that underlies the (either:) statement? Would it be better to use a different method for selecting one of many long strings?
First of all, it's JavaScript, not Java. Other than unfortunately similar names, they have little in common and are completely separate languages. You shouldn't be using (either:) for program control, assuming that's what you're doing; use (if:)s instead. For example:
(set: _var to (either: 1, 2, 3))\
(if: _var is 1)[\
Really long string...\
](elseif: _var is 2)[\
etc....
Depending on what your code actually entails, you might get some small boosts from this, but I doubt it'll be anything to write home about.
3. Do (else-if:)'s make a big difference as opposed to just a bunch of (if:)'s?
A bunch of (if:)s is probably marginally slower than using (elseif:)s. Ultimately, again, we're talking unnoticeable performance gains here, if anything. It would take potentially 100s of (if:)s in the same passage being processed to have a noticeable impact.
4. Should I... take the plunge and convert to another story format to get a more performant story? I would really hate to do this because I've done quite a few things in Harlowe that I consider kind of technically complex and would take some time to figure out how to mirror them. But definitely willing to do it if it's the best thing in the long run.
Maybe, but that depends on the problem. I'll address this more directly below.
5. I probably won't complete my story for another 2-3 years. Do you think in that time, Harlowe will have improved / gotten fast to the point where tuning at this point won't make a huge difference?
Browsers might be faster in the future, and I'm sure there's room for improvement in Harlowe's code. No one can say for sure though.
I heard through the grapevine that Harlowe stores a complete history of variables or something. I would *love* to turn that off somehow, or figure out how to minimize it's impact.
It stores a complete history of variables, at each moment. If you have 1000 variables and click through 1000 passages, then it's storing 1,000,000 variables by the end. Obviously, that's a lot, and it will cause noticeable slowdown. You can't turn off Harlowe's history system. SugarCube's history system can be shut off, and if this is really the issue you're facing, it might be worth making the switch. I suspect this is probably the culprit. If it is indeed the problem, then the performance issues should be getting worse as play goes on. If that's what's happening, then this is the problem.
I don't know that you need to switch formats though. It's probably the case that you could do a better job managing the variables you have now; using more temporary variables and using less variables overall, or reusing variables. Many Twine creators create pointless variables, and pay for it as their stories grow. For example, an author might create a variable that checks if a player has been to a passage before rather than using the (history:) macro. Or, an author might make a variable that tests if the user is out of health instead of just checking if the health variable itself is 0 or not:
-> BAD
(if: $health <= 0)[
(set: $noHealth to true)
]
(if: $noHealth)[
You DEAD!
]
-> GOOD
(if: $health <= 0)[
(set: $health to 0)
]
(if: $health is 0)[
You DEAD!
]
Check your code for pointless variables, and cut down on the clutter as much as you can.
It's also possible that you have headers or footers running every round that are eating up performance. This is especially noticeable when you're running loops in Harlowe. Sometimes you need a loop, but loops are not really well optimized in my experience.
Look at the code you have running on every turn and try to trim the fat. Look at any loops you've got running and make sure you aren't better served using another method. Here's an example of such a situation.
There are other reasons your performance might be struggling, too. Try your game in different browsers to make sure it's not your browser's JavaScript engine. It might also be related to saved games--if you're loading old saves to test from, it's possible that the saved data includes junk variables or data that you aren't using anymore.
Some complicated JavaScript or poorly-written CSS could also be hindering your game, so look at what you have running in those places too.
In conclusion, I would be surprised if it wasn't possible for you to fix the performance issues, and that needing to change story formats or wait for improved versions of Harlowe was actually your only option. The issues you mention specifically might net you smaller performance gains, but I think you should focus on:
- Cleaning up your variable store by using less story variables wherever possible.
- Looking at headers/footers/other repeated code and trying to make that code more efficient (assuming you are using this type of code).