DEV Community

Cover image for My Screen Limit Has No Skip Button. To Get YouTube Back, I Have to Touch Grass
Sagar Maurya
Sagar Maurya

Posted on

My Screen Limit Has No Skip Button. To Get YouTube Back, I Have to Touch Grass

Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Submission ๐ŸŒฟ

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass

What I Built

I have a bad habit with screen-time apps. They show a "skip for today" button, and I press it. Every time.

So I built one with no skip button. Outside Leash lets me use YouTube and Reddit for 20 minutes a day. After that, the tab turns into a quest that reads like a text from a friend: "Find one weirdly colored thing outside and snap a pic of it." The only way back in is a photo from my phone that actually matches. If it does, my sites unlock for 30 minutes and the laptop jumps back to the page I was on.

Everything runs on my laptop: a Chrome extension, a small Python server, and Gemma 4 E2B through Ollama. 16 GB of RAM, no GPU, no cloud.

YouTube tab โ”€โ”€(20 min)โ”€โ”€> extension โ”€โ”€> localhost:8000 quest page
                                              โ”‚
phone adds a photo โ”€โ”€> Gemma 4 E2B checks it โ”€โ”˜
        โ”‚
        โ””โ”€โ”€ yes: sites unlock for 30 min, laptop jumps back
Enter fullscreen mode Exit fullscreen mode

Demo

In this video I set the limit to 1 minute instead of 20 so you don't have to wait.

1. The lock. The 20 minutes are up, and my tab turns into this.

The quest page on my laptop

2. The phone. I open the address on my phone, take a photo in my Camera app, and add it here.

The quest page on my phone

3. The pass. Gemma says yes, and the laptop unlocks by itself.

The passed screen on my phone

Code

GitHub logo mauryasagar / outside-leash

A screen limit you can't click past. Hit your limit, go outside, send a photo, get your sites back. Fully local with Gemma 4 E2B.

๐ŸŒฟ Outside Leash

A screen limit you can't click past. Hit your daily limit, go outside, send a photo, get your sites back.

Chrome extension ยท Python server ยท Gemma 4 E2B via Ollama ยท 100% local

Built for the Hacktoberfest Open-Source AI Challenge, Week 1: Touch Grass


Overview

After 20 minutes a day on YouTube, Reddit, Instagram, Facebook or X, the extension sends you to a quest page. You only get back in by sending a photo from your phone that matches the quest. Pass, and the sites unlock for 30 minutes.

Everything runs on your own laptop. No cloud and no API keys.

Screenshots

Quest page on the laptop
The quest page on the windows, with the address to open on your phone












Quest page on the phone Passed screen on the phone
On the phone, you add your photo Photo accepted, sites unlock for 30 minutes

How it works




flowchart TD
A["Browse YouTube, Reddit, etc."] --> B{"20 min used today?"}
B --
โ€ฆ





How I Built It

The lock

The extension wakes up every 30 seconds. It only counts time when the tab I'm looking at is a blocked site, and it keeps a per-day total.

used += TICK_SECONDS;
await chrome.storage.local.set({ used, day: today });
if (used < LIMIT_SECONDS) return;
Enter fullscreen mode Exit fullscreen mode

Past the limit, it asks my local server whether I've passed a quest recently. If not, it sends the tab to the quest page and remembers where I came from:

chrome.tabs.update(tab.id, {
  url: SERVER + "/?back=" + encodeURIComponent(tab.url)
});
Enter fullscreen mode Exit fullscreen mode

The quests

My first plan was to ask the model for both the quest and the question that checks the photo. It went badly. It kept giving me leaf quests, and some of its check questions were useless, like "is the photo clear?"

So I split the jobs. The code picks a random theme, the model only words the quest, and I wrote each check question by hand:

THEMES = [
    ("something that is a different colour from everything around it",
     "Is the main subject of the photo one object that "
     "clearly stands out in colour from everything around it?"),
    # ...five more
]
Enter fullscreen mode Exit fullscreen mode

That way the model can never make the check easier or harder than the quest. The first quests it wrote sounded like a form ("within a 10-minute walk during daylight"). I rewrote the prompt, and now they read like a text from a friend.

A quest also stays the same until I pass it, so refreshing the page won't get me an easier one.

The check

I tried Qwen3-VL 2B first. It took about 47 seconds per photo. Almost all of that was the model reading the image (about 1100 tokens), and shrinking the photo changed nothing.

Gemma 4 E2B took about 31 seconds at first, because it writes out its reasoning before it answers. With thinking turned off, it took about 3.4 seconds:

body = {
    "model": MODEL,
    "prompt": prompt,
    "stream": False,
    "think": False,
    "options": {"num_predict": max_tokens},
}
Enter fullscreen mode Exit fullscreen mode

The answer is just the first word, yes or no, so I only let it write 10 tokens.

Keeping myself honest

The server blocks photo uploads from the laptop, so I can't finish a quest by cheating from the same machine:

if ip in ("127.0.0.1", "::1") or ip == lan_ip():
    return self._send(403, json.dumps({
        "error": "Finish the quest from your phone, not this laptop."
    }))
Enter fullscreen mode Exit fullscreen mode

What Broke

The camera. Every time the page opened my phone's camera, the browser crashed with a "low memory" error. I closed every tab and it still happened. I added a gallery button, but that lets me upload any old photo. In the end I replaced both buttons with one "Add your photo" button. You take the photo in your Camera app first, and the page rejects anything older than 10 minutes:

const ageMin = (Date.now() - file.lastModified) / 60000;
if (ageMin > 10) {
  res.textContent = 'That photo is older than 10 minutes. Take a new one.';
  return;
}
Enter fullscreen mode Exit fullscreen mode

A check that was too loose. A pink flower passed an "old thing" quest. I rewrote the checks to ask about the main subject of the photo.

The spoof. I took a photo of a tree on a screen, and it passed. I tried two fixes:

  • Adding "if it's a screen, say no" to the question broke my real photo and still let the spoof through.
  • A separate "is this a screen" question caught both screens, but it also called my real old photo a screen.

I left both out. A check that locks me out of a real quest is worse than one that lets a spoof through.

I only tested with a handful of photos, so I don't have an accuracy number, and I won't make one up.

What It Can't Do

  • It can't tell where I am. I passed the colour quest with a pink cloth on the floor at home. The check only looks at the photo, so "go outside" is the quest, not something the code can enforce.
  • If I turn off the extension, the lock is gone.
  • The lock only works while the server is running.
  • A photo of a screen can still fool it.

It's a speed bump, not a vault. For me that's enough, because the point is to make me stop and stand up.

Why Does Open Innovation Matter?

  • My photos stay on my laptop. Quest photos show where I live and what's around me. Nothing in the code calls an outside server. The only traffic is my phone talking to my laptop on my home Wi-Fi.
  • Swapping models was a one-line change. I compared Qwen3-VL and Gemma by changing the model name. That comparison, plus turning off Gemma's thinking, took a 47-second check down to about 3 seconds.
  • It costs nothing per photo. A check that runs every time I get locked out would add up on a paid API.

I didn't test a hosted vision model, so I can't say it would be worse. It would probably catch more spoofs. What I'd give up is that every photo of my surroundings would go to someone else's server, with a bill attached.

Prize Categories

Best Use of Gemma. Gemma 4 E2B runs locally through Ollama, with thinking turned off so each check takes about 3 to 4 seconds.

Top comments (0)