From e3775c2ae9746d06b98520f2483abf69030edf4a Mon Sep 17 00:00:00 2001 From: meleki Date: Sat, 3 Oct 2026 15:33:09 +0200 Subject: [PATCH] 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. --- API.md | 5 ++++- Architecture.md | 6 ++++-- Concepts.md | 24 ++++++++++++++++++++++-- Development.md | 2 +- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/API.md b/API.md index c1e2ca7..e8b6fe8 100644 --- a/API.md +++ b/API.md @@ -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 diff --git a/Architecture.md b/Architecture.md index c2900eb..edf6107 100644 --- a/Architecture.md +++ b/Architecture.md @@ -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:@`, 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:@`, 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 — the project's named render layers, an object's own choice or its parent's, a camera's `Sees` and `Overlay`) 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), diff --git a/Concepts.md b/Concepts.md index 1ac00a5..a3ed4c4 100644 --- a/Concepts.md +++ b/Concepts.md @@ -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 diff --git a/Development.md b/Development.md index 7e94ab0..9d3c44c 100644 --- a/Development.md +++ b/Development.md @@ -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