Tutorial 2 - Note Taking - WorkAdventure Documentation
Tutorial 2 - Note Taking - WorkAdventure Documentation
Recent posts
This tutorial shows you how to take notes as an admin and leave it to read for other users.
Preparation
Make sure your map was built on the WorkAdventure Starter-Kit in order to have a ready to use API
1. Create a variable on the map that can store the text of the note we want to display
2. Design a web page that will display the note
3. Open and close this web page (as an iframe) when someone walks near the note post
To implement a proper note-taking system, we will rely on WorkAdventure scripting API. The scripting
API allows you to write Javascript / Typescript code that will be executed in the browser of each player.
Of course, when I write a note on the map, I want other users to see this note when they are coming in.
To do so, we will use a feature of the scripting API called "variables". Variables are used to hold the
"state" of the map. The state is a key/value store that is shared between all players. When a player
changes the state, all other players are notified of the change.
We will create a variable attached to the map named noteText that will contain the text of the note.
Create a new object point called noteText . Give it the class name variable and add a custom
property of the type boolean and name it persist . Add a check.
INFO
persist is used to make sure that the variable is saved on WorkAdventure servers. If you don't
set this property, the variable will be lost as soon as the last user leaves the map.
Now add a new layer and call it visibleNote . Place a tile where you want the note to be visible.
Make sure you have a src folder in your map repository. You can also use this Github Repo as a
reference.
There should be a main.ts file here. If not, create the main.ts file.
Then click in the Navigation on Map then Map Properties and make sure there is an existing script
property and that is points to src/main.ts .
This will start a local web server on port 3000. You can access it at http://localhost:3000.
Now, let's create our note.html file. Create a new file in the src folder and name it note.html .
src/note.html
<!DOCTYPE html>
<html lang="en">
<head>
<style>
body {
background-color: white;
}
textarea {
width: 100%;
height: 100px;
}
pre {
text-align: center;
}
</style>
</head>
<body>
<div id="editSection">
<div>
<textarea id="noteTextArea"></textarea>
</div>
<div>
<button id="saveButton">Save</button>
</div>
</div>
<pre id="displayText"></pre>
</body>
</html>
We could certainly do a way better job at styling this page, but this is not the point of this tutorial.
We need to tell Vite that this file exists. To do so, we need to edit the vite.config.ts file. This file is
used by Vite to know which files to compile.
vite.config.ts
// ...
export default defineConfig({
// ...
build: {
rollupOptions: {
input: {
index: "./index.html",
note: "./note.html",
...getMapsScripts(maps),
},
},
},
// ...
});
Let's check that everything is working fine. Open your browser at http://localhost:3000/note.html. You
should see the note page.
src/main.ts
WA.room.onEnterLayer("visibleNote").subscribe(async () => {
console.log("Entering visibleNote layer");
});
WA.room.onLeaveLayer("visibleNote").subscribe(() => {
noteWebsite.close();
});
export {};
The WA.onInit() function is called when the scripting API is ready. This is the entry point of our
code.
The WA.room.onEnterLayer("visibleNote") and WA.room.onLeaveLayer("visibleNote")
functions are called when the player enters or leaves the visibleNote layer.
The WA.ui.website.open() function opens a new website in an iframe.
Iframes opened via the WA.ui.website object are relative to the "viewport". This means you
can decide where the iframe will be displayed on the screen (top-left, bottom-right, middle,
etc.) using the position option.
You can of course also decide the size of the iframe. Units are expressed in CSS units. We
recommend using vh and vw units that are relative to the viewport size (30vh = 30% of the
viewport height).
The allowApi option allows the website to use the scripting API. It is very important to not
forget this one. Indeed, the "note.html" page will need to use the scripting API to read and write
the note text.
The url parameter can be a full URL (starting with http:// or https:// ) or a relative URL.
In case of a relative URL, it is relative to the map URL. Because our map and the note.html
are in the same directory, we can simply write ./note.html .
The WA.ui.website.open() function returns a Promise that resolves to a UIWebsite
object. This object has a close() method that can be used to close the website. We call this
close() method when the user leaves the visibleNote layer.
The first thing we need to do is to add 2 <script> tags to the note.html file. One will load the
WorkAdventure scripting API. The other one will point to our code.
src/note.html
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... -->
<script src="https://play.workadventu.re/iframe_api.js"></script>
<script type="module" src="src/note.ts"></script>
</head>
<body>
<!-- ... -->
</body>
</html>
NOTE
If you are using a self-hosted version of WorkAdventure, you will want to replace the
play.workadventu.re domain with your own server's domain.
Now, create a file called note.ts in your src folder with the following code:
src/note.ts
export {};
We use the WA.state object to read and write the noteText variable. Remember that this variable
is shared between all players. So if a player modifies the variable, all other players will see the new
variable value when they open the page.
When the map is loaded and no variable has been set yet, the WA.state.noteText variable will be
undefined . We use the ?? operator to set the value to an empty string in this case.
Also, a variable can hold any kind of (serializable) value. Typescript does not know that the
noteText variable is a string. We use a type assertion to tell Typescript that we know what we are
doing.
INFO
If we wanted to be technically exact, we should force checking that the noteText variable is
indeed a string.
Something like:
We use the addEventListener function to listen to the click event on the saveButton button.
When the button is clicked, we save the note text in the noteText variable.
Let's add some authorization checks to make sure that only users with the admin tag can modify the
note text.
The WA.player object contains information about the current player. In particular, it contains the list of
tags of the player in the tags property.
We will use this tags property to check if the player has the admin tag.
src/note.ts
//...
if (WA.player.tags.includes("admin")) {
displayText.style.display = "none";
noteTextArea.value = (WA.state.noteText ?? "") as string;
saveButton.addEventListener("click", () => {
WA.state.noteText = noteTextArea.value;
});
} else {
editSection.style.display = "none";
displayText.innerText = (WA.state.noteText ?? 'No messages left') as string;
}
export {};
We add a editSection variable that points to the <div> containing the edit section of the page.
We add a displayText variable that points to the <div> containing the text of the note.
We add an if statement to check if the player has the admin tag. If the player has the admin tag,
we hide the displayText section and display the editSection section.
If the player does not have the admin tag, we hide the editSection section and display the
displayText section.
CAUTION
It is important to understand that anyone could modify the Javascript code of the page (using the
browser developer tools) to remove the authorization checks, or worse, change the value of the
noteText variable.
Even if your code makes it impossible for a normal non-admin user to edit the text, an attacker
with enough knowledge could still do it.
If you want to secure your noteText variable, you should edit the variable in the Tiled map, and
add a writableBy: admin property to the noteText variable object. When you do this,
WorkAdventure will perform security checks on the server-side to ensure that only users with the
admin tag can modify the variable.
ABOUT TAGS
Tags can be added to members of your world from the WorkAdventure dashboard.
The default self-hosted version does not have a dashboard, so does not have this "tags" feature.