Describe render layers and overlay cameras (#302)

- Concepts: a section on render layers, Sees and Overlay, and why z
  never sorts across cameras.
- API: the fields renderLayers, renderLayer, sees and overlay.
- Architecture: renderLayers in the model, the overlay views in
  WorldViewport.
- Development: e2e total 1720.
admin committed 2026-10-03 15:33:09 +02:00
1 parent d36fc4ad1c
commit e3775c2ae9
4 files changed
+31 -6

No files matched your search

+4 -1
@@ -54,7 +54,10 @@ has no switch of its own and hands out every plugin file it has.
The named collision layers are the project's field `collisionLayers` (#152), a list of up to 16
names of which the first one is layer 0. A project file without it has the single layer *Default*,
which is what every collider is on, so the field needs no format bump either.
which is what every collider is on, so the field needs no format bump either. The render layers
(#302) are the field `renderLayers`, read by the same rules; an object names one in `renderLayer`
(-1 for *Inherit*), a camera the ones it shows in the mask `sees` and whether it is an overlay in
`overlay`.
Every project document carries `formatVersion` (`PROJECT_FORMAT_VERSION` in `core/model/Project.ts`,
currently 2). There are no load-time migrations: `serialize.ts` reads what it recognises and drops
+4 -2
@@ -119,7 +119,7 @@ web/index.html Vite source page (dev) index.html built page
web/play.html a released game (#266) play.html built page (generated, served)
src/main.ts, play.ts the two entries; page.ts is the canvas both are (the WebGL context, root, resize)
src/core/model/ Project (object holders), Asset + AssetTypes, SceneObject (and what a list calls one:
`objectName`, `groupName`), Properties (value types, and the walks over a nested value: `mapNested`, a struct field taken out or renamed), hierarchy, walk (generic parent/child walks), instance (container content resolved from its template), usages (where an asset is used), container (the cycle guard), placement (what may be dropped where), texture (frames, the slice grid, a frame's collision outlines), frameOutline (#193: a frame's outlines as a collider wears them, centred, a pixel to a unit, cut into pieces once per drawn list), traceCollision (#161: a frame's outlines read off its picture — the pixels from an alpha threshold on are solid, each 4-connected island is walked round along the pixel edges and cut down to a few corners without ever crossing itself; crumbs below 1 % of the frame drop out), generated (pictures that are drawn rather than uploaded, #185: the key `gen:<assetId>@<revision>`, the register of readers that tell the picture path an asset's canvas size and revision, and the `fingerprint` pixel art and vector art make their revision with), vectorart (#129: the canvas as a property, which ring is worth drawing, and the revision as a fingerprint of the drawing rather than a counter, a texture fill's picture included) + vectorPath (what a shape draws, as plain commands: closed rings fill, every ring strokes, a segment is a line while neither of its ends carries a handle; a paint resolved to sorted stops or the picture it names) + vectorPaint (#186: gradients and texture fills — where a paint lies when it is switched on, the colour between two stops, adding, moving and removing a stop, a paint moved with its shape, and the rule that a texture fill takes uploaded pictures only) + vectorBoolean (#187: union, subtract, intersect and exclude on the sampled outlines, each shape read by the even-odd rule; the result rings in the order Pixi's hole detection needs, every outline followed by its holes and preceded by the islands inside them) + vectorCurves (#208: every sampled point remembers its cubic and its `t`, so a run of result points along one cubic becomes that cubic again, cut with de Casteljau), pixelart (#130: the palette a picture is painted in, how the layers of a frame come together, the sheet of all frames, a frame id read as a cut of it, and the revision) + pixelCel (the file of one layer on one frame, and its SHA-256 name worked out in the browser) + pixelDraw (what the tools do to the indices: brush, line, rectangle, ellipse, fill, resize about an anchor, merge, a palette colour taken out) + pixelEdit (every edit of layers, frames and cels as a function from one state to the next), polygon (an outline checked, cut into convex pieces and clipped to a rectangle), tile (the three kinds and their block shapes, reading a tile's pictures, the animation step), autotile (which quarter tile a neighbourhood asks for, the 47/16 tiles a block produces, 1 for a plain tile), tilemap (the cells of a layer, which neighbours a cell is joined to, the cells a stroke or a rectangle covers), tilemapCollision (the solid cells of a map, drawn in or out by their tile's collision scale and merged into rectangles, one group per one-way angle and per surface (`tileMaterials`, #193), the outlined cells as polygons — an autotile's outlines cut into its quarters and pieced together per cell like its picture —, where one sits in the world, and which cells of a placed map a world rectangle can reach, in cells (`cellsWithin`, #184)), tilemapMemo (what a map's cells work out to, kept while they hold the same: a version per cell map compared cell by cell, since strokes paint in place), animation (which frame at time t, a row's value there, what a row may aim at, the players on an object; KeyRef and its lookups) + animationPreview (the root at a frame, written into copies), curve (#247: a drawn easing evaluated at t — each segment a cubic solved for t by bisection, held to its rules by `sanitizedCurve`: ends at 0 and 1, no point overtaking another, no handle past its neighbour — and which keys and `Lerp` nodes use one) + curvePresets (the built-in eases traced as curves, a segment halved only where it strays), graphLookup (what a graph sees of the project: behaviors to run, state machines to read, curves to ease along), structTypes (#253: Struct assets as types — every typed struct variable, struct field and `Pack`/`Expand` found and brought in line with its asset, a renamed field carried through every value first, the cycle rule), Scope (how long a shared value lives: per instance, one for the run, or one per scene and rebuilt with every scene that loads, #164 — for a state machine's current state and for the values of a Variables asset), collisionLayers (which colliders may meet: the project's named layers, a collider's layer and mask, and the one rule `layersMeet` the engine, Solids and the event pair search all answer by)
`objectName`, `groupName`), Properties (value types, and the walks over a nested value: `mapNested`, a struct field taken out or renamed), hierarchy, walk (generic parent/child walks), instance (container content resolved from its template), usages (where an asset is used), container (the cycle guard), placement (what may be dropped where), texture (frames, the slice grid, a frame's collision outlines), frameOutline (#193: a frame's outlines as a collider wears them, centred, a pixel to a unit, cut into pieces once per drawn list), traceCollision (#161: a frame's outlines read off its picture — the pixels from an alpha threshold on are solid, each 4-connected island is walked round along the pixel edges and cut down to a few corners without ever crossing itself; crumbs below 1 % of the frame drop out), generated (pictures that are drawn rather than uploaded, #185: the key `gen:<assetId>@<revision>`, the register of readers that tell the picture path an asset's canvas size and revision, and the `fingerprint` pixel art and vector art make their revision with), vectorart (#129: the canvas as a property, which ring is worth drawing, and the revision as a fingerprint of the drawing rather than a counter, a texture fill's picture included) + vectorPath (what a shape draws, as plain commands: closed rings fill, every ring strokes, a segment is a line while neither of its ends carries a handle; a paint resolved to sorted stops or the picture it names) + vectorPaint (#186: gradients and texture fills — where a paint lies when it is switched on, the colour between two stops, adding, moving and removing a stop, a paint moved with its shape, and the rule that a texture fill takes uploaded pictures only) + vectorBoolean (#187: union, subtract, intersect and exclude on the sampled outlines, each shape read by the even-odd rule; the result rings in the order Pixi's hole detection needs, every outline followed by its holes and preceded by the islands inside them) + vectorCurves (#208: every sampled point remembers its cubic and its `t`, so a run of result points along one cubic becomes that cubic again, cut with de Casteljau), pixelart (#130: the palette a picture is painted in, how the layers of a frame come together, the sheet of all frames, a frame id read as a cut of it, and the revision) + pixelCel (the file of one layer on one frame, and its SHA-256 name worked out in the browser) + pixelDraw (what the tools do to the indices: brush, line, rectangle, ellipse, fill, resize about an anchor, merge, a palette colour taken out) + pixelEdit (every edit of layers, frames and cels as a function from one state to the next), polygon (an outline checked, cut into convex pieces and clipped to a rectangle), tile (the three kinds and their block shapes, reading a tile's pictures, the animation step), autotile (which quarter tile a neighbourhood asks for, the 47/16 tiles a block produces, 1 for a plain tile), tilemap (the cells of a layer, which neighbours a cell is joined to, the cells a stroke or a rectangle covers), tilemapCollision (the solid cells of a map, drawn in or out by their tile's collision scale and merged into rectangles, one group per one-way angle and per surface (`tileMaterials`, #193), the outlined cells as polygons — an autotile's outlines cut into its quarters and pieced together per cell like its picture —, where one sits in the world, and which cells of a placed map a world rectangle can reach, in cells (`cellsWithin`, #184)), tilemapMemo (what a map's cells work out to, kept while they hold the same: a version per cell map compared cell by cell, since strokes paint in place), animation (which frame at time t, a row's value there, what a row may aim at, the players on an object; KeyRef and its lookups) + animationPreview (the root at a frame, written into copies), curve (#247: a drawn easing evaluated at t — each segment a cubic solved for t by bisection, held to its rules by `sanitizedCurve`: ends at 0 and 1, no point overtaking another, no handle past its neighbour — and which keys and `Lerp` nodes use one) + curvePresets (the built-in eases traced as curves, a segment halved only where it strays), graphLookup (what a graph sees of the project: behaviors to run, state machines to read, curves to ease along), structTypes (#253: Struct assets as types — every typed struct variable, struct field and `Pack`/`Expand` found and brought in line with its asset, a renamed field carried through every value first, the cycle rule), Scope (how long a shared value lives: per instance, one for the run, or one per scene and rebuilt with every scene that loads, #164 — for a state machine's current state and for the values of a Variables asset), collisionLayers (which colliders may meet: the project's named layers, a collider's layer and mask, and the one rule `layersMeet` the engine, Solids and the event pair search all answer by), renderLayers (#302: which cameras see an object — tLine truncated
src/core/properties/ PropertySchema, kinds (one row per value kind), listItems (an item's kind, read off its value), resolve (the only override merge), deviation (what is gold), collider/camera/bounds geometry, clip (the region clip areas cut each object to, a convex polygon, #260) (with the side a one-way collider blocks from, and the rectangle around a shape a broad phase looks at first, #184), convex (capsules and polygons: rounded convex pieces against each other), ray (where a ray meets a shape, in double precision), rigidbody (what the engine reads off a rigidbody, a collider's material and the scene), joint (what it reads off a joint: its settings, where its far end is, its length and a hinge's limits, #154), aspect, enabled, editorRun, assetRef/textureRef (how a reference reads), declaredRows (the row a Property node declares in a shader or particle graph, and the params that node has in both)
src/core/util/ list (take out, put back and move an item — what a command's undo is made of), vec (dot, the closest point on a segment — shared by the collider maths, the outline hit area and the polygon grips; a cubic Bezier at `t` and cut in two at `t` — shared by vector art, its Boolean operations and the curve grips), color (`mixColor`, channel by channel — keys of an animation, stops of a gradient, the particles' Mix colour), recorder (#253: assignments taken back last first — the undo of an edit whose reach is not known in advance)
src/core/commands/ undoable commands (pixelArtCommands: one command runs any pixel art edit and keeps the state before it, #130), CommandStack, SetBagValueCommand base, RenameCommand base (undone by renaming back: variable, struct field, port), MoveCommand base (undone by moving back: tile picture, tilemap layer, vector shape), vectorArtCommands (#129: the shapes of a drawing, one gesture one command), one import command shape for texture/font/sound, require.ts (validated lookups, and what an instance may not change), naming.ts
@@ -172,7 +172,9 @@ src/ui/ widget toolkit (generic, knows nothing about assets); fon
on its own: a symbol the Latin subset lacks is never written as a character, #214); SortableList + sortable (the layer list of every editor that has one: rows dragged into order, eye, duplicate, cross, rename in place; the index arithmetic of a list shown upside down, kept apart so it is measured without a canvas)
src/viewport/ WorldViewport (the drawing of a world or a holder, the base of every view; it draws from
a `ViewSource` — the project and word of a change — so a released game draws without the
editor, #266), gamePointer (the mouse handed to a running world), projectFiles (the file
editor, #266; a view through a camera keeps only what that camera `Sees` and lays one
see-through view per overlay camera over itself, each handed its view and frame and
drawn like any other, #302), gamePointer (the mouse handed to a running world), projectFiles (the file
libraries pointed at the server, and what a project names fetched ahead),
fullscreen + FullscreenCorner (the browser's Fullscreen API, when the corner button shows,
and the button itself, shared by the Game tab and the released game, #267),
+22 -2
@@ -40,6 +40,26 @@ one, so switching it off hands the view to the next; with none on the tab stays
shows what Play would show, minus the editor symbols. Play has no built-in behaviour (no input,
no movement): everything that happens is defined by behavior graphs.
**Render layers and overlay cameras** (#302). A project has up to 16 named **render layers**,
edited in *Project settings…* next to the collision layers and kept apart from them: what meets
and what is seen are two questions. Sprites, texts, tilemaps, particle sources and containers
carry a **Render layer** row under their switches. Its default *Inherit* puts the object on its
parent's layer, and at the top on the first one, so a HUD container on `UI` takes everything in
it along. A camera's **Sees** ticks the layers it shows, all of them by default. A camera with
**Overlay** switched on is never the main camera; every overlay camera that is switched on draws
over the main one, in hierarchy order, see-through. Each camera draws a picture of its own: only
its layers, sorted by `z` among themselves. The pictures are then laid on top of each other, so
`z` never sorts across cameras. A sprite of an overlay camera at `z` -1 lies above a sprite of
the main camera at `z` 0. Something meant to lie *below* the world goes to a camera of its own
that is made the main one, with the game camera as an overlay. The main camera decides the size
of the picture and the zoom of the tab; an overlay camera is fitted into that picture without
distortion, so one of the same size and zoom covers it exactly. The mouse is reported through the
main camera (#304 is about asking another). Two cameras switched on without *Overlay* draw as
before: through the first one only. The Scene tab shows every layer.
Measured in the checks (step 63): a green sprite of an overlay camera at `z` -10 covers a red one
of the main camera at `z` 1000, a `UI` sprite in front of the main camera and a `Default` one in
front of the overlay stay away, and the same holds in the running game.
**A clip area cuts what is below it** (#260). It is an object of its own (*Clip area*, `+`
menu) with a `width` x `height`, and it turns, scales and mirrors with its parent like a sprite.
Everything parented below it, at any depth, is drawn only inside its rectangle, in the Scene tab
@@ -171,8 +191,8 @@ notice line, the save status, the frame rate and the **Account** menu. What the
out lives in the menu now: the project list in *Open project…*, the project name, the
**start-scene switch** (*Start scene* / *Active scene*, see **Start scene**), the **While playing**
preset (see above), the **Link zoom** of the released game (see above), the **symbol scale**
of the scene view's icons (see [Scene editing](Scene-editing)) and the collision layers in
*Project settings…*. A project is deleted in *Open project…*: **Delete** asks first, and Cancel, Esc
of the scene view's icons (see [Scene editing](Scene-editing)), the collision layers and the
render layers in *Project settings…*. A project is deleted in *Open project…*: **Delete** asks first, and Cancel, Esc
and the deletion itself all lead back to the project list. The active scene is picked where the scenes are — by double-clicking
one in the **Assets** panel. The **Assets** panel's `+` creates an asset and opens its tab; its menu lists the types in
two alphabetical groups, first what can be placed into a scene, then what only lives in the library
+1 -1
@@ -18,7 +18,7 @@ php tests/php/accounts.test.php # the API's accoun
# has and the web server's container has not (SKIP there)
php tests/php/snapshots.test.php # the snapshot store (#231), the same way
php tests/php/releases.test.php # the release store (#266), the same way
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1716 editor checks, screenshots in /tmp/gm-e2e-*.png
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1720 editor checks, screenshots in /tmp/gm-e2e-*.png
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step
./e2e.sh start [GM_STEPS] # the same run detached, see below
./e2e.sh status # live progress, or the last run's result