+2 votes
by (150 points)
It's been a while since I've dug into Twine and my code brain is stunted. I'd like to create a sort of magnetic poetry function and thought Twine might be able to handle it.

It doesn't have to be fancy. Something like: the audience would see a blank area, and a "word bank". They could click on a word in the bank, and that word would appear in the blank area. They could click another word, and that word would appear next.

I don't so much care about undo or unselecting words right now.

A nice bonus would be if there was a way to share their creations, but that seems like a lot to ask!

Is this possible?

I prefer using Twine Original Flavor, but am willing to transition to Twine 2 if that's necessary!

1 Answer

+1 vote
by (63.1k points)
edited by

That's a cool idea.  How I'd handle it is through a single string variable containing the poem, then use DOM replacement macros (<<replace>> in SugarCube) to update the output.  I'd store the word bank itself in an array.

Here's a rough example of how something like that might look in SugarCube 2.  Note that you can install SugarCube 2 in Twine 1 if you want to stick with 1.

::StoryInit
<<set $poem to ''>>
<<set $wordBank to [
    'hello',
    'how',
    'the',
    'sky',
    'blah',
    'feels'
]>>

::main
<div id='poem'>$poem</div>
<div id='word-bank'><<include 'bank'>></div>

::bank
<<for _i to 0; _i < $wordBank.length; _i++>>\
    <<capture _i>>\
        <<link $wordBank[_i]>>
            <<addword $wordBank[_i]>>
        <</link>>
    <</capture>>\
<</for>>
<<button 'Add Line Break'>>
    <<addbreak>>
<</button>>\

::widgets [widget nobr]
<<widget 'addword'>>
    <<set _word to $args[0]>>
    <<set _del to $wordBank.indexOf(_word)>>
	
    <<if $poem is ''>>
        <<set $poem to _word>>
    <<else>>
        <<set $poem to $poem + ' ' +_word>>
    <</if>>
	
    <<run $wordBank.deleteAt(_del)>>
	
    <<if $wordBank.length < 1>>
        <<replace '#word-bank'>>\
            <<link 'Again'>>
                <<run Engine.restart()>>
            <</link>>\
        <</replace>>
    <<else>>
        <<replace '#poem'>>$poem<</replace>>
    <</if>>
	
    <<replace '#word-bank'>><<include 'bank'>><</replace>>
<</widget>>

<<widget 'addbreak'>>
    <<set $poem to $poem + '\n'>>
    <<replace '#poem'>>$poem<</replace>>
<</widget>>

Then in CSS:

#word-bank {
  float: right;
  margin: 2em;
  margin-top: 10%;
  padding: 1em;
  border: 2px #eee solid;
  height: 20em;
  width: 10em;
}

I'm not sure if there's an easy way to accomplish this in Harlowe or Sugarcane; the <<for>> macro and the <<capture>> macro are pretty important here, and Sugarcane lacks both.  It might work with some modification in Harlowe.

by (159k points)

NOTE: Harlowe is a Twine 2 only story format.

by (150 points)
Oh wow, thank you!! this is so close to what I imagined!

The main problem I'm having is that the words aren't properly disappearing. When I click one to add to the poem, it effectively deletes it from the wordbank but doesn't visually delete it. So when I click another word that comes after that one in this list, it actually clicks one farther -- Does that make sense? I'm on Mac 10.11, and it does this with Chrome and Safari.
by (63.1k points)

I can't seem to reproduce that exact issue, but I did notice a mistake in the 'addword' widget.  Try changing it to this and let me know if that helps. 

<<widget 'addword'>>
    <<set _word to $args[0]>>
    <<set _del to $wordBank.indexOf(_word)>>
	
    <<if $poem is ''>>
        <<set $poem to _word>>
    <<else>>
        <<set $poem to $poem + ' ' +_word>>
    <</if>>
	
    <<run $wordBank.deleteAt(_del)>>
	
    <<if $wordBank.length < 1>>
        <<replace '#word-bank'>>\
            <<link 'Again'>>
                <<run Engine.restart()>>
            <</link>>\
        <</replace>>
    <<else>>
        <<replace '#word-bank'>><<include 'bank'>><</replace>>
    <</if>>
	
    <<replace '#poem'>>$poem<</replace>>
<</widget>>

 

by (150 points)

Thank you, Chapel!

I ended up getting a little outside help on the disappearing words issue. I ended up with this code, which works!

<<set $poem to ''>><<set $wordBank to [
'The', 'day', 'I', 'was', 'born,', 
]>><h1>Header</h1><div id='poem'>$poem</div><div id='bank-container'><h2>WORD BANK</h2>
    <<for _i to 0; _i < $wordBank.length; _i++>>\
        <<capture _i>>\<<link $wordBank[_i]>> <<addword $wordBank[_i]>>
            <</link>>\
        <</capture>> &middot; \
    <</for>>
    <<button 'Add Line Break'>>
        <<addbreak>>
    <</button>>\
</div>

<<widget 'bankWidget'>>
    <<if $wordBank.length < 1>>
        <<button 'Again'>>
            <<run Engine.restart()>>
        <</button>>\
<<else>>\
    <<for $i = 0; $i < $wordBank.length; $i++>>\
        <<capture $i>>\
            <<link $wordBank[$i]>>\
                <<addword $wordBank[$i]>>\
            <</link>>\
        <</capture>> &middot; \
    <</for>>
    <<button 'Add Line Break'>>
        <<addbreak>>
    <</button>>\
    <</if>>
<</widget>>

<<widget 'addword'>>
    <<set _word to $args[0]>>
    <<set _del to $wordBank.indexOf(_word)>>

    <<if $poem is ''>>
        <<set $poem to _word>>
    <<else>>
        <<set $poem to $poem + ' ' + _word>>
    <</if>>
    
    <<run $wordBank.deleteAt(_del)>>

    <<replace '#poem'>>$poem<</replace>>

    <<replace '#bank-container'>><<bankWidget>><</replace>>
<</widget>>

<<widget 'addbreak'>>
    <<set $poem to $poem + '\n'>>
    <<replace '#poem'>>$poem<</replace>>
<</widget>>

And here's the wordbank CSS for that, including a bit to make the wordbank look more like cut out words:

#bank-container {
  float: right;
  margin: 0em 1em;
  padding: 0em 1em 1em 1em;
  border: 4px #eee outset;
  height: auto;
  width: 45%;
  line-height: 200%;
  background-color:rgba(0,0,0,0.5);
  text-align: center;
}
a {
  padding: .15em .45em;
  background-color: white;
  color: black;
}

Thanks for your help!!

...