惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Blog of Author Tim Ferriss
P
Privacy & Cybersecurity Law Blog
P
Proofpoint News Feed
S
Schneier on Security
G
GRAHAM CLULEY
The Hacker News
The Hacker News
C
Cybersecurity and Infrastructure Security Agency CISA
Know Your Adversary
Know Your Adversary
C
Cyber Attacks, Cyber Crime and Cyber Security
爱范儿
爱范儿
M
MIT News - Artificial intelligence
V
Vulnerabilities – Threatpost
F
Fortinet All Blogs
月光博客
月光博客
Simon Willison's Weblog
Simon Willison's Weblog
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
Spread Privacy
Spread Privacy
P
Proofpoint News Feed
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
Y
Y Combinator Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tor Project blog
T
Troy Hunt's Blog
Latest news
Latest news
N
Netflix TechBlog - Medium
Vercel News
Vercel News
Stack Overflow Blog
Stack Overflow Blog
Project Zero
Project Zero
N
News and Events Feed by Topic
F
Full Disclosure
酷 壳 – CoolShell
酷 壳 – CoolShell
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CERT Recently Published Vulnerability Notes
H
Hacker News: Front Page
C
Cisco Blogs
I
Intezer
P
Privacy International News Feed
MongoDB | Blog
MongoDB | Blog
L
LINUX DO - 热门话题
Blog — PlanetScale
Blog — PlanetScale
Security Latest
Security Latest
Last Week in AI
Last Week in AI
Scott Helme
Scott Helme
B
Blog
博客园_首页
MyScale Blog
MyScale Blog
Cloudbric
Cloudbric

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Vibe Coding for Beginners: How I Built a Working Photo Booth Web App With Claude
Rachael Berkey · 2026-06-19 · via DEV Community

TL;DR - A non-coder's first real build: how I vibe coded a working photo booth web app with Claude: live camera, branded frames, a Supabase backend, and the beginner gotchas nobody warns you about.

So it’s time to break the fourth wall a little bit. Hi, I'm Rachael, and I write for MLH, which, to be clear, means I write words, not code. My technical credentials begin and mostly end with the HTML and CSS I taught myself on LiveJournal sometime around 1999, when the height of web development was getting your blinking text and your tiled starfield background to coexist. Make your MySpace jokes now. So when I tell you this is the story of building my first real tool, please understand the comedy baked into that sentence: I am usually learning, researching, and writing what I hope are interesting and informative pieces (which hopefully this will be for someone equally new to or unfamiliar with software development), not the person who would normally be trusted near a repository.

I've written little scripts before. I've gone directly to the little HTML button in the WordPress editor when it just...won’t....work. I once, memorably, turned the homepage of an intranet site italic because IT wasn’t answering my question fast enough and I thought I could figure it out. But I had never built a tool – something a stranger could open, use, and walk away from with a thing they wanted. And it just happened that I was ready to write about vibe coding at the same time I clocked a functional tool we needed for events. So here’s how Claude and I built a photo booth for MLH.

What I Built

The problem I needed to solve was small and concrete, which in hindsight is the best possible kind of first project. Major League Hacking (MLH) runs a ton of events, and the idea was a browser-based photo booth: an attendee opens a page on their phone, snaps a selfie with the built-in (front-facing, mirrored) camera or uploads a picture of themself from their Photo Album, drops a branded event frame over it, pinches and drags to line it up, and saves the finished square PNG straight to their camera roll to post. Organizers, who are sometimes less technical than others, and sometimes a different person at each event, sign-in to a little gated panel and upload the transparent PNG frames ahead of time.

That's it. No accounts for attendees. No app store. Just a link.

Simple to describe is not the same as obvious to build, and the gap between those two is exactly where I learned the most.

Decision One: Where Does This Thing Even Live?

Chatting it through with Claude

My instinct as a beginner was to reach for a framework, because that's what every tutorial does. Claude talked me out of it, and the reasoning stuck with me: for a tool that has to be reliable at a live event, run by whoever's around, the fewest moving parts wins. So the entire tool is one self-contained index.html with HTML, CSS, and JavaScript in a single static file, no build step, no dependency install, nothing to break the morning of the event. It drops straight into a GitHub repo and serves from GitHub Pages for free.

The first time I really felt the value of vibe coding was here. I didn't have to know that a no-build static site was the robust choice. I described the constraints (free, reliable, runs at an event, handed off to non-devs) and the right architecture fell out of the conversation. My job was to recognize the reasoning was sound, not to have memorized it.

Two Repos Compared

Decision Two: The Photo Never Leaves The Phone

This was the technical bit I'm proudest of understanding, even though I didn't write it.

The frame is a transparent PNG. The selfie is whatever the camera grabs. To combine them, you draw both onto an HTML <canvas> – the photo underneath, the frame on top – and then export the canvas as a PNG. All of it happens in the browser, on the device. The attendee's face never gets uploaded anywhere. For an event full of people who didn't sign up for anything, that's not just a nice-to-have; it's a whole privacy story.

Today I leaned into making that canvas feel like an actual photo booth instead of a file picker. There's now a live front camera that opens right in the page and mirrors you like a selfie cam (So raising your left hand raises the left hand on screen. It’s a small thing, but weirdly important), with upload still there as a fallback for desktop or locked-down cameras. And lining the photo up is now a proper gesture: one finger to drag, two fingers to pinch-zoom, a slider for fine control, and the scroll wheel on a desktop. None of that changes the privacy story – it's all still just math on a canvas that never leaves the phone.

Once I saw it work, the concept of client-side compositing went from a phrase I would've nodded along to into something I could actually explain to someone else. That's the test, right?

Decision Three: A Backend That Doesn't Need A Server

Here's where I almost made a beginner mistake, and the conversation saved me.

My plan was to just commit the frame images into the repo. Easy! Except the person uploading frames won't always be me, might be non-technical, and absolutely should not have to learn git commit to put a PNG online before an event. So we needed a real "organizers upload frames, attendees see them" flow…which sounds like it requires a backend and sounds like it kills my lovely static site.

The thing that unlocked it: Supabase, called directly from the browser with a publishable key and access rules. Frames live in a Supabase Storage bucket. Anyone can read them (so attendees see the frame options); only a signed-in organizer can add or remove them. The whole thing is enforced by storage policies, which look like this:

-- Anyone can view/list the frames (so attendees see them)
create policy "Anyone can view frames"
  on storage.objects for select to public
  using ( bucket_id = 'frames' );

-- Only signed-in organizers can add frames
create policy "Organizers can upload frames"
  on storage.objects for insert to authenticated
  with check ( bucket_id = 'frames' );

Understanding that "static site" and "has a backend" aren't opposites was a real moment of clarity for me. The site stays a single file on GitHub Pages (there are no serverless functions of my own) and the database does the heavy lifting over the network. The publishable key is meant to be in the client; the actual security lives in those policies, not in hiding a string. Understanding that distinction (public key in the file = fine; database password in the file = never, ever) felt like leveling up.

I also turned off public sign-up entirely. Organizer accounts get created from the Supabase dashboard, so there's no "anyone can register and start deleting frames" hole, and no single person who's permanently the only one with the keys.

One more reliability detail I'm glad we added: the Supabase client loads from a CDN, and the page is written to degrade gracefully if that script doesn't load. If the network has a bad day, the booth still opens, the camera still works, and you just don't get the cloud frames. "Fails into something usable" is the bar for anything running at an event.

The Part Nobody Warns You About: The Boring Footguns

Vibe coding is great at architecture. It's also great at the small operational stuff I would never have thought to ask about, and which would have absolutely wrecked me live.

Two that I'm now never going to forget:

  1. Free Supabase projects go to sleep after about a week of inactivity. A photo booth that's been quiet since the last event will be paused, and you'll find out about it in front of a line of people. The fix is dumb and important: open the dashboard the day before any event and wake it up.
  2. Cross-origin images can silently "taint" a canvas and make the saved photo come out blank. Because the frames now load from Supabase (a different origin than the page), pulling one onto the canvas and then exporting it can trip a browser security rule. The one-line fix, which Claude helped me wire in yesterday, is to request remote frame images with crossOrigin = "anonymous" so the canvas stays exportable. I would never have guessed that on my own; it's exactly the kind of thing that works perfectly with local files and then breaks the moment real cloud frames show up.

Neither of these is glamorous. Both are the kind of thing that separates "it works on my laptop" from "it worked at the event." I wouldn't have known to care.

Saving The Photo: Download Vs. The Share Sheet

This was the change I was most surprised mattered to me. Originally the finished image just downloaded as a file, which is fine on a laptop but inconvenient on a phone, where a "download" disappears into some Files app limbo and isn't obviously in your photos.

So now the save button is smarter about where it's running. On a phone, it hands the PNG to the native share sheet (navigator.share with the file), which is the sheet that already has "Save Image" / "Add to Photos" plus Instagram, Messages, AirDrop, and everything else. The photo lands in the camera roll, or goes straight to a story, in one tap. On desktop — where that share sheet doesn't exist — it falls back to the plain download. If someone opens the share sheet and then cancels, it just quietly does nothing instead of double-saving.

The lesson I keep relearning: "make a file" and "give a person their photo in the place they expect it" are different problems, and the second one is the one that actually matters at an event.

The change we made in the code

Making The Tool Actually Feel Like MLH

A tool that looks like a default Bootstrap page undercuts the whole "official event booth" vibe I wanted. So the design leans into the real MLH palette (red #E73727, navy #122F4C, yellow #F8B92A) with a narrow red/navy/yellow tricolor bar under the header as a signature accent. Display type is Space Grotesk, body is Inter, both from Google Fonts.

Screenshot of MLH branded photobooth

There was a nice little development trick here too. Early on I had Claude generate a few built-in sample frames in code (a DEFAULT_FRAMES array) so the picker was never empty while I was testing and demoing. Today, now that the real "frames come from Supabase" flow works, I cleared that array out. The picker will only show actual event frames, and when none are uploaded yet it shows a friendly "no frames yet" message instead of nothing. Scaffolding that you delete once the real thing works is a pattern I want to remember.

(Note to self, and to anyone copying this: confirm logo usage against the actual brand guidelines before anything goes properly public. Using a logo and using it correctly are different tasks.)

Deploying, And The Surprisingly Nice PR Loop

Deployment was almost anticlimactic, which is the goal. Public repo, drop index.html at the root, flip on GitHub Pages from the branch, and a live URL appears at https://<username>.github.io/<repo>/. All of which, Claude walked me through.

The part that genuinely changed how I think about maintaining a project: I can keep editing it through Claude Code on the web, connected to the repo over GitHub. I describe a change in plain English like, "remove the three sample frames and make the picker show a friendly message when there are none,” and it opens a pull request. I review it, I merge it, and merging auto-redeploys Pages.

That review step matters. It's not "AI changes my live site." It's "AI drafts a change, I read the diff, and I decide." For someone like me, that's the perfect amount of training wheels: I'm still the one accountable for what ships, but I'm reading real diffs instead of staring at a blank file.

So is Vibe Coding "Real"?

Here's my honest take after my first one.

Vibe coding did not mean I didn't understand my project. If anything I understand this tool better than things I've tried to build before, even when I was trying to customize my LiveJournal profile page, because every decision came with a why I had to evaluate, instead of a copy-paste I never questioned. The split that worked for me: Claude handled the syntax, the boilerplate, and the operational gotchas; I handled the constraints, the tradeoffs, and the final call.

What I'd tell past-me, one week ago, staring at the empty repo:

  • Pick something with hard boundaries. "Photo booth that downloads a PNG" is a real finish line. "A social app" is not.
  • Make the AI explain the why, not just hand you code. The reasoning is the part you keep.
  • Read the diffs. Merge the diffs. Own the diffs.
  • Write down the boring operational stuff (the sleeping database, the cross-origin thing) the moment you learn it, because you will not remember it at 8am before an event.

It's one static file, a public key, and some storage rules. It is also the first thing I've made that someone I've never met can open, use, and walk away from with something they wanted. That feels like a real line crossed, and I crossed it faster, and with a better understanding, because I had a very fast, very patient pair to argue with. And ask around MLH because I’ve been grinning about my success for days. (Everyone has been very excited for me too.)

Next up is mostly content, not code: loading the real designed frames, provisioning organizer accounts in Supabase for whoever's running the next event and remembering to wake the database up the night before. The plumbing is in. Now I just need an event to take it to.

See the tool in action here: https://bookoisseur.github.io/EventPhotoSharing/

FAQ

What is vibe coding?
Vibe coding is building software by describing what you want in plain English and letting an AI like Claude write the actual code. You stay in charge of the decisions — the constraints, the tradeoffs, the final call — while the AI handles the syntax and boilerplate. It's less "AI builds it for you" and more "you have a very fast, very patient pair to argue with."

Can you really build a web app if you can't code?
Yes. I write words for a living, not code, and I built a working photo booth that strangers can open and use. You don't need to know how to write the code, but you do need to understand the decisions well enough to say yes or no to them. That part you can't outsource.

Do you need to know how to code to use Claude for a project like this?
No, but it helps to be willing to learn why. I didn't write the JavaScript, but I made Claude explain every architectural choice so I could evaluate whether the reasoning was sound. The reasoning is the part you keep; the syntax is the part the AI handles.

What did you actually build?
A browser-based photo booth for events: an attendee opens a link on their phone, takes a selfie or uploads a photo, drops a branded event frame over it, lines it up, and saves a square PNG to their camera roll. No app to download, no account to make. It's one self-contained HTML file with a Supabase backend, hosted free on GitHub Pages.

What tools did you use?
Claude (for the vibe coding), a single static index.html file for the whole front end, Supabase for the backend that lets organizers upload frames, and GitHub Pages for free hosting. Ongoing edits happen through Claude Code on the web, which opens a pull request I review and merge.

How do you pick a good first vibe-coding project?
Pick something with hard boundaries. "A photo booth that saves a PNG" is a real finish line you can actually reach. "A social app" is not — it has no edge, so you never feel done. A small, concrete problem is the best possible first project.

How much does it cost to build something like this?
Nothing, for a project this size. GitHub Pages hosting is free, and Supabase has a free tier that's plenty for serving small frame images. The one catch: a free Supabase project goes to sleep after about a week of inactivity, so you wake it up the day before you need it.

Is the photo private — does it get uploaded anywhere?
The photo never leaves the device. The selfie and the frame are combined right in the browser on an HTML canvas, and the finished image is exported locally. For an event full of people who didn't sign up for anything, that's the whole point.

Can a static site really have a backend?
Yes — "static site" and "has a backend" aren't opposites. The page stays a single file with no server of its own, and Supabase is called directly from the browser using a publishable key plus access rules. The security lives in those rules, not in hiding the key.