Skip to content
flurithemePublic

About

Winter by Fluri Themes — DOM-aware interactive snowfall, accumulation, snowballs, a playful yeti and Christmas effects. TypeScript + React.

Topics

Resources

Contributing

Security policy

Accessibility

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

23 Commits

Folders and files

Repository files navigation

Winter by Fluri Themes — Change the forecast.

Winter by Fluri ❄️

Interactive snowfall that feels at home on your website.

DOM-aware snow accumulation, playful physics, and optional Christmas effects.
Built with TypeScript. Made for your interface.

License: MIT TypeScript: typed API Framework independent Renderer: Canvas 2D

npm downloads for @fluritheme/fluri over the last 30 days

Live playground · Explore the presets · Documentation · Founder

Quick start · Features · React & Next.js · API · Contributing


Fluri is a JavaScript and TypeScript snow animation library for the web. Snow gathers on supported DOM edges, follows moving elements, and falls onto surfaces below. Visitors can brush it away, gather snowballs, watch a tiny snowplough clear a path, or invite a mischievous yeti to start a snowball fight.

Use a light dusting on a portfolio, a playful snowfall on a landing page, or warm Christmas lights on the surfaces you choose. Your content stays in ordinary HTML; Fluri draws the winter around it.

Why Fluri?

Three Fluri features: snow follows a card’s edges, a pointer brushes snow into powder, and sliders customize snowfall and wind.

  • Snow with somewhere to land. Surface-local accumulation follows supported DOM geometry, scrolling, and responsive layouts. Uneven packing and rounded shoulders give each pile its own shape.
  • A tiny yeti with a plan. Opt in to an animated visitor that sneaks over, scoops real snow, packs a ball and aims at your snowman. Hits knock it apart; moving targets can make it miss. No images or animation assets to load.
  • A little room to play. Brush deposits, gather and throw snowballs, build a snowman, or run a snowplough along a designated shelf.
  • Your website, your forecast. Ten presets, typed overrides, adjustable wind, flake styles, snow depth, and live configuration export.
  • A good guest. Pointer-transparent canvases, reduced-motion support, hidden-tab suspension, adaptive quality, and explicit cleanup.
  • Local by default. The engine needs no account, API key, geolocation, analytics, cookies, or external weather service.
  • Christmas, on purpose. Optional lights, garlands, ornaments, gifts, frost, icicles, wreaths, candy canes, and sparkles on explicitly marked elements.

The Winter playground: purple live snow scene, draggable surfaces and a panel of snowfall, wind and interaction controls.

Try the live engine →

Quick start

npm install @fluritheme/fluri

Also available on jsDelivr and UNPKG. npm is the recommended way to integrate Fluri with your build tool; raw CDN files require an import map or an ESM transformation service to resolve dependencies.

Mark the elements that should collect snow:

<article data-weather-surface>Your existing content.</article>
<section data-weather-ignore>Keep important controls clear.</section>

Start after the DOM is ready:

import { createWeather } from '@fluritheme/fluri';

const weather = createWeather({
  preset: 'gentle-snow',
  dom: { detection: 'explicit' },
});

weather.start();

// Release the effect when the page leaves.
window.addEventListener('pagehide', () => weather.destroy(), { once: true });

Importing the core and creating an idle controller are safe during server rendering. Call start() in the browser after mount; autoStart defaults to false. In a component, call destroy() in its unmount cleanup.

Complete getting-started guide →

Make the forecast yours

weather.setIntensity(0.65);
weather.updateConfig({
  snow: {
    wind: { base: 0.12, gusts: true },
    accumulation: { maxDepth: 16 },
  },
  performance: { adaptive: true, maxDPR: 1.5 },
});

Choose explicit surfaces for predictable integration. Use attributes or registerSurface() to control material, accumulation, depth, clipping, and layer. Automatic discovery is also available.

<nav data-weather-surface data-weather-snow-depth="12">Your navigation</nav>
<article data-weather-surface data-weather-material="sticky">Your card</article>
const element = document.querySelector('article');
if (element) {
  const unregister = weather.registerSurface(element, {
    material: 'sticky',
    maxSnowDepth: 12,
    layer: 'content',
  });

  // Remove this registration when the element is no longer needed.
  unregister();
}

Ten ways to start

Quiet & considered A little atmosphere Seasonal & playful
gentle-snow — a soft dusting winter-magic — glow and deeper piles christmas-classic — a familiar flurry
minimal — a restrained particle budget cinematic — depth and larger flakes christmas-night — cool, glowing snow
frosted-glass — sparse crystals snowstorm — wind and denser snowfall north-pole — deeper snow and snowballs
playful — snowballs, snowmen, and pointer airflow

Preview every preset →

Presets configure the weather. Attach the optional Christmas module to add decorations.

React and Next.js

The core is framework independent. @fluritheme/fluri-react adds a component and hook that own the controller through mount, updates, and cleanup, including React Strict Mode.

npm install @fluritheme/fluri @fluritheme/fluri-react
'use client';

import { useFluri } from '@fluritheme/fluri-react';

export function WinterCard() {
  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>
  );
}

Prefer a decorative component? Use <Fluri options={{ preset: 'gentle-snow' }} />. It renders no React DOM and starts the effect after mount. In Next.js, keep it inside a client component.

Vanilla JavaScript, Vue, and Svelte can use the core with their own mount and cleanup hooks. Framework integrations →

A little Christmas ✨

Add the separate Christmas export and label the surfaces to decorate:

import { christmasPack } from '@fluritheme/fluri/christmas';

const removeChristmas = weather.use(
  christmasPack({
    lights: { warmth: 0.9 },
    garlands: true,
    frost: true,
  }),
);
<nav data-weather-surface data-holiday-lights data-holiday-garland>A warmer welcome.</nav>

Remove it independently with removeChristmas(). Decorations use original procedural artwork; they do not fetch images or fonts. Seasonal configuration →

Make it interactive

weather.updateConfig({
  interactions: {
    snowballs: { enabled: true, activation: 'press-and-drag' },
    snowman: { enabled: true },
  },
});

weather.trigger('gust');
weather.trigger('plough', { selector: '[data-plough-route]', speed: 90 });

Brush a snowy edge with the pointer. Hold Shift and drag near deposits to gather a snowball, then release to throw. Stack three compatible resting balls on one support to make a snowman. For a plough, mark its chosen shelf with data-plough-route.

Touch behavior preserves ordinary page scrolling. Provide accessible buttons for intentional actions; the playground includes keyboard and touch controls. Gathering, transfer, and ploughing account for stored snow mass.

Meet the yeti

The Fluri yeti gathering, packing and throwing a snowball at a snowman

const weather = createWeather({
  interactions: {
    snowballs: { enabled: true },
    snowman: { enabled: true },
    yeti: { enabled: true, size: 1, cooldown: 16 },
  },
});
weather.start();

Give it a visible, mostly horizontal surface at least 150 px wide. Add data-weather-yeti to your preferred snowy shelf. It stays attached as the page scrolls, blinks and breathes while idle, and waits for a snowman on the same shelf. Its sequence is arrive → sneak → scoop → pack → aim → throw → celebrate (or shrug). Gathering consumes deposited snow; empty shelves cannot produce ammunition. One yeti and one projectile per instance keep the interaction bounded.

<div data-weather-surface data-weather-yeti>Room for a little rivalry.</div>
// Optional demo controls. Visitors can also assemble their own snowman from three balls.
weather.addSnow(8, '[data-weather-yeti]');
weather.trigger('snowman', { selector: '[data-weather-yeti]' });
weather.trigger('yeti', { selector: '[data-weather-yeti]' });
weather.on('yeti:hit', () => console.log('Snowman down!'));
weather.updateConfig({ interactions: { yeti: { enabled: false } } });

Disabled by default. Respects pause, hidden tabs and reduced-motion preferences. Try Yeti vs snowman in the playground.

Runtime controls

Method Purpose
start() · pause() · resume() Control the animation lifecycle
stop() Clear visuals while keeping the instance
destroy() Release canvases, observers, listeners, actors, and plugins
setPreset(name, overrides?) · setIntensity(value) Change the forecast
updateConfig(patch) · getConfig() Apply validated changes or read a configuration snapshot
addSnow(depth, selector?) · clearAccumulation(selector?) Manage deposits
registerSurface(element, options?) Register an element; returns an unregister function
trigger(type, options?) Trigger a gust, burst, snowball, snowman, yeti, or plough
use(plugin) · on(event, callback) Add a plugin or subscribe to events; both return cleanup functions
getMetrics() Inspect actual timing, budgets, counts, and state

Full API reference →

Considerate by default

Fluri respects prefers-reduced-motion by default and suspends animation in hidden tabs. Enable its optional accessible pause button with accessibility: { controls: true }, or connect your own controls. Pale snow gains subtle cool edges on light solid-color backgrounds, while custom snow colors stay yours.

Adaptive quality bounds snowfall density and reacts to slow frames. Configure particle and surface counts, pixel ratio, and FPS to fit your page. Test on your target devices: layout complexity and effects affect the cost.

Fluri is a stylized 2D simulation. Geometry and paint order approximate supported browser behavior; complex masks, perspective transforms, closed shadow-root internals, and cross-origin iframe contents have limits.

Accessibility · Performance · Browser support · Known limits

Run the playground locally

Requires Node.js 22.12+ and pnpm 10.33.2.

pnpm install --frozen-lockfile
pnpm dev

Open http://127.0.0.1:5173. Explore the surface workshop, layers, real snow interactions, presets, seasonal decorations, and the 1,000-node stress scene. Export your forecast as validated JSON.

For the complete website and playground production layout:

pnpm build
pnpm preview

Open http://127.0.0.1:4173. Development and deployment →

Build and verification commands
pnpm exec playwright install chromium firefox webkit
pnpm check
pnpm test:browser
pnpm build:examples
pnpm test:frameworks
pnpm format:check
pnpm audit --audit-level high
pnpm release:check

pnpm build produces ESM and declarations in packages/*/dist, plus the website and playground in root dist/. pnpm measure records bundle sizes; pnpm benchmark runs the documented local DOM benchmark.

Keep exploring

Website · Showcase · Playground · Docs · GitHub

Customization · Physics & layers · Troubleshooting · Changelog

Website participation

Owners can register a website, verify their domain, and independently choose a public community listing or private aggregate reporting. The library has no automatic telemetry. Read the participation and privacy guide.

Contribute & share

Found a rough edge or made something snowy? Read the contribution guide, open an issue with a useful reproduction, or share Fluri with someone building a seasonal website. Project questions: fluritheme@gmail.com. See the security policy for private vulnerability reports.

License

MIT — free to use, modify, and redistribute, including commercially, with the required notices. Original Fluri artwork and procedural decorations use the same license.

A little winter. Your kind of wonder. ☃️

About

Winter by Fluri Themes — DOM-aware interactive snowfall, accumulation, snowballs, a playful yeti and Christmas effects. TypeScript + React.

Topics

Resources

Contributing

Security policy

Accessibility

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages