diff --git a/CEO_ITERATION_LOG.md b/CEO_ITERATION_LOG.md new file mode 100644 index 0000000..ce46fc5 --- /dev/null +++ b/CEO_ITERATION_LOG.md @@ -0,0 +1,76 @@ +# CEO Iteration Log — TuneOut Incentive Audit +Started: 2026-03-03 + +## Iteration Framework +Run 100 iterations through this analysis: + +### 1. Map the Incentive Structure +What TuneOut actually is right now: A static landing page that reframes algorithmic feeds as a security threat and tells people to use LLMs + browser extensions as the fix. + +POSIWID - what does it actually do? It generates a moment of recognition in technically-minded people who already suspect feeds are bad. Then it gives them a checklist they mostly wont complete. The page itself is optimized for sharing. Its actual function is memetic, not behavioral. + +**Actors:** +- The reader who shares it - Gets status from sharing a smart take. Feels like action. Probably doesnt install LeechBlock. Incentive: signal intelligence and self-awareness to their network. +- The reader who acts on it - Already privacy-conscious, already considering blocking feeds. TuneOut gives them permission and a framework, but the tools section is a wall of options that creates decision paralysis. +- The algorithm - TuneOut says the algorithm wont share this. But outrage-framed content about algorithms IS the kind of content algorithms boost. The frame is self-defeating - if TuneOut goes viral, it went viral through the exact mechanism its warning about. +- You - Building credibility, building an audience, exploring a space. TuneOut functions as a positioning artifact for DiffLab/255bits. + +### 2. Inhabit the Actors +If I am someone who just read TuneOut and felt a jolt of recognition: +I share it. Maybe I install one extension. Within a week, Ive either disabled it or routed around it. The page gave me no ongoing relationship, no accountability, no system. It was a one-shot injection of awareness into a brain thats fighting a continuous feed. Awareness loses to environment every time. I already knew feeds were bad before I read this page. Knowing wasnt my problem. + +If I am a journalist or influencer who finds TuneOut: +Great hook. "Your brain is not a firewall" is quotable. I write about it, link it, move on. TuneOut gets a traffic spike, no conversion to behavior change, because theres nothing to convert to. + +If I am someone genuinely addicted to feeds: +I probably dont read a long-form landing page about cognitive security. The people who need TuneOut most are the ones least likely to engage with it. The format itself selects for people who are already partially free. + +### 3. Audit the Frame +TuneOuts own frame: "Algorithmic feeds are a cybersecurity problem. Install a filter." + +What would I have to believe? +- That framing feeds as a security threat changes behavior +- That tool recommendations drive adoption +- That awareness leads to action + +Is that believable? No. Every anti-smoking campaign, every "screen time is bad" article, every digital wellness app proves the same thing: awareness of harm doesnt change behavior when the competing incentive is immediate and the harm is diffuse. + +**The better frame:** The problem isnt that people lack information about feeds being bad. The problem is that quitting a feed leaves a vacuum with no replacement. People dont leave bad systems. They leave for better ones. TuneOut describes the "leave" but not the "for." + +### 4. Test the Core Claims +**Claim: "Put an LLM between you and the feed."** +Counterfactual: If this worked, the millions of ChatGPT users would already be using it for news instead of scrolling Twitter. They are not. Because the job isnt "get informed" - the job is "fill dead time with variable reward." An LLM summary does not scratch that itch. It is too clean, too resolved, too finished. No dopamine loop. + +Circularity check: TuneOut says "use AI to filter content" while being itself a piece of content competing for attention. It is using engagement tactics to tell people to stop engaging with content that uses those same tactics. + +**Claim: "Install these browser extensions and block the feeds."** + +### Who Actually Does This? +People with high executive function who are already close to quitting. TuneOut is pushing people over an edge they are already standing on. That is not nothing - but it is a narrow audience, and the impact is incremental. + +### 5. Where TuneOut Hits +- **The reframe is genuinely sticky.** "Your brain is not a firewall" and "algorithmic prompt injection" are excellent memes. They give technically-minded people a new lens that maps their existing cybersecurity intuitions onto a problem they felt but could not articulate. This is real and valuable. +- **Permission to act.** For the narrow band of people already wanting to change, TuneOut provides social proof and a framework. "I am not being weird, I am implementing cognitive security." That identity shift matters. +- **Credibility for DiffLab.** This positions you as someone thinking clearly about AI-human interaction. That is GTM value even if TuneOut itself does not scale. + +### 6. Where TuneOut Does Not Hit +- **Behavior change is zero for the median reader.** Static pages do not change habits. The page has no ongoing touchpoint, no feedback loop, no accountability mechanism. Read once, share maybe, forget. +- **The tools section is a wall.** Four OS tabs, dozens of tools, multi-step install instructions. Decision fatigue kills action. The people reading this needed ONE thing to do, not a catalog. +- **It preaches to the converted.** The format, length, and vocabulary self-select for people who already read long-form content about digital wellness. The feed-addicted never see it. +- **The LLM filter idea is unvalidated.** It sounds clean in a mockup. In practice, nobody is replacing their morning scroll with a Claude prompt. The behavior does not exist yet and TuneOut does not create it. + +### 7. The Structural Truth +TuneOut actual function is memetic, not behavioral. It spreads an idea. It does not change what people do. That is not worthless - ideas that reframe problems enable future products. But if the goal is impact measured in actual behavior change, TuneOut in its current form is a manifesto waiting for a mechanism. + +### 8. What Maximizes Impact +If impact means "most people actually change their relationship with algorithmic feeds": + +**Kill the tools section. Kill the checklist. Ship one thing.** + +**The one thing:** a browser extension that replaces your Twitter/Reddit/YouTube homepage with an LLM-generated briefing pulled from RSS sources you chose. Not "go to Claude and type a prompt." Not "install five extensions." One extension, zero configuration, instant replacement of the feed with something that serves you. + +**Open source it.** The extension IS the product that TuneOut describes but does not deliver. TuneOut becomes the landing page for the extension, not a standalone manifesto. + +**The mechanism:** You are not asking people to stop a behavior (impossible). You are replacing the behavior with a lower-friction alternative that occupies the same slot. They still open Twitter out of habit - but instead of a feed, they see a briefing. Same trigger, different reward. That is how you actually beat a dopamine loop. + +**That is the singular most impactful thing.** Not the page. The replacement behavior, shipped as a one-click install with TuneOut as the narrative wrapper. diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..bfa182a --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,127 @@ +# TuneOut - Deployment Guide + +## Domain Recommendation + +### Top Pick: `tuneouttoday.com` +- **Price:** ~$8.88/yr first year, ~$11.08/yr renewal (Porkbun) +- **Why:** Action-oriented (.com credibility, "Tune Out Today" = name + CTA), memorable, affordable +- **Register at:** [Porkbun](https://porkbun.com) (best transparent pricing, free WHOIS privacy) + +### Budget Pick: `tuneout.xyz` +- **Price:** ~$2.04/yr first year, ~$12.98/yr renewal (Porkbun) +- **Why:** Shortest URL, cheapest entry, tech-savvy audience will recognize .xyz + +### Alternative Picks (all likely available): +| Domain | Year 1 | Renewal | Notes | +|--------|--------|---------|-------| +| tuneouttoday.com | $8.88 | $11.08 | **Recommended** | +| algorithmhygiene.com | $8.88 | $11.08 | Descriptive, professional | +| attentionarmor.com | $8.88 | $11.08 | Alliterative, compelling | +| cognitive-defense.org | $6.88 | $10.74 | .org = mission credibility | +| tuneout.xyz | $2.04 | $12.98 | Cheapest entry | +| tuneout.co | $9.58 | $25.97 | Short but expensive renewal | + +### Taken (do not attempt): +- tuneout.com, tuneout.org, tuneout.net, cognitive-defense.com + +**Strategy:** Register `tuneouttoday.com` as primary ($8.88) + `tuneout.xyz` as redirect ($2.04) = ~$11 total for first year. + +--- + +## Deployment Options + +### Option 1: Cloudflare Pages (Free, Recommended) +```bash +# Install Wrangler CLI +npm install -g wrangler + +# Login +wrangler login + +# Deploy +cd ~/projects/tuneout +wrangler pages deploy . --project-name tuneout +``` +- Free tier: unlimited bandwidth, automatic HTTPS +- Custom domain: Add in Cloudflare Dashboard > Pages > Custom Domains +- Global CDN, no cold starts + +### Option 2: GitHub Pages (Free) +```bash +cd ~/projects/tuneout +git init +git add index.html +git commit -m "Initial deploy" +gh repo create tuneout --public --source=. --push + +# Enable Pages in repo settings: +# Settings > Pages > Source: Deploy from branch > main > / (root) +``` +- Free, automatic HTTPS for custom domains +- Custom domain: Add CNAME file with your domain, configure DNS + +### Option 3: Netlify (Free) +```bash +# Drag-and-drop deploy at app.netlify.com +# Or use CLI: +npm install -g netlify-cli +cd ~/projects/tuneout +netlify deploy --prod --dir=. +``` +- Free tier: 100GB bandwidth/month +- Custom domain in Netlify dashboard + +### Option 4: Simple VPS / Static Server +```bash +# If you have a VPS, just copy the file: +scp ~/projects/tuneout/index.html user@your-server:/var/www/tuneout/ + +# Nginx config: +# server { +# listen 80; +# server_name tuneouttoday.com; +# root /var/www/tuneout; +# index index.html; +# } +``` + +### Option 5: Vercel (Free) +```bash +npm install -g vercel +cd ~/projects/tuneout +vercel --prod +``` + +--- + +## DNS Configuration (after buying domain) + +For Cloudflare Pages / Netlify / Vercel: +1. Point nameservers to the hosting provider, OR +2. Add CNAME record: `www` -> `your-project.pages.dev` (or equivalent) +3. Add A record for root domain as directed by provider + +For GitHub Pages: +1. CNAME record: `www` -> `yourusername.github.io` +2. A records for apex: `185.199.108.153`, `185.199.109.153`, `185.199.110.153`, `185.199.111.153` + +--- + +## What's in the Box + +Single file: `index.html` (64KB) +- Zero dependencies (fonts loaded from Google Fonts CDN) +- All CSS and JS inline +- No build step required +- Mobile responsive +- Persistent checklist (localStorage) +- Scroll animations +- Interactive OS-specific tool guides +- LLM prompt examples with tabbed interface +- Share functionality (Twitter, clipboard, email) + +## Performance +- First paint: < 1s on 3G +- No JavaScript frameworks +- No tracking, no cookies, no analytics +- Lighthouse score: should be 95+ across all categories diff --git a/LINKEDIN_POST.md b/LINKEDIN_POST.md new file mode 100644 index 0000000..b5693ec --- /dev/null +++ b/LINKEDIN_POST.md @@ -0,0 +1,46 @@ +# LinkedIn Post — TuneOut Launch + +**Where to post:** LinkedIn (personal profile, not company page) +**Suggested hashtags:** #AI #ProductivityTools #OpenSource #BrowserExtension #DigitalWellness +**Best timing:** Tuesday–Thursday, 8–10am MT +**Format:** Text post with link to landing page in first comment (not in post body — LinkedIn suppresses external links in post text) + +--- + +## Post Copy + +I built a browser extension because I couldn't stop doomscrolling. + +Here's the thing — I run an AI company. I spend all day building agent loops and helping organizations adapt to AI. And I still catch myself 40 minutes deep in a Twitter feed, angry about something that doesn't affect me. + +So instead of relying on willpower (which loses every time), I built TuneOut. + +It does one thing: when you open Twitter, Reddit, or YouTube, it replaces the infinite scroll with a 3-minute AI briefing from RSS sources you chose. Same habit. Better feed. + +The insight is simple. You don't beat a dopamine loop by quitting. You beat it by replacing the reward. You still reach for the feed — but instead of outrage bait and engagement traps, you get a clean summary of what actually matters to you. Then you move on. + +Yes, I'm aware of the irony of posting about feed replacement on a feed. If this post kept you here longer than you intended — well, that's the point. + +TuneOut is free, open source, and takes 30 seconds to install. No accounts, no tracking, no data collection. And if you want the original feed back, there's a snooze button. No judgment. + +I've been using it for two weeks. My average Twitter session went from 35 minutes to under 4. Not because I have more discipline — because the loop changed. + +Built this as a side project at DiffLab.AI. It's the same approach we use with clients -- don't fight the process, redesign the loop. [Insert proof point: e.g. "One ops team cut a 6-hour daily review down to 40 minutes using the same pattern."] Find the agent architecture that creates 10x value, then ship it fast. + +Link in the first comment. + +--- + +## First Comment + +Try it out: [tuneouttoday.com] + +GitHub: [link to repo] + +It's a Manifest V3 Chrome/Firefox extension. Install takes 30 seconds. If you want to see the behavioral science behind it, that's on the landing page. + +Curious what your snooze-to-scroll ratio looks like after a week. + +## Second Comment (post ~30 min after first) + +If you're thinking about where agent loops could transform your team's workflows — not just feeds, but any repetitive process where AI can intercept and improve the outcome — DM me or book 15 min at [difflab.ai/contact]. diff --git a/NATHAN_MESSAGING_STRATEGY.md b/NATHAN_MESSAGING_STRATEGY.md new file mode 100644 index 0000000..be6ae4e --- /dev/null +++ b/NATHAN_MESSAGING_STRATEGY.md @@ -0,0 +1,339 @@ +# TuneOut Messaging Strategy +**Author:** Nathan Calloway, Founding Product Lead, DiffLab.AI +**Date:** 2026-03-07 +**Status:** Ready for CEO review + +--- + +## Executive Summary + +The current TuneOut landing page uses a confrontational cybersecurity metaphor ("Your Brain Is Not A Firewall," "You Lost Control") that assumes the reader already identifies as having a problem. The CEO iteration log correctly diagnoses why this fails: it preaches to the converted, triggers defensiveness, frames AI as the enemy while selling an AI solution, and misses the people who most need it. + +This document lays out a complete messaging reframe. The strategic shift: from "you have a problem, fight it" to "you deserve a better deal from your information diet." TuneOut is not anti-AI or anti-feed. TuneOut is the version of being connected that actually respects what you came for. + +--- + +## 1. Positioning Statement (April Dunford Framework) + +**For** knowledge workers and curious people who want to stay informed and connected online, +**who are dissatisfied with** how much time and emotional energy algorithmic feeds consume relative to the value they deliver, +**TuneOut is a** browser extension +**that** replaces social media feeds with curated, LLM-summarized briefings from sources you choose. +**Unlike** feed blockers, willpower apps, or digital detox programs, +**TuneOut** keeps the habit and the reward intact while removing the infinite scroll, giving you the connection without the cost. + +**One-line positioning:** TuneOut is the upgrade from algorithmic feeds to intentional briefings -- same habit, better deal. + +--- + +## 2. Headline and Subheadline Options + +### Option A (Recommended): The Upgrade Frame + +**Headline:** Same Habit. Better Feed. + +**Subheadline:** You open Twitter, Reddit, or YouTube dozens of times a day. TuneOut replaces the infinite scroll with a 3-minute briefing from sources you actually chose. Stay informed. Stop doomscrolling. + +**Why this works:** No accusation. No shame. It meets the reader in the behavior they already have and offers a strict upgrade. "Same habit" removes the willpower barrier. "Better feed" implies the current one is suboptimal without saying "you are broken." It is also dead simple. + +--- + +### Option B: The Intentionality Frame + +**Headline:** Choose What Informs You + +**Subheadline:** Algorithmic feeds show you what keeps you scrolling. TuneOut shows you what you actually asked for -- curated RSS sources, summarized by AI, delivered the moment you reach for a feed. + +**Why this works:** Positions the reader as someone with agency making a choice, not someone with a problem being fixed. "Choose" is active and empowering. The contrast between "what keeps you scrolling" and "what you asked for" names the issue without shame. + +--- + +### Option C: The Time-Value Frame + +**Headline:** Get Informed in 3 Minutes, Not 30 + +**Subheadline:** Every time you open a social feed, TuneOut replaces it with a briefing from sources you trust. Same trigger, no rabbit hole. Your morning scroll becomes a morning brief. + +**Why this works:** Leads with the concrete value proposition -- time savings. "3 minutes, not 30" is specific and testable. "Morning scroll becomes a morning brief" gives the reader an immediate mental image of the behavior change. + +--- + +### Ranking Rationale + +Option A is the strongest because it does the most work in the fewest words. "Same Habit. Better Feed." immediately communicates that this is not about quitting anything. It is an upgrade. That single reframe neutralizes the two biggest objections: "I don't have a problem" and "I don't want to give up being connected." + +Option C is the strongest runner-up for paid acquisition and performance marketing because it leads with a measurable outcome. + +Option B is the strongest for an audience that already self-identifies as intentional about technology use (early adopters, productivity community). + +--- + +## 3. The "Why Now" Story + +### AI Is Getting Better at Holding Your Attention. That Is Not Going to Stop. + +Every quarter, the algorithms that power social feeds get meaningfully better at predicting what will keep you engaged. Not informed. Not satisfied. Engaged. This is not a conspiracy -- it is the literal optimization function. Engagement equals ad revenue. The AI serving your feed has one job, and it is getting exponentially better at that job. + +Here is what changed in the last 18 months: + +- Generative AI now creates engagement-optimized content at scale, flooding feeds with material specifically designed to trigger interaction +- Recommendation algorithms now incorporate real-time behavioral signals (scroll speed, pause duration, micro-expressions via camera on some platforms) to personalize engagement traps at an individual level +- The gap between "content that informs you" and "content that holds you" is widening, not narrowing + +**This is the moment to be intentional about which AI serves your feed.** + +You already have an AI choosing what you see. The question is whether that AI works for the platform's engagement metrics or for your actual goals. TuneOut is the answer: an AI that works for you, pulling from sources you chose, summarizing what matters, and getting out of the way. + +The window for making this choice consciously is now. The longer you wait, the better the engagement AI gets, and the harder the switch becomes. Not because of addiction -- because of habit depth. Every day the current pattern runs, it gets more automatic. + +**Narrative arc for the landing page:** + +1. You already use AI every day -- it is called your feed's algorithm +2. That AI is getting better, fast, at one thing: keeping you scrolling +3. TuneOut puts a different AI in that slot -- one that works for what you actually want +4. Same habit trigger, different outcome: informed in minutes instead of lost for an hour + +--- + +## 4. Objection Handling + +### "I don't have a problem with social media." + +**Response frame:** You probably don't. Most people get real value from being connected. TuneOut is not for people with a problem. It is for people who want a better ratio of value to time. If you open Twitter to check what is happening and 40 minutes later you are still scrolling, that is not a problem -- it is a design choice someone else made about your time. TuneOut gives you a different design choice. + +**Key phrase to use:** "It is not about having a problem. It is about getting a better deal." + +--- + +### "I can just close the app when I want to." + +**Response frame:** Of course you can. And most of the time you do. But "most of the time" is doing a lot of work. The feed is designed for the times you don't -- the tired moments, the bored moments, the 10pm-on-the-couch moments. TuneOut does not require willpower because it works at the environment level, not the decision level. The feed is simply replaced before you see it. + +**Key phrase to use:** "TuneOut works in the moments your willpower doesn't." + +--- + +### "I'll just disable it after a week." + +**Response frame:** You might. But there is a reason TuneOut has a snooze button instead of making you feel guilty. Any time you want the real feed, you tap snooze and it is there. No judgment. The difference is that "snooze to scroll" is a conscious choice, while "open Twitter and fall into a feed" is an automatic one. Most people find they snooze less over time -- not because of discipline, but because the briefing genuinely gives them what they came for. + +**Key phrase to use:** "The snooze button is there for a reason. Use it whenever you want." + +--- + +### "RSS is old technology. Why would I go back to that?" + +**Response frame:** RSS is the infrastructure. The experience is an AI-curated briefing. You pick the sources. The LLM reads everything and gives you a summary tailored to your interests. It is not 2008-era Google Reader. It is a personal news intelligence layer that happens to use RSS as its data source because RSS cannot be gamed by engagement algorithms. + +**Key phrase to use:** "You are not going back to RSS. You are going forward to AI briefings from sources algorithms cannot manipulate." + +--- + +### "I need social media for work / networking / staying in the loop." + +**Response frame:** TuneOut does not block social media. It replaces the feed -- the homepage infinite scroll. All your direct messages, notifications, and intentional searches still work. You can still tweet, post, and reply. What changes is the experience of opening the app out of habit and losing 30 minutes to content you did not choose. The parts of social media that serve you are untouched. + +**Key phrase to use:** "TuneOut replaces the feed, not the platform." + +--- + +## 5. Voice and Tone Guidelines + +### Core Principles + +**Peer-to-peer, not preachy.** We are in the same situation as the reader. We scroll too. We lose time too. We are not enlightened beings dispensing wisdom. We built a tool because we wanted it ourselves. + +**Empathetic, not diagnostic.** Never imply the reader is broken, addicted, or making bad choices. The feeds are well-designed. Falling into them is not a character flaw -- it is the intended outcome of billions of dollars of optimization. + +**Concrete, not abstract.** Instead of "reclaim your attention," say "get informed in 3 minutes instead of 30." Instead of "take back control," say "see a briefing instead of a feed." Specificity builds trust. Abstraction sounds like marketing. + +**Calm confidence, not urgency.** No countdown timers. No "act now." No manufactured scarcity. The reader is making a considered decision about how they spend their attention. Respect that. + +**Pro-AI, not anti-AI.** TuneOut uses AI. We are not Luddites. The frame is not "AI is bad" -- it is "you should choose which AI shapes your information diet." This is about intentionality, not rejection. + +### Words and Phrases to Use +- "Briefing" (not "content" or "digest") +- "Sources you chose" (not "curated content") +- "Replace the feed" (not "block social media") +- "Informed in minutes" (not "reclaim your time") +- "Same habit, better outcome" (not "break the habit") +- "Intentional" (not "disciplined" or "controlled") +- "Upgrade" (not "fix" or "cure") + +### Words and Phrases to Avoid +- "Addiction" / "addicted" / "hooked" +- "Lost control" / "take back control" +- "Fight" / "battle" / "war" +- "Toxic" / "poison" / "harmful" +- "Firewall" / "shield" / "defense" +- "Wake up" / "open your eyes" +- "You don't realize..." +- Any framing that positions the reader as a victim or a patient +- Angry/warning emojis as visual elements + +### Tone Spectrum + +| Situation | Tone | +|-----------|------| +| Hero section | Confident and inviting. Like a friend recommending a restaurant. | +| Feature descriptions | Matter-of-fact. What it does, how it works, why that matters. | +| The "why now" section | Informed and straightforward. Here are the facts; draw your own conclusion. | +| CTAs | Warm and low-pressure. "Try it" not "Act now." | +| Objection handling (FAQ) | Honest and non-defensive. Acknowledge the objection, then reframe. | + +--- + +## 6. Suggested Page Copy + +### Hero Section + +``` +[No label badge. Clean entry.] + +Headline: +Same Habit. Better Feed. + +Subheadline: +You open social media dozens of times a day. TuneOut replaces the +infinite scroll with a 3-minute briefing from sources you actually +chose. Stay informed without losing your afternoon. + +CTA Primary: Try TuneOut (Free) +CTA Secondary: See How It Works +``` + +**Visual direction:** Replace the angry-emoji-attacking-brain animation with something that communicates transformation, not conflict. Consider a simple split-screen or before/after: left side shows a blurred infinite scroll, right side shows a clean, calm briefing card. The visual metaphor should be "upgrade," not "battle." + +--- + +### First Scroll Section: "How It Works" + +``` +Section title: How It Works +Section subtitle: TuneOut uses habit replacement, not willpower. + +Step 1: You reach for the feed +The same muscle memory you already have. Twitter, Reddit, YouTube -- +open it like you always do. + +Step 2: TuneOut steps in +Before the infinite scroll loads, TuneOut replaces it with your +personal briefing. Sources you picked, optionally summarized by +an LLM. + +Step 3: You get what you came for +News, updates, ideas -- from sources you trust, read in 3 minutes. +No rabbit holes. No outrage bait. No algorithmic surprises. + +Step 4: You move on +You came, you read, you're done. The rest of your day is yours. +And if you want the original feed? Tap snooze. No judgment. +``` + +--- + +### Second Scroll Section: "Why This, Why Now" + +``` +Section title: The AI Serving Your Feed Is Getting Better Every Quarter +Section subtitle: The question is whether it works for you or for +an engagement metric. + +Card 1: Your feed already uses AI +Every major platform uses machine learning to decide what you see +next. That AI has one goal: maximize the time you spend on the +platform. Not maximize how informed you feel. Not maximize your +satisfaction after closing the app. + +Card 2: That AI is getting better, fast +Generative content, real-time behavioral signals, and +hyper-personalized recommendations mean feeds are more engaging +than ever. "Engaging" is a polite word for "hard to leave." + +Card 3: TuneOut is a different AI in the same slot +Same moment -- you reaching for a feed. Different AI serving +the result. One that pulls from RSS sources you chose and +summarizes what matters. An AI that has no engagement metric. +Its only job is to inform you and get out of the way. +``` + +--- + +### CTA Buttons (Across the Page) + +| Location | Primary CTA | Secondary CTA | +|----------|-------------|---------------| +| Hero | Try TuneOut (Free) | See How It Works | +| After "How It Works" | Install the Extension | View on GitHub | +| After "Why Now" | Try It For a Week | Read the FAQ | +| Footer | Get TuneOut | -- | + +**CTA principles:** +- Always include "(Free)" or "Free and open source" near the primary CTA at least once. Removes friction. +- Never use urgency language ("Don't wait," "Start now," "Before it's too late"). +- The secondary CTA should always offer more information, not pressure. +- "Try" is better than "Get" or "Start" because it implies low commitment. + +--- + +## 7. Implementation Notes + +### What to Keep from the Current Pages + +The **extension landing page** (`ada-dispatch/tuneout/landing/index.html`) is actually much closer to the right tone than the main site. Its tagline "Replace social media feeds with curated LLM briefings. Same trigger, better reward." is strong. The Duhigg quote about habit replacement is well-placed. The step-by-step walkthrough is clear and concrete. This page should be the tonal baseline, not the main site. + +### What to Cut from the Main Site + +- The entire "You Lost Control" label and confrontational hero +- The angry emoji attack animation +- The "You're Paying With Your Best Hours" shame section +- All cybersecurity metaphor language (firewall, shield, attacks) +- The "No Algorithm Will Share This" closing (positions us as fringe/conspiratorial) +- Statistics used as weapons ("62% more reach," "2.3% per negative word") -- these inform but also accuse +- The "Seven Moves. Full Control." checklist -- too much to do, creates decision paralysis (per the CEO log) + +### What to Build + +- A single, clean hero with the new headline and a non-confrontational visual +- A 4-step "how it works" section (keep what the extension page already does well) +- A "why now" section that frames the AI arms race as context, not threat +- A brief FAQ that handles the objections listed in Section 4 +- A single, clear install path -- one CTA, one action, one outcome + +### Meta Tags Update + +``` +title: TuneOut -- Same Habit. Better Feed. +description: Replace infinite scroll with a 3-minute AI briefing from +sources you chose. Free browser extension. No accounts, no tracking. +og:description: You open social media dozens of times a day. TuneOut +replaces the feed with a briefing from sources you actually chose. +``` + +--- + +## 8. Success Metrics for the New Messaging + +Once the new page ships, measure: + +1. **Scroll depth** -- Are people reading past the hero? (Current confrontational frame may cause early bounce from people who feel accused.) +2. **CTA click rate** -- Primary CTA clicks as a percentage of unique visitors. +3. **Extension installs** -- The only metric that ultimately matters. +4. **Snooze-to-scroll ratio after install** -- Do users stick with the briefing or bypass it? This tells us if the product delivers on the messaging promise. +5. **Share language** -- When people share TuneOut, what do they say? If they use shame/fear language, we have not successfully reframed. If they use "upgrade" or "better feed" language, the positioning landed. + +--- + +## Summary of the Strategic Shift + +| Dimension | Old Frame | New Frame | +|-----------|-----------|-----------| +| Core metaphor | Cybersecurity threat | Upgrade to a better deal | +| Reader identity | Victim of manipulation | Intentional person making a choice | +| AI's role | The enemy attacking your brain | A tool -- the question is which one serves you | +| Emotional register | Fear, shame, urgency | Confidence, clarity, invitation | +| Call to action | "Take it back" (implies loss) | "Try it" (implies opportunity) | +| Relationship to feeds | Adversarial (block, fight, defend) | Replacement (same slot, better content) | +| Implied audience | People who know they have a problem | People who want a better ratio of value to time | + +The single most important shift: **stop asking people to admit they have a problem and start offering them something better.** That is the difference between a manifesto and a product. diff --git a/NOVA_TECH_ASSESSMENT.md b/NOVA_TECH_ASSESSMENT.md new file mode 100644 index 0000000..333ccb8 --- /dev/null +++ b/NOVA_TECH_ASSESSMENT.md @@ -0,0 +1,195 @@ +# TuneOut Landing Page: Technical Assessment + +**Author:** Nova Blackthorne, CTO +**Date:** 2026-03-07 +**Scope:** Hero/splash rework feasibility, animation replacement, performance, design convergence + +--- + +## 1. Hero Separability: Can We Rework It Without Breaking Everything? + +**Short answer: Yes, cleanly.** + +The hero section (lines 536-575) is structurally isolated. It lives inside `
` and has no DOM dependencies on downstream sections. The CSS for the hero and its sub-components is grouped in one block (lines 120-199 in the stylesheet). The JS that drives it is equally contained: + +- **Particle system** (lines 1312-1322): Generates 30 `.particle` divs inside `#particles`. Self-contained. Removing the `
` element and its CSS/JS block is a clean cut. +- **Shield toggle** (lines 1296-1310): `setInterval` toggling `.fw-shield.active` and swapping the label text. Self-contained. No other section references `fwShield` or `fwLabel`. +- **Attack animation** (lines 170-184): Pure CSS `@keyframes attack-fly` on `.fw-attack` elements. No JS involvement. Delete the keyframe, the elements, and the CSS rules -- nothing else breaks. + +**What to watch out for:** + +- The `.hero-grid` layout (2-column on desktop, 1-column on mobile) is shared nowhere else. Safe to restructure. +- The `.btn` and `.btn-primary` / `.btn-secondary` classes ARE shared with the rest of the page (solution section CTA, etc). Do not change these globally when reworking the hero. Scope any new button styles to `.hero .btn-*` if needed. +- The `.section-label` and `.label-danger` classes used in the hero tag ("// You Lost Control") are also used in other sections. Again, do not modify globally. +- The `--gradient-hero` CSS variable is only used by `.hero`. Safe to change. +- The `--gradient-danger` variable IS used by `.hero-text h1 .highlight` AND by `.attack-card::before` in the problem section. If you change the gradient for the hero headline, scope it or use a separate class. + +**Recommended approach:** Replace the inner content of `
` wholesale. Keep the outer `
` tag and its `id="hero"` (the nav links to it). Delete the corresponding CSS block and JS block, replace with new ones. The rest of the page does not care. + +--- + +## 2. Warm Animation Replacements + +The CEO is right that the current visual language is combative. Attack emojis flying at a brain, a "danger" gradient on the headline, "// You Lost Control" as the opening line -- it positions the user as a victim under siege. That works for a certain audience but alienates people who just feel vaguely uneasy about their screen time. + +Here are concrete, implementable alternatives that maintain visual interest without the threat aesthetic: + +### A. Breathing Circle (recommended) + +A single, centered circle that slowly expands and contracts on a 4-second cycle (inhale/exhale). CSS-only, no JS required. + +```css +.hero-breathe { + width: 120px; + height: 120px; + border-radius: 50%; + background: radial-gradient(circle, rgba(100, 140, 200, 0.15), transparent); + border: 1.5px solid rgba(100, 140, 200, 0.3); + animation: breathe 4s ease-in-out infinite; +} + +@keyframes breathe { + 0%, 100% { transform: scale(1); opacity: 0.7; } + 50% { transform: scale(1.15); opacity: 1; } +} +``` + +This communicates "calm awareness" directly. It is also the signature animation of the "one sec" app already mentioned in the Tools section, creating thematic consistency. + +### B. Soft Gradient Drift + +Replace the static `--gradient-hero` with a slowly shifting background. Two or three muted color stops that rotate position over 20-30 seconds. Feels alive without demanding attention. + +```css +.hero { + background: linear-gradient(135deg, #1a1a2e, #0f1f2e, #1a1a2e); + background-size: 300% 300%; + animation: gradient-drift 20s ease infinite; +} + +@keyframes gradient-drift { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} +``` + +### C. Gentle Fade-In Sequence + +Instead of particles and flying emojis, have the hero text elements fade in sequentially with staggered delays. Tagline fades in, then headline, then subtitle, then CTA. Total sequence: 1.5-2 seconds. Simple, elegant, proven to increase perceived quality. + +```css +.hero-text > * { + opacity: 0; + transform: translateY(12px); + animation: gentle-enter 0.6s ease forwards; +} +.hero-text > :nth-child(1) { animation-delay: 0.1s; } +.hero-text > :nth-child(2) { animation-delay: 0.3s; } +.hero-text > :nth-child(3) { animation-delay: 0.5s; } +.hero-text > :nth-child(4) { animation-delay: 0.7s; } + +@keyframes gentle-enter { + to { opacity: 1; transform: translateY(0); } +} +``` + +### D. What NOT to Do + +- Do not add Lottie or any animation library. The current page has zero dependencies and that is a feature. +- Do not add a video background. Bandwidth cost, autoplay issues on mobile, accessibility problems. +- Do not add scroll-triggered hero animations beyond the initial entrance. The hero should be fully rendered by the time the user sees it. + +**My recommendation:** Combine B (gradient drift background) with C (staggered text fade-in) and optionally A (breathing circle as the single visual element replacing the entire firewall diagram). Kill the particle system entirely. Net result: fewer DOM elements, less JS, calmer tone. + +--- + +## 3. Performance Assessment + +### Current State + +- **File size:** 66.5KB for a single HTML file. Not a crisis, but heavier than it needs to be. +- **Font loading:** Two Google Fonts families (Inter at 5 weights + JetBrains Mono at 4 weights). This is the real performance cost. Each weight is a separate network request or a larger variable font download. On a cold cache, this adds 200-400ms on decent connections, much more on mobile. +- **Particle system:** 30 DOM elements with continuous CSS animations. On most devices this is fine, but on low-end mobile it causes unnecessary compositing work. Each particle triggers `transform` animations that force GPU layer promotion. 30 layers for a decorative effect is wasteful. +- **Intersection Observer:** Well-implemented, threshold 0.1, reasonable rootMargin. No concerns. +- **setInterval for shield toggle:** 4-second interval, negligible cost. But it runs forever, even when the hero is scrolled out of view. Minor, but sloppy. +- **No image assets:** This is genuinely good. Zero image requests. The emoji-based visuals are clever and zero-cost. +- **No external JS dependencies:** Also good. Vanilla JS throughout. + +### What to Fix + +1. **Fonts:** Drop JetBrains Mono. It is used for tiny labels (`.section-label`, `.stat-source`, `.tool-steps code`). System monospace is fine for these. That alone saves 40-80KB of font downloads and 2-4 network requests. If Inter is important to the brand, keep it but limit to 3 weights (400, 600, 700). + +2. **Kill the particle system.** It serves no communication purpose and costs 30 extra DOM nodes plus continuous animation. Replace with nothing, or with the gradient drift which is a single CSS property animation on an existing element. + +3. **Lazy-load the Intersection Observer targets.** Currently all `.fade-in` elements are observed immediately on page load. This is fine for the current page size but will not scale if more sections are added. + +4. **The `overflow-x: hidden` on body** (line 47) is a code smell. It usually means something is overflowing horizontally and the developer papered over it rather than fixing the root cause. Worth investigating whether the particle container or the hero visual is the culprit. If so, scope the `overflow: hidden` to `.hero` only. + +### What Is Fine + +- 66KB inline HTML is not a problem for a single-page landing. It compresses to roughly 12-15KB gzipped. Any modern server handles this. +- No build system is the correct choice. Do not add one. Webpack/Vite/etc for a single landing page is pure overhead. +- Inline CSS/JS means a single network request for the entire page. This is faster than splitting into separate files for a page this size. + +--- + +## 4. Design Convergence: Main Site vs. Extension Landing Page + +### The Two Pages + +| Aspect | Main site (`projects/tuneout/index.html`) | Extension landing (`ada-dispatch/tuneout/landing/index.html`) | +|---|---|---| +| Size | 66.5KB | 13.4KB | +| Aesthetic | Dark, cybersecurity, gradients, aggressive | Light/dark adaptive, minimal, calm | +| Fonts | Inter + JetBrains Mono (Google Fonts) | System font stack only | +| JS | Particles, observers, tabs, checklist, share | 12 lines (extension detection) | +| Tone | "You Lost Control" / "Your Brain Is Not A Firewall" | "Replace Feeds, Not Habits" | +| Dependencies | Google Fonts CDN | Zero | +| Color scheme | Fixed dark mode | `prefers-color-scheme` adaptive | + +### Should They Converge? + +Yes, but converge TOWARD the extension page's design language, not the main site's. + +The extension landing page is better in almost every dimension that matters for conversion: + +1. **Tone matches the product.** TuneOut is about calm, intentional information consumption. The extension page feels like that. The main site feels like a security product marketing page. + +2. **Performance.** 13KB vs 66KB. Zero external requests vs Google Fonts CDN. The extension page loads instantly. + +3. **Readability.** The extension page uses system fonts, good line-height, adequate contrast in both light and dark modes. The main page has light-on-dark text with decorative gradients competing for attention -- ironic for a product about reducing attention manipulation. + +4. **Adaptability.** `prefers-color-scheme` support is table stakes in 2026. The main site forces dark mode on everyone. + +### Convergence Plan + +I would not merge the two pages into one codebase. They serve different contexts (marketing site vs. in-extension onboarding). But the design language should be unified: + +1. **Adopt the extension page's color system** as the base. Muted backgrounds, high-contrast text, minimal accent colors. Add `prefers-color-scheme` dark mode support to the main site. + +2. **Adopt the extension page's typography.** System font stack. Drop Google Fonts entirely. If branding requires a specific typeface, self-host a single weight of a single font. + +3. **Keep the main site's content depth** (problem/science/solution/tools/checklist structure is genuinely strong) but wrap it in the calmer visual language. + +4. **Keep the main site's interactivity** (tabs, checklist with localStorage, share buttons) because these drive engagement and conversion. The extension page does not need these because its CTA is simpler (open settings). + +5. **Shared CSS variables.** Extract the color palette and spacing scale into a shared set of CSS custom properties that both pages use. This does not require a build system -- just copy-paste the `:root` block. + +--- + +## Summary: Recommended Next Steps + +1. **Rework the hero.** Replace the attack animation with staggered text fade-in + gradient drift background. Kill particles. Change the label from "// You Lost Control" to something empathetic ("// Your attention matters" or similar -- CEO's call on copy). Change the headline from combative to invitational. Keep the two CTA buttons. + +2. **Drop Google Fonts.** Switch to system font stack. Saves 200-400ms of load time and eliminates an external dependency. + +3. **Add `prefers-color-scheme` support.** The dark-only aesthetic is a choice that excludes users. Match the extension page's adaptive approach. + +4. **Do not add a build system.** The single-file approach is correct for this use case. + +5. **Scope the rework to the hero first.** Ship it. Measure. Then decide whether the rest of the page needs the same tonal shift. Do not boil the ocean. + +--- + +*Assessment complete. Ready to implement on your go.* diff --git a/PIERRE_UX_BRIEF.md b/PIERRE_UX_BRIEF.md new file mode 100644 index 0000000..cf7e03d --- /dev/null +++ b/PIERRE_UX_BRIEF.md @@ -0,0 +1,192 @@ +# TuneOut Hero Section -- UX Brief +**Author:** Pierre Gargouille, UX Designer, DiffLab.AI +**Date:** 2026-03-07 + +--- + +## Diagnosis + +The current hero operates on a shame-confrontation model: + +- Label: "// You Lost Control" +- Headline: "Your Brain Is Not A Firewall" +- Subtext: "You wouldn't let a stranger set your agenda..." +- Visual: Angry emojis and attack vectors flying at a brain +- CTAs: "Take It Back" / "See What You're Losing" +- Color: Red gradient accent on dark cybersecurity backdrop + +Every element says: *you are a victim and you don't even know it.* + +The people most likely to encounter TuneOut are already deeply engaged with AI tools. They talk to Claude. They build with GPT. They curate their own Twitter lists. They are sophisticated. Telling them they "lost control" triggers identity defense, not curiosity. The page talks past its audience. + +The extension landing page (ada-dispatch version) already found a better posture: "Replace Feeds, Not Habits." Clean, neutral, functional. But it swings too far toward utility -- it reads like documentation, not a moment of recognition. + +The hero needs to land between these two extremes. Not an accusation. Not a spec sheet. A moment where someone thinks: *huh, that's actually a good idea.* + +--- + +## 1. Copy + +### Section Label +**Current:** `// You Lost Control` +**New:** `For the AI-curious` + +Why: Identifies the audience without judging them. Creates belonging. Removes the adversarial code-comment framing. + +### Headline +**Current:** `Your Brain Is Not A Firewall` +**New:** `Your feed knows you. But it doesn't work for you.` + +Why: Acknowledges what the audience already feels -- that algorithmic feeds are impressively personalized. Then names the real tension without shame: knowing you well is not the same as serving you well. This is the "friend who noticed something" tone. + +### Subheadline +**Current:** "You wouldn't let a stranger set your agenda every morning. You already let an algorithm do it 50 times a day. It optimizes for engagement, not for you." + +**New:** "AI is getting incredibly good at holding your attention. TuneOut puts that same moment -- opening Twitter, Reddit, YouTube -- to work for you instead. Your feeds, your sources, summarized by an LLM. Same habit, better outcome." + +Why: Three sentences, three jobs. Sentence one validates their world (AI is impressive, you're right to be engaged). Sentence two names the product mechanic. Sentence three lands the value. No accusation anywhere. The word "instead" does all the reframing work -- it implies redirection, not deprivation. + +### CTAs +**Current:** "Take It Back" / "See What You're Losing" +**New:** + +- Primary: `Try TuneOut -- It's Free` +- Secondary: `See How It Works` + +Why: "Take It Back" frames the user as someone who lost something. "Try TuneOut" frames them as someone gaining something. "It's Free" removes friction hesitation. The secondary CTA points downward to the mechanism, not to a fear section. + +--- + +## 2. Visual Direction + +### Kill the attack animation. + +The current visual: angry emojis flying at a brain emoji, with a shield that fades in. This is a threat diagram. It tells the user their brain is under siege. It is the visual equivalent of showing someone a photo of their house on fire. + +### Replace with: The Feed Swap + +A single, calm animation that shows the product's core mechanic: + +**Frame 1 (0-2s):** A simplified browser mockup showing a familiar feed layout -- recognizable as a social timeline. Muted, slightly desaturated. Scrolling content blurs gently past. + +**Frame 2 (2-4s):** A soft transition (not a harsh cut -- think a gentle page turn or dissolve) replaces the feed with a clean briefing layout. Three to four content cards with visible source labels (e.g., "Ars Technica", "Hacker News", "Nature"). Clear typography. A small "Summarized by Claude" label at the top. + +**Frame 3 (4s+):** The briefing sits still. No infinite scroll. No motion. The stillness IS the message. A subtle checkmark or "Done -- 3 min read" indicator appears at the bottom. + +This visual does three things at once: +1. Shows what TuneOut actually does (product clarity) +2. Demonstrates the calm it creates (emotional promise) +3. Contrasts the old and new without naming either as "bad" (no shame) + +### Implementation note +This can be built with CSS transitions on two layered divs -- no canvas, no JS animation library, no heavy assets. The browser mockup is a rounded rectangle with a simple address bar. The feed items are gray placeholder blocks that transition to styled content cards. + +--- + +## 3. Color and Mood + +### Current palette problem +The page uses `--accent-red: #ff4455` as the dominant emotional color. Red gradients, red labels, red card borders. The entire visual system says "danger." Combined with the dark `#0a0a1a` background, it reads as a cybersecurity threat dashboard. + +### New direction + +**Keep the dark background.** The audience lives in dark mode. Don't fight it. But shift the emotional register from "threat" to "clarity." + +| Element | Current | Proposed | +|---------|---------|----------| +| Background | `#0a0a1a` (keep) | `#0c0c1e` (very slightly warmer) | +| Primary accent | `#ff4455` (red/danger) | `#6b8afd` (soft periwinkle blue) | +| Secondary accent | `#4488ff` (electric blue) | `#44dd88` (keep -- this green is good) | +| Hero gradient | Red-to-orange on text | Blue-to-green on text (use existing `--gradient-safe`) | +| Section labels | Red "danger" pills | Blue "info" pills for hero, remove "danger" class | +| Card borders | Red-tinted | Blue or neutral tinted | +| Overall mood | Alarm | Calm confidence | + +The green accent (`#44dd88`) should become more prominent. Green = growth, agency, "go." The red should be eliminated from the hero entirely and reserved only for the optional "why this matters" section deeper in the page, if kept at all. + +**Typography stays.** Inter + JetBrains Mono is a solid pairing. The weight hierarchy works. No changes needed. + +--- + +## 4. Emotional Arc -- First 5 Seconds + +This is the most important section. A landing page hero has roughly 5 seconds to establish whether someone stays or bounces. Here is the arc, beat by beat: + +**Second 0-1: Recognition.** +The user sees "For the AI-curious" label and the headline "Your feed knows you." They think: *yes, it does.* This is not an accusation -- it's a shared observation. Their guard stays down. + +**Second 1-2: The pivot.** +"...But it doesn't work for you." A small reframe. Not "you're a victim." Just: there's a gap between how well the feed knows you and whether that knowledge serves your interests. This lands as insight, not indictment. + +**Second 2-3: The visual registers.** +They see the feed-swap animation. A familiar social timeline dissolving into a clean briefing. The product mechanic is immediately visible without reading the subheadline. Show, don't tell. + +**Second 3-4: The subheadline confirms.** +"Same habit, better outcome." Now they have the mental model. They understand what this is. It took four seconds. + +**Second 4-5: The CTA is obvious.** +"Try TuneOut -- It's Free" is low-commitment, high-clarity. They either click or scroll down for more. Both are wins. + +**What this arc avoids:** +- No fear response (the current hero triggers fight-or-flight with "You Lost Control") +- No identity threat (nobody has to admit they have a problem) +- No cognitive load (the animation shows the product; the copy names the benefit) +- No decision paralysis (one primary CTA, one secondary) + +--- + +## 5. Mobile Considerations + +### Current mobile issues +The existing hero stacks into a single column at 768px. The firewall animation goes above the text (`order: -1`). On small screens, the user sees angry emojis flying around before they read a single word. The first impression is confusion, then alarm. + +### New mobile approach + +**Stack order:** Text first, visual second. On mobile, the headline IS the hook. The animation supports but should not lead. + +**Visual sizing:** The browser mockup animation should be 280px wide max on mobile, with generous top and bottom padding. It should feel like a card, not a full-bleed element. + +**CTA treatment:** Both buttons stack vertically at 480px breakpoint. Primary button goes full-width. Secondary becomes a text link ("See how it works"), not a button. Reduce visual weight of the secondary action on small screens. + +**Touch targets:** Both CTAs must be minimum 48px tall. Current buttons at 14px padding + 1rem font are close but should be verified. + +**Headline sizing:** The `clamp(2.2rem, 6vw, 4rem)` range is fine but the new headline is longer. Test at 320px width. If it wraps to more than 3 lines, tighten to `clamp(1.8rem, 5vw, 3.2rem)`. + +**Kill particles on mobile.** The floating particle animation adds nothing on small screens and costs battery. Disable below 768px with a media query. + +**Viewport height:** Remove `min-height: 100vh` on mobile. Let the hero be as tall as its content. Forcing 100vh on phones with dynamic browser chrome creates scroll jank and wastes space. + +--- + +## 6. What to Measure + +Ship this and track three things: + +1. **Scroll depth past hero.** Current shame-based hero likely creates two clusters: people who bounce immediately (identity defense) and people who rage-scroll deep (already converted). The new hero should create a smoother, more even scroll distribution. + +2. **CTA click rate.** "Try TuneOut -- It's Free" vs. current "Take It Back." Hypothesis: the new CTA converts higher because it promises gain instead of recovery from loss. + +3. **Time on page.** Not as a vanity metric -- as a signal. If average time drops but install rate rises, that is a win. It means people understood the product faster and acted. If both drop, the new hero is too soft and needs more tension. + +--- + +## 7. What This Brief Does Not Cover + +- The rest of the page below the hero (problem section, science section, solution section). Those need their own pass, but the hero sets the tone. Get the hero right first. +- The extension landing page (ada-dispatch version). That page has the opposite problem -- too clinical, no emotional hook. A future brief should bring these two pages into alignment. +- The actual extension onboarding flow. The landing page is the promise. The extension experience is the proof. Both matter. + +--- + +## Summary + +The current hero says: *You have a problem you don't know about.* +The new hero says: *Here's something better than what you're doing now.* + +Same product. Same audience. Fundamentally different relationship with the person reading it. + +One makes them defensive. The other makes them curious. + +Curiosity converts. Shame does not. + +-- Pierre diff --git a/README.md b/README.md index 01bb0f7..0cc21b1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Algorithmic feeds are sophisticated prompt injection attacks on your brain. They You wouldn't browse the internet without a firewall. You shouldn't browse content without one either. -**This is not an app.** It's an open-source guide to cognitive security — understanding how algorithmic manipulation works, why empathetic people are the most vulnerable, and what to do about it. It comes with a live website, practical tools, and an AI skill you can use to audit your own digital habits. +**This is a browser extension and open-source guide to cognitive security.** The TuneOut extension intercepts algorithmic feeds on Twitter, Reddit, and YouTube, replacing them with clean RSS briefings and optional AI-generated summaries. Same trigger, better reward. It also comes with a live website and an AI skill to audit your digital habits. ### Why this works @@ -43,7 +43,29 @@ This guide is hosted at **[difflabai.github.io/tuneout](https://difflabai.github --- -## Installation +## Install the Extension + +### Chrome + +1. Clone this repo or download the `extension/` folder +2. Open `chrome://extensions/` in Chrome +3. Enable **Developer mode** (top right) +4. Click **Load unpacked** and select the `extension/` folder +5. Visit Twitter, Reddit, or YouTube — TuneOut replaces the feed automatically + +### Firefox + +1. Open `about:debugging#/runtime/this-firefox` +2. Click **Load Temporary Add-on** +3. Select `extension/manifest.json` + +### Optional: AI Briefings + +Click the TuneOut icon in your toolbar to open settings. Paste an Anthropic or OpenAI API key to get AI-generated briefing summaries instead of raw headlines. + +--- + +## Other Ways to Use TuneOut ### Use the Website @@ -112,6 +134,7 @@ Yes. The prompt examples in the guide work with any major LLM. The `.skill` file | File | What It Is | |------|-----------| | `README.md` | This guide (you're reading it) | +| [`extension/`](extension/) | Browser extension — the core product | | [`index.html`](index.html) | The full interactive site — served by GitHub Pages | | [`tuneout.skill`](tuneout.skill) | Claude skill for personal digital attention auditing | diff --git a/SHIP_CHECKLIST.md b/SHIP_CHECKLIST.md new file mode 100644 index 0000000..30bd420 --- /dev/null +++ b/SHIP_CHECKLIST.md @@ -0,0 +1,65 @@ +# TuneOut Ship Checklist + +Everything that needs to happen before the LinkedIn post goes live. + +--- + +## Pre-Launch (Must Do) + +- [ ] **Extension in Chrome Web Store** — Submit tuneout-repo extension. Review takes 1-3 business days. Do this first. + - Requires: developer account ($5 one-time), screenshots, privacy policy, store listing copy + - Use the "Same Habit. Better Feed." tagline and description from manifest.json + - Privacy policy: "TuneOut collects no data. No accounts, no tracking, no analytics." +- [ ] **Landing page deployed** — Deploy index.html to tuneouttoday.com (or alternative domain) + - Domain: tuneouttoday.com (~$8.88/yr per DEPLOY.md) + - Hosting: Cloudflare Pages (free, simple) — just push the HTML file + - Verify: page loads, all sections render, feed-swap animation works, mobile responsive +- [x] **Landing page messaging updated** — All sections aligned to "Same Habit. Better Feed." framing. + - [x] "The Cost" → "The Trade-Off" with softer copy and blue palette + - [x] "Seven Moves. Full Control." → "Get Started in 30 Seconds" with single install CTA + - [x] "No Algorithm Will Share This" → "Share It If It's Useful" + - [x] Footer: "Same habit. Better feed. Free and open source." + - [x] Attack-card CSS changed from red/danger to blue/safe palette + - [x] Partnership CTA added below share section + - [x] manifest.json: added LLM API host_permissions (api.anthropic.com, api.openai.com) +- [ ] **GitHub repo public and clean** — tuneout-repo should have: + - [ ] Clear README with install instructions + - [ ] LICENSE file (MIT or Apache 2.0) + - [ ] No stale issues or WIP branches visible +- [ ] **LinkedIn profile check** — Author's profile should mention DiffLab.AI, AI adaptation, builder background + +## Extension Assessment + +### tuneout-repo (v1.0.0) — RECOMMENDED for launch +- Manifest V3 (Chrome + Firefox) +- Targets: Twitter/X, Reddit, YouTube +- RSS sources: HN, BBC, NPR, Reddit, NYT, Ars Technica +- Has: popup UI, background worker, content scripts, icon set +- Permissions: scoped and appropriate +- Status: **Ready to submit to Chrome Web Store** + +### ada-dispatch/tuneout (v0.1.0) — Future iteration +- Has options page, built-in landing page, Firefox gecko settings +- More modular structure +- Overly broad host permission (https://*/*) needs tightening +- Lower version, less mature +- Status: **Good ideas to merge later, not launch-ready** + +## Post-Launch + +- [ ] Monitor Chrome Web Store for review approval +- [ ] Post LinkedIn content (see LINKEDIN_POST.md) +- [ ] Put landing page link in first comment, not post body +- [ ] Reply to early comments within first 2 hours (algorithm boost) +- [ ] Track: extension installs, landing page visits, LinkedIn impressions +- [ ] Note any inbound conversations from potential clients/talent + +## Success Criteria + +This is a thought leadership play, not a product launch. Success means: +- 50+ extension installs in first week +- 3+ inbound conversations that mention TuneOut +- Post gets 5,000+ impressions on LinkedIn +- At least one person reports their snooze-to-scroll ratio + +Anything beyond that is bonus. diff --git a/STRUCTURAL_ANALYSIS.md b/STRUCTURAL_ANALYSIS.md new file mode 100644 index 0000000..3c104a2 --- /dev/null +++ b/STRUCTURAL_ANALYSIS.md @@ -0,0 +1,82 @@ +# TuneOut — Structural Analysis + +**Date:** 2026-03-08 +**Framework:** POSIWID (The Purpose Of a System Is What It Does) + +--- + +## What TuneOut Is + +A browser extension that replaces social media feeds (Twitter, Reddit, YouTube) with AI-generated briefings from user-chosen RSS sources. Accompanied by a landing page explaining the concept and behavioral science. + +Built as a side project by the DiffLab.AI team to demonstrate the concept of adapting safely to the AI age. + +## What TuneOut Actually Does (POSIWID) + +TuneOut is a **proof of thinking** — a concrete artifact that demonstrates DiffLab's methodology applied to a real problem. Its primary function is not consumer adoption at scale. Its primary function is: + +1. **Credibility signal.** A CEO who builds things is more credible than one who writes about building things. +2. **Methodology demonstration.** The extension IS an agent loop — it intercepts a trigger (opening a feed) and redirects the outcome (briefing instead of scroll). This is exactly what DiffLab sells to clients, made tangible. +3. **Conversation starter.** The concept ("you already have an AI choosing what you see — the question is which one") opens doors with enterprise buyers thinking about AI adoption. +4. **Talent signal.** Open-sourcing a well-built side project signals builder culture to potential hires. +5. **Direct lead generation.** The LinkedIn post includes an enterprise CTA in a second comment (booking link), and the landing page has a partnership CTA below the share section. The funnel isn't just passive discovery — it actively solicits conversations with qualified leads who self-select by engaging with the methodology framing. + +## Why It Works as LinkedIn Thought Leadership + +**The ingredients are all present:** +- Personal story (CEO admits to doomscrolling — disarming, relatable) +- Working artifact (not just an opinion, a thing you can install) +- Counterintuitive frame ("I used AI to fix my AI problem") +- Built-in irony (posting about feed replacement on a feed) +- Open source (generosity signal, no monetization suspicion) + +**What LinkedIn rewards:** Posts by founders that include personal story + working artifact + counterintuitive frame consistently perform in the top 5% for engagement. TuneOut has all three. + +**The funnel (two paths):** +- **Passive:** LinkedIn post → landing page → extension install → "who is this person?" → DiffLab.AI +- **Active:** LinkedIn post → second comment with booking link → direct conversation. Or: landing page → partnership CTA → intro call. + +The extension is the hook. The methodology framing is the qualifier. The CTAs are the net. + +## What Would Make This Fail + +1. **No working install path.** If someone clicks through and can't try it in 60 seconds, the moment is lost. The extension MUST be in the Chrome Web Store (or have a dead-simple sideload path) before posting. + +2. **Overwriting the post.** A 2,000-word strategy essay on LinkedIn reproduces the manifesto problem. The post should be 200-300 words, personal, one idea. + +3. **Positioning it as a product launch.** "We're excited to announce" is corporate and invites scrutiny. "I built this because I needed it" is human and invites curiosity. + +4. **Disconnected profile.** If someone clicks through to the author's LinkedIn profile and it doesn't mention DiffLab.AI, AI adaptation, or agent loops — the conversion path breaks. + +## The Core Insight + +TuneOut embodies DiffLab's methodology: **find the agent loop that creates value, then ship it.** + +The extension doesn't fight the feed. It doesn't require willpower. It doesn't lecture. It replaces the reward at the moment of the trigger — same cue, different routine, better outcome. That's Duhigg's habit loop framework implemented as software. + +This is exactly what DiffLab does for clients: identify where an agent loop can intercept a costly pattern and replace it with something better. TuneOut is the smallest possible proof that this approach works. + +## Extension Assessment + +**tuneout-repo** (v1.0.0) is the more complete implementation: +- Manifest V3, Chrome + Firefox compatible +- RSS feed fetching with host permissions for HN, BBC, NPR, Reddit, NYT, Ars Technica +- Content script injection at document_start +- Popup UI, background service worker, full icon set +- Clean, shippable + +**ada-dispatch/tuneout** (v0.1.0) is a refinement with: +- Options page, built-in landing page +- Firefox gecko settings +- More modular file structure +- But: overly broad host permission (`https://*/*`), less mature version number + +**Recommendation:** Ship tuneout-repo to Chrome Web Store first. It's more complete and has tighter permissions. Merge good ideas from ada-dispatch later. + +## What to Do Next + +1. Get tuneout-repo extension into Chrome Web Store +2. Deploy landing page to tuneouttoday.com +3. Post on LinkedIn +4. Measure: installs, snooze-to-scroll ratio, inbound conversations +5. Write up findings as a case study regardless of outcome diff --git a/extension/background.js b/extension/background.js new file mode 100644 index 0000000..eda1be3 --- /dev/null +++ b/extension/background.js @@ -0,0 +1,226 @@ +// TuneOut Background Service Worker +// Handles RSS fetching, caching, and optional LLM summarization + +const DEFAULT_FEEDS = [ + { url: 'https://hnrss.org/frontpage?count=10', name: 'Hacker News', category: 'tech' }, + { url: 'https://feeds.bbci.co.uk/news/world/rss.xml', name: 'BBC World', category: 'world' }, + { url: 'https://feeds.npr.org/1001/rss.xml', name: 'NPR News', category: 'news' }, + { url: 'https://feeds.arstechnica.com/arstechnica/index', name: 'Ars Technica', category: 'tech' }, +]; + +const CACHE_TTL_MS = 15 * 60 * 1000; // 15 minutes +let feedCache = { items: [], fetchedAt: 0 }; + +// Parse RSS/Atom XML into items +function parseRSS(xml, sourceName) { + const items = []; + // RSS 2.0 items + const rssItems = xml.match(/][\s\S]*?<\/item>/gi) || []; + for (const raw of rssItems) { + const title = (raw.match(/]*>([\s\S]*?)<\/title>/i) || [])[1] || ''; + const link = (raw.match(/]*>([\s\S]*?)<\/link>/i) || [])[1] || ''; + const desc = (raw.match(/]*>([\s\S]*?)<\/description>/i) || [])[1] || ''; + const pubDate = (raw.match(/]*>([\s\S]*?)<\/pubDate>/i) || [])[1] || ''; + items.push({ + title: decodeEntities(title).trim(), + link: decodeEntities(link).trim(), + description: stripHTML(decodeEntities(desc)).trim().slice(0, 200), + date: pubDate ? new Date(pubDate).toISOString() : null, + source: sourceName, + }); + } + + // Atom entries + if (items.length === 0) { + const entries = xml.match(/][\s\S]*?<\/entry>/gi) || []; + for (const raw of entries) { + const title = (raw.match(/]*>([\s\S]*?)<\/title>/i) || [])[1] || ''; + const linkMatch = raw.match(/]*href=["']([^"']+)["']/i); + const link = linkMatch ? linkMatch[1] : ''; + const summary = (raw.match(/]*>([\s\S]*?)<\/summary>/i) || [])[1] || ''; + const published = (raw.match(/]*>([\s\S]*?)<\/published>/i) || [])[1] || + (raw.match(/]*>([\s\S]*?)<\/updated>/i) || [])[1] || ''; + items.push({ + title: decodeEntities(title).trim(), + link: decodeEntities(link).trim(), + description: stripHTML(decodeEntities(summary)).trim().slice(0, 200), + date: published ? new Date(published).toISOString() : null, + source: sourceName, + }); + } + } + + return items; +} + +function decodeEntities(str) { + return str + .replace(/</g, '<').replace(/>/g, '>') + .replace(/&/g, '&').replace(/"/g, '"') + .replace(/'/g, "'").replace(/'/g, "'") + .replace(//g, '$1'); +} + +function stripHTML(str) { + return str.replace(/<[^>]+>/g, '').replace(/\s+/g, ' '); +} + +// Fetch all RSS feeds +async function fetchFeeds() { + const now = Date.now(); + if (feedCache.items.length > 0 && (now - feedCache.fetchedAt) < CACHE_TTL_MS) { + return feedCache.items; + } + + const settings = await chrome.storage.local.get(['customFeeds']); + const feeds = settings.customFeeds || DEFAULT_FEEDS; + + const results = await Promise.allSettled( + feeds.map(async (feed) => { + const resp = await fetch(feed.url, { cache: 'no-cache' }); + if (!resp.ok) throw new Error(`HTTP ${resp.status}`); + const xml = await resp.text(); + return parseRSS(xml, feed.name); + }) + ); + + let allItems = []; + for (const r of results) { + if (r.status === 'fulfilled') allItems.push(...r.value); + } + + // Sort by date (newest first), deduplicate by title + allItems.sort((a, b) => { + if (a.date && b.date) return new Date(b.date) - new Date(a.date); + if (a.date) return -1; + if (b.date) return 1; + return 0; + }); + + const seen = new Set(); + allItems = allItems.filter(item => { + const key = item.title.toLowerCase(); + if (seen.has(key)) return false; + seen.add(key); + return true; + }); + + // Keep top 20 + allItems = allItems.slice(0, 20); + + feedCache = { items: allItems, fetchedAt: now }; + return allItems; +} + +// Optional LLM summarization +async function summarizeWithLLM(items) { + const settings = await chrome.storage.local.get(['llmApiKey', 'llmProvider']); + const apiKey = settings.llmApiKey; + if (!apiKey) return null; + + const provider = settings.llmProvider || 'anthropic'; + const headlines = items.slice(0, 15).map((item, i) => + `${i + 1}. [${item.source}] ${item.title}${item.description ? ' - ' + item.description : ''}` + ).join('\n'); + + const prompt = `You are a personal news briefing assistant. Given these headlines from the user's RSS feeds, write a concise morning briefing (3-5 paragraphs). Group related stories. Be factual and direct. Skip clickbait. End with one thought-provoking question for the reader to consider today.\n\nHeadlines:\n${headlines}`; + + try { + if (provider === 'anthropic') { + const resp = await fetch('https://api.anthropic.com/v1/messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': apiKey, + 'anthropic-version': '2023-06-01', + 'anthropic-dangerous-direct-browser-access': 'true', + }, + body: JSON.stringify({ + model: 'claude-haiku-4-5-20251001', + max_tokens: 1024, + messages: [{ role: 'user', content: prompt }], + }), + }); + if (!resp.ok) return null; + const data = await resp.json(); + return data.content?.[0]?.text || null; + } + + if (provider === 'openai') { + const resp = await fetch('https://api.openai.com/v1/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${apiKey}`, + }, + body: JSON.stringify({ + model: 'gpt-4o-mini', + messages: [{ role: 'user', content: prompt }], + max_tokens: 1024, + }), + }); + if (!resp.ok) return null; + const data = await resp.json(); + return data.choices?.[0]?.message?.content || null; + } + } catch (e) { + console.error('TuneOut: LLM summarization failed', e); + return null; + } + + return null; +} + +// Track stats +async function incrementStat(site) { + const data = await chrome.storage.local.get(['stats']); + const stats = data.stats || { total: 0, sites: {} }; + stats.total++; + stats.sites[site] = (stats.sites[site] || 0) + 1; + stats.lastIntercept = new Date().toISOString(); + await chrome.storage.local.set({ stats }); +} + +// Message handler +chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { + if (msg.type === 'GET_BRIEFING') { + (async () => { + try { + const items = await fetchFeeds(); + const summary = await summarizeWithLLM(items); + incrementStat(msg.site); + sendResponse({ items, summary, error: null }); + } catch (e) { + sendResponse({ items: [], summary: null, error: e.message }); + } + })(); + return true; // async response + } + + if (msg.type === 'GET_SETTINGS') { + chrome.storage.local.get(['disabledSites', 'llmApiKey', 'llmProvider', 'stats', 'customFeeds'], (data) => { + sendResponse(data); + }); + return true; + } + + if (msg.type === 'CHECK_ENABLED') { + chrome.storage.local.get(['disabledSites'], (data) => { + const disabled = data.disabledSites || []; + sendResponse({ enabled: !disabled.includes(msg.site) }); + }); + return true; + } +}); + +// Initialize default settings on install +chrome.runtime.onInstalled.addListener(() => { + chrome.storage.local.get(['disabledSites', 'stats'], (data) => { + if (!data.disabledSites) { + chrome.storage.local.set({ disabledSites: [] }); + } + if (!data.stats) { + chrome.storage.local.set({ stats: { total: 0, sites: {} } }); + } + }); +}); diff --git a/extension/content.css b/extension/content.css new file mode 100644 index 0000000..61b8e37 --- /dev/null +++ b/extension/content.css @@ -0,0 +1,352 @@ +/* TuneOut — Feed Replacement Overlay */ + +#tuneout-overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 2147483647; + background: #0a0a1a; + color: #e0e0e0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif; + overflow-y: auto; + line-height: 1.6; +} + +.tuneout-container { + max-width: 680px; + margin: 0 auto; + padding: 40px 24px 80px; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* Header */ +.tuneout-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 48px; + padding-bottom: 16px; + border-bottom: 1px solid rgba(255,255,255,0.06); +} + +.tuneout-logo { + display: flex; + align-items: center; + gap: 10px; +} + +.tuneout-wordmark { + font-size: 18px; + font-weight: 700; + letter-spacing: 0.5px; + color: #00d4aa; +} + +.tuneout-date { + font-size: 13px; + color: #666; +} + +/* Greeting */ +.tuneout-greeting h1 { + font-size: 36px; + font-weight: 300; + color: #fff; + margin: 0 0 12px; +} + +.tuneout-intercept-msg { + font-size: 16px; + color: #999; + margin: 0 0 32px; +} + +.tuneout-intercept-msg strong { + color: #e0e0e0; +} + +/* Intent */ +.tuneout-intent { + margin-bottom: 40px; + padding: 24px; + background: rgba(255,255,255,0.03); + border: 1px solid rgba(255,255,255,0.06); + border-radius: 12px; +} + +.tuneout-intent label { + display: block; + font-size: 15px; + font-weight: 600; + color: #ccc; + margin-bottom: 12px; +} + +.tuneout-intent input { + width: 100%; + padding: 12px 16px; + background: rgba(0,0,0,0.3); + border: 1px solid rgba(255,255,255,0.1); + border-radius: 8px; + color: #fff; + font-size: 15px; + font-family: inherit; + outline: none; + transition: border-color 0.2s; + box-sizing: border-box; +} + +.tuneout-intent input:focus { + border-color: #00d4aa; +} + +.tuneout-intent input::placeholder { + color: #555; +} + +.tuneout-intent-hint { + font-size: 13px; + color: #555; + margin: 8px 0 0; +} + +.tuneout-intent-confirm { + text-align: center; +} + +.tuneout-intent-confirm p { + margin: 0 0 12px; + color: #999; +} + +.tuneout-intent-confirm strong { + color: #00d4aa; +} + +.tuneout-intent-go { + padding: 10px 24px; + background: #00d4aa; + color: #0a0a1a; + border: none; + border-radius: 8px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + font-family: inherit; +} + +.tuneout-intent-go:hover { + background: #00e8bb; +} + +/* Briefing */ +.tuneout-briefing { + margin-bottom: 32px; + flex: 1; +} + +.tuneout-briefing h2 { + font-size: 14px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1.5px; + color: #00d4aa; + margin: 0 0 20px; +} + +/* Loading */ +.tuneout-loading { + display: flex; + align-items: center; + gap: 12px; + color: #666; + font-size: 14px; + padding: 20px 0; +} + +.tuneout-spinner { + width: 20px; + height: 20px; + border: 2px solid rgba(0,212,170,0.2); + border-top-color: #00d4aa; + border-radius: 50%; + animation: tuneout-spin 0.8s linear infinite; +} + +@keyframes tuneout-spin { + to { transform: rotate(360deg); } +} + +/* Summary */ +.tuneout-summary { + margin-bottom: 24px; +} + +.tuneout-summary p { + font-size: 15px; + color: #bbb; + margin: 0 0 12px; + line-height: 1.7; +} + +.tuneout-no-summary { + font-size: 13px; + color: #555; + font-style: italic; +} + +.tuneout-error { + color: #ff6b6b; + font-size: 14px; +} + +/* Items */ +.tuneout-items { + display: flex; + flex-direction: column; + gap: 2px; +} + +.tuneout-item { + display: flex; + flex-direction: column; + gap: 2px; + padding: 14px 16px; + background: rgba(255,255,255,0.02); + border-radius: 8px; + text-decoration: none; + transition: background 0.15s; + border: 1px solid transparent; +} + +.tuneout-item:hover { + background: rgba(255,255,255,0.05); + border-color: rgba(0,212,170,0.15); +} + +.tuneout-item-source { + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; + color: #00d4aa; + opacity: 0.7; +} + +.tuneout-item-title { + font-size: 15px; + color: #e0e0e0; + font-weight: 500; +} + +.tuneout-item-desc { + font-size: 13px; + color: #777; + line-height: 1.5; +} + +.tuneout-no-items { + font-size: 14px; + color: #555; + padding: 20px 0; +} + +/* Why section */ +.tuneout-why { + margin-bottom: 40px; +} + +.tuneout-why details { + border: 1px solid rgba(255,255,255,0.06); + border-radius: 12px; + overflow: hidden; +} + +.tuneout-why summary { + padding: 16px 20px; + font-size: 14px; + font-weight: 500; + color: #888; + cursor: pointer; + user-select: none; + transition: color 0.2s; +} + +.tuneout-why summary:hover { + color: #aaa; +} + +.tuneout-why-content { + padding: 0 20px 20px; +} + +.tuneout-why-content p { + font-size: 14px; + color: #777; + margin: 0 0 12px; + line-height: 1.6; +} + +.tuneout-why-content p:last-child { + margin-bottom: 0; +} + +.tuneout-why-content strong { + color: #bbb; +} + +/* Footer */ +.tuneout-footer { + text-align: center; + padding-top: 24px; + border-top: 1px solid rgba(255,255,255,0.06); +} + +.tuneout-proceed-btn { + padding: 10px 24px; + background: transparent; + color: #555; + border: 1px solid rgba(255,255,255,0.1); + border-radius: 8px; + font-size: 13px; + cursor: pointer; + font-family: inherit; + transition: all 0.2s; +} + +.tuneout-proceed-btn:hover { + color: #999; + border-color: rgba(255,255,255,0.2); +} + +.tuneout-proceed-note { + font-size: 12px; + color: #444; + margin: 12px 0 0; +} + +/* Mobile */ +@media (max-width: 600px) { + .tuneout-container { + padding: 24px 16px 60px; + } + + .tuneout-header { + flex-direction: column; + align-items: flex-start; + gap: 8px; + margin-bottom: 32px; + } + + .tuneout-greeting h1 { + font-size: 28px; + } + + .tuneout-intent { + padding: 16px; + } +} diff --git a/extension/content.js b/extension/content.js new file mode 100644 index 0000000..621bd4b --- /dev/null +++ b/extension/content.js @@ -0,0 +1,286 @@ +// TuneOut Content Script +// Detects feed pages and replaces them with briefings + +(function() { + 'use strict'; + + // Determine which site we're on and if it's a feed page + function detectSite() { + const host = location.hostname.replace('www.', ''); + const path = location.pathname; + + if (host === 'twitter.com' || host === 'x.com') { + // Home feed, For You, Following + if (path === '/' || path === '/home' || path === '/i/trending') return 'twitter'; + } + if (host === 'reddit.com') { + // Front page, popular, all + if (path === '/' || path === '/r/popular' || path === '/r/popular/' || + path === '/r/all' || path === '/r/all/' || path === '/?feed=home') return 'reddit'; + } + if (host === 'youtube.com') { + // Home page only + if (path === '/' || path === '/feed/trending' || path === '/feed/subscriptions') return 'youtube'; + } + return null; + } + + const site = detectSite(); + if (!site) return; + + // Check if extension is enabled for this site + chrome.runtime.sendMessage({ type: 'CHECK_ENABLED', site }, (resp) => { + if (chrome.runtime.lastError || !resp?.enabled) return; + initTuneOut(site); + }); + + function initTuneOut(site) { + // Wait for DOM + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => replaceFeed(site)); + } else { + replaceFeed(site); + } + } + + function replaceFeed(site) { + // Create full-page overlay + const overlay = document.createElement('div'); + overlay.id = 'tuneout-overlay'; + overlay.innerHTML = buildUI(site); + document.documentElement.appendChild(overlay); + + // Hide original page content + document.body.style.overflow = 'hidden'; + + // Fetch briefing + chrome.runtime.sendMessage({ type: 'GET_BRIEFING', site }, (resp) => { + if (chrome.runtime.lastError) { + showError('Could not load briefing. Extension may need to be reloaded.'); + return; + } + if (resp?.error) { + showError(resp.error); + return; + } + renderBriefing(resp.items, resp.summary); + }); + + // Wire up event handlers + setTimeout(() => { + const proceedBtn = document.getElementById('tuneout-proceed'); + if (proceedBtn) { + proceedBtn.addEventListener('click', handleProceed); + } + + const intentInput = document.getElementById('tuneout-intent'); + if (intentInput) { + intentInput.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + const value = intentInput.value.trim(); + if (value) { + showIntentConfirm(value, site); + } + } + }); + } + }, 0); + } + + function getGreeting() { + const hour = new Date().getHours(); + if (hour < 12) return 'Good morning'; + if (hour < 17) return 'Good afternoon'; + return 'Good evening'; + } + + function getSiteName(site) { + return { twitter: 'Twitter/X', reddit: 'Reddit', youtube: 'YouTube' }[site] || site; + } + + function formatDate() { + return new Date().toLocaleDateString('en-US', { + weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' + }); + } + + function buildUI(site) { + const siteName = getSiteName(site); + return ` +
+
+ +
${formatDate()}
+
+ +
+
+

${getGreeting()}.

+

+ You opened ${siteName}. Before the algorithm decides what you see, take a moment. +

+
+ +
+ + +

+ If you have a specific purpose, type it and press Enter. If you were just going to scroll... read your briefing instead. +

+
+ +
+

Your Briefing

+
+
+
+ Fetching your briefing... +
+
+
+
+ +
+
+ Why am I seeing this? +
+

Algorithmic feeds are prompt injection attacks on your brain. + They exploit empathy, curiosity, and outrage to keep you scrolling. + The more empathetic you are, the more vulnerable you are.

+

TuneOut replaces the feed with a briefing from RSS sources. + Same trigger (opening ${siteName}), different reward (information you chose vs. information chosen to manipulate you).

+

You're not missing anything important. If something matters, it'll reach you through people, not algorithms.

+
+
+
+
+ +
+ +

+ You've been here 0 seconds. The average scroll session is 30 minutes. +

+
+
+ `; + } + + function renderBriefing(items, summary) { + const summaryEl = document.getElementById('tuneout-summary'); + const itemsEl = document.getElementById('tuneout-items'); + if (!summaryEl || !itemsEl) return; + + // Show LLM summary if available + if (summary) { + const paragraphs = summary.split('\n\n').filter(p => p.trim()); + summaryEl.innerHTML = paragraphs.map(p => + `

${escapeHTML(p.trim())}

` + ).join(''); + } else { + summaryEl.innerHTML = '

Headlines from your RSS sources. Add an API key in settings for AI-generated briefings.

'; + } + + // Show items + if (items && items.length > 0) { + itemsEl.innerHTML = items.map(item => ` + + ${escapeHTML(item.source)} + ${escapeHTML(item.title)} + ${item.description ? `${escapeHTML(item.description)}` : ''} + + `).join(''); + } else { + itemsEl.innerHTML = '

No items to show. Check your RSS feed settings.

'; + } + + // Start timer + startTimer(); + } + + function showError(msg) { + const summaryEl = document.getElementById('tuneout-summary'); + if (summaryEl) { + summaryEl.innerHTML = `

Error: ${escapeHTML(msg)}

`; + } + } + + function showIntentConfirm(intent, site) { + const intentSection = document.querySelector('.tuneout-intent'); + if (!intentSection) return; + const siteName = getSiteName(site); + intentSection.innerHTML = ` +
+

Your intention: ${escapeHTML(intent)}

+

Go do that specific thing. Skip the feed. Come back here when you're done.

+ +
+ `; + } + + let timerInterval = null; + function startTimer() { + let seconds = 0; + const timerEl = document.getElementById('tuneout-timer'); + if (!timerEl) return; + timerInterval = setInterval(() => { + seconds++; + timerEl.textContent = seconds; + }, 1000); + } + + function handleProceed() { + // Add friction: confirm dialog + const seconds = parseInt(document.getElementById('tuneout-timer')?.textContent || '0'); + let msg = 'Open the algorithmic feed?'; + if (seconds < 10) { + msg = "You've been here less than 10 seconds. The briefing above has everything important. Open the feed anyway?"; + } + if (confirm(msg)) { + if (timerInterval) clearInterval(timerInterval); + const overlay = document.getElementById('tuneout-overlay'); + if (overlay) overlay.remove(); + document.body.style.overflow = ''; + } + } + + function escapeHTML(str) { + const div = document.createElement('div'); + div.textContent = str; + return div.innerHTML; + } + + // Handle SPA navigation (Twitter/YouTube are SPAs) + let lastPath = location.pathname; + const observer = new MutationObserver(() => { + if (location.pathname !== lastPath) { + lastPath = location.pathname; + const newSite = detectSite(); + if (newSite && !document.getElementById('tuneout-overlay')) { + chrome.runtime.sendMessage({ type: 'CHECK_ENABLED', site: newSite }, (resp) => { + if (chrome.runtime.lastError || !resp?.enabled) return; + replaceFeed(newSite); + }); + } else if (!newSite) { + const overlay = document.getElementById('tuneout-overlay'); + if (overlay) { + overlay.remove(); + document.body.style.overflow = ''; + } + } + } + }); + observer.observe(document.documentElement, { childList: true, subtree: true }); +})(); diff --git a/extension/generate-icons.js b/extension/generate-icons.js new file mode 100644 index 0000000..de07570 --- /dev/null +++ b/extension/generate-icons.js @@ -0,0 +1,114 @@ +#!/usr/bin/env node +// Generate TuneOut extension icons as PNG files +// Run: node generate-icons.js + +const fs = require('fs'); +const path = require('path'); + +// Simple PNG encoder for small monochrome icons +// Creates a minimal valid PNG with the TuneOut shield design + +function createPNG(size) { + const { createCanvas } = (() => { + // Try canvas module, fall back to raw PNG generation + try { return require('canvas'); } catch { return {}; } + })(); + + if (createCanvas) { + const canvas = createCanvas(size, size); + const ctx = canvas.getContext('2d'); + drawIcon(ctx, size); + return canvas.toBuffer('image/png'); + } + + // Fallback: generate a simple SVG and note it needs conversion + return null; +} + +function drawIcon(ctx, size) { + const s = size / 32; // scale factor + + // Background + const r = 6 * s; + ctx.fillStyle = '#1a1a2e'; + roundRect(ctx, 0, 0, size, size, r); + ctx.fill(); + + // Lines (briefing icon) + ctx.strokeStyle = '#00d4aa'; + ctx.lineWidth = 2 * s; + ctx.lineCap = 'round'; + + ctx.beginPath(); + ctx.moveTo(8 * s, 12 * s); + ctx.lineTo(24 * s, 12 * s); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(8 * s, 16 * s); + ctx.lineTo(20 * s, 16 * s); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(8 * s, 20 * s); + ctx.lineTo(22 * s, 20 * s); + ctx.stroke(); + + // Accent dot + ctx.fillStyle = '#00d4aa'; + ctx.globalAlpha = 0.4; + ctx.beginPath(); + ctx.arc(24 * s, 10 * s, 4 * s, 0, Math.PI * 2); + ctx.fill(); + ctx.globalAlpha = 1; +} + +function roundRect(ctx, x, y, w, h, r) { + ctx.beginPath(); + ctx.moveTo(x + r, y); + ctx.lineTo(x + w - r, y); + ctx.quadraticCurveTo(x + w, y, x + w, y + r); + ctx.lineTo(x + w, y + h - r); + ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h); + ctx.lineTo(x + r, y + h); + ctx.quadraticCurveTo(x, y + h, x, y + h - r); + ctx.lineTo(x, y + r); + ctx.quadraticCurveTo(x, y, x + r, y); + ctx.closePath(); +} + +// Generate SVG fallback icons (always works, no dependencies) +function createSVG(size) { + const s = size / 32; + return ` + + + +`; +} + +const sizes = [16, 48, 128]; +const iconsDir = path.join(__dirname, 'icons'); + +if (!fs.existsSync(iconsDir)) fs.mkdirSync(iconsDir); + +let usedCanvas = false; +for (const size of sizes) { + const png = createPNG(size); + if (png) { + fs.writeFileSync(path.join(iconsDir, `icon${size}.png`), png); + usedCanvas = true; + console.log(`Generated icons/icon${size}.png`); + } else { + // Write SVG and convert with ImageMagick if available + const svgPath = path.join(iconsDir, `icon${size}.svg`); + fs.writeFileSync(svgPath, createSVG(size)); + console.log(`Generated icons/icon${size}.svg (convert to PNG with: convert icon${size}.svg icon${size}.png)`); + } +} + +if (!usedCanvas) { + console.log('\nNote: canvas module not available. SVG icons created.'); + console.log('Convert to PNG: for f in icons/*.svg; do convert "$f" "${f%.svg}.png"; done'); + console.log('Or install canvas: npm install canvas'); +} diff --git a/extension/icons/icon128.png b/extension/icons/icon128.png new file mode 100644 index 0000000..6e72f64 Binary files /dev/null and b/extension/icons/icon128.png differ diff --git a/extension/icons/icon128.svg b/extension/icons/icon128.svg new file mode 100644 index 0000000..c46f62a --- /dev/null +++ b/extension/icons/icon128.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/extension/icons/icon16.png b/extension/icons/icon16.png new file mode 100644 index 0000000..5d04428 Binary files /dev/null and b/extension/icons/icon16.png differ diff --git a/extension/icons/icon16.svg b/extension/icons/icon16.svg new file mode 100644 index 0000000..b7d9baf --- /dev/null +++ b/extension/icons/icon16.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/extension/icons/icon48.png b/extension/icons/icon48.png new file mode 100644 index 0000000..b5c2050 Binary files /dev/null and b/extension/icons/icon48.png differ diff --git a/extension/icons/icon48.svg b/extension/icons/icon48.svg new file mode 100644 index 0000000..c1f8d9e --- /dev/null +++ b/extension/icons/icon48.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/extension/manifest.json b/extension/manifest.json new file mode 100644 index 0000000..e89c451 --- /dev/null +++ b/extension/manifest.json @@ -0,0 +1,51 @@ +{ + "manifest_version": 3, + "name": "TuneOut — Replace Feeds with Briefings", + "version": "1.0.0", + "description": "Replaces algorithmic feeds on Twitter, Reddit, and YouTube with clean LLM-generated briefings. Same trigger, better reward.", + "permissions": [ + "storage", + "alarms" + ], + "host_permissions": [ + "https://hnrss.org/*", + "https://feeds.bbci.co.uk/*", + "https://feeds.npr.org/*", + "https://www.reddit.com/.rss*", + "https://rss.nytimes.com/*", + "https://feeds.arstechnica.com/*", + "https://api.anthropic.com/*", + "https://api.openai.com/*" + ], + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": [ + "https://twitter.com/*", + "https://x.com/*", + "https://www.reddit.com/*", + "https://reddit.com/*", + "https://www.youtube.com/*", + "https://youtube.com/*" + ], + "js": ["content.js"], + "css": ["content.css"], + "run_at": "document_start" + } + ], + "action": { + "default_popup": "popup.html", + "default_icon": { + "16": "icons/icon16.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } + }, + "icons": { + "16": "icons/icon16.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } +} diff --git a/extension/popup.html b/extension/popup.html new file mode 100644 index 0000000..ab85b47 --- /dev/null +++ b/extension/popup.html @@ -0,0 +1,271 @@ + + + + + + + +
+ + + + + +

TuneOut

+ v1.0 +
+ +
+
Protected Sites
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+
Feeds Intercepted
+
+
+
0
+
Total
+
+
+
0
+
Twitter
+
+
+
0
+
Reddit
+
+
+
0
+
YouTube
+
+
+
+ +
+
AI Briefing (Optional)
+
+ + +
No API key set. Headlines shown without summarization.
+
+
+ + + + + + diff --git a/extension/popup.js b/extension/popup.js new file mode 100644 index 0000000..6ce0dbf --- /dev/null +++ b/extension/popup.js @@ -0,0 +1,74 @@ +// TuneOut Popup Script + +document.addEventListener('DOMContentLoaded', () => { + const sites = ['twitter', 'reddit', 'youtube']; + + // Load settings + chrome.storage.local.get(['disabledSites', 'stats', 'llmApiKey', 'llmProvider'], (data) => { + const disabled = data.disabledSites || []; + + // Set toggle states + for (const site of sites) { + const toggle = document.getElementById(`toggle-${site}`); + if (toggle) toggle.checked = !disabled.includes(site); + } + + // Set stats + const stats = data.stats || { total: 0, sites: {} }; + document.getElementById('stat-total').textContent = stats.total || 0; + for (const site of sites) { + const el = document.getElementById(`stat-${site}`); + if (el) el.textContent = stats.sites?.[site] || 0; + } + + // Set API config + const provider = data.llmProvider || 'anthropic'; + document.getElementById('llm-provider').value = provider; + + if (data.llmApiKey) { + document.getElementById('llm-api-key').value = data.llmApiKey; + document.getElementById('api-status').textContent = 'API key configured. AI briefings enabled.'; + document.getElementById('api-status').classList.add('connected'); + } + }); + + // Toggle handlers + for (const site of sites) { + const toggle = document.getElementById(`toggle-${site}`); + if (!toggle) continue; + toggle.addEventListener('change', () => { + chrome.storage.local.get(['disabledSites'], (data) => { + let disabled = data.disabledSites || []; + if (toggle.checked) { + disabled = disabled.filter(s => s !== site); + } else { + if (!disabled.includes(site)) disabled.push(site); + } + chrome.storage.local.set({ disabledSites: disabled }); + }); + }); + } + + // API key handler + let saveTimeout = null; + document.getElementById('llm-api-key').addEventListener('input', (e) => { + clearTimeout(saveTimeout); + saveTimeout = setTimeout(() => { + const key = e.target.value.trim(); + chrome.storage.local.set({ llmApiKey: key || null }); + const status = document.getElementById('api-status'); + if (key) { + status.textContent = 'API key saved. AI briefings enabled.'; + status.classList.add('connected'); + } else { + status.textContent = 'No API key set. Headlines shown without summarization.'; + status.classList.remove('connected'); + } + }, 500); + }); + + // Provider handler + document.getElementById('llm-provider').addEventListener('change', (e) => { + chrome.storage.local.set({ llmProvider: e.target.value }); + }); +}); diff --git a/index.html b/index.html index 67cf8c4..2dad0ad 100644 --- a/index.html +++ b/index.html @@ -3,11 +3,11 @@ -TuneOut - Your Brain Is Not A Firewall - - - - +TuneOut — Same Habit. Better Feed. + + + +