今日已更新 188 条资讯 | 累计 24145 条内容
关于我们

标签:#Productivity

找到 702 篇相关文章

AI 资讯

Your AI coding agent forgets everything every session. I fixed it with markdown and YAML.

Every time I opened a fresh session with my coding agent, it started from zero. Which repos am I working across? Which client is this for? Where did we leave off yesterday? I'd re-explain the same context, the agent would occasionally load the wrong project, and nothing I decided last week survived into this one. A "re-explain myself" tax on every single session. I tried the obvious fix first — a better prompt, a longer system message. It didn't hold. Context that has to persist can't live inside the chat; the chat is the thing that resets. What actually worked: give the agent a place outside the chat to read and write — and make it the most boring, durable thing I could. Plain files in a git repo. The substrate: markdown + YAML the agent reads at session start open-bridge is a plain git repo of markdown and YAML. At the start of every session the agent reads it, so it begins already knowing my world. No database, no SaaS, no daemon, nothing to host — the substrate itself runs nothing . It's just files the agent reads. That "just files" choice is the whole point: Agents can read a file but can't hold an API key. What I write today, the agent still reads in six months — no migration, no second app, no vendor lock-in. It's auditable. Clone it and cat anything the agent reads. No black box. It's model- and tool-agnostic. Plain text is something every agent runtime can read. A tiny slice of what that looks like (from the repo's examples/agency setup — fictional "Acme Dev"): # ecosystem.yaml — the repos/clients the agent should know about projects : bigcorp : { display_name : " BigCorp E-Commerce" , repos : [ bigcorp-api , bigcorp-frontend ] } startupxyz : { display_name : " StartupXYZ MVP" , repos : [ startupxyz-app ] } # work/board.md — generated from the task dirs, read every session ## Doing | bigcorp-api-payment-retry | incident | P1 | Stripe webhook retries failing | | startupxyz-onboarding | feature | P2 | guided signup flow | So when I say "good morning, briefing

2026-06-23 原文 →
AI 资讯

Find meeting times with the Nylas Availability API

"What time works for everyone?" is a surprisingly hard question to answer in code. You have to read each person's calendar, line up the busy blocks, respect working hours and time zones, leave buffer time between meetings, and only then find the gaps everyone shares. The Nylas Availability API does all of that in one request: hand it a list of participants and a window, and it returns the time slots that actually work. This post covers finding meeting times from two angles: the HTTP API for your backend, and the nylas CLI for the terminal. I work on the CLI, so the terminal commands below are the ones I reach for when I'm checking a calendar. Availability versus Free/Busy There are two endpoints here, and picking the right one saves you work. The Availability endpoint finds bookable slots across a group of participants, applying working hours, buffers, and meeting duration to return times you can actually book. Free/Busy is simpler: it returns the raw busy blocks for one or more email addresses over a window, leaving the slot math to you. Reach for Availability when the question is "when can these people meet?" and you want the answer as a list of open slots. Reach for Free/Busy when you only need to see when calendars are busy, for example to gray out times in a custom UI. Availability is a POST /v3/calendars/availability , an application-level call that takes participants by email, while Free/Busy is grant-scoped at POST /v3/grants/{grant_id}/calendars/free-busy . This post focuses on Availability, since that's the one that answers the scheduling question directly. Find a time across participants The core request lists the participants and the window to search. Each participant is identified by email and must be associated with a valid Nylas grant, since the endpoint reads their calendars. You set start_time and end_time as Unix timestamps for the search window, duration_minutes for how long the meeting is, and interval_minutes for how the candidate start times ar

2026-06-23 原文 →
AI 资讯

Send and download email attachments with Nylas

Email is how most files still move between people: the signed contract, the PDF invoice, the logo embedded in a newsletter. If your app sends or processes mail, it has to handle attachments, and doing that against each provider means Gmail's attachment encoding, Microsoft Graph's, and raw MIME for IMAP. The Nylas Email API gives you one model for both directions: attach files to outbound messages with the same call you use to send, and pull files off inbound messages with a read-only Attachments API. This post covers both halves from two angles: the HTTP API for your backend, and the nylas CLI for the terminal. I work on the CLI, so the terminal commands below are the ones I reach for when I'm checking a file came through. Two APIs: one to attach, one to read There's a split worth understanding up front. You add attachments through the Messages or Drafts API, as part of sending or saving a message, and you read existing attachments through the dedicated Attachments API. The Attachments API is read-only: it downloads bytes and returns metadata, but it never adds files. That division keeps the model simple, since attaching is part of composing a message and reading is a separate concern. The size of what you're attaching decides how you encode it on the way out. Small files ride inline in the JSON request, larger ones move to a multipart request, and very large files use a separate upload step. On the way in, every attachment, regardless of how it was sent, is fetched the same way: by its attachment_id together with the message_id it belongs to. Get those two ideas straight and the rest is mechanical. Attach a small file inline with Base64 For files that keep the whole request under 3 MB, the simplest path is the application/json schema. You pass each attachment in an attachments array with its content_type , filename , and the file bytes as a Base64-encoded content string. The 3 MB ceiling covers the entire HTTP request, not just the file, so it's the right path for

2026-06-23 原文 →
开发者

26 Free Online Developer Tools — No Signup, No Install (2026)

Most "free developer tools" lists link to GitHub repos you need Node.js to run locally, or SaaS products with a login wall. Everything below runs in a browser tab, handles your data client-side or deletes it from the server within 30 minutes, and requires no account of any kind. All 26 tools are at at-use.com . Grouped by what you are actually trying to do. Encoding & Decoding Base64 Encoder/Decoder — Encode text or binary to Base64, or decode it back. UTF-8 text and binary file payloads both work. Runs in your browser — nothing sent to a server. URL Encoder/Decoder — Percent-encode strings for safe URL inclusion, or decode percent-encoded URLs back to readable text. Handles both application/x-www-form-urlencoded and RFC 3986 encoding modes. HTML Entity Encoder/Decoder — Convert special characters to named HTML entities ( < → &lt; , & → &amp; ) or decode entities back to characters. Useful when building template strings or sanitizing output for display. Binary Translator — Text to binary, binary to text, or translate between binary, decimal, hex, and octal. Useful for low-level debugging and learning number representations. Number Base Converter — Convert integers between binary (base 2), octal (base 8), decimal (base 10), and hexadecimal (base 16). All four outputs shown simultaneously. JWT Decoder — Paste a JWT token to decode and inspect the header and payload. Runs entirely in the browser — your token never leaves your machine. JSON & Text JSON Formatter & Validator — Format, validate, and minify JSON in one click. Toggle between pretty-print and compact output. Syntax errors include the exact line and column number. Uses browser-native JSON.parse() — no data sent anywhere. Text Diff — Side-by-side text comparison with no character limit (diffchecker.com caps at 25,000 characters on the free tier). JSON-aware mode auto-formats both inputs before diffing so whitespace differences do not pollute the output. Case Converter — 12 text case

2026-06-23 原文 →
AI 资讯

Why Your Ubuntu Laptop Lags, and How to Fix It for Free

My main work laptop is a Dell from 2017 with 8 GB of RAM. For weeks it had been crawling, freezing for whole seconds while I worked, and every so often it would simply switch itself off in the middle of a task. If you have ever lost unsaved work to a laptop that powers down on its own, you know exactly how frustrating that is. So I sat down and fixed it properly. The first thing I learned is worth saying up front: a slow, crashing laptop is usually two different problems wearing the same costume . Treat them as one and you will chase your tail. Separate them, and both become fixable. Everything below is free and copy-paste ready. It was tested on Ubuntu 24.04 LTS, and it applies to almost any older Linux machine. The honest disclaimer: Nobody can promise an old laptop will never lag. Software cannot add cores or memory that are not physically there. But you can absolutely stop the freezes and shutdowns completely and make everyday work feel smooth. That is the realistic, achievable goal. 0. Diagnose first, do not guess The biggest mistake is blindly applying "speed up Ubuntu" tweaks before knowing what is actually wrong. Spend five minutes measuring. Your lag has one of four common causes: heat, memory, disk, or a dying battery . Check temperature (the usual cause of random shutdowns): sudo apt install lm-sensors -y sudo sensors-detect --auto sensors Watch the Core temperatures while you work. If they spike past 90 to 100 °C right before a crash, you have a thermal problem, not a software one. Check memory (the usual cause of freezing): free -h sudo apt install htop -y htop In htop , watch the Mem and Swp bars during normal use. If memory pins near your limit and swap fills up, that thrashing is your freeze. Check disk space (a quiet killer): df -h / A root partition above 90% full makes Linux lag and turn unstable. Small SSDs fill up fast. Read the crash logs and battery health: # What went wrong during the previous (crashed) session journalctl -b -1 -p err --no-pa

2026-06-23 原文 →
AI 资讯

Manage email drafts with the Nylas API and CLI

Sometimes an email shouldn't go out the instant your code runs. A human needs to review it first, or the user wants to compose now and hit send later, or an AI agent proposes a reply that a person approves before it ships. The mechanism for all three is the same: a draft. Build that against providers directly and you're juggling Gmail's draft resource, Microsoft Graph's, and an IMAP APPEND to the Drafts folder, each with its own shape and quirks. The Nylas Email API collapses that into one draft resource. You create a draft on the user's account, it lands in their real Drafts folder, and you send it later with a single request, the same way across Gmail, Microsoft 365, Yahoo, iCloud, IMAP, and Exchange. This post walks the full draft lifecycle from two angles: the HTTP API for your backend, and the nylas CLI for the terminal. I work on the CLI, so the terminal commands below are the ones I reach for. One draft resource across every provider A draft in the Nylas model is a real object in the user's mailbox, not a staging area on the side. When you create one, it saves to the user's own Drafts folder on their provider, so it shows up in their normal mail client exactly like a draft they started themselves. That's the property that makes drafts useful for review workflows: a person can open the mailbox and see the pending message before it sends. Because drafts are real provider objects, edits flow both ways. A draft you create through the API appears in the user's mail client within the provider's sync window, and a change the user makes there alters the same draft you'd fetch back through the API. The operations split across two paths: create and list live on /v3/grants/{grant_id}/drafts , while fetch, update, send, and delete act on a specific draft at /v3/grants/{grant_id}/drafts/{draft_id} . They behave the same across all six providers, so you write the integration once. Create a draft Creating a draft is a POST /v3/grants/{grant_id}/drafts with the same message

2026-06-23 原文 →
AI 资讯

SQL Formatter: a data tool that earns its tab

Developers inheriting sprawling SQL codebases or revisiting queries from weeks earlier know the frustration: a dense, unformatted block that obscures joins, filters, and logical flow. Readable SQL isn’t cosmetic — it directly affects debugging speed, peer review accuracy, and long-term maintainability. What it is SQL Formatter restructures raw SQL into clear, conventionally formatted code, running entirely in the browser. It applies consistent indentation, capitalisation of keywords, and logical line breaks — all without altering the query’s semantics. The formatter understands the syntax of all major database engines, including PostgreSQL, MySQL, SQL Server, and Oracle, so it preserves dialect-specific functions and operators rather than flattening them into a generic style. The tool is one of 200+ free browser utilities on DevTools. It processes all input entirely on your machine — no data ever leaves the browser, no account is required, and no analytics track your usage. That privacy-first design means you can safely format queries that contain proprietary business logic embedded in production SQL. The engine handles the full spectrum of SQL complexity: basic SELECT statements, multi-table joins, Common Table Expressions (CTEs), correlated subqueries, window functions, and DML operations like INSERT or UPDATE . Because it parses the input rather than applying regular expressions, deeply nested constructs retain their hierarchy, with each subquery or CTE level indented to show ownership. How to use it Paste any SQL fragment into the left-hand editor and the formatted result appears instantly in the output panel. A live preview updates as you switch formatting options, so you can tune the output without re-pasting. The primary configuration controls help you match your team’s conventions or personal preference: Dialect : selecting a specific database ensures that functions such as PostgreSQL’s STRING_AGG or MySQL’s GROUP_CONCAT are not inadvertently mangled, and th

2026-06-23 原文 →
AI 资讯

Tired of Searching for Different Base64 Tools? I Built One Place for Everything

As developers, we've all been there. Q: Need to decode a Base64 string? Open one website. Q: Need to convert an image to Base64? Open another website. Q: Need to validate a Base64 string? Search Google again. Q: Need to compare two Base64 values? Yet another tool. I found myself repeatedly switching between different websites, browser tabs, and terminal commands just to perform simple Base64-related tasks. So I decided to build something that solved this problem for me. The Goal Keep every commonly used Base64 utility in one place and make it work directly in the browser. No installations. No command-line knowledge required. No account creation. Just open the website and use the tool What You'll Find Instead of only providing an encoder and decoder, I wanted to cover the complete Base64 workflow. Some of the available tools include: Base64 Encode / Decode Image to Base64 Audio to Base64 Video to Base64 Base64 Validator Base64 Detector Base64 Compare Base64 Repair Base64 URL Encode Base64 File Decoder CSS Data URI Converter And more are being added regularly. Why I Built It Honestly, this started as a personal productivity project. I was using different Base64 tools almost every week and got tired of bookmarking multiple websites for related tasks. Having everything in one place turned out to be surprisingly useful, so I decided to make it public. Give It a Try https://base64converters.com I'm continuously improving it and would love feedback from fellow developers. Are there any Base64-related tools or workflows you use frequently that should be included?

2026-06-23 原文 →
AI 资讯

Why I Log response.model on Every Claude Call (and You Should Too)

It is a one-line habit that has saved me more debugging time than any clever abstraction: I log which model actually answered every Claude request. Not which model I asked for. Which one responded. In 2026, with model fallbacks, fast-changing model strings, and routing logic, those are not always the same thing. Here is why the gap exists and what it has caught. The request model and the response model can differ You send model: "claude-fable-5" . You assume Fable 5 answered. But the response object tells you what actually served the request: const response = await client . messages . create ({ model : " claude-fable-5 " , max_tokens : 16000 , thinking : { type : " adaptive " }, messages : [{ role : " user " , content : prompt }], }); console . log ( " requested fable-5, served: " , response . model ); Most of the time they match. The interesting cases are when they do not. The Fable 5 safeguard fallback The reason this matters most in 2026 is Fable 5's safeguards. Fable 5 has hard guardrails in cybersecurity, biology, chemistry, and health. If your prompt trips one, the request does not just refuse. It silently falls back to Opus 4.8 to produce a safe answer. For my security work, this is a sharp edge. I run contract-analysis prompts that can look adversarial to a safeguard. If one trips, I am quietly getting Opus 4.8 output while believing I am getting Fable-tier reasoning. The quality difference on a hard audit is exactly the thing I paid double for, and it vanished without an error. The only way to know is to read response.model : if ( ! response . model . startsWith ( " claude-fable-5 " )) { logger . warn ( { requested : " claude-fable-5 " , served : response . model }, " Fable 5 request fell back, likely a safeguard trip " , ); } Without that log, a fallback is invisible until I notice the analysis got worse and have no idea why. Routing logic and config drift The other source of the gap is my own code. I have routing that picks a model based on task type and

2026-06-22 原文 →
AI 资讯

I built 128 things with AI in 4 months. Then I made an AI dissect all of it.

I'm 19. In four months I built 128 projects with AI — 61 GitHub repos, 15 MCP servers, a 7-department agent OS, the works. I shipped 5 . Total stars: 6 . Revenue: $0 . That gap bothered me enough that I did the obvious-but-uncomfortable thing: I had an AI audit everything — every repo, every project folder, 4,239 build sessions, 244 memory notes — and pin it all like specimens in a cabinet. No flattery. Here's what the autopsy found. → The full interactive atlas: https://builder-archive.vercel.app/en The number that explains everything 128 built. 5 shipped. It's tempting to read that as a discipline problem. It isn't. The build velocity is real — I once shipped ~20 vertical SaaS in a single weekend on a shared Next.js + Drizzle + Stripe stack. The code works. The UIs are clean. The problem is the last mile . README writing, deployment, the final 10% that turns a repo into a thing a stranger can use — that's where almost everything died. Not ability. Execution. The AI put it in one line: "Can build anything. Finishes nothing." Strength and weakness are the same coin Here's the part I didn't want to see: the thing that makes me fast is the thing that kills me. Because I can build deep, I lose the stopping point. Because building is cheap, I start the next thing before finishing the last. The audit scored two skill axes: Build (design → implementation → automation): advanced Distribution (publish → ship → monetize): beginner Every problem I have lives in that asymmetry. It's not a motivation gap — total commits across repos: ~4,800. The effort is enormous. It just never crosses the finish line into something public. The hardest thing I made is the one I hid The audit flagged a buried asset: a GCC/ZATCA e-invoicing toolkit — Saudi Fatoora Phase 2, EN16931 + Peppol validation, secp256k1 signing, Go compiled to WASM. The single hardest, most verifiable piece of work I've done. It's been sitting in a private repo. That's the disease in one example: the more valuable the th

2026-06-22 原文 →
AI 资讯

How I Stopped Duplicating AI Skills Across Claude Code, Cursor, Codex, Gemini CLI, and Other Tools

Has anyone else ended up maintaining the same AI skill in multiple places? I use Claude Code, Codex, Cursor, Gemini CLI, Kimi, and several other AI tools. Over time, I accumulated a huge collection of skills and workflows. The annoying part wasn't creating them. It was keeping them synchronized. A skill would exist in one format for Claude Code, another for Cursor, another for Gemini, and so on. Eventually, I got tired of duplicating everything and built an open-source project called AI Omni Skills. The idea is to keep a single source of truth and generate the formats required by different AI tools. Now I update a skill once and regenerate whatever structure a specific tool expects. I'm curious: How are you managing skills today? Are you duplicating them across tools? What integrations would you want to see? Repo: https://github.com/moatazhamada/ai-omni-skills

2026-06-22 原文 →
AI 资讯

How to Reduced Load Time From 5 Seconds to 1 Second

The Problem: How Website Slow Performance Costs Businesses Revenue A slow website doesn't just frustrate users it actively costs businesses money. Every additional second of load time causes visitors to leave, damages your search engine rankings and directly reduces conversions. Research shows that pages taking 5 seconds to load have a bounce rate 75% higher than pages loading in 1 second. For e-commerce sites, this translates to thousands of dollars in lost sales monthly. Recently, we worked with a client experiencing exactly this problem. Their website averaged 5-second load times, resulting in high bounce rates, poor mobile performance and declining search visibility. They needed immediate action. The Initial Audit: Identifying Website Speed Bottlenecks Before implementing solutions, we performed a comprehensive website audit using industry-standard tools like Google PageSpeed Insights, GTmetrix and WebPageTest. Step 1: Image Optimization – The Biggest Win Images typically account for 50-80% of page weight. Optimizing images delivered the most dramatic performance improvements. What to do: Converted to Modern Formats – We converted all PNG and JPEG files to WebP format, which provides 25-35% better compression than traditional formats while maintaining visual quality. Aggressive Compression – Images were compressed using lossless and lossy techniques without perceptible quality loss to users. Implemented Lazy Loading – Below-the-fold images were set to load only when users scrolled near them, not on initial page load. Responsive Images – Different image sizes were served based on device screen size, so mobile users didn't download desktop-sized images. Step 2: Minifying and Deferring Code – Eliminating Render-Blocking Resources JavaScript and CSS files were creating significant render-blocking bottlenecks. What to do: Minified CSS and JavaScript – Removed unnecessary characters (spaces, comments, line breaks) from all CSS and JavaScript files. Removed Unused Code

2026-06-22 原文 →
AI 资讯

Diff Checker: a small tool that solves a specific problem

Code reviews, configuration changes, and debugging sessions demand precise understanding of what changed between two versions of text. Manual comparison of large blocks of code or configuration files is error-prone, and version control diffs don’t always provide a quick, focused view for sharing or verifying changes outside a repository. What it is Diff Checker is a browser-based text comparison tool that performs line-by-line analysis of two text blocks and highlights differences with color-coded visual indicators. It processes text entirely in the browser—part of the 200+ free tools on DevTools—meaning no data is uploaded or stored, a privacy‑first design. The interface uses a split‑pane layout: original text on the left, modified text on the right. As you paste or type, the comparison engine recalculates the diff in real time, marking added, removed, and changed segments so differences are immediately clear. Several configuration options tailor the analysis. Toggling whitespace sensitivity ignores differences in indentation or blank lines, useful when comparing code from teams with different formatting conventions. Case sensitivity can be turned off for text where capitalization inconsistencies are irrelevant. A swap button reverses the comparison direction with a single click, handy when the assignment of “original” and “modified” is accidentally reversed. How to use it Paste the original text into the left panel and the modified version into the right panel. The diff view updates instantly, so you don’t need to press a button to see changes. For code, the process is straightforward. Drop a baseline function on the left: function calculateTotal ( items ) { let total = 0 ; for ( let item of items ) { total += item . price ; } return total ; } And the updated version on the right: function calculateTotal ( items , taxRate = 0 ) { let total = 0 ; for ( let item of items ) { total += item . price * ( 1 + taxRate ); } return Math . round ( total * 100 ) / 100 ; } The

2026-06-22 原文 →
AI 资讯

Lorem Ipsum Generator: a small tool that solves a specific problem

Placeholder text is necessary scaffolding in web development, but ubiquitous Lorem ipsum can lead to design monotony and disconnect from project context. Developers building mockups, prototypes, or content-heavy interfaces often need filler text that matches the tone of the target application without introducing distracting Latin. What it is The Lorem Ipsum Generator is a browser-based tool that produces placeholder text in multiple styles, moving beyond classical Latin pseudo-text. It offers distinct variants: traditional Lorem ipsum, Hipster Ipsum with artisanal terminology, Corporate Speak filled with business jargon, and Pirate Ipsum with nautical themes. Each style maintains readability while providing vocabulary that aligns with the spirit of a given project. The generator is part of DevTools, a privacy-first collection of 200+ free browser tools where all processing happens locally—no signup, no tracking. Developers can configure generation parameters to specify the number of paragraphs, total word count, and whether to start with the familiar “Lorem ipsum dolor sit amet” opening. The output is plain text ready for pasting into HTML, design files, or CMS entries. How to use it The interface is a straightforward form: select a text style from the dropdown, then set the number of paragraphs or words you need. The tool generates the text instantly and provides a one-click copy button. <!-- Example output structure when pasting into HTML --> <div class= "content-area" > <p> Leverage agile frameworks to provide a robust synopsis for high level overviews... </p> <p> Iterative approaches to corporate strategy foster collaborative thinking... </p> </div> For typical workflows, 1–3 paragraphs suffice for article previews or body content. Headlines work well with 5–15 words, while navigation elements often need only 2–5 words. The quick copy functionality streamlines populating multiple content areas. Different styles suit different contexts: Corporate Speak makes busi

2026-06-22 原文 →
AI 资讯

The Principle of Least AI

Why AI Alternatives Matter AI is prone to problems affecting its output: hallucinations, incompleteness, inconsistency, and bias. AI usage is costly, and the popular free services might require expensive paid plans or downgrade to sponsored light versions at any time. Don't Hit Submit! Ethical issues aside, lazily using AI to often and too early won't make you a better coder or more creative. And AI companies don't only take your money, they're also after your data – and your time! Techniques like Rubber Duck Debugging (internal dialog development preparing questions and anticipating answers without actually asking anyone) are alternatives to AI for coding and creativity. Don't Ask Suggestive Questions If your question implies a certain answer, asking only makes sense for falsification. AI (and other people) will hopefully tell you when you're completely wrong. Only that AI often doesn't. Current models are trained for flattery and verbosity. Don't Ask Why What a waste of time! Try to ask open questions, and always prefer asking "how", not "why". Stay Skeptical Don't believe anything without a factful proof or a recent, reputable, relevant source. GEO, the AI-agent-targeting variant of search engine optimization, already succeeded to gaslight AI and poison its answers with fake sources biased towards commercial results. AI seems much more gullible than real people. Source: The Shape of Enshittification: Books That No Longer Get Read, An Internet That No Longer Gets Surfed, & The End of Social Media As We Know It.. Principle of Least Power Remember the rule of least power : don't rent a truck when you need a mini van. Don't use AI when you need autocomplete, web search, or a tutorial! I sketched a pyramid of thinking, creativity, and information retrieval again. As you can guess, AI assistants are "on top" as the most costly exception, while the broad basis should be traditional groundwork. Here's a cute AI-slop adaption: Source: Hand-Crafted Creative Counter-Culture

2026-06-22 原文 →
AI 资讯

Browser Scroll Restoration Is Broken on SPAs. Here's How a Chrome Extension Fixes It.

Chrome has had scroll restoration support since 2015. You can even control it: history.scrollRestoration = 'manual' . But if you've ever tried to reliably restore a user's position on a React or Next.js app, you know it doesn't work the way you'd expect. Here's what breaks, why it breaks, and how a browser extension can sidestep the entire problem. What the Browser Actually Does The default behavior is history.scrollRestoration = 'auto' . When you navigate back to a page, the browser tries to scroll to where you were. This works fine for static pages. It falls apart for: SPAs where content is injected into the DOM after navigation Infinite scroll pages where the content at a given Y position changes depending on what was previously loaded Lazy-loaded images that push content down after the scroll restore fires The fundamental problem: the browser fires scroll restoration when the page HTML is parsed, not when the page content is fully rendered. A React app that loads a skeleton → fetches data → renders actual content will restore scroll into a partially-rendered DOM. The history.scrollRestoration = 'manual' Trap If you set manual , you own scroll restoration completely. Most Next.js apps do this. The typical approach: // Save position before navigation router . beforeEach (( to , from ) => { savedPositions [ from . path ] = window . scrollY ; }); // Restore after navigation router . afterEach (( to ) => { const position = savedPositions [ to . path ]; if ( position !== undefined ) { nextTick (() => window . scrollTo ( 0 , position )); } }); The nextTick is the problem. It fires after the Vue/React render cycle, but before async data fetching completes. The page renders empty containers, scroll restores to Y=800, then data loads and pushes everything down. User ends up at Y=800 in a now-different page position. The correct fix is to wait until the content that was at Y=800 actually exists. There's no clean hook for this — you'd need to observe the DOM until the expec

2026-06-22 原文 →
AI 资讯

Why I Chose DeepSeek Over GPT-4 for a Free AI Conversation App

I did not choose DeepSeek because I think GPT-4 is bad. I chose it because I was building a free app, and free apps teach you what actually matters pretty fast. The question was simple: how do I keep sessions cheap enough that people can practice a lot without me lighting money on fire? The answer pushed me toward DeepSeek-V3 (and later R1 for specific tasks). The real constraint was volume The app is a conversation practice tool. People come in to rehearse hard talks, not to admire the model. A single practice session runs 8-15 turns. Each turn is roughly 300-600 tokens in, 100-300 out. Multiply that by five sessions a week per active user and the costs start compounding. Here is what the math looked like when I was choosing (mid-2026 pricing): Model Input cost (per 1M tokens) Output cost (per 1M tokens) Cost per 10-turn session (est.) GPT-4o $2.50 $10.00 ~$0.04-0.06 GPT-4 Turbo $10.00 $30.00 ~$0.12-0.18 DeepSeek-V3 $0.27 $1.10 ~$0.004-0.007 DeepSeek-R1 $0.55 $2.19 ~$0.008-0.012 At scale, the difference between $0.005 and $0.05 per session is the difference between running a free product and needing a paywall after three conversations. I wanted people to come back daily without hitting a wall. What DeepSeek handled well It stayed in character for 10-15 turns. It pushed back when the user got vague. It followed persona heuristics (numbered if/then rules in the system prompt) about as reliably as GPT-4o did for our use case. For salary negotiation rehearsal, the model needs to say "that's not in the budget" and hold that position for three more turns while the user tries different approaches. DeepSeek-V3 did this. Not perfectly, but reliably enough that sessions felt real. It also made the app easier to run as a free product. People can try, fail, reset, and try again without me worrying about per-session cost. Where GPT-4 was still better GPT-4 (and 4o) is smoother with nuanced emotional wording. When a conversation gets subtle, loaded with subtext, or requires pick

2026-06-22 原文 →