Commit Graph
8 Commits
Author SHA1 Message Date
adminandClaude Opus 5.5 d6fd000160 Let a behavior hear the end of an animation it played itself
game-maker / gate (push) Successful in 3m11s
game-maker / suite (push) Failing after 12m9s
A behavior that played an animation on the parent of its owner never
heard it finish. On animation finished listened to the owner and to
what stands below it, and the parent stands above.

- Play animation notes on the player which behavior asked for it.
- On animation finished hears, as before, every animation on the
  owner or below it, and now also every animation the behavior
  played itself, on whatever object. Its output object names that
  object.
- Two behaviors that both played the same animation on the same
  object each hear its end once.
- A behavior that is called by Run behavior or heard by an On node
  counts as the behavior it sits in.
- The description of the node and the engine prompt say so.

Tests:
- Gate on melektaus-atx: 218 files, 3392 tests, CHECK EXIT 0.
- Two new unit tests: the behavior hears the animation on the parent
  of its owner while a bystander does not, and two starters hear it
  once each.
- Both counter-probes bite.
- e2e 6,17-26 on melektaus-atx: 480 checks, all pass.
- No new e2e check, and nothing was looked at in the browser. The
  rule for called and heard behaviors has no test of its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:37:04 +02:00
adminandClaude Opus 5.5 c1cc80bb45 Add nodes that ask whether an animation still runs (#233)
A graph could start, pause and stop an animation and hear it finish,
but it could not ask in between whether one runs or how far it is.
Two data nodes answer that now.

- Animation playing takes an object and an animation and gives
  playing, progress and time left (s). It answers at the moment it is
  read: right after Play animation in the same pass it says on, and in
  the frame On animation finished fires it says off.
- With Animation at None it answers for the running animation started
  last on the object.
- Animation length gives the seconds of one pass, from the timeline
  and the frame rate alone.
- The rule is a pure function in src/core/model/animation.ts
  (playerStatus, leadingPlayer). The nodes reach an animation's
  length through a new field animation on GraphLookup.
- animationPort is exported so both nodes show the same picker as
  Play animation.

Decided in the issue: a Once (reset) counts as running while it blends
out, and progress and time left also hold for Loop and Ping-pong, at
the place of the playhead. On Ping-pong progress falls again on the
way back and time left counts to the next turn.

Decided here, the issue says nothing on it:
- A paused animation does not count as running. Progress and time
  left stand still.
- One that Stop animation fades out does not count as running, and
  its time left is 0.
- Time left of a Once (reset) includes its blend out. While it blends
  out progress is 1 and time left is the rest of the fade.

Finding, not fixed: on the node the name of the chosen animation
overlaps the output label progress in the same row. That comes from
the fixed node width in NodeView and was seen in the Fit view only.

Tests:
- Gate: 198 files, 2903 tests (2891 + 12), exit 0
- e2e 1-6: 282 checks passed, 06 has +2 for block 6z-ix
- Nine unit counter-probes fail, 1 to 4 tests each
- The browser counter-probe fails 6z-ix with ["false","false"]
- e2e total 1615 is computed, not measured in a full run. The smokes
  were not run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:57:31 +02:00
adminandClaude Opus 5.5 14972d057f Refactoring round 8: hide data files, safe saves, Esc as Cancel (#85)
game-maker / gate (push) Successful in 3m53s
game-maker / suite (push) Successful in 11m55s
Recurring cleanup round over the code since round 7 (bc688f3). The
issue now also asks to fix bugs and small inconsistencies found on the
way, so unlike the rounds before, this one changes behaviour in a few
places. Duplicated code in api went from 23 clones with 228 lines to
none (jscpd, at least 50 tokens). In src it stays at 22 clones with
271 lines, the same before and after.

Bugs:
- nginx served project and snapshot files as they were, so anyone who
  knew a project id could read it without signing in. Every file the
  API writes now goes through AtomicFile (temp file, mode, rename).
  Projects, snapshots, releases, accounts and sessions are 0640, and
  nginx answers 403 for them.
- Any signed-in account could delete a shared image, font or sound,
  which projects of other accounts may wear. Deleting one is now for
  administrators only. The editor never deleted a file, so the
  client's delete is gone.
- Two saves of one project could run at once. The lock file was
  removed after each save, so a waiting save and the next one locked
  different files. The lock file now stays, and deleting a project
  takes the lock as well.
- Bytes that are no picture got a 500 instead of a 422, because the
  error handler also threw for warnings silenced with @.
- A session file was rewritten in place. A request reading it at that
  moment found it empty and was signed out. It is replaced atomically.
- Delete did nothing for a shape picked in the vector art list. Delete
  now goes through removeSelection, one case per kind of selection,
  and a kind without a case fails the type check.

Inconsistencies:
- Escape on a question does what its Cancel does. Cancel on "Delete
  project?" and "Restore snapshot?" leads back to the picker or the
  list like the other questions did, and so does deleting a project.
- Editor texts use American spelling throughout, like the port names:
  48 British spellings in 45 lines (colour, centre, initialised).
- objectName and groupName replace eleven copies of "own name, else
  the asset's" and three of "Group". One copy fell back to the object
  id instead of "?".

Duplicates, dead code, comments:
- routeFiles serves images, fonts and sounds instead of three copies.
  HashedFileStore holds what the three stores shared: keeping a file
  under its hash with its name, listing and deleting. The stores keep
  only which bytes they take and what a record says.
- AtomicFile replaces nine copies of temp file plus rename.
- removeShapes is the one way the canvas, the inspector button and
  Delete take shapes out.
- GraphInterpreter.fire was called by tests only. The 54 calls use a
  helper in tests/helpers.ts now.
- FileStore.delete, HttpFileStore.delete and the PluginApi type were
  unused. A doc comment in actions.ts sat above the wrong function.

Checked and left as is:
- solidCells is used by tests only. It is the per-cell view before the
  merge into rectangles, the one place the largest-scale rule shows.
- An undo checker ran all 124 commands of the unit tests and compared
  the project before and after undo. The only differences are empty
  ports, groups and notes lists where there were none, which the file
  format drops anyway.

Docs:
- README: the check sum.
- Wiki, own commit: API (admin-only deletes, 422, file modes, lock
  file), Home (the "Not yet" list named three things that exist),
  Concepts, Keyboard, Vector art, Architecture and Development, and
  the 38 characters Gitea flagged as ambiguous on eight pages.
- .gitignore: the lock files, and pasted-*.png in any folder, which
  keeps the screenshot archive out.

Tests:
- ./check.sh: 195 files, 2817 tests, exit 0 (+2 for the name helpers).
- PHP: accounts 52 in the web container and 53 in the CI image with
  the race test (+2), snapshots 15 (+1), releases 20.
- Full e2e run: ALL PASSED, 1586 checks (+6 in 12, 47, 49 and 50).
- Smokes jumprun, tetris, actor: 24, 19 and 21 checks. The example
  project files were restored byte for byte afterwards.
- The file stores of HEAD and of this commit give byte-identical
  output for the live folders and for store, list and delete in a
  throwaway folder.
- Counter-checks, all fail as expected: a 500 for bad bytes fails 12,
  no admin check fails 49, removing the lock file again loses saves
  in 3 of 3 runs (151 to 170 of 321), Delete ignoring shapes fails 47,
  Escape that only closes fails 50, and dropping the shape case fails
  the type check (TS2366).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:12:55 +02:00
adminandClaude Opus 5 195fc94e08 Animations blend out on Stop and at the end of Once (reset), and Play can restart a running animation (#106)
game-maker / gate (push) Successful in 1m33s
game-maker / suite (push) Successful in 5m37s
Stop animation gets a blend (s) port that fades the animation back to what
lies underneath. Play animation gets blend out (s) for Once (reset) and a
restart port that starts a running, paused or fading animation from frame 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 11:50:10 +02:00
adminandClaude Opus 5 8a377d9239 Play animation's blend is given in seconds, not in frames of the new animation (#106)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 11:14:15 +02:00
adminandClaude Opus 5 04dc254b3d Play animation can blend into the new animation over a number of frames (#106)
game-maker / gate (push) Successful in 1m33s
game-maker / suite (push) Successful in 5m34s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 10:03:53 +02:00
adminandClaude Opus 5 4ed2edd0f0 An animation is a value a graph can pick, and playing a running one makes it win again (#97)
Play, Pause and Stop animation take the animation on a port instead of a
fixed setting, fed by the new Animation literal or a list item tagged
`$animation`. Playing an animation already running keeps its frame but
counts it as started last, so turning back to a walk that never stopped
shows that walk. The actor demo walks through one Play animation over
`ItemAt(walk, facing)` again and stops every animation to stand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 20:47:31 +02:00
adminandClaude Opus 5 193378e6a9 An animation is a timeline of rows over one asset, played on an object rather than worn as a picture (#97)
Part (a) of the animation rework: model, commands, saving, runtime and nodes.

- AnimationAsset holds a root (sprite, text, container or scene) and rows; a row keys one
  property of the root or of an object inside it, keys sit on whole frames.
- The last key decides the length (its frame counts as a frame of its own). The playhead runs
  between frames, so numbers and colors blend every tick even at 10 fps; everything else holds.
- Playback gains `once-reset`, which puts back what was there before the start. A row can be
  relative, adding to where its target stood.
- Play / Pause / Stop animation act on an object; each instance plays on its own, the later
  start wins on a shared property, and a behavior writing the same property still writes last.
- A sprite no longer wears an animation through `texture`. "Create animation from texture"
  builds a sprite plus a texture row keyed frame by frame instead.
- The Animation tab shows a placeholder until the timeline editor (part b) lands.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 20:02:25 +02:00