AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻譯準備中
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證零相依、嚴格型別的 Canvas 彩紙,支援表情符號、文字、圖像與圖集粒子。
AI 翻譯
Zero-dependency, strictly typed canvas confetti with emoji, text, image and spritesheet particles
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Canvas confetti that is tiny to start with and goes as far as you need. One call for a classic pop — and,
when you want more, emoji, text, images and spritesheets, streams that follow the pointer, composable physics,
Web Worker rendering and a fully typed plugin API. Zero dependencies.
-~16%20kB%20brotli-d6ff3f>)檢視完整 README ↗Canvas confetti that is tiny to start with and goes as far as you need. One call for a classic pop — and, when you want more, emoji, text, images and spritesheets, streams that follow the pointer, composable physics, Web Worker rendering and a fully typed plugin API. Zero dependencies.
English · Türkçe
Playground · Guide · API reference
import { Konfeti } from "konfeti";
Konfeti.fire(); // that's it: a classic confetti pop on a fullscreen overlay
Konfeti.fire() creates its overlay canvas on first use, keeps it sized to the
window at the device pixel ratio, and stops its animation loop when the last particle is gone.Konfeti.fire(), ~14 kB with
konfeti/lite, and Web Worker rendering lives in its own entry — bundles that never use it carry none of it.npm
npm install konfeti
pnpm
pnpm add konfeti
yarn
yarn add konfeti
Without a bundler, load the <script> build (it defines window.konfeti):
<script src="https://cdn.jsdelivr.net/npm/konfeti/dist/konfeti.iife.js"></script>
<script>
konfeti.Konfeti.fire();
</script>
import { Konfeti, KonfetiPresets } from "konfeti";
// fire from a button, upward and a bit wider than the default
button.addEventListener("click", (event) => {
Konfeti.fire({ origin: event, spread: 90, particleCount: 120 });
});
// a ready-made look
Konfeti.fire(KonfetiPresets.FIREWORKS);
// every burst is awaitable
await Konfeti.fire({ particleCount: 80 });
console.log("the last particle is gone");
The default confetti piece, fully configurable. Numbers take a value, a [min, max] range or { min, max }.
Konfeti.fire({
paper: {
form: ["rect", "circle", { value: "strip", weight: 2 }], // weighted mix of silhouettes
width: [6, 10],
height: [12, 18],
cornerRadius: 2, // or per corner: { tl: 6, br: 6 }
colors: ["#ff0a54", "#ffd000", { color: "#00c2ff", weight: 3 }],
gradient: { colors: ["gold", "orange"], angle: 45 },
flip: { axis: "both", frequency: [0.5, 1.5] }, // the back shows a darker shade
wobble: { amplitude: [2, 8] },
shine: 0.5, // glossy highlight as it turns
trail: { length: 12 }, // a fading streak behind each piece
fadeOut: { start: 0.6, easing: "easeInQuad" },
},
});
Color themes are ready-made: paper: { colors: KonfetiPalettes.PASTEL } — also GOLD, NEON, RAINBOW, WINTER,
AUTUMN, OCEAN, CANDY, FOREST, MONOCHROME and CLASSIC.
Mix any shapes with weights; each one can override the paper style.
Konfeti.fire({
shapes: [
{ type: "paper", weight: 4 },
{ type: "star", points: [5, 6], shine: 0.6 },
{ type: "heart", colors: "#ff4d6d" },
{ type: "emoji", emoji: ["🎉", "🥳", "✨"], size: [22, 32] },
{ type: "text", text: ["YAY", "WOW"], fontWeight: 900 },
{ type: "image", src: "/coin.png", size: [20, 30] },
{ type: "spritesheet", src: "/coin-spin.png", frames: { cols: 8, rows: 1 }, fps: 14 },
],
});
Built in: paper, star, triangle, polygon, heart, ribbon, path (any SVG path), emoji, text,
image and spritesheet (a URL, an image element or inline <svg> markup). Emoji and text are rasterized once and
cached — and redrawn automatically if their
web font finishes loading later.
Ten ready-made looks, as plain read-only data:
import { Konfeti, KonfetiPresets, extendPreset } from "konfeti";
Konfeti.fire(KonfetiPresets.SNOW);
Konfeti.fire(extendPreset(KonfetiPresets.FIREWORKS, { particleCount: 80 })); // your settings win
BASIC, REALISTIC, CANNON, SIDE_SHOTS, SCHOOL_PRIDE, FIREWORKS, SNOW, STARS, EMOJI_RAIN,
HEART_BURST, plus presets that show off newer options: SHOOTING_STARS (trails), MAGNET (attractor),
FORCE_FIELD (repulsor), GOLDEN (gold palette), SPARKLER and FIREFLIES (additive glow), JACKPOT (floor),
CONGRATS, SUCCESS and LEVEL_UP (text formations; LEVEL_UP is choreographed with delay) and LOGO_REVEAL
(image formation).
Stream particles until you stop — a fountain, a trail behind the pointer, sparks from an element.
const trail = Konfeti.emit({
rate: 60, // particles per second
follow: "pointer", // or an element, or a point like { x: 0.5, y: 1 }
spread: 360,
startVelocity: [50, 150],
shapes: [{ type: "star", size: [6, 10] }],
});
trail.moveTo(document.querySelector("#rocket")!); // follow something else
trail.stop(); // stop emitting; particles already out finish their lives
await trail;
Particles form a text or an image, hold it, then burst apart. Every shape can take part.
Konfeti.fire({
formation: { text: "YOU\nWIN", font: "900 110px sans-serif", hold: 1200 }, // or image: "/logo.png"
shapes: [{ type: "paper", weight: 3 }, { type: "star" }],
});
Konfeti.fire({
physics: {
gravity: 700, // px/s² — negative floats upward
drag: 3.5,
wind: [-40, 40],
swirl: { strength: [80, 200], frequency: [0.3, 0.8] },
floor: { y: 1, bounce: 0.35, friction: 0.4 }, // particles bounce and settle
attract: { target: "pointer", strength: 900 }, // pulled toward the pointer; negative pushes away
},
emission: { mode: "interval", every: 350, times: 8 }, // or "burst" (default) / "stream"
seed: 42, // same seed, same burst
});
const burst = Konfeti.fire(); // every fire() returns a handle
burst.pause();
burst.resume();
burst.stop();
await burst;
// the same burst again (exact with KonfetiFactory.create(canvas, { fixedTimestep: true }))
Konfeti.fire({ seed: burst.getSeed() });
Konfeti.pause(); // freeze everything (hidden tabs pause on their own)
Konfeti.resume();
Konfeti.reset(); // remove every particle
// fire from the click position on every click; "pointerdown" also works when touch events are cancelled
const off = Konfeti.onClick(button, { particleCount: 30 }, { trigger: "pointerdown" });
off();
Hooks — onStart, onParticleSpawn, onParticleUpdate, onParticleDeath, onComplete — let you watch or
steer every particle.
Konfeti is a shared fullscreen instance. Create dedicated ones for your own canvas, defaults or particle
budget:
import { KonfetiFactory } from "konfeti";
const stage = KonfetiFactory.create(document.querySelector("canvas"), {
maxParticles: 800, // oldest particles make room beyond this (default 1500)
disableForReducedMotion: true, // honour prefers-reduced-motion (off by default)
defaults: { paper: { colors: ["gold", "white"] } },
});
stage.fire();
stage.destroy(); // stops, clears and removes its listeners
Move simulation and drawing off the main thread, so big bursts stay smooth while the page is busy:
import { createWorker } from "konfeti/worker";
const stage = createWorker(document.querySelector("canvas"), { maxParticles: 3000 });
await stage.fire({ particleCount: 1500 });
stage.isWorker(); // false where OffscreenCanvas is missing — it then runs on the main thread
Options are type-checked to be worker-safe, element and click origins are measured for you, and
stage.getStats() replaces hooks (which cannot run in a worker). The worker script loads on first use.
import { Konfeti, defineShape, definePhysics } from "konfeti";
declare module "konfeti" {
interface ShapeRegistry {
diamond: { sharpness?: number };
}
interface PhysicsRegistry {
magnet: { x: number; y: number; strength: number };
}
}
defineShape("diamond", {
viewBox: [24, 24],
path: ({ sharpness = 0.5 }) => `M12 0L${24 - sharpness * 12} 12L12 24L${sharpness * 12} 12Z`,
});
definePhysics("magnet", {
defaults: { x: 0.5, y: 0.5, strength: 600 },
apply: (p, dt, world, { x, y, strength }) => {
p.vx += (x * world.width - p.x) * strength * dt * 0.001;
p.vy += (y * world.height - p.y) * strength * dt * 0.001;
},
});
Konfeti.fire({
shapes: [{ type: "diamond", sharpness: 0.8 }],
physics: { magnet: { strength: 900 } },
});
Both are fully typed everywhere once declared — including autocomplete for type: "diamond".
| Import | What you get |
|---|---|
konfeti | Everything: all shapes registered, presets, the console banner |
konfeti/lite | Paper only — register just the shapes you use with registerShapes(...) |
konfeti/worker | createWorker() and the worker types |
konfeti/konfeti.worker.js | The worker script, to self-host under a strict Content-Security-Policy |
dist/konfeti.iife.js (<script>) | window.konfeti with everything, including createWorker |
ESM and CommonJS builds with .d.ts for every entry; sideEffects is set so unused code tree-shakes away.
Measured with size-limit (minified + brotli) and checked in CI:
| Usage | Size |
|---|---|
Konfeti from konfeti | ~19.8 kB |
everything from konfeti | ~23.9 kB |
Konfeti from konfeti/lite | ~13.9 kB |
createWorker from konfeti/worker | ~21.9 kB |
| worker script (loaded on first use) | ~19.1 kB |
Evergreen browsers. The build targets ES2022 (roughly Chrome 85+, Firefox 79+, Safari / iOS 14.5+); let your
bundler lower it if you support older webviews. Worker rendering is feature-detected and falls back to the main
thread where OffscreenCanvas is missing. It also works with server-side rendering: importing never touches
the DOM.
konfeti fits single-file playable ads: no dependencies, no network requests of its own, no storage, no eval.
Pass images as data: URIs or elements your engine already loaded, fire on pointerdown if your engine cancels
touch events, pause with Konfeti.pause() on MRAID viewableChange, and call disableBanner() in production.
On low-end phones, KonfetiFactory.create(null, { adaptiveQuality: true }) lowers the resolution, then the
effects, then the particle count while frames are slow.
The guide has the full checklist.
Konfeti.fire() codellms.txt /
llms-full.txt for chat assistants
(how to use them)pnpm monorepo:
| Path | What |
|---|---|
packages/konfeti | The library (published to npm as konfeti) |
playground/ | Site: playground (/), guide (/docs/), API reference (/docs/api/) |
e2e/ | Playwright browser tests against the built library and site |
docs/PLAN.md | Roadmap and design notes |
pnpm install
pnpm dev # site on http://localhost:5199 (generates the API reference first)
pnpm test # unit + type tests (Vitest)
pnpm e2e # build, then browser tests in the installed Chrome (Playwright)
pnpm typecheck # tsc --noEmit in every package
pnpm lint # ESLint (strict type-checked)
pnpm build # library → ESM + CJS + IIFE + .d.ts
pnpm size # size budgets
pnpm site:build # static site → playground/dist
Issues and pull requests are welcome. CI runs formatting, lint, types, unit tests, the build, size budgets and the browser tests on every push.
MIT © mbattaloglu