Level Editor
Bare has a level editor built into the game. While the dev server runs, editor saves write to the level's JSON file through it. Check the browser console for save errors and review the resulting file changes in Git.
In a production build, the editor still works, but saves go to that browser's local storage instead of the project's files. Once a level has been edited there, it's loaded from local storage instead of its JSON file. The Level Editor button is not added there; see Level editor in production.
Saving from the editor differs from calling bare.level.Save() during gameplay; see saving destinations.
Opening the editor
When a scene has a level loaded, a Level Editor button appears at the top of the screen. If the Chrome extension is connected, the button is hidden and you open the editor from the extension instead.
You can change this with the showEditorButton and editorButtonPosition options of StartBare.
Example: the Platformer always shows the button.
Editing
| Action | Controls |
|---|---|
| Select an object. | Click |
| Select the deepest child under the pointer, instead of the whole object. | Alt + click |
| Add to the selection. Clicking an object that's already selected removes it. | Shift / Ctrl + click, or Shift + drag |
| Deselect. | Click an empty spot |
| Select objects whose bounds are fully inside the rectangle. | Drag on an empty spot |
| Select objects whose bounds overlap the rectangle, even partly. | Alt + drag on an empty spot |
| Select on all layers. | Ctrl + drag on an empty spot |
| Move, scale, rotate. | Drag the selection or its handles |
| Place it. | Pick a prefab, then click |
| Place off the grid; the grid is hidden while you hold Alt. | Alt + click while placing |
| Place multiple, with the grid on. | Shift while placing |
| Stamp copies of an object: each click places one, with all its edits. Right-click or double-click it again to stop. | Double-click an object |
| Toggle stamping. | S |
| Stop stamping. | Right-click an empty spot, or the Cancel button |
| Remove an object, or the whole selection when it's selected. | Right-click it |
| Delete the selection. | Delete |
| Copy, cut, paste. | Ctrl+C, Ctrl+X, Ctrl+V |
| Select all. | Ctrl+A |
Pick prefabs to place from the extension, and choose the layer you're editing there as well.
Grid
Turn on the grid and set its size with the ⚙️ settings button in the level editor. The settings are saved to settingsData.json.
By default, an object's pivot snaps to the grid lines. For tile-based games, set "editorObjectSnapToPivot": false at the top level of settingsData.json: objects then fill the grid cell under the pointer instead. The RPG does this.
Categories
The editor's sidebar groups your prefabs into categories. Set them up with categories in settingsData.json:
"categories": {
"characters": {
"entries": ["player"],
"expanded": true
},
"backgrounds": {
"entries": ["backgrounds/blueLand"]
}
}| Property | Description |
|---|---|
entries | The prefabs in this category. See below for the forms it can take. |
extends | A prefab every entry extends, unless the entry already has its own extends. |
expanded | Open the category when the editor starts. |
image | The image shown for the category. Defaults to the first entry. |
showLabels | Show names under the entries. On by default. |
An entry doesn't have to be a prefab yet: the editor creates a prefab for any name that doesn't exist. entries can be:
- A list of names, like
["player", "enemy"]. - A path, like
"backgrounds/blueLand". This creates ablueLandprefab withimagePathbackgrounds. - A numbered name, like
"tile_1#12", fortile_1totile_12. If a prefab namedtile_exists, they all extend it. - A folder, like
"level_[editorImages]", for a prefab for every image inpublic/images/editorImages.
Prefabs that aren't in any category are listed under uncategorized prefabs, or prefabs when you have no categories. Settings on an uncategorized category, like expanded, apply to that group. All loaded images are listed under images.
Example: the Platformer's categories.
Components in the editor
By default, your components don't run while you're editing, so enemies don't walk off while you place them. To make a component run in the editor too, use @Run:
import { Component, GameMode, Run } from 'bare-engine';
@Run(GameMode.Edit, GameMode.Play)
export class LabelComponent extends Component
{
// shows in the editor and in the game
}@Run(GameMode.Edit) makes a component that only exists in the editor, for example a helper that draws a range indicator. See Making your own tools for a full example.
Example: the Showcase's LevelConnectorComponent only exists in the editor. It shows which level each edge of a level leads to, and lets you click through.
Making your own tools
bare.editor returns the editor scene while it's open, and bare.levelEditorOpen tells you if it is. BareEvent.editor_opened and BareEvent.editor_closed fire when it opens and closes.
Together with @Run(GameMode.Edit) components, you can build editors for your own data on top of the level editor. An editor component is a normal component: it can draw, react to the pointer, read other objects and @Save its results into the level.
Example: the RPG's map editor
The RPG has a second editor for its world map: which level is next to which. It reuses the level editor, with a different level and different prefabs.
Its own settings and level.
mapData.jsonis a separatesettingsData.jsonfor the map, andlevels/map.jsonis the map itself.A prefab for every level. The map's category uses
"level_[editorImages]", so every image ineditorImagesbecomes a placeable level. Each one extends alevelprefab with"texture": "NAME", so it shows its own image.Opening it.
MapHandlerprocessesmapData.jsonwith its ownSettingsHandler, and adds a Map Editor button and a debug action that open the editor with that level and settings:tsawait bare.scene.Add(EditorScene, { levelPathOrData: "data/levels/map.json", settingsHandler: this.mapSettingsHandler, });An editor component. Every level on the map has a
LevelConnectorComponentwith@Run(GameMode.Edit). When you drag levels next to each other, it finds its neighbours, draws a line to them, and saves them in@Savefieldstop,right,bottomandleft. Hovering a level shows its name, and clicking it opens that level in the editor.Using the result. The game reads the saved map to know where each exit leads, and updates it on
BareEvent.level_savedToDiskwhen you save the map.Previews. Whenever a level is saved, the RPG's
SnapshotHandlerrenders it to an image ineditorImages, so the map always shows what the levels look like.
Level editor in production
Production builds don't add the Level Editor button, and showEditorButton and editorButtonPosition have no effect there. To show it, add EditorUIScene yourself once the game has started:
import { EditorUIScene } from "bare-engine";
await bare.scene.Add(EditorUIScene, { openEditorButtonPosition: { x: 1, y: 0 } });openEditorButtonPosition is optional and works like editorButtonPosition: a normalized position and pivot, so { x: 1, y: 0 } is the top right. It defaults to { x: 0, y: 0 }, the top left. The button stays across scene changes and is only visible while a level is loaded.
The button only opens the editor, so you can also open it from your own button or key while a level is loaded:
import { EditorScene } from "bare-engine";
bare.scene.Add(EditorScene);Players' edits are saved in their browser's local storage, as described at the top of this page.