<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="manifest" href="/site.webmanifest"><meta name="theme-color" content="#35ddc0"><link rel="dns-prefetch" href="https://www.googletagmanager.com"><link rel="alternate" type="application/rss+xml" title="GeekTechLive" href="/rss.xml"><link rel="preload" href="/fonts/Manrope-Variable.woff2" as="font" type="font/woff2" crossorigin><link rel="canonical" href="https://geektechlive.com/"><meta name="description" content="I ran a tech podcast for ten years. Now I'm teaching myself to build apps. StackGarden is the first one out the door."><meta name="generator" content="Astro v5.18.1"><meta property="og:site_name" content="GeekTechLive"><meta property="og:type" content="website"><meta property="og:url" content="https://geektechlive.com/"><meta property="og:title" content="GeekTechLive | Apps, Games, and Projects by Chris"><meta property="og:description" content="I ran a tech podcast for ten years. Now I'm teaching myself to build apps. StackGarden is the first one out the door."><meta property="og:image" content="https://geektechlive.com/images/OG-share.png"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta property="og:image:type" content="image/png"><meta property="og:image:alt" content="GeekTechLive | Apps, Games, and Projects by Chris preview image"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="GeekTechLive | Apps, Games, and Projects by Chris"><meta name="twitter:description" content="I ran a tech podcast for ten years. Now I'm teaching myself to build apps. StackGarden is the first one out the door."><meta name="twitter:image" content="https://geektechlive.com/images/OG-share.png"><meta name="twitter:image:alt" content="GeekTechLive | Apps, Games, and Projects by Chris preview image"><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"GeekTechLive","url":"https://geektechlive.com/","inLanguage":"en-US"}</script><script type="application/ld+json">{"@context":"https://schema.org","@type":"Person","name":"Chris Favero","url":"https://geektechlive.com/","email":"connect@geektechlive.com","sameAs":["https://bsky.app/profile/geektechlive.com","https://www.instagram.com/geektechlive/"]}</script><script>
      (() => {
        const consentKey = 'gtl_consent_analytics';
        const consentRegions = new Set([
          'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR',
          'HR', 'HU', 'IE', 'IS', 'IT', 'LI', 'LT', 'LU', 'LV', 'MT', 'NL', 'NO', 'PL', 'PT',
          'RO', 'SE', 'SI', 'SK'
        ]);
        const measurementId = 'G-CFYFEW07MV';
        const parseRegion = () => {
          const locale = navigator.language || '';
          if (locale.includes('-')) return locale.split('-')[1].toUpperCase();
          const preferred = navigator.languages?.find((item) => item.includes('-'));
          return preferred ? preferred.split('-')[1].toUpperCase() : '';
        };
        const requiresConsent = () => {
          const region = parseRegion();
          if (!region) return true;
          return consentRegions.has(region);
        };
        const storage = {
          get(key) {
            try {
              return window.localStorage.getItem(key);
            } catch {
              return null;
            }
          },
          set(key, value) {
            try {
              window.localStorage.setItem(key, value);
              return true;
            } catch {
              return false;
            }
          }
        };
        const loadAnalytics = () => {
          if (window.gtag) return;
          const script = document.createElement('script');
          script.async = true;
          script.src = `https://www.googletagmanager.com/gtag/js?id=${measurementId}`;
          document.head.appendChild(script);
          window.dataLayer = window.dataLayer || [];
          window.gtag = function gtag() {
            window.dataLayer.push(arguments);
          };
          window.gtag('js', new Date());
          window.gtag('config', measurementId);
        };
        const stored = storage.get(consentKey);
        if (stored === 'granted') {
          loadAnalytics();
          return;
        }
        if (stored === 'denied') return;
        if (!requiresConsent()) {
          storage.set(consentKey, 'granted');
          loadAnalytics();
          return;
        }
        storage.set(consentKey, 'pending');
      })();
    </script><title>GeekTechLive | Apps, Games, and Projects by Chris</title><meta name="astro-view-transitions-enabled" content="true"><meta name="astro-view-transitions-fallback" content="animate"><script type="module" src="/_astro/ClientRouter.astro_astro_type_script_index_0_lang.CDGfc0hd.js"></script><link rel="stylesheet" href="/_astro/about.zxaiqFSF.css"></head> <body class="page-shell"> <a class="skip-link" href="#main-content">Skip to main content</a> <header class="site-header"> <div class="container nav-wrap"> <a class="logo logo-wordmark" href="/"> <img class="logo-image logo-badge-image" src="/images/geektechlive-mic-isolated.png" alt="GeekTechLive microphone mark" width="111" height="250"> <span class="logo-label">GeekTechLive</span> </a> <nav class="nav-links" id="site-nav" data-nav> <a href="/" class="active" aria-current="page">Home</a><a href="/guess-the-gadget/" class>Guess the Gadget</a><a href="/apps/" class>Apps</a><a href="/blog/" class>Blog</a><a href="/fun/" class>DOS Lab</a><a href="/history/" class>History</a><a href="/about/" class>About</a><a href="/contact/" class>Contact</a> </nav> <button class="mobile-toggle" data-nav-toggle type="button" aria-label="Toggle menu" aria-controls="site-nav" aria-expanded="false">Menu</button> </div> </header> <div id="main-content" tabindex="-1">  <main> <section class="hero home-hero"> <div class="container hero-grid home-hero-grid"> <div class="home-hero-copy"> <img class="home-brandmark" src="/images/geektechlive-wordmarkA.png" alt="GeekTechLive wordmark" width="1049" height="312" loading="eager"> <pre class="hero-terminal" aria-hidden="true"></pre> <h1 class="gradient-text">Podcast roots. Learning to code. Shipping what I can.</h1> <p class="lead">
I ran a tech podcast for ten years. Now I'm teaching myself to build apps. StackGarden is the first one
            out the door — a relaxing puzzle game, live on the App Store.
</p> <div class="cta-row"> <a class="btn btn-primary" href="https://apps.apple.com/us/app/stackgarden/id6759578207" target="_blank" rel="noopener noreferrer">Download StackGarden</a> <a class="btn btn-secondary" href="/apps/stackgarden/">Learn More</a> </div> </div> <aside class="hero-panel reveal home-hero-panel"> <div class="meta">What&apos;s Live Now</div> <div class="home-signal-list"> <article class="home-signal-card reveal" style="transition-delay:0ms"> <div class="home-signal-top"> <span class="meta">Live now</span> <a class="home-signal-link" href="/apps/stackgarden/">Open StackGarden</a> </div> <h2>StackGarden is live on the App Store.</h2> <p>The first shipped app. A relaxing puzzle game that works in under five minutes.</p> </article><article class="home-signal-card reveal" style="transition-delay:35ms"> <div class="home-signal-top"> <span class="meta">Play today</span> <a class="home-signal-link" href="/guess-the-gadget/">Play today</a> </div> <h2>Guess the Gadget is a free daily browser game.</h2> <p>New puzzle every day. No account needed. See how you stack up on the leaderboard.</p> </article><article class="home-signal-card reveal" style="transition-delay:70ms"> <div class="home-signal-top"> <span class="meta">From the blog</span> <a class="home-signal-link" href="/blog/">Read the blog</a> </div> <h2>Notes on what I&#39;m building and learning.</h2> <p>Launch updates, build decisions, and things worth writing down.</p> </article> </div> </aside> </div> </section> <section class="stats-strip"> <div class="container stats-strip-grid"> <div class="stat-item"> <span class="stat-value" data-count="17" data-suffix="+">17+</span> <span class="stat-label">Years online</span> </div> <div class="stat-item"> <span class="stat-value" data-count="1500" data-suffix="+" data-format="comma">1,500+</span> <span class="stat-label">Posts archived</span> </div> <div class="stat-item"> <span class="stat-value" data-count="1">1</span> <span class="stat-label">App shipped</span> </div> <div class="stat-item"> <span class="stat-value">Daily</span> <span class="stat-label">Puzzle game</span> </div> </div> </section> <section class="section"> <div class="container"> <article class="card reveal guess-launch-card"> <div class="guess-launch-grid"> <div> <div class="kicker">Daily Ritual</div> <h2>A new gadget puzzle every day. Come back tomorrow and do it again.</h2> <p class="lead">
One shared puzzle. Four turns. Six curated answers. Free to play, no account needed.
</p> <div class="pill-list"> <span class="pill">Daily puzzle</span> <span class="pill">Visible attribution</span> <span class="pill">Public leaderboard</span> </div> <div class="cta-row"> <a class="btn btn-primary" href="/guess-the-gadget/">Play Guess the Gadget</a> <a class="btn btn-secondary" href="/guess-the-gadget/#how-it-works">See how it works</a> </div> </div> <aside class="guess-launch-visual"> <div class="guess-launch-art-frame"> <img src="/images/guess-the-gadget-og.svg" alt="Guess the Gadget launch artwork" width="1200" height="630" loading="lazy"> </div> <div class="guess-launch-meta"> <div> <span class="meta">Format</span> <p>6 choices. 4 turns. Score based on how fast you get it.</p> </div> <div> <span class="meta">Sources</span> <p>Every answer links back to where the info came from.</p> </div> </div> </aside> </div> </article> </div> </section> <section class="section"> <div class="container split home-arc-split"> <article class="card reveal home-archive-card"> <div class="kicker">Why This Site Exists</div> <h2>The old podcast and blog work still shape the new app and web work.</h2> <p class="lead">
Ten years of podcasting and gadget coverage left a trail. The history archive is where that all lives —
            verified records, a curated timeline, and the design progression from era to era.
</p> <div class="archive-signal-grid"> <div class="archive-signal"> <span class="meta">Podcast era</span> <strong>2009-2017</strong> </div><div class="archive-signal"> <span class="meta">Current mode</span> <strong>Building apps</strong> </div><div class="archive-signal"> <span class="meta">Working style</span> <strong>Nights, weekends, one thing at a time</strong> </div> </div> <div class="cta-row"> <a class="btn btn-primary" href="/history/">Explore History Archive</a> <a class="btn btn-secondary" href="/fun/">Open DOS Lab</a> </div> </article> <article class="card reveal home-lab-card"> <div class="kicker">Old Work, New Format</div> <h2>The DOS Roots Lab turns old Pascal programs into browser games you can actually play.</h2> <p class="lead">
Written in Turbo Pascal in the early days. Rebuilt for the web. Still kind of fun.
</p> <div class="pill-list"> <span class="pill">Pascal roots</span> <span class="pill">Browser remakes</span> <span class="pill">Playable archive</span> </div> <div class="cta-row"> <a class="btn btn-primary" href="/fun/">Visit DOS Roots Lab</a> <a class="btn btn-secondary" href="/timeline/">View Timeline</a> </div> </article> </div> </section> <section class="section"> <div class="container split home-story-split"> <article class="card reveal home-log-card"> <div class="kicker">Latest From The Log</div> <h2>Project notes, launch updates, and what I&apos;m learning as I go.</h2> <div class="home-post-list"> <article class="home-post-item"> <div class="meta">March 26, 2026</div> <h3><a href="/blog/refined-the-site-a-bit/">Refined the site a bit</a></h3> <p>Updated the site look a little. </p> </article><article class="home-post-item"> <div class="meta">March 22, 2026</div> <h3><a href="/blog/mobile-blog-posting-active/">Mobile blog posting active!</a></h3> <p>How I set up Keystatic CMS to post to my Astro blog from any device.</p> </article><article class="home-post-item"> <div class="meta">March 22, 2026</div> <h3><a href="/blog/rss-feed-for-geek-tech-live/">RSS feed for GeekTechLive </a></h3> <p>RSS feed and links active on the site</p> </article> </div> <div class="cta-row"> <a class="btn btn-primary" href="/blog/">Read The Blog</a> <a class="btn btn-secondary" href="/apps/">Browse All Apps</a> </div> </article> <article class="card reveal home-about-card"> <div class="kicker">About Chris</div> <h2>Solo work, built outside the day job.</h2> <p class="lead">
StackGarden is live. More things in progress. The about page has the full story.
</p> <div class="cta-row"> <a class="btn btn-primary" href="/about/">Read About Chris</a> <a class="btn btn-secondary" href="/contact/">Get In Touch</a> </div> </article> </div> </section> </main>  </div> <footer> <div class="container"> <a class="footer-brandmark" href="/" aria-label="GeekTechLive home"> <img src="/images/geektechlive-wordmarkA.png" alt="GeekTechLive wordmark" width="1049" height="312" loading="lazy"> </a> <p>&copy; 2026 GeekTechLive. Podcast and blog roots. App development future.</p> <nav class="footer-nav" aria-label="Site navigation"> <a href="/apps/">Apps</a> <a href="/blog/">Blog</a> <a href="/guess-the-gadget/">Guess the Gadget</a> <a href="/fun/">DOS Lab</a> <a href="/history/">History</a> <a href="/about/">About</a> <a href="/contact/">Contact</a> </nav> <nav class="footer-social" aria-label="Social profiles"> <a class="footer-social-link" href="https://bsky.app/profile/geektechlive.com" target="_blank" rel="noopener noreferrer"> <svg class="footer-social-icon" aria-hidden="true" width="18" height="18" viewBox="0 0 24 24" fill="currentColor"> <path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.785 2.643 3.593 3.519 6.173 3.175-.375.553-.15 1.58 1.198 2.578-3.038-.084-5.994 1.093-5.994 3.998C2.001 23.266 7.293 24 9.67 24c5.135 0 8.702-4.098 8.702-9.24 0-3.14-1.074-4.7-2.39-6.013L12 12.683V10.8Zm0 0c1.087-2.114 4.046-6.053 6.798-7.995C21.434.944 22.439 1.266 23.098 1.565 23.861 1.908 24 3.08 24 3.768c0 .69-.378 5.65-.624 6.479-.785 2.643-3.593 3.519-6.173 3.175.375.553.15 1.58-1.198 2.578 3.038-.084 5.994 1.093 5.994 3.998C21.999 23.266 16.707 24 14.33 24c-5.135 0-8.702-4.098-8.702-9.24 0-3.14 1.074-4.7 2.39-6.013L12 12.683"></path>   </svg> <span>Bluesky</span> </a><a class="footer-social-link" href="https://www.instagram.com/geektechlive/" target="_blank" rel="noopener noreferrer"> <svg class="footer-social-icon" aria-hidden="true" width="18" height="18" viewBox="0 0 24 24" fill="currentColor">  <path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069ZM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0Zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324ZM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8Zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881Z"></path>  </svg> <span>Instagram</span> </a> <a class="footer-social-link" href="/rss.xml"> <svg class="footer-social-icon" aria-hidden="true" width="18" height="18" viewBox="0 0 24 24" fill="currentColor"> <path d="M6.503 20.752c0 1.794-1.456 3.248-3.251 3.248-1.796 0-3.252-1.454-3.252-3.248 0-1.794 1.456-3.248 3.252-3.248 1.795 0 3.251 1.454 3.251 3.248Zm-6.503-12.572v4.811c6.05.062 10.96 4.966 11.022 11.009h4.817c-.062-8.742-7.099-15.758-15.839-15.82Zm0-8.18v4.819c11.479.076 20.763 9.362 20.84 20.82H24C23.924 11.166 12.824.076 0 0Z"></path> </svg> <span>RSS</span> </a> </nav> <p class="footer-legal"><a href="/privacy/">Privacy</a> | <a href="/terms/">Terms</a></p> </div> </footer> <button class="consent-manage-btn" type="button" data-consent-manage hidden>Privacy settings</button> <section class="consent-banner" data-consent-banner hidden aria-live="polite" aria-label="Analytics consent"> <p class="consent-copy">We use analytics to understand site performance. You can accept or decline tracking.</p> <div class="consent-actions"> <button class="btn btn-primary" type="button" data-consent-accept>Accept</button> <button class="btn btn-secondary" type="button" data-consent-decline>Decline</button> <a class="consent-link" href="/privacy/">Privacy policy</a> </div> </section> <script>
      console.log('%cHey, you found the console.', 'color:#f1cb52;font-size:14px;font-weight:bold;');
      console.log('%cBuilt by Chris. Astro + TypeScript + too many late nights.', 'color:#35ddc0;font-size:12px;');
      console.log('%cSource: github.com/chrisfavero (or just ask)', 'color:#b7ced0;font-size:11px;');
    </script> <script type="module">document.addEventListener("astro:page-load",()=>{const d=new AbortController,{signal:i}=d;document.addEventListener("astro:before-swap",()=>d.abort(),{once:!0});const o=document.querySelector("[data-nav]"),a=document.querySelector("[data-nav-toggle]"),p=o?Array.from(o.querySelectorAll("a")):[];if(o&&a){const t=()=>{o.classList.remove("show"),a.setAttribute("aria-expanded","false"),a.textContent="Menu"},s=()=>{o.classList.add("show"),a.setAttribute("aria-expanded","true"),a.textContent="Close"};a.addEventListener("click",()=>{a.getAttribute("aria-expanded")==="true"?t():s()}),document.addEventListener("click",e=>{o.classList.contains("show")&&!o.contains(e.target)&&!a.contains(e.target)&&t()},{signal:i}),document.addEventListener("keydown",e=>{e.key==="Escape"&&o.classList.contains("show")&&(t(),a.focus())},{signal:i}),p.forEach(e=>{e.addEventListener("click",t)})}const c=document.querySelectorAll(".reveal");if("IntersectionObserver"in window&&c.length){const t=new IntersectionObserver((s,e)=>{s.forEach(r=>{r.isIntersecting&&(r.target.classList.add("in-view"),e.unobserve(r.target))})},{threshold:0,rootMargin:"0px 0px -4% 0px"});c.forEach(s=>t.observe(s))}else c.forEach(t=>t.classList.add("in-view"));(()=>{const t="gtl_consent_analytics",s="G-CFYFEW07MV",e=document.querySelector("[data-consent-banner]"),r=document.querySelector("[data-consent-manage]"),l=document.querySelector("[data-consent-accept]"),u=document.querySelector("[data-consent-decline]");if(!e||!r||!l||!u)return;const g={get(n){try{return window.localStorage.getItem(n)}catch{return null}},set(n,v){try{return window.localStorage.setItem(n,v),!0}catch{return!1}}},L=()=>{if(window.gtag)return;const n=document.createElement("script");n.async=!0,n.src=`https://www.googletagmanager.com/gtag/js?id=${s}`,document.head.appendChild(n),window.dataLayer=window.dataLayer||[],window.gtag=function(){window.dataLayer.push(arguments)},window.gtag("js",new Date),window.gtag("config",s)},w=()=>{e.hidden=!1,r.hidden=!0},m=()=>{e.hidden=!0,r.hidden=!1},f=n=>{g.set(t,n),n==="granted"&&L(),m()},h=g.get(t);h==="pending"||!h?w():m(),r.addEventListener("click",w),l.addEventListener("click",()=>f("granted")),u.addEventListener("click",()=>f("denied"))})()});</script> </body> </html> <script>
  (function () {
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    const counters = document.querySelectorAll('.stat-value[data-count]');
    if (!counters.length) return;
    const observer = new IntersectionObserver(function (entries, obs) {
      entries.forEach(function (entry) {
        if (!entry.isIntersecting) return;
        const el = entry.target;
        const target = parseInt(el.dataset.count, 10);
        const suffix = el.dataset.suffix ?? '';
        const useComma = el.hasAttribute('data-format');
        const duration = target >= 100 ? 2200 : 3200;
        const start = performance.now();
        const tick = function (now) {
          const progress = Math.min((now - start) / duration, 1);
          const eased = 1 - Math.pow(1 - progress, 2);
          const current = Math.round(eased * target);
          el.textContent = (useComma ? current.toLocaleString('en-US') : String(current)) + suffix;
          if (progress < 1) requestAnimationFrame(tick);
        };
        requestAnimationFrame(tick);
        obs.unobserve(el);
      });
    }, { threshold: 0.6 });
    counters.forEach(function (el) { observer.observe(el); });
  })();
</script> <script>
  (function () {
    const el = document.querySelector('.hero-terminal');
    if (!el) return;
    const lines = [
      '> GEEKTECHLIVE v17 initialized',
      '> loading: apps, games, history...',
      '> ready.'
    ];
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      el.textContent = lines.join('\n');
      return;
    }
    let output = '';
    let lineIdx = 0;
    let charIdx = 0;
    const tick = () => {
      if (lineIdx >= lines.length) {
        el.textContent = output.trimEnd();
        return;
      }
      const line = lines[lineIdx];
      if (charIdx < line.length) {
        charIdx++;
        el.textContent = output + line.slice(0, charIdx) + '\u258b';
        setTimeout(tick, 28);
      } else {
        output += line + '\n';
        lineIdx++;
        charIdx = 0;
        setTimeout(tick, 110);
      }
    };
    tick();
  })();
</script>