feat: ambient (never-completing) effects and a noise module#97
Open
s-celles wants to merge 3 commits into
Open
feat: ambient (never-completing) effects and a noise module#97s-celles wants to merge 3 commits into
s-celles wants to merge 3 commits into
Conversation
`wave` provides periodic waveforms; this adds aperiodic ones. The distinction matters for effects meant to run continuously: a field driven by a sine visibly repeats and the eye picks the period out quickly, where noise does not. Deterministic pseudo-noise seeded by position rather than randomness, so a field is reproducible, testable, and stable across a resize. Also adds `math::rem_euclid`, since `f32::rem_euclid` is std-only and this has to build under no_std. Refs ratatui#96 Assisted-by: AI
Every existing effect is a transition: it runs once against a timer and finishes. These are meant to sit under a UI for as long as it is open, which changes two things. They never complete. `done()` is always false and there is no timer, so `execute` accumulates its own elapsed time from the tick duration. Driving them from a timer's alpha would mean looping it, which restarts the field and leaves a visible seam once a cycle. They each set the cell filter they can act on. An effect that paints an absolute colour needs blank cells; one that modulates an existing colour needs cells that carry a glyph. Applied to the wrong ones an effect runs, reports itself as running, and does nothing at all -- the failure mode is silence, so the constructors choose rather than leaving it to the caller. `with_filter` still overrides. Note for reviewers: the correct filter for blank cells is `Not(NonEmpty)`, not the more obvious `Not(Text)` -- `Text` matches the space character, so `Not(Text)` selects neither blanks nor glyphs. One `Ambient` shader with a `Kind` enum rather than seven structs: it keeps the elapsed-time bookkeeping in one place and stays `Clone` without boxing closures. All seven are registered with the default DSL, so applications can expose them as configuration rather than code. Refs ratatui#96 Assisted-by: AI
Cycles through the seven ambient effects on generic content that mixes text with blank space, so painting and modulating effects are both visible at once. Each is compiled from its DSL expression, shown on screen beneath the animation, rather than constructed in Rust -- what is running is exactly what a user could write in a config file. Reports frame rate alongside draw time, mean and peak. Frame rate alone would be uninformative: the loop blocks on an input poll, so it reads the target rate whatever the effect costs. Draw time is what reflects the effect's expense, and the peak is what is felt as stutter where the mean hides it. The target rate is adjustable with +/- so the difference between effects can be seen. Refs ratatui#96 Assisted-by: AI
Author
|
This is my first PR here. It have been done with AI assistance and as a reimplementation of some effects found in Tachikoma.jl from @kahliburke) so it may be imperfect.
|
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.


Implements what I described in #96. Opening it as a concrete proposal rather
than a finished thing.
What's here
pub mod noise— value noise, fbm, and two shaping curves. Deterministicpseudo-noise seeded by position, sitting next to
waveas its aperiodiccounterpart. Independent of everything below; useful on its own.
Seven effects. Three that paint cell backgrounds (
noise_field,color_wave,glow) and four that modulate existing colours (breathe,flicker,shimmer,drift). All registered with the default DSL.An example (
cargo run -p organic-effects) cycling through them on genericcontent, each compiled from its DSL expression rather than constructed in Rust.
The three commits are independent in that order —
noisecan be taken alone ifthe ambient question needs more discussion.
The design decisions worth arguing about
The code takes a position but I'm not attached to any of them.
Never-completing effects.
done()is alwaysfalse,timer()returnsNone, andexecuteaccumulates its own elapsed time from the tick duration.EffectTimersimply doesn't apply. Wrapping a transition infx::repeatingisn't an alternative: looping restarts the field and leaves a visible seam once
a cycle.
Constructors set a default cell filter. A departure from the rest of
fx::,which leaves the filter unset. These can't: a painting effect restricted to
glyphs, or a modulating one restricted to blanks, runs, reports itself as
running, and does nothing whatsoever. The failure mode is silence, so the
constructor chooses.
with_filterstill overrides.One
Ambientshader with aKindenum rather than seven structs — keepsthe elapsed-time bookkeeping in one place and stays
Clonewithout boxingclosures. Seven files would match the existing layout better; happy to switch.
Notes for reviewers
Not(NonEmpty)is the filter for blank cells, notNot(Text)—Textmatches the space character, so
Not(Text)selects neither blanks nor glyphs.This is the first of the two gotchas I mentioned in #96 and it cost me a while
to find.
math::rem_euclidis added becausef32::rem_euclidis std-only and this hasto build under
no_std.Testing
Full CI matrix locally, including
--no-default-features. Clippy adds no newwarnings over the 3 already on
development.Beyond the usual, the tests pin two things specific to ambient effects:
channel per second, at the parameters used in each doc example. This caught a
real bug:
noise_fieldoriginally shipped with a documentedspeedso low itdrifted about one RGB unit per second, which compiles, paints, reports itself
as running, and looks like a still image.
Written with AI assistance.