How to run the dust full screen, and an honest look at what packaging it as a PWA would and would not buy — including the one part of the idea that does not work at all.
The page has no chrome of its own, so a browser in full screen is already most of the way there. F11 on Windows and Linux, ⌃⌘F on macOS. On a phone, add it to the Home Screen and it opens without the browser bars.
Every part of the look is a URL switch, so a particular feel can be bookmarked:
| switch | range | does |
|---|---|---|
glow | 0–1 | twinkle around the pointer. Never moves the mark. |
wake | 0–1 | pushes grains aside. Bends the K while the pointer is over it. |
pull | 0–1 | draws grains in until they knot and brighten. |
radius | 0.01–1 | how far any of that reaches. |
tide | 0–1 | the unattended cycle. 0 makes it pointer-driven only. |
attack / release | secs | how fast it gathers, how slowly it lets go. |
etau | secs | how long a burst of movement keeps working. |
grains | N | density. Lower it on a tired machine. |
travel | secs | how long the grains take to fly to the index title. |
spread | 0–0.95 | how staggered their departures are. |
arc | 0–0.5 | how far they bow off a straight line. |
dim / shrink | 0–3 / 0–1 | how much a grain fades and narrows as the mark shrinks. |
Add .mouse or .touch to any of them to set one input type only.
A few worth trying:
/?travel=3&spread=0.9 the index transition, slow and loose
/?travel=0.4&spread=0&arc=0 the same trip as one rigid move
/?tide=0.4&glow=0.35 calmer: rarely forms, barely reacts
/?glow=0.9&radius=0.35 heavier fairy dust under the cursor
/?wake=0.7 the K bends away from the pointer
/?pull=0.5 grains gather into a bright knot
/?grains=25000 lighter on the fans
Press d on the page for a readout of grain count, frame rate and every switch.
Neither needs a PWA, and both matter more than one.
A screensaver that lets the screen sleep is not a screensaver.
navigator.wakeLock.request('screen') holds it awake. It needs a user gesture and a
visible document, and the lock drops when the tab is hidden, so it has to be re-acquired on
visibilitychange. This is the single biggest quality win available, and it works on
a plain web page.
WebGL at 60fps will drain a laptop or phone. Halving the frame rate and cutting
grains when the battery is discharging and low costs nothing visually —
grains is already a switch.
Worth separating two things that sound the same.
A real screensaver is an OS component the system starts when the machine
goes idle — .scr on Windows, .saver on macOS. The web cannot
register as one. No API, no permission, no workaround.
A fullscreen page you leave open is what a PWA gets you. That is most of the fun, and worth having — but it should be called what it is.
| a PWA gives | why it matters here |
|---|---|
| standalone window | no browser chrome — the thing that makes it feel like an app |
| an icon | the reason anyone opens it a second time |
| offline | trivial: the page is one file that fetches nothing |
| somewhere to iterate | a settings screen for the switches above |
If a genuine screensaver is ever wanted, that is a native wrapper around this same page —
Electron emitting a .scr, or a small .saver hosting a web view.
Different project, same index.html.
The idea: give out a little KBAR to anyone who installs the PWA. It is a nice idea and the mechanism it assumes does not exist.
Every signal the platform offers is a value produced on the claimant's own device:
| signal | why it proves nothing |
|---|---|
beforeinstallprompt | a JS object, in a browser the claimant controls |
appinstalled | an event they can dispatch themselves |
display-mode: standalone | trivially true for anyone who wants it to be |
getInstalledRelatedApps() | see below — it is not what it looks like |
getInstalledRelatedApps() looks like the answer and is not. Its Digital Asset
Links check binds the app to the site, so that other websites
cannot probe what you have installed. It is an anti-fingerprinting measure. There is no
signature, nothing for a server to verify, and the result still arrives as a value on the
claimant's machine.
The attack is not clever: open devtools, watch the claim request, replay it. No client-side check survives that, because the client is the adversary.
A Web Push subscription, verified by using it. The endpoint is issued by the browser vendor's push service, not by the page, so the server can push a nonce and require the client to echo it. That proves a real browser, really reachable.
Two things make it stronger: on iOS, Web Push only works once the page is on the Home Screen, so there a live subscription really is install evidence; and pushing again at day 7 and only paying if it still answers turns install, claim, uninstall into keep it for a week — which is what you wanted to pay for anyway.
The cost is a notification permission prompt on a novelty page, which most people will decline.
| angle | cost | mitigation |
|---|---|---|
| Replay the claim | near zero | server-issued single-use token |
| Farm browser profiles | low — the real attack | per-wallet cap + wallet history |
| Sybil wallets | scriptable | wallet must predate the campaign |
| Rotate IPs | cheap | rate limit only; never IP as identity |
| Install, claim, uninstall | zero | delayed re-check, or accept it |
WalletConnect is worth having, but it proves control of a key at claim time — not personhood, not uniqueness. It is a payment rail and a de-duplication key. The account-history requirement is what does the anti-sybil work.
The short version. Spend the effort on a fixed total budget and an established-wallet requirement, and ship.
A cap — "first 200 wallets, then it stops" — is the only control that bounds the downside absolutely; everything else is probabilistic. Requiring the wallet to predate the campaign is a single mirror-node read and turns mint a key, claim into have been here before, which is exactly who the reward is for.
At that scale the worst realistic outcome is that some existing community members get a slightly larger share than intended. Building push verification to protect a few hundred KBAR would cost more than the KBAR.
Anyone can read the source and reskin it — one unminified file, and the K is two SVG shapes. That is fine and not worth defending. If someone puts their own letter in it, nothing is lost and the idea travels.
The one thing to watch is the reverse: swapping in someone else's logo, which is their trademark and not ours to animate. Fine as a private experiment, not under a KPAY address.