Skip to content

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 ​

ActionControls
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:

json
"categories": {
  "characters": {
    "entries": ["player"],
    "expanded": true
  },
  "backgrounds": {
    "entries": ["backgrounds/blueLand"]
  }
}
PropertyDescription
entriesThe prefabs in this category. See below for the forms it can take.
extendsA prefab every entry extends, unless the entry already has its own extends.
expandedOpen the category when the editor starts.
imageThe image shown for the category. Defaults to the first entry.
showLabelsShow 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 a blueLand prefab with imagePath backgrounds.
  • A numbered name, like "tile_1#12", for tile_1 to tile_12. If a prefab named tile_ exists, they all extend it.
  • A folder, like "level_[editorImages]", for a prefab for every image in public/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:

ts
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.

  1. Its own settings and level. mapData.json is a separate settingsData.json for the map, and levels/map.json is the map itself.

  2. A prefab for every level. The map's category uses "level_[editorImages]", so every image in editorImages becomes a placeable level. Each one extends a level prefab with "texture": "NAME", so it shows its own image.

  3. Opening it. MapHandler processes mapData.json with its own SettingsHandler, and adds a Map Editor button and a debug action that open the editor with that level and settings:

    ts
    await bare.scene.Add(EditorScene, {
        levelPathOrData: "data/levels/map.json",
        settingsHandler: this.mapSettingsHandler,
    });
  4. An editor component. Every level on the map has a LevelConnectorComponent with @Run(GameMode.Edit). When you drag levels next to each other, it finds its neighbours, draws a line to them, and saves them in @Save fields top, right, bottom and left. Hovering a level shows its name, and clicking it opens that level in the editor.

  5. Using the result. The game reads the saved map to know where each exit leads, and updates it on BareEvent.level_savedToDisk when you save the map.

  6. Previews. Whenever a level is saved, the RPG's SnapshotHandler renders it to an image in editorImages, 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:

ts
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:

ts
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.

Bare Engine is open source under the MIT license.