"In-app tutorial" is the term used in the codebase for GDevelop. It is displayed "guided lesson" in GDevelop editor. Each term designates the same thing.
To display the tutorial with different languages, every text that you will specify has to be an object messageByLocale
with locales as keys and the translated sentence as value.
For example, this will be the description of a tooltip:
{
...,
"description": {
"messageByLocale": {
"en": "Click on the button",
"fr-FR": "Cliquez sur le bouton"
}
}
}
Note: If the user language is not available, it will fallback to english.
An in-app tutorial is a JSON with 7 fields:
{
"id": "physics2-joints",
"flow": [...],
"editorSwitches": {...},
"endDialog": {...},
"availableLocales": [...],
"initialTemplateUrl": "https://...",
"initialProjectData": {...},
"titleByLocale": {...},
"bulletPointsByLocale": {...},
}
This id is a string that should be unique across all in-app tutorials.
This is the list of locales for which a translation is available. This can be displayed to the GDevelop user before following the tutorial.
This field holds the content for the dialog that will displayed after the user has completed the last step of the flow.
It's a field that contains an array under the content
key.
The array contains either:
-
an image (that can be clickable if
linkHref
field is provided){ ..., "endDialog": { "content": [ ..., { "image": { "imageSource": "https://resources.gdevelop-app.com/...", "linkHref": "https://gdevelop.io" } ] } }
-
a text
{ ..., "endDialog": { "content": [ ..., { "text": { "messageByLocale": { "en": "you made it until the end of the tutorial!" } } } ] } }
A flow is an array of steps or meta steps.
A step is more or less an element to highlight plus a trigger that can be detected programmatically to decide to go to the next step.
Here is the structure of a step (all fields are optional):
id
(string): id of the step (useful for shortcuts and editor switches)elementToHighlightId
(string): the CSS selector of the element to highlightnextStepTrigger
: see Triggerstooltip
: see Tooltipdialog
: A dialog to display with the same structure as the the end dialogdeprecated
(true): Useful to discard a step that is not useful anymore in order to not change the count of step of the tutorial and impact progress save on user side.isCheckpoint
(true): Useful to divide a tutorial in different part. When there are checkpoint steps, the notion of progress is part-based.isTriggerFlickering
(true): useful when a DOM mutation is not caught and the presence trigger is not fired.shortcuts
: list of steps that the flow can use as shortcuts.stepId
: id of the step to jump totrigger
: DOM trigger (presence of absence of element) or objectAddedInLayout trigger.
skippable
(true): if the step can be skipped (useful when the user interaction can result in this step not being mandatory)isOnClosableDialog
(true): if the step is on a closable dialog, if the element to highlight is missing (meaning the dialog has been closed), the flow will go back to the previous step that is not on a closable dialog.mapProjectData
(object): allow to read data in the GDevelop project object and store it during the duration of the tutorial. This data can then be used in the tooltips. See Available Project Data
At the moment, only one trigger can be specified to go the next step. Here is the list of supported triggers:
presenceOfElement
(string): the CSS selector of an element present in the DOM or a custom selectorabsenceOfElement
(string): the CSS selector of an element absent from the DOM or a custom selectorvalueHasChanged
(true): the CSS selector of an input whose value has changedvalueEquals
(string | boolean): the CSS selector of an input whose value is equal to the string:- for numbers, it has to be a string (ex: "2")
- for booleans (checkboxes), use booleans (ex: true)
objectAddedInLayout
(true): an object has been added to the scene (from scratch, duplication or the asset store)instanceAddedOnScene
(string): the name of an object for which an instance has been added on the sceneinstancesCount
(number): the number of instances that should be present on the scene (to be used withinstanceAddedOnScene
)
previewLaunched
(true): a preview has been launchedclickOnTooltipButton
(messageByLocale
object): the label of the button displayed in the tooltip that the user has to click to go to the next step.editorIsActive
(stringscene:editor
): to detect when a user switched editorsscene
is optional (if your tutorial only requires a single scene, no need to specify it). In that case, you can write:EventsSheet
if you want to check the user is on the events sheet.- The editor possible values are the same as for the editor switches.
- The scene is the key under which the scene name has been stored.
Notes:
- You can learn about CSS selectors here.
Custom selector
There are a few custom selectors that you can use:
objectInObjectsList:enemy
: to select an object in the objects list in the scene editorsceneInProjectManager:playScene
: to select a scene in the scene list in the project managerobjectInObjectOrResourceSelector:enemy
: to select an object in the objects list that appears when opening the instruction editoreditorTab:playScene:Scene
: to select the tab of an editor. The scene name is optional so if you don't need it, useeditorTab::Scene
.
Project data is read when the step is complete. Here is how to construct mapProjectData
:
- For each item of the object:
- the key of the object is the string under which to store the data
- the value is the "data accessor"
- At the moment, here are the available data accessors:
projectLastSceneName
that will read the name of the last scene added to the project.sceneLastObjectName:scene
that will read the name of the last object added to the scene (scene is optional, if you don't mention it, the first project scene is used)
Example: This will store the name of the last object added to the project under the key firstObject
:
{
...,
"mapProjectData": {
"firstObject": "projectLastSceneName",
}
}
For each step, you can specify a tooltip to display next to the element you want to highlight. A tooltip contains the 3 following fields:
title
: (optional) Translated textdescription
: (optional) Translated textplacement
: The placement of the tooltip relatively to the element to highlight. Either one of those values:bottom
,top
,left
,right
(default valuebottom
)
Notes:
- At least one field among
title
anddescription
should be provided. If you don't want to display a tooltip, do not provide thetooltip
field in your step. - To use data stored with
mapProjectData
, include the placeholder$(...)
in your text.- For example, the description
"Drag $(firstObject) to the scene"
will be displayed"Drag Platformer to the scene"
.
- For example, the description
- You can also use a function that will display dynamic data in your tooltip texts. Available functions:
- Use
$(instancesCount:firstObject)
to display the number of instances on the scene of the object saved under the keyfirstObject
.
- Use
The orchestrator detects when the user went into an editor (either the home page, a scene editor or an events sheet) that does not allow the tutorial to be continued.
For this to work, you must provide the editor switches that happen during your tutorial. Here is how to do it:
If your flow contains a step with id ClickOnCreateObjectButton
(that should happen in the scene editor) and another step ClickOnAddEventButton
(that should happen in the events sheet for scene playScene
), here is what the field should look like:
{
...,
"editorSwitches": {
{
"ClickOnCreateObjectButton": { "editor": "Scene" },
"ClickOnAddEventButton": { "editor": "EventsSheet", "scene": "playScene" },
}
}
}
Notes:
playScene
is either:- the key under which the name of the scene has been stored during the tutorial.
- the key under which the name of the scene is defined in the field
initialProjectData
.
- The possible values for the expected editor are:
Scene
,EventsSheet
,Home
(other editors are not supported at the moment).
If the tutorial does not start from scratch, we can provide a template URL to download the project from with initialTemplateUrl
. This should match the URL of the template in the GDevelop templates S3 bucket (https://resources.gdevelop-app.com/in-app-tutorials/templates/{gameName}/game.json)
This template should be available inside the templates
folder, with the same name as the tutorial. It will get deployed to the S3 bucket when merging to master.
Inside the app, when a tutorial is running, all objects or scenes added are tracked, so they can be re-used.
However, if we start from a template, we need to know which objects or scenes are already present so they can be tracked.
Ideally, we should be able to detect them automatically, but for now, we need to provide the list of objects and scenes that are already present in the template.
To do so, we can provide the initialProjectData
field.
Ex:
{
...,
"initialTemplateUrl": "https://resources.gdevelop-app.com/in-app-tutorials/templates/plinkoMultiplier/game.json",
"initialProjectData": {
"gameScene": "GameScene",
"multiplier": "Multiplier",
"particles": "PegStar_Particle"
},
}
These fields are used in the small dialog displayed after clicking on the guided lesson card.
We're introducing meta steps to speed up the process. These meta steps should handle particular situations that are not interesting to the tutorial designer and will also bring consistency across tutorials.
At the moment, there are 2 meta steps available (both are used in the joystick
tutorial):
- LaunchPreview
- AddBehavior
TODO: add documentation about how to use those steps.
In the meantime, you can check how both are used in the joystick
tutorial and discover the available fields in the types declaration.
Available in GDevelop desktop app only.
Starting from version 5.4.202, you can load your in-app tutorial from your computer to try it.
To do so, go to your preferences, in the section "Contributor options", activate the toggle "Show button to load guided lesson from file and test it.".
Once this is done, a new button "Load local lesson" should appear in the homepage's learn tab, above the guided lessons section. Select your JSON file and complete your lesson!
Notes:
-
The editor will perform a basic schema check before actually running the tutorial.
- If errors are found, please open the developer console, they will be listed there.
- The check is not exhaustive.
-
If your in-app tutorial is using an initial template, make sure to have it opened before loading the tutorial.
-
If you are using meta steps in your tutorial, you need to first run the build command:
npm run build -- --gdevelop-root-path=/path/to/GDevelop/repository
Then select the json file generated in the folder
dist/tutorials
.
If you can use ChatGPT, you can easily have a basic translation for your tutorial. To do so, for each object with a en
key, you should add all needed locale keys and then you can ask ChatGPT to translate it.
For instance, if you have the following:
"messageByLocale": {
"en": "Click on this button"
}
Transform it to this:
"messageByLocale": {
"en": "Click on this button",
"fr": "",
"de": "",
"es": "",
"th": "",
...
}
And the ask the following to ChatGPT:
Given this JSON, can you add translations for the empty fields corresponding to the keys that represent the locale to translate to?
{COPY PASTE THE JSON}
Some tests are run in our Continuous Integration (CI) pipeline when you open a PR. You can run them on your device to make sure your in-app tutorial passes the checks.
Prerequisites:
- Clone GDevelop repository on your computer and run
npm install
in the foldernewIDE/app/
.
To do so, in a terminal:
- install the project: at the root of the repository, run
npm install
- Build the tutorials: run
npm run build -- --gdevelop-root-path=/path/to/GDevelop/repository
- Run the tests: run
npm run check-post-build
- Read the output to see if your in-app tutorial passes the tests.
You should follow those steps if you want your in-app tutorial to be integrated in GDevelop's interface.
Open a new PR in GDevelop's repository and:
- In the file
InAppTutorial.js
:- add your tutorial id in a constant and add it to the list
guidedLessonsIds
. - if applicable, add your tutorial id in the list in the function
isMiniTutorial
.
- add your tutorial id in a constant and add it to the list
- In the file
GuidedLessons.js
, add an item in the listguidedLessonCards
with all the fields (you should have a SVG file to use in the card).