Sign in

Kevin Yap

@kevinyap.ca
244 followers 791 following 410 posts

Software developer working on Google Chrome. Previously: Relay.app, Riot Games, and MLSE Digital Labs. I made @zeal.gg and @surveil.land, and post about code, games, and baseball. kevinyap.ca 🇨🇦

PostsRepliesMedia
Kevin Yap @kevinyap.ca · 27/09/2026
Got last-minute tickets to this game since I hadn't seen a Scherzer start. Honestly thought that Schneider was going to let him throw a complete game. George getting a double and Max going 7 IP 1 ER 7 K and both receiving massive standing ovations was such a fantastic end to the season.
000
Kevin Yap @kevinyap.ca · 29/08/2026
Last time I fiddled with this, I believe it was indeed JSON parsing of some fetch requests contributing to most of the CPU time which I slimmed down as much as possible, so I'll probably just have to look into that again.
110
Kevin Yap @kevinyap.ca · 29/08/2026
Thanks, yeah I suspect it's related to something I changed right before leaving on my trip that didn't get executed until today (I run slightly different crons on the weekend so this would've been the first time they fired under these conditions).
110
Kevin Yap @kevinyap.ca · 29/08/2026
Turns out being on the Wi-Fi was causing all requests to the site to hang due to the .land TLD — accessing it through the pages.dev subdomain worked fine. Apparently public networks sometimes just blanket block non-traditional TLDs out of fear of malware/phishing.
000
Kevin Yap @kevinyap.ca · 29/08/2026
Incidentally, I was using the free Wi-Fi at an art gallery when I got the alert about stale event refreshes, and when I went to check the site, nothing would load for me, leading me to momentarily believe all of Cloudflare Pages was somehow down.
100
Kevin Yap @kevinyap.ca · 29/08/2026
Of course, since this happened while I was on vacation, I decided to just do the risk-free fix of "subscribing to the paid tier for a month until I can get back to a computer and actually deploy proper changes".
100
Kevin Yap @kevinyap.ca · 29/08/2026
@surveil.land had a few hours where it wasn't properly indexing new events, but it seems like it's fully recovered and caught up on its backlog now. (Cloudflare Workers started taking more CPU time than allotted by the free plan, so the jobs were just timing out instead of executing.)
221
Kevin Yap @kevinyap.ca · 11/08/2026
Thanks for putting this together! I really wish more of the "competitive MTG scene" would ditch Twitter — it's the only community I care about following that hasn't yet (somehow traditional sports media made the jump before them), but there doesn't seem to be any desire to do so 😕
000
Kevin Yap @kevinyap.ca · 31/07/2026
When I initially wrote @surveil.land, there were zero Store Championship events stored in the database, and I wasn't sure if there was a bug in the event-fetching logic, or if there actually were just no events scheduled worldwide. Glad it ended up being the latter!
000
Kevin Yap @kevinyap.ca · 28/07/2026
Your articles are fantastic, and I've come back to many of them repeatedly over the years (notably every time I've needed hex grids for Advent of Code). In my mind, you pioneered the concept of "interactive widgets in explainers". Thanks for all the effort you put into writing and education!
121
Kevin Yap @kevinyap.ca · 26/07/2026
If Gausman gets traded at the deadline, the Jays BETTER give him a player-friendly contract for a year or two so that he can retire a Blue Jay. The man and his family love Toronto more than any other player I can think of, and he's such a great ambassador for our team and the country.
020
Kevin Yap @kevinyap.ca · 16/07/2026
Will be rooting for the sixteen Ruby Storm players this weekend! Wondering whether it's one or two specific testing teams that decided to run the deck, or just a bunch of individual pilots.
000
Kevin Yap @kevinyap.ca · 14/07/2026
You could also really tell how stressed and focused adef was at points in the run where it seemed like it was destined to fail, but the rapport and knowledge between him and the couch made for such a dramatic and entertaining watch. You couldn't have scripted (nor seeded!) a better run for GDQ.
100
Kevin Yap @kevinyap.ca · 14/07/2026
The guts to do this run unseeded in a marathon setting, and then ending up meeting the win condition on literally the last possible ante *while* reasoning out the line in real time (the Serpent boss blind serving as substitute Cryptids) demonstrated such mastery over the game.
110
Kevin Yap @kevinyap.ca · 14/07/2026
I was familiar with Balatro but didn't know about naneinf runs before watching this, and there are so many interesting deckbuilder + roguelike concepts showcased, like transitioning from an econ build into your late-game scoring build, and needing to play to your outs on the fly.
110
Kevin Yap @kevinyap.ca · 14/07/2026
I only just now got around to watching @adef.bsky.social's "naneinf" Balatro run, but it's *by far* my favourite GDQ run of all time. Spoilers in the thread (watch the run if you haven't!) 🧵
110
Kevin Yap @kevinyap.ca · 29/06/2026
Looks like another Storm player made top 4! I have to think more about how to sideboard with Hex Magic, though. Previously the decision was easy (swap flex-slot cards with sideboard cards), but the issue with Hex Magic is that you want to keep enough of them in your deck to chain them together.
020
Kevin Yap @kevinyap.ca · 28/06/2026
As expected, it's basically the worst card to top-deck late-game, but it makes early setup turns (when you still have 3+ cards in hand) feel nearly inevitable. It also digs for removal under High Noon and similar cards way more efficiently than your impulse draws.
110
Kevin Yap @kevinyap.ca · 28/06/2026
I'm testing it by replacing Glimpse the Impossible instead of Artist's Talent since I feel keeping Glimpses makes the mana curve too high and Talent is often nice as a "less scary" 9th/10th reducer, but I'm not completely sold on that yet.
100
Kevin Yap @kevinyap.ca · 28/06/2026
Having Hex Magic in the graveyard after playing Past in Flames also feels great, especially if you happened to also played some Manamorphoses earlier in the turn to increase your hand size even further before flashing it back.
110
Kevin Yap @kevinyap.ca · 28/06/2026
There's a nice play pattern where you stick a Ruby Medallion on turn 2, then on turn 3, play Hex Magic before playing your third land drop and just play the land out of exile instead. That makes it a draw-5 (or draw-6 if you're OTD).
110
Kevin Yap @kevinyap.ca · 28/06/2026
Some notes on Hex Magic: Unlike your other high-cost cards like Past in Flames and Wish which you really don't want to see multiple of in your hand, multiple Hex Magics don't feel too bad since you can exile one with the other and still play it, effectively extending your hand twice.
100
Kevin Yap @kevinyap.ca · 28/06/2026
Lost to the same Boros Energy player in R5 and in QF. They were on 2× Mana Tithe and 3× Ranger-Captain maindeck with Sanctifier en-Vec, Drannith Magistrate, High Noon, and Wear // Tear in the sideboard (the perception is definitely that Storm has moved up a peg due to Hex Magic).
110
Kevin Yap @kevinyap.ca · 28/06/2026
Made top 8 of the Modern Challenge on Ruby Storm with Hex Magic! Card plays way better than I thought it would. R1: [W] Affinity ⛈️⛈️ R2: [W] Simic Ritual ⛈️⛈️ R3: [W] Ruby Storm ❌⛈️⛈️ R4: [W] Jeskai Energy/Blink ❌⛈️⛈️ R5: [L] Boros Energy ⛈️❌❌ R6: [W] Grixis Moonshadow ⛈️❌⛈️ QF: [L] Boros Energy ❌❌
Magic Online screenshot of a decklist titled "Ruby Storm [Hex Magic]". There is a screenshot overlayed of the top 8 standings:

1. Backoff (8-1)
2. Suechtier (7-2)
3. Polikasoill (7-1)
4. LegendaryHuman (6-2)
5. Coradorable (5-2)
6. pwqz (me!) (5-2)
7. jev_ (5-2)
8. Alakai (4-3)

The decklist is as follows:

Maindeck:
4 Pyretic Ritual
1 Flashback
1 Elegant Parlor
1 Gemstone Caverns
1 Grapeshot
2 Arid Mesa
4 Reckless Impulse
2 Wooded Foothills
4 Manamorphose
4 Ruby Medallion
2 Wish
3 Past in Flames
4 Wrenn's Resolve
4 Desperate Ritual
4 Ral, Monsoon Mage
2 Valakut Awakening
1 Sacred Foundry
2 Artist's Talent
3 Scalding Tarn
2 Bloodstained Mire
1 Steam Vents
4 Mountain
3 Hex Magic
1 Thundering Falls

Sideboard:
2 Wear // Tear
1 Untimely Malfunction
1 Past in Flames
1 Empty the Warrens
1 Grapeshot
3 Prismatic Ending
2 Brotherhood's End
1 Blood Moon
3 Flusterstorm
120
Kevin Yap @kevinyap.ca · 25/06/2026
Got to learn about Cloudflare Pages Functions (yes, double pluralized) while building out this feature! The problem I needed to solve was being able to rewrite the Open Graph tags in the static HTML to show event info based on the link, even though the site itself is effectively a SPA.
000
Kevin Yap @kevinyap.ca · 22/06/2026
Honestly, I should have known better given that I already had to learn about Canadian postal codes and "forward sortation areas" at a previous job. I just made an incorrect assumption that the geocoding API was doing that lookup & resolution already since mine happened to work. Testing is important.
000
Kevin Yap @kevinyap.ca · 22/06/2026
Pushed some updates to @surveil.land thanks to feedback I got after posting it on /r/spikes: - Added format and country filters. - Fixed searching for Canadian postal codes (embarrassing; I initially tested with my own and it worked, but it turns out that was a fluke)
101
Kevin Yap @kevinyap.ca · 19/06/2026
It's been over 6 years since I've done a write-up on a project that I've built (way too long), so today I tried a new technique to overcome my fear of publishing: forcing myself to just write everything in one sitting and then hitting publish. Here's my post on how and why I built @surveil.land!
kevinyap.ca
Building a Better RCQ Locator
I built a website for finding Regional Championship Qualifiers for Magic: The Gathering that you can check out at https://surveil.land.
001
Kevin Yap @kevinyap.ca · 15/06/2026
(tagging @fireshoes.bsky.social for RCQ grinder visibility)
010
Kevin Yap @kevinyap.ca · 15/06/2026
There's already a couple of other similar websites that have cropped up; competition is a good thing! My goals with surveil.land were a) to have an opinionated, unobtrusive design and b) to optimize for long-term maintainability. It should also be very responsive since there's no actual backend.
110
Kevin Yap @kevinyap.ca · 15/06/2026
I build it as a single static site powered by data blobs in a bucket which are updated regularly via a cron job. With this design, I should be able to keep it running indefinitely so long as locator.wizards.com doesn't make any upstream changes (fingers crossed).
110
Kevin Yap @kevinyap.ca · 15/06/2026
I'm back on the Modern RCQ grind this season, but ever since Spicerack was shut down, it's been difficult to find events. Decided to build surveil.land over the weekend to help locate RCQs, Store Championships, and other competitive MTG events (like 5Ks) around the world.
surveil.land
surveil.land | Competitive MTG Event Locator
Find RCQs, Store Championships, and other high-stakes events near you.
2134
Kevin Yap @kevinyap.ca · 05/06/2026
Breaking down competitive games by how much micro/meso/macro skill they test you on, rather than just their genre, is a really cool framework for understanding why certain games appeal more to people than others.
youtube.com
Once you see this, You’ll see Competitive Games Differently
YouTube video by Surnex
000
Kevin Yap @kevinyap.ca · 25/05/2026
I'm fairly certain the Ferrari Luce is just a blue Magic Mouse with four wheels. Indisputably a Jony Ive Project™.
Overhead marketing photo of the Ferrari Luce with an Apple Magic Mouse edited in next to it.
000
Kevin Yap @kevinyap.ca · 20/05/2026
I created @zeal.gg (a rank-tracking site for League of Legends) back in 2018 while playing a ton of League in uni. Now nearly eight years later, I've found myself building a new site related to tracking games of Magic: the Gathering. Guess this is just my side-project niche for life.
020
Kevin Yap @kevinyap.ca · 15/05/2026
For simulation scripts like this, you can often get orders of magnitude speed-up "for free" by running them with PyPy instead of the usual Python interpreter. It does some pre-compilation magic to make loop-heavy code like this *way* faster. (Might be useful for future videos!) pypy.org
030
Kevin Yap @kevinyap.ca · 09/05/2026
This was a 95.1-mph four-seamer and 90.2-mph off the bat, meaning Barger returned it right back home 11-mph *faster* than it was hit. The outfield assist to home has got to be one of the sweetest plays in baseball.
020
Kevin Yap @kevinyap.ca · 09/05/2026
Okamoto moved back in the box after the April 17th game, which gives us exactly 18 games pre- and post-adjustment. - First 18 games: .188 / .263 / .290 (.553 OPS), 4 RBI - Next 18 games: .308 / .400 / .708 (1.108 OPS), 19 RBI (!) Love how well he's fitting in with the #BlueJays.
010
Kevin Yap @kevinyap.ca · 05/05/2026
Having to upload screenshots of my changes on an external site if I wanted to embed them in the PR made me realize how much we take "free" image/video uploads on modern services for granted — I haven't had to think about dedicated image hosts at all for probably a decade or so!
120
Kevin Yap @kevinyap.ca · 05/05/2026
First PR merged on @tangled.org, into Tangled itself! 🧑‍💻 Doing local dev on an atproto app was neat because even though my local DB was unseeded, the app consumes live firehose data, so I was able to see how these changes looked on real data just by letting it run for a bit!
tangled.org
appview/timeline: collapse identical events #1400
Group consecutive timeline events (defined as being the same action and operating on the same target) together so that the same target is not seen multiple times in a row. This notably does not comple...
1270
Kevin Yap @kevinyap.ca · 03/05/2026
Matchups (38 players, 6 rounds of Swiss): R1: [W] Domain Zoo (OTD) ⛈️❌⛈️ R2: [L] Jeskai Control (OTP) ❌❌ R3: [W] UR Prowess (OTD) ⛈️⛈️ R4: [W] Boros Energy (OTP) ⛈️⛈️ R5: [W] UR Prowess (OTD) ⛈️⛈️ R6: [ID into 5th seed] QF: Neoform (OTD) ❌❌
000
Kevin Yap @kevinyap.ca · 03/05/2026
Flashback was an all-star. Flashed back a countered Wear // Tear to destroy Damping Sphere, used it to have 2 more opportunities to flip Ral with Galvanic Discharge on the stack, and in many other instances replayed rituals for more storm or impulses to search for enough gas to find the win.
100
Kevin Yap @kevinyap.ca · 03/05/2026
First Modern RCQ of the season. Pivoted to Boros last minute with 2 MD Flashback, then was anxious about Belcher and Neoform so I added 2 Vexing Baubles to the SB. Made top 8, then lost T2 then T3 to Neoform in the QF despite my best efforts to cast Bauble, so no invite. List felt great though!
Screenshot from Moxfield of my Ruby Storm decklist.

Maindeck:
2 Artist's Talent
3 Bloodstained Mire
4 Desperate Ritual
2 Elegant Parlor
2 Flashback
1 Gemstone Caverns
2 Glimpse the Impossible
1 Grapeshot
1 Lindblum, Industrial Regency
4 Manamorphose
3 Mountain
3 Past in Flames
4 Pyretic Ritual
4 Ral, Monsoon Mage
4 Reckless Impulse
4 Ruby Medallion
2 Sacred Foundry
3 Scalding Tarn
1 Thundering Falls
1 Valakut Awakening
2 Wish
3 Wooded Foothills
4 Wrenn's Resolve

Sideboard:
1 Blood Moon
1 Brotherhood's End
1 Empty the Warrens
1 Fire Magic
1 Grapeshot
3 Orim's Chant
1 Past in Flames
1 Untimely Malfunction
2 Vexing Bauble
3 Wear // Tear
110
Kevin Yap @kevinyap.ca · 01/05/2026
This bumper played again during the game tonight and my partner asked who it was. I thought "oh it's the math rock song", remembered your post, and was able to identify the artist — thanks!
020
Kevin Yap @kevinyap.ca · 30/04/2026
Secret Lair concerns aside, it's so awesome to see your card game come to life, and cool that it's themed around emotions which has influenced so much of your other work! Always looking for simple games to play with non-MTG fans, and a single deck that can fit in a pocket is very appealing.
010
Kevin Yap @kevinyap.ca · 29/04/2026
agh whenever I self-edit a post too many times I inevitably leave in a really stupid typo; I should just type something once and then hit send 🫠
010
Kevin Yap @kevinyap.ca · 29/04/2026
I think a big contributor to this feeling is seeing so many atproto-based hobby projects cropping up that are clearly labours of love rather than big company initiatives — it inspires me to come up with something to build too (I'll have to make it out to an @atproto.to event sometime)!
110
Kevin Yap @kevinyap.ca · 29/04/2026
Said this before too, but it's very cool to see the ATmosphere growing steadily. Having a shared identity across sites, knowing that you own your data, and being able to introspect what's stored on your behalf feels like the "open internet dream" coming back to life.
110
Kevin Yap @kevinyap.ca · 29/04/2026
Following @mitchellh.com's post, I checked out out @tangled.org and it really reminds me of early days of GitHub when you could actually discover people and interesting repos from the global timeline. Mirrored my Advent of Code solution repo and will probably start bringing other projects over too.
tangled.org
kevinyap.ca/advent
My Advent of Code solutions in Python.
1180
Kevin Yap @kevinyap.ca · 25/04/2026
I stumbled upon the realization that calling "prime = win" for Ral flips would be valid†, and inadvertently let this cursed idea loose in the Storm Discord — sorry not sorry if anyone pulls this on you in paper. † For any 𝑛-sided die where 𝑛 ∈ {2,4,6,8}.
Screenshot of a Discord conversation. Transcript:

pwqz (Yesterday at 18:27):
I didn't even know there was a coin flip tool in the Companion app lol. I'd recommend just rolling a D6 and assigning some set of values to heads (odds, evens, primes, etc)

junshiro (Yesterday at 19:02):
@pwqz prime = I win is just so good

nubbet (Yesterday at 19:48):
@pwqz This will be my ral rule. Primes I win is gas
000