Work Text:
CONTENTS:
👉 Instructions
And you may ask yourself, “Well, how did I get here?”
👉 The sorcerer's magical scroll
Games on AO3: would you like to know more?
See also
What do I do? Contents ↑
NB, 15 Dec 2025: If you're having any difficulty reading any of this, and are logged-out (hence can't access site skins) or using a personal site skin (and necessarily logged-in) that clashes with my work skin, then please see this subsection of How to AO3 for info. on accessing public site skins even without the buttons' presence.
Not much to say on that:
'phones,
- just scroll down to find a bubble (a pretty disc with a colorful pattern) somewhere on the page,
- touch/tap the bubble,
- you'll see an explodey flash of color all over your Android Chrome viewport (sadly, not iPhone Safari)
- ...and a radar-ping pulse around the bubble when you touch/tap it,
- and find yourself at the top of the auto-refreshed page,
- scroll down again on the hunt for the next bubble somewhere else on the page.
Computers,
- see above, except with a mouse and cursor
- ...and that radar-ping pulse when your cursor even comes near a bubble (or you click it, of course);
- oh, and good luck catching the bubbles... they're afraid of mice! 😉
Happy hunting — and enjoy the music! ❤️
Background blah-blah Contents ↑
So... yeah... this idea hit me in a dream Friday night, and I finally got my ass moving on it like, oh-dark-hundred this morning, and... badda-bing, it's a go!
The proposal: RNG via meta (CSRF token) initial glyph ^= to place refresh-clickable boxes every 1/64 through page (OK, so due to the fencepost problem, that's at the initial spot of top: 0% and left: 0%, plus 63 to bottom right, right?), and maybe 4 RGBA colors via the meta final glyph $=. No problem... piece of cake... what could possibly go wrong?
How large, though? Maybe 5em?
Well, cutting to the chase: it works (obviously)! Sure, the original basic CSS starting position of left: 0% overhung the actual paragraph edge a few pixels to the left, and left: 100% brought it too far to the right (the discs disappeared entirely), and top: 100% dropped it through the bottom (disappearing trick, round 2), but... I worked on that.
I'd pull an Eddie Murphy and ask “Want some code? Want some code? Want some code? ...psych! You can't have none! [etc.]”, but that's cruel. I'll drop it here raw, for your viewing pleasure.
Secret arcane computer incantations Contents ↑
The HTML is short and sweet, just one single [classed] anchor — open your work to edit, and drop it like it's hot (c'mon, man, tell me you remember that one — Snoop Dogg, 2004, man!):
<a href="https://archiveofourown.org/works/88888888" class="disc_link" rel="nofollow"></a>
It's the CSS that's a little more involved, relying (as mentioned earlier) upon the meta CSRF token, as with the 256 randomly displayed [static] chess puzzle work (See? It's good for more than just bubble-popping! But seriously, you could use RNG for anything that might need randomness [see my comment thread in Targeting specific AO3 work sections (not site) with CSS effects for how to use it in one's comment section]: maybe randomize your fic's background color, or various gradients, or which characters happen to act in a given scene, or which entire <div> scenes even occur [just to throw your readers], or you could toss in an ever-changing card or bingo or lottery game), which in turn stems (as explained therein) from Mewsmodeus (Mewzebub)'s seminal work:
#workskin .disc_link {
display: block;
width: 100px;
height: 100px;
border-radius: 50%;
text-decoration: none;
position: absolute;
opacity: 0.7;
transition: transform 0.25s ease-in-out;
z-index: 1;
}
/* These two create the radar-ping pulse on :hover , when your cursor contacts the bubbles' hitboxes */
#workskin .disc_link:after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 50%;
border: 3px solid black;
/* The border above is fallback for older browsers that don't support box-shadow below (e.g.: MSIE 8 or older; not sure of other browsers, but it's been fully supported broadly for a long time) */
box-shadow: 0 0 0 1px black,
0 0 0 3px white,
0 0 0 6px black,
0 0 0 8px white,
0 0 0 9px black;
opacity: 0;
transform: scale(0);
transition: all 0.7s ease-out;
}
#workskin .disc_link:hover:after {
opacity: 1;
transform: scale(2);
border-color: rgba(0, 0, 0, 0);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0),
0 0 0 3px rgba(255, 255, 255, 0),
0 0 0 6px rgba(0, 0, 0, 0),
0 0 0 8px rgba(255, 255, 255, 0),
0 0 0 9px rgba(0, 0, 0, 0);
}
/* I later amended the CSS (17 Sep 2025, when a friend, Ellanannette, suggested making the bubble-popping “more colorful”) in hope of creating a dandelion-like exploding firework emulation (inspired by some very different-looking dandelion-like fireworks that lushfuneral was working-up in the Discord for a Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo | The 100 Girlfriends Who Really, Really, Really, Really, Really Love You fic) upon clicking, but had been stymied for a bit: the below should work, initially set for 100px * 100px, but I saw no effect and so tested it at 500px * 500px, after which I could see that it performed the size-increase, but clearly failed to cause the cool firework effect of the repeating-conic-gradient, or even so much as its radial-gradient fallback...
...and that's when it hit me: the specificity! The regular non-clicked bubbles' backgrounds and background-images were taking precedence; force-feed the declaration a little !important, et voilà! Problem solved-ish (or at least Good Enough For Government Work): it works in desktop Chrome, MS Edge, Opera, and Android Chrome, though not Firefox nor TOR... but don't ask me about iPhone Safari... I dunno what the hell it thinks it's doing in iPhone Safari. 😁
NB: I gave :focus a shot, but the fireworks lingered a little too long for my taste, the momentary flash of :active feeling a little more suitable, but you might want to keep the idea in mind, if you use a similar execution for some different atmosphere. */
#workskin .disc_link:active {
height: 500px;
width: 500px;
border-radius: 50%;
overflow: hidden;
background-image: repeating-conic-gradient(red 0deg 3deg, transparent 5deg 20deg), repeating-conic-gradient(yellow 1deg 4deg, transparent 5deg 22deg), repeating-conic-gradient(green 0deg 2deg, transparent 3deg 10deg), repeating-conic-gradient(blue 2deg 5deg, transparent 4deg 15deg), radial-gradient(circle, red, orange, yellow, green, blue, purple) !important;
background-size: 100px 100px, 88px 88px, 70px 70px, 90px 90px, 100px 100px;
background-position: center, center, center, center, center;
background-repeat: no-repeat;
}
/* This part with the :active is what makes the big explodey screen-flash of color when you pop the bubbles */
#workskin:is(:has(.disc_link:active)) {
background: radial-gradient(circle farthest-corner at center center, red 0%, orange 9%, yellow 18%, green 27%, blue 36%, purple 45%, black 54%, blue 63%, green 72%, yellow 81%, orange 90%, red 100%);
}
/* This makes the bubbles' hitboxes larger than their visible disc size */
#workskin .disc_link:before {
content: "";
position: absolute;
/* If you change the width and height of the hit box (the larger space surrounding the discs, triggering their movement before you :hover over the bubbles themselves), then you'll probably want to adjust the top and left */
/* NB: I used background-color: #88888850 for testing purposes */
top: -100px;
left: -100px;
width: 300px;
height: 300px;
border-radius: 50%;
z-index: -1;
}
/* These first four govern the colors and patterns of the discs' surfaces, using the meta's [only] final glyphs {A, g, Q, w} */
/* These and the next 64-glyph set look at part of the AO3-generated page for the random CSRF token that AO3 injects into each page;
the CSS itself uses no JS nor does it ping any offsite JS listening somewhere else, instead taking advantage of the result of the in situ AO3 JS action */
/* Use the same rule setup (changing the actual values, obviously) with different class names (e.g.: {.disc_link1, .disc_link2, .disc_link3, ..., .disc_link_n}) for n-many styled anchors, and you'd have n-many bubbles to pop (though you'd need to prevent the refresh occurring automatically, so either just drop a <span class="Add_A_Yellow_Background_Class_Here"><sup class="actions Add_A_White_Background_Class_Here"><sub><a href="Your_URL_Here" rel="nofollow">Refresh button</a></sub></sup></span>, or maybe set it on a timer or condition or timer upon meeting condition [I haven't looked into this not-button subset, just an offhand thought]) */
#workskin .disc_link:is(:has(meta:last-of-type[content$='A']) *) {
background-color: red;
background: radial-gradient(circle, rgba(255, 0, 0, 1) 0%, rgba(255, 255, 255, 1) 100%);
}
#workskin .disc_link:is(:has(meta:last-of-type[content$='g']) *) {
background-color: green;
background-image: linear-gradient(green, rgba(255, 255, 255, 90), green, rgba(255, 255, 255, 90), green, rgba(255, 255, 255, 90), green);
}
#workskin .disc_link:is(:has(meta:last-of-type[content$='Q']) *) {
background-color: blue;
background: repeating-conic-gradient(blue 0%, rgba(255, 255, 255, 90) 12.5%, blue 0%, rgba(255, 255, 255, 90) 12.5%, blue 0%, rgba(255, 255, 255, 90) 12.5%, blue 0%, rgba(255, 255, 255, 90) 12.5%);
}
#workskin .disc_link:is(:has(meta:last-of-type[content$='w']) *) {
background-color: grey;
background-image:
radial-gradient(black 20%, transparent 0),
radial-gradient(DarkSlateGray 20%, transparent 0);
background-size:
30px 30px,
30px 30px,
100% 100%;
background-position: 0 0, 15px 15px;
}
/* These next 64 govern the locations of the discs, in groups of 16 in the column near the left edge, 16 left-middle, 16 right-middle, and 16 along the right-most column of the viewport, using the meta's initial glyph set */
/* Cf. 4-glyph REM note [in previous section] re. AO3's JS-result per page */
/* Tried adding transform: translate(0, 200px); and transition-duration: 8s; to half of the following (each column's top four static, 2nd four downward at 8-11s spd, 3rd four upward at 12-15s, bottom four static), but it had no obvious effect on the static bubble discs, instead slowing the hovers' translation */
#workskin .disc_link:is(:has(meta:last-of-type[content^='A']) *) {
top: 0%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='B']) *) {
top: 5.27%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='C']) *) {
top: 10.53%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='D']) *) {
top: 15.8%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='E']) *) {
top: 21.07%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='F']) *) {
top: 26.33%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='G']) *) {
top: 31.6%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='H']) *) {
top: 36.87%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='I']) *) {
top: 42.13%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='J']) *) {
top: 47.4%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='K']) *) {
top: 52.67%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='L']) *) {
top: 57.93%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='M']) *) {
top: 63.2%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='N']) *) {
top: 68.47%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='O']) *) {
top: 73.73%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='P']) *) {
top: 79%;
left: 5px;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='Q']) *) {
top: 0%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='R']) *) {
top: 5.27%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='S']) *) {
top: 10.53%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='T']) *) {
top: 15.8%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='U']) *) {
top: 21.07%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='V']) *) {
top: 26.33%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='W']) *) {
top: 31.6%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='X']) *) {
top: 36.87%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='Y']) *) {
top: 42.13%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='Z']) *) {
top: 47.4%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='a']) *) {
top: 52.67%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='b']) *) {
top: 57.93%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='c']) *) {
top: 63.2%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='d']) *) {
top: 68.47%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='e']) *) {
top: 73.73%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='f']) *) {
top: 79%;
left: 29.37%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='g']) *) {
top: 0%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='h']) *) {
top: 5.27%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='i']) *) {
top: 10.53%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='j']) *) {
top: 15.8%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='k']) *) {
top: 21.07%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='l']) *) {
top: 26.33%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='m']) *) {
top: 31.6%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='n']) *) {
top: 36.87%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='o']) *) {
top: 42.13%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='p']) *) {
top: 47.4%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='q']) *) {
top: 52.67%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='r']) *) {
top: 57.93%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='s']) *) {
top: 63.2%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='t']) *) {
top: 68.47%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='u']) *) {
top: 73.73%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='v']) *) {
top: 79%;
left: 58.753%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='w']) *) {
top: 0%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='x']) *) {
top: 5.27%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='y']) *) {
top: 10.53%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='z']) *) {
top: 15.8%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='0']) *) {
top: 21.07%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='1']) *) {
top: 26.33%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='2']) *) {
top: 31.6%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='3']) *) {
top: 36.87%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='4']) *) {
top: 42.13%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='5']) *) {
top: 47.4%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='6']) *) {
top: 52.67%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='7']) *) {
top: 57.93%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='8']) *) {
top: 63.2%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='9']) *) {
top: 68.47%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='-']) *) {
top: 73.73%;
left: 88.13%;
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='_']) *) {
top: 79%;
left: 88.13%;
}
/* The discs' skittering away from your cursor is accomplished between the first entry's transition: transform 0.25s ease-in-out; (exacerbated by the .disc_link::before ), and a repetition of the initial glyphs' sequence for :hover (below shows the first three examples only, for brevity; view page source if you really want each one's specifics [here's how to do that, in case you don't know how], along with all of the extra effects in this work that have nothing to do with the actual bubble-pop game [such as re-styling the buttons below, or injecting " ⇗" after offsite links) */
#workskin .disc_link:is(:has(meta:last-of-type[content^='A']) *):hover {
transform: translate(100px, -10px);
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='B']) *):hover {
transform: translate(100px, 50px);
}
#workskin .disc_link:is(:has(meta:last-of-type[content^='C']) *):hover {
transform: translate(150px, 0px);
}
UPDATE 07 Nov: Ironskink golfed the RNG even further-down for site skin purposes, BTW; cf. this NB in RNG in site skins for details.
UPDATE 28 Nov: I discovered 8 new RNG sources in the page source... but they get renormalized in the DOM as rendered...; see this sub-section of RNG in site skins for details.
RECOMMENDATIONS
Contents ↑
If you've enjoyed this random-bubble-popping game (and/or its code and execution), then you might like a few others of a similar vein — while I do have a few of my own in the CSS Abuse and HTML Tryhard collection (the Bubble-Pop! game, obviously, and a point-and-click CYOA Hunt the Wumpus, for example), I might suggest some others' works, such as heark's Namari's Map and mackerel_cheese's find my friends, or actual games such as sudoku of WordsOfWilderness's Heart Flutter Among Stars, or One_of_Them's (greenbean_paste)'s Closed Loop System (Minesweeper, plus evolving Murderbot Diaries updates as you click), or gifbot's But can it run Doom? and Nethack Sokoban (or check in on Playable Games on AO3, periodically)?
You might also want to check out pilliamw's Project Sekai - AO3 Edition.
If you don't mind an off-site interactive, then you might also enjoy
- Zorked Linux (my daughter gave me the heads-up on this one),
- CSS Hell,
- and CSS Hole.
Also in this series (itself part of the CSS Abuse and HTML Tryhard collection): Contents ↑
-
Part 1 — How to AO3
(general info. for newb.s, but includes tips and information that years-long veterans often don't know) -
Part 2 — How to make and fix a series on AO3
(plus unrelated tips re. Wayback, different spaces and dashes, TTS problems) -
Part 3 — Analyzing AO3 reader traffic flow
(one's own fics' reader traffic) -
Part 4 — A year-long AO3 overall traffic analysis
(when do people upload, read, comment, kudos, and bookmark? Reader and new-upload traffic in general, across all of AO3 ) -
Part 5 — Fonts, and colors, and work skins, oh my!
(change your letters and ink color, see others' work skin secrets, etc.) -
Part 6 — Chess puzzle extravaganza
(256 randomly selected preconfigured static chess puzzles, a new one with every refresh
[secret message-reveal from BBEG, because of course];
no offsite JS: just HTML and some CSS) -
Part 7 — Bubble-pop! game
(More RNG fun;
playable bubble-popping;
no offsite JS: just CSS and some HTML;
caution re. volume;
full code included.) -
Part 8 — Targeting specific AO3 work sections (not site) with CSS effects
(wanna put some color into your CSS-verboten summary? Maybe drop an image below your series link, or style your comments section? 😉) -
Part 9 — Inside, Outside, Upside-down
(a showpiece of fun that one can have with CSS — a challenge puzzle, rather than a tutorial;
incl. CSS on a single paragraph within the work summary, among other things;
try to navigate it, work out its little puzzles, and work out how it was all done;
caution re. volume in ch. 1, and flashing lights on:hoverin ch. 2;
NB: must be in single-chapter view, not entire-work) -
Part 10 — Green Rain font, from The Matrix
(several ways to drop Green Rain into your background, simulating the digital rain effect) -
Part 11 — Building ConLangs, with a concrete example
(going about constructing one's own invented language: words, grammar, writing, etc.)
NB: For simplicity, I've collected those and later CSS-heavy works and [playable] games (such as the Bubble-Pop! game, or the point-and-click CYOA Hunt the Wumpus, for example) together in the CSS Abuse and HTML Tryhard collection.
NB: If the work skin [for this piece or any other] was stripped by downloading, so that you can't see any red ink or yellow highlighting or any other special effect, then please see my fonts tutorial's sub-section on re-inserting rules.
O ~~~ O
