The undo and redo arrows read as arrows now, and the run buttons sit on the middle of the window: the first pair was a three-quarter circle with a triangle at the end of the arc, which at 16 units puts the head exactly where the arc already is - the two melt into one another and the icon reads as a comma, which is what the screenshot showed - so both are drawn as a flat head standing free beside its tail, a triangle pointing left with a tail curving away to the right and down (redo mirrored), and they were checked in the real build, not only in an SVG renderer, because ImageMagick draws these paths a good deal more kindly than Pixi does; the play/pause pair was off centre because the row has three flexible children - the two spacers around it and the notice label, which is flexible since #177 so that the bar does not overflow at 1280 px - and each takes a third of what is left, so Toolbar.layout() now moves the pair onto the middle of the bar after super.layout(), clamped between the redo edge and the start of the notice so that a narrow window pushes the pair back instead of laying two captions on top of each other; one new e2e check in 46a measures that middle against innerWidth/2 (1148 checks), and the README gained the screenshot of the editor
game-maker / gate (push) Successful in 2m6s
game-maker / suite (push) Successful in 7m18s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-20 16:51:34 +02:00
1 parent 60d0146bde
commit da35f10d1a
6 files changed
+40 -7

No files matched your search

+3 -1
View File
@@ -4,6 +4,8 @@ A browser-based tool "one step before a game engine": create **assets** (scenes,
sprites), place them into scenes, tweak their properties in an inspector and press **Play** –
all in one program, all drawn inside a single WebGL canvas.
![](screenshot.png)
Live: <https://nockal.com/game-maker/> · Widget playground: <https://nockal.com/game-maker/?playground>
**The documentation is the wiki:** <https://git.nockal.com/meleki/game-maker/wiki> – every concept,
@@ -40,7 +42,7 @@ npm run build # writes dist/ and regenerates index.html; the folder is wh
The browser suite and the three example games need a machine with a GPU:
```bash
node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 1147 checks (GM_STEPS=20 for one step)
node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 1148 checks (GM_STEPS=20 for one step)
# every tool signs in first – see the Accounts page
node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs
node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

+18
View File
@@ -148,6 +148,24 @@ export class Toolbar extends HStack {
this.status.setStyle(state.saveStatus === 'error' || state.saveStatus === 'conflict' ? 'body' : 'small');
}
/**
* The row lays itself out first, then the two run buttons are moved onto the middle of the bar.
* The row alone cannot put them there: the two spacers around them share the free space with the
* flexible notice, so each gets a third of it and the pair ends up left of centre. Middle means
* the middle of the bar here, not the middle of what the row had left over. It never travels
* past the notice, so a narrow window pushes the pair back rather than one label over another.
*/
override layout(): void {
super.layout();
const width = this.pauseButton.x + this.pauseButton.w - this.playButton.x;
const leftMost = this.redoButton.x + this.redoButton.w + this.gap;
const rightMost = this.notice.x - this.gap - width;
const x = Math.round(Math.max(leftMost, Math.min((this.w - width) / 2, rightMost)));
const shift = x - this.playButton.x;
this.playButton.position.set(this.playButton.x + shift, this.playButton.y);
this.pauseButton.position.set(this.pauseButton.x + shift, this.pauseButton.y);
}
override redraw(): void {
this.bg.clear();
this.bg.rect(0, 0, this.w, this.h).fill(Theme.colors.panelHeader);
+2 -2
View File
@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-8 -8 16 16" width="16" height="16">
<!-- The mirror of undo.svg, every x negated. -->
<path d="M3.5 -2 C1.5 -5.5, -4 -5.5, -5 -1.5 C-5.8 1.5, -4.5 4.3, -1.5 5.5" fill="none" stroke="currentColor" stroke-width="1.6" />
<path d="M7.2 -4.6 L0.8 -4.6 L4 1.2 Z" fill="currentColor" />
<path d="M1.5 -1.6 C-1.7 -1.6, -5.5 -0.6, -4.9 3.6" fill="none" stroke="currentColor" stroke-width="1.7" />
<path d="M5.9 -1.6 L1.5 -4.4 L1.5 1.2 Z" fill="currentColor" />
</svg>

Before

Width:  |  Height:  |  Size: 343 B

After

Width:  |  Height:  |  Size: 321 B

+6 -4
View File
@@ -1,6 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-8 -8 16 16" width="16" height="16">
<!-- An arrow bending back on itself. Cubic curves, not arcs: Pixi's parser draws an A in the
middle of a path as a spike (see plugins.svg). -->
<path d="M-3.5 -2 C-1.5 -5.5, 4 -5.5, 5 -1.5 C5.8 1.5, 4.5 4.3, 1.5 5.5" fill="none" stroke="currentColor" stroke-width="1.6" />
<path d="M-7.2 -4.6 L-0.8 -4.6 L-4 1.2 Z" fill="currentColor" />
<!-- A flat head pointing left, well clear of the tail that bends away to the right and down:
at 16 units a head sitting on the end of a circular arc merges with the arc and the whole
thing reads as a comma. Cubic curves, not arcs: Pixi's parser draws an A in the middle of a
path as a spike (see plugins.svg). -->
<path d="M-1.5 -1.6 C1.7 -1.6, 5.5 -0.6, 4.9 3.6" fill="none" stroke="currentColor" stroke-width="1.7" />
<path d="M-5.9 -1.6 L-1.5 -4.4 L-1.5 1.2 Z" fill="currentColor" />
</svg>

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 608 B

+11
View File
@@ -34,6 +34,17 @@ export async function topbar(t) {
buttons.pauseEnabled === false,
JSON.stringify(buttons),
);
// The pair is centred on the bar itself. The row cannot do that on its own: the spacers around
// the two buttons share the free space with the flexible notice and so get a third of it each,
// which used to leave the pair well left of the middle.
const play = await json('__gm.toolbarAt("play")');
const pause = await json('__gm.toolbarAt("pause")');
const barCentre = await json('window.innerWidth / 2');
check(
'play and pause sit on the middle of the bar, not on the middle of what is left over',
Math.abs((play.x + pause.x) / 2 - barCentre) <= 2,
JSON.stringify({ middle: (play.x + pause.x) / 2, barCentre }),
);
await shot('46-topbar');
// 46b. The one menu. Four entries, and the separator between what opens a project and what