Skip to content

Animate cell#14

Merged
Stephan-342B merged 17 commits into
mainfrom
11-cell-animation
Jul 8, 2026
Merged

Animate cell#14
Stephan-342B merged 17 commits into
mainfrom
11-cell-animation

Conversation

@Stephan-342B

Copy link
Copy Markdown
Owner

Update readme

Update readme
@Stephan-342B Stephan-342B linked an issue May 16, 2025 that may be closed by this pull request
stephan and others added 16 commits July 6, 2026 19:17
…rid centering

Replace the hand-rolled AnimatableService/ServiceState orchestration with a
javafx.concurrent.Worker-based service layer, and center the grid with equal
left/right margins.

New package org.mahefa.service.concurrent:
- AnimationWorker<T>: implements Worker<T>, driving an AnimationTimer on the FX
  thread (READY -> SCHEDULED -> RUNNING -> SUCCEEDED/CANCELLED), with bindable
  state/running/value, cancel(), and setCurrentSpeed/onSpeedChanged for live
  speed changes.
- PathfindingWorker / MazeGeneratorWorker: reuse AStar/Solver and
  AldousBroder/MazeGenerator unchanged.

Wiring: GridService and MainWindowController use the workers; isReady binds to
runningProperty().not(). Old RouteFinderService/MazeService paths are commented
out, not deleted (project still in progress).

Grid centering: signed padding + drop the +5 canvas inflation so left/right
margins are equal (was left-heavy, occasionally flipping to the right).

Refs #15

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…x-worker

Migrate maze/pathfinding services to javafx.concurrent.Worker + fix grid centering
Infra-only migration to unblock native CSS animations; no behaviour change.

- JavaFX 20.0.2 -> 23 (via javafx.version property); Java baseline -> 21.
- Spring Boot parent 2.1.3.RELEASE -> 3.5.0 (Spring 6 / jakarta). The old
  spring-boot-maven-plugin could not process Java 21 classfiles that JavaFX 23
  ships as ("Unsupported class file major version 65"). No javax.* usage in
  source, so the jakarta move needs no code changes.
- Drop jfoenix (0 usages in source/FXML) and the stale explicit junit 4.11.
- Add org.mahefa.Launcher (does not extend Application) and point the
  spring-boot / exec plugins at it, avoiding the "JavaFX runtime components are
  missing" launcher guard for both forked run and fat-jar.
- Drop the redundant maven-compiler-plugin source/target (java.version drives it).

jfxanimation is kept for now; it's removed in PR 2 with the CSS-transition rewrite.

Verified: mvn compile clean; app boots via spring-boot:run through the launcher
(Spring Boot 3.5.0, Java 21), UI renders, ikonli 12.3.1 FontIcons render, no
runtime exceptions.

Closes #17

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Migrate to JavaFX 23 + Spring Boot 3.5.0 (infra) [1/2]
The sass-maven-plugin (3.7.2) runs SCSS compilation through embedded JRuby, whose
FilenoUtil reflects into java.base/sun.nio.ch. On Java 17+ that prints an
IllegalCallerException + stack trace during `mvn clean install`
(sass:update-stylesheets). It is non-fatal (CSS still compiles) and pre-existing
(unrelated to the JavaFX 23 / Spring Boot upgrade), just noisy.

Fix: open the package to the unnamed module for the Maven JVM itself (where the
plugin's JRuby runs) via .mvn/jvm.config:

    --add-opens=java.base/sun.nio.ch=ALL-UNNAMED

Verified: `mvn clean install` now completes with BUILD SUCCESS and no
FilenoUtil/IllegalCallerException output.

Closes #19

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix 'sun.nio.ch is not open to unnamed module' during the build
- Console shows only an INFO-level narrative: message-only %highlight
  pattern + logging.threshold.console=INFO (the key that keeps per-cell
  DEBUG off the terminal); framework logs quieted to WARN.
- New service.concurrent.progress package: Narrative (symbols + human()),
  ProgressReporter (daemon-ticker braille spinner, committed checkmark/cross
  line + summary), LogCleaner (Clear buttons reset the log; console WIPE|MARKER
  and file WIPE|APPEND|NEW_FILE handled independently).
- Workers own a ProgressReporter and drive it via new AnimationWorker hooks
  onSucceeded()/onCancelled()/updateMessage(); Solver/MazeGenerator expose
  search counters. A* logs cursor + frontier push/relax detail at DEBUG.
- Optional, opt-in per-session file log: LogFileInitializer attaches a
  timestamped Logback FileAppender (logs/pathfinding-fx-<timestamp>.log,
  TRACE threshold so it keeps the DEBUG detail the console drops). NEW_FILE
  rolls to a fresh timestamped file on clear.
- App-owned config namespaced under app.* and bound by AppProperties
  (@ConfigurationProperties, @ConfigurationPropertiesScan); clear modes bind
  directly as enums; AppProperties.Narrative#newLogCleaner() is the factory.
  Convert application.properties to application.yml.
- Remove the dead AnimatableService/MazeService/RouteFinderService/ServiceState
  service layer; add Heap.size() and enum getLabel().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Worker narrative logging + quiet console
Pure moves, no behavior change. Rename the base package/groupId
org.mahefa -> com.mahefa.pathfindingfx (reverse-domain) and regroup by concern:

- ui.component / ui.controller / ui.event / ui.animation / ui.style
- domain (Location, RouteNode, Cost) + domain.enumerator
- algorithm (State) + algorithm.pathfinding + algorithm.maze + algorithm.collection
- util, exception, config, service (+ service.concurrent[.progress])

Breaks up the old 'common' catch-all and separates JavaFX widgets from the
model that were both under 'component'. Updates the 3 FXML files (Navbar/MenuBar
imports + fx:controller), pom.xml (groupId + mainClass x2) and application.yml
(logging.level). Spring component scan is unaffected (entry point stays the base
package). Adds explicit imports where the component split crossed a same-package
reference (Cell/Grid -> domain.Location; RouteNode -> ui.component.Cell).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RouteNode now stores a domain Location for current/previous instead of a UI
Cell, so the whole com.mahefa.pathfindingfx.domain package is free of JavaFX and
ui imports. Solver's node map is keyed by Location; AStar resolves a Cell from
the grid where it needs to mutate the view (grid.getCellAt(row, col)).

Behavior is unchanged: the grid holds one Cell per location, so value-equality
keying by Location is equivalent to the previous identity keying by Cell.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refactor: package architecture (com.mahefa.pathfindingfx) + decouple RouteNode
Replace the per-algorithm AnimationTimer approach with a record/replay design
reusable across both algorithm categories:

- algorithm.step: Step / StepType / Stepper + AbstractStepper (shared superclass
  holding the pure GridModel and the lazy step buffer; subclasses implement only
  advance()/isComplete()).
- algorithm.grid: pure JavaFX-free GridModel snapshot + Moves (neighbours + A*
  turn cost, ported from GridUtils to operate on Location only).
- Steppers: AStarStepper (search + PATH steps carrying the arrow angle),
  AldousBroderStepper, RandomizedStepper — pure, reuse RouteNode/MinHeap/Cost.
- service.concurrent: StepPlayer (speed-controlled, testable pulse(now)); one
  reusable StepWorker driving any Stepper; GridSnapshot (UI→model boundary);
  StepTally + RunNarrative so the worker logs the ▶/live/✓ narrative for any run.
- ui.component.GridStepRenderer: the only UI-touching piece — StepType→Cell flag,
  and a faithful port of the A* "drawback" arrow that walks to the target.
- GridService.generateMaze/findPath flow through the single StepWorker; controller
  rewired accordingly.

Fixes / fidelity:
- Aldous-Broder start/target were left as walls — now opened (Flag NONE) up front;
  NodeType (START/TARGET) is never touched, so it is preserved.
- Restores the moving shortest-path arrow and the worker narrative log.
- PATH steps animate at a fixed interval (LaunchAnimationSpeed.SHORTEST_PATH),
  independent of the search-speed slider — matching the original drawback, which
  stayed fast even on SLOW.

Old algorithm classes and workers are @deprecated(forRemoval = true), not modified.
Tests: StepPlayerSpeedTest, StepPlayerPathSpeedTest, AStarStepperTest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reusable Stepper/StepPlayer pipeline for maze + pathfinding
JavaFX CSS has no @Keyframes, so the original web keyframe animations are
reproduced natively (no jfxanimation):

- ui.animation.NodeAnimations (javafx.animation only):
  - pop(Node): ScaleTransition for start/target icon appearance.
  - visited(Region): Timeline pulse (scale 0.3→1.2→1.0) + background morph
    dark-blue → blue → green → cyan, ending filled cyan (1.5s, ease-out).
  - shortestPath(Region): Timeline scale pulse 0.6→1.2→1.0 (1.5s, linear);
    yellow fill/border from CSS.
- MainWindowController flag listener: WALL→pop, VISITED→visited, SHORTEST_PATH→
  shortestPath; other flags (NONE/CURRENT) release the programmatic background and
  reset scale so CSS applies. Fixes the old missing-break/commented-CURRENT bug.
- cell.scss: base `.cell` gets `-fx-background-color: transparent` + a `transition`
  for the simple colour states (wall/current/shortest-path); `:visited` keeps only
  its border (background is animated by the Timeline).
- Deleted CellAnimation; removed the de.schlegel11:jfxanimation dependency.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reveal animations (NodeAnimations, cell.scss, controller):
- Run the visited/shortest-path scale+colour pulse on a transient overlay
  tile instead of the cell, so a cell's border (which doubles as the shared
  gridline) no longer ripples/collapses when the pulse shrinks it. The tile
  is created per reveal and removed on finish/interruption — no permanent
  per-cell node.
- Track the running reveal per node and stop it before starting a new one,
  so fast VISITED -> SHORTEST_PATH transitions can't fight over the same
  background/scale (fixes the colour overlap) or leak a tile.
- Restore the pop overshoot bounce (0.3 -> 1.2 -> 1.0): walls at 0.3s,
  start/target icons at 2s. Shortest-path pop now rides on the travelling
  arrow (0.6 -> 1.2 -> 1.0) so it stays cohesive without scaling the cell.
- Grid draws only top+left cell borders (last row/col add the outer edges)
  so shared gridlines aren't doubled into a bold 2px line.

Path arrow (GridStepRenderer, Grid):
- Remove the arrow from its previous cell by reference, not index 0, so the
  reveal tile isn't deleted instead and the arrow isn't stranded at the end.
- Clear stray arrows defensively on board clear.

Target node lifecycle (AStarStepper, GridStepRenderer):
- Don't mark the target CURRENT on arrival (pointer/shortest-path colours
  are identical, so it read as an early path cell); mark it VISITED, then
  SHORTEST_PATH only when the drawback arrow lands on it.

Basic random maze (StepPlayer, StepWorker, GridService, RandomizedStepper):
- Place all walls at once, independent of the speed slider, matching the
  original; Aldous-Broder stays paced. StepPlayer treats a non-positive
  interval as instant; StepWorker.runInstant drives it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cell animation via native CSS transitions (drop jfxanimation)
@Stephan-342B Stephan-342B marked this pull request as ready for review July 8, 2026 21:08
@Stephan-342B Stephan-342B merged commit fa30ff9 into main Jul 8, 2026
1 check failed
@Stephan-342B Stephan-342B deleted the 11-cell-animation branch July 8, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cell animation

1 participant