Three small design decisions in a "toggle effects via CSS class" library, and the tradeoffs behind them

I built halloween.js, a small library that adds Halloween-themed page effects (blinking eyes, flying witches, a dropping spider, screen-corner webs) to any website, driven entirely by CSS classes on <body>. The effects themselves aren't interesting — CSS animations and a setTimeout scheduler. What I want to write about are three decisions that turned out harder than they looked once real usage exposed the edge cases.

1. Reactive sync via MutationObserver instead of an imperative API

The obvious API for a library like this is imperative: Halloween.start("eyes"). I built that first, then threw most of it away.

The problem: this library is meant to be dropped into contexts where you don't control JS execution order — a WordPress header, a page builder, a CMS field that toggles a class based on user state. An imperative API assumes you can call a function at the right moment. In practice, the "right moment" doesn't exist in these environments.