From fa9e6a5540cb68565e5cb28122e0f8970d39d1d0 Mon Sep 17 00:00:00 2001 From: meleki Date: Wed, 23 Sep 2026 08:13:41 +0200 Subject: [PATCH] Describe the 500 weight and the SVG icons (#214) - Architecture: fonts load 400, 500, 600 and 700. Icons, markIcons and the chevron are described. - Development: tests find icons through __gm.locateIcons(id). - Behaviors, Scenes, Sounds: kind, scene and sound marks are described instead of written as glyphs. - Development: editor-suite check sum 1312. --- Architecture.md | 14 ++++++++++---- Behaviors.md | 5 +++-- Development.md | 12 +++++++++++- Scenes.md | 6 +++--- Sounds.md | 2 +- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Architecture.md b/Architecture.md index f46b106..cb24985 100644 --- a/Architecture.md +++ b/Architecture.md @@ -59,9 +59,10 @@ `labelToken()` and `measureToken()`, which a subclass overrides (`TabButton` draws and measures plain). The box behind the label is `drawBackground()`, likewise overridable: `TabButton` paints an index card there, rounded above and square below (#176). - The padding is an inset rather than a claim, so a 24 px icon button spends it on the glyph - instead of truncating it away; a button that switches between label forms (`↺` and `↺ ▾`) asks - for `minWidth` and grows. `__gm.textOverflows()` guards the whole class of bug: it reports any + The padding is an inset rather than a claim, so a 24 px icon button spends it on the icon + instead of truncating it away; a row action that switches between its plain and its menu form + (the reset picture alone, or with a chevron) asks for `minWidth` and grows by the chevron's room + (`trailingRoom()`, which `Dropdown` uses for its chevron too). `__gm.textOverflows()` guards the whole class of bug: it reports any visible text drawn wider than the widget owning it, `__gm.labelsDropped()` guards the other direction — a button too narrow to draw any of its label (e2e step 14). - **Vite + TypeScript**, **Vitest** for core, toolkit and editor logic. @@ -106,7 +107,10 @@ src/runtime/physics/ engine (loads Rapier once, reports its state, converts be normal, impulse and point; whether a dynamic body lands on or passes a one-way collider, decided before each step for the contact hook; the push a `Move` gives a dynamic body, and what the physics nodes reach through `NodeContext.physics`) -src/ui/ widget toolkit (generic, knows nothing about assets); 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/ui/ widget toolkit (generic, knows nothing about assets); fonts (the faces the editor ships: + Source Sans 3 in 400, 500, 600 and 700, Source Code Pro 400, Latin only, #202/#214), icons + + Icon (the menu's tick boxes and current-entry dot as SVG files, and a widget that shows one file + 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/ view (transforms), items (what to draw), symbols (how to draw it), symbolIcons (the SVG files in icons/, parsed once, in the theme's colours, #175), FileLibrary (load once, never retry a failure, tell the listeners) ← TextureLibrary, FontLibrary; @@ -169,6 +173,8 @@ src/editor/panels/ AssetPanel, assetGroups (groups by type and their order, assetMenu (the two groups of the + menu), HierarchyPanel, Toolbar + toolbarIcons (five icon buttons, no captions: menu, undo, redo, play, pause, #183), headerIcons (the pictures of the tab headers' switches: the magnet, #194), + markIcons (the kind marks, the row actions reset, apply and the two fit arrows, and a + transition's in/out arrow — they were characters the bundled font does not have, #214), TilemapPanel (tools, tiles and layers of the one selected tilemap, beside the scene view, #142; painting itself is SceneViewport) src/editor/graph/ GraphEditor (header, breadcrumb), GraphCanvas, graphView (zoom limits, grid, panAndZoom — shared with NodeBoard and the Tile tab's TileCanvas), EdgeLayer (curves and fold marks), graphMenus, diff --git a/Behaviors.md b/Behaviors.md index e6f9db2..bfc83e0 100644 --- a/Behaviors.md +++ b/Behaviors.md @@ -52,8 +52,9 @@ shown on the node and editable in the inspector. because no tab may reach into the `Editor` to switch itself on. An **unconnected `list` input** of a node is the same button and the same tab: its inline value lives in the very same params bag a setting does, and the slot stops resolving the moment an edge feeds the port. What an item holds - is **its own** and is chosen there: the **kind mark** in front of a row (`#`, `Aa`, `✓`, `◧`, `▦`, `⊞`) - is the picker — a click opens the menu, with no chevron, since the mark has to stay as narrow as + is **its own** and is chosen there: the **kind mark** in front of a row (`#` for a number, `Aa` for a text, a + small picture for every other kind: a tick for a boolean, a half-filled square for a color, a grid + for a texture, a square with a cross for a struct) is the picker — a click opens the menu, with no chevron, since the mark has to stay as narrow as its column — and `+ Item ▾` asks for the kind of the one it appends. Because the kind lives in the value, every such change is an ordinary **value edit**: one command, one undo step, and no neighbouring item touched. A **struct item** carries its own shape the same way: its fields are diff --git a/Development.md b/Development.md index 01b7ea1..0670780 100644 --- a/Development.md +++ b/Development.md @@ -13,7 +13,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs npm run build # writes dist/ and regenerates index.html ./build.sh # the same under `set -o pipefail`, for callers that pipe the output php tools/make-user.php # an account; every tool signs in (see Accounts) -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1310 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1312 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 @@ -121,6 +121,16 @@ the whole answer there, and no colour check can see an order. The node palette has the same property, and `__gm.graph.paletteRows()` is its witness: the rows all look alike, only their sequence says whether the search ranked them (#43). +**A symbol is a picture, so a step finds it as one** (#214). The reset and apply buttons, the fit +arrows, the kind marks, the tick boxes and the scene marks used to be characters, and `locate` +found them by that character. They are SVG files now, because the Latin font the editor ships has none of those glyphs. +A file that carries an `id` names its graphics `icon:`, and `__gm.locateIcons(id)` lists every +such picture on screen as `{ x, y, menu }`: `menu` says whether the button it sits on opens a menu. +In a step, `t.findIcon(id, menu)` and `t.clickIcon(id, menu)` do the same as `find` and `clickText`. +A menu's tick boxes are read through `t.menuTicked()` as `{ label, ticked }`. The unit test +`tests/ui/fonts.test.ts` reads the character map straight out of the font files and fails on any +character in `src/` that one of the shipped faces lacks. + **What no colour check can see: whether anything was drawn at all.** `__gm.pixelAt` re-renders the stage on demand, so it answers correctly on a screen that has been frozen for a minute — which is exactly the failure mode of drawing on change instead of every frame (see *Architecture*). The diff --git a/Scenes.md b/Scenes.md index 8e5561f..1f39206 100644 --- a/Scenes.md +++ b/Scenes.md @@ -6,13 +6,13 @@ Those are three different questions, and this page is about keeping them apart. The **active scene** is what the editor shows: the Scene tab draws it, the hierarchy lists it, a dropped asset lands in it. It is set by double-clicking a scene in the Assets panel, or through -*Set as active scene* in its context menu — the toolbar has no scene picker since #183. `●` marks +*Set as active scene* in its context menu — the toolbar has no scene picker since #183. A dot marks it in the list. Both ways stay open while a run is on: they only move the editor's view and never touch the running world. The **start scene** is where a run begins — the title screen, the first level, whatever a player would see first. It is named on the **project**, not on the scene asset: right-click a scene in -the Assets panel → **Set as start scene**. `▶` marks it, and the same place offers **Clear start +the Assets panel → **Set as start scene**. The play triangle marks it, and the same place offers **Clear start scene** to take the name back. A project that never names one has none, and then the two questions have the same answer. @@ -29,7 +29,7 @@ It stands in the settings dialog beside the project name and the collision layer belong to the project — the dialog is the one place these are edited, not the split it says. It is captioned with the mode it stands in — *Start scene* or *Active scene*, worded exactly like the entries of its own menu, so that what you picked and what you read back are the same words. -The start scene is marked `▶` in the Assets panel, the active one `●`. +The start scene is marked with the play triangle in the Assets panel, the active one with a dot. The point of the two modes is that a game with a title screen is otherwise tedious to work on: every run would begin at the title, three clicks away from the level you are editing. *Active diff --git a/Sounds.md b/Sounds.md index a600dea..d22a32b 100644 --- a/Sounds.md +++ b/Sounds.md @@ -9,7 +9,7 @@ file that fails does not stop the rest. The asset is named after the file ("jump an `.m4a` as `audio/mp4`, `audio/x-m4a` or as nothing at all. **+ → Sound** asks the other question and opens the picker: **every sound the server already -holds**, one row each. A sound has nothing to show, so the row carries a **▶** at its left that +holds**, one row each. A sound has nothing to show, so the row carries a **play triangle** at its left that plays it — pressing that is a preview and picks nothing. Picking a row and pressing **Use sound** makes the asset; **Upload…** is the way in for a file the server does not have yet. A row captioned with an asset name is one this project already uses, and picking it uses that asset