feat(style): animate + opacity + status lifecycle (pulse, ripple halo, done, muted) - #7
Merged
Conversation
…cycle presets
Adds three Style-schema fields (no new verbs, per the asset-style-ir
constraint) so agents can visually mark assets as being-processed /
completed / abandoned — e.g. survey stations in a pixel-drill demo:
- animate: generic property animation, a list of effects driven by ONE
shared client rAF loop: [{property: opacity|circle_radius|stroke_width,
from, to, period}]. glow stays as back-compat sugar that compiles to a
single opacity effect; [] stops a running animation.
- opacity: flat 0..1 static opacity on fills/lines/circles, composing
with the hover-highlight expression.
- status: one-word lifecycle sugar for LLM callers, expanded server-side
into concrete fields (explicit fields always win):
active -> attention pulse (opacity + marker-size)
done -> stop animation, full opacity, success stroke
muted -> stop animation, grayed out
Server: AssetStyle model validator expands status; update_style
broadcasts the EXPANDED style so clients only ever see concrete fields.
Frontend: glow engine generalized to the effects list; static opacity
paint; update_style cleanly starts/stops/re-tunes animations and resets
circle radius. SDK Style + update_style MCP tool docs mirrored.
Tests: tests/test_style_animate.py — status expansion, explicit-wins,
glow back-compat, animate round-trip, event round-trips, opacity-only
partial update. Demo: demo_status.py walks stations through
active -> done -> muted.
Note: the async-client fixtures share the pre-existing limitation that
StreamableHTTPSessionManager.run() is once-per-process (same pattern and
behavior as tests/test_assets.py on main).
…ssipates
Adds a "ripple" animate property: an auxiliary halo circle layer beneath
point markers whose ring expands (radius from→to px) while its opacity
ramps to transparent, then restarts — a sawtooth "dissipating wave"
rather than the existing sine oscillations. Optional "color" tints the
halo (defaults to the marker's fill color).
- models.py: document ripple in AssetStyle.animate; status="active"
preset now expands to opacity + circle_radius + ripple (3 effects) —
explicit animate still wins over the preset
- main.py (inline frontend): ensureHaloLayer/removeHaloLayer manage a
'halo-{asset}' circle layer (reuses the asset source, inserted below
the marker); animTick drives the sawtooth radius/opacity; registerAnim
wires the halo in, unregisterAnim removes it; normalizeEffects passes
the optional color through
- sdk/mapcontrol/models.py + mcp_tools.py: docs mirrored
- tests: +3 (active preset includes ripple w/ outward growth; custom
ripple round-trips) — 10/10 model tests pass; the 3 async-fixture
errors are the pre-existing StreamableHTTPSessionManager once-per-
process limitation (same as tests/test_assets.py on main)
- demo_status.py: finale now shows a raw ripple spec (8→40px, amber)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Style-schema animation extension:
animate+opacity+status(+ ripple halo)Adds attention-lifecycle styling to assets via the Style schema (no new verbs), so agents driving the map can visually indicate what's being processed:
New
AssetStylefieldsanimate— generic property animation, list of effects driven by one shared client rAF loop:[{"property": "opacity"|"circle_radius"|"stroke_width"|"ripple", "from": .., "to": .., "period": s}]rippleis a sonar-ping halo: an auxiliary ring beneath point markers expands (from→topx) while fading to transparent (sawtooth), then restarts. Optional"color"tints it.[]stops any running animation.opacity— static 0..1 opacity (composes with hover highlight).status— one-word lifecycle sugar, expanded server-side into concrete fields (explicit fields always win):"active"→ attention pulse (opacity + marker-size + ripple halo)"done"→ stop animation, full opacity, green success stroke"muted"→ stop animation, grayed outglowis kept as back-compat sugar compiling to a single opacity effect.Implementation
models.py: fields +_expand_statusmodel validator;update_stylebroadcasts the expanded style so clients/session-restore only ever see concrete valuesmain.py(inline frontend): generalized animation engine replacing the glow loop; halo layer management for ripple; static-opacity application; restyle start/stop viaupdate_styleStyledataclass + MCPupdate_styledocs mirroreddemo_status.py: 6-station drill-loop demo (active → done, muted pivot, raw ripple finale)Tests
server/tests/test_style_animate.py— 10/10 model tests pass. The 3 async-fixture round-trip tests hit the pre-existingStreamableHTTPSessionManager.run() once-per-processlimitation (same astests/test_assets.pyon main); not a regression.