Repository navigation
Effects: add SquishEffect, a squash and stretch shader - #1755
Merged
Merged
Conversation
SquishEffect bulges a sprite's middle out, or pinches it in, while its top and bottom rows stay where they are. Paired with a change of height (bulge = 1 - scaleY, the height scaled about the feet) it gives squash and stretch that keeps the sprite's volume. A bulge widens the sprite past its own frame, and a ShaderEffect body has no vertex stage: the quad batchers transform corners on the CPU and the GPU vertex shader only projects. So the vertex step runs in the batchers. An effect sets `_vertexScale` (internal, 1 by default), the batchers scale its quad about the centre with UVs unchanged (`scaleQuad`), and the fragment narrows the texture back (`p.x *= uSquishXFactor`), the same split as a shader that scales VERTEX in a vertex function. The scale is 1 + bulge while bulging out and 1 otherwise, so the effect costs no extra fill at rest and every other effect is untouched. The fragment returns transparent outside the frame, so neighbouring atlas frames never bleed in. Tween: a tween stopped while the game updates no longer runs one more step and fires onComplete in the same frame. The game loop is itself a TICK listener and the emitter walks a snapshot of its listeners, so a tween stopped from an update() was still called for that tick. Replacing the jump stretch with the landing squash hit it: the old tween finished one frame later and snapped the player back to full height. `_onTick` now ignores a tween that is not running; the emitter is unchanged. Both platformer examples (built-in physics and Matter) stretch on take-off and squash on landing, eased back with Back.Out. The stretch is applied from update() because the Matter adapter rewrites currentTransform on every step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SeWCkETjW35ZbXDRswV1hx
Merged
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.
Adds
SquishEffect, a squash and stretch shader, uses it in both platformer examples, and fixes aTweenbug the examples exposed.SquishEffect
The middle of the sprite bulges out (
setBulge(0.3)) or pinches in (setBulge(-0.3)), and its top and bottom rows stay put. On its own it's a jelly wobble. Paired with a change of height it gives squash and stretch that keeps the sprite's volume: scale the sprite toscaleYof its height about its feet, and set the bulge to1 - scaleY. A stretched sprite then pinches in and a squashed one bulges out. Its doc page has the full example.Where the room for the bulge comes from
A bulge widens the sprite past its own frame, and the platformer's frames have only 0 to 5 px of margin. Without extra room the bulge is cut straight down both sides.
A shader with a vertex stage makes that room with
VERTEX.x *= x_factor. AShaderEffectbody has no vertex stage: the quad batchers transform corners on the CPU, and the GPU vertex shader only projects them. So the vertex step runs in the batchers:_vertexScale. It's internal and 1 by default.scaleQuad. The UVs stay inside the frame. This happens in the WebGL quad batcher, the WebGL lit batcher and the WebGPU quad batcher.p.x *= uSquishXFactor), then applies the bulge curve. It returns transparent outside the frame, so neighbouring atlas frames never bleed in.The scale is
1 + bulgewhile the sprite bulges out and 1 otherwise. So the effect adds no extra fill at rest, and every other effect is untouched.It's made for a sprite carrying it as its only effect. Chained with another effect, or on the camera, it squishes the whole frame. The bulge isn't part of the sprite's bounds, so culling and pointer events ignore it. On Canvas it disables itself like every other effect.
Tween: a stopped tween ran one more step
A tween stopped from inside the game's update still ran one more step in that frame, and fired
onCompleteif that step reached the end.TICKlistener, registered first.update()is still called for that tick.In the platformer, the landing replaced the jump's tween just as it was finishing. The old tween took its last step a moment later and snapped the player back to full height for one frame. Any game that stops or replaces a tween from an
update()could have anonCompletefire after the stop._onTicknow ignores a tween that isn't running. The emitter is unchanged: calling every listener in its snapshot is the usual emitter behaviour.Examples
Both platformers stretch to 1.25 on take-off, including a mid-air jump, and squash on landing by up to 0.25 depending on the fall speed. Both ease back with
Back.Outover 300 ms.isGrounded().currentTransformon every step, for every body, before the entities update. So both examples apply the stretch fromupdate()and let the tween animate a plain{ scaleY }. The effects skill documents this.Verification
squish-effect.spec.js, 19 tests:SpritethroughpreDrawscaleQuad, the setter andclone()Tweentests fail on the old code: 1 extra step and 1 completion afterstop().llms.txtlists the effect. The effects skill lists it with a usage section and two symptom rows. The 20.10.0 changelog has one entry under Added and one under Fixed.🤖 Generated with Claude Code
https://claude.ai/code/session_01SeWCkETjW35ZbXDRswV1hx