Skip to content

Sprite Lab in Lab2: effects - #75703

Open
breville wants to merge 18 commits into
stagingfrom
spritelab-lab2-effects
Open

breville wants to merge 18 commits into
stagingfrom
spritelab-lab2-effects

Conversation

@breville

@breville breville commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

[written by Claude]

Two new blocks on the free play level: set weather to [none | rain | snow] fills the whole scene with weather that reacts to the world, and burst N [sparks | confetti] from [sprite] flings a flourish out of a sprite. Both run as a particle layer in the engine, not as sprites: they never count against the sprite budget, answer no events, and appear in no picker.

Both descend from legacy Sprite Lab's effect blocks. create [burst | pop | rain | spiral] effect with N [image] sprites (gamelab_makeBurst) spawns a one-shot batch of real sprites, each given a behaviour and a short lifetime, from the stage centre and against the sprite limit; do [effect] effect (gamelab_setForegroundEffect) paints a canvas overlay with rain, confetti and a starburst among its looks. The burst block keeps the first one's shape and gains an origin sprite and a look instead of an image; the weather block takes the overlay's rain and makes it continuous and world-aware. Neither legacy block is in a Lab2 toolbox.

What students see

  • Rain falls at a slight angle, splashes off tiles and characters without reaching into them, and is already falling on the first frame. Snow sways down, rests on a tile for half a second and fades, and melts when a character touches it without being pushed. None turns it off.
  • Weather follows gravity. Flip it and the drops slow, turn, and come up to speed the other way, landing on the undersides of tiles. Zero gravity still reads as a side view, so weather falls as under the default.
  • Sparks are hot whites and golds, fast and brief, shrinking as they fade. Confetti is coloured paper that launches gentler, floats down slower, tumbles, and lasts two to three times longer. Bursts pass through everything. A second burst adds to the first; an image on several sprites bursts from each of them; no sprite means the middle of the stage.
  • Weather lands on things and bounces off them but never moves anything and never fires a touch event.

Recordings

Rain & sparks

Screen.Recording.2026-10-01.at.3.30.24.PM.mov

Snow & confetti

Screen.Recording.2026-10-01.at.3.31.30.PM.mov

Rain with a gravity flip

Screen.Recording.2026-10-01.at.3.30.54.PM.mov

How

  • weather.ts: a pool of plain records per kind with a rule table (count, speed, sway, what a contact with a tile or a body does), a felt gravity that eases toward the scene's, and drawing in world space. bursts.ts: one-shot bursts with a table per look (launch, drag, fall, life, size, shape, palette) and a fade through the canvas alpha, since in our p5 a tint's alpha is tint strength, not opacity.
  • The engine steps and draws both inside the paint after the sprites, so they sit under the camera, and steps once per frame even when a thumbnail capture paints twice. Weather gets the tiles and every other sprite as bodies through the platform resolver's own collision geometry (wallBox, bodyBox, now exported from platformPhysics.ts). The spark image (static/spritelab_lab2/particles/spark.png, drawn in code) is tinted once per palette colour into a p5.Image; a p5.Graphics would not do, since its canvas is scaled by the pixel density while image() reads it at its logical size.
  • Two lab-defined blocks, added to both scene toolboxes of the free play level; the burst's sprite field joins the rename and delete cascades. Bursts are capped at 100 per call and 400 in flight.

Tried and set aside

  • Particles as sprites through the resolver: plain records were simpler and cheaper, and the resolver's geometry could be shared without them.
  • Weather anchored to a sprite (chimney smoke, a sparkling treasure): deferred for world-wide weather; the pool and rules would carry over.
  • A splash ring where rain lands read as a drawn effect; the drop now bounces, fades and vanishes instead.
  • Snow pushed aside by the player felt like shoving snow around; a touched flake now keeps its path and melts.
  • Hanging in zero gravity: a weightless scene still reads as a side view, so zero falls as the default.
  • Bursts of a project image that landed, bounced and rested read as items to pick up, not a flourish; replaced by sparks that touch nothing.
  • Sparks and confetti as one motion in two palettes were indistinguishable; each look now has its own motion and shape.

Where this could go

  • A student-editable system. Each weather kind and burst look is a handful of settings (count, speed, what happens on contact, colours), which is the shape the Systems idea from the behavior2 prototype needs: blocks like "set rain to N drops" or "make snow bounce off tiles" would change those settings, and the engine would run them as it does now.
  • Events from contacts. The body contact in the weather step knows which box it hit, so "when rain hits [sprite]" is a lookup and a dispatched event.
  • Anchored emitters and student images are each one more setting (where particles start, what they are drawn with) plus a block to set it.

Testing

  • Unit tests for the weather (pool, recycling, contacts for both kinds, seeding outside tiles, a bouncing drop's streak staying above its tile, gravity easing and flip, undersides, zero gravity, drawing), the bursts (spread, colours, drag and gravity, the two looks' motion, the fade, image and paper drawing), the exported boxes, and both blocks' generators and dropdowns.
  • In the browser as a test student: rain and snow on the platformer demo level at 61fps; a gravity flip landing drops under tiles; both blocks generating their calls from the free play flyout and running on Play, including sparks after the p5.Image fix.
  • Not tested: a touch device.

breville and others added 17 commits October 1, 2026 20:07
…layer

A fixed pool of particles falls through the scene once a frame inside
the paint, under the camera in a platform scene. Rain splashes on a
tile and comes back from the top; snow rests on a tile for a second and
fades; both bounce off a player. Particles are plain records, not
sprites: no block can name them and no event sees them. The engine
starts every run in a default weather (a URL switch sets it until a
block exists) and exposes a set-weather command for the block to come.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e it

A flake swaying sideways below a tile's top never crossed the top, so
it fell on inside the tile and drew over it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tact

The felt gravity eases toward the scene's, so a flip slows the drops,
turns them, and brings them up to speed the other way; at zero they
hang. Every contact is one rule, settle for some frames with or without
a bounce: rain bounces a little and vanishes on tiles and bodies alike;
snow rests on a tile for a second and melts off a body in ten frames.
Bodies are every sprite that is not a tile. The pool starts spread along
the whole fall and comes around from a world's height beyond the edge,
so it never arrives in waves. The splash ring is gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A contact can let the particle pass: no snap to the surface, no shove
out of the body's side, any overlap counts. Snow uses it for bodies, so
walking through snow no longer pushes flakes sideways; they fade where
they are, still falling.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…gravity

A scene at zero gravity still reads as a side view, so its rain and
snow fall as they would at the default. Only a flip turns them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
"set weather to [none | rain | snow]", in both of free play's scene
toolboxes. A run starts with no weather; the block sets it until the
next set or the end of the run. The URL switch that stood in for the
block is gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
"burst N [image] from [sprite]" on the free play level. The copies
launch in every direction with a little lift, fall with the scene's
gravity, bounce off tiles, characters and objects losing energy each
time, spin, and fade over their last third; in a story scene they land
on the stage floor. They are the student's own image at particle size,
drawn from the preloaded map, or decoded on demand once if the scene's
preload never saw the name. An image naming several sprites bursts
from each with the count shared out; none names the stage centre. A
second burst adds to the first. Capped per call and in flight.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A bounce that would be a hop ends the motion, a stopped particle lies
still for twelve frames, and every particle fades over its last eight,
so nothing lingers on the ground as if it were there to pick up.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…thing

The burst block flings tinted sparks from one shipped spark image, in a
sparks or a confetti palette, instead of copies of a project image. The
particles slow in the air, fall with the scene's gravity, pass through
tiles and bodies, and are gone in under a second, so a burst reads as a
visual effect and never as items left to pick up.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Over the last two fifths of a particle's life, as its motion dies away,
instead of a snap at the very end.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Each look has its own motion. Sparks are hot, fast and brief, and
shrink with their fade over the last half of their life, so the end is
visible on a small spark. Confetti launches gentler, falls at a third
of the rate with more drag, lives two to three times longer, and draws
as a scrap of paper that turns edge-on and face-on as it tumbles.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sparks fade through the canvas alpha, from a spark image tinted once
per palette colour: in this p5 a tint's alpha is strength, not
opacity, and recolouring per particle rebuilt a canvas each draw. The
particles step once per frame though a thumbnail capture paints twice.
No weather is seeded inside a tile, and one boxed in by a row of tiles
lands on the tile it is in instead of falling through. A burst's
allowance is shared out exactly over its origins. The weather reads
its tile and body boxes from the platform resolver's own geometry.
Only live weather gathers the scene's boxes. The rain streak follows
the wind the drop drifts with, and a melting flake keeps its sway.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…hics

A p5.Graphics canvas is scaled by the sketch's pixel density (2x the
device ratio here) while image() samples it at its logical size, so
each spark showed one corner of the glow.  A p5.Image stays 1:1.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@breville
breville requested a review from a team October 1, 2026 22:19
@breville breville added the AI generated This PR has been substantially generated using AI. label Oct 2, 2026
@breville
breville requested review from dju90 and wilkie October 2, 2026 00:17
The streak trails a drop's motion, so during the bounce it pointed back
into the tile by a few pixels for the fading frames.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@markabarrett markabarrett left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI generated This PR has been substantially generated using AI.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants