Skip to content

Instantly share code, notes, and snippets.

@JoshuaGrams
Last active August 3, 2024 04:07
Show Gist options
  • Save JoshuaGrams/2e5d3029dc48edf8770abb4a6b682ff2 to your computer and use it in GitHub Desktop.
Save JoshuaGrams/2e5d3029dc48edf8770abb4a6b682ff2 to your computer and use it in GitHub Desktop.
Line-by-line text reveal: Twine/SugarCube.
:: Some Passage
This will show at the start.
@@.hide;This will show after you click or press space/enter.@@
@@.hide;.nocontinue;This will show after you advance again, but will <em>not</em> have the continue marker.@@
<span class="hide">HTML tags work fine too, but the other notation is shorter.</span>
:: StoryInit
/* Remember how much of each passage has been revealed.
* If you would prefer a different variable name, do
* <<set setup.continueVar to '$myContinueCounts'>>
*/
<<set $continued to {}>>
// This whole thing goes in the Story JavaScript
// -----------------------------------------------------------------------------------
// If you prefer, you can delete these configuration commands from the JavaScript
// and <<set ...>> these three values in your StoryInit instead.
// These keys cause the text to advance.
setup.continueKeys = new Set([' ', 'Enter'])
// Ignore clicks/keypresses on anything in one of these CSS selectors.
// Any selector should work, so also things like '.myClass' or '#myID'
setup.noContinue = new Set(['a', 'button', 'input', 'textarea'])
// SugarCube only: variable telling how many sections have been
// revealed on various passages.
// Be sure to <<set $continued to {}>> in StoryInit
// (or whatever you call the variable).
setup.continueVar = '$continued'
// ------------------------------------------------------------------------------
function isInSelector(elt, selector) {
while(elt && elt.matches) {
if(elt.matches(selector)) return true
elt = elt.parentNode
}
return false
}
function revealFirstHidden(ev) {
// Ignore these elements.
if(ev) for(const selector of setup.noContinue) {
if(isInSelector(ev.target, selector)) return
}
// Remove any existing continue indicators.
let shown = $('.passage .continue')
if(shown) shown.removeClass('continue')
// Get any hidden items.
const hidden = $('.passage .hide')
if(hidden.length > 0) {
// We're doing the special thing, prevent the default behavior
ev && ev.preventDefault()
// If more are hidden, add the continue indicator.
let show = hidden.first()
if(hidden.length > 1 && !show.hasClass('nocontinue')) {
show.addClass('continue')
}
// Set the first to fade in and then unhide it.
show.addClass('fadein')
show.removeClass('hide')
// If scrollIntoView() exists (maybe not on IE?), do it.
if(show[0].scrollIntoView) {
show[0].scrollIntoView({behavior: 'smooth', block: 'nearest'})
}
// If we're being called directly (not from an event),
// and we're in SugarCube...
if(ev && State && typeof State.getVar === 'function') {
// and the variable exists,
const count = State.getVar(setup.continueVar)
// increment the number of things we've revealed.
if(count) count[passage()] = (count[passage()] || 0) + 1
}
}
}
// When you open up the story in your browser, add keyboard and mouse handlers.
$(document).ready(function() {
$('html').on('click', revealFirstHidden)
$('html').on('keypress', function(ev) {
const modifiers = ev.ctrlKey || ev.altKey || ev.shiftKey
if(setup.continueKeys.has(ev.key) && !modifiers) {
revealFirstHidden(ev)
}
})
})
// If you want to remember how much was already revealed, include this bit,
// which happens every time a new passage is displayed.
$(document).on(':passagedisplay', function() {
// If we're in SugarCube
if(State && typeof State.getVar === 'function') {
// $continued[passage()] tells how many hidden items were revealed.
const count = State.getVar(setup.continueVar)
const n = count && count[passage()] || 0
for(let i=0; i<n; ++i) revealFirstHidden()
}
})
.hide { display: none; }
.fadein {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 0.5s;
}
@keyframes fadeInOpacity {
0% { opacity: 0; }
100% { opacity: 1; }
}
.continue:after {
content: "\A➔";
white-space: pre;
}
@cosmonautdad
Copy link

hello ! love this , but the continue marker still haunts me whenever i'm adding more than one reveal

@JoshuaGrams
Copy link
Author

Sorry, I'm not sure what you're saying. The continue marker doesn't go away when you reveal the last one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment