Procedurally generated, calm background textures
npm install @sprig-and-prose/sprig-textureProcedurally generated, calm, parasympathetic background textures for use across projects.
This library generates seamless, tiling textures designed to:
- Eliminate gradient banding and grid artifacts
- Provide subtle "paper / watercolor surface" material
- Create calm, non-distracting backgrounds
- Be deterministic (same key = same texture)
Important: This library generates neutral material textures. Lighting, vignettes, and mood gradients belong in CSS, not in the texture bitmap.
``javascript
import { generateTexture, releaseObjectUrl, nightInk, bloom } from 'sprig-texture';
const { canvas, blob, url } = await generateTexture({
key: 'my-unique-key',
palette: nightInk,
preset: bloom,
});
// Use the URL as a background image
element.style.backgroundImage = url(${url});
element.style.backgroundRepeat = 'repeat';
element.style.backgroundSize = '1024px 1024px';
// Clean up when done (prevents memory leaks)
releaseObjectUrl(url);
`
Textures are deterministic: the same key + palette + preset will always produce the same texture. This allows caching and consistent rendering across sessions.
- nightInk: Dark blue-gray tones (default)
- parchment: Warm paper tones
- quiet: Minimal variation, subtle
- bloom: Slightly richer, more variation (default)
This package includes a reusable CSS module for creating watercolor brush stroke effects, perfect for highlighting keywords, badges, or decorative elements.
`css`
/ In your CSS file /
@import 'sprig-texture/src/styles/watercolor-stroke.css';
Or in JavaScript/TypeScript (if your bundler supports CSS imports):
`javascript`
import 'sprig-texture/src/styles/watercolor-stroke.css';
Apply the .watercolor-stroke class to an element and set CSS variables for color and opacity:
`html`
COLLECTS
The effect is applied via a ::before pseudo-element, so ensure your element has position: relative:
`css`
.my-badge {
position: relative;
display: inline-block;
padding: 0.1rem 0.45rem;
}
The CSS includes several pre-configured color variants that you can use via data attributes:
`html`
COLLECTS
EXPANDS
OPTIONAL
AGGREGATES
Override the CSS variables to use your own colors:
`css`
.custom-stroke {
--watercolor-pigment-color: rgba(120, 60, 200, 1);
--watercolor-opacity: 0.35;
}
The stroke position is controlled by four CSS properties on the ::before pseudo-element. To adjust the position, override these values:
`css`
.my-element::before {
top: -1.2rem; / move stroke DOWN = make this LESS negative /
bottom: -0.54rem; / move stroke UP = make this MORE negative /
left: -0.80rem;
right: -0.80rem;
}
The watercolor effect is created using:
- Radial gradients for the pigment color distribution
- Clip-path polygon for the wavy brush stroke shape
- Blur filter for soft edges
- Mix-blend-mode: screen for the watercolor blending effect
- Subtle transforms (rotate, skew) for natural variation
1. Texture ≠ lighting: The generated bitmap is neutral material; CSS handles mood
2. Micro-variation prevents banding: Multi-scale noise (low, mid, high frequency)
3. Subtlety over effect: Everything should be "barely there"
4. Forgiving defaults: generateTexture({ key }) should look good
The texture is generated in 5 layers:
1. Base fill: Palette-driven base color
2. Ultra-low-frequency tone drift: Very large radial washes to prevent flat regions
3. Mid-frequency mottling: Soft radial blobs for material variation
4. Paper grain / speckles: Soft dots for texture and anti-banding
5. Fiber strokes: Thin strokes with vertical bias
All layers tile seamlessly.
Generates a texture and returns a Promise resolving to { canvas, blob, url }.
- args.key (string, required): Deterministic seed keyargs.size
- (number, optional, default: 1024): Canvas size (square)args.palette
- (Palette, optional): Color palette (default: nightInk)args.preset
- (Preset, optional): Numeric parameters (default: bloom)
Releases an object URL created by generateTexture(). Call this when you're done using the texture to prevent memory leaks in long-running sessions.
See examples/demo.html for a working demo with controls.
To run the demo, start a local server:
`bash`
npm run serve
Then open http://localhost:3000/examples/demo.html in your browser.
Alternatively, you can use any static file server:
- npx serve . (if you have serve installed)python3 -m http.server 8000` (Python 3)
-
- Or any other static file server