Skip to content

Draw High Tide's wall on the canvas and let it be shaped - #458

Merged
SunkenInTime merged 10 commits into
mainfrom
t3/high-tide-wall-editor
Nov 2, 2026
Merged

SunkenInTime merged 10 commits into
mainfrom
t3/high-tide-wall-editor

Conversation

@SunkenInTime

@SunkenInTime SunkenInTime commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Shaping a High Tide wall in a release build

One cloud strategy in shipped 5.1.3 and in this PR

ci: test web

Third of four PRs. Players asked for "a 1:1 harbor wall that you can curve too instead of just the icon", and to "show were you want the wall to stop". A High Tide has been a lone icon on the canvas since the first release. This draws the wall and lets you shape it. Dara picked the curved wall with up to 6 bends, handles rather than drawing, and a new High Tide that lands with a straight 30 m wall.

What a user does

  • Drop High Tide. It lands with a straight 30 m wall running up the screen.
  • Hover the icon or the wall. White dots show on each point, pale dots between them, and a length tag at the end. On touch, selecting the icon shows them.
  • Drag a white dot to move it, or a pale dot to add a bend. Right-click a white dot to remove it. The wall stays smooth through every point and holds 6 bends.
  • It stops at 60 m, the blueprint's Max2D_Distance, and the tag says "60 m, the longest".
  • Drag the icon and the wall goes with it, in a single drag or a group drag.
  • A High Tide saved before this stays an icon on the same pixel. Right-click offers "Draw wall", and a wall offers "Remove wall".
  • E deletes it from the icon, the wall or a dot. Undo covers each drag. It flips with the side, copies to pages, and shows in screenshots and video. A page change morphs one wall into the other, and fades it when only one page has one.
  • Viewers see the wall and no dots.

The band is the #424 replay look, and both now share paintWallStroke. A wall doesn't cut view cones in the editor. Nothing does there today, smokes included.

How it's built

GuidedWallAbility extends BaseAbility, so High Tide's box and anchor are unchanged. The wall isn't inside that box. Flutter only delivers hits inside a widget's box, and growing the box would move every saved High Tide, so the wall and its dots are canvas layers of their own: PlacedWallList under the abilities, PlacedWallHandleList over everything. Only the band itself is hit, so items beside it stay reachable. lib/const/wall_path.dart holds the geometry, a centripetal curve that passes through every point and can't loop where points bunch up.

Saved data is #454's wallPath, which #449 protects from older clients. This PR adds no format change.

Ground truth

All in a release driver build of 00177fec, the head.

Old-build round trip, cloud, real 5.1.3 on dev. One strategy, three runs, stored rows read between each:

Step The High Tide's row Wall stored Level 1 reads Shipped reads
This PR writes a wall rev 2 at (766.3, 596.0) 3 points none none
5.1.3 moves the icon and adds an agent rev 3 at (860.3, 666.5) 3 points none none
This PR reopens it rev 3 at (860.3, 666.5) 3 points, wall at the moved icon none none

Saved pixel. test/high_tide_wall_test.dart renders a saved High Tide with the old BaseAbility and with this PR, on attack and defense: same box, same pixels. #454's run showed 5.1.3 and this data match pixel for pixel.

Sessions. tool/drive/scripts/high-tide-wall.json drags Harbor and High Tide from the real panels, bends the wall, hits 60 m, carries the icon and switches sides. high-tide-wall-menu.json covers "Draw wall" on a saved icon, adding and removing a bend, Ctrl+Z (the logged wall proves the key landed), a second page, and picture and video export. high-tide-wall-reopen.json reopens the store and deletes with E, and the log shows 1 ability going to 0. All CLEAN on Lotus. The video's frames show the wall morphing across the page change:

Frames across a page change in the exported video

test/high_tide_wall_test.dart has 36 tests that drive real pointers through the layers, including drags interrupted by a page change or a delete, and a bend added to 300 seeded walls. Of 26 mutations, 23 fail a test, one showed a guard was dead code, which I removed, and two survive. Taking the wall away under the pointer still cleared the delete target in the test harness, so that line isn't proven there; I kept it because a removed MouseRegion reports no exit. Starting a new bend at the pointer instead of on the wall also survives, because the limit guard covers that case too.

On web, real Edge against dev, same head

Shaping a wall in Edge at real speed

A release web build in headless Edge with the GPU on, at 1600 by 900, on a cloud strategy against dev. Playwright sent pointer and key events at human speed:

  • Dragged Harbor and High Tide from the panels, bent the wall, ran it to "60 m, the longest", carried the icon, switched sides, reloaded the page. The wall came back, and dev stored it at revision 6.
  • Ctrl+Z restored a bend removed by right-click.
  • It doesn't fight the browser. Across every drag: no dragstart, no text selection, no scroll. Right-click on a dot and on blank canvas both left the browser menu off, and the app's own right-click still worked. Frames stayed at 6.9 ms median and about 7 ms at p99 during drags, the display's limit in this run.
  • Hover at real speed. From 25 fps video: dots show within a frame of stopping on the wall and stay 220 ms after leaving. A 500 px pass over the wall in 250 ms shows no dots at all, so crossing one on the way elsewhere doesn't flash.
  • A second account. On a view-only link it sees the wall, gets no dots, and dragging pans the map. On an editor link, with both accounts open, it dragged the wall, the first account saw it move live, and after the first account's right-click and undo, both screens ended on the same wall. Dev stored revision 9, and level 1 and shipped readers still get no wall.

MP4 export

The earlier missing MP4 was the rig, not the app. Driver builds ship no ffmpeg folder, so plain MP4 stops at "Video encoder not found. Reinstalling Icarus should fix this." Transparent .mov uses a Dart encoder, which is why it ran. On a copy of this build with the ffmpeg folder from the installed 5.0.0 app added, a two-page wall exported a 1080p H.264 MP4 of 1.7 MB, with the wall morphing across the page change.

What isn't covered

  • Touch is covered by a widget test, not a real device. The web run was headless, so a person hasn't dragged these dots in a visible browser window.
  • Editor raster cost isn't measured. In replays the stroke cost nothing measurable, and the editor draws one per wall.
  • Thickness is the app's wall style, not a game number, so "1:1" means true length and true path.
  • A lineup's landing draws no wall. Nothing can give one a wall, since a lineup makes a fresh ability. The design said it would keep one; this is simpler.

Merge

On main, not stacked. #449 and #454 are merged, and convex/ isn't touched, so merging deploys nothing. PR 4, replay capture, comes after this.

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 386d3be4-6aef-4b97-b7a2-5466f3471c36
Commits

Reviewing files that changed from the base of the PR and between f55562b and 00177fe.

Files selected for processing: 17
  • lib/const/abilities.dart
  • lib/const/agents.dart
  • lib/const/settings.dart
  • lib/const/transition_data.dart
  • lib/const/wall_path.dart
  • lib/dev/drive/drive.dart
  • lib/widgets/draggable_widgets/ability/ability_visibility_context_menu.dart
  • lib/widgets/draggable_widgets/ability/placed_ability_widget.dart
  • lib/widgets/draggable_widgets/ability/placed_wall.dart
  • lib/widgets/draggable_widgets/placed_widget_builder.dart
  • lib/widgets/page_transition_overlay.dart
  • lib/widgets/replay/replay_effects.dart
  • test/high_tide_wall_test.dart
  • test/replay_frame_test.dart
  • tool/drive/scripts/high-tide-wall-menu.json
  • tool/drive/scripts/high-tide-wall-reopen.json
  • tool/drive/scripts/high-tide-wall.json
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

A new High Tide lands with a straight 30 m wall. Hovering it shows a white dot
on each point and a pale dot between them: drag a white dot to move a point, a
pale one to add a bend, right-click a white dot to remove it. It stops at 60 m
and holds six bends. A High Tide saved before this stays an icon on the same
pixel, and offers "Draw wall".

The wall and its dots are their own canvas layers, so the icon's box and every
saved position stay as they were.
…in the limit

A dot's draft and an icon's carried wall outlive a gesture whose widget has
gone, because Flutter ends those without a callback. A bend pulled from a
full-length wall started at the pointer, past the limit, so it now starts on
the wall. Dots stay when a mouse lets go on one, and a drag rebuilds only its
own wall.
@SunkenInTime
SunkenInTime force-pushed the t3/high-tide-wall-editor branch from f1659e1 to e8fbdab Compare November 2, 2026 01:57
@SunkenInTime
SunkenInTime merged commit db2285f into main Nov 2, 2026
15 checks passed
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.

1 participant