spectrum 0.2.1+1 spectrum: ^0.2.1+1 copied to clipboard
A rainbow of Color and Gradient utilities. Interpolate gradients with a realized GradientTween. New type Steps & shaded varieties. Color generation & operators.
spectrum #
pub.dev Listing | API Doc | GitHub #
Gradient API References: GradientUtils
| GradientTween
| Steps
| FooShadedSteps
| AnimatedGradient
Color API References: Shading
| ColorOperators
| ColorOperatorsMethods
| Spectrum
| SpectrumUtils
More: ColorArithmetic
Shades
| StopsArithmetic
Maths
| SwatchMode
| GradientStoryboard
| NillGradients
| MaterialColorToList
๐ธ Zaba.app โ simple packages, simple names.
A rainbow of Color
and Gradient
utilities such as GradientTween
,
gradient copyWith()
any potential parameters for the many types, Steps
-type gradients,
complementary()
for colors, AnimatedGradient
,
MaterialColor
generation,
and more!
๐ Table of Contents #
-
๐ Gradients
- ๐ซ Interpolation
- ๐ Steps
- ๐งน Softness
- ๐ถ๏ธ Shaded Steps
- โฐ Animation
- ๐ Gradient Storyboard
- ๐ Override Copy With
-
๐จ Colors
- โ Operators
- ๐๏ธ Spectrum
- ๐ค Complementary Colors
-
๐ฃ๏ธ Roadmap
๐ Gradients #
Feel free to consider any instantiated Gradient
and use a fancy Gradient.copyWith()
method to override some or all of its properties. This method accepts all manner
of potential Gradient
subtype properities and applies only the ones necessary
for the return.
This
GradientUtils
extension method is employed as the default "copy with" function throughout other portions ofspectrum
. This is achieved by a private methodspectrumCopyWith()
which fulfills theGradientCopyWith
type alias definition in default contexts where constructor argumentoverrideCopyWith
is not initialized.
Another gradient utility is the simple getter Gradient.reversed
which returns
a gradient with same properties, but whose colors
(and interpretted or
explicit stops
) are in reverse order.
๐ซ Interpolation #
Smooth Gradient
tweening not just by Gradient.lerp()
... oh no,
that is not enough.
This package provides full bespoke IntermediateGradient
s
for truly smooth and eye-popping gradient animations between dissimilar gradient
types!
The interpolated Gradient
is obtained via GradientTween.evaluate(Animation animation)
or transform(double t)
.
๐ก
Until betterList
interpolation is implemented, feel free to experiment withisAgressive
.
๐ |
---|
๐ Steps #
Spectrum also adds entirely new gradient types called Steps
,
as well as shaded varieties named FooShadedSteps
.
Imagine a gradient that somewhat defeats the idea of a gradient and, instead of
smoothly transitioning between colors, creates a series of hard steps.
This is achieved by intrinsically duplicating both the List<Color>
of colors
as well as the (interpreted or explicit) List<double>
of stops
. As a product
of this process, any explicitly initalized list of stops
ought to not end in
1.0
lest that stop get eaten. For example, a three-color Steps
could have
stops: [0.0, 0.3, 0.8]
.
๐ |
---|
๐งน Softness
A softness
may be increased or zeroed out depending on preference or user
device display density. A high-DPI screen would look just fine with an aliased,
hard edge between colors. A low-DPI screen would benefit from a (still,
incredibly small) softness
to provide as an additive for each second entry
when duplicating stops.
Imagine
Steps.stops
is[0.0, 0.3, 0.8]
. Providing asoftness
of0.001
, the effective, resolved stops for this gradient is now:[0.0, 0.001, 0.3, 0.3001, 0.8, 0.8001]
.
A larger softness has the effect of making Steps more like their original Gradient counterpart. The neighboring example transitions from softness: 0.0 -> softness: 0.14 . |
๐ |
---|
๐ถ๏ธ Shaded Steps
Now imagine more intrinsic color and stops math for a variety of
self-elaborating gradients... something like FooShadedSteps
may be born.
Each of Linear , Radial , and Sweep extends from the original Steps counterpart and overrides its steppedColors & steppedStops properties to actually "quadruplicate" these lists, optionally with a variety of customizable parameters (including the function to perform the color shading). The neighboring example is a LinearShadedSteps transitioning from a negative value to a positive value with LinearShadedSteps.shadeFunction defaulting with Shades.withWhite . |
๐ |
---|
โฐ Animation #
Provide an animation such as an AnimationController
to an AnimatedGradient
along with a gradient for which to alter the properties.
Obtain the actual Gradient
-type output by calling AnimatedGradient.observe
or by using the Gradient.animate(...)
convenience method, which inherently returns observe
.
Of course you may provide a number of Tween
s for properties like Gradient.center
or Gradient.begin
,
and these are provided with a TweenSpec
;
but consider other specialized functionalities: GradientAnimation.colorArithmetic
& GradientAnimation.stopsArithmetic
.
โ A
TweenSpec
is a new form oftypedef
wherein the definition is for a type ofMap
and not a type ofFunction
.
๐ |
---|
๐ Gradient Storyboard
All the animatable descriptions fit snugly into a "GradientStoryboard".
The storyboard
maps one or more GradientAnimation
enum constants to a description object that correlates.
(Expect potential changes in functionality here in the future.)
The above softness and ShadedSteps example gifs
are made by an AnimatedGradient
.
GradientAnimation (storyboard key ) |
Description Object (storyboard value ) |
Literal |
---|---|---|
colorArithmetic |
ColorArithmetic |
Color Function(Color color, double factor) |
stopsArithmetic |
StopsArithmetic |
double Function(double stop, double factor) |
tweenSpec |
"TweenSpec" Map | Map<GradientProperty, Tween<dynamic>> |
none |
null / anything |
null / anything |
In terms of GradientProperty
s,
the mapping is what would be expected. A property like GradientProperty.center
is mapped to a Tween<AlignmentGeometry?>
, and one like GradientProperty.radius
expects a value of a Tween<double>
.
final animatedGradient = AnimatedGradient(
controller: _controller,
gradient: RadialSteps(colors: Colors.red.complementTriad),
storyboard: {
// GradientAnimation.none: null, // disables any animations
/// "colorArithmetic" expects a [ColorArithmetic],
// such as a method from [Shades].
GradientAnimation.colorArithmetic: Shades.withOpacity,
/// "stopsArithmetic" expects a [StopsArithmetic],
// such as a method from [Maths].
GradientAnimation.stopsArithmetic: Maths.subtraction,
// GradientAnimation.stopsArithmetic:Maths.addition,
// GradientAnimation.stopsArithmetic:Maths.division,
/// "tweenSpec" expects a `Map<GradientProperty, Tween<dynamic>>`.
GradientAnimation.tweenSpec: {
GradientProperty.center: Tween<AlignmentGeometry>(
begin: const Alignment(1, 1), end: const Alignment(-1, -1)),
GradientProperty.focal: Tween<AlignmentGeometry>(
begin: const Alignment(3, -1), end: const Alignment(-3, -1)),
GradientProperty.radius: Tween<double>(begin: 0.5, end: 0),
GradientProperty.focalRadius: Tween<double>(begin: 2, end: 0),
GradientProperty.startAngle:
Tween<double>(begin: -1.0 * 3.1415927, end: 0.0 * 3.1415927),
GradientProperty.endAngle:
Tween<double>(begin: 2.0 * 3.1415927, end: 4.0 * 3.1415927),
GradientProperty.shadeFactor: StepTween(begin: -200, end: 0),
GradientProperty.softness: Tween<double>(begin: 0, end: 0.14),
. . .
},
},
);
Any properties that do not apply to the provided
Gradient
type are ignored.
๐ |
---|
๐ Override Copy With #
As an advanced feature, if you are operating with bespoke Gradient
types that
would not be hard-code recognized by this package, feel free to override the
GradientCopyWith
function in either a GradientTween
or an AnimatedGradient
.
This overriding function, which is expected to accept a large number of potential parameters, can be programmed to return your bespoke type.
Provide this GradientCopyWith
function as GradientTween.overrideCopyWith
,
for example, such as:
Gradient customCopyWith(Gradient original, { List<Color>? colors, List<double>? stops, . . . /* remaining potential parameters */ })
=> CustomGradient(
colors: colors ?? original.colors,
stops: stops ?? original.stops,
. . . );
---
final tween = GradientTween(
begin: customGradient,
end: differentCustomGradient,
overrideCopyWith: customCopyWith);
๐ |
---|
๐จ Colors #
โ Operators #
ColorOperators
are on deck as well as some nice methods to go along.
Aside from operators for objectives such as color inversion, averaging two colors, adding or subtracting them from one another, randomly making a choice of one amongst several options, or comparing the luminance of two colors...
ColorOperatorsMethods
exist for exposure of these extensions as well. These methods allow a
convenience pass for a value denoted strength
that may represent an "opacity"
at values ranging 0.0 .. 1.0
or represent an "alpha" component when greater
than or equal to 2
(clamped to 255
).
/// - [-], to invert a `Color`
///
/// - [>] & [<], to compare the luminance of `Color`s
///
/// - [+] & [-], to add/subtract the RGB components to/from one another,
/// maintaining the [alpha] from the original color `this`
///
/// - [~/], to average all components of two colors together, including [alpha]
///
/// - [|], to randomly choose a `Color`, either `this` or `Color other`;
/// unless the operand on the right is a `List<Color>`, then the random choice
/// may come from the list or `this`.
extension ColorOperators on Color { . . . }
/// - [inverted], for returning `-this`
/// - [compareLuminance], for returning the brighter or darker `Color`
/// utilizing `>`
/// - [or], for randomization by `Color | List<Color>`
///
/// The following methods resemble the operator counterparts but they have a
/// slot for provision of a `strength` or alpha/opacity override
/// (see [Spectrum.alphaChannel] for details):
/// - [add], to `+` one `Color` to another
/// - [subtract], to `-` one `Color` from another
/// - [average], to `~/` all channels of two `Color`s
extension ColorOperatorsMethods on Color { . . . }
// TODO: Examples of operators usage.
๐ |
---|
๐๏ธ Spectrum #
An abstract class called Spectrum
provides a few helper functions for Color
s, such as Spectrum.alphaChannel()
that performs the same function as described by the parameter strength
above.
Another static function Spectrum.materialColor()
allows the generation of an entire MaterialColor
swatch from a single Color
value with customizable options. Many color generation modes are available: SwatchMode.shade
or SwatchMode.desaturate
,
as well as more specialized modes SwatchMode.complements
and SwatchMode.fade
.
To generate a MaterialAccentColor
instead, check out Spectrum.materialAccent()
.
final color0 = Spectrum.materialColor(
color,
mode: SwatchMode.shade,
factor: 200,
);
// ๐ก The above has a shorthand: `color.asMaterialColor`, using shade @ 200
final color0a = Spectrum.materialAccent(
color,
mode: SwatchMode.shade,
factor: 200,
);
// ๐ก The above has a shorthand: `color.asMaterialAccent`, using shade @ 200
final color1 = Spectrum.materialColor(
color,
mode: SwatchMode.desaturate,
// factor: 0.2, // override opacity/alpha
);
final color2 = Spectrum.materialColor(
color,
mode: SwatchMode.fade,
// factor: 100 // TODO: provide same shading spread as SwatchMode.shade,
// (currently only performs .withWhite(factor) on the provided color)
);
final color3a = Spectrum.materialAccent(
color,
mode: SwatchMode.complements,
);
๐ก
With extensions onMaterialColor
andMaterialAccentColor
, employ getterasList
or methodtoList()
to convert these palettes into boiled-downList<Color>
, such as:// The getter does not insert the "primary" color at the beginning of the list. // (This value is typically mapped as `shade500` anyway.) final List<Color> shadesColor0 = color0.asList; // The method has a flag to insert the "primary" at the beginning of the list. // Default is `true` to differentiate versatility with `asList`. final List<Color> shadesColor3a = color3a.toList(includePrimary: false);
This makes a
MaterialColor
or accent color a great candidate for feedingGradient.colors
.final matColorGradient = LinearGradient(colors: shadesColor0);
Another extension adds a number of convenient getters and methods to any
instantiated Color
. These utilities, called SpectrumUtils
offer two "categories" of functionality: the first currently has one method,
a.blend(b,t)
which is shorthand for Color.lerp(a,b,t)
; the second category deals with the
generation of complementary colors.
๐ |
---|
๐ค Complementary Colors #
Color.complementary(int count)
is a method for turning a single Color
into a List
of length count
containing the original and a quantity of complements that you specify.
๐ก Use
Color.complementary()
to createGradient.colors
in a cinch!
Consider the color red . An example would be red.complementary(2) , which actually has a more efficient getter dubbed red.complementPair , that would return red and its inverse: [red, cyan] . It follows that red.complementary(3) , more efficiently gotten as red.complementTriad would return red and its complements: [red, green, blue] . |
Consider Color.complementary(4) , Color.complementary(5) or Color.complementary(6) for a nice assortment of pairings to pick from. |
A call like red.complementary(36)
returns a list beginning with red and
progressing through another 35 colors that, on the whole, resemble a gently
transitioning rainbow of colors, as each chip is 10ยฐ apart on the 360ยฐ
color wheel.
The red color is
Color(0xFFFF0000)
and the pink color isColor(0xFFFF61ED)
.
๐ |
---|
๐ฃ๏ธ Roadmap #
More to come. Package in progress.
๐ Bug reports very welcome!
Flesh out README and documentation with example images and code snippets;full comments pass for maintained accuracy and increased clarity.- Improve different methods for
GradientTween
,especially when considering new(see flagSteps
type gradientsisAgressive
) & tweeningIntermediateGradient
s themselves. Offer options for tween "mode". Support tweeningAnimatedGradient
. - Provide options for
Color.complementary()
such that the "distance" in color-wheel degrees could be customized, etc. - New
Color
utilities. - Self-animating variety of
AnimatedGradient
, which currently requires anAnimation<double>
parameter such as anAnimationController
. - Provide true gradient storyboarding with multiple gradients and keyframes.
- Brand new
Gradient
types? Consider expanding upon "shaded" concept.