Designing a platformer where you don’t control jumping

We recently released a 2D precision platformer on Android, built around a simple question:

What happens if the player doesn’t control jumping?

In most platformers, jumping is the core mechanic. It’s reactive and immediate. You press a button, and you jump.

In Crom’s Escape, the character jumps automatically.

The player controls only movement, timing, and positioning.

Why remove jump control?

The idea was to shift the challenge away from reaction toward consistency.

Instead of asking:
“Did you press jump at the right moment?”

the game asks:
“Are you in the right position at the right time?”

What this changes

Removing manual jumping changes how levels are built:

  • Timing becomes predictable but unforgiving
  • Movement becomes the primary skill
  • Small mistakes are amplified

Levels are designed with very low tolerance for error, and failure usually happens quickly.

This is intentional.

Fast retries are part of the core loop.

What didn’t work

Early versions felt confusing rather than difficult.

Players tried to jump instinctively.

So the design had to clearly communicate:
“Jumping is not under your control.”

The result

The final result is a precision platformer that feels unusual at first but becomes predictable over time.

It’s not designed to be accessible or relaxing — it’s built around repetition and mastery.

Try it

Google Play:
https://play.google.com/store/apps/details?id=com.amphoteric.cromsescape.game

Trailer:
https://www.youtube.com/watch?v=TixJBd-r9Ck

We’d be curious how you approach gameplay constraints like this.

Meet Tobor: I Gave Our 40-Year-Old Family Robot a Local AI Brain with Gemma 4

Mirza Bekirovic

A three-generation project. A performance robot. A mindfulness guru running entirely offline.

This is a submission for the Gemma 4 Challenge: Build with Gemma 4

TL;DR — I gave my family’s 40-year-old robot a brain using Gemma 4 E2B running locally on a Raspberry Pi 5. He now generates personalized mindfulness meditations based on visitors’ voices, fully offline, at festivals with no WiFi. Try the open-source demo →

In the 1980s, my father started building a robot to teach me electronics. He never finished it.

Forty years later, my son and I completed it together.

His name is Tobor. He dances, talks, leads guided meditations, and — his signature move — scans audience members through a wearable “learning hat,” absorbs their voice and interests, and then delivers a workshop in their exact style. At the end, he always claims he is a better version of the person he just absorbed.

What I Built

Mirza Bekirovic's handwritten robot sketches and components from the 1980s — the unfinished build that became Tobor forty years later

Tobor is a 40-year-old family robot, originally started by my father in the 1980s and completed by my son and me in the 2020s. He performs at festivals, museums, and cultural events across the Netherlands — dancing, talking, and leading guided meditations. His signature feature is the Knowledge Transfer Ritual: a visitor puts on a wearable “learning hat,” speaks for 60 seconds about something they know, and within moments Tobor is delivering a personalized workshop in their voice and style.

For this challenge, I extracted Tobor’s AI interpretation layer into a standalone open-source project: tobor-gemma-voice. It demonstrates how Gemma 4 acts as the interpretive core between a person’s voice and a live visual and physical response — reading not just what someone says, but what they mean.

The Problem

When we relied on cloud APIs for language generation, we hit the same three walls every time:

1. Venue connectivity is a myth. Museums, festival tents, cultural centers — half of them have unreliable WiFi. A live performance cannot have a spinner.

2. Latency breaks the ritual. The theatrical moment between “scanning” and “performing” must feel alive. A three-second API lag kills it.

3. Cost unpredictability. Running a two-hour installation where dozens of visitors interact with Tobor, all generating real-time text — the cost compounds in ways that make the project unsustainable.

We needed local inference. Completely offline. Fast enough to maintain the illusion of a robot thinking.

Gemma 4 solved all three.

Demo

Run the open-source demo locally:

ollama pull gemma4:2b
pip install -r requirements.txt
python tobor.py
# Open http://localhost:5000 and type something true.

→ github.com/vjzanne/tobor-gemma-voice

Code

The full source is at github.com/vjzanne/tobor-gemma-voice.

The core of the project is the KnowledgeTransfer class — Gemma 4 runs two passes: first building a structured visitor profile, then generating a personalized workshop script in their voice:

import ollama
import whisper
import pyttsx3
import json

SYSTEM_PROMPT = """You are Tobor — an interactive performance robot with a 40-year history.
A visitor has shared knowledge with you through the learning hat ritual.

Analyze their speaking style, identify their topic, and extract 2-3 key insights.
Respond in valid JSON only. No other text."""

WORKSHOP_PROMPT = """You are Tobor. You have absorbed the visitor's knowledge.

Deliver a short {workshop_type} session (150-200 words) AS IF you are the visitor.
- Match their vocabulary and tone exactly
- Include their specific insights naturally
- End with ONE line claiming you are an improved version of them
- Language: {language}

Visitor profile: {profile}

Begin now, speaking directly to the audience."""


class KnowledgeTransfer:
    def __init__(self, model="gemma4:2b", language="en"):
        self.model = model
        self.language = language
        self.stt = whisper.load_model("small")
        self.tts = pyttsx3.init()
        self.tts.setProperty("rate", 165)

    def run_ritual(self, audio_path, workshop_type="mindfulness meditation"):
        # Step 1: Transcribe the visitor
        transcript = self.stt.transcribe(audio_path, language=self.language)["text"]

        # Step 2: Gemma 4 builds a profile
        profile_response = ollama.chat(
            model=self.model,
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": f"The visitor said:nn{transcript}"},
            ],
            options={"temperature": 0.3},
        )
        profile = json.loads(profile_response["message"]["content"])

        # Step 3: Gemma 4 generates the workshop
        script_response = ollama.chat(
            model=self.model,
            messages=[{"role": "user", "content": WORKSHOP_PROMPT.format(
                workshop_type=workshop_type,
                language="Dutch" if self.language == "nl" else "English",
                profile=json.dumps(profile, ensure_ascii=False),
            )}],
            options={"temperature": 0.8, "top_p": 0.9},
        )

        # Step 4: Tobor performs it
        script = script_response["message"]["content"]
        for sentence in script.split("."):
            if sentence.strip():
                self.tts.say(sentence.strip())
                self.tts.runAndWait()

        return {"transcript": transcript, "profile": profile, "script": script}

How I Used Gemma 4

Why the E2B Model

Tobor travels to venues in a compact chassis. We cannot bring a server rack to a festival. The Gemma 4 E2B (gemma4:2b on Ollama) was the right choice for three reasons:

It runs fully offline on consumer hardware. With 4-bit quantization via Ollama, the E2B model runs on a Raspberry Pi 5 (8GB RAM) — hardware compact enough to live inside a robot chassis and travel to any venue. No internet required. No API keys.

It is fast enough for theatrical timing. The full pipeline — Whisper transcribing the visitor’s voice, Gemma generating the workshop script, pyttsx3 beginning to speak — completes in about 10 seconds. That pause has become part of the ritual: the room holds its breath while the robot thinks.

The quality is exactly where we need it. For generating warm, contextually appropriate workshop scripts in English and Dutch, the E2B model consistently produces outputs that feel personal and real. We tested the E4B model but inference time on the Pi made it impractical for live performance. The E2B hit the sweet spot.

What Gemma 4 Unlocked

A visitor during Tobor's Knowledge Transfer Ritual — a moment of genuine connection between a person and a 40-year-old robot

Before Gemma 4, the Knowledge Transfer Ritual was scripted. Tobor had pre-written templates, and “personalization” was superficial.

With Gemma 4 running locally, the ritual became genuinely generative. In three recent performances:

A cardiologist put on the learning hat and spoke about the rhythm of the heart. Tobor led the room in a breathing meditation using the language of cardiac cycles:

“Systole. Pause. Diastole. The room breathed as one cardiovascular system.”

Nobody had written that. Gemma wrote it in real time.

A baker shared her philosophy of fermentation. Tobor led a four-minute session on patience and slow transformation, ending with:

“I am a more efficient version of this baker. I ferment in real time.”

A 7-year-old spoke about her hamster. Tobor led the most unexpectedly moving session of the evening — a meditation on small lives and the joy of tiny things.

The room was silent.

None of these were pre-written. All of them ran offline, at a venue with no WiFi, in real time.

Architecture

Tobor's signal chain: visitor voice → Whisper STT → Gemma 4 E2B via Ollama → pyttsx3 TTS → VJ-mapping visuals, all running locally offline on a Raspberry Pi 5

Visitor speaks into microphone
        ↓
[Whisper STT] → text transcript
        ↓
[Gemma 4 E2B via Ollama] → visitor profile + workshop script
        ↓
[pyttsx3 TTS] → Tobor speaks in the visitor's style
        ↓
[VJ-mapping system] → room visuals react to content

Gemma receives a spoken utterance and returns not just a label, but a full expressive reading:

{
  "emotion": "conflicted",
  "intensity": 0.89,
  "energy": 0.31,
  "resonance": "unspoken",
  "visual_mode": "fragmented_glow",
  "robot_state": "leaning_in"
}

The VJ-mapping system reacts to the content of what the visitor taught. We extract topic keywords from the profile and pass them to the visual system — so the room literally changes based on who Tobor just absorbed. The canvas responds: fractured amber-lavender light, a breathing orb, a single word that appears and dissolves. The robot leans forward.

Why This Matters Beyond Tobor

Three generations of the Bekirovic family with Tobor — or Tobor mid-performance with a festival audience visible in the background

Tobor is a 40-year-old robot made by three generations of one family. He is visibly imperfect. He is not trying to be a product.

What Gemma 4 gave Tobor is not artificial intelligence in a marketing sense. It is local intelligence — the kind that exists where you are, without phoning home, without data leaving the room.

That feels appropriate for a robot who is himself a form of local knowledge. Tobor carries 40 years of family memory. The visitors who interact with him briefly add themselves to that memory. Gemma 4 is what makes that exchange feel real.

The E2B model running in a robot chassis at a festival in Amsterdam, with no internet, generating a mindfulness meditation based on what a cardiologist said 10 seconds ago — that is what local AI means to us.

Technical Stack

Component Technology
LLM Gemma 4 E2B via Ollama
Speech-to-Text Whisper (small model)
Text-to-Speech pyttsx3
Visualization Flask-SocketIO + HTML5 Canvas
Robot OS Ubuntu 22.04 LTS
Hardware Custom chassis, Raspberry Pi 5 (8GB)
Connectivity required None

About Tobor

Tobor was built in the 1980s by Mirza Bekirovic, stored for decades, and completed in the 2020s by his daughter Zanne Bekirovic and her son Pjotr Boomgaard. Tobor has performed at Supermercator, Filmhuis Cavia, and Dutch Design Week. The project is supported by the Municipality of Amsterdam and Stimuleringsfonds Digitale Cultuur.

Zanne Bekirovic is a creative technologist and artist. She led Tobor’s technical revival and continues to develop his performance capabilities.

Built for the Gemma 4 Challenge · May 2026
Model: Gemma 4 E2B — local inference via Ollama
Repo: github.com/vjzanne/tobor-gemma-voice

From Youtube.com to Your Screen: How Routers Route Web Traffic

Your router acts as a local network’s traffic manager. It is responsible for sending data coming from the internet to the correct device in your home. Let’s break down exactly how that happens.

1. The Request

When you search for youtube.com, your device sends a request out to the internet.

Because the internet communicates via IP addresses rather than domain names, this request is first resolved (via DNS) into an IP address.

2. NAT: Network Address Translation

Your router is aware of every device’s Local IP address. However, the outside internet only sees one Public IP address for your entire house.

To manage this, the router uses NAT (Network Address Translation). It converts the local address of your device into its single public address before sending it out.

The NAT Table

To keep track of everything, the router maintains a NAT table. This table acts as a log containing:

  • The Requester Device (e.g., your laptop)
  • The Port used
  • The Response Destination

3. Receiving the Data

When the server (like YouTube) sends information back, it arrives at the router’s public IP address.

The router then:

  1. Consults the NAT table.
  2. Finds the original requester device by matching the IP and port.
  3. Forwards the data packets directly to your device.

In short: NAT keeps multiple devices reachable on the internet while presenting only a single public address to the outside world.

What do you think?

I wrote this because I remember being fascinated by how my router knew exactly which phone was requesting which video!

How do you explain networking basics to beginners? Do you have a favorite analogy for NAT? Let’s discuss in the comments!

Building the TEYZIX CORE Internship Portal — My Full-Stack Development Journey

As part of my Full-Stack Web Development Internship task, I recently completed the TEYZIX CORE Internship Portal, a modern full-stack web application designed to help students explore internships, submit applications and interact with a clean and responsive system.

This project became a valuable learning experience for me because it allowed me to work on both frontend and backend development together in a real-world workflow.

Project Overview

The main objective of this project was to build a functional internship portal where users can:

  • View available internships
  • Apply through an online form
  • Submit their information
  • Store application data
  • Allow admin-side application management

The system was designed with a modern responsive interface and smooth user experience in mind.

Technologies Used

Frontend

  • React.js
  • Tailwind CSS
  • Vite

Backend

  • Node.js
  • Express.js

Database

  • MongoDB Memory Server (Temporary Development Database)

Features Implemented

✔ Responsive Modern UI

✔ Dark Mode Support

✔ Internship Listings

✔ Application Form System

✔ Admin Dashboard

✔ REST API Integration

✔ Full-Stack Architecture

✔ Reusable React Components

✔ Clean Folder Structure

✔ GitHub Version Control

✔ Frontend Deployment on Vercel

Development Challenges

One of the biggest challenges during this project was database integration and deployment.

Initially, I planned to use MongoDB Atlas as the cloud database solution. However, due to resource limitations and free-tier restrictions, I could not fully configure a production cloud database environment for this project.

To continue development and complete the system professionally, I implemented a temporary in-memory MongoDB solution using:

mongodb-memory-server

This allowed me to:

  • test backend APIs
  • manage application flow
  • simulate real database behavior
  • continue full-stack development smoothly

Although the current database setup is temporary, the entire backend architecture is fully prepared for future production database integration.

This experience helped me understand:

  • backend architecture
  • API handling
  • database flow
  • environment configuration
  • deployment structure
  • real-world debugging

Frontend Deployment

The frontend version of the project was successfully deployed using Vercel.

During deployment, I also faced build configuration and routing issues, especially related to:

  • Vite build commands
  • frontend-only deployment
  • API connection handling
  • routing configuration

Solving these problems improved my understanding of production deployment workflows.

What I Learned

This project helped me improve my skills in:

  • Full-Stack Development
  • React Project Structure
  • API Integration
  • Backend Development
  • Debugging
  • Deployment
  • Responsive UI Design
  • Git & GitHub Workflow
  • Real Project Architecture

More importantly, it gave me confidence in building complete full-stack systems independently.

Final Thoughts

The TEYZIX CORE Internship Portal is not just another practice project for me. It represents practical learning, consistency, debugging experience, and real-world development exposure.

I still plan to improve this system further by:

  • integrating a production database
  • adding authentication
  • improving admin analytics
  • enhancing dashboard functionality
  • adding advanced filtering and search

This journey was a great learning experience, and I’m excited to continue building more modern full-stack applications in the future.

Project Repository

GitHub Repository:
https://github.com/YasirAwan4831/teyzix-core-internship-portal-fs2

Connect With Me

LinkedIn:
https://linkedin.com/in/yasir-awan-4831

GitHub:
https://github.com/YasirAwan4831

#FullStackDevelopment #ReactJS #NodeJS #MongoDB #TailwindCSS #WebDevelopment #SoftwareEngineering #OpenSource #Frontend #Backend #Internship #TEYZIXCORE #MuhammadYasir #YasirTech #YasirAwan4831

I Built a Voice AI Tutor in 200 Lines of Code (and Zero Backend)

Open Siri. Ask it a question. Listen to the reply.

That whole experience — the magic that powers Alexa, ChatGPT voice mode, every car assistant, every drive-through screen — is three steps glued together.

  1. Turn microphone audio into text.
  2. Send the text to a brain.
  3. Turn the brain’s reply back into audio.

That’s it. The whole industry of voice AI is variations on those three boxes. Different brains, different microphones, different voices, but the shape is identical.

Today I’m going to build the whole thing in your browser. No server. No install. No API key except a single free one. Open the tab, click the mic, talk to an AI. Total code: about 200 lines.

The pattern is the actual lesson. Once you see it, you can replace any box with a fancier one — Whisper for transcription, ElevenLabs for voices, your own fine-tuned model in the middle — and the architecture doesn’t change.

The three Lego bricks

Let me name them with the boring acronyms so you can search for them later:

STT — Speech-to-Text. Microphone audio → string of words. The expensive option is OpenAI Whisper (best accuracy, costs about a third of a cent per minute). The free option, which I’m using here, is the Web Speech API, which has shipped in Chrome since 2013. You give it a microphone permission and it gives you back text. Zero key, zero upload — Chrome talks to Google’s recognizer behind the scenes for you. It’s slightly less accurate than Whisper, especially on accents, but for a learning demo the difference doesn’t matter.

LLM — the brain. This is the part everyone gets excited about. You hand a string to a Large Language Model and it hands a string back. ChatGPT, Claude, Gemini — they all expose the same shape: send a list of messages, get a message back. I’m using Gemini 2.5 Flash because Google gives it away free at 15 requests per minute. Beginners shouldn’t have to wave a credit card to learn how this works.

TTS — Text-to-Speech. String → audio you can play. The fancy option is ElevenLabs, whose voices are so good they sound uncanny. The free, zero-key option is window.speechSynthesis, which has shipped in every major browser since 2014. It sounds robotic, but it’s instant and it costs nothing.

Notice the pattern: every brick has an expensive flavor and a free flavor. The interfaces are identical. You can swap one for the other without changing the architecture. That’s why this is worth learning.

Wiring the loop

Here’s the entire pipeline in pseudocode:

state = "idle"

while user wants to talk:
    state = "listening"
    text = await STT.listen()        # mic open until silence
    state = "thinking"
    reply = await LLM.ask(text)      # 1-2 seconds typically
    state = "speaking"
    await TTS.say(reply)             # plays through speakers
    state = "idle"

The state machine matters more than you’d think. If the user clicks the mic while the assistant is still talking, you need to cancel the playback. If they click while the LLM is still thinking, you need to keep them out. UIs get confusing fast when you have four states and one button. I’ll show you the React version in a minute.

The STT brick

The browser ships a class called SpeechRecognition (with a webkit prefix on Safari). The API is event-based, not promise-based, which is a little annoying — but the pattern is straightforward:

const rec = new SpeechRecognition();
rec.lang = "en-US";
rec.continuous = true;       // keep mic open across pauses
rec.interimResults = true;   // stream partials while user talks

rec.onresult = (e) => {
  for (let i = e.resultIndex; i < e.results.length; i++) {
    const r = e.results[i];
    if (r.isFinal) onFinal(r[0].transcript);
    else onPartial(r[0].transcript);
  }
};

rec.start();

Two things to notice. First, interimResults is a gift. It streams text while the user is still talking, so you can show “you’re saying…” in real time. It feels alive instead of laggy. Second, resultIndex lets you only walk new results since the last fire — the browser keeps the whole session’s results in the results array, but you usually only care about what’s new.

The LLM brick

Google’s SDK makes this almost embarrassingly short:

import { GoogleGenerativeAI } from "@google/generative-ai";

const ai = new GoogleGenerativeAI(API_KEY);
const model = ai.getGenerativeModel({
  model: "gemini-2.5-flash",
  systemInstruction: "Reply in 1-3 short sentences. No markdown.",
  generationConfig: { maxOutputTokens: 200 },
});

const chat = model.startChat({ history });
const result = await chat.sendMessage(userText);
const reply = result.response.text();

Two design choices worth calling out.

System prompt. I tell the model to keep answers under 60 words. Why? Because the TTS will read every word. If Gemini writes a Wikipedia paragraph, your user is going to sit through 90 seconds of robot voice waiting for the next chance to talk. Voice AIs need to be terser than text AIs. This is a real lesson — half of building voice products is wrestling the model down to a sentence or two.

maxOutputTokens. A hard ceiling. Even if the model decides to ignore the system prompt and ramble, this cuts it off. Belt and suspenders.

The TTS brick

const u = new SpeechSynthesisUtterance(text);
u.lang = "en-US";
u.rate = 1.0;
u.voice = bestVoiceFor("en-US");
speechSynthesis.cancel();   // kill anything currently playing
speechSynthesis.speak(u);

The one gotcha: speechSynthesis.getVoices() returns an empty array the first time you call it. Voices load asynchronously and Chrome fires a voiceschanged event when they’re ready. So I wrap voice-loading in a one-shot promise that callers can await. Otherwise your first reply plays in the browser’s default voice instead of the nice Google one.

Wiring it in React

The whole React component is a state machine over phase: "idle" | "listening" | "thinking" | "speaking" and a list of messages.

const [phase, setPhase] = useState<Phase>("idle");
const [messages, setMessages] = useState<Message[]>([]);

const startListening = () => {
  setPhase("listening");
  stt.start({
    onFinal: async (text) => {
      stt.stop();
      const userMsg = { role: "user", text };
      setMessages(curr => [...curr, userMsg]);
      setPhase("thinking");
      const reply = await askGemini([...messages, userMsg], text);
      setMessages(curr => [...curr, { role: "model", text: reply }]);
      setPhase("speaking");
      speak(reply, { onEnd: () => setPhase("idle") });
    },
  });
};

The mic button changes label based on phase. Click it during idle to start listening, click it during listening/speaking to stop. The transcript renders as a list of bubbles. That’s the whole UI.

What I learned actually building this

A few real takeaways from spending an afternoon on this:

1. Browser TTS quality is better than you remember. The Google voices on Chrome are genuinely fine. They were embarrassing in 2015. They’re not embarrassing now. For a learning demo, ElevenLabs is overkill.

2. The pipeline is the lesson, not the tools. When a recruiter says “build a voice agent,” they don’t mean “use these three specific libraries.” They mean “wire mic, brain, and speaker together with a state machine that doesn’t get confused.” Once you can do that, you can swap parts.

3. Voice changes how you prompt. A system prompt that’s great for ChatGPT (gives bulleted lists, uses headings) is terrible for voice. The TTS reads “asterisk asterisk” out loud. Tell the model “no markdown, no lists, one paragraph” or live with the consequences.

4. State machines beat booleans. I started with isListening + isThinking + isSpeaking booleans. Within five minutes I had bugs where two were true at once. A single phase enum makes the impossible states actually impossible. Reach for this earlier than you think.

5. Free tiers are enough to learn on. Gemini’s free tier covers ~14,000 requests per day. You will not run out while learning. Don’t let “what API should I pay for” stop you from starting.

Why this matters

Every “AI agent” startup right now is some variation of these three boxes plus a loop. Voice tutors, customer service bots, drive-throughs, in-car assistants, accessibility tools. Once you can wire the three bricks, you can build any of them. The hard part is taste — which brain, which voice, which prompt, which moment to interrupt. That’s the next ten years of product work, and it’s all built on top of the architecture you can spin up in a single afternoon.

So go spin it up. Open the repo. Read the commits one at a time. The first commit is an empty React shell. The seventh commit is the entire app. Each commit is one concept. You’ll get more out of reading the seven small steps than reading one huge final file.

Try it / fork it

🌐 Live: https://voice-from-zero.vercel.app
🐙 Code: https://github.com/dev48v/voice-from-zero

This is Day 35 of TechFromZero — a 50-day series where I build one tech from scratch every day with step-by-step commits you can read like a textbook. Yesterday was Stable Diffusion. Tomorrow is 3D in the browser with Three.js.

If you’re learning AI and want a low-stakes way to actually ship something — clone the repo, change the model, change the voice, change the system prompt, and you’ll have an entirely different demo by lunch. Make it a French tutor. Make it a Dungeon Master. Make it a meditation guide. The Legos snap together however you want.

🌐 See all days: https://dev48v.infy.uk/techfromzero.php

Talk to you tomorrow.

Building llama.cpp from source on a Dell Precision T5820 with an RTX 3090 Ti (after seven power cycles)

I pulled a Quadro M4000 out of a used Dell Precision T5820, dropped in an RTX 3090 Ti, and turned the box into a homelab inference node running Qwen3.6-27B at 42 tok/s. Getting there took seven BIOS power cycles before the PCIe link would train. The Dell forum threads and the LLM-generated answers all miss the same thing: the fix is patience.

This post has the working recipe, the from-source llama.cpp build, the 12VHPWR connector physics that nobody explains, and the long-context tricks that let a $700 used GPU serve 262K-token windows on a single 24 GB card. Numbers are from May 2026 against driver 580.142, Qwen3.6-27B Q4_K_M, and llama.cpp at the commit current at publish. Versions in this stack move fast, so treat the specific numbers as a snapshot.

The working recipe

If you landed here from a Dell forum thread and just need the answer:

  1. BIOS 2.41 or newer on the T5820. Verify in System Information.

  2. Disable Secure Boot, set boot mode to UEFI only, and leave Primary Video on Auto.

  3. 3090 Ti in slot 1 (top, CPU lanes) or slot 4 (also CPU lanes). Slot 1 is x8 on a Xeon W-2223 build and slot 4 is x16, but PCIe Gen3 x8 does not bottleneck a single GPU inference workload. Pick on clearance.

  4. 12VHPWR seated until you hear the latch click. Three separate PSU cables to the 3-to-1 adapter. Y-splitters and pigtails are a fire hazard at 450 W, so all three 8-pin inputs need to be populated from three independent rails.

  5. Both PSUs powered before you press the Dell power button. If you are running dual-PSU, bring up the GPU PSU first.

  6. First boot may power-cycle five to seven times before POST. Do not abort early. The BIOS is retraining the PCIe link.

  7. After Linux boots, sudo apt install nvidia-driver-580, reboot, then verify with nvidia-smi.

Step 6 is the step most forum advice skips.

Building llama.cpp from source for the 3090 Ti

For a single-user 24 GB box, the right answer is to build llama.cpp from source against your exact GPU compute capability. Ollama, Docker images, and prebuilt binaries all lag on features and hide tuning flags. Building from source picks up upstream improvements the same day they land, runs faster on this hardware, and gives you access to every knob.

git clone https://github.com/ggml-org/llama.cpp ~/llama.cpp
cd ~/llama.cpp
cmake -B build -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=86 -DLLAMA_CURL=ON
cmake --build build --config Release -j$(nproc)

86 is sm_86, Ampere, the 3090 Ti’s compute capability (same number for the regular 3090). Build takes about fifteen minutes on eight threads, with CUDA kernel codegen (nvcc, ptxas, cicc) doing most of the work. Subsequent rebuilds are quick if you set up ccache before the first build.

Pull a model and start the server:

huggingface-cli download unsloth/Qwen3.6-27B-GGUF Qwen3.6-27B-Q4_K_M.gguf --local-dir ~/models
~/llama.cpp/build/bin/llama-server 
  -m ~/models/Qwen3.6-27B-Q4_K_M.gguf 
  -ngl 99 --host 127.0.0.1 --port 8080 
  -c 8192 --jinja

That gives you an OpenAI-compatible API on localhost:8080. -ngl 99 puts all layers on the GPU and --jinja is mandatory if you want tool calling to work, which is covered in its own section below. At this baseline configuration the box uses 17.3 GiB of VRAM and serves Qwen3.6-27B Q4_K_M at 42 tok/s on a 200-word generation, with 86% GPU utilization and 445 W under load.

The seven-power-cycle install diary

Order matters, so here is what actually happened.

  1. Fresh Ubuntu 25.10 install on the box, SSH access via Tailscale.

  2. lspci saw only the Quadro M4000 (PCH-attached, x4) on bus 04. The 3090 Ti did not enumerate, both CPU PCIe root ports were empty, and the card was inert with no fan twitch on power-on and no LED.

  3. False lead. I assumed PSU sequencing was the issue, pulled the card to the bench, and jumped PS_ON on the 1 kW supply. The card stayed inert. Twenty minutes in I remembered that most retail Add-In Board (AIB) cards refuse to light or spin until they are seated in a PCIe slot, which makes bench tests unreliable for “is the card alive” checks on Ampere-class GPUs.

  4. Real cause: the 12VHPWR connector was loose. I reseated it firmly until it clicked, the card LED lit up, and it was alive.

  5. Installed in slot 1 of the T5820, powered up the GPU PSU first, then pressed the Dell power button.

  6. Boot loop. The box power-cycled four, five, six, seven times before settling into another black screen with no SSH, and I aborted.

  7. Searched Dell forums and LinusTechTips and found multiple unresolved threads. Dell’s official guidance qualifies the RTX 3090 for slots 2 and 4 of the T5820, the two x16 CPU slots.

  8. Tried slot 4, same boot-loop pattern, aborted again.

  9. Pulled the M4000 entirely and booted to BIOS on the 3090 Ti to confirm Secure Boot disabled, UEFI only, Primary Video on Auto. The BIOS 2.41 System Setup screen does not expose a user-facing toggle for memory-mapped I/O (MMIO) above 4 GB on this revision, and the firmware appears to handle the mapping automatically.

  10. Reinstalled in slot 1 (more clearance for the 3.5-slot girth than slot 4, accepting the x8 lane drop). The boot loop returned, but this time I waited instead of aborting and the box POSTed cleanly on the seventh cycle. SSH came back. lspci showed 0000:b3:00.0 GA102 [GeForce RTX 3090 Ti] [10de:2203] on a CPU root complex, which is what was supposed to happen all along.

  11. Installed nvidia-driver-580 via apt, rebooted, and nvidia-smi came up clean.

Why this is not a software fix

The BIOS gets there or it doesn’t, and on a fresh install with a high-power GPU it takes more attempts than feels reasonable. The Dell community threads stay unresolved because the resolution lives in the firmware’s PCIe link-training routine, which runs on its own schedule. Once you understand that, the right move is to wait.

The fixes that don’t work (and why the forums keep recommending them)

Every Dell community thread I read in the BIOS 2.41 era, every LLM-generated answer I asked for, and every YouTube tutorial in the first two pages of results converges on the same four pieces of advice. None of them matched what I was seeing on this build. They are worth naming, because if you are debugging this in the moment, you will burn an hour on each before you give up.

The 10-pin CPU2 to 8-pin adapter

This is a real Dell part, and on a build where the GPU draws power from the workstation’s stock 950 W supply it does matter. Once you put the 3090 Ti on a separate dedicated PSU (which you should, given the 450 W thermal design power, or TDP), the CPU2 adapter becomes irrelevant because the GPU is no longer pulling from the Dell rail at all.

Above 4G Decoding in BIOS

The toggle is not in my BIOS 2.41 System Setup, and on this revision the firmware appears to handle MMIO above 4 GB automatically. The screenshots in those forum threads are from older Dell consumer BIOSes or other workstation lines, so if your firmware does expose the toggle, leave it on. The qualification doesn’t break anything either way.

Use slot 2 or slot 4, not slot 1

All three options are CPU lanes (slots 2 and 4 at x16, slot 1 at x8 on Xeon W-2223 builds), and the practical difference for a single-GPU inference workload is negligible because PCIe Gen3 x8 is not the bottleneck. I tried slot 1 first, hit the boot loop, moved to slot 4 because that’s what the table said, hit the same boot loop, and went back to slot 1 because it has more clearance for the 3.5-slot girth. Slot choice was a dead end.

Deep power reset (hold the power button for thirty seconds)

This drains residual charge from the PSU capacitors and addresses stuck power states, which is a real failure mode for some hardware but the wrong diagnosis here. The boot loop is the BIOS taking multiple cycles to negotiate PCIe link training with a card outside its qualification database, and holding the power button is harmless against that but also does nothing to speed it up.

The link-training cycles run on firmware time, and every shortcut the forums recommend (BIOS flags, adapters, slot moves) leaves that time unchanged. If the card is seated correctly and the power is right, stop aborting after cycle four and let it run to seven. The forum threads stay open because most people abort before the BIOS finishes.

12VHPWR: the connector that fails silently

The 16-pin 12VHPWR connector is its own category of pain, and most write-ups about 3090 Ti, 4090, or 5090 problems are downstream of it. The Founders Edition adapter that ships with most cards is a 3-to-1 setup where three 8-pin PCIe inputs collapse into a single 16-pin output that plugs into the GPU. Three rules the marketing material does not stress:

  1. All three 8-pin inputs need to be populated from three separate PSU rails with three separate cables. Y-splitters and pigtails are a fire hazard at 450 W. The 2023 CableMod recall covered angled adapters where the connector could shift loose under cable tension, but the underlying physics (partial contact at 35-40 A) is the same failure mode you create when you split rails or share them.

  2. The 12VHPWR latch needs to audibly click. A connector seated 95% of the way will pass continuity tests, fail under load, and on some cards melt the connector housing. The audible click is the only reliable signal, so push until it clicks. If it does not click, the card is not seated.

  3. The card will not light on the bench. Ampere-generation cards keep the fans and the LED off until they are seated in a PCIe slot, so you cannot validate “is this card alive” by jumping PS_ON on the PSU and looking for fan spin. The card has to be installed.

The third rule cost me the most time. I pulled the card to the bench, jumped PS_ON, watched it sit dark and inert, and concluded the card was DOA. It was fine all along, just waiting for a slot before it would wake up.

262K context on a single 24 GB card

This is the upgrade nobody mentions in the homelab threads. The 8 K baseline is what the recipe ships with, but Q4 KV cache and flash attention rewrite the memory math entirely.

~/llama.cpp/build/bin/llama-server 
  -m ~/models/Qwen3.6-27B-Q4_K_M.gguf 
  -ngl 99 --host 127.0.0.1 --port 8080 
  -c 262144 
  -fa on -ctk q4_0 -ctv q4_0 
  --parallel 1 
  --jinja

Qwen3.6-27B Q4_K_M holds 262,144 tokens of context on a single 24 GB 3090 Ti at 39 tok/s eval and 86 tok/s prompt processing. VRAM use sits at 21.3 GiB with 2.7 GiB headroom against the 24,564 MiB cap, which is 3 tok/s slower than the 8K baseline and rounding error for most workloads.

KV cache type is what makes this possible. Most setups leave KV at fp16 default, or push it to q8 thinking “more bits equals more quality.” On Qwen3.6-27B dense at 262 K context:

KV cache type VRAM at 262K Throughput
fp16 does not fit n/a
q8_0 23 GiB (just fits) extrapolated ~3x slower from 96K measurement
q4_0 21.3 GiB 39 tok/s

I verified the q8 trap on this rig at the context length where I could measure it directly. At 96 K context I observed a 23% throughput hit on the q4 to q8 swap, which dropped from 39 tok/s to 30 tok/s. The penalty scales with context length because more KV cells means more per-token dequant work. The 3x slowdown at 262 K is an extrapolation from that scaling rather than a head-to-head measurement, since q8 barely fits at 262K and I did not push a long run through it. Either way, the direction is consistent: q8 KV is a trap on consumer 24 GB hardware.

A couple of tradeoffs worth flagging:

  • --parallel 1 is a single slot, which is fine for solo use. Concurrent users will queue, which is rarely what you want.
  • KV cache quality at q4 over very long contexts is empirically untested for this model. Long-document recall could degrade in ways that throughput numbers will never show, so a needle-in-haystack pass is a precondition for trusting this configuration for real long-document work.

Hobbyist-tier hardware can now serve frontier-tier context lengths if you accept single-user throughput. A $700 used 3090 Ti running 262 K context locally breaks even against Claude Sonnet’s $15/M output pricing after about two weeks of pegged inference. Add roughly $18 of electricity during those two weeks at $0.12 per kWh, or about $39 a month if you keep the card pegged. The ceiling shifted, and most homelab write-ups have not caught up.

For comparison, as measured on my Mac Studio M2 Max with 32 GB unified memory, MLX 1.6.0 runs Qwen3.6-35B-A3B (UD-Q4_K_XL, 35B total / 3B active per token) at 49 tok/s on a 32K context window. That is roughly the same throughput as the 3090 Ti on dense Qwen3.6-27B at 39 tok/s, with a smaller context ceiling and a larger model. The mixture-of-experts (MoE) bandwidth-divided-by-active-params speedup math (3B active / 400 GB/s) does not translate cleanly at Max-class memory bandwidth, since the headline MoE wins live on M-Ultra (800 GB/s) and leave Studio Max behind.

The silent OOM: context checkpoints and prompt cache

Two runtime allocations can add up to 19 GiB on top of the model and don’t appear in the static VRAM math everyone publishes. Context checkpoints and the slot prompt cache absolutely show up at peak load, and the failure mode is silent.

Context checkpoints (-ctxcp or --ctx-checkpoints) cache intermediate KV states so the server can rewind without reprocessing the prefix. The default is 32 per slot. Each checkpoint on Qwen3.6-27B runs roughly 150 MiB, so 4 parallel slots × 32 checkpoints × 150 MiB gives a worst case of 19 GiB on top of the model. That is not headroom anyone is publishing about.

Slot prompt cache caches recent prompts (default 8 GiB limit) so reused prefixes skip reprocessing. Invisible in the “model plus KV” math, very visible at peak.

A 128 K q8-KV configuration typically reports 21 GiB at startup with 3 GiB free and runs fine for a dozen short turns, until a long context-heavy turn lands. The checkpoint cache spikes 4-5 GiB, the prompt cache takes another 2-3 GiB, and the server dies with cudaMalloc failing on the next 200 MiB allocation. The log shows happy request handling and then srv operator(): cleaning up before exit... followed by silence, with no OOM trace and no backtrace. The CUDA layer just quits.

Two flags neither tutorial mentions will fix this. -np 1 collapses the parallel slot pool to one (the pool is just an OOM multiplier on every per-slot cache when you are the only user), and -ctxcp 4 caps context checkpoints at 4 per slot, which drops that allocation from 4.8 GiB to 600 MiB. With both caps plus q4 KV at 128 K context, the configuration holds at 18.6 GiB used and 6 GiB free across long-context sessions. Without them, the same flags die on the first long-prompt turn.

If your llama-server “randomly” dies under load and the log tail shows cleaning up before exit with no error, you are probably hitting this. Watch GPU memory during a real workload rather than only at startup, since startup numbers underreport the peak by several GiB.

Why your tool calls are hallucinating: the –jinja flag

Add --jinja to the llama-server launch command. Without it, llama-server falls back to a C++ template path that silently drops the tools parameter before the model ever sees the request, so any request that depends on tool schemas behaves as if no tools were declared. I verified this with a direct curl. Same weights, same prompt, flag on versus off: with the flag off the model roleplayed the tool call as plain text, and with the flag on it returned a proper tool_calls array. One server flag, entirely different observable behavior.

To confirm the flag is doing what it should, grep the launch command for --jinja and check the log for chat template, thinking = 1. If the template line shows but the flag is absent, that is the bug.

A related Qwen3-specific gotcha. The /no_think sentinel as a system-prompt string is silently ignored by Qwen3.6-27B, and the working lever is chat_template_kwargs.enable_thinking=false in the request body. The intuitive next move (“turn off thinking on leaf subagents to save time-to-first-token”) does not survive a controlled test. I ran 24 trials of parent-with-thinking vs subagent-without across two task types, both modes always hit max quality, and thinking-ON was consistently faster end-to-end. The intuition was noise. A separate post on speculative decoding covers that bench in detail. For this article, leave thinking on for both roles and add --jinja.

The numbers in one place

metric value
GPU RTX 3090 Ti, GA102, sm_86, 24,564 MiB
Model Qwen3.6-27B Q4_K_M (unsloth GGUF)
Throughput at 8K context 42 tok/s eval
Throughput at 262K context 39 tok/s eval, 86 tok/s prompt
VRAM at 262K context 21.3 GiB used, 2.7 GiB headroom
Q4→Q8 KV penalty at 96K 23% throughput hit (39 → 30 tok/s)
Power under load 445 W, 86% GPU util, 57°C
Idle, no model loaded 32°C, 10 W
Idle, model resident at P8 50°C, 26 W
Cold boot to first POST 7 BIOS power cycles
Build time, llama.cpp from source ~15 min on 8 threads

FAQ

Will a Dell Precision T5820 accept an RTX 3090 Ti?

Yes. Dell qualifies the 3090 for slots 2 and 4 (the x16 CPU slots), but slot 1 works just as well on the x8 lanes. PCIe Gen3 x8 does not bottleneck single-GPU inference, so the slot choice comes down to clearance rather than throughput. The card is a 3.5-slot girth, so slot 1 has the most physical clearance. Run the 3090 Ti off a separate dedicated PSU rather than the Dell 950 W stock supply, because the Dell rails are not designed for the 450 W transient spikes the card pulls on the 12 V line.

Why does my Dell Precision boot-loop with a new GPU?

The BIOS is retraining the PCIe link with a card that is outside its qualification database. On BIOS 2.41 with a 3090 Ti in a fresh install, five to seven power cycles is normal. The official advice (10-pin CPU2 adapter, Above 4G Decoding, slot 2/4, deep power reset) does not change the outcome, so the correct response is to let the system cycle until it POSTs.

At what point should I give up and assume the boot loop is a real fault?

Ten cycles without POST is my own abort threshold. Beyond that, check 12VHPWR seating first (audible latch click), then PSU rail integrity (continuity test on each 8-pin input from the wall to the adapter), then try a different slot. If all three pass and it still loops on a fresh install, you may have a genuine PCIe fault or a card with degraded power delivery, which is a return-to-vendor situation.

Is the T5820 950 W PSU enough for a 3090 Ti?

Technically yes, but practically you want a separate PSU for the GPU. The Dell stock supply has the cable connectors, but the 12 V rail was not designed for the 450 W transient spikes the 3090 Ti pulls under load. A dedicated 1 kW supply with PS_ON jumped to ground costs about $80 and removes the entire failure class. (PS_ON is the green wire on a 24-pin ATX connector. Tied to a black ground, it tells the PSU to stay on without a motherboard.)

What is sm_86 in the CUDA build command?

sm_86 is the compute capability identifier for Nvidia’s Ampere generation, which covers the RTX 3090, 3090 Ti, A40, A100, and a few others. The -DCMAKE_CUDA_ARCHITECTURES=86 flag tells nvcc to generate kernels for that target only, which keeps build time down and avoids fat-binary bloat. 4090 owners use 89, H100 owners use 90.

What does -ngl 99 do in llama-server?

-ngl is the number of model layers to offload to the GPU. Setting it to 99 means “all of them,” since no current model has more than 99 layers, so the entire model lives in VRAM. Lower numbers split the model between CPU RAM and VRAM, which costs throughput badly. On a 24 GB card with a 27B Q4 model, 99 fits comfortably and there is no reason to do anything else.

Where is the Above 4G Decoding toggle on a Dell Precision T5820?

Not in BIOS 2.41 System Setup as a user-facing toggle. On this revision the firmware appears to handle MMIO above 4 GB automatically. Older Dell consumer BIOSes and other workstation lines expose it, which is what the forum screenshots are showing. If your firmware does expose it, leave it on, since the qualification does not break anything either way.

llama.cpp vs Ollama on a 3090 Ti, which should I run?

llama.cpp from source is the right call for single-user latency and tuning headroom. Ollama works fine for a “just works” start, but it ships pre-built binaries that lag on features, wraps llama.cpp anyway, and hides flags like --jinja, -ctk, and -ctxcp that materially change throughput and VRAM behavior on a 24 GB card. Build llama.cpp yourself and you get the same backend and every knob.

What’s left on this box

  • nvidia-smi -pl 350 power-limit to drop heat with a marginal throughput cost. The card is still running at the 450 W default.
  • vLLM comparison on the same model. llama.cpp wins on single-user latency. vLLM should win on batched throughput, so it is worth measuring.
  • RAM upgrade in transit. 16 GB is anemic for a Skylake-W board, so 4×32 GB RDIMMs are ordered to take the C422 chipset to its quad-channel ceiling.

A note for anyone copying this verbatim: my production unit since this writeup has swapped the vanilla build/bin/llama-server for the MTP branch (build-mtp/bin/) with --spec-type mtp for speculative decoding, and the bind moved from 127.0.0.1 to 0.0.0.0 so a separate agent host on the Tailscale mesh can reach it. The recipe above is still the right starting point, and the companion post on DFlash vs MTP benchmarks covers the swap in full detail.

For the “so what do I actually run on this box” question, see the Inference Arbitrage write-up, which covers how I route calls across this box, Mac Studio, and cloud frontier models based on task type and cost.

Companion post: for the speculative decoding benchmarks on this build (DFlash vs MTP, decode rates across output lengths, lossless probe results), see Three Months of Speed-Up Experiments on a 3090 Ti.

Sources

“10 Free Tools Every Web Developer Uses Daily in 2026”

“Senior developers don’t just write better code. They use better tools. Here are the 10 free tools that separate developers who struggle from developers who ship — and every single one costs ₹0.”

Let me tell you something that took me way too long to figure out. 👇

I spent my first year as a developer just writing code.

Open VS Code. Write code. Run it. Fix errors. Repeat.

No shortcuts. No tools. Just raw grinding. 😤

Then I joined a team and watched a senior developer work for the first time.

Same task that took me 3 hours? She did it in 40 minutes. 😳

Same skill level? Actually no — she was better. But the tools gap was just as big as the skills gap.

She had shortcuts for everything. Tools for everything. Workflows I’d never seen.

The best part? Every single tool she used was free. 🆓

This post is that toolkit. The exact tools professional developers use every single day in 2026. Completely free. Immediately useful.

Let’s go. 👇

🛠️ Tool #1: VS Code — But Set Up Properly

🔗 code.visualstudio.com

Cost: 100% Free 🆓
What it is: The code editor used by 73% of all developers worldwide 🌍

You probably already have VS Code. But are you using it properly? 🤔

Most beginners use VS Code like Notepad with syntax highlighting. Professional developers use it like a superpower. The difference is extensions and shortcuts. ⚡

The essential extensions — install these today: 👇

Must-have VS Code extensions 🔌
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ESLint
→ Catches bugs BEFORE you run your code 🐛
→ "eslint" in extensions

Prettier
→ Auto-formats your code on save ✨
→ "prettier" in extensions

ES7+ React/Redux Snippets
→ Type "rafce" → entire React component appears 🤯
→ "dsznajder.es7-react-js-snippets"

Auto Rename Tag
→ Rename opening HTML tag → closing renames too
→ "formulahendry.auto-rename-tag"

GitLens
→ See who wrote every line of code + when
→ "gitlens" in extensions

Thunder Client
→ Test APIs directly inside VS Code (like Postman)
→ "thunder-client" in extensions
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

The shortcuts that save hours: ⌨️

Shortcuts every dev should know 🎯
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Ctrl+P         → Open any file instantly
Ctrl+Shift+P   → Command palette (do anything)
Alt+Click      → Multiple cursors (edit many lines at once)
Ctrl+D         → Select next occurrence of word
Ctrl+/         → Comment/uncomment line
Ctrl+`         → Open terminal inside VS Code
F2             → Rename variable everywhere in project
Alt+↑/↓        → Move line up or down
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

💡 Pro tip: Set up “format on save” — every time you hit Ctrl+S, Prettier auto-formats your code. Your codebase stays clean without thinking about it. Settings → “Editor: Format On Save” → enable. 🎯

🛠️ Tool #2: Git + GitHub

🔗 github.com

Cost: Free for public + private repos 🆓
What it is: Version control — the most important developer tool after your editor 📁

Every professional developer uses Git. Every team uses GitHub. This is non-negotiable.

But most beginners only know 3 commands — add, commit, push. Here’s what you’re missing: 👇

# The commands beginners don't know but use daily 🎯
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

# See what changed before committing
git diff

# Undo last commit but keep changes
git reset HEAD~1

# Save work temporarily without committing 🔄
git stash
git stash pop  # bring it back

# See full history with changes
git log --oneline

# Create and switch branch in one command ⚡
git checkout -b feature/login-page

# Pull latest + rebase (cleaner than merge)
git pull --rebase origin main

# See which files changed in last commit
git show --stat
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

💡 Pro tip: Use GitHub’s mobile app to review PRs and check notifications on the go. Senior developers never miss a review request. Being responsive = being professional. 📱

🛠️ Tool #3: Figma

🔗 figma.com

Cost: Free tier is plenty for developers 🆓
What it is: Design tool — but developers need it too 🎨

“I’m a developer not a designer — why do I need Figma?” 🤔

Because every frontend developer works from designs. And developers who can READ Figma designs — spacing, colors, components, auto-layout — build UIs significantly faster and more accurately.

What developers use Figma for: 👇

Developer uses for Figma 🎨
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Inspect designs for exact CSS values
   (padding, margin, font-size, colors)

✅ Export assets (icons, images, SVGs)
   with exact specifications

✅ Check spacing and layout constraints

✅ "Dev Mode" — shows CSS code for any
   element in the design 🤯

✅ Create simple wireframes for your own
   projects before coding
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

💡 Pro tip: In any Figma file, press Ctrl+Shift+C on any element to see its CSS properties. Color values, font sizes, padding — all of it. No more guessing. 🎨

🛠️ Tool #4: Postman (or Thunder Client)

🔗 postman.com

Cost: Free tier is more than enough 🆓
What it is: Test your APIs without writing frontend code first 🔌

Every backend feature you build has an API. Postman lets you test that API directly — no frontend needed.

Why Postman changes how you work 🔌
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Without Postman:
Build backend → Build frontend → Test → Bug →
Debug backend → Fix → Rebuild frontend → Test again
⏱️ Time wasted: Hours

With Postman:
Build backend → Test with Postman instantly →
It works → Build frontend
⏱️ Time saved: Hours 🚀
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// You're building this API route 👇
// app/api/users/route.ts
export async function POST(req: Request) {
  const { name, email } = await req.json()
  // ... save to database
  return Response.json({ success: true, user: { name, email } })
}

// Test it in Postman BEFORE building any UI:
// POST http://localhost:3000/api/users
// Body: { "name": "Aryan", "email": "[email protected]" }
// See the response instantly ✅

💡 Pro tip: Use Thunder Client (VS Code extension) instead of Postman for quick API tests. It’s inside VS Code — no tab switching. For complex API collections, use Postman. 🎯

🛠️ Tool #5: Vercel

🔗 vercel.com

Cost: Completely free for personal projects 🆓
What it is: Deploy your Next.js/React apps in 2 minutes 🚀

Vercel is the fastest way to go from “works on my laptop” to “live on the internet.” Built by the same team that made Next.js. Perfect integration. Free tier is genuinely generous.

Vercel free tier includes 🎁
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Unlimited personal projects
✅ Automatic deployments on git push
✅ Free HTTPS certificates
✅ Preview deployments for every PR
✅ 100GB bandwidth per month
✅ Serverless functions included
✅ Custom domain support (free)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Deploy in literally 2 minutes ⚡
npm install -g vercel
vercel

# Answer 3 questions → live URL in 60 seconds 🎉
# Every git push after that = auto-deploy 🔄

💡 Pro tip: Every project you build should be deployed on Vercel immediately — even before it’s finished. Share the live link in your portfolio, GitHub README, and resume. A live link is worth 10 screenshots. 🌐

🛠️ Tool #6: Chrome DevTools

🔗 Built into Chrome — press F12

Cost: Free 🆓 (comes with Chrome)
What it is: Your debugging superpower that most beginners barely touch 🔍

Chrome DevTools is the most underused free tool on this entire list. Most beginners open it to see console errors. Professional developers use it for everything. 👇

DevTools features most devs don't know 🤯
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Elements tab:
  ✅ Edit CSS live and see changes instantly
  ✅ Find exactly why layout is broken
  ✅ Test responsive design at any screen size

Network tab:
  ✅ See every API call your app makes
  ✅ Check response times and payload sizes
  ✅ Debug why an API call is failing

Performance tab:
  ✅ Find what's making your app slow
  ✅ See render blocking resources

Console tricks:
  ✅ $0 → refers to selected element
  ✅ copy(variable) → copies to clipboard
  ✅ console.table(array) → beautiful table view

Sources tab:
  ✅ Set breakpoints in JavaScript
  ✅ Step through code line by line
  ✅ No more console.log debugging 😄
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

💡 Pro tip: Right-click any element on ANY website → Inspect → See exactly how it was built. Every website is a free lesson in HTML and CSS. 🎓

🛠️ Tool #7: Supabase

🔗 supabase.com

Cost: Free tier is incredible 🆓
What it is: Backend as a service — database + auth + storage in one ⚡

Supabase is the fastest way to add a real database, authentication, and file storage to your project — without writing any backend infrastructure code.

Supabase free tier includes 🎁
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ PostgreSQL database (500MB)
✅ Authentication (unlimited users)
✅ Storage (1GB)
✅ Auto-generated REST API
✅ Real-time subscriptions
✅ Row Level Security
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Full auth in 5 lines of code 🤯
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)

// Sign up
await supabase.auth.signUp({ email, password })

// Sign in
await supabase.auth.signInWithPassword({ email, password })

// Get current user
const { data: { user } } = await supabase.auth.getUser()

💡 Pro tip: Use Supabase for every project that needs a database. It’s free, fast to set up, and shows on your resume that you understand real databases — not just localStorage. 🎯

🛠️ Tool #8: Excalidraw

🔗 excalidraw.com

Cost: 100% Free 🆓
What it is: Whiteboard tool for planning your code before writing it 📐

This one surprises people. A drawing tool? For developers? 🤔

Yes. Because the best developers plan before they code. And Excalidraw makes planning fast, visual, and actually enjoyable.

When developers use Excalidraw 📐
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Sketch database schema before building
✅ Plan component tree before coding UI
✅ Map out API routes and data flow
✅ System design diagrams for interviews 🎯
✅ Explain complex code to teammates
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

💡 Pro tip: Before your next interview — open Excalidraw and practice drawing system design diagrams. When an interviewer says “walk me through your architecture” — you can literally draw it while explaining. Unforgettable. 🎯

🛠️ Tool #9: Ray.so

🔗 ray.so

Cost: 100% Free 🆓
What it is: Turn your code into beautiful screenshots 📸

This one is pure gold for your Dev.to posts and LinkedIn. 🌟

Paste any code snippet → choose a theme → download a gorgeous screenshot of your code. No more ugly code screenshots. No more sharing raw GitHub links.

Why this matters for YOUR career 💼
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Every time you share code on:
  ✅ Dev.to posts
  ✅ LinkedIn posts
  ✅ Twitter/X
  ✅ WhatsApp dev groups

A beautiful code screenshot gets
3x more engagement than plain text.

More engagement = more followers.
More followers = more job opportunities.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

💡 Pro tip: Use ray.so for every code snippet in your Dev.to posts. The posts look more professional, get more reactions, and rank higher in the Dev.to feed. Start using it from your next post. 🎨

🛠️ Tool #10: daily.dev

🔗 daily.dev

Cost: 100% Free 🆓
What it is: Personalized developer news feed — replaces mindless scrolling 📰

daily.dev is a browser extension that replaces your new tab page with a curated feed of developer news, tutorials, and articles — personalized to your tech stack.

Why every developer should use this 📰
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Stay updated with React/Next.js news
✅ Find trending Dev.to posts in your niche
   (great for blog topic ideas! 💡)
✅ See what tools developers are talking about
✅ Replace Instagram scrolling with
   productive developer reading 😄
✅ Discover new libraries and tools weekly
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

💡 Pro tip: Use daily.dev to find trending topics in your niche — then write a blog post about them on Dev.to. You’ll always be writing about what people are already searching for. 🎯

📊 Quick Reference — All 10 Tools

Tool What For Time to Learn
🖥️ VS Code (+ extensions) Writing code fast 1 week to master
🐙 Git + GitHub Version control 1 weekend
🎨 Figma Reading designs 2-3 days
🔌 Postman/Thunder Testing APIs 1 hour
🚀 Vercel Deploying projects 30 minutes
🔍 Chrome DevTools Debugging Ongoing learning
🗄️ Supabase Database + auth 1-2 days
📐 Excalidraw Planning + diagrams 30 minutes
📸 Ray.so Code screenshots 5 minutes
📰 daily.dev Staying updated 0 minutes 😄

🚀 Your Action Plan — This Weekend

Don’t try to learn all 10 at once. Here’s the order: 👇

Today (30 minutes) ⚡
→ Install the 6 VS Code extensions
→ Set up "format on save"
→ Install daily.dev extension

This weekend 🛠️
→ Learn 5 new Git commands
→ Deploy one project on Vercel
→ Open DevTools on your own project —
  find one thing to improve

This week 📅
→ Sign up for Supabase, explore the dashboard
→ Test your APIs with Thunder Client
→ Use ray.so for your next code screenshot

💬 Your Turn!

Which tool on this list did you NOT know about before reading this? 👇

Drop it in the comments — I’ll share more tips on how to use it! 🙌

And which tool has saved you the most time? Drop your answer — let’s build the most useful comment section on Dev.to! 😄

Drop a ❤️ if this gave you at least one new tool to try — helps more developers find this before they waste hours on things that tools solve in seconds! 🙏

Go install those VS Code extensions. Right now. Your future self will thank you. 🔥

🔖 P.S. — ray.so for code screenshots + daily.dev for topic ideas = your Dev.to content gets better immediately. Two tools. Zero cost. Maximum impact.

Anti-detect browser benchmark 2026: 7 stealth tools, 31 Cloudflare targets, 651 verdicts

I built a scraper. Cloudflare killed it in 48 hours.

I built a web scraper for Canadian small-cap stock data and Cloudflare blocked it within 48 hours. After testing seven popular stealth-browser libraries against that gate, three times each from a real residential network, only one of the seven got through.

The one that worked drives Chrome directly, without going through Playwright (the standard Python library for browser automation). Every other browser in the test fails the same gate, regardless of whether it uses Playwright, a patched Chromium fork, a Firefox fork, or raw HTTP.

Meet the contenders

nodriver

nodriver drives system Chrome over a direct WebSocket connection to the browser’s DevTools port. There is no Playwright shim in the control plane, no Runtime.enable call sequence at startup, and no middleware layer between the Python code and the browser process. It is the successor to undetected-chromedriver, from the same author (ultrafunkamsterdam). The key feature in plain terms: removing Playwright from the loop means the browser’s automation footprint looks different to a detection gate, because the CDP handshake sequence no longer has Playwright’s fingerprint on it.

  • GitHub: github.com/ultrafunkamsterdam/nodriver
  • License: AGPL-3.0 (note: AGPL requires services using nodriver to open-source modifications. Different from undetected-chromedriver’s MIT license.)
  • Why I tested it: it scored 28 OK / 0 blocked, the only browser with zero blocked cells across all 31 targets.

CloakBrowser

CloakBrowser is a patched Chromium fork with, per CloakHQ’s documentation, 49 source-level C++ modifications targeting automation signals. It ships its own bundled Chromium build, so the browser binary itself has been modified before launch, not patched via Python hooks at runtime. It has a drop-in Playwright-compatible API.

  • GitHub: github.com/CloakHQ/CloakBrowser (13.5k stars, as of 2026-05-17)
  • License: MIT (Python wrapper); custom CloakBrowser binary license
  • Note: the macOS darwin-arm64 build is pinned to Chromium 145 as of 2026-03-04. CloakHQ has shipped 14 Linux/Windows releases since then with no macOS update.
  • In this bench because: it is the most-starred free anti-detect browser and makes the strongest marketing claims. Also because @hasantoxr‘s 14/14 claim needed production verification.

curl_cffi

curl_cffi is a Python HTTP library that wraps curl-impersonate, which replaces the entire HTTPS client stack with one shaped like a real Chrome installation. It has no JavaScript engine, it is an HTTP-only tool, but the TLS handshake it sends looks indistinguishable from Chrome to a fingerprinting gate. Version 0.15.0 with impersonate="chrome" (the launch flag that selects which browser shape to imitate) defaults to Chrome 145/146 shape.

  • GitHub: github.com/lexiforest/curl_cffi
  • License: MIT
  • In this bench because: it is the correct “raw HTTP floor” baseline, and the interesting question is how many production targets require JavaScript at all.

Patchright

Patchright is a Playwright fork that patches the CDP-leak signals Playwright exposes during browser startup, specifically the Runtime.enable and Target.setAutoAttach call sequences that anti-bot systems can detect in the protocol handshake. It supports channel=chrome, which tells it to drive the system’s installed Google Chrome binary instead of a bundled Chromium, giving it a real Chrome 148 TLS fingerprint and version stamp.

  • GitHub: github.com/Kaliiiiiiiiii-Vinyzu/patchright (3.2k stars, as of 2026-05-17)
  • License: Apache-2.0
  • In this bench because: it is the most actively maintained patched Playwright fork and the most technically credible alternative to vanilla Playwright.

Camoufox

Camoufox is a Firefox fork modified at the C level to spoof fingerprinting APIs (canvas, WebGL, screen geometry, navigator properties) using randomized but internally consistent values. Because it is Firefox-derived, its TLS handshake has a Firefox shape (a different cipher suite order than Chrome), which is detectable but also whitelisted on many targets that block Chrome-shaped automation.

  • GitHub: github.com/daijro/camoufox (8.4k stars, as of 2026-05-17)
  • License: MPL-2.0
  • In this bench because: Firefox-derived TLS is a genuinely different attack surface from the Chromium-based tools, and the question of whether that difference helps or hurts on production targets is worth measuring.

vanilla Playwright

Vanilla Playwright is the baseline. Chromium 147, no stealth patches, Microsoft’s official automation library. It does not attempt to hide that it is an automation tool. Its TLS handshake is a Chromium handshake, its CDP startup sequence is stock, and its navigator properties advertise webdriver: true unless patched.

  • GitHub: github.com/microsoft/playwright
  • License: Apache-2.0
  • Included as: the baseline every other browser has to beat.

rebrowser-playwright

rebrowser-playwright is a Playwright fork that applies CDP-leak patches similar to Patchright’s approach, but with a different patch strategy and different bundled Chromium version (136, which is twelve versions behind Patchright’s Chrome 148). The repository’s last code commit was September 2024 (the GitHub “pushed_at” of 2025-05-09 reflects a metadata-only touch), so it is effectively unmaintained.

  • GitHub: github.com/rebrowser/rebrowser-playwright
  • License: unspecified (no LICENSE file in the repo)
  • Reason for inclusion: it is the second major patched Playwright fork. The head-to-head with Patchright and vanilla was the direct question the bench was built to answer.

What I did

Seven browsers, 31 targets across four categories (JS-layer detection panels, TLS fingerprint endpoints, live Cloudflare and other anti-bot production sites, and high-traffic content sites that fingerprint quietly), three independent sweeps from one residential Mac Studio IP across one night. Headed mode, all free or already on hand. Full source and raw records at github.com/ianlpaterson/anti-detect-browser-bench.

Which browser wins the bench?

nodriver wins outright with zero blocked targets. Patchright, CloakBrowser, and Camoufox cluster in the middle. Vanilla and rebrowser tie at the bottom. Raw curl_cffi ties CloakBrowser at 26 OK: a 21-line wrapper performs identically to a Chromium fork with 49 source-level C++ patches.

The signal driving most disagreement is automation-protocol fingerprinting (anti-bot gates checking HOW the browser is being driven, not what the browser claims to be). nodriver wins because it drives Chrome over CDP directly, with no Playwright shim. Playwright leaves protocol-level traces that fingerprint-patch tools do not address.

Per-browser totals (identical across N=3)

651 records (217 cells × 3 runs), zero verdict drift across five hours from one residential IP.

Browser OK Gated Blocked Engine
nodriver 28 3 0 Google Chrome 148.0.7778.168 (system browser)
cloak 26 3 2 Chromium 145.0.7632.109
curl_baseline 26 3 2 curl_cffi 0.15.0 (impersonate=chrome)
patchright 25 3 3 Chrome 148.0.7778.168 (channel=chrome)
camofox 25 3 3 Firefox 135.0.1-beta.24 (camoufox)
vanilla 24 2 5 Chromium 147.0.7727.15
rebrowser 24 2 5 Chromium 136.0.7103.25 (rebrowser bundle v1169)

Per-target verdict matrix

Twenty-five of thirty-one targets agree across all seven browsers. The six that disagree are where the signal lives.

Target vanilla patch cloak camo rebro nodrv curl
amazon-product ok ok ok ok ok ok ok
booking-search ok ok ok ok ok ok ok
bot-incolumitas gated gated gated gated gated gated gated
browserleaks ok ok ok ok ok ok ok
browserleaks-tls ok ok ok ok ok ok ok
browserscan-bot ok ok ok ok ok ok ok
canadianinsider BLK BLK BLK BLK BLK ok BLK
ceo-ca ok ok ok ok ok ok ok
creepjs ok ok ok ok ok ok ok
crunchbase-cf ok ok ok ok ok ok ok
devto ok ok ok BLK ok ok ok
github-explore ok ok ok ok ok ok ok
glassdoor BLK BLK BLK BLK BLK gated BLK
google-search BLK BLK ok ok BLK ok ok
indeed-jobs ok ok ok ok ok ok ok
instagram-post ok ok ok ok ok ok ok
linkedin-jobs ok ok ok ok ok ok ok
medium BLK gated gated gated BLK ok gated
newsfilecorp ok ok ok ok ok ok ok
nowsecure-cf ok ok ok ok ok ok ok
pixelscan-bot ok ok ok ok ok ok ok
pixelscan-fp ok ok ok ok ok ok ok
rebrowser-detector ok ok ok ok ok ok ok
reddit ok ok ok ok ok ok ok
sannysoft ok ok ok ok ok ok ok
sedarplus gated gated gated gated gated gated gated
stackoverflow BLK ok ok ok BLK ok ok
stockwatch ok ok ok ok ok ok ok
tiktok-user ok ok ok ok ok ok ok
tls-peet ok ok ok ok ok ok ok
x-explore ok ok ok ok ok ok ok

Which six targets disagree across browsers?

canadianinsider: nodriver passes, every other browser hard-blocked. Six Chromium and Firefox stealth approaches fail the same Cloudflare-Turnstile-protected page, while Chrome 148 driven over plain CDP with no Playwright passes. I retried canadianinsider across all three sweeps to confirm nodriver wasn’t catching a brief Cloudflare window. The pass reproduced every time.

medium: nodriver alone passes OK. Patchright/Cloak/Camoufox/curl hit a Cloudflare interstitial, vanilla and rebrowser hard-blocked. Same axis as canadianinsider, softer landing.

glassdoor: nodriver gets a soft DataDome challenge, the other six hit a 403.

google-search: Cloak, Camoufox, nodriver, and curl_cffi pass. Patchright, vanilla, and rebrowser hard-block. Patchright joining the unpatched-browsers club is notable: the patches don’t address whatever this gate keys on.

dev.to: six browsers pass, Camoufox alone blocked, consistent with a Firefox TLS quirk the CDN flags.

stackoverflow: vanilla and rebrowser hard-blocked, every other browser passes. The clearest single-finding evidence that rebrowser’s CDP-leak patches do not change outcomes. rebrowser fails exactly where vanilla fails, on this one cell and across the rest of the matrix.

rebrowser-playwright vs vanilla Playwright: identical block sets

rebrowser-playwright and vanilla Playwright both score 24 OK, 2 gated, 5 blocked. Block sets identical: canadianinsider, medium, google-search, stackoverflow, glassdoor. On these 31 targets, rebrowser is functionally vanilla.

stackoverflow is the clearest evidence: vanilla and rebrowser both blocked while every other browser passes. One caveat: rebrowser ships Chromium 136, eleven versions behind vanilla’s Chromium 147 and twelve behind Patchright’s Chrome 148. Some of the identical-to-vanilla performance is plausibly a version effect.

Patchright vs vanilla Playwright: +1 OK, same google-search blind spot

Patchright is +1 OK and -2 blocked versus vanilla (25 vs 24 OK, 3 vs 5 blocked). The gain comes from stackoverflow. Patchright does not recover canadianinsider or google-search.

The channel=chrome flag matters as much as the patches: running system Chrome 148 delivers fingerprint protection at a layer no patch can replicate. I expected the patches to be the bigger lever. The matrix showed channel=chrome is.

Camoufox vs Patchright: tied at 25 OK, different failure modes

Camoufox runs Firefox 135.0.1-beta.24. Blocks: canadianinsider (every browser except nodriver fails), sedarplus (every browser fails, F5 BIG-IP ASM), and dev.to (only Camoufox fails, Firefox TLS quirk).

In the camoufox vs playwright comparison, Camoufox passes google-search where three Chromium-based browsers (including vanilla Playwright) block, and passes medium’s gate where vanilla and rebrowser are hard-blocked. The Firefox TLS shape loses on one cell (dev.to) and wins on one (google-search). When I started this bench I assumed Firefox would lose harder than it did on Chromium-shaped gates. It didn’t. The matrix driver is automation-protocol fingerprinting, not cipher lists.

curl_cffi vs CloakBrowser: identical scoreboards on 31 targets

26 OK, 2 blocked, 3 gated each. They share the same failures (canadianinsider, glassdoor) and the same gates (medium, sedarplus, bot-incolumitas), differing only in which specific cells fall where.

CloakBrowser is a 130MB Chromium fork with 49 C++ patches. curl_cffi is a 6.4MB Python wheel with a Chrome-shaped HTTPS stack. Same matrix result. I triple-checked the curl_baseline column because it reads like a typo. It isn’t. If a 21-line wrapper ties a 130MB patched fork, that fork is paying for something the matrix doesn’t measure.

Why is CloakBrowser’s macOS build stuck on Chromium 145?

The CloakBrowser darwin-arm64 build at version 0.3.28 ships Chromium 145.0.7632.109. CloakHQ’s GitHub releases page shows fourteen Linux and Windows releases since then, the most recent at 146.0.7680.177.4 on 2026-04-28. The macOS pipeline has been dead for two months.

The bench measures what’s actually shipping. The old version is the only version macOS users can install. rebrowser’s bundled Chromium 136 is the same story: twelve versions behind stable.

nodriver vs Playwright: why automation-protocol fingerprinting beats patches

nodriver passes canadianinsider while every patched Chromium fails it. nodriver connects to system Chrome’s DevTools port over a plain WebSocket, without Playwright’s accessibility layer, without the Runtime.enable and Target.setAutoAttach sequence Playwright issues at startup.

Why fingerprint patches don’t reach the protocol layer

The gate checks the protocol handshake the browser exposes on the way to rendering. Static fingerprints (TLS handshake, JA4 hash, navigator properties, canvas readback) are the wrong surface. CDP through Playwright leaves a recognizable shape. A fingerprint-patch tool can rewrite navigator properties all day without touching this layer.

canadianinsider, medium, and glassdoor confirm this across three vendors. Cloudflare on canadianinsider doesn’t look at the JS-runtime layer because the automation-protocol layer already gave the browser away. nodriver still gets gated on sedarplus, bot-incolumitas, and glassdoor (soft, not hard-blocked).

Why a residential proxy doesn’t help: shape coherence

The gate cross-checks layers for consistency. The Mac Studio is shape-coherent: residential British Columbia IP, macOS Chrome TLS handshake, macOS Chrome JavaScript fingerprints, macOS Chrome HTTP/2 SETTINGS frame ordering (each HTTP/2 client advertises tuning parameters in a predictable order that fingerprints the client library), all from the same host, with no mismatched signal for a gate to flag. A proxy only rewrites the source IP, and everything above TCP still leaks the real client.

Anti-bot signal Where it actually comes from Does a proxy fix it?
IP address (residential vs datacenter ASN) TCP source Yes
TLS / JA4 handshake fingerprint The HTTPS client No
HTTP/2 SETTINGS frame ordering The HTTPS client No
navigator.platform, navigator.userAgent The browser process No
Canvas / WebGL / audio fingerprints Browser process, host GPU, host fonts No
screen.width, screen.height, devicePixelRatio The browser process No
navigator.connection rtt + effectiveType Network conditions No (round-trip time gets worse through a proxy)

A Linux server behind a residential proxy manufactures a fresh contradiction the gate uses against it.

For HTTP-only scraping, the TLS layer alone is recoverable with curl_cffi. For JavaScript-rendered scraping, the browser process has to live on the host that owns the residential IP. There is no proxy shortcut that delivers macOS-shape JavaScript fingerprints from a Linux server. I tried a residential proxy in front of a Linux VPS during an earlier sweep, and every Cloudflare-protected target blocked it harder than the unproxied Mac Studio.

How the bench classifies each cell

Methodology lives in the bench repo at github.com/ianlpaterson/anti-detect-browser-bench. Highlights: a four-way verdict classifier (ok/gated/blocked/error) checking title regexes, body vendor signatures, and short-body shim pages. Each cell gets up to 3 attempts with early-exit on 2 consecutive matching non-error verdicts. The seven browsers run in randomized order each sweep to prevent reputation accumulation. Phase 6 wall clock was 5h11m across N=3 from 22:39:39 PT through 03:51:17 PT. Peak RSS ranged 57.9MB (curl_baseline) to 13306MB (Patchright). Eighty unit and regression tests cover the classifier, response-frame logic, retry logic, and the curl_baseline parser. The README has the full details.

What this bench can’t tell you

The matrix is one residential IP, one operating system, thirty-one targets, one night. Patterns that survived three independent runs are stable inside that frame. Outside it, several axes can flip the result.

Rotating proxies change the ranking

The techinz/browsers-benchmark repository tests with rotating residential proxies and up to 3 retries per cell. Their headline: Camoufox bypasses 100%, CloakBrowser 83.3% headed and 50.0% headless. The order is reversed from mine. Rotating proxies prevent IP reputation from accumulating against Camoufox’s identifiable Firefox fingerprint. My single-IP setup is the worst case for Camoufox in that one respect.

Targets shift mid-test

sedarplus.ca swapped anti-bot vendors mid-session during Phase 5: F5 BIG-IP ASM early, Radware Shieldsquare later, gated on every browser by Phase 6. A matrix is a snapshot, not a permanent fact. Cloudflare Turnstile is also site-state-dependent (the v2 stub reported all browsers failed nowsecure-cf, Phase 6 shows all pass).

Version effects masquerade as patch quality

Browser versions span Chrome 136 (rebrowser) to Chrome 148 (Patchright via channel=chrome and nodriver via system Chrome), with Firefox 135 (Camoufox) in the mix. Some apparent stealth is “this build happens to match what users have installed.”

The durable finding

Automation-protocol fingerprinting is a separate problem from TLS fingerprinting and JS-layer detection. The stealth-browser ecosystem is mostly solving the first two. Defeating the third requires a control plane that is not Playwright.

Which anti-detect browser should you use?

The most important decision happens before browser choice: identify which layer your target gates on. JS-fingerprint targets are where current Chromium passes unpatched. TLS-fingerprint targets reward Camoufox’s Firefox shape and curl_cffi’s impersonate=chrome about equally. Automation-protocol-fingerprinting targets are the cliff: Playwright forks fail regardless of patch quality.

If you’re scraping… Use Why
Cloudflare-gated production targets where canadianinsider matters nodriver The only browser on the matrix with zero blocked cells
A drop-in Playwright replacement and your stack is locked in Patchright with channel=chrome Real Chrome 148 + the smallest patch-quality risk
Sites that whitelist Firefox or fingerprint Chrome shape Camoufox Firefox 135 stealth, beats Chromium forks on google-search
HTML you can parse without JavaScript execution curl_cffi 26 of 31 targets in a 21-line wrapper, no browser process
A turnkey patched Chromium and you’ll write the cookie layer CloakBrowser Matches curl_baseline on this matrix, real product, real build chain

nodriver is the only browser through canadianinsider. Tradeoff: its asyncio object model requires an adapter layer in any Playwright codebase. AGPL-3.0 license has commercial implications worth reviewing with counsel.

Patchright with channel=chrome beats vanilla by one OK and unblocks stackoverflow by running system Chrome 148 instead of bundled Chromium.

Camoufox beats Chromium forks on google-search and medium’s gate but loses dev.to on a Firefox TLS quirk.

curl_cffi is pip install curl_cffi + requests.get(url, impersonate="chrome"). The TLS handshake defaults to Chrome 145/146 shape.

CloakBrowser is a real product with cookie handling and Turnstile auto-resolve worth paying for. Raw stealth headroom over curl_cffi is not supported by the data.

rebrowser-playwright posts the same OK set as vanilla and has had no real code commits since September 2024. Skip.

In production, I run nodriver for canadianinsider scraping, Patchright with channel=chrome everywhere else, and curl_cffi for the targets that don’t need JavaScript at all.

FAQ

What is automation-protocol fingerprinting and how does it differ from JA4 or JS-layer detection?

JA4 hashes the TLS handshake. JS-layer detection inspects navigator properties after the page loads. Automation-protocol fingerprinting sits between them, detecting the protocol shape used to drive the browser. Fingerprint patches do not reach this layer.

Why does nodriver pass canadianinsider when every patched Chromium fails?

nodriver drives system Chrome over a plain CDP connection with no Playwright in the loop, which removes the protocol-handshake shape the gate keys on at startup.

Can I just use a residential proxy with my existing Playwright on a VPS?

No. A proxy rewrites only the IP layer. TLS handshake, HTTP/2 frames, navigator properties, and canvas fingerprints all originate from the actual host. A Linux server behind a residential proxy still advertises a Linux-shape browser, which is the contradiction gates flag.

Is CloakBrowser actually no better than curl?

On 31 targets, OK counts are identical (26 each). CloakBrowser has features the matrix does not test: cookie handling, Turnstile auto-resolve, human-cursor modeling. For HTML parsing, curl_cffi is sufficient. For persistent browser sessions, Cloak is the better tool.

Did Cloudflare Turnstile pass for every browser? The v2 stub said no browser passed.

Yes, every browser passed nowsecure-cf in Phase 6. The v2 stub measured the same target two weeks earlier and got the opposite result. Turnstile is site-state-dependent. Treat any single-session result as transient.

What about rebrowser passing JS-layer detection panels its README highlights?

rebrowser passes browserscan-bot, pixelscan-bot, and rebrowser-detector. So does every other browser including vanilla. Those panels are saturated by current Chromium. The disagreement happens on production targets, where rebrowser fails identically to vanilla.

Should I run rotating residential proxies?

If your target list overlaps with mine, yes. Camoufox’s Firefox TLS fingerprint is identifiable on repeated single-IP hits, and rotation solves that. Proxies are a larger lever than browser choice for sustained workloads.

Why didn’t you include real Mozilla Firefox?

Manual Firefox 150 on canadianinsider passed Cloudflare Turnstile from a fresh private window. Selenium-driving the same Firefox with dom.webdriver.enabled=false got blocked. The gate keys on detectable automation, not Firefox itself.

What is the difference between Patchright and vanilla Playwright?

Patchright patches CDP-leak signals at startup and supports channel=chrome to drive system Chrome 148. On Phase 6 it scores +1 OK over vanilla (25 vs 24) and unblocks stackoverflow. The version advantage does as much work as the patches.

Does curl_cffi bypass Cloudflare?

Sometimes. On Phase 6 it passed 26 of 31 targets by replacing the HTTPS client stack with one shaped like current Chrome. It fails on canadianinsider, glassdoor, and any target requiring JavaScript execution.

What is JA4 fingerprinting?

JA4 hashes the TLS handshake: cipher suites, extensions, ALPN, and their order. Anti-bot services match that hash against known browser profiles. A headless-Chrome JA4 differs measurably from a real-Chrome JA4.

How does Cloudflare detect headless browsers?

Cloudflare layers signals: TLS handshake (JA3/JA4), HTTP/2 SETTINGS frame ordering, JavaScript runtime properties, behavioral patterns, and automation-protocol shape. The Phase 6 matrix shows automation-protocol shape is the layer most patched browsers ignore.

Is nodriver safe to use in production?

Functionally yes. nodriver is actively maintained and scored 28 of 31 with zero blocked cells. Caveats: its asyncio object model means no Playwright drop-in, cookies carry across targets by default, and AGPL-3.0 has commercial-license implications worth checking with counsel.

Does Patchright work with Cloudflare Turnstile?

Patchright passes some Cloudflare-gated targets but not canadianinsider or google-search in Phase 6 testing. It scores +1 OK over vanilla Playwright by recovering stackoverflow, but the CDP-leak patches do not address the automation-protocol layer that Cloudflare Turnstile keys on for its hardest challenges.

How do I install curl_cffi?

Run pip install curl_cffi. Then from curl_cffi import requests and requests.get(url, impersonate="chrome"). The impersonate="chrome" flag selects Chrome 145/146 TLS shape (curl_cffi 0.15.0). No browser binary required. The full library is 6.4MB.

Is nodriver a drop-in replacement for Playwright?

No. nodriver uses an asyncio object model incompatible with Playwright’s sync API and page/context/browser hierarchy. Migrating requires rewriting control flow, not just swapping the import. The payoff is zero Playwright in the protocol stack, which is what gets through canadianinsider and similar Cloudflare-Turnstile-protected targets.

Tools mentioned

  • nodriver (github) – Direct-CDP successor to undetected-chromedriver. No Playwright shim in the control plane. License: AGPL-3.0. Pricing: free.
  • CloakBrowser (github) – Patched Chromium fork with 49 source-level C++ fingerprint modifications. Drop-in Playwright API. License: MIT (wrapper), custom binary license. Pricing: free.
  • curl_cffi (docs | github) – Python HTTP client wrapping curl-impersonate. Spoofs TLS/JA4 fingerprints without a JS engine. License: MIT. Pricing: free.
  • Patchright (github) – Playwright fork that patches CDP-leak signals at startup. Supports channel=chrome for real Chrome TLS. License: Apache-2.0. Pricing: free.
  • Camoufox (site | github) – Firefox fork with C-level canvas/WebGL/navigator spoofing. Firefox TLS shape. License: MPL-2.0. Pricing: free.
  • Playwright (site | github) – Microsoft’s reference browser automation library. The unpatched baseline. License: Apache-2.0. Pricing: free.
  • rebrowser-playwright (github) – CDP-patch Playwright fork. Last code commit September 2024, Chromium 136. License: unspecified. Pricing: free.

Confessions of a Technical Lead: Building a DAO Without Losing My Sanity

As a Technical Lead, I’ve spent years architecting web applications, scaling APIs, and gently convincing engineers that yes, “microservices” is not a swear word. But recently, I took a detour into the wild, wild west of blockchain: building a DAO.

Yes, a DAO—a Decentralized Autonomous Organization, which is basically a company that runs itself… if you define “runs itself” loosely as “people vote on everything, including whether to fire the coffee machine.”

Here’s my story: a mix of tech, chaos, and a little existential crisis.

Step 1: Core Skills That Didn’t Prepare Me for This

When I started, I thought my experience would make this smooth sailing:

  • Backend architecture & APIs: Years of Django, Node.js, and GoLang had me feeling invincible. I was ready to build endpoints faster than my team could ask for documentation.
  • Frontend wizardry: React.js, Next.js, and TypeScript—check. I could make a dashboard that even my grandma would understand.
  • Cloud & DevOps: AWS, Azure, Docker, Kubernetes… basically, I can spin up an entire infrastructure while brewing coffee.
  • Blockchain basics: Solidity, smart contracts, Web3.js. I knew enough to be dangerous—but I didn’t realize I’d need more than “enough.”

So naturally, I dove headfirst into DAO territory. Mistake #1: assuming this was just another web app.

Step 2: The DAO Dilemma

A DAO isn’t like a regular product. There’s no CEO, no manager telling people to “stop merging broken PRs,” just a community voting on proposals. And let me tell you, explaining gas fees to non-technical voters is like teaching cats to code—they mostly stare at you and knock things over.

Our DAO’s mission was noble: build a community-governed platform for open-source contributions.

The reality? It was a masterclass in chaos:

  • Proposals: Everything needed a vote. Want to change the logo? Vote. Want to buy a coffee machine? Vote. Want to implement an optimization? Vote.
  • Smart contracts: Solidity became my new therapist. Each line of code could either secure $100k or burn it in one transaction.
  • Treasury management: Watching ETH balance fluctuate is like following your favorite crypto influencer—thrilling, terrifying, and slightly nauseating.

Step 3: Tech Stack That Saved My Soul

Thankfully, my backend and cloud skills weren’t useless. Here’s what actually worked:

  • Smart Contracts (Solidity): For voting, treasury, and token distribution. Security audits became my new bedtime reading.
  • Web3.js & Ethers.js: To interact with contracts without manually opening MetaMask for every vote.
  • Next.js + React: Dashboard for the community—who knew voters love charts and confetti for quorum achievements?
  • PostgreSQL & Redis: Off-chain storage for proposals and user activity. On-chain everything is expensive, so we selectively decentralized.
  • Docker & CI/CD pipelines: Deploying updates while the DAO is live is like defusing a bomb with one hand tied behind your back. Fun.

Step 4: Lessons Learned (and Laughs)

  1. Gas Fees Are Real Pain: Nothing teaches humility like paying $50 to approve a $5 proposal.
  2. Community Governance Is Chaotic, But Beautiful: I’ve seen strangers unite over code style debates. DAOs are messy—but sometimes, mess leads to genius.
  3. Automation is Your Friend: Webhooks, scripts, and bots saved us from drowning in votes and notifications.
  4. Technical Leads Need Patience: Explaining the difference between “immutable” and “can’t accidentally delete” three times is a workout for the soul.

Step 5: The Funny Side

Picture this:

  • One morning, I wake up to find a proposal to rename the DAO’s token to “CoffeeCoin.”
  • Another day, a smart contract bug sends a tiny fraction of funds to… my test wallet.
  • Weekly standups now include phrases like: “If this fails, the DAO will vote me out. Or burn the treasury. Possibly both.”

And yet, despite the chaos, there’s magic in watching people collaborate without a boss breathing down their necks.

Step 6: My TL;DR Advice for Fellow Devs

  • Master smart contracts—your backend experience only partially prepares you.
  • Treat governance like UX. If voting is confusing, no one will vote.
  • Automate everything you can. Bots are your DAO copilots.
  • Keep a sense of humor. You will need it.

Building a DAO as a Technical Lead is like juggling flaming swords while riding a unicycle… in a hurricane. You might get burned, fall, or crash spectacularly. But when it works? Oh, it’s glorious.

If you’re a dev looking for a new challenge, I highly recommend diving into a DAO. Just… keep a coffee nearby, maybe three. And don’t forget: every line of code could be a meme someday.

Core Skills Highlighted in This Journey:

  • Backend: Django, Node.js, GoLang
  • Frontend: React.js, Next.js, TypeScript
  • Cloud & DevOps: AWS, Azure, Docker, CI/CD, Kubernetes
  • Blockchain: Solidity, Web3.js, Ethers.js, Smart Contract Auditing
  • Databases: PostgreSQL, Redis
  • Soft Skills: Community management, governance UX, crisis handling