Skip to content

Instantly share code, notes, and snippets.

@JoshuaGrams
Last active February 4, 2026 05:47
Show Gist options
  • Select an option

  • Save JoshuaGrams/2e5d3029dc48edf8770abb4a6b682ff2 to your computer and use it in GitHub Desktop.

Select an option

Save JoshuaGrams/2e5d3029dc48edf8770abb4a6b682ff2 to your computer and use it in GitHub Desktop.

Revisions

  1. JoshuaGrams revised this gist Feb 2, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion reveal.tw
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@ This will show at the start.

    @@.hide;This will show after you click or press space/enter.@@

    @@.hide;.nocontinueThis will show after you advance again, but will <em>not</em> have the continue marker.@@
    @@.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>

  2. JoshuaGrams revised this gist Dec 25, 2020. 5 changed files with 118 additions and 24 deletions.
    14 changes: 12 additions & 2 deletions reveal.tw
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,17 @@
    :: Some Passage
    This will show at the start.

    @@.hide;This will show after you click or press space/enter.@@

    @@.hide;This will show after you advance again.@@
    @@.hide;.nocontinueThis will show after you advance again, but will <em>not</em> have the continue marker.@@

    @@.hide;And again...@@
    <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 {}>>
    87 changes: 87 additions & 0 deletions script.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,87 @@
    // 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()
    }
    })
    1 change: 0 additions & 1 deletion story.css
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    .hide { display: none; }
    21 changes: 0 additions & 21 deletions story.js
    Original file line number Diff line number Diff line change
    @@ -1,21 +0,0 @@
    function revealFirstHidden(ev) {
    if(ev.target.nodeName === 'A') return
    const hidden = $('.passage .hide')
    if(hidden.length > 0) {
    let show = hidden.first()
    show.removeClass('hide')
    if(show[0].scrollIntoView)
    show[0].scrollIntoView({behavior: 'smooth', block: 'nearest'})
    }
    }

    const continueKeys = { " ": true, Enter: true }

    $(document).ready(function() {
    $('html').on('click', revealFirstHidden)
    $('html').on('keypress', function(ev) {
    if(continueKeys[ev.key] && !(ev.ctrlKey || ev.altKey || ev.shiftKey)) {
    revealFirstHidden(ev)
    }
    })
    })
    19 changes: 19 additions & 0 deletions style.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    .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;
    }
  3. JoshuaGrams renamed this gist Nov 28, 2020. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. JoshuaGrams created this gist Nov 27, 2020.
    7 changes: 7 additions & 0 deletions example.tw
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    This will show at the start.

    @@.hide;This will show after you click or press space/enter.@@

    @@.hide;This will show after you advance again.@@

    @@.hide;And again...@@
    1 change: 1 addition & 0 deletions story.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    .hide { display: none; }
    21 changes: 21 additions & 0 deletions story.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@
    function revealFirstHidden(ev) {
    if(ev.target.nodeName === 'A') return
    const hidden = $('.passage .hide')
    if(hidden.length > 0) {
    let show = hidden.first()
    show.removeClass('hide')
    if(show[0].scrollIntoView)
    show[0].scrollIntoView({behavior: 'smooth', block: 'nearest'})
    }
    }

    const continueKeys = { " ": true, Enter: true }

    $(document).ready(function() {
    $('html').on('click', revealFirstHidden)
    $('html').on('keypress', function(ev) {
    if(continueKeys[ev.key] && !(ev.ctrlKey || ev.altKey || ev.shiftKey)) {
    revealFirstHidden(ev)
    }
    })
    })