Last active
May 5, 2021 12:50
-
-
Save JoshuaGrams/073e02468a5fe3addb8cdbfdc6f199d3 to your computer and use it in GitHub Desktop.
Extremely basic storylets in Ink
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(storyContent) { | |
var story = new inkjs.Story(storyContent); | |
var storyContainer = document.querySelectorAll('#story')[0]; | |
function showAfter(delay, el) { | |
setTimeout(function() { el.classList.add("show") }, delay); | |
} | |
function choose(list, n) { | |
const last = list.length - 1; | |
for(let i=0; i<Math.min(n, list.length - 2); ++i) { | |
const j = i + Math.floor((last - i)*Math.random()); | |
const t = list[i]; list[i] = list[j]; list[j] = t; | |
} | |
return list.slice(0, n); | |
} | |
function scrollToBottom() { | |
var progress = 0.0; | |
var start = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; | |
var dist = document.body.scrollHeight - window.innerHeight - start; | |
if( dist < 0 ) return; | |
var duration = 300 + 300*dist/100; | |
var startTime = null; | |
function step(time) { | |
if( startTime == null ) startTime = time; | |
var t = (time-startTime) / duration; | |
var lerp = 3*t*t - 2*t*t*t; | |
window.scrollTo(0, start + lerp*dist); | |
if( t < 1 ) requestAnimationFrame(step); | |
} | |
requestAnimationFrame(step); | |
} | |
function continueStory() { | |
var paragraphIndex = 0; | |
var delay = 0.0; | |
// Generate story text - loop through available content | |
while(story.canContinue) { | |
// Get ink to generate the next paragraph | |
var paragraphText = story.Continue(); | |
// Create paragraph element | |
var paragraphElement = document.createElement('p'); | |
paragraphElement.innerHTML = paragraphText; | |
storyContainer.appendChild(paragraphElement); | |
// Fade in paragraph after a short delay | |
showAfter(delay, paragraphElement); | |
delay += 200.0; | |
} | |
// Create HTML choices from ink choices | |
const limit = story.variablesState.num_storylets || story.currentChoices.length; | |
choose(story.currentChoices, limit).forEach(function(choice) { | |
// Create paragraph with anchor element | |
var choiceParagraphElement = document.createElement('p'); | |
choiceParagraphElement.classList.add("choice"); | |
choiceParagraphElement.innerHTML = `<a href='#'>${choice.text}</a>` | |
storyContainer.appendChild(choiceParagraphElement); | |
// Fade choice in after a short delay | |
showAfter(delay, choiceParagraphElement); | |
delay += 200.0; | |
// Click on choice | |
var choiceAnchorEl = choiceParagraphElement.querySelectorAll("a")[0]; | |
choiceAnchorEl.addEventListener("click", function(event) { | |
// Don't follow <a> link | |
event.preventDefault(); | |
// Remove all existing choices | |
var existingChoices = storyContainer.querySelectorAll('p.choice'); | |
for(var i=0; i<existingChoices.length; i++) { | |
var c = existingChoices[i]; | |
c.parentNode.removeChild(c); | |
} | |
// Tell the story where to go next | |
story.ChooseChoiceIndex(choice.index); | |
// Aaand loop | |
continueStory(); | |
}); | |
}); | |
scrollToBottom(); | |
} | |
continueStory(); | |
})(storyContent); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
VAR num_storylets = 0 // 0 means no limit. | |
VAR location = "home" | |
VAR driving = false | |
-> home | |
== choose_storylet == | |
// This is your "deck of cards": a list of conditional choices, one for each | |
// storylet. Each choice will show up only when the storylet is available. | |
// | |
// It's a little inconvenient having the conditions separate from the content, | |
// but you can have little groups of conditions near the content and use the | |
// threading operator <- to include them into a bigger "deck" knot. | |
// | |
// If you want to show only 1 or 3 (or however many) of the available | |
// storylets instead of all of them, I think that's better handled in the | |
// presentation layer (randomly select a few choices instead of showing all | |
// of them), though I've seen people do it purely in Ink with lists. | |
+ {driving && location != "home"} [Home] -> home | |
+ {driving && location != "fairweather"} [Fairweather Farm] -> fairweather | |
+ {driving && location != "anderson"} [Anderson Farm] -> anderson | |
+ {driving && location != "docks"} [Docks] -> docks | |
== home == | |
~ location = "home" | |
Where the heart is. | |
+ [Drive] -> car | |
== fairweather == | |
~ location = "fairweather" | |
Organic vegetables, eggs from happy hens. | |
+ [Drive] -> car | |
== anderson == | |
~ location = "anderson" | |
Meat and dairy products for three generations. | |
+ [Drive] -> car | |
== docks == | |
~ location = "docks" | |
A bustling wharf. | |
+ [Drive] -> car | |
== car == | |
You get behind the wheel. | |
~ driving = true | |
<- choose_storylet | |
~ driving = false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment