AI 资讯
I built two Next.js 15 + Tailwind v4 templates with zero extra dependencies — here's what I learned
Earlier this month I shipped two premium templates — a SaaS landing page and a developer portfolio. Not a startup, not a SaaS, just templates. This post is about the two constraints I built them under, why they made the code better, and a few things I learned launching as a solo dev with zero audience. Constraint 1: zero dependencies beyond next, react, and tailwind Open the package.json of most templates and you'll find 20+ packages: icon libraries, animation libraries, carousel plugins, UI kits, utility libraries. Every one of them is a version conflict waiting to happen for the buyer, and most are replaceable with a few lines of code in 2026. What I used instead: Icons → inline SVG components. An icon component is ~10 lines. You need maybe 15 icons for a landing page. Animations → plain CSS. Scroll-blur navbars, gradient glows, an animated "typing" terminal — all doable with keyframes and transitions. No framer-motion. The dashboard mockup in the hero → pure CSS. Divs, borders, gradients. It looks like a product screenshot but it's ~80 lines of JSX and weighs nothing. Result: both templates land at ~100KB first-load JS, npm install takes seconds, and there is nothing to break when Next.js 16 arrives. Constraint 2: every piece of content in ONE typed config file The thing I hated most about templates I've used: content is smeared across 30 components. Changing a headline means hunting through JSX. So both templates keep all content in a single file — lib/content.ts for the landing page, site.config.ts for the portfolio. Headlines, nav, pricing tiers, testimonials, project lists, even the lines that animate in the fake terminal. Components are pure renderers of that config's TypeScript type. Two things surprised me here: TypeScript becomes your content linter. Forget an alt text, malform a link, give a pricing tier three features when the type expects a non-empty array — the build fails. Content mistakes surface at compile time. It forces better component design. W
AI 资讯
I Love Fragrances, So I Built a 6-Game Arcade + Concierge About My Obsession
Hi, my name's Ibrahim, I'm a university student, and I have a problem: I love fragrances way more than my bank account loves me for it. It started small, the way these things always do. A cheap Middle Eastern attar someone gave me as a gift, the kind that costs less than a coffee but somehow smells like it belongs in a much fancier bottle. Then another. Then I started actually reading about notes, pyramids, accords, sillage, the whole rabbit hole. Fast forward through a lot of saved-up allowance and skipped nights out, and I've now got about 20 bottles on my shelf. Mostly affordable Middle Eastern gems (some of them genuinely punch way above their price), with a small handful of designer pieces I saved up for and treat like trophies. If you're a fellow fragrance enthusiast, you already know the feeling: you don't just "wear" a scent, you collect them, you study them, you have opinions about whether a note is top, heart, or base and you will absolutely fight someone about it. That obsession is basically the entire reason this project exists. So when I saw the DEV Weekend Challenge's "Passion" prompt, there was only one thing I could possibly build. What I built: recommendmeafragrance recommendmeafragrance is a browser arcade for fragrance nerds: six small daily games built around real perfume data (notes, brands, years, price tiers), plus an AI Concierge you can actually talk to about what you're in the mood for. Every game feeds into a personal "shelf" that tracks which fragrances you've discovered, plus streaks so you have a reason to come back tomorrow. Here's the tour. 🧪 Scentle: Wordle, but for your nose A new fragrance is picked every day (the same one for everyone, worldwide, no matter your timezone). You get 6 guesses, and after each one you get Wordle style feedback: was the brand exact or just the same house family, did the real answer come out earlier or later than your guess, is it pricier or cheaper, same gender, same concentration, how many notes do you
产品设计
The System Has Awakened: Turn Your Coding Journey Into a Solo Leveling RPG ⚔️
This is a submission for Weekend Challenge: Passion Edition What I Built This weekend, I...
产品设计
The System Has Awakened: Turn Your Coding Journey Into a Solo Leveling RPG ⚔️
This is a submission for Weekend Challenge: Passion Edition What I Built This weekend, I...
AI 资讯
Shipping Async Video Background Removal at $0.10/sec
Why async matters for video I've been running useKnockout - a background removal API that processes images in ~200ms - for a few months. Images are fast enough to handle synchronously: POST a file, wait 200ms, get a PNG back. Video is different. Even a 5-second clip at 30fps is 150 frames. At 200ms per frame, that's 30 seconds of processing. You can't hold an HTTP connection open for 30 seconds and call it a good API. So today I shipped POST /video/remove - async video background removal that returns a job ID immediately, processes in the background, and gives you ProRes 4444 (RGB+alpha) when it's done. What shipped As of v0.11.0 (July 10, 2026): POST /video/remove - upload a video, get a job ID back GET /jobs/{job_id} - poll for status, download the result when ready ProRes 4444 output - RGB with full alpha channel, ready to drop into Premiere/Final Cut/DaVinci Node SDK videoRemove() and getJob() in v0.7.0 Python SDK video_remove() and get_job() in v0.7.0 Billing is a dedicated video.seconds meter at $0.10/sec (different from the per-image rate), with a 15-second cap to keep costs predictable. How to use it (Node SDK) import { useKnockout } from ' useknockout-node ' ; import fs from ' fs ' ; const client = useKnockout ({ apiKey : process . env . KNOCKOUT_API_KEY }); // Submit the video const job = await client . videoRemove ({ file : fs . createReadStream ( ' ./input.mp4 ' ) }); console . log ( ' Job ID: ' , job . id ); // Poll until done let status = await client . getJob ( job . id ); while ( status . status === ' processing ' ) { await new Promise ( resolve => setTimeout ( resolve , 2000 )); status = await client . getJob ( job . id ); } if ( status . status === ' completed ' ) { // Download the ProRes 4444 result const video = await fetch ( status . result_url ); const buffer = await video . arrayBuffer (); fs . writeFileSync ( ' ./output.mov ' , Buffer . from ( buffer )); } The job object includes duration_seconds (billed amount), status ( processing / complet
AI 资讯
TrulyFreeOCR – a Java OCR pipeline in a single fat JAR, zero native deps required
Introduction I'm the author of TrulyFreeOCR, an open-source OCR pipeline that turns scanned PDFs into searchable, highly-compressed PDFs. Everything is Apache 2.0 / MIT / BSD — no GPL, no AGPL, no proprietary model weights. Why I built it: I needed an OCR pipeline for a document processing system where: Every dependency had to be business-friendly (no GPL/AGPL) Deployment required zero admin rights (no sudo, no brew, no apt-get) MRC compression was needed to hit 5-10x file size reduction vs JPEG-only Everything had to run offline on CPU — no cloud APIs, no GPU I surveyed 20+ existing tools (full comparison in the repo's docs) and none fit all requirements. OCRmyPDF is closest but needs Python + Ghostscript + Tesseract as system deps, and MPL-2.0 requires publishing modifications. The VLM models (DeepSeek-OCR, GLM-OCR, etc.) produce better text extraction but need GPUs and don't output PDFs at all. What it does: Input: any PDF (scanned, born-digital, or mixed) Output: searchable PDF with invisible text layer + MRC compression (JBIG2/CCITT foreground + JPEG background) Single fat JAR — one file to copy, one command to run Bootstrap script downloads everything (JDK, Gradle, Tesseract, Leptonica, jbig2enc) into project subdirs Fully offline, CPU-only PDF/A-2b output available 7 bundled language models, 100+ more downloadable Concurrent OCR (configurable thread pool) Try it in 3 commands: $ git clone https://github.com/msmarkgu/TrulyFreeOCR.git $ cd TrulyFreeOCR $ ./bootstrap.sh ./run.sh tests/simple-text.pdf -o output.pdf Limitations (being upfront): Tesseract-based accuracy — good for clean scans, not SOTA for noisy/photographed docs No table/formula extraction yet No handwriting recognition CPU-only is slower than GPU backends for high volume Would love feedback — especially from anyone who's tried to deploy OCR in an enterprise environment. https://github.com/msmarkgu/TrulyFreeOCR
AI 资讯
Stop Paying AWS Just to Test Your Code Locally
Every developer building on AWS eventually runs into the same frustrations: waiting for deployments just to verify a small change, needing an internet connection for local development, watching cloud costs grow during testing, and discovering issues in CI that could have been caught earlier. That's exactly why we built LocalEmu. LocalEmu is an open-source AWS emulator that lets you build and test against AWS APIs entirely on your own machine. It supports 132 AWS services and works with the tools you already use every day—AWS CLI, boto3, Terraform, AWS CDK, and Pulumi. Instead of changing your workflow, you simply point your tools to localhost:4566 and continue developing. Unlike many local emulators that only mock API responses, LocalEmu focuses on realistic behavior where it matters most. Lambda functions execute using the official AWS runtime images. EC2 instances run as real containers connected through a virtual network with enforced security groups. RDS uses real PostgreSQL and MySQL engines, and optional IAM policy enforcement allows you to validate authorization rules before deploying to AWS. Getting started takes only a couple of commands: pip install localemu [runtime] localemu start Once running, you can use the included awsemu CLI or simply point your existing AWS CLI, boto3, Terraform, CDK, or Pulumi configuration to localemu. No new SDKs or complex setup are required. LocalEmu also includes a built-in dashboard that launches automatically. It provides a live overview of running services, resource exploration, an S3 object browser, a DynamoDB viewer, CloudTrail event history, and a real-time activity feed so you can inspect what's happening inside your local cloud environment. The biggest advantage is speed. You can iterate in seconds instead of minutes, experiment freely, reset your environment whenever you want, and develop without an AWS account, credentials, or cloud costs for local testing. We're actively improving LocalEmu and would love feedback f
AI 资讯
I Got 9.9 Lower TTFT on a Real Android Phone by Reusing llama.cpp KV State
Local LLM inference has an expensive habit: It recomputes prefixes it has already seen. A system prompt. A reused RAG document. A few-shot block. A long static context. If the prefix is identical, why pay the prefill cost again? That's the problem I explored with EdgeSync-LLM. The idea The mechanism is simple: Prompt = shared prefix + new suffix On the first request, EdgeSync prefills the prefix and captures its KV cache state. On the next request sharing that exact prefix, it restores the state and decodes only the new suffix. No llama.cpp fork. No patch. The current validated path uses the public: llama_state_seq_get_data and llama_state_seq_set_data APIs. Measured on a real Android ARM64 phone Model: Qwen2.5-0.5B-Instruct Q4_K_M Shared prefix: 123 tokens 40 requests. 4 threads. Release build. Path Mean TTFT p50 p95 Cold 4828 ms 4752 ms 5297 ms KV state reuse 486 ms 476 ms 569 ms 9.9× lower TTFT on cache hits. The warm path was approximately: 363 ms to decode the 10-token suffix 123 ms to restore the state blob Fragment size: 1.64 MB I also measured the same mechanism on x86-64. Cold mean TTFT: 1395 ms Warm mean TTFT: 185 ms That's 7.5× on cache hits. But I almost published a fake 8.8× speedup This was the most important part of the project. My first implementation directly copied raw K/V tensors. It was fast. Very fast. The benchmark reported an 8.8× speedup. There was one problem. It was wrong. llama.cpp tracks more than the K/V tensor values. Cache cells also have position and sequence metadata used to construct the attention mask. Copying tensor values without restoring that bookkeeping produced an inert fragment. The model skipped prefix computation... ...but attention could not actually see the restored prefix. 14 of 24 cache hits reproduced, token for token, the output of a generation with no prefix at all. The “speedup” was dropped context. So I discarded it. Timing is not enough A broken cache can be fast. That's why EdgeSync now runs two correctness chec
AI 资讯
I got tired of GitHub deleting my traffic stats after 14 days, so I built a local-first alternative 🚀
Hey DEV community! 👋 If you maintain open-source projects on GitHub, you probably love checking your repository's "Insights" tab. Seeing people clone, view, and star your project is an amazing feeling. But there are two catches that have always frustrated me: The Tedious Click-Fest: To see how your projects are doing, you have to manually open GitHub in your browser, navigate to each repository individually, click "Insights", and then click "Traffic". If you maintain 5+ repos, this becomes a chore real quick. The 14-Day Limit: Even worse, GitHub only keeps your traffic data for exactly 14 days. If you don't check your stats within that window, that data is gone forever. If you want a unified view and historical data, you either have to manually scrape it yourself, write a cron job, or pay a monthly subscription for a third-party SaaS tool. I didn't want to do any of those. So, I built my own solution. 🌟 Enter: Repo-rter Repo-rter is a completely free, 100% open-source desktop application available for Windows, macOS, and Linux. It fetches your GitHub traffic data and caches it locally on your machine, meaning you never lose your historical stats again. TIP Privacy First: Unlike SaaS alternatives, Repo-rter doesn't store your Personal Access Token (PAT) on any server. Everything runs locally on your machine, so your data remains strictly yours. ✨ Key Features Infinite History: Automatically merges new traffic data with your local cache. Say goodbye to the 14-day limit! Release Downloads Tracker: Wondering how many people downloaded your .exe or .dmg? Repo-rter tracks total and individual asset downloads across all your releases. Neo-Brutalist UI: I wanted the app to be fun to use, so it features a vibrant, gamified Neo-Brutalist design. Export to Markdown: Need to show off your stats? Generate and download a beautiful Markdown report of your repo's health and traffic with one click. Cross-Platform: Built with Tauri, it's incredibly lightweight and runs natively on Wi
AI 资讯
Running a 120-site uptime monitor for $0/month on Cloudflare's free tier
I built a tool that answers one question: when a website won't load, is it your connection or the site? It runs two checks in parallel — measures your own line in the browser (latency + a 1 MiB download), and probes the target from Cloudflare's edge — then returns one of four verdicts: it's not you, it's you, it's both, or all clear. Demo: https://itsnotyou.site The interesting part isn't the tool, it's that the whole thing — app, ~120 monitored sites with 24h history, SSR status pages, share cards, outage alerts — runs for $0/month plus domains. The one thing that wanted to cost money Everything fit the Workers free plan except a background monitor probing ~120 sites on a tight cadence. As a Worker cron that's ~120 subrequests/run and, done naively, thousands of KV writes/day — which pushes you onto Workers Paid. The real ceiling is KV: 1,000 writes/day. So I split it. The user-facing test stays on Cloudflare — the edge probe still measures from the colo nearest the user, which is the point of edge. But the background sweep moved to a cheap VPS I already had: it probes the roster on a systemd timer and pushes results back into KV over the REST API. Staying under 1,000 KV writes/day One KV key, not key-per-site. All ~120 statuses live in a single blob. Key-per-site at sweep cadence would be millions of writes/month; a single blob is one write per sweep. Widen the cadence. I started at 2 min = 720 writes/day. Cloudflare emailed that I'd hit 50% of the daily limit (the sweep wasn't the only writer). I went to 3 min = 480/day, leaving headroom for share cards and the notify list. Move the hot counter off KV. The anonymous "tests today" counter was the sneaky risk — a traffic spike could exhaust the write budget and stall the status sweep, the one thing you can't let happen. It went to Analytics Engine instead (free, uncapped, separate budget). Now no amount of user traffic can starve the monitor. Reader and writer share code so their rules never drift: the streak/histo
AI 资讯
I Got Tired of Hunting for Free Online Tools. So I Built 1000+ of Them — All Client-Side, Zero Backend.
I Got Tired of Hunting for Free Online Tools. So I Built 1000+ of Them — All Client-Side, Zero Backend. Every time I needed a simple tool — format JSON, resize an image, generate a QR code — I'd open Google, search for a "free online tool," and land on some sketchy site with 47 pop-up ads, a 10MB file size limit, and a $9.99/month "premium" upgrade staring me in the face. Sound familiar? I knew there had to be a better way. So I built one. And then another. And... well, 1000+ tools later (1052 to be exact, across 2130+ bilingual pages), here we are. What started as a weekend project turned into an obsession: a completely free, ad-light, privacy-first toolbox that does everything in your browser. No uploads. No servers. No accounts. No BS. 🚀 The Self-Imposed Constraints The most interesting part? I gave myself some pretty extreme constraints: Constraint Why 100% static HTML/JS No server, no database, no build step $0 hosting GitHub Pages — literally free forever Works offline Everything runs client-side, so once loaded, it just works Bilingual Every tool has an English + Chinese version No frameworks Vanilla HTML, CSS, and JavaScript — no React, no Vue, no build tools SEO-first Every page has Schema.org structured data, OG tags, and sitemap integration Why these constraints? Because I wanted to prove that you can build something genuinely useful without any recurring costs, complex infrastructure, or venture capital. Just pure engineering. 🔧 The Architecture (If You Can Call It That) The whole thing is beautifully simple: webtools-cn.github.io/tools-site/ ├── index.html ← Homepage with category filtering ├── en/index.html ← English homepage ├── sitemap.xml ← Auto-generated, ~2130 URLs ├── llms.txt ← AI search optimization ├── [tool-name]/ ← Each tool is a standalone folder │ └── index.html ← Self-contained HTML + JS + CSS └── en/[tool-name]/ ← English version of each tool └── index.html Each tool is a completely standalone HTML file . No build process, no framework,
AI 资讯
I couldn't find how much heat my PC puts in the room, so I built a widget
I game in a room that warms up fast. I could see CPU usage in Task Manager and watts in HWiNFO if I went looking. What I actually wanted was simpler: How much heat is this machine putting into the air right now? Not in a spreadsheet. In plain language I could glance at while the PC was running. The gap Lots of tools show watts and temperatures . Almost none answer room heat : BTU per hour Heat accumulated over a session Plain context like "about a quarter of a space heater" With ambient temp: still-air rise or rough exhaust CFM The conversion is straightforward ( BTU/hr ≈ watts × 3.412 ), but I didn't want to do it in my head every time. So I built HeatLens — a small desktop widget built around room heat, not raw sensor dumps. What HeatLens shows Total wattage — what the PC is drawing now Heat dissipation — BTU/hr or kW Session heat — BTU or kWh since launch Max temperature — hottest live sensor Trend graphs — watts, heat, and temp over time CFM estimate — with ambient temp: rough exhaust airflow for a +10 °F rise Still-air rise — how fast a reference room would warm with no ventilation Estimated power is labeled separately from measured sensors. Where the data comes from LibreHardwareMonitor / Open Hardware Monitor (HTTP + WMI on Windows) nvidia-smi for NVIDIA GPUs Linux RAPL / hwmon when exposed by the kernel Labeled fallbacks when direct power sensors aren't available On Windows, best results: LibreHardwareMonitor with Remote Web Server on port 8085 . What it is not HeatLens is not a replacement for a Kill-A-Watt at the wall. Software usually can't see monitor power, full PSU loss, or every platform rail. A plug-in meter is still the most accurate whole-system reading. HeatLens is for context : "~400 W gaming → ~1,400 BTU/hr into the room" Session heat over an hour or two Rough CFM / still-air numbers as sanity checks — not duct design Things I learned building it Sensor coverage is messy. Different backends, missing rails, and estimates that need clear labeling.
AI 资讯
A Baby Growth Percentile Calculator Using WHO and CDC Reference Data
New parents obsess over percentile numbers. I get it. I built a tool that plots your baby measurements against official WHO and CDC growth standards. What it does: Weight, height, and head circumference percentiles for ages 0-36 months Visual growth chart showing where your baby falls on the curve Uses WHO Child Growth Standards (0-24 months) and CDC reference data (24-36 months) 35 pages, all pre-rendered for fast loading The hard part: Parsing the WHO growth standard tables into usable JSON. Those tables are dense and not designed for programmatic use. That took more time than building the actual calculator UI. ?? Try it: babypercent.com Built with Next.js, no database, no tracking. Just a calculator that respects your privacy.
AI 资讯
What I learned building an AI video background changer
Hey DEV community, I recently launched bgchanger.video , an AI video background changer for removing or replacing video backgrounds directly in the browser. The idea is simple: many creators, indie hackers, marketers, and product teams need cleaner videos, but traditional editing tools can feel too heavy for quick background cleanup. With bgchanger.video, you can: Upload a video Remove the original background Export with a transparent background Replace the background with a solid color Download the result in formats like MP4, WebM, MOV, MKV, or GIF Keep the original audio when needed I built it for quick workflows like: Product demo videos Social media clips Creator videos Ad creatives Cleaner profile or presentation videos Background cleanup before further editing The current version focuses on making the workflow straightforward: upload, configure, generate, download. I am still improving the product and would love feedback from other builders: Is the workflow clear enough? What export options would you expect? Would you prefer templates, custom background uploads, or batch processing? What would make this useful in your own video workflow? You can try it here: https://bgchanger.video Thanks for checking it out. Feedback is very welcome.
AI 资讯
I Got Tired of Maintaining Frontend Code. So I Built a Declarative UI Runtime.
Here is a question that sounds simple until you've actually shipped a UI: how many files does it take...
开发者
Introducing OrBit: A Local-First Workspace Synchronization Engine for Developers
As developers , we often face challenges keeping our workspaces perfectly synchronized across devices and collaborators. Whether it’s dealing with slow cloud sync, merge conflicts, or latency issues, these problems can disrupt our workflow and productivity. That’s why I’m excited to introduce OrBit , a local-first workspace synchronization engine designed to keep your development environments in sync with sub-millisecond latency — all while supporting offline work and peer-to-peer collaboration. What is OrBit ? OrBit is built around a multi-layered architecture that combines the power of Rust, Tauri, and VS Code to deliver a seamless synchronization experience: Rust-based local watcher daemon: Monitors file system changes with kernel-level events for ultra-low latency. Tauri-based native desktop dashboard: Provides a lightweight, secure, and cross-platform interface to manage your sync settings. VS Code extension: Integrates directly with your editor for smooth, real-time syncing of your code workspace. Unlike traditional cloud-based sync solutions, OrBit uses peer-to-peer connections and Conflict-free Replicated Data Types (CRDTs) to ensure your workspaces stay consistent even during network partitions or offline periods. Key Features Real-time sync with sub-millisecond latency: Changes propagate instantly across your devices. Offline support: Work uninterrupted without internet, with automatic merging when reconnected. Conflict resolution: CRDTs handle concurrent edits gracefully, preventing data loss. Native desktop and editor integration: Manage sync easily via the desktop app and VS Code extension. Peer-to-peer architecture: No heavy cloud servers required, enhancing privacy and speed. Why OrBit ? OrBit is designed for developers who demand speed, reliability, and seamless collaboration. It eliminates the frustration of slow syncs and merge conflicts, letting you focus on coding. Whether you’re working solo across multiple devices or collaborating with a team,
AI 资讯
The project file is the interface: letting AI agents drive a video editor
Last week I open sourced FableCut , a Premiere-style video editor that runs in the browser and that AI agents can operate. It hit the front page of Hacker News ( thread ), and the questions there made me realize the interesting part isn't the editor. It's one design decision: the project file is the interface. The usual way, and why I flipped it Most AI video tools hide the edit behind an API. You call addClip() , applyFilter() , and the tool owns the state. If you want a human to touch the result, you build a whole collaboration layer. FableCut does the opposite. The entire timeline lives in one JSON document, project.json : media, clips, tracks, keyframes, transitions, markers. The editor UI reads it. The export renders it. And anything that can write JSON can edit video: Claude Code through MCP, a Python script, jq , or you with a text editor. { "id" : "c_title" , "kind" : "text" , "track" : "V3" , "start" : 0 , "duration" : 2.2 , "props" : { "text" : "HANDMADE" , "font" : "Bebas Neue" , "glow" : 45 , "textAnim" : "letter-pop" } } That clip is a glowing kinetic caption. There is no API call that creates it. Writing it into the file IS creating it. SSE as a doorbell, not a data channel The first question on HN was "what's the benefit of SSE here?" Fair question, because the SSE channel does almost nothing, and that's the point. The server watches the project file with fs.watch , debounces 150ms, and pushes the literal string change to the browser. No payload. The browser re-fetches the project and re-renders. The whole mechanism is about 15 lines on a bare node:http server. Why not WebSockets? Because the data only flows one way. Everything that writes (the UI, an agent, a shell script) goes through REST or the filesystem. The browser only ever needs to hear "something changed, go look." An event with no payload can't arrive out of order, and a missed event costs nothing because the next fetch has the latest state anyway. The revision counter, or: how a human and
AI 资讯
Unboxable in Tech: The Evidence Locker
Eleven exhibits, last time. A career that kept refusing to fit inside a single box — trainer,...
AI 资讯
I replaced the chat window for my local AI agent with a face
I run a local LLM agent (Hermes) on my own machine. The problem was never the model — it was the interface . I had a Telegram tab open all day just to talk to it: type a command, wait, read a wall of text back, scroll. It felt like texting a very capable stranger. So I built Ghost Vessel — a monitor-resident, video-call-style avatar that fronts the agent. The name is the whole idea: the ghost is your agent, the vessel is the body it borrows. It's not a waifu toy; it's a real agent client that happens to have a face. Here's what actually turned out to be interesting to build. The reply is a script, not a string The core idea is an output contract . Instead of treating the agent's reply as text to print, I split every reply into three planes: dialogue → spoken via local TTS data → code, logs, files → rendered as chat cards, never read aloud action → emotion beats that drive the avatar Emotion beats are inline tags the model emits in-band with its answer: [working] — the avatar puts on glasses and takes notes while a task runs [confirm] deploy to prod? — pops a human-in-the-loop approve/cancel, and the agent blocks on your keypress [happy] / [concerned] / … — fine-grained facial expressions So "run the build, and if it passes, deploy" becomes a little performance : it looks busy while working, shows you the log as a card, then leans in and asks before the irreversible step. The text you'd have skim-read becomes something you glance at. No runtime GPU for the avatar The obvious way to animate a face is live inference. I didn't want that — the GPU is busy running the actual model. Instead the avatar is ~30 pre-rendered clips , and the emotion beats just select and blend between them (blink-aligned seamless idle loops, a head-pose "settle gate" so an expression only reveals when the head is frontal). The avatar's runtime cost is basically video playback. Your GPU stays 100% on your LLM. The tradeoff: no real-time lip-sync. I decided a believable talking mouth loop + expre
AI 资讯
I built on-device workout rep counting in Flutter — here's what actually worked
I'm building TrainWiz , a Flutter app that turns real exercise into a pet-raising game: you do squats or push-ups, your phone counts the reps, and a little creature levels up and evolves. The core technical problem sounds trivial and absolutely is not: count reps from the camera, on-device, without uploading a single frame. Here's what broke along the way, and what finally worked. Why on-device Two reasons: privacy and latency. A fitness camera that streams your body to a server is a non-starter for most people, and rep feedback has to feel instant or the whole "game" loop dies. So everything runs locally with tflite_flutter + an on-device pose model — no footage ever leaves the phone. Naive attempt #1: joint-angle thresholds The obvious approach: track the knee angle, count a rep when it dips below X° and comes back up. // looks fine in a demo, dies in the real world final kneeAngle = angleBetween ( hip , knee , ankle ); if ( ! _down && kneeAngle < 100 ) _down = true ; if ( _down && kneeAngle > 160 ) { reps ++ ; _down = false ; } It demos beautifully. Then real users prop the phone on the floor, stand at an angle, and it falls apart. The trap: a phone camera gives you 2D pose. A "120° knee angle" flattens completely depending on where the camera sits — the same squat reads as 90° or 150° purely from perspective. Lifting to 3D via the model's z doesn't save you either; monocular z is noisy enough that the angle jitters across your threshold and double-counts. Naive attempt #2: a "body-line" gate Next idea: figure out which exercise you're doing so I can pick the right signal. Standing (squat) vs. horizontal (push-up) should be easy — just check if shoulder, hip and heel form a straight line, right? Wrong, again for the 2D reason. In a real push-up shot from the front-corner, shoulder–hip–heel are not collinear on the image plane — perspective bends them. I gated push-up counting on "body is a straight line" and it would just... stop counting mid-set. Nothing is more