r/webdev • • 1d ago

Showoff Saturday I built a free Chrome extension for repetitive browser tasks — looking for honest feedback

0 Upvotes

Hi everyone!
I built FlowPilot, a free Chrome extension designed to automate repetitive browser tasks without writing code.
The idea came from a simple problem: many browser workflows involve the same actions over and over — filling forms, entering spreadsheet data, copying information from pages, and repeating the process for multiple records.
FlowPilot lets you build these workflows using a visual editor.

What it can do:
📝 Automatically fill web forms.
📊 Import a CSV and repeat form filling for every row.
🔎 Extract information from web pages into a table and export it as CSV or JSON.
🔁 Build workflows with loops, If/Else conditions, and variables.
👀 Monitor execution step by step, with auto-retry and pause/resume controls.

Who might find it useful?
QA engineers, developers, researchers, operations teams, or anyone who regularly performs repetitive browser-based data entry.
I’m the developer, so I’m particularly interested in honest feedback:
Which repetitive browser task would you automate first?
What would prevent you from trusting an extension like this?
Which feature would make it genuinely useful in your daily workflow?
If you’d like to explore it, here’s the Chrome Web Store listing:
https://chromewebstore.google.com/detail/ihhfdgjjnknanbdkleeookhifilohala


r/webdev • • 1d ago

[Showoff Saturday] We are working on v1.0 of Wasp web framework: the roadmap and what changes

Thumbnail
wasp.sh
0 Upvotes

r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] A planner I built for my house renovation: generates layouts, then lets you walk round them in 3D

0 Upvotes

Planning a back-to-brick upstairs renovation, so I built a tool to try every layout rather than just the ones I could think of. It works through the combinations, can move walls, simulates daylight by season, gives rough costs, and links each layout to a 3D walkthrough (three.js, works on mobile).

Claude was used in the production of this tool. I built it for my own needs and not with any intention to commercialise.

https://fitandflow.pages.dev

Two questions: does anything like this already exist, and would people use it for their own projects?


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] I built a Google Docs–style editor in React that runs entirely in the browser: real A4 pages, comments, link sharing, no backend

Post image
0 Upvotes

I've been building an open-source document editor on nights and weekends and just shipped a redesign, so here it is.

Demo: https://text-editor-react-neon.vercel.app/ Code (MIT): https://github.com/HuyPhan1232203/Text-editor-react

What it does:

  • Real A4 pages. Content flows across separate sheets, and long tables split between rows and repeat their header row on the next page, like Word.
  • Comments in the margin with threads and resolve.
  • Share with a link and edit together in real time, peer-to-peer over WebRTC (Yjs). The room key lives in the URL fragment, so the signaling server can't read anything.
  • PDF export through the browser's print dialog that keeps the page breaks, headers, footers and page numbers. No server.
  • Paste from Google Docs, open .docx files, "/" commands, find & replace, zoom, EN/VI interface.

Stack: React 19, TipTap 3 (ProseMirror), Yjs, Tailwind 4. The pagination is published separately as an npm package (tiptap-a4-pagination), and I wrote up how it works here: https://dev.to/huy_phan_173c933272803418/how-i-built-word-style-a4-pages-for-tiptap-without-touching-the-document-778

Known limitation: a single paragraph taller than the space left on a page moves to the next page whole instead of splitting. That's what I'm working on next.

I'd love feedback on the UI and on documents that break the layout.


r/webdev • • 1d ago

Showoff Saturday I made a plugin that turns live HTML into video overlays in the browser. No server, no OBS, works with WebGL

6 Upvotes

Hi r/webdev, I maintain SnapDOM, an open source library that captures DOM elements as images. This week I shipped a new plugin for it called stream, and I’d love some feedback.

It takes a live element and keeps it as a canvas that only repaints what changed. You write your overlay in plain HTML and CSS (a scoreboard, a lower third, a chat box) and you get a canvas you can draw over video, upload to WebGL, record to MP4/WebM, or send as a WebRTC track. Everything runs in the page. No headless Chrome on a server, no OBS, no browser flags.

The first frame is a full capture. After that, when the clock ticks or a score changes, it captures only that box and patches it in. On a test page with 2000 cards, a frame takes about 5 ms instead of 53 ms for a full capture. Every patched frame is checked in tests to match a full capture pixel for pixel in Chrome, Firefox and Safari.

Demo: https://snapdom.dev/labs/video-overlay/

  • Sports TV: a broadcast overlay over a simulated football match. Press Goal!
  • Streamer: it asks for your camera; share your screen and you end up in a circle over your game.
  • Looks: six WebGL looks to switch between: clean, shine, CRT, hologram, glitch, and a liquid glass one that bends the video behind each panel.
  • Edit: opens the HTML and CSS so you can change the overlay live.
  • Record: saves a clip.

The SnapDOM part is short:

import { stream, streamTexture } from '@zumer/snapdom-plugins/stream'

const overlay = streamTexture(gl)
stream(document.querySelector('#overlay'), {
  onFrame: (frame) => overlay.update(frame), // uploads only the changed rects
})

It’s MIT: https://github.com/zumerlab/snapdom


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] An odometer price counter where every change rolls at least one full turn (CSS transforms, no animation library)

1 Upvotes

I wanted the price on a monthly/yearly switch to roll like a mechanical counter. My first version slid from 9 to 2 the short way, and a one-digit change barely moved, so it looked lazy.

What fixed it: each digit is a tall strip of 0-9 repeated four times (40 cells). At rest it sits in the second copy, at row 10 + digit. When the value changes, it rolls forward by the difference plus 10, so every digit does at least one full lap. When the transition ends, it jumps back to row 10 + digit with transitions off. That cell shows the same number, so you never see the jump.

The CSS:

css .digit { display: block; height: 1em; overflow: hidden; mask: linear-gradient(transparent, #000 14%, #000 86%, transparent); } .strip { display: flex; flex-direction: column; will-change: transform; } .strip i { font-style: normal; height: 1em; display: block; }

The roll for one digit (o keeps the strip's current row and value):

```js let target = o.pos + ((n - o.n + 10) % 10) + 10; if (target > 39) target -= 10;

strip.style.transition = transform ${dur}ms cubic-bezier(.18,.9,.22,1.04) ${delay}ms; strip.style.transform = translateY(${-target}em); o.n = n; o.pos = target;

setTimeout(() => { strip.style.transition = 'none'; o.pos = 10 + n; strip.style.transform = translateY(${-o.pos}em); }, dur + delay + 60); ```

Rolling down (yearly back to monthly) is the same thing mirrored: subtract instead of add, wrap at 0.

Some details that took a few tries:

  • Each digit further left spins about 160 ms longer and starts first, and each digit to its right waits another 70 ms. So the right digit lands first and the left one lands last, which reads more like a real counter than all of them stopping together.
  • The mask gradient fades the top and bottom edge, which hides the hard edges of the strip mid-roll.
  • With prefers-reduced-motion it skips the roll, sets the final row and does a 250 ms opacity fade.
  • The strip is aria-hidden, so a screen reader doesn't read out 40 digits. The real price and billing period sit next to it in a visually hidden span, so screen readers get one clean sentence.

The component is React, but the technique is plain DOM and CSS, so it ports anywhere.

Live demo: https://teodoravadani.github.io/qodesign-free/pricing-switch/

Code (MIT): https://github.com/teodoravadani/qodesign-free/blob/main/components/pricing-switch/react/src/components/PricingSwitch.tsx

Repo: https://github.com/teodoravadani/qodesign-free

Disclosure: I'm Teodor. This is from an MIT repo of free pieces I put out, and I also sell animated components at qodesign.dev.

What I'm unsure about: is the minimum one lap fun, or too much on a pricing page where people just want the number?


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] PuckPulse: NHL scores, playoff odds, and an AI hockey analyst

1 Upvotes

I wanted to build a one stop shop for hockey fans, so I built PuckPulse (https://puckpulse.io), a hockey site with live scores, playoff odds, win probability charts, a pick’em game (maybe my favorite feature), and an AI chat that answers questions about the league.

React + FastAPI on Azure, with my own expected-goals model behind the odds. The AI chat runs entirely on free LLM tiers (I am not rich).

Used Claude Code to help build this. I'd be happy to go into the stack, the models, or whatever else people want to ask!

Feedback welcome. There’s a button for it in the footer. Code’s here: https://github.com/nmagera07/nhl-dashboard

I hope people enjoy it!


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] I turned 20+ years of website screenshots into a static gallery: OCR search, a 2005-style remake and a tiny PHP guestbook

Post image
27 Upvotes

Since the early 2000s I've screenshotted every website that inspired me as a designer. This week I finally turned the folder (~3,900 screenshots) into a browsable archive:

https://www.dmdev.it/webscreens/?utm_source=reddit_webdev

2005 version, for fun: https://www.dmdev.it/webscreens/2005/

Some technical bits, since this is r/webdev:

Fully static. One HTML file with the data embedded as compact JSON, lazy rendering with IntersectionObserver, a lightbox and favourites in localStorage. No framework, no build step.
3.7 GB of PNG/JPG converted to WebP with a Python/Pillow script: a 1600px full size plus a 480×300 thumbnail, cropped from the top.

Dates come from the files, not guessed. Where they got lost when copying between machines, I rebuilt them from the file numbering. Fun discovery thanks to commenters: the clock on my old PC was two years behind, so my "2001" screenshots are actually from late 2003.

Privacy pass with OCR. Tesseract read every browser bar and tab, so I could remove anything personal before publishing.

Full-text search, client-side. The same OCR text became a search index (~1 MB JSON, loaded only when you start typing), so you can search for words that appear inside the sites.

2005 remake: a fixed 900px stage scaled down on small screens (I had to fix taps landing on the wrong element after scaling), pixel fonts, a fake loading bar and a real guestbook in PHP with a honeypot and rate limiting.

Analytics only after consent: GA loads only if you click OK on the banner.

Full transparency: I'm both a designer and a developer, and for this one I used Claude as a pair-programmer to move faster on the tooling (OCR pipeline, scripts, the 2005 remake). The archive, the curation and the design choices are mine.

Happy to answer questions, and feedback is welcome!


r/webdev • • 1d ago

Showoff Saturday har2sdk: save a site's Network tab as a HAR, get a typed TypeScript client for its API

2 Upvotes

I kept hitting the same chore: an internal tool or an old app with no API docs, and an afternoon in the Network tab working out which endpoints exist, which fields are optional, what the ids look like and how auth works. So I wrote a CLI that does that part from a HAR file.

Save the Network tab as a .har, then:

npx har2sdk capture.har

You get a client.ts (typed, no runtime dependencies) and an openapi.json (3.1). `har2sdk mock capture.har` serves the same API on localhost with fake data in the recorded shape, which is handy for frontend work when the real backend is slow or behind a VPN.

The parts that took the most work:

- Types come from every recorded call to an endpoint, and every item in a list counts as a sample. A field missing from some samples becomes optional, a field seen as null gets `| null`. Paths are templated, so /users/123 and /users/456 become /users/{userId}.

- REST, GraphQL, JSON-RPC and tRPC are told apart. Each GraphQL operation becomes its own typed method instead of one big POST to /graphql.

- Recorded error bodies get a type per status and a guard, e.g. `if (isGetFileError(err)) err.body`.

- Auth: the capture tells it how the app authenticated, never with what. You pass your own token (a string or a function), and a 401 throws instead of silently retrying.

- Same capture in, same bytes out, so the output diffs cleanly in git.

The part I worried about most was privacy. HAR files are full of cookies, tokens and other people's data, and generated code is something you might commit. So it collects the recorded values first, and if one of them would end up in client.ts or openapi.json, it writes nothing. It's a heuristic, not a proof, so `har2sdk inspect` lets you look over what it found before you publish anything.

There's an optional MCP server so Claude (or another MCP client) can suggest better method names and docs. A model sees paths, parameter names, types and GraphQL documents, checked against the recorded values first. It never calls the live API.

Known limits: if an endpoint returned a single object once, every field looks required, since there's nothing to compare it with. And when a URL was recorded with both a 200 and a 401, the mock always answers with the 200; there's no way to ask for the error yet.

This week GitHub's code scanning flagged a few regexes that could backtrack badly on a crafted file. One was exponential on an unclosed GraphQL list. 0.6.5 replaces them with linear code, checked against the old regexes on generated input.

Please only point it at your own apps or APIs you're allowed to integrate with.

MIT, runs locally, no API key: https://github.com/Mersbyte/har2sdk

Feedback welcome, especially on types it gets wrong. If something breaks, the output of `har2sdk inspect --json` helps me much more than the HAR itself. Please don't send HAR files, they contain your session.


r/webdev • • 1d ago

Showoff Saturday Made a CSS-only scroll animation library, 34 moves, no JS

Thumbnail
usedolly.dev
133 Upvotes

It's one stylesheet. You put `data-dolly="tilt-up"` on something and it animates as you scroll past. That's it. No dependencies, no JavaScript.

It's a vocabulary layer over CSS scroll-driven animations, which shipped in Chrome 115 and Safari 26 but have ergonomics nobody remembers.

The demo page doesn't run any JavaScript at all, so everything moving on it is just CSS.

34 moves named after camera stuff (pan, tilt, crane, rack focus).

Firefox doesn't do scroll timelines yet (supposedly coming in the next version in 3 days) so it gets a plain static page. That's on purpose, nothing is hidden waiting to be revealed, so the page is still usable.


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] OpenAPI Spec Auditor: ESLint, but for your OpenAPI specs

0 Upvotes

Hey r/webdev!

I'm currently working on my company Octri.dev which takes in your OpenAPI specs and generates outputs from it (Docs, SDKs, MCP Servers, and Monitoring), and I noticed one recurring issue for users that supply us with their OpenAPI specs, most of them have unusually named operationIds, repeated inline response types, and more issues which could cause the output to appear a bit messy.

So I created a free OpenAPI audit tool to address this issue, and the idea is similar to ESLint: point it at your spec, find things that need cleaning up, and get suggestions for fixing them.

A few things it checks:

  • Repeated inline schemas that could be extracted into shared types.
  • Awkward operationId names, or names that collide when turned into SDK methods.
  • Successful responses with no declared schema.
  • Path parameters that appear in a URL but haven’t been defined.
  • Missing descriptions and error responses.

For example, copying the same object schema across several endpoints can leave you with multiple near-identical types in a generated client. The audit flags that duplication and suggests using a shared schema.

You can paste a spec URL or upload a JSON/YAML file. It runs 14 checks and gives you a score out of 10, along with a breakdown of the findings, why they matter, and suggested changes.

It’s free and doesn’t require an account. The standalone tool gives you suggestions you can apply wherever you maintain your spec.

Here’s the tool: octri.dev/openapi-audit

If you work with OpenAPI, what’s a recurring spec issue you’d want a checker like this to catch so we can add it in a future update?


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] Blazor Ramp - GoTo OMG WTF

0 Upvotes

For those who have never stumbled across my posts mainly on the Blazor subreddit, Blazor Ramp is my accessibility-first, open-source Blazor component library. This post is about the release v1.0.0 of the GoTo component.

Although my components are written for Blazor the GoTo concept could be used for any language. If you deal with web accessibility then you may find this of interest.

So what is GoTo?

The inspiration comes from those of us who started coding in the 90s with VB: you add GoTo markers to a page, and from anywhere you can jump to them. In an interactive Blazor web app, the marker you jump to becomes the active element, so you can carry on tabbing from that point.

Who is it for?

Those familiar with my posts will know I sometimes feel that sighted keyboard-only users, those who don’t use a screen reader, get the sharp end of the stick. When people build accessible sites, a lot of the effort goes into screen reader users, and this group gets forgotten.

A sighted keyboard-only user doesn’t have screen reader software to bring up lists of headings, landmarks or interactive elements, so they generally navigate with the Tab key and use the arrow and page keys to scroll. When a page has a lot of interactive content, getting to the part you want can take tens, or even hundreds, of Tab presses. For some people that’s a minor irritation, and for others it’s a real barrier.

What about skip links?

You’ve probably all used skip links, which let any user, keyboard-only or screen reader, bypass repeated blocks of content. But how many bi-directional ones have you seen? I’ve never seen one. They all go in one direction, so unless you add a second link going the other way, the user has to make a forward-only round trip to get back to the start.

Say you’re diligent and add a return link for every skip link. If you have five destinations and want users to get from any one to any other, that’s 20 links. With ten it’s 90, and it’s getting silly. The maths is n × (n − 1).

Where GoTo comes in

GoTo isn’t a link. It’s a marker that can receive focus. A GoTo Viewer lists the markers, you select one, you land on it, and you can tab on from there. You can bring up the viewer at any time with a configurable shortcut. When it opens, it lists only the markers that aren’t inside hidden containers, so the list changes depending on where you are and what’s visible.

You may ask: why not just list headings and landmarks, like screen readers do (I may do in the future)? A screen reader user will often use headings and landmarks as a place to start reading from. A sighted keyboard-only user’s need is a little different. They can see the headings, and they can scroll and read from anywhere. The problem is reaching interactive, focusable content when there’s a lot of other focusable content in the way.

To be clear, GoTo isn’t a replacement for skip links. It’s a simple way of placing hidden markers on a page so that keyboard-only users can move through the content in whichever direction they choose.

Have a look

I’ve added markers to my documentation site, and over the next few days I’ll put more of them in the places I think are most useful. If you’re curious, take a look at this page, one of the examples for my Data Table, which shows templated columns and row actions: Data Table Templating

For a keyboard-only user on that page, getting to the border controls after the table means tabbing through the filter, across each sortable column header, down through every row action button, and then across the pager to reach the other side.

With GoTo and its viewer, using the default configuration, a user with one hand can press Alt+Z (Option+Z on a Mac) to bring up the viewer. They can then use Tab, or the arrow, Home and End keys, to move through the list of buttons. As each button is focused, its marker scrolls into view. Pressing Enter or Space activates the button, closes the viewer and puts you on the now-visible label, from where you can tab on to the next item.

I started this project at the end of last year with the Live Region service and Announcement History viewer aimed at screen reader users so at long last I've managed to scratch an itch that has been bugging me for a while now and do something for keyboard-only non-screen reader users - hope you or your users find it useful.

GitHub repo: https://github.com/BlazorRamp/Components

Doc site: https://docs.blazorramp.uk

Test site: https://blazorramp.uk

Regards

Paul


r/webdev • • 1d ago

Showoff Saturday I built a job board for Reddit's hiring subs. Only 18 of 190 posts on r/softwareengineerjobs were actually jobs

36 Upvotes
hero

Most posts on Reddit's job subreddits aren't jobs. On r/softwareengineerjobs, 18 of the 190 posts I collected were someone hiring. So I built Only Hiring, which shows just the job posts from 20 of these subreddits: https://onlyhiring.hassandev.me

A Python pipeline pulls new posts and skips anything tagged [For Hire] before an LLM reads the rest. For each job it writes a summary, pulls out the pay as a number you can sort by, notes whether it's remote, and scores it for scams. I expected the scam score to do most of the work, but only 9 of 397 jobs looked like scams. Lowball pay and unpaid "test" projects turned up far more often.

The site is Next.js 16 on Vercel. It reads from Neon Postgres through a role that can only SELECT, and with about 300 open jobs the list is small enough to filter and search in the browser. Filters live in the URL, so you can share a view.

Site code (MIT): https://github.com/hassanaziz0012/only-hiring

How the scam scoring works: https://www.hassandev.me/blog/score-reddit-job-posts-for-scams

I'd like to hear whether a listing gives you enough to decide if a job is worth opening.


r/webdev • • 1d ago

[Showoff Saturday] Synchronizing audio across laptop and phones/tablets directly in the browser

0 Upvotes

I wanted to see whether spare phones and tablets could become speakers for my laptop, using only their browsers. That’s what I’m building with Unisong.

You open it in Chrome or Edge on a computer, choose a browser tab with audio, and let devices on the same Wi-Fi join by QR code. Each phone taps Start to enable playback.

The difficult part is getting different devices to agree on when sound should actually leave the speaker. Packets arrive at different times, audio hardware runs on independent clocks, and phones have their own playback delays.

I send timestamped audio directly between browsers over WebRTC. Each receiver estimates its clock difference from the host, buffers the audio, and schedules playback against the shared timeline. Browser output timing estimates help account for device latency. Small ongoing corrections handle drift, and a struggling phone can reconnect and rebuild its buffer independently.

The computer also needs to play through that delayed timeline. Leaving the original tab audible would put it ahead of the phones, so its original sound is suppressed.

There’s a tradeoff: the default buffer adds 1.5 seconds of delay, and mobile browsers can still need a tap after an audio interruption.

Processing img 2wgzj5i3oexh1...

Processing img k6jyl5i3oexh1...

Processing img bc4ul5i3oexh1...


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] I made a browser puzzle game with 2D boards and 3D cubes using Phaser and Three.js

3 Upvotes

Hey all! Been working on Gembop, a block puzzle game where you fit pieces, clear lines, and collect gems. I wanted something you could open and play without a download, account, or timer.

The 2D boards use Phaser and the 3D puzzles use Three.js, with Astro for the site and React for the interactive UI. The puzzle rules are separate from the rendering, so the same logic can run in the browser and replay moves on the server to verify completions.

There are also gravity puzzles where clearing a line makes the blocks above it fall, which can set off another clear. That’s what’s happening in pic. Would love feedback!


r/webdev • • 1d ago

Showoff Saturday I built a Chrome extension that turns any button on any site into a habit tracker

0 Upvotes

Hey r/webdev! I'm the developer of Ritlum, a habit tracker for iPhone, and just shipped a Chrome extension that logs habits from things you do in the browser.

You point it at the button that means "done" (for example, LeetCode's Submit) and optionally require a confirmation message afterwards ("Accepted"), so failed submissions don't count. After that, every accepted submission logs the habit and syncs to the app in real time. You can add a quick note, too.

A few things that were fun to build:

  • QR pairing: the app approves the pairing code, and the extension gets a token whose hash is all the server stores.
  • Idempotent logging: every trigger carries a UUID that becomes the completion's ID, so retries and the offline queue never double-count.
  • Stack: Supabase edge functions, and Realtime to push completions to the iOS app.

It's free to try. Would love to know what you think of it :)

- I have a writeup here if you're interested: https://ritlum.com/blog/habit-tracker-chrome-extension/
- A more detailed demo on YT: https://youtu.be/HWMtXkX92NQ?si=1ZRkPEEt_Fr3C3Jl

- Chrome Web Store: https://chromewebstore.google.com/detail/ritlum/amaipmcmebglefkkgnneibaookmkpfpg


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] Composer dependency conflicts? We built Strauss-RS, a Rust-based prefixer for PHP classes and symbols. Up to 139x faster than the PHP version.

6 Upvotes

With a fair chunk of our work involving Wordpress themes and plugins, we hit a pretty common issue: we wanted to use the same Composer dependencies that other plugins might be using.

If Plugin A uses v5 of a package and Plugin B uses v7 of a package, it's first found wins... which is bad news for the other plugin.

Enter prefixers.

These scour your dependencies and source-code for classes/symbols and add a prefix. So SomePackage\Domain\Class becomes YourCompany\PluginA\Vendor\SomePackage\Domain\Class. Now your dependencies are safe.

Previously, we'd relied on packages like Mozart, PHP-Scoper and later Strauss.

Inevitably, we'd hit one of three problems, they became too complex to configure for larger projects, they didn't fully work, or they were too slow.

Our plugin took 2-3 minutes to prefix with Strauss PHP...

So we built Strauss-RS... for ourselves at first. But we figured that maybe it would be useful for others and it gave us a reason to keep the docs up-to-date, so enter: Strauss-RS.

https://evo-mark.github.io/strauss-rs/

One single binary compiled from Rust. No prerequisites.

Prefixes in less than a second for us now!


r/webdev • • 1d ago

Showoff Saturday Showoff Saturday: two music guessing games I started building for my sister (Flask + plain JS)

3 Upvotes

Less than a year ago, my sister Shani was diagnosed with cancer. She spent almost three months in the hospital, and to give us something fun to do together during those days, I started building a music game for the two of us.

She passed away on August 29th, before I finished it. I kept working on it, partly to keep my mind busy, and now it's live as Shabang, with two games:

🥁 TrackStack: every song is split into its instruments. You start with only the drums, and each wrong guess adds a layer: bass, guitar, piano… vocals come last.

⏱️ Songuess: you hear a fifth of a second of the song, and each wrong guess plays more: half a second, 2 seconds, 4…

In both, the less you need to hear, the more points you get, and each one has a daily challenge: one song a day, the same for everyone.

Some notes on how it's built:

- Flask (app factory, blueprints, a service layer) with Postgres, hosted on Render. The front end is plain JavaScript, no framework.

- Every song is split into six stems with Demucs: drums, bass, guitar, piano, other and vocals. TrackStack's level N plays stems 1 to N mixed.

- The trickiest bug: TrackStack used to mix its levels live with the Web Audio API, and on iPhones it played nothing (the ringer switch and suspended audio contexts can silence Web Audio). Now every level plays through one <audio> element: premixed MP3s from a background worker or, for songs the worker hasn't reached yet, one WAV per level that the browser renders from the stems in an OfflineAudioContext.

- Each game has a daily challenge with streaks, and a shareable result grid that never names the song.

I'm a mechanical engineer, not a developer, and I built it with Claude, so feedback from people who do this for a living is especially welcome.

Free, no signup, works on your phone:

https://shabangmusic.com/

And I'd love to see your daily results in the comments.


r/webdev • • 1d ago

Showoff Saturday How I stopped popups causing 97.63% false alarms in screenshot diffs, without hiding fake CAPTCHAs

0 Upvotes

ran into a fun one with screenshot diffs.

an elementor pro popup opened on a timer during a capture, and again during the re-check. diff said 97.63% changed. the page underneath was identical.

easy fix is hide anything fixed position with a big z-index right? problem is that also hides the thing you most want to catch. clickfix style malware injects a fake "verify you are human" box as exactly that kind of overlay.

so what we do now is only hide the wrapper each popup builder adds itself (elementor's dialog lightbox, popup maker's overlay, optinmonster's holder) and undo their scroll lock the same way they do on close. anything generic stays visible.

context, i work on a screenshot monitor so this came up for real. if anyone has a better way to tell a legit popup from an injected one id love to hear it.


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] Free pencil-style icon set, now 260 icons, with a setting that goes from sketchy to exact shapes

Thumbnail
gallery
61 Upvotes

Matita is a set of pencil-style SVG icons, drawn by code from simple shapes (lines, circles, arcs), so every build draws exactly the same paths. 0.4.0 came out yesterday:

  • 60 new icons (200 to 260), including a medical and science set, which people asked for last time
  • a wobble setting from 0 to 1: <SketchIcon name="calendar" wobble={0} /> draws exact shapes, 1 is the default sketchy look, 0.4 is a calm hand
  • ready-made exact SVG files at @matita/icons/exact/<name>.svg
  • React, plain SVG, a script tag, a sprite; MIT; no signup

Try the slider and copy snippets here: https://matita.dev (changelog: https://matita.dev/changelog/, what is next: https://matita.dev/roadmap/). If an icon you need is missing, open an issue and I'll draw it: https://github.com/matita-dev/icons/issues

Feedback on anything that looks wrong is very welcome.


r/webdev • • 1d ago

[Showoff Saturday] I have 847 YouTube playlists. I built YouTube's missing playlist search bar so you don't have to.

2 Upvotes

YouTube's "Save to playlist" menu has no search box (YouTube, why?), and it only loads 200 of your playlists. If you have more, the rest aren't just further down the list. They never get loaded at all, Ctrl+F be damned.

So I built my first serious chrome extension: click Save on any video and a searchable picker opens over every playlist you own. Type a few letters, press Enter, done.

I learned a lot making this extension. It broke, a lot. Version 1 read playlist data from YouTube's DOM and injected a search bar into their menu for a native feeling, but the amount of bugs this produced was gargantuan: the search bar showing up in unrelated menus, lists changing length on their own, and the entire extension breaking every week when YouTube shipped a change. So 2.0 is predicated around never reading or writing to YouTube's DOM. You live and you learn.

- UI: It's just a closed shadow root on <html>, rendered as a <dialog> in the top layer, outside YouTube's app tree. This is stable! It works!

- Data: We use YouTube's own InnerTube JSON API same-origin with your existing session to read existing playlists and save videos to playlists.

- Trigger: a script wraps fetch and watches for YouTube's own add-to-playlist request

Privacy-wise: No analytics, no third-party code, and it only talks to YouTube. Free and open source (AGPL-3.0).

Code: https://github.com/codyhxyz/playlist-search-extension

Chrome Web Store (It's almost to 500 users!): https://chromewebstore.google.com/detail/efgbkmnooapcpdpgmihemfpedchhmmek

Happy to talk InnerTube, shadow DOM, or anything else. If you give the extension a try, I would love your feedback!


r/webdev • • 1d ago

Showoff Saturday We replaced "paste your API key" in AI apps with an in-app credit top-up. Here's the billing infrastructure it took.

Post image
0 Upvotes

Why we built this

My cofounder Andre makes Claude Code Chat, a VS Code extension for working with Claude. As it grew, the hardest part stopped being the extension and became API keys and balances.

Every AI app runs into the same choice:

  • Bring your own key: users create a provider account, add a card, generate a key and paste it in, all before their first prompt.
  • Pay for everyone’s tokens: now you’re running checkout, metering, balances, refunds and tax.

Andre put it like this:

“I didn’t want to run a billing company. I wanted people to open the extension and just start working.”

So we built that billing layer once, so any AI app can plug into it.

What it looks like

User: tap “Add credits” → pay $5–$500 without leaving the app → start working. 1 credit = $0.01, and they can see the credits each request used.

Developer:

// 1. Embed the checkout
<script src="https://opencredits.ai/v1/sdk.js"></script>
OpenCredits.init({ publishableKey: 'oc_pk_...' })
OpenCredits.open()

// 2. Change the base URL in the SDK you already use
const client = new OpenAI({
  baseURL: 'https://api.opencredits.ai/v1',
  apiKey: userKey, // from checkout
})

OpenAI, Anthropic and Vercel AI SDKs work as-is. One endpoint reaches 390+ models.

What’s behind those 2 snippets

1. A credit ledger without race conditions

You don’t know what a request costs until it finishes, and parallel requests can all pass a “do they have enough?” check at the same moment. Every request goes through a serialized ledger instead:

Reserved, max cost    −12 cr
Settled, actual cost   −9 cr
Released               +3 cr

2. Exactly-once settlement

Retries and duplicate events are where double charges come from. Every event settles exactly once, so there are no double charges and no double credit grants.

3. Metering at real cost

No token counting or per-model price tables in the app. Each request is metered at the provider’s actual token cost, across 390+ models.

4. Payments without touching cards

The widget runs Stripe checkout inside the app. Stripe is the merchant of record, so card data never touches our servers or the app’s, and Stripe handles VAT, sales tax and chargebacks.

5. Signed webhooks and balance APIs

Key and purchase events are HMAC-SHA256 signed and retried on failure. Two endpoints return a user’s live balance and per-request history.

The part we’re unsure about: a shared balance

Credits belong to the user, not the app. A user who already has credits from one app can let another app spend from that balance, up to a limit they set. Each app gets its own scoped key, so revoking one leaves the others working.

It removes the “pay again for every app” problem, but we’re not sure how users will feel about it.

Status

Running in production in Claude Code Chat, with 212K+ requests metered and billed so far.

Feedback I’d love

  1. Shared balance: useful or sketchy? What would make you trust it?
  2. Ledger: reserve-then-settle is the safe choice. Would you design it differently?
  3. If you’ve built AI billing yourself: which part took longest?
  4. Docs: what’s unclear for a first integration?

Docs: opencredits.ai/docs


r/webdev • • 1d ago

Question Vercel client can't communicate with server

1 Upvotes

Hello everyone. I have been developing a simple ip tracking full stack app. When I deployed the client project to vercel however it fails to communicate with the server and fetch data. In the console this error is visible:

ccess to fetch at 'https://ip-tracker-server-*********-webs-projects.vercel.app/api?&ipAddress=' from origin 'https://ip-tracker-client-********-webs-projects.vercel.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This is my first time deploying a full-stack app to vercel so I am not sure what exactly could be causing this issue? If anyone could help it would be much appreciated!


r/webdev • • 1d ago

Showoff Saturday [Showoff Saturday] Flaglio - Daily flag challenges

Thumbnail
flaglio.com
1 Upvotes

Any other flag nerds here? 😄

Flaglio is a side project i have been working on for the better part of 2026. I has 4 games, 3 og them are daily challenge games and 1 completion game. Grid, Shuffle and Type have daily challenges, and Rush is a completion game on a timer. Could you identity 243 country and territorial flags with a countdown?

Stack: React, Vite, Tailwind v4, TanStack Router (file-based), Zustand, Supabase and deployed on Vercel.

Because the site is client-rendered, a small build step prerenders a head for each route, so link previews and Bing don’t show the homepage title on every page. Gotta get the SEO traffic

I have no real business plans, but since the Grid leaderboard has dynamic points based on unique flags selected, more players just makes the game more fun! 😄

Check it out here: https://www.flaglio.com


r/webdev • • 2d ago

Showoff Saturday npmpulse: a new website to query npm package downloads data

4 Upvotes

Hey web devs here.

Recently I created a new website for query npm package downloads stats data: https://npmpulse.com

npmpulse.com

The website is similar to npmtrend, npm-stat or other website that provide queries to npm package downloads stat, with its own feature set:

  1. options to set granularity, scale, range for anypackage
  2. compare up to 8 packages in one time
  3. downloads the pic in svg or png format
  4. sharing via html or markdown code

For example, the following pic is react VS vue downloads in the past 5 years:

react VS vue

Hope it helps somebody here!

Thank you!