Route page-transition agents around map geometry#102
Conversation
|
Implementation is ready on @greptileai please review this stacked diff against |
Greptile SummaryThis correction commit removes the previously-added reduced-motion branch and aligns agent path sampling with the existing
Confidence Score: 5/5Safe to merge — all code paths either produce a correct A*-routed path or degrade gracefully to direct interpolation, and no existing transition behavior is touched. The clearance check is now symmetric (all four segment endpoints tested via _segmentDistanceSquared), the A* heap is correctly implemented with lazy-deletion, positionAt samples the right segment with proper distance normalization, coordinate spaces are consistent end-to-end, and every early-exit in findPath falls back safely to [start, end]. The head commit removes the reduced-motion branch and routes path sampling through the same eased t as all other lerps — minimal and correct. No files require special attention. agent_path.dart is the densest file but its invariants are well-covered by the new tests. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as User navigates page
participant SP as StrategyProvider
participant GEO as viewConeGeometryProvider
participant PP as AgentTransitionPathPlanner
participant TP as TransitionProvider
participant OL as PageTransitionOverlay
UI->>SP: setActivePage(pageID)
SP->>SP: snapshot prev state
SP->>GEO: await future (async, catches errors)
GEO-->>SP: VisionGeometryMap or null on error
SP->>SP: addPostFrameCallback
note over SP: next frame
SP->>SP: _snapshotAllPlaced → entries
SP->>PP: plan(entries, geometry, isAttack, sizes, coordinateSystem)
PP->>PP: centerFor(startPos) and centerFor(endPos) in world coords
PP->>PP: elevationFor → max(start, end) elevation
PP->>PP: findPath(start, end, layer)
alt direct path walkable
PP-->>PP: AgentTransitionPath([start, end])
else "A* search"
PP->>PP: _nearestConnectableNode x2
PP->>PP: "A* with lazy-deletion heap"
PP->>PP: _reconstruct then _smooth path
PP-->>PP: AgentTransitionPath(smoothed waypoints)
end
PP-->>SP: agentPaths map
SP->>TP: transitionNotifier.start with agentPaths
TP->>TP: store agentPaths in PageTransitionState
loop each animation frame
OL->>OL: "t = easeOutCubic.transform(controller.value)"
OL->>TP: ref.read agentPaths[entry.id]
OL->>OL: agentPath.positionAt(t) → world center
OL->>OL: "pathTopLeft = center minus virtualOffsetToWorld(agentSize/2)"
OL->>OL: "_overlayScreenPosition(coordinatePosition = pathTopLeft)"
OL-->>UI: agent rendered at path-sampled screen position
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as User navigates page
participant SP as StrategyProvider
participant GEO as viewConeGeometryProvider
participant PP as AgentTransitionPathPlanner
participant TP as TransitionProvider
participant OL as PageTransitionOverlay
UI->>SP: setActivePage(pageID)
SP->>SP: snapshot prev state
SP->>GEO: await future (async, catches errors)
GEO-->>SP: VisionGeometryMap or null on error
SP->>SP: addPostFrameCallback
note over SP: next frame
SP->>SP: _snapshotAllPlaced → entries
SP->>PP: plan(entries, geometry, isAttack, sizes, coordinateSystem)
PP->>PP: centerFor(startPos) and centerFor(endPos) in world coords
PP->>PP: elevationFor → max(start, end) elevation
PP->>PP: findPath(start, end, layer)
alt direct path walkable
PP-->>PP: AgentTransitionPath([start, end])
else "A* search"
PP->>PP: _nearestConnectableNode x2
PP->>PP: "A* with lazy-deletion heap"
PP->>PP: _reconstruct then _smooth path
PP-->>PP: AgentTransitionPath(smoothed waypoints)
end
PP-->>SP: agentPaths map
SP->>TP: transitionNotifier.start with agentPaths
TP->>TP: store agentPaths in PageTransitionState
loop each animation frame
OL->>OL: "t = easeOutCubic.transform(controller.value)"
OL->>TP: ref.read agentPaths[entry.id]
OL->>OL: agentPath.positionAt(t) → world center
OL->>OL: "pathTopLeft = center minus virtualOffsetToWorld(agentSize/2)"
OL->>OL: "_overlayScreenPosition(coordinatePosition = pathTopLeft)"
OL-->>UI: agent rendered at path-sampled screen position
end
Reviews (4): Last reviewed commit: "Match agent transition easing" | Re-trigger Greptile |
Greptile SummaryThis PR routes agent markers around map geometry during page transitions using a bounded A* pathfinder that reuses the existing view-cone collision layers, elevation selection, and segment index. Non-agent transition behaviour is unchanged, and a direct-lerp fallback is preserved when geometry is unavailable or reduced-motion is enabled.
Confidence Score: 4/5Safe to merge; all 290 tests pass and non-agent transitions are untouched. The core pathfinding is correct — the A* heap, lazy deletion, path reconstruction, and string-pulling smoother all behave as expected, and the distance-normalised sampling correctly delivers constant-velocity motion. Two quality gaps exist: the clearance check in lib/page_transition/agent_path.dart — specifically Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant SP as StrategyProvider
participant VCG as viewConeGeometryProvider
participant PTO as PageTransitionOverlay
participant APF as AgentTransitionPathfinder
SP->>VCG: await future (preload geometry)
VCG-->>SP: VisionGeometryMap (or null)
SP->>SP: addPostFrameCallback snapshot and start transition
PTO->>VCG: watch(viewConeGeometryProvider)
VCG-->>PTO: AsyncData VisionGeometryMap
PTO->>PTO: _syncAgentPaths(state, geometry, isAttack)
PTO->>APF: findPath(start, end, layer) per move-entry
APF-->>PTO: "AgentTransitionPath (A* + string-pull)"
loop each build frame
PTO->>PTO: agentPath.positionAt(rawProgress)
PTO->>PTO: _overlayScreenPosition(pathTopLeft)
end
alt reduceMotion
PTO->>PTO: transitionProvider.complete()
end
alt geometry is null
PTO->>PTO: Offset.lerp(start, end, t) fallback
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant SP as StrategyProvider
participant VCG as viewConeGeometryProvider
participant PTO as PageTransitionOverlay
participant APF as AgentTransitionPathfinder
SP->>VCG: await future (preload geometry)
VCG-->>SP: VisionGeometryMap (or null)
SP->>SP: addPostFrameCallback snapshot and start transition
PTO->>VCG: watch(viewConeGeometryProvider)
VCG-->>PTO: AsyncData VisionGeometryMap
PTO->>PTO: _syncAgentPaths(state, geometry, isAttack)
PTO->>APF: findPath(start, end, layer) per move-entry
APF-->>PTO: "AgentTransitionPath (A* + string-pull)"
loop each build frame
PTO->>PTO: agentPath.positionAt(rawProgress)
PTO->>PTO: _overlayScreenPosition(pathTopLeft)
end
alt reduceMotion
PTO->>PTO: transitionProvider.complete()
end
alt geometry is null
PTO->>PTO: Offset.lerp(start, end, t) fallback
end
Reviews (2): Last reviewed commit: "Route page-transition agents with A-star" | Re-trigger Greptile |
| if (distance >= bestDistance || | ||
| !_pointIsWalkable(candidatePoint, layer) || | ||
| !_edgeIsWalkable(point, candidatePoint, layer)) { | ||
| continue; | ||
| } | ||
| best = candidate; | ||
| bestDistance = distance; | ||
| } | ||
| } | ||
| if (best != null) return best; | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| bool _pointIsWalkable(Offset point, VisionGeometryLayer layer) { | ||
| if (!layer.contains(point)) return false; | ||
| if (clearance <= 0) return true; | ||
| final nearby = layer.segmentIndex?.queryPoint(point, clearance) ?? |
There was a problem hiding this comment.
Inner rings are re-examined on each radius expansion
The nested loops at radius = r iterate the full square [center±r, center±r], so every cell at radii 0 … r-1 is rechecked. Because _pointIsWalkable calls layer.contains (a winding-number test over all mask segments) and possibly a quadrant-tree query, re-scanning those cells at each successive radius multiplies work that is already done. For typical values (radius up to 3, gridSpacing = 18) the overhead is negligible, but the intent — "search only the new ring when the previous ring found nothing" — would be clearer and more efficient with a ring-only iteration pattern.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
Addressed all current Greptile concerns in
Focused analysis is clean and the full Flutter suite passes (291/291). @greptileai please review the latest head. |
|
Corrected the transition behavior in
Focused analysis and all agent path tests pass. @greptileai please review the latest head. |
- Delete obsolete skill docs and scripts - Update agent instructions and lockfile references
What changed
easeOutCubicprofile so all agents retain the prior animation feel and arrive within the same transition durationWhy
Straight-line interpolation lets agents visually run through walls. The stacked view-cone work already provides authoritative, map-aligned collision geometry that can also guide page-transition movement.
Validation
fvm flutter test --no-pub test/agent_transition_path_test.dartLive verification note
No run registry entry exists for
E:\Projects\icarus-agent-page-pathing, so there is no running app or DTD/app URI to hot reload. The required globalflutter-run-registryskill is also unavailable in this session.