THE FIELD GUIDE
From the first flake
to your own forecast.
Install the package, choose a surface, and start the weather. Practical documentation for a considered integration.
Your first snowfall.
Fluri’s packages are prepared for their first npm release. You can use the built package archives from this site today. Download them, then install the local files in your project.
npm install ./themes-fluri-0.1.0.tgz
After registry publication, the package name is @themes/fluri. The
optional adapter is @themes/fluri-react. These downloads contain compiled
ESM, TypeScript declarations, README, and MIT licensing.
import { createWeather } from '@themes/fluri';
const weather = createWeather({
preset: 'gentle-snow',
dom: { detection: 'explicit' },
});
weather.start();
// Release the effect when your page unmounts.
window.addEventListener('pagehide', () => {
weather.destroy();
}, { once: true });
Importing the library and creating an idle controller are safe during server
rendering. Call start() in the browser after mount.
autoStart defaults to false.
Bring your own framework.
The core uses browser APIs. Use the React adapter for automatic lifecycle cleanup, or pair the controller with your framework’s mount and unmount hooks.
For React, install both archives with React already in your application:
npm install ./themes-fluri-0.1.0.tgz ./themes-fluri-react-0.1.0.tgz
import { createWeather } from '@themes/fluri';
const weather = createWeather({
preset: 'gentle-snow',
dom: { detection: 'explicit' },
});
weather.start();
// Release the effect when your page unmounts.
window.addEventListener('pagehide', () => {
weather.destroy();
}, { once: true });
import { useFluri } from '@themes/fluri-react';
export function WinterPage() {
const weather = useFluri({
preset: 'gentle-snow',
dom: { detection: 'explicit' },
});
return (
<article data-weather-surface>
<h1>A little winter.</h1>
<button onClick={() => weather.current?.pause()}>
Pause snow
</button>
</article>
);
}
<script setup lang="ts">
import { onMounted, onBeforeUnmount } from 'vue';
import { createWeather } from '@themes/fluri';
const weather = createWeather({ preset: 'gentle-snow' });
onMounted(() => weather.start());
onBeforeUnmount(() => weather.destroy());
</script>
<template>
<article data-weather-surface>A little winter.</article>
</template>
Next.js integrations belong in a client component with 'use client'. The
React hook starts after mount and cleans up on unmount; it is safe with Strict Mode
setup replay.
Give snow a place to land.
For predictable behavior, choose explicit detection and label the elements you want to collect snow. Keep important controls and dense content clear.
<article data-weather-surface data-weather-snow-depth="14">
Snow can settle here.
</article>
<section data-weather-ignore>
Keep this content clear.
</section>
const unregister = weather.registerSurface(element, {
material: 'sticky',
maxSnowDepth: 12,
layer: 'content',
});
// Remove this registration when it is no longer needed.
unregister();
Supported materials: flat, slippery, sticky,
and no-accumulation. Explicit surfaces can override depth, accumulation,
layer, and clipping behavior.
Set your forecast.
Start from one of the ten presets and override only the values you need. Configuration is validated at runtime and fully typed.
const weather = createWeather({
preset: 'gentle-snow',
snow: {
intensity: 0.45,
wind: { base: 0.12, gusts: true },
accumulation: { maxDepth: 14 },
},
dom: { detection: 'explicit', maxSurfaces: 60 },
performance: { adaptive: true, maxDPR: 1.5 },
accessibility: { reducedMotion: 'respect' },
});
Use the playground to change options live and export validated JSON. The complete API reference documents defaults, ranges, attributes, events, and plugin hooks.
Share your website, on your terms.
The library has no automatic installation reporting or visitor analytics. Owners can separately register a domain, verify control, and choose whether to share daily aggregate counts or request a public community listing. Website-owner approval does not replace any visitor consent required by the source analytics.
Register or manage a website ↗ · Read the reporting and privacy guide ↗
Keep control of the weather.
| Method | What it does |
|---|---|
start() |
Create the overlays and start the simulation. |
pause() / resume() |
Temporarily pause or resume the effect. |
stop() |
Stop the animation and clear its visuals. |
destroy() |
Release overlays, listeners, observers, and plugins. |
setIntensity(0.5) |
Change snowfall intensity from 0 to 1. |
setPreset('minimal') |
Switch preset at runtime. |
updateConfig(patch) |
Apply a typed partial configuration. |
addSnow(8) / clearAccumulation() |
Add deposited snow or clear it. |
trigger('gust') |
Trigger an intentional effect. |
getMetrics() |
Read runtime budgets, counts, state, and timings. |
Store the controller in your page or component lifecycle. Destroy it when the owning page or component leaves. A destroyed controller cannot be restarted; create a new instance for a new lifecycle.
A little Christmas, on purpose.
The Christmas module is a separate import. Choose its effects, then label the surfaces where each should appear.
import { christmasPack } from '@themes/fluri/christmas';
const removeChristmas = weather.use(christmasPack({
lights: { warmth: 0.9 },
garlands: true,
frost: true,
}));
// Remove this plugin independently when the season ends.
removeChristmas();
<nav data-weather-surface
data-holiday-lights
data-holiday-garland>
A warmer welcome.
</nav>
Other supported effects include ornaments, gifts, icicles, wreaths, sparkle, and candy canes. See the API reference for each option and attribute.
Leave room for the rest of your page.
Keep adaptive performance enabled. It bounds the requested snowfall by visible area and device input class, responds to sustained late frames, and reduces rendering detail under pressure. Overflow parcels are bounded and coalesced.
- Start with a gentle or minimal preset and explicit surfaces.
-
Use
dom.maxSurfaces,snow.particleCount,performance.maxDPR, andperformance.maxFPSto set your budget. - Measure on your own page and physical target devices.
- Inspect
getMetrics()or the playground’s Quality panel.
Performance depends on the browser, device, page styles, and effects. A local benchmark is not a cross-device guarantee.
Make motion optional.
The default accessibility.reducedMotion: 'respect' honors the
operating-system reduced-motion preference. Hidden tabs suspend animation. Offer
visitors an accessible pause control if you add a continuous effect.
const pause = document.querySelector('button');
pause?.addEventListener('click', () => {
const paused = weather.getMetrics().state === 'paused';
if (paused) weather.resume();
else weather.pause();
pause.setAttribute('aria-pressed', String(!paused));
});
Snow is decorative. Keep important information in normal HTML, preserve readable contrast, and test keyboard and touch behavior with the effect running.
Know the edges.
Fluri uses an approximation of supported DOM geometry, clipping, and paint order. It cannot exactly reproduce arbitrary CSS composition or a true three-dimensional simulation.
- Closed shadow-root internals and cross-origin iframe contents are not inspectable.
- Complex masks, perspective transforms, and some native top layers have limits.
- Automatic surface detection is heuristic; use explicit registration for reliable control.
- Browser emulation does not replace testing on a physical phone.