Basic Arcweave tutorial | Part 15: Polish the project
Polish this tutorial's project: delete unused boards, merge elements, and make better use of the morale score system.
Video tutorial
Watch this tutorial as a video:
⚠️ This video does not reflect the latest updates to Arcweave's UI.
✅ You can play the finished version of the Tutorial Project here and explore its diagrams and structure here.
Clean up the project
To clean up the project, you can:
- Delete any "dummy" elements or boards used purely for demonstration.
- Delete any empty boards.
- Remove unused formatting.
- Delete unused variables. For example, the
roll_resultvariable we used earlier to deduct from the player's morale is no longer needed once we change how morale is calculated (see below).
Initial morale
If you followed Part 13, your starting element already rolls the player's initial morale. This section puts that setup together. If your project still assigns a fixed value instead, replace it with a dice roll.
Roll for initial morale
In the element where morale is first set, replace the fixed value with a dice roll:
player_morale = roll(6,3)This rolls three six-sided dice and assigns the result to player_morale.
Show initial morale
Next, let's render the result to the player. In the element's text, show the value and add some text that introduces it:
You start with a morale of
show(player_morale, ".")Morale commentary
We can let the game comment on the player's initial morale, by adding some conditional text:
if player_morale < 12
It's not that great, to be honest, but you have to work with what you've got.
elseif player_morale >= 12 and player_morale <18
It's a pretty good morale score to start with.
else
Perfect morale score! You feel super elevated!
endifPut it all together
Putting all of the above together, the starting element looks like this:
You rub your eyes. You are on the floor. Your office. It's midday. And you have work to do.
You start with a morale of
player_morale = roll(6,3)
show(player_morale, ".")
if player_morale < 12
It's not that great, to be honest, but you have to work with what you've got.
elseif player_morale >= 12 and player_morale <18
It's a pretty good morale score to start with.
else
Perfect morale score! You feel super elevated!
endif✅ Test this in Play Mode. Due to the initial value being randomized, you'll see different outcomes each time you restart the story.
Add morale check
There's not much point in having a stat like morale if it never affects anything.
Let's add a morale check at a key moment in the story: when Horace opens the door and comments on the player being late (or dirty).
Add a penalty
First, let's add a penalty for not having showered. Inside the element where Horace opens the door, type:
Horace Linetti opens the door and lets you in.
if shower_taken
"You're late!" he says.
else
"Good Lord! You smell as if you've spent the night on an office floor," he says, fanning the air with his hand.
player_morale = player_morale - 2
endifRoll the check
Next, we add the actual check: we'll roll a 20-sided die and compare it against the player's morale. As an extra rule, if the player has maximum morale (18), the check is considered a success.
Add the following to the element content:
if player_morale >= roll(20) or player_morale == 18
You enter the apartment. As you marvel at the design of the living room, he disappears towards the bedrooms. "Let me know if you find my grandmother's ring," he hollers.
else
You freeze with shame. Without a word, you turn around and leave.
endifStore the result
Right now, the outcome of the check only affects the text shown inside that one element; it does not affect the options or the rest of the story. To fix this, we need to store the result in a variable so we can evaluate it anywhere else needed.
- Create a new Boolean variable called
morale_check_success, with initial value set tofalse. - Inside the element content, plant accordingly the assignment of the
morale_check_successvariable:
if player_morale >= roll(20) or player_morale == 18
morale_check_success = true
You enter the apartment. As you marvel at the design of the living room, he disappears towards the bedrooms. "Let me know if you find my grandmother's ring," he hollers.
else
morale_check_success = false
You freeze with shame. Without a word, you turn around and leave.
endif✅ For safety, explicitly set the variable to
falsein theelsebranch, even iffalseis also its initial value.
Complete element content
So, the complete element content is now:
Horace Linetti opens the door and lets you in.
if shower_taken
"You're late!" he says.
else
"Good Lord! You smell as if you've spent the night on an office floor," he says, fanning the air with his hand.
player_morale = player_morale - 2
endif
if player_morale >= roll(20) or player_morale == 18
morale_check_success = true
You enter the apartment. As you marvel at the design of the living room, he disappears towards the bedrooms. "Let me know if you find my grandmother's ring," he hollers.
else
morale_check_success = false
You freeze with shame. Without a word, you turn around and leave.
endifBranch the outputs
After this element, add a branch that evaluates the morale_check_success variable and diverts the flow accordingly:
- If
true→ You continue to the living room. - If
false→ You walk away.
✅ Test it in Play Mode with Debug mode turned on so you can watch the variables update in real time. Try it both with and without showering to confirm both outcomes work as expected.
Reset variables on restart
If your project has restart jumpers (see Add restart jumpers in Part 9), be careful: once your project has several variables, jumping straight back to the start without resetting them can cause the story to behave incorrectly. (The Restart button in Play Mode's menu already resets all variables and visits.)
Not every variable should be reset, though. For example, a variable that counts how many times the player has died should usually persist across restarts, since that's the entire point of tracking it. In this project, however, we want a clean slate every time, so in the story's starting element we reset:
morale_check_success: No need to reset; it gets recalculated before it's used.player_morale: No need to reset; it gets recalculated before it's used.shower_taken: Reset tofalsering_state: Reset to0has_key: Reset tofalse
Since resetting the first two variables does no harm, you can reset all of them at once: add ${ resetAll() } at the top of the starting element's content. resetAll() resets every global, board, and component variable to its initial value; to keep some of them unchanged, pass them as arguments, e.g. resetAll(player_morale). It does not reset element visits; use resetVisits() for that.
Simplify unnecessary branches
Branches are useful when they affect the flow of the story or the player's available actions. They're overkill, however, when their only job is to change which text gets rendered; that's a job for code inside an element instead.
In the bathroom, for example, there is a branch diverting to two nearly identical elements. Their only difference is the displayed text depending on whether the player has picked up the key. We can simplify this by merging the two elements into one and using Arcscript in the element's content to create conditional text:
Two identical mirrors over two identical sinks. You wonder whether the siblings have to do everything simultaneously.
if !has_key
Hey, wait a second. These two mirrors are not positioned fully flat on the wall. They actually... When you stand at the centre of the room, they both reflect the same corner: the top part of the door.
endifAfterwards, we need to fix the option of examining the door, so it doesn't happen again and again. Add a new branch after the above element that checks whether the player already has the key:
if not has_key→ Go to the element where the key is found.
✅ The branch only has an
ifstatement. If the player already has the key, there is no other option than to go back.
Play through this section again to confirm that examining the mirrors behaves correctly whether or not the player has already found the key.
Adding a project cover
As a final polishing touch, let's give the project a cover image:
- Exit the project by clicking the Workspace icon at the top left of your window.
- Find your project thumbnail in the list, click the three dots •••, and select Upload cover.
- Select an image from your drive and upload it.
Your project now has a cover, which will be shown in your project list and when sharing the project with others.
What's next
This project is now finished! The following pages and their videos demonstrate more features, the next one being importing & exporting projects in a Pro or Team workspace.