Redirect to another passage


I been trying to set a countdown that will auto lead to an other passage after an amount of time. I found out that code who is working great. But I can’t find the way to set the destination to an other passage. As you can see I put google home site to test the thing…

It’s in Harlowe


Might help to let people know which IF authoring program/tool you’re trying to do this with. I’m new to the site but that seems to not be apparent. :wink:
EDIT: Yay, so it’s Harlowe. That’d be Twine. Can’t help you there but I’m sure now someone will be able to. I think it’s weird the system let you post directly to Authoring without any sub-category to begin with. Maybe that’s a bug, or maybe it’s a feature, I dunno.

1 Like

I can’t see any code in you post, so I’m not sure which part is or isn’t working great.

Regardless, the following should do what you want:

(set: $time to 0)
(set: $timelimit to 30)

(live: 1s)[
     (set: $time to ($time + 1))
     (if: $time > $timelimit)[
          (goto:"Passage Name")

This is set up for 30 seconds, but can be edited to whatever amount of time you want.

If you want the timer to persist through multiple passages, put the set variable macros in the startup passage, and the counter in the passages themselves. If you want it to count, but not go anywhere in certain passages, you would just need:

(live: 1s)[
     (set: $time to ($time + 1))

I though I copie/paste but here is the code I used :

< html>
< body>
< div id=“counter”>30
< script>
setInterval(function() {
var div = document.querySelector("#counter");
var count = div.textContent * 1 - 1;
div.textContent = count;
if (count <= 0) {
}, 1000);
< /script>
< /body>
< /html>

I don’t know why but the code wont show ? Well if I put a space after the < it does show but margin are really messed up :s

I can’t speak to the javascript, but if you’re using Harlowe the following should work:

(open-url: "")

(goto-url: "")

The first opens a new tab, the second replaces the current tab.

note: I will assume you were trying to use this forum’s “Preformatted Text” tool-bar option to include the following example.

<div id="counter">30</div>
	setInterval(function() {
		var div = document.querySelector("#counter");
		var count = div.textContent * 1 - 1;
		div.textContent = count;
		if (count <= 0) {
	}, 1000);

The Harlowe story format has been deliberately design to restrict an Author’s ability to use JavaScript to access the internals of it’s engine, it also has limited support for using JavaScript in general.

Where exactly in your project did you place your example?

Because if I add the above example to the contents of a Passage and then view it within the story HTML file, I see a countdown which results in a URL redirection when it reaches zero.

1 Like

The countdown actually work, I had issue redirecting to an other passage. But it did work when I put an web URL

redirecting to an other passage

Harlowe’s engine doesn’t include support for “URL based Passage Navigation”, which is why your updating of window.location with a Passage related URL didn’t work. If you want such functionality then you will need to implement it yourself, however the fact that Harlowe doesn’t have a documented JavaScript API makes doing that difficult.

Thank that piece of knowledge is appreciated !

There is a way to do this with inserted Javascript in the story.
First add this into the story :

// Harlowe Macro Framework, by Chapel; version 1.0.2
;!function(){"use strict";var r={major:1,minor:0,patch:2},e=[r.major,r.minor,r.patch].join(".");r.semantic=e,r=Object.freeze(r);var t=$("tw-storydata"),a=Object.freeze({name:t.attr("name"),ifid:t.attr("ifid")}),n=t.attr("format-version"),o=n.split("."),i=Object.freeze({major:o[0],minor:o[1],patch:o[2],semantic:n});window.Harlowe=window.Harlowe||{},window.Harlowe=Object.assign(window.Harlowe,{framework:r,API_ACCESS:Object.freeze({MACROS:require("macros"),STATE:require("state"),CHANGER:require("datatypes/changercommand"),ENGINE:require("engine")}),engine:i,story:a})}(),function(){"use strict";function e(r){return"number"==typeof r||"boolean"==typeof r||"string"==typeof r||null===r||Array.isArray(r)&&r.every(e)||r instanceof Set&&Array.from(r).every(e)||r instanceof Map&&Array.from(r.values()).every(e)||_changer.isPrototypeOf(r)}window.Harlowe=Object.assign(window.Harlowe,{helpers:{isSerialisable:e,isSerializable:e,arrayify:function(r,e){if(r){var t=[];return void 0!==e&&(t=t.slice(e)),t}},getPassageData:function(r){var e=$('tw-passagedata[name="'+r+'"]');if(e[0])return e}}})}(),function(){"use strict";var n=window.localStorage||!1,o=Harlowe.story.ifid+"-tw-storage";function r(){try{if(!n)throw new Error("storage is inaccessible");n.setItem(o,JSON.stringify({ifid:Harlowe.story.ifid}))}catch(r){console.warn(r)}}function i(r){try{var e;if(n)return e=JSON.parse(n.getItem(o)),r&&r&&"string"==typeof r?e[r]:e;throw new Error("storage is inaccessible")}catch(r){console.warn(r)}}null==i()&&r(),{clear:r,save:function(r,e){try{if(!r||"string"!=typeof r)throw new TypeError("cannot store values without a valid storage key");if(void 0===e)throw new TypeError("cannot store undefined values");var t={};if(t[r]=e,!n)throw new Error("storage is inaccessible");var a=i();Object.assign(a,t),n.setItem(o,JSON.stringify(a))}catch(r){console.warn(r)}},load:i,remove:function(r){try{if(!r||"string"!=typeof r)throw new TypeError("cannot store values without a valid storage key");if(!n)throw new Error("storage is inaccessible");var e=i();e.hasOwnProperty(r)&&(delete e[r],n.setItem(o,JSON.stringify(e)))}catch(r){console.warn(r)}}}}(),function(){"use strict";function a(r,e,t){if(!(this instanceof a))return new a(r,e,t);||"unknown",this.args=e||[],||{},this.type=t&&t.type||"basic",this.fn=t&&t.fn||"handler","changer"===this.type&&("handler"===this.fn?this.instance=t&&t.instance||null:this.descriptor=t&&t.descriptor||null)}a.create=function(r,e,t){if(!r||"string"!=typeof r||!r.trim())throw new TypeError("Invalid macro name.");return e&&e instanceof Array||(e=[]),t&&"object"==typeof t||(t={type:"basic",fn:"handler"}),new a(r,e,t)},Object.assign(a.prototype,{clone:function(){return a.create(,this.args,},syntax:function(){return"("":)"},error:function(r,e){var t="Error in the "+this.syntax()+" macro: "+r;return e&&alert(t),console.warn("HARLOWE CUSTOM MACRO ERROR -> ",t),new Error(r)},typeCheck:function(r){r&&r instanceof Array||(r=Harlowe.helpers.arrayify(arguments));var n=this,o=[];if(r.forEach(function(r,e){var t=e+1,a=[];"string"==typeof r&&("any"===(a=r.includes("|")?r.split("|").map(function(r){return r.trim().toLowerCase()}):[r.trim().toLowerCase()])[0]||a.some(function(r){return typeof n.args[e]===r})||o.push("argument "+t+" should be a(n) "+a.join(" or ")))}),o.length)return n.error(o.join("; "))}}),window.Harlowe=Object.assign(window.Harlowe,{MacroContext:a})}(),function(){"use strict";var c=Harlowe.API_ACCESS.MACROS,l=Harlowe.API_ACCESS.CHANGER;window.Harlowe=Object.assign(window.Harlowe||{},{macro:function(r,e,t){if(!r||"string"!=typeof r||!r.trim())throw new TypeError("Invalid macro name.");if(!e||"function"!=typeof e)throw new TypeError("Invalid macro handler.");var a,n,o,i,s;t&&"function"==typeof t?(o=r,i=e,s=t,c.addChanger(o,function(){var r=Harlowe.helpers.arrayify(arguments,1),e=l.create(o,r),t=Harlowe.MacroContext.create(o,r,{type:"changer",fn:"handler",instance:e});return i.apply(t,r),e},function(){var r=Harlowe.helpers.arrayify(arguments),e=r.shift(),t=Harlowe.MacroContext.create(o,r,{type:"changer",fn:"changer",descriptor:e});s.apply(t,r)},c.TypeSignature.zeroOrMore(c.TypeSignature.Any))):(a=r,n=e,c.add(a,function(){var r=Harlowe.helpers.arrayify(arguments,1),e=Harlowe.MacroContext.create(a,r,{type:"basic",fn:"handler"}),t=n.apply(e,r);return null==t?"":t},c.TypeSignature.zeroOrMore(c.TypeSignature.Any)))}})}(),function(){"use strict";var t=Harlowe.API_ACCESS.STATE,e=Harlowe.API_ACCESS.ENGINE;function a(){return t.passage}window.Harlowe=Object.assign(window.Harlowe||{},{passage:a,tags:function(r){r=r||a();try{var e=Harlowe.helpers.getPassageData(r).attr("tags");return e?e.split(" "):[]}catch(r){return console.warn(r.message),[]}},goto:function(r){return e.goToPassage(r)},variable:function(r,e){if("$"!==r[0])throw new Error('cannot access variable "'+r+'"');if(r=r.substr(1),void 0!==e){if(!Harlowe.helpers.isSerialisable(e))throw new Error('The value passed to variable "'+r+'" cannot be serialized.');t.variables[r]=e}return t.variables[r]},visited:function(r){return t.passageNameVisited(r||a())},hasVisited:function(r){return 0<t.passageNameVisited(r||a())},turns:function(){return t.pastLength}})
let anchor = window.location.hash.substr(1);
if(anchor != ""){window.Harlowe.goto(anchor);}
}();// end Harlowe Macro Framework

Now HTML anchor can go to the passage mentionned,
It use the GitHub - ChapelR/harlowe-macro-api: Adds an accessible, simplified framework to Harlowe for creating custom macros in JavaScript.
and a little script writed for it.

It is pratic to link two builded stories from a passage to another with :
<a href="file.html#passage_name">link to the passage</a>