Installation
To make render times functionally instant, Dynamowaves intentionally eskews importing a library such as SVG.js to build a new SVG on execution.
Instead, it builds randomly seeded <paths> based on criteria you set,
and then leverages HTML web components (sorry, IE) to allow it to easily grab its reference element's applied attributes and then fully replace it with a slick lil' wave.
You can install Dynamowaves via npm, leveraging a CDN, or by including the script file directly in your project.
npm Installation
To install Dynamowaves via npm, run the following command:
npm install dynamowaves
After installation, you can import Dynamowaves in your JavaScript or TypeScript files:
import 'dynamowaves';
Angular Setup
To use Dynamowaves in an Angular project, follow these additional steps after installing via npm:
- In your
angular.jsonfile, add thedynamowavesscript to thescriptsarray:
"scripts": [
"node_modules/dynamowaves/dist/dynamowaves.js"
]
- In your
app.module.tsfile, addCUSTOM_ELEMENTS_SCHEMAto theschemasarray:
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
// ...
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }
Script Installation
Alternatively, you can include the Dynamowaves script file directly in your project:
<!-- Download and add to your project locally -->
<script src="path/to/dynamowaves.js"></script>
<!-- Or, reference the CDN -->
<script src="https://cdn.jsdelivr.net/gh/mzebley/dynamowaves/dist/dynamowaves.min.js" crossorigin="anonymous"></script>
Usage
Since Dynamowaves use HTML templating syntax, all it takes to call one is to add the custom element to your HTML!
<!-- Without any added attributes you get a top facing wave filled with the current color of its parent -->
<dynamo-wave></dynamo-wave>
A dynamo-wave will inherit any class, id, or style applied to its invoking element.
<!-- Example 1 -->
<dynamo-wave style="fill:slateblue"></dynamo-wave>
<style>
.fill-theme {
fill: var(--theme);
}
</style>
<!-- Example 2 -->
<dynamo-wave class="fill-theme"></dynamo-wave>
<style>
#special_wave {
height: 3rem;
width:80%;
transform: translateX(10%);
}
</style>
<!-- Example 3 -->
<dynamo-wave id="special_wave" class="fill-theme fill-light"></dynamo-wave>
Data Attributes
Dynamowaves come out of the box with a variety of data attributes that can be used to customize their appearance and behavior.
Points and Variance
A dynamowave will generate itself a new, randomized wave path each time it's rendered. This wave path is calculated using points, which determine the number of points that make up the wave path, and variance - the maximum amount each point can deviate from the wave's center.
| Attribute | Default | Options |
|---|---|---|
|
data-wave-points |
6 | Any positive integer |
|
data-wave-variance |
3 | Any positive integer |
<!-- Update the points and variance to change up your wave feel -->
<dynamo-wave data-wave-points="100" data-wave-variance="2"></dynamo-wave>
Legacy support: Existing markup that uses data-variance will continue to work, but data-wave-variance is the preferred attribute for clarity going forward.
Deterministic waves
Every generated wave encodes its exact SVG path into data-wave-seed. Copy that attribute to reuse the same shape anywhere:
<dynamo-wave id="hero-wave" data-wave-animate="true"></dynamo-wave>
<script>
const heroSeed = document.getElementById('hero-wave')?.getAttribute('data-wave-seed');
if (heroSeed) {
const footerWave = document.createElement('dynamo-wave');
footerWave.setAttribute('data-wave-seed', heroSeed);
document.body.appendChild(footerWave);
}
</script>
The value is a compact, URL-safe string representation of the full path; if it is present on an element, the component renders that exact path instead of generating a new one.
Anchored endpoints
When you need the wave to begin and end on the baseline—perfect for pinned backgrounds or matching solid color blocks—set data-start-end-zero. The attribute accepts boolean-like values such as "true", "1", or you can include it without a value. It works for both horizontal and vertical waves.
<!-- Empty attribute keeps the first and last points at height 0 -->
<dynamo-wave data-start-end-zero></dynamo-wave>
<!-- Explicit true value works as well -->
<dynamo-wave data-wave-face="left" data-start-end-zero="true"></dynamo-wave>
Wave Direction
Need more than a just a wave that faces up? Leverage the data-wave-face attribute.
| Attribute | Default | Options |
|---|---|---|
|
data-wave-face |
'top' | 'top', 'bottom', 'left', 'right' |
<!-- Bottom facing wave -->
<dynamo-wave class="fill-theme" data-wave-face="bottom"></dynamo-wave>
Wave Animation
Want a dynamowave that you can just sit around and stare at? You might be interested in the data-wave-speed and data-wave-animate attributes.
| Attribute | Default | Options |
|---|---|---|
|
data-wave-speed |
7500 | Duration in milliseconds |
|
data-wave-animate |
false | true, false |
Accessibility Note: The data-wave-animate attribute will be ignored if the viewer's browser has reduced motion enabled.
<!-- Animated wave -->
<dynamo-wave class="fill-theme" data-wave-speed="5000" data-wave-animate="true"></dynamo-wave>
Need to know when a loop finishes? Listen for the dynamo-wave-complete event to react when an animation cycle ends.
document.querySelector('dynamo-wave')
.addEventListener('dynamo-wave-complete', (event) => {
console.log('Wave finished animating', event.detail);
});
Wave Observation
Looking to really lean into generative design? The data-wave-observe attribute adds an intelligent IntersectionObserver to your dynamowave, enabling dynamic wave regeneration.
| Attribute | Default | Options |
|---|---|---|
|
data-wave-observe |
unset |
|
Margin Configuration: The optional pixel value after a colon adjusts the viewport intersection threshold. Use positive margins to start regeneration earlier, or negative margins to delay wave regeneration until the element is further from the viewport.
<!-- One-time wave regeneration -->
<dynamo-wave class="fill-theme" data-wave-observe="once"></dynamo-wave>
<!-- Continuous wave regeneration -->
<dynamo-wave class="fill-theme" data-wave-observe="repeat"></dynamo-wave>
<!-- Wave regenerates with 100px expanded viewport -->
<dynamo-wave class="fill-theme" data-wave-observe="repeat:100px"></dynamo-wave>
<!-- Wave regenerates with 50px contracted viewport -->
<dynamo-wave class="fill-theme" data-wave-observe="once:-50px"></dynamo-wave>
Available Functions
Dynamowaves come with a few functions that can be called to manipulate the wave after it's been rendered.
.generateNewWave()
Want to see a new wave? Call generateNewWave(duration) on the dynamowave you'd like to regenerate. The duration parameter is an optional integer that determines how quickly the old wave morphs into the new wave - default is 800(ms).
const wave = document.querySelector('dynamo-wave');
wave.generateNewWave(500);
.play()
Call play(duration) on any dynamowave that you'd like to animate. The duration parameter is an optional integer that determines the length of the animation loop - default is 7500(ms).
.pause()
To stop the animation loop, call pause() on the dynamowave you'd like to stop.
const wave = document.querySelector('dynamo-wave');
function toggleWaveAnimation() {
if (wave.isAnimating) {
wave.pause();
} else {
wave.play(5000);
}
}
Practical Application
Dynamowaves come out of the box entirely style agnostic. The onus is on the developer to add the necessary attributes to get them to fit their intended platform, but at the same time this provides nearly endless possibilities for customization.
Make use of position:sticky and create a neat little header!
<!-- Widget classes not, uh, provided out-of-the-box -->
<div class="widget">
<div class="header">
<h2>I'm the heading!</h2>
<dynamo-wave data-wave-face="bottom"></dynamo-wave>
</div>
<div class="content">...</div>
</div>
Use an animated dynamowave to add some more pizzazz to transition effects.
Slap one of these bad boys along the edge of a photo to create an always fresh, mask-image effect without having to actually create multiple clip paths or image masks!
<div class="widget horizontal">
<div class="image-wrapper">
<img src="./img/image_path.jpeg" />
<!-- When covering an image, I find it helps the browser render
to set the far edge with a bit of a negative overlap
It keeps the image from peeking through from behind the wave -->
<dynamo-wave data-wave-face="left" style="fill:var(--widget-bg);position:absolute;right:-1px"></dynamo-wave>
</div>
<div class="content">...</div>
</div>