Move repo, CI and the video worker over to the name Feuerwerk (#422)
feuerwerk / gate (push) Successful in 4m30s
feuerwerk / suite (push) Successful in 18m38s

Stage 3 of the rename. The repo now lives at meleki/feuerwerk, the
runners carry feuerwerk labels and the WSL distro on melektaus-atx is
called feuerwerk-ci. The code has to follow, or CI finds no runner and
the suite no longer picks the GPU path.

- ci.yml: workflow name feuerwerk, jobs on feuerwerk-ci (gate, stein2)
  and feuerwerk-wsl (suite, melektaus-atx).
- GAME_MAKER_* variables are now FEUERWERK_*. This includes
  FEUERWERK_BROWSER=wsl, which the runner config on melektaus-atx sets.
- The video worker runs as container feuerwerk-video with the image
  feuerwerk-video and works on /srv/feuerwerk.
- e2e.sh starts the unit feuerwerk-e2e, the CI image keeps its paths
  under the new name.
- README and repo links point to git.nockal.com/meleki/feuerwerk. The
  old URLs still redirect with 301.

Both runners keep their old labels until the first CI run with this
ci.yml is through. Then they go, together with the image tag
game-maker-ci:latest and GAME_MAKER_BROWSER in the atx config.

Tests:
- Gate on melektaus-atx through the renamed distro: CHECK EXIT 0,
  307 files, 4756 tests.
- e2e 60 on melektaus-atx: ALL PASSED, 20 checks. Renderer is the
  RTX 4070 through D3D12, so FEUERWERK_BROWSER reaches the GPU path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-13 13:42:52 +02:00
1 parent 043c224cc3
commit 6097307b6d
16 files changed
+78 -78

No files matched your search

+6 -6
View File
@@ -1,10 +1,10 @@
# Runs the whole proof on the Gitea runner: gate, the editor suite and the three example games. # Runs the whole proof on the Gitea runner: gate, the editor suite and the three example games.
# #
# The suite runs on `game-maker-wsl`, the runner in the WSL2 distro game-maker-ci on # The suite runs on `feuerwerk-wsl`, the runner in the WSL2 distro feuerwerk-ci on
# melektaus-atx (#283). Its label picks the image built from tools/ci/Dockerfile. The GPU # melektaus-atx (#283). Its label picks the image built from tools/ci/Dockerfile. The GPU
# (/dev/dxg and the Windows driver libraries), /dev/shm and GAME_MAKER_BROWSER=wsl come from that # (/dev/dxg and the Windows driver libraries), /dev/shm and FEUERWERK_BROWSER=wsl come from that
# runner's own config.yaml, not from here – without them chromium falls back to software WebGL and # runner's own config.yaml, not from here – without them chromium falls back to software WebGL and
# the harness stops. The gate needs no GPU and runs on `game-maker-ci`, the runner on stein2 with # the harness stops. The gate needs no GPU and runs on `feuerwerk-ci`, the runner on stein2 with
# the same image. Pointing the suite at that label too moves the browser runs back to stein2. # the same image. Pointing the suite at that label too moves the browser runs back to stein2.
# #
# Two jobs without `needs:`, so they start together. The gate does not stand in front of the # Two jobs without `needs:`, so they start together. The gate does not stand in front of the
@@ -14,7 +14,7 @@
# On two runners the gate's vitest no longer shares cores with the suite's chromium, which # On two runners the gate's vitest no longer shares cores with the suite's chromium, which
# measures text widths and frame counts. GM_TEST_WORKERS still caps vitest at two workers, for the # measures text widths and frame counts. GM_TEST_WORKERS still caps vitest at two workers, for the
# day both jobs share one runner again. # day both jobs share one runner again.
name: game-maker name: feuerwerk
on: on:
push: push:
@@ -22,7 +22,7 @@ on:
jobs: jobs:
gate: gate:
runs-on: game-maker-ci runs-on: feuerwerk-ci
timeout-minutes: 20 timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -46,7 +46,7 @@ jobs:
php tests/php/videos.test.php php tests/php/videos.test.php
suite: suite:
runs-on: game-maker-wsl runs-on: feuerwerk-wsl
timeout-minutes: 45 timeout-minutes: 45
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
+34 -34
View File
@@ -1,6 +1,6 @@
# Feuerwerk # Feuerwerk
[![game-maker](https://git.nockal.com/meleki/game-maker/actions/workflows/ci.yml/badge.svg?branch=main)](https://git.nockal.com/meleki/game-maker/actions?workflow=ci.yml) [![feuerwerk](https://git.nockal.com/meleki/feuerwerk/actions/workflows/ci.yml/badge.svg?branch=main)](https://git.nockal.com/meleki/feuerwerk/actions?workflow=ci.yml)
A browser-based tool "one step before a game engine": create **assets** (scenes, cameras, A browser-based tool "one step before a game engine": create **assets** (scenes, cameras,
sprites), place them into scenes, tweak their properties in an inspector and press **Play** – sprites), place them into scenes, tweak their properties in an inspector and press **Play** –
@@ -10,7 +10,7 @@ all in one program, all drawn inside a single WebGL canvas.
Live: <https://nockal.com/feuerwerk/> · Widget playground: <https://nockal.com/feuerwerk/?playground> Live: <https://nockal.com/feuerwerk/> · Widget playground: <https://nockal.com/feuerwerk/?playground>
**The documentation is the wiki:** <https://git.nockal.com/meleki/game-maker/wiki> – every concept, **The documentation is the wiki:** <https://git.nockal.com/meleki/feuerwerk/wiki> – every concept,
node, tab and shortcut, plus the architecture and the development workflow. This file is the short node, tab and shortcut, plus the architecture and the development workflow. This file is the short
way in. way in.
@@ -57,43 +57,43 @@ node tools/seed-actor.mjs && node tools/smoke-actor.mjs
Every push runs all of it on the Gitea runners – the gate as one job, build and suite as another Every push runs all of it on the Gitea runners – the gate as one job, build and suite as another
beside it – so locally take the gate plus the step your change touches and leave the full run to beside it – so locally take the gate plus the step your change touches and leave the full run to
CI. Details, the GPU requirement and the detached runner are in CI. Details, the GPU requirement and the detached runner are in
[Development](https://git.nockal.com/meleki/game-maker/wiki/Development). [Development](https://git.nockal.com/meleki/feuerwerk/wiki/Development).
## Documentation ## Documentation
| Page | What it covers | | Page | What it covers |
|---|---| |---|---|
| [Concepts](https://git.nockal.com/meleki/game-maker/wiki/Concepts) | Assets, scene objects, overrides, play mode, the camera, the console | | [Concepts](https://git.nockal.com/meleki/feuerwerk/wiki/Concepts) | Assets, scene objects, overrides, play mode, the camera, the console |
| [Accounts](https://git.nockal.com/meleki/game-maker/wiki/Accounts) | Signing in and out, the accounts, who a project belongs to, what the check tools need | | [Accounts](https://git.nockal.com/meleki/feuerwerk/wiki/Accounts) | Signing in and out, the accounts, who a project belongs to, what the check tools need |
| [Scenes](https://git.nockal.com/meleki/game-maker/wiki/Scenes) | The edited scene, the start scene, and switching scenes from a graph | | [Scenes](https://git.nockal.com/meleki/feuerwerk/wiki/Scenes) | The edited scene, the start scene, and switching scenes from a graph |
| [Scene editing](https://git.nockal.com/meleki/game-maker/wiki/Scene-editing) | Placing, z-order, hierarchy, the editor offset | | [Scene editing](https://git.nockal.com/meleki/feuerwerk/wiki/Scene-editing) | Placing, z-order, hierarchy, the editor offset |
| [Behaviors](https://git.nockal.com/meleki/game-maker/wiki/Behaviors) | Node graphs: variables, the node set, structs and lists, loops, nesting, editing | | [Behaviors](https://git.nockal.com/meleki/feuerwerk/wiki/Behaviors) | Node graphs: variables, the node set, structs and lists, loops, nesting, editing |
| [Structs](https://git.nockal.com/meleki/game-maker/wiki/Structs) | Struct assets: a named shape that struct variables, fields and `Pack`/`Expand` follow | | [Structs](https://git.nockal.com/meleki/feuerwerk/wiki/Structs) | Struct assets: a named shape that struct variables, fields and `Pack`/`Expand` follow |
| [Colliders](https://git.nockal.com/meleki/game-maker/wiki/Colliders) | Shapes (box, circle, capsule, polygon), collision events, blocking movement, one-way colliders and raycasts | | [Colliders](https://git.nockal.com/meleki/feuerwerk/wiki/Colliders) | Shapes (box, circle, capsule, polygon), collision events, blocking movement, one-way colliders and raycasts |
| [Physics](https://git.nockal.com/meleki/game-maker/wiki/Physics) | Rigidbodies, the collider material, gravity, the fixed step, joints | | [Physics](https://git.nockal.com/meleki/feuerwerk/wiki/Physics) | Rigidbodies, the collider material, gravity, the fixed step, joints |
| [Textures](https://git.nockal.com/meleki/game-maker/wiki/Textures) | Images, frames, nine-slice, the filter, upload limits | | [Textures](https://git.nockal.com/meleki/feuerwerk/wiki/Textures) | Images, frames, nine-slice, the filter, upload limits |
| [Vector art](https://git.nockal.com/meleki/game-maker/wiki/Vector-Art) | Pictures drawn from shapes: the pen, curves, gradients and texture fills, combining shapes | | [Vector art](https://git.nockal.com/meleki/feuerwerk/wiki/Vector-Art) | Pictures drawn from shapes: the pen, curves, gradients and texture fills, combining shapes |
| [Pixel art](https://git.nockal.com/meleki/game-maker/wiki/Pixel-Art) | Pictures painted pixel by pixel: the palette, the tools, layers and frames | | [Pixel art](https://git.nockal.com/meleki/feuerwerk/wiki/Pixel-Art) | Pictures painted pixel by pixel: the palette, the tools, layers and frames |
| [Fonts](https://git.nockal.com/meleki/game-maker/wiki/Fonts) | Font assets, the picker, what a text falls back to | | [Fonts](https://git.nockal.com/meleki/feuerwerk/wiki/Fonts) | Font assets, the picker, what a text falls back to |
| [Sounds](https://git.nockal.com/meleki/game-maker/wiki/Sounds) | Sound assets and clips, `Play sound`, buses and the Master routing, sound FX | | [Sounds](https://git.nockal.com/meleki/feuerwerk/wiki/Sounds) | Sound assets and clips, `Play sound`, buses and the Master routing, sound FX |
| [Instruments](https://git.nockal.com/meleki/game-maker/wiki/Instruments) | Instruments as node graphs, Chips and presets, the keys of the Instrument tab, `Play note` | | [Instruments](https://git.nockal.com/meleki/feuerwerk/wiki/Instruments) | Instruments as node graphs, Chips and presets, the keys of the Instrument tab, `Play note` |
| [Patterns](https://git.nockal.com/meleki/game-maker/wiki/Patterns) | Patterns and the piano roll, playing one in a loop or from a game | | [Patterns](https://git.nockal.com/meleki/feuerwerk/wiki/Patterns) | Patterns and the piano roll, playing one in a loop or from a game |
| [Songs](https://git.nockal.com/meleki/game-maker/wiki/Songs) | Songs, their tracks and items, routing, recording, playing one from a game | | [Songs](https://git.nockal.com/meleki/feuerwerk/wiki/Songs) | Songs, their tracks and items, routing, recording, playing one from a game |
| [Animations](https://git.nockal.com/meleki/game-maker/wiki/Animations) | Animation assets and the Animation tab | | [Animations](https://git.nockal.com/meleki/feuerwerk/wiki/Animations) | Animation assets and the Animation tab |
| [Curves](https://git.nockal.com/meleki/game-maker/wiki/Curves) | Easings drawn by hand, the Curve tab, using one on a key or a `Lerp` | | [Curves](https://git.nockal.com/meleki/feuerwerk/wiki/Curves) | Easings drawn by hand, the Curve tab, using one on a key or a `Lerp` |
| [Shaders](https://git.nockal.com/meleki/game-maker/wiki/Shaders) | Shader graphs that sprites, texts, particle fields and cameras wear, their node set, passes, shader functions | | [Shaders](https://git.nockal.com/meleki/feuerwerk/wiki/Shaders) | Shader graphs that sprites, texts, particle fields and cameras wear, their node set, passes, shader functions |
| [Particles](https://git.nockal.com/meleki/game-maker/wiki/Particles) | Particle graphs: a particle as a function of its age | | [Particles](https://git.nockal.com/meleki/feuerwerk/wiki/Particles) | Particle graphs: a particle as a function of its age |
| [State machines](https://git.nockal.com/meleki/game-maker/wiki/State-machines) | The asset, named transitions, `State branch`, `Set state` and `State transition` | | [State machines](https://git.nockal.com/meleki/feuerwerk/wiki/State-machines) | The asset, named transitions, `State branch`, `Set state` and `State transition` |
| [Containers](https://git.nockal.com/meleki/game-maker/wiki/Containers) | Templates, instances, screens | | [Containers](https://git.nockal.com/meleki/feuerwerk/wiki/Containers) | Templates, instances, screens |
| [Tiles](https://git.nockal.com/meleki/game-maker/wiki/Tiles) | The tile asset, plain tiles and the two autotile kinds, the pictures as animation steps, the Tile tab | | [Tiles](https://git.nockal.com/meleki/feuerwerk/wiki/Tiles) | The tile asset, plain tiles and the two autotile kinds, the pictures as animation steps, the Tile tab |
| [Tilemaps](https://git.nockal.com/meleki/game-maker/wiki/Tilemaps) | The tilemap asset, painting in the scene view, layers, what it looks like in the game | | [Tilemaps](https://git.nockal.com/meleki/feuerwerk/wiki/Tilemaps) | The tilemap asset, painting in the scene view, layers, what it looks like in the game |
| [Plugins](https://git.nockal.com/meleki/game-maker/wiki/Plugins) | Extending the editor: the plugin file, how it is loaded, switching one on and off, API v1 | | [Plugins](https://git.nockal.com/meleki/feuerwerk/wiki/Plugins) | Extending the editor: the plugin file, how it is loaded, switching one on and off, API v1 |
| [Keyboard](https://git.nockal.com/meleki/game-maker/wiki/Keyboard) | Every shortcut | | [Keyboard](https://git.nockal.com/meleki/feuerwerk/wiki/Keyboard) | Every shortcut |
| [Architecture](https://git.nockal.com/meleki/game-maker/wiki/Architecture) | Stack, source layout, the rules that keep it organised | | [Architecture](https://git.nockal.com/meleki/feuerwerk/wiki/Architecture) | Stack, source layout, the rules that keep it organised |
| [Development](https://git.nockal.com/meleki/game-maker/wiki/Development) | Commands, the e2e suite, the example games, CI | | [Development](https://git.nockal.com/meleki/feuerwerk/wiki/Development) | Commands, the e2e suite, the example games, CI |
| [API](https://git.nockal.com/meleki/game-maker/wiki/API) | The PHP JSON API and the project document | | [API](https://git.nockal.com/meleki/feuerwerk/wiki/API) | The PHP JSON API and the project document |
## Ideas, gaps and bugs ## Ideas, gaps and bugs
They live in the issue tracker: <https://git.nockal.com/meleki/game-maker/issues>. What is not They live in the issue tracker: <https://git.nockal.com/meleki/feuerwerk/issues>. What is not
there yet is listed on the wiki's [Home](https://git.nockal.com/meleki/game-maker/wiki) page. there yet is listed on the wiki's [Home](https://git.nockal.com/meleki/feuerwerk/wiki) page.
+1 -1
View File
@@ -67,7 +67,7 @@ declare(strict_types=1);
* POST ?r=videos&name=x.mov[&convert=0] raw video bytes → {file,name,status,…} * POST ?r=videos&name=x.mov[&convert=0] raw video bytes → {file,name,status,…}
* POST ?r=videos/{file}/convert → {file,name,status,…} | 403 | 404 * POST ?r=videos/{file}/convert → {file,name,status,…} | 403 | 404
* DELETE ?r=videos/{file} → 204 | 403 | 404 | 409 * DELETE ?r=videos/{file} → 204 | 403 | 404 | 409
* (an upload is converted by the worker in `game-maker-video` (#402): * (an upload is converted by the worker in `feuerwerk-video` (#402):
* `status` is queued, converting with `progress`, failed with `error`, * `status` is queued, converting with `progress`, failed with `error`,
* or ready with width, height, duration, fps, audio and `poster`; * or ready with width, height, duration, fps, audio and `poster`;
* with `convert=0` it is only kept, `unconverted`, until it is asked * with `convert=0` it is only kept, `unconverted`, until it is asked
+1 -1
View File
@@ -5,7 +5,7 @@ declare(strict_types=1);
* The videos waiting to be converted (#402): `data/videos/queue/{folder}-{hash}.json` says what * The videos waiting to be converted (#402): `data/videos/queue/{folder}-{hash}.json` says what
* became of an upload, and its `source` where the upload lies – kept as it came beside the MP4, * became of an upload, and its `source` where the upload lies – kept as it came beside the MP4,
* `{folder}/{hash}.source.{ext}`, for downloading it. The API adds to it, the worker in the * `{folder}/{hash}.source.{ext}`, for downloading it. The API adds to it, the worker in the
* container `game-maker-video` takes from it, one at a time, oldest first. * container `feuerwerk-video` takes from it, one at a time, oldest first.
* *
* A job is `queued`, `converting` (with `progress` from 0 to 1) or `failed` (with `error`). A done * A job is `queued`, `converting` (with `progress` from 0 to 1) or `failed` (with `error`). A done
* one is no job any more: its MP4 lies in the account's folder and the job is gone. A failed one * one is no job any more: its MP4 lies in the account's folder and the job is gone. A failed one
+1 -1
View File
@@ -3,7 +3,7 @@ declare(strict_types=1);
/** /**
* Converts what waits in the VideoQueue, one video at a time (#402). Runs in the container * Converts what waits in the VideoQueue, one video at a time (#402). Runs in the container
* `game-maker-video` through `tools/video-worker.php`, and in CI beside the PHP server. * `feuerwerk-video` through `tools/video-worker.php`, and in CI beside the PHP server.
* *
* Each job goes: probe the upload, convert it into a temp file beside its target, read the result * Each job goes: probe the upload, convert it into a temp file beside its target, read the result
* back for its details, cut a poster, then move all three into place and drop the job. Whatever * back for its details, cut a poster, then move all three into place and drop the job. Whatever
+1 -1
View File
@@ -10,7 +10,7 @@
set -u set -u
UNIT=game-maker-e2e UNIT=feuerwerk-e2e
DIR=$(dirname "$(readlink -f "$0")") DIR=$(dirname "$(readlink -f "$0")")
LOGDIR=$DIR/logs LOGDIR=$DIR/logs
+1 -1
View File
@@ -4,7 +4,7 @@ declare(strict_types=1);
/** /**
* Videos (#402): the conversion rules, the store and its queue, and the worker with the real * Videos (#402): the conversion rules, the store and its queue, and the worker with the real
* ffmpeg. Plain PHP like files.test.php; CI runs it with `php tests/php/videos.test.php`. It needs * ffmpeg. Plain PHP like files.test.php; CI runs it with `php tests/php/videos.test.php`. It needs
* ffmpeg and ffprobe on the PATH, which the CI image and the container `game-maker-video` have. * ffmpeg and ffprobe on the PATH, which the CI image and the container `feuerwerk-video` have.
*/ */
require __DIR__ . '/../../api/lib/AtomicFile.php'; require __DIR__ . '/../../api/lib/AtomicFile.php';
+4 -4
View File
@@ -1,7 +1,7 @@
# The image behind the Gitea Actions label `game-maker-ci`. It is built on the host and kept # The image behind the Gitea Actions label `feuerwerk-ci`. It is built on the host and kept
# local (the runner has `force_pull: false`), so a change here needs a rebuild: # local (the runner has `force_pull: false`), so a change here needs a rebuild:
# #
# DOCKER_BUILDKIT=0 docker build --network git_default -t game-maker-ci:latest tools/ci # DOCKER_BUILDKIT=0 docker build --network git_default -t feuerwerk-ci:latest tools/ci
# #
# Both flags are needed on stein2: DNS is dead in Docker's default bridge network, and Buildkit # Both flags are needed on stein2: DNS is dead in Docker's default bridge network, and Buildkit
# cannot join a named network. # cannot join a named network.
@@ -10,11 +10,11 @@ FROM node:22-bookworm
# chromium + the Vulkan drivers: the e2e harness starts chromium with --use-angle=vulkan and has # chromium + the Vulkan drivers: the e2e harness starts chromium with --use-angle=vulkan and has
# no software fallback. The render device itself comes from the runner's container.options; # no software fallback. The render device itself comes from the runner's container.options;
# without it chromium falls back to llvmpipe and gets WebGL 1.0 only. # without it chromium falls back to llvmpipe and gets WebGL 1.0 only.
# xvfb serves the other GPU path, GAME_MAKER_BROWSER=wsl (tools/lib/browser.mjs): under WSL2 the # xvfb serves the other GPU path, FEUERWERK_BROWSER=wsl (tools/lib/browser.mjs): under WSL2 the
# GPU is /dev/dxg behind Mesa's d3d12 driver, which headless chromium cannot reach, an X11 one can. # GPU is /dev/dxg behind Mesa's d3d12 driver, which headless chromium cannot reach, an X11 one can.
# php-cli serves api/index.php, which every tool loads and saves its project through. # php-cli serves api/index.php, which every tool loads and saves its project through.
# ffmpeg converts uploaded videos (#402), through tools/video-worker.php like the container # ffmpeg converts uploaded videos (#402), through tools/video-worker.php like the container
# game-maker-video on stein2 does. # feuerwerk-video on stein2 does.
# The fonts are the host's set on purpose: the checks measure text widths to find click points, # The fonts are the host's set on purpose: the checks measure text widths to find click points,
# so a different set moves them. # so a different set moves them.
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
+8 -8
View File
@@ -1,11 +1,11 @@
#!/bin/bash #!/bin/bash
# Sourced, not run: it leaves the PHP server in the caller's background and exports # Sourced, not run: it leaves the PHP server in the caller's background and exports
# GAME_MAKER_BASE_URL, which every tool reads. # FEUERWERK_BASE_URL, which every tool reads.
# #
# The build wires its assets absolutely under /feuerwerk/dist/, so the checkout has to be # The build wires its assets absolutely under /feuerwerk/dist/, so the checkout has to be
# served under that path segment – hence the symlink into /srv rather than `-t .`. # served under that path segment – hence the symlink into /srv rather than `-t .`.
export GAME_MAKER_BASE_URL=http://127.0.0.1:8080/feuerwerk/ export FEUERWERK_BASE_URL=http://127.0.0.1:8080/feuerwerk/
feuerwerk_serve() { feuerwerk_serve() {
local root local root
@@ -30,27 +30,27 @@ feuerwerk_serve() {
# A server from an earlier step of the same job is fine to keep. Asked of the one route that # A server from an earlier step of the same job is fine to keep. Asked of the one route that
# answers without a session, so "is it up" does not depend on being signed in. # answers without a session, so "is it up" does not depend on being signed in.
if curl -sf "${GAME_MAKER_BASE_URL}api/index.php?r=auth/session" >/dev/null 2>&1; then if curl -sf "${FEUERWERK_BASE_URL}api/index.php?r=auth/session" >/dev/null 2>&1; then
echo "server already up at $GAME_MAKER_BASE_URL" echo "server already up at $FEUERWERK_BASE_URL"
return 0 return 0
fi fi
mkdir -p /srv && ln -sfn "$root" /srv/feuerwerk mkdir -p /srv && ln -sfn "$root" /srv/feuerwerk
# Uploaded videos are converted by the worker (#402); on stein2 that is the container # Uploaded videos are converted by the worker (#402); on stein2 that is the container
# game-maker-video, here a process beside the server. # feuerwerk-video, here a process beside the server.
php "$root/tools/video-worker.php" "$root/data" >/tmp/video-worker.log 2>&1 & php "$root/tools/video-worker.php" "$root/data" >/tmp/video-worker.log 2>&1 &
# Without workers the single-threaded dev server stalls: the editor fetches project and # Without workers the single-threaded dev server stalls: the editor fetches project and
# textures in parallel. The router serves videos with Range requests, see there. # textures in parallel. The router serves videos with Range requests, see there.
PHP_CLI_SERVER_WORKERS=8 php -S 0.0.0.0:8080 -t /srv "$root/tools/ci/router.php" >/tmp/php-server.log 2>&1 & PHP_CLI_SERVER_WORKERS=8 php -S 0.0.0.0:8080 -t /srv "$root/tools/ci/router.php" >/tmp/php-server.log 2>&1 &
for _ in $(seq 60); do for _ in $(seq 60); do
curl -sf "${GAME_MAKER_BASE_URL}api/index.php?r=auth/session" >/dev/null 2>&1 && break curl -sf "${FEUERWERK_BASE_URL}api/index.php?r=auth/session" >/dev/null 2>&1 && break
sleep 0.5 sleep 0.5
done done
if ! curl -sf "${GAME_MAKER_BASE_URL}api/index.php?r=auth/session" >/dev/null 2>&1; then if ! curl -sf "${FEUERWERK_BASE_URL}api/index.php?r=auth/session" >/dev/null 2>&1; then
echo "the server never came up" >&2 echo "the server never came up" >&2
tail -20 /tmp/php-server.log >&2 tail -20 /tmp/php-server.log >&2
return 1 return 1
fi fi
echo "serving $root at $GAME_MAKER_BASE_URL" echo "serving $root at $FEUERWERK_BASE_URL"
} }
+1 -1
View File
@@ -5,7 +5,7 @@ import { sampleZoom } from './lib/zoomTransition.mjs';
/** /**
* Videos (#402). A WebM goes up and the worker turns it into an MP4 (in CI beside the PHP server, * Videos (#402). A WebM goes up and the worker turns it into an MP4 (in CI beside the PHP server,
* on stein2 in the container game-maker-video). "+ → Video" offers it with what it is; Use makes * on stein2 in the container feuerwerk-video). "+ → Video" offers it with what it is; Use makes
* the asset and opens its tab, which shows the picture. A drag in the clip strip spans a clip, one * the asset and opens its tab, which shows the picture. A drag in the clip strip spans a clip, one
* undo step. A sprite wearing the clip plays only that stretch, over and over, without sound in the * undo step. A sprite wearing the clip plays only that stretch, over and over, without sound in the
* editor; Play starts it over from the clip's start and lets it be heard, Esc makes it quiet again. * editor; Play starts it over from the clip's start and lets it be heard, Esc makes it quiet again.
+6 -6
View File
@@ -2,7 +2,7 @@
* Signing the check tools in. Since #177 every API route but `auth/*` needs a session, so every * Signing the check tools in. Since #177 every API route but `auth/*` needs a session, so every
* seed, smoke and e2e run logs in first – as `e2e`, the account that owns the four test projects. * seed, smoke and e2e run logs in first – as `e2e`, the account that owns the four test projects.
* *
* The password is never in the repo: it comes from `GAME_MAKER_E2E_PASSWORD` or from * The password is never in the repo: it comes from `FEUERWERK_E2E_PASSWORD` or from
* `data/e2e-password.txt`, which is git-ignored and written once per server (CI writes its own). * `data/e2e-password.txt`, which is git-ignored and written once per server (CI writes its own).
*/ */
import { readFile } from 'node:fs/promises'; import { readFile } from 'node:fs/promises';
@@ -23,26 +23,26 @@ const cookies = new Map();
/** The password of the `e2e` account; the step that drives the sign-in screen types it in. */ /** The password of the `e2e` account; the step that drives the sign-in screen types it in. */
export async function e2ePassword() { export async function e2ePassword() {
const fromEnv = process.env.GAME_MAKER_E2E_PASSWORD; const fromEnv = process.env.FEUERWERK_E2E_PASSWORD;
if (fromEnv) return fromEnv; if (fromEnv) return fromEnv;
try { try {
return (await readFile(PASSWORD_FILE, 'utf8')).trim(); return (await readFile(PASSWORD_FILE, 'utf8')).trim();
} catch { } catch {
throw new Error( throw new Error(
`no password for the "${E2E_USER}" account: set GAME_MAKER_E2E_PASSWORD or put it in ${PASSWORD_FILE}`, `no password for the "${E2E_USER}" account: set FEUERWERK_E2E_PASSWORD or put it in ${PASSWORD_FILE}`,
); );
} }
} }
/** The password of `e2e-admin`, from `GAME_MAKER_E2E_ADMIN_PASSWORD` or `data/e2e-admin-password.txt`. */ /** The password of `e2e-admin`, from `FEUERWERK_E2E_ADMIN_PASSWORD` or `data/e2e-admin-password.txt`. */
export async function e2eAdminPassword() { export async function e2eAdminPassword() {
const fromEnv = process.env.GAME_MAKER_E2E_ADMIN_PASSWORD; const fromEnv = process.env.FEUERWERK_E2E_ADMIN_PASSWORD;
if (fromEnv) return fromEnv; if (fromEnv) return fromEnv;
try { try {
return (await readFile(ADMIN_PASSWORD_FILE, 'utf8')).trim(); return (await readFile(ADMIN_PASSWORD_FILE, 'utf8')).trim();
} catch { } catch {
throw new Error( throw new Error(
`no password for the "${E2E_ADMIN}" account: set GAME_MAKER_E2E_ADMIN_PASSWORD or put it in ${ADMIN_PASSWORD_FILE}`, `no password for the "${E2E_ADMIN}" account: set FEUERWERK_E2E_ADMIN_PASSWORD or put it in ${ADMIN_PASSWORD_FILE}`,
); );
} }
} }
+2 -2
View File
@@ -30,7 +30,7 @@ const HEADLESS = [
]; ];
/** /**
* GAME_MAKER_BROWSER=wsl, for a runner inside WSL2 (#283). There the GPU is /dev/dxg behind Mesa's * FEUERWERK_BROWSER=wsl, for a runner inside WSL2 (#283). There the GPU is /dev/dxg behind Mesa's
* d3d12 driver: no DRM render node, no Vulkan. Headless chromium finds no surface and gets no WebGL, * d3d12 driver: no DRM render node, no Vulkan. Headless chromium finds no surface and gets no WebGL,
* an X11 chromium on ANGLE/GL does. So this mode brings its own invisible X server. * an X11 chromium on ANGLE/GL does. So this mode brings its own invisible X server.
* *
@@ -49,7 +49,7 @@ const WSL = [
/** Starts chromium with the CDP port open; `proc.stderr` carries its last words. */ /** Starts chromium with the CDP port open; `proc.stderr` carries its last words. */
export async function launchBrowser({ port, width, height }) { export async function launchBrowser({ port, width, height }) {
const wsl = process.env.GAME_MAKER_BROWSER === 'wsl'; const wsl = process.env.FEUERWERK_BROWSER === 'wsl';
const display = wsl ? await startXvfb({ width, height }) : null; const display = wsl ? await startXvfb({ width, height }) : null;
const proc = spawn( const proc = spawn(
'chromium', 'chromium',
+2 -2
View File
@@ -26,13 +26,13 @@ export const DEFAULT_BASE_URL = 'https://nockal.com/feuerwerk/';
/** /**
* Reads `[projectId] [baseUrl]` from argv, falling back to `defaultId` and to * Reads `[projectId] [baseUrl]` from argv, falling back to `defaultId` and to
* `GAME_MAKER_BASE_URL` – which is how CI points every tool at its own server without * `FEUERWERK_BASE_URL` – which is how CI points every tool at its own server without
* repeating the project ids in shell scripts. Targeting the playground aborts: no tool may * repeating the project ids in shell scripts. Targeting the playground aborts: no tool may
* overwrite or mutate it. * overwrite or mutate it.
*/ */
export function cliArgs(script, defaultId) { export function cliArgs(script, defaultId) {
const projectId = process.argv[2] ?? defaultId; const projectId = process.argv[2] ?? defaultId;
const baseUrl = process.argv[3] ?? process.env.GAME_MAKER_BASE_URL ?? DEFAULT_BASE_URL; const baseUrl = process.argv[3] ?? process.env.FEUERWERK_BASE_URL ?? DEFAULT_BASE_URL;
if (projectId === PROJECTS.playground) { if (projectId === PROJECTS.playground) {
console.error(`refusing to run ${script} against the playground project (${PROJECTS.playground}).`); console.error(`refusing to run ${script} against the playground project (${PROJECTS.playground}).`);
process.exit(2); process.exit(2);
+1 -1
View File
@@ -7,7 +7,7 @@ declare(strict_types=1);
* php tools/video-worker.php [datadir] keeps watching the queue * php tools/video-worker.php [datadir] keeps watching the queue
* php tools/video-worker.php [datadir] --once converts what waits now, then stops * php tools/video-worker.php [datadir] --once converts what waits now, then stops
* *
* On stein2 it runs in the container `game-maker-video` (tools/video/), in CI beside the PHP * On stein2 it runs in the container `feuerwerk-video` (tools/video/), in CI beside the PHP
* server (tools/ci/serve.sh). Both need ffmpeg and ffprobe on the PATH. * server (tools/ci/serve.sh). Both need ffmpeg and ffprobe on the PATH.
*/ */
+2 -2
View File
@@ -1,11 +1,11 @@
# The image of the container `game-maker-video` (#402): PHP and ffmpeg, nothing else. The worker # The image of the container `feuerwerk-video` (#402): PHP and ffmpeg, nothing else. The worker
# itself is not baked in: compose.yml mounts the checkout, so a change to tools/video-worker.php or # itself is not baked in: compose.yml mounts the checkout, so a change to tools/video-worker.php or
# api/lib/Video*.php needs a restart, not a rebuild. # api/lib/Video*.php needs a restart, not a rebuild.
# #
# The same Debian as the CI image (tools/ci/Dockerfile), so CI converts with the same ffmpeg. # The same Debian as the CI image (tools/ci/Dockerfile), so CI converts with the same ffmpeg.
# Built on stein2 like that one, for the same reasons (dead DNS in the default bridge network): # Built on stein2 like that one, for the same reasons (dead DNS in the default bridge network):
# #
# DOCKER_BUILDKIT=0 docker build --network git_default -t game-maker-video:latest tools/video # DOCKER_BUILDKIT=0 docker build --network git_default -t feuerwerk-video:latest tools/video
FROM debian:12-slim FROM debian:12-slim
RUN apt-get update && apt-get install -y --no-install-recommends php-cli php-mbstring ffmpeg \ RUN apt-get update && apt-get install -y --no-install-recommends php-cli php-mbstring ffmpeg \
+7 -7
View File
@@ -4,18 +4,18 @@
# #
# It works on the checkout itself (the folder nginx serves), as www-data like the PHP container, so # It works on the checkout itself (the folder nginx serves), as www-data like the PHP container, so
# the files it writes belong to the same user. It needs no network. # the files it writes belong to the same user. It needs no network.
name: game-maker-video name: feuerwerk-video
services: services:
game-maker-video: feuerwerk-video:
container_name: game-maker-video container_name: feuerwerk-video
image: game-maker-video:latest image: feuerwerk-video:latest
restart: unless-stopped restart: unless-stopped
network_mode: none network_mode: none
user: '33:33' user: '33:33'
working_dir: /srv/game-maker working_dir: /srv/feuerwerk
volumes: volumes:
- ../..:/srv/game-maker - ../..:/srv/feuerwerk
command: ['php', 'tools/video-worker.php', '/srv/game-maker/data'] command: ['php', 'tools/video-worker.php', '/srv/feuerwerk/data']
# A 1080p conversion takes all four cores otherwise, and the web stack shares them. # A 1080p conversion takes all four cores otherwise, and the web stack shares them.
cpus: 3 cpus: 3