For designers and client websites
The vibedom widget
A floating button that carries a website's sonic identity. The seed travels inside the snippet: no AI calls, no database and no cost per visitor. Audio only downloads when someone hits play.
- Under 5 KB upfront
- Isolated Shadow DOM
- No cookies or analytics
- Tone.js only on click
1. Paste the snippet
Generate a seed in the playground and copy the code under
“Your embeddable widget”. It should look like this, before </body>:
<!-- vibedom: generative music for your site -->
<script src="https://vibedom.dev/widget.js"
data-seed="eyJtZXRhZGF0YSI6eyJ1cmwiOiJodHRwczovL25lb24tZ3JpZC5leGFtcGxlIiwiZGV0ZWN0ZWRWaWJlIjoiQ3liZXJwdW5rOiB0w6ljbmljbywgbm9jdHVybm8geSBuZcOzbiIsImV4cGxhbmF0aW9uIjoiRm9uZG8gbmVncm8gcHVybywgYWNlbnRvcyB2ZXJkZSBuZcOzbiB5IHRpcG9ncmFmw61hIG1vbm9zcGFjZSB0cmFkdWNpZG9zIGEgUmUgZnJpZ2lvIGdyYXZlLCBzaWVycmFzIGRlc2FmaW5hZGFzIHRyYXMgdW4gZmlsdHJvIGNlcnJhZG8geSB1biBhcnBlZ2lvIGRlIGVjbyBxdWUgcmVjdWVyZGEgYSBkYXRvcyBmbHV5ZW5kby4ifSwidWlUaGVtZSI6eyJiYWNrZ3JvdW5kQ29sb3IiOiIjMEEwQTBBIiwiYWNjZW50Q29sb3IiOiIjMDBGRjY2IiwidGV4dENvbG9yIjoiI0U2RkZFOSIsImZvbnRGYW1pbHkiOiJtb25vc3BhY2UifSwibXVzaWNhbFBhcmFtcyI6eyJicG0iOjg0LCJyb290Tm90ZSI6IkQiLCJzY2FsZSI6InBocnlnaWFuIiwib2N0YXZlIjozfSwic3ludGhDb25maWciOnsicGFkIjp7IndhdmVmb3JtIjoic2F3dG9vdGgiLCJhdHRhY2siOjIuNSwicmVsZWFzZSI6NCwiZmlsdGVyRnJlcSI6NTIwfSwiYXJwIjp7ImVuYWJsZWQiOnRydWUsIndhdmVmb3JtIjoic3F1YXJlIiwiZGVuc2l0eSI6MC40NSwiZGVsYXlXZXQiOjAuNTV9LCJlZmZlY3RzIjp7InJldmVyYkRlY2F5Ijo1LjUsInJldmVyYldldCI6MC41NSwiY2hvcnVzRGVwdGgiOjAuMjV9LCJpbnRlcmFjdGl2aXR5Ijp7InNjcm9sbFRhcmdldCI6ImZpbHRlckZyZXEiLCJzY3JvbGxNdWx0aXBsaWVyIjozLjUsImhvdmVyTm90ZVRyaWdnZXIiOnRydWV9fX0="
defer></script>
The seed is the widget. It contains colours, copy and musical parameters. No other service is needed: if vibedom's backend disappeared, this button would keep working.
Webflow, Framer or WordPress
Paste the snippet into the project's custom HTML or the page footer. In WordPress, use a code
snippets plugin or the child theme's footer.php. Avoid fields that strip
<script> tags.
One widget per page is enough. Keep it out of checkout and admin screens: it works best on the public site, where visitors choose to press play.
2. Attributes
| Attribute | Required | What it does |
|---|---|---|
src |
Yes | Loader URL. Always use https://vibedom.dev/widget.js. |
data-seed |
Yes | The Sound Seed in base64, as generated by the playground. If it is missing or corrupt, the widget does not render and never breaks the page. |
data-label |
No |
Button text and accessible label. Defaults to “Play this website” or “Escuchar esta web”
depending on the document's lang.
|
defer |
Recommended | Does not block the host page's render. |
Colours and copy
The button takes backgroundColor, accentColor and
textColor from the seed's uiTheme. If accent and background match, it
falls back to the text colour so the icon stays visible. To change the palette, regenerate the
seed in the playground; there is no CSS to edit.
<script src="https://vibedom.dev/widget.js"
data-seed="…"
data-label="Give this page a soundtrack"
defer></script>
3. How it works
- On page load, the snippet decodes the seed and paints a button inside a Shadow DOM. It does not download the engine or Tone.js. The loader is under 5 KB (around 2 KB compressed).
-
On the first click, it loads
widget-player.jsand Tone.js from jsDelivr. That click is also the gesture browsers require to create the audio context. - While playing, the engine performs the seed in the browser: pad, drone and arpeggio. There is no pre-recorded audio and no API request.
The button exposes aria-pressed, a visible focus ring and respects
prefers-reduced-motion. Loading and error states are announced through its
accessible label, not with an alert that interrupts the visitor.
4. CSP and SRI
If the host site uses a strict Content-Security-Policy, add these origins. The
widget needs jsDelivr for Tone.js, blob: for Tone's internal clock and worklets,
and inline styles for the Shadow DOM:
script-src 'self' https://vibedom.dev https://cdn.jsdelivr.net blob:;
worker-src blob:;
style-src 'self' 'unsafe-inline';
Don't paste this over your current CSP. Merge it with what you already have: directives are combined, and a duplicated CSP can disable the more permissive one or break the rest of the site.
Subresource Integrity (SRI)
You can add integrity and crossorigin="anonymous" to the loader. The
hash changes every time a new widget.js is published; if you pin it, review the
hash when you update. Compute the current one with:
curl -s https://vibedom.dev/widget.js \
| openssl dgst -sha384 -binary \
| openssl base64 -A
SRI protects the loader; the player and Tone.js are imported at runtime and cannot carry
integrity. That is why you should pin the version in the URL as well (see
Versioning).
5. Privacy and cost
- No cookies,
localStorageor vibedom analytics. - The host page's URL is not sent to any server.
- Audio is synthesised in the browser; no music is downloaded and nothing is uploaded.
- The first click requests Tone.js from jsDelivr, which sees the visitor's IP like any CDN. If you need to avoid it, contact us before embedding in a strict environment.
- Cost per visitor: zero AI calls. The seed is already embedded in the HTML.
6. Troubleshooting
The button does not appear
Check that data-seed is not empty or cut off when copying, and that the CSP
allows https://vibedom.dev. If the snippet sits inside an editor that removes
<script>, move it to the theme HTML or a code plugin.
The button appears but there is no sound
Audio needs the click gesture: it cannot autoplay. On iOS also check the silent switch. If
the CSP blocks blob:, Tone cannot start its internal clock.
The first click takes a second
That is expected: the player and Tone.js (about 230 KB compressed from the CDN) download at that moment. The button shows its loading state in the meantime.
I want the button in another corner or at another size
Position and size are part of the widget's design and are not configurable by attribute. If you need a client-specific variant, regenerate the seed and ask for an adaptation before touching the Shadow DOM's CSS.
Can I put several widgets on the same page?
No. Each snippet creates its own floating button and two buttons overlap. Use one per page.
7. Versioning
To keep an update from silently changing a client's widget, add the version to the URL:
https://vibedom.dev/widget.js?v=1.0.0
The parameter busts browser and CDN caches, but the file is still the published one. Check the changelog before bumping. Seed changes do not affect the widget: every snippet carries its own.
Ready to try it? Generate a seed from your site and copy the final snippet.
Open the playground