Skip to content

Send a rain event

Click the hydrant and it rains for everyone on the page for a few seconds. Someone who opens the page afterward sees nothing, because events are never stored.

Live exampleRoom connecting…
Remix
Test it with another person
  1. Keep this page open in your normal window.
  2. Copy the private-window link, then paste it into a private or incognito window.
  3. Interact in either window and watch the other one update.

Copy the code

Both versions use the same shared data and behavior. The live playground runs the Vanilla HTML version.

Save this as index.html, or open it in the playground to test and change it.

Remix

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Send a rain event</title>
  <style>
    :root {
      color: #1c1c1c;
      background: #f4efe5;
      font-family: ui-sans-serif, system-ui, sans-serif;
    }
    * { box-sizing: border-box; }
    body { display: grid; min-height: 100vh; margin: 0; padding: 1.5rem; place-items: center; }
    .hydrant {
      width: 120px;
      height: 150px;
      border: 0;
      background: url("https://playhtml.fun/docs/fire-hydrant.png") center / contain
        no-repeat;
      cursor: pointer;
    }
    .rain {
      position: fixed;
      inset: 0;
      z-index: 9999;
      pointer-events: none;
    }
    .rain::before {
      content: "";
      position: absolute;
      inset: 0;
      background: url("https://media.giphy.com/media/Wmp1EOzVybWd13s5DB/giphy.gif")
        0 0 / 200px;
      animation: rain 6s ease-in-out forwards;
    }
    .cloud {
      position: absolute;
      top: 10px;
      width: 150px;
      height: 80px;
      background: url("https://playhtml.fun/docs/rain-cloud.webp") center / contain
        no-repeat;
      animation: cloud 5.5s ease-out both;
    }
    @keyframes rain {
      0%, 15% { opacity: 0; }
      30%, 85% { opacity: 0.7; }
      100% { opacity: 0; }
    }
    @keyframes cloud {
      0% { opacity: 0; transform: translateY(-120px); }
      20%, 80% { opacity: 0.9; transform: none; }
      100% { opacity: 0; transform: translateY(-120px); }
    }
  </style>
</head>
<body>
  <main>
    <button id="hydrant" class="hydrant" aria-label="Summon rain"></button>
  </main>

  <script type="module">
    import { playhtml } from "https://unpkg.com/playhtml@latest";

    // Fade in rain under a row of five clouds, then clean up.
    function makeItRain() {
      const rain = document.createElement("div");
      rain.className = "rain";
      for (let i = 0; i < 5; i++) {
        const cloud = document.createElement("div");
        cloud.className = "cloud";
        cloud.style.left = `${i * 20}%`;
        cloud.style.animationDelay = `${i * 150}ms`;
        rain.append(cloud);
      }
      document.body.append(rain);
      setTimeout(() => rain.remove(), 6000);
    }

    document.getElementById("hydrant").addEventListener("click", () => {
      playhtml.dispatchPlayEvent({ type: "rain" });
    });

    await playhtml.init({
      developmentMode: true,
      events: {
        rain: { type: "rain", onEvent: makeItRain },
      },
    });
  </script>
</body>
</html>

Register the event with playhtml.init, then dispatch it from a click. Every connected browser, including yours, runs onEvent:

playhtml.init({
  events: {
    rain: { type: "rain", onEvent: makeItRain },
  },
});

hydrant.addEventListener("click", () => {
  playhtml.dispatchPlayEvent({ type: "rain" });
});

The rain itself is plain DOM and CSS animation that removes itself after six seconds.

See Events for when to use events instead of shared data.