Performance Marketing · AI Product Development

Jim
Rhine.

Builder of things that should exist.

Ten years in performance marketing. One year building an AI product suite from scratch during a job search that took longer than expected. Eight tools later, I understand both sides of the problem — the marketer who needs better tools and the builder who has to make them.

Scroll

I don't see tasks.
I see systems.

I've been an early adopter my whole career. Before AI it was beta software, before that it was figuring out how Facebook's ad platform worked from the inside as a founding hire on their Phoenix support team. The technology changes. The instinct to understand how things actually work doesn't.

At Gannett I managed 175+ client accounts and over $2.5M in annual ad spend across Meta, YouTube, and Snapchat. When I got laid off in a company restructuring in 2025, I didn't spend the time waiting. I subscribed to ChatGPT, Claude, and Gemini — not to compare chatbots, but to understand where each one excelled and how they could work together. What started as curiosity became eight production-grade AI tools.

My philosophy on AI hasn't changed since I built my first custom GPT at Gannett and cut a 15-hour monthly workflow down to under 4 hours. AI doesn't replace people. It removes the friction that wastes their time. Every product in this portfolio is built around that idea.

Performance marketing taught me to measure everything, distrust my own assumptions, and kill anything that wasn't working no matter how much I liked it. Building these tools is the same discipline pointed at a different problem. None of them started as an experiment for the sake of using AI — they started as friction I actually hit, in a job search, in a hobby, in a client account. The tools are the byproduct. Asking what's actually broken here is the habit that doesn't change.

Outside of work I'm a Warhammer 40k hobbyist, 3D printing and painting miniatures. I run a YouTube channel called Lore A Plenty covering 40k, Witcher, and Lord of the Rings lore. I have German Shepherds who have inspired more than one product. I lift, I collect music obsessively, and I have more interests than hours to pursue them.

Performance Marketing

Meta Ads Manager YouTube Ads Snapchat Ads Google Ads Attribution Campaign Strategy ATS Optimization Creative Operations

AI & Product

Prompt Engineering Gemini API Claude API Product Strategy UX Design Workflow Architecture JSON Schema AI Pipeline Design

Development

React TypeScript Node.js Express Vercel Redis Tailwind CSS Swift / Xcode Chrome Extensions

Eight products.
One philosophy.

Every tool in this portfolio starts from the same place — something frustrated me or something I loved needed a better solution. AI handles the execution. The domain knowledge is the product.

8

Products shipped

109

Delivery iterations, ResumeGap alone

30+

Generated scene styles, True To Fur

1

Year, zero prior engineering background

01

ResumeGap

Know your fit before you apply.

AI-powered career intelligence platform. Resume gap analysis, ATS optimization, Reality Check Verdict on job postings, cover letter generation, interview prep, and Chrome/Firefox extensions. Live at resumegap.io.

Live Product SaaS Gemini API React Clerk Auth

02

📊

Job Pulse

Real market intelligence, not vibes.

AI labor market dashboard with salary trends, hot and cooling role tracking, skill demand analysis, and temporal anchoring so data reflects right now — not 18 months ago.

Market Intel Recharts React 19

03

📱

Ad Studio Mockup

Built for the day Meta goes down.

Pixel-accurate Facebook and Instagram ad mockups across Feed, Desktop, and Story placements — with real spec validation, AI copy analysis, and carousel coherence scoring. No Meta dependency.

Marketing Tech Spec Validation AI Copy

04

⚙️

Visora

From raw documents to board-ready visuals.

AI document intelligence platform. Upload Word, Excel, PDF, or CSV files and generate presentation decks, infographics, executive briefs, BI dashboards, or social carousels — rendered through a JSON-to-Nano Banana image pipeline instead of a template engine.

Document AI Nano Banana Gemini Flash

05

💀

Grim-Gen

Warhammer 40k thumbnail forge.

AI creative production suite for 40k YouTube creators. Faction-tuned aesthetic chapters, Cogitator prompt expansion, multi-layer typography with drag-and-drop positioning, 1080p export. Built for Lore A Plenty.

Creative AI HTML5 Canvas 40k

06

🐾

True To Fur Studio

Your pet. Actually your pet.

AI pet portrait platform with identity preservation — 30+ scene styles from spa humor to legacy portraits. Started as an Etsy observation. Became personal after Thor passed in January.

Consumer AI Identity Preservation Gemini Image

07

🎵

Library Doctor

Read-only first. Always.

macOS desktop app for Apple Music library diagnostics. Scans 4,000+ tracks in seconds. Finds duplicates, orphaned files, missing tracks, metadata issues, and artwork problems — without touching anything until you say so.

macOS Swift FFmpeg

08

✂️

EarMark

Drop video. Set range. Get clip.

macOS video clip extractor. VLC-powered preview, frame-level scrubbing, clip queue for batch exports, lossless Original Format Copy or precise MP4 re-encode. No timeline editor required.

macOS VLCKit Swift

ResumeGap

Built because the job market was wasting my time.

Status

Live — resumegap.io

Timeline

March 2026 – Present · 28 active build days · 109 delivery zips

Stack

Vanilla HTML/CSS/JS Node.js Gemini 2.5 Flash Clerk Redis Vercel Chrome MV3 Firefox MV2

Live Link

resumegap.io ↗

How It Started

I didn't set out to build a SaaS product. I set out to stop wasting time on a job search that was taking longer than any I'd had before.

It was mid-2025. Laid off in a restructuring at Gannett, applying into a market that was genuinely slower than anything I'd navigated in my career. Every application wanted the same things — resume tailored to the posting, cover letter written for that specific role, language mirrored from the job description because ATS filters are looking for exact matches. Multiply that by the volume of applications a market like this requires and you're spending most of your productive hours on preparation before a single human has looked at anything.

I'd built a Claude artifact that could take a job description and my resume and tell me where the gaps were. Draft a cover letter. It was rough — required manual input for everything, didn't remember anything between sessions, produced output that needed editing before it was usable. But it cut the time down enough that I kept pulling the thread.

I moved it into Google AI Studio because I wanted more than an artifact allowed. Rebuilt it with more structure. And while I was in there I built the Market Overview tool alongside it — I wanted to understand not just whether my resume matched a specific job but whether the roles I was targeting were growing or contracting. Two tools, same problem, different angles. Used both of them for myself for a while. They worked well enough that I started thinking other people in the same situation would find them useful. That's where the project changed.

ResumeGap landing page — Know Your Fit Before You Apply

Landing page — the value proposition in one line

ResumeGap analysis dashboard

Analysis dashboard — match score, Reality Check Verdict, gap breakdown

Building It Out

The Reality Check Verdict wasn't planned. It came from running my own applications through the tool and noticing something. Some job descriptions were full of language that looked fine individually and was alarming in aggregate. "Unlimited PTO" combined with "full presence expected during core hours 8am–7pm" combined with "small but scrappy team where everyone wears many hats" — none of those phrases are obviously bad on their own. Together they're describing something specific. The tool started flagging that, rating postings from Safe to Caution to RUN. That became the feature people noticed first.

Interview prep came after that. Then recruiter outreach templates — five of them, calibrated to different stages, all written to stay under LinkedIn's character limits because nobody told me that was a constraint until I started testing them on real connection requests. Then the Candidate Signal Report, which flips the perspective entirely and generates a recruiter-facing summary of your candidacy. The idea was that you could attach it to an application and make it easier for a recruiter to see why you were worth a conversation before they opened your resume.

None of this was roadmapped. Each feature came from actually using the tool on real applications during a real search. Someone could argue that's not a development methodology. They'd be right. It's also why the features that exist are the ones that actually matter.

ResumeGap features — ATS Match, Reality Check, Toxic Phrases

Feature set — seven tools in one analysis

ResumeGap pricing — half the price of Jobscan

Pricing — half the cost of Jobscan, more features than both

Making It Real

The artifact version worked for me because I knew exactly what I was doing with it. A real product needed to work for someone who just found it, had no context, and was probably applying for a job they needed. That's a different problem.

Proper deployment meant building a backend. Node.js serverless functions on Vercel, one per feature. All AI processing server-side so API keys never touch the browser. Authentication through Clerk — switched to live production keys in late June after running in test mode long enough to find most of the edge cases. Persistent storage through Redis for saved reports, resume versions, and shareable report links with 90-day TTL. A JSON sanitizer on every single endpoint because Gemini occasionally returns control characters inside JSON strings and without the sanitizer those become silent 500 errors that are genuinely unpleasant to track down.

The browser extensions came from a specific frustration — switching between a job board and the analysis tool and copying job descriptions manually was unnecessary friction. Chrome extension first, Manifest v3. The Firefox port took five iterations. MV2 and MV3 handle background scripts, API namespacing, and permission models differently enough that a straight port doesn't work. I know this from experience. Both extensions now clip job postings directly from LinkedIn, Indeed, or any career page into a queue that loads straight into the analysis flow.

Clipped Jobs panel — Chrome extension

Chrome extension — clip jobs from LinkedIn and Indeed directly to your queue

ResumeGap saved reports panel

Saved reports — track every application over time

Interview Prep Pack

Interview Prep Pack — best stories, weak spots, salary tactics, recruiter screen

Where It Is Now

ResumeGap went from a personal artifact to a live SaaS product in roughly 3.5 months. 28 build days. 109 delivery iterations — a number that only makes sense if you understand that building alone means every bug is yours to find, every Safari rendering quirk is yours to debug, every edge case in Gemini's JSON output lands on you specifically.

The tool does substantially more now than the one I built for myself. Resume gap analysis, ATS optimization, Reality Check Verdict on job postings, cover letter generation in multiple styles, line-by-line resume rewriting, keyword gap analysis, learning path generation, interview prep across five dimensions, recruiter outreach messages for every stage of the process, a Candidate Signal Report, batch job comparison, saved reports, multi-resume version management, shareable report links, and browser extensions for Chrome and Firefox.

The application tracker I keep thinking about would close the loop. Everything before you apply is handled. The tracker handles after. Together that's a complete job search operating system hiding inside what started as a keyword matcher. It'll get built.

"We price ResumeGap for job seekers, not procurement departments."

The Constraint That Mattered Most

One thing hasn't changed from the artifact version to the current product. ResumeGap doesn't fabricate experience. The resume rewriter works with what's already on your resume, said better. The cover letter doesn't invent qualifications. The interview prep doesn't script you through gaps you can't cover — it flags them honestly and gives you language to address them in the room. AI that invents skills to fill gaps doesn't help job seekers. It sets them up for interviews they can't survive. That constraint was the first design decision and it's still the most important one.

Stack

Vanilla HTML/CSS/JS Node.js Serverless Gemini 2.5 Flash Clerk Auth Redis Vercel Chrome MV3 Firefox MV2 JSON Sanitizer

JobPulse

Because "the market is tough" isn't actually useful information.

Status

Live in AI Studio + Integrated in ResumeGap

Timeline

November 2025 – Present

Stack

React 19 TypeScript Tailwind CSS Gemini API Recharts JSON Schema

The Origin

While building ResumeGap I kept running into the same problem from a different direction. The tool could tell you how well your resume matched a specific job. What it couldn't tell you was whether that job was worth chasing at all — whether the role was growing or contracting, whether the salary expectation made any sense, whether the skills you were missing were worth acquiring or already becoming irrelevant by the time you learned them.

Different question. Needed its own answer. Job Pulse started November 2025 — what if you could get a real intelligence briefing on any role or industry in seconds, without wading through three LinkedIn articles and a Glassdoor page last updated sometime in early 2023.

Job Pulse dashboard

Market overview — Technology and Software sector with salary progression and top movers

Job Pulse hot and cooling roles

Hot vs cooling roles — LLMOps Engineer +52.4% vs Junior Manual QA Tester -45.8%

What It Does

Pick an industry or search a specific role. You get an executive summary of current market conditions, a five-year salary chart, a side-by-side breakdown of roles gaining demand versus roles actively declining, the skills appearing most on job postings right now, emerging tools employers are actually hiring for, and a pro tip calibrated to that specific market.

The Technology and Software view right now shows LLMOps Engineer at +52.4% growth. Junior Manual QA Tester at -45.8% decline. That's not decorative data — that's the kind of signal that should change how someone spends the next six months. Search "paid social specialist" and the dashboard rebuilds around that niche. Salary trend from $63k in 2022 to $81k in 2026. That granularity is what separates it from a generic market summary.

The One Decision That Changed Output Quality

Most AI-powered market tools have a quiet problem nobody talks about. They pull from training data without anchoring to the present, so you get confident analysis describing a market from eighteen months ago. The numbers feel slightly off and you can't figure out why. Job Pulse hard-codes a time anchor into every prompt. The model is explicitly instructed to evaluate conditions as of Q2 2026. The executive summary opens with "As of Q2 2026" because that's what the model was told to reason about. It's invisible when it works. Which is how it should be.

Where It Lives Now

Job Pulse exists in two places. The standalone version in AI Studio is the full product — denser, more data, built to function on its own as a career intelligence dashboard. The Market Overview tab inside ResumeGap is the same core idea calibrated to complement a gap analysis rather than replace it. Same philosophy doing two different jobs.

What It Gets Wrong

The data is AI-estimated from industry knowledge and hiring pattern analysis. Directional trends, not hard statistics from live job posting databases. The tool says this in the footer. That disclaimer isn't legal cover — it's accurate. Job Pulse is useful for directional decisions. For salary floor before accepting an offer — go look at actual compensation data. The tool can't do that and doesn't pretend to. I'd rather it be honest about the edges than confident past them.

Stack

React 19 TypeScript Tailwind CSS Gemini API Recharts JSON Schema Temporal Prompt Anchoring

Ad Studio Mockup

Built for the day Meta goes down and clients still need mockups.

Status

Live in AI Studio

Built During

Early 2026 — July 2026

Stack

React Tailwind CSS Express Gemini API adSpecs.ts assetValidator.ts

The Origin

Meta goes down sometimes. Not often, but enough to be annoying. And when it does, the third-party tools that depend on Meta's infrastructure go with it. At Gannett that meant our mockup tools for client creative reviews would vanish at exactly the wrong moment — campaign needs approval, client is waiting, nothing works. We'd improvise. Everyone does. The improvised versions looked like it.

So I built something that didn't need Meta to be having a good day. Self-contained, no external dependencies for the core workflow. Pixel-accurate placements, real spec validation, AI copy analysis. Works fine when Meta's infrastructure is being weird, which honestly is more useful than I initially expected it to be. That was the original reason. The tool kept growing from there.

Ad Studio mobile feed with fit analysis

Mobile Feed — Strong Fit, 90% engagement probability, hook strength analysis

Ad Studio Story placement — Weak Fit

Story/Vertical — same ad, Weak Fit flagged with specific reasons. The placement difference made visible.

What It Does

The tool renders pixel-accurate mockups of Facebook and Instagram ads across every major placement — Mobile Feed, Desktop Feed, Story/Vertical — built from actual HTML and CSS. Not a static graphic with your content dropped into it. Real elements, real flex containers, real CSS. Text truncates where Facebook truncates it. Video ads actually play in the mockup — something a screenshot can't show but matters when reviewing video creative with a client on a call.

Upload a creative and it validates immediately against actual Meta specs. The verdict is specific — Recommended, Allowed, Allowed but not ideal, or Unsupported with the exact reason. Resolution 800x800 is below minimum 1080x1080. That kind of specific. No vague warnings that leave you guessing what to fix.

Desktop Feed mockup

Desktop Feed rendering

Video ad mode

Video ad — Good, Needs Polish verdict

Carousel with coherence scoring

Carousel coherence score — 7/10, actionable fix

The Feature That Makes It A Teacher, Not Just A Tool

Most mockup tools show you what the ad looks like. That's the whole product. You see the thing, you approve the thing, you find out later what was wrong with it. This one flags problems while you're still building. Specific ones, with actual reasoning.

Weak Fit on a Story placement means "headline might wrap awkwardly to two lines" — not a vague warning, the specific thing that's going to look bad. The carousel card showing Unsupported with "Resolution 800x800 is below minimum 1080x1080" saves you an upload attempt and whatever time you'd spend figuring out why Ads Manager rejected it.

I kept thinking about the account managers and creative teams I'd worked with over the years — smart people who didn't run campaigns daily and didn't have the pattern recognition that comes from doing this for seven years. The fit analysis and validation verdicts are basically a paid social manager looking over your shoulder while you build, without requiring an actual paid social manager in the room. Didn't plan that feature that way. Just kept asking who else would use this besides me.

Spec validation and creative angles

Spec validation + eight creative angle frameworks, configurable tone

Per-card carousel validation

Per-card validation — Unsupported flagged with exact resolution requirement

What's Not Done

Reels placement isn't fully built out. Stories work. Feed works across mobile and desktop. Reels has enough unique rendering behavior that it needs its own treatment. Still pending.

Stack

React Tailwind CSS Express Node.js Gemini API adSpecs.ts assetValidator.ts PNG + JSON Export

Visora

Document intelligence that skips the template — the app writes a JSON description of the deliverable and lets an image model render it directly.

Status

Live in AI Studio

Stack

React Express Gemini 2.5 Flash Nano Banana v2.4 mammoth xlsx esbuild Vite

The Origin

Most document intelligence tools stop at analysis and hand you a wall of text. I wanted Visora to hand back something you'd actually put in front of a stakeholder — a deck, an infographic, an executive brief — without hand-building a template for every shape a deliverable could take. Templates felt like the wrong abstraction from the start: consistent, a little flat, and only ever as good as the templates I'd bothered to build.

Around the same stretch I was building it, NotebookLM started showing up everywhere — Google's version of source-grounded document intelligence, built by a team with a lot more resources than a solo project running out of AI Studio. That's not a coincidence I get to take credit for. It's just the timing. Watching a much bigger version of the same idea ship made the gap in my own thinking more obvious: the analysis was already good. The output format was the constraint.

Visora dashboard showing a generated visual brief alongside the source-grounded knowledge model

A generated Visual Brief next to its own knowledge model — source findings, interpretation, and hypotheses, each labeled by confidence tier

The Architecture

Visora skips the template renderer entirely and feeds a JSON pipeline straight into Nano Banana, Google's image generation model. Instead of dropping extracted data into a fixed layout, Visora writes a structured JSON description of the deliverable and lets the image model synthesize the actual visual. The design style, layout aspect ratio, and branding constraints all become parameters in that JSON rather than CSS in a template file.

That sounds like a small architectural choice. It isn't. It means the ceiling on output quality is no longer "how many templates did I build" — it's whatever the image model is capable of, which keeps moving without me touching the code.

What It Does

Drag in PDFs, Word, Excel, CSV, JSON, text, images, scans, or charts, or paste text and CSV directly. The Analysis stage separates its output into tiers — Source Findings (hard factual grounding pulled straight from the document), Interpretation (derived logical evidence), and Hypotheses (potential strategic avenues) — so a reader can tell at a glance what's a quote from the source and what's the model reasoning past it. That tiering was the right idea from day one.

Every generated asset ships with a Nano Banana Prompt tab and a Structured JSON tab sitting right next to the visual — the actual instructions that produced the output, visible and inspectable rather than hidden behind a "regenerate" button and a shrug.

What's Still Being Worked Out

It's early, which means it's had a lot more testing from me than from anyone else. The image renders correctly, matching the JSON the app wrote — that reliability was the entire point of this pipeline. Where it still shows its age is the occasional run that needs a re-synthesize pass before it's presentation-ready, a normal generative-model retry rather than anything broken: a bad run means retrying the JSON, nothing more. I'd rather ship it at this stage and say so than wait for a version of "done" that a generative pipeline doesn't really have.

Stack

React Tailwind CSS Express Gemini 2.5 Flash Nano Banana v2.4 mammoth xlsx esbuild Vite JSON Deliverable Contract

Grim-Gen

Built for a YouTube channel. Useful for every lore creator who's spent forty minutes on a thumbnail that took forty seconds to reject.

Status

Live in AI Studio

Built For

Lore A Plenty ↗

Timeline

June 5 – July 9, 2026 · One month

Stack

React TypeScript Express Gemini API HTML5 Canvas Pointer Events Motion

The Origin

I run a Warhammer 40k YouTube channel called Lore A Plenty. The whole point of it is helping people learn 40k lore — and Witcher, and Lord of the Rings — in a way that's actually entertaining and genuinely relaxing. Long-form narration, calm delivery, the kind of content you put on when you want to absorb something without feeling like you're being yelled at. Every video still needs a thumbnail that stops someone mid-scroll in a feed full of other grimdark artwork.

The standard workflow was genuinely annoying — generate art, open Photoshop or Canva, resize everything to YouTube's 16:9 1080p requirement, add text, fight with the text because it's either unreadable against a busy background or looks like something from a 2009 gaming blog, export, realize the font tracking is wrong, start over. I've done that enough times to know I didn't want to keep doing it. So I built Grim-Gen instead. One place, start to finish.

The channel exists and has content worth watching. My focus over the last year has been on the product suite because the job search had more immediate stakes. Growing Lore A Plenty and adding content is still very much on the list. Grim-Gen will be waiting when that time comes back around.

Grim-Gen full interface

Full interface — Scriptorium Decoders, Cogitator Art Forge, Vox Layers, Aesthetic Chapters

Grim-Gen typography controls

Active Typography Scribe — font size, letter tracking, outline width, backing box, Sacred Enamels palette

What It Does

Type a character or scene concept into the Scriptorium Decoders panel. "Angron" is enough. Hit decode and the Cogitator Pre-Optimize system expands that into a full cinematic prompt — heavy weathering, gothic architecture, plasma fire, tox-smoke, the atmospheric detail that takes ten minutes to write well and about three seconds here. Pick an Aesthetic Chapter — eight options tuned for 40k visual language. Same base prompt, eight genuinely different visual results.

Grim-Gen finished output — The Forgotten Crusade

Finished export — "The Forgotten Crusade" · Angron at the Siege of Terra · Made in approximately four minutes

The Typography Engine — Which Is Actually The Product

Everybody does AI image generation now. Type a prompt, get a picture. That part stopped being impressive a while ago. What's actually hard is what happens after the image exists. You have incredible grimdark artwork and then you drop text on it and it immediately becomes unreadable. The image is dark where your text is dark, or the font looks fine at 200px and terrible at the size YouTube actually renders it in the feed. I've shipped thumbnails that looked good on my screen and embarrassing everywhere else.

Grim-Gen has a proper multi-layer typography system because of exactly that. Vox Layers lets you add multiple text layers and position each one with drag controls. Font size, letter tracking, and outline width adjust with sliders. The Heavy Backing Box draws a dark pill behind the text at whatever opacity keeps it readable without covering the artwork. Sacred Enamels Repository is a color picker tuned to 40k faction palettes. The export renders everything directly onto HTML5 Canvas at 1080p. What you see is what you download. No mismatch.

Stack

React TypeScript Express Gemini API HTML5 Canvas Pointer Events Motion Tailwind CSS 1080p PNG Export

True To Fur

Started with an Etsy listing. Became something else entirely.

Status

Live in AI Studio · Public release planned

Scenes

30+ styles · Spa · Legacy · Humor · Portraits

Stack

Gemini API Identity Preservation Multi-reference Processing Up to 10 Pet References Up to 5 Owner References

The Origin

I came across pet spa portraits on Etsy — the kind where someone's dog is rendered artistically, wrapped in a towel, looking vaguely regal and deeply unimpressed by the whole experience. Cute concept. Inconsistent execution, slow turnaround. I thought I could build something that did it better and instantly. So I did. Started with a handful of spa scenes and kept adding styles until there were over thirty. That part went roughly as planned.

Then Thor died in January.

My German Shepherd. Seven years old. The dog in the close-up photos drooling at a treat just out of frame. The one nose-to-nose with me at sunset — we apparently did that a lot, because there are multiple versions of that moment. The one the courtroom sketch tool accused of Excessive Cuteness in Case No. PAW-99-2024. The one who got a sheriff's badge in a sepia western saloon and somehow looked like he'd earned it.

I went back to True To Fur differently after that. Not for the funny stuff, though that still exists and still works. For the portraits. The ones that put him somewhere he never got to go. He never saw snow. The tool put him in it and got his face right. The tool was already built. It just turned out to matter more than I thought it would.

Thor — portrait in the snow, wearing a scarf

He never saw snow. The tool put him in it and got his face right.

Thor — running through snow

Full stride, running straight at the camera

True To Fur interface — scene gallery

Interface — pet identity upload, scene gallery, three angle variations per style

True To Fur generation settings

Generation settings — aspect ratio, 2K quality, custom scene fields like crime and reward amount

The Range

Thirty-plus scene styles across two categories — the funny ones and the other ones. Personality scenes: Bubble Beard with candlelit lighting and foam. Mud Mask Glow-Up with full green clay treatment and cucumber slices. Influencer Selfie Mode — mirror selfie, oversized aviators, ring light reflected in the lenses. Over-the-Top Foam Explosion — bubbles everywhere, the expression of an animal tolerating this with considerable dignity. Fashion Runway. Red Carpet with a "HAUTE PAUTURE" collar tag. Wanted Poster with customizable crime and reward amount. Courtroom Sketch — The Defendant, Case No. PAW-99-2024, Accused of: Excessive Cuteness.

Legacy scenes are different. Sunset Silhouette — owner and dog nose to nose with the sun behind them. Split Frame Then vs Now, puppy and adult side by side. Studio Portrait, dark background, professional lighting. Half-and-Half — owner and pet split down the center, faces pressed together. The black and white version of that one came from my reference photos and Thor's. That's me in that image. That's us.

Thor — Influencer Selfie Mode, sunglasses and phone

Influencer Selfie Mode — oversized aviators, phone in paw

Thor — studio portrait, dark background

Studio Portrait — dark background, professional lighting

Thor — foam explosion

Over-the-Top Foam Explosion

Thor — black and white studio portrait

Studio portrait — black and white

Thor — fashion runway

Fashion Runway — Haute Pauture

Thor — courtroom sketch

Courtroom Sketch — Excessive Cuteness

Thor — K9 Guardian, tactical harness on a mountain ridge

K9 Guardian — tactical harness, mountain ridge at first light

Thor and Jim — sunset silhouette

Sunset Silhouette — owner and pet, golden hour

Jim and Thor — black and white legacy portrait

Legacy portrait — black and white, cheek to cheek

"The ear set is right. The coat pattern is right. The way he holds himself is right. That's what identity preservation actually means in practice."

Thor — mountain sunrise

Mountain sunrise — he never stood here. The tool got his face right anyway.

Thor — golden hour, moon, stars triptych

Triptych — golden hour, full moon, Milky Way

Thor — amber eyes close-up

The amber eyes close-up. That exact expression. That exact level of focus.

Thor — then vs now

Then vs Now — same plaid collar in both. Puppy references uploaded separately.

Jim and Thor — Yotes cap portrait

Owner and pet portrait — both identities preserved

What's Not Done

Not publicly available yet. The tool works — these images are the proof. Making it properly available to other people, pricing it, handling the infrastructure for strangers uploading photos of animals they love — that work hasn't happened yet. It'll happen. The reason it needs to exist got a lot clearer in January.

Stack

Gemini API Identity Preservation Prompts Multi-reference Processing Up to 10 Pet References Up to 5 Owner References 2K Quality Premium Dark UI

Library Doctor

Built for people who have spent years collecting music and would really prefer not to break it.

Status

In active development · macOS desktop app

Stack

macOS Swift Xcode Claude + Codex FFmpeg Local-first

The Origin

Apple Music libraries are fragile in ways that aren't obvious until something goes wrong. You've got thousands of tracks accumulated over years — ripped CDs, purchases, downloads, files moved between computers, metadata edited with third-party tools, artwork added inconsistently, duplicates accreted gradually without anyone noticing. The library works fine until it doesn't. And when it doesn't, you're not entirely sure what happened or how to fix it without making things worse.

The tools available range from underwhelming to actively dangerous — the kind of apps that will helpfully delete things you didn't mean to delete. Library Doctor came from wanting something better. Specifically something that would tell me what was wrong without touching anything first.

Library Doctor dashboard — health score 36

Dashboard — health score 36/Messy · 4,615 files · 10 second scan · read-only by default

Library Doctor repair preview — artwork issues

Repair Preview — "Review only — no replacement artwork source is available." Honest about limits.

The Design Philosophy In One Line

"Read-only scan complete. No files will be changed during scan."

That's the first thing you see when Library Doctor finishes a scan. Not a list of things it already fixed. A report of what it found, with every potential change requiring your review before anything happens. That constraint is the product. Everything else exists in service of that one principle.

What It Does

Scan your library. Get a health score — 36 out of 100, rated Messy, with specific reasoning. "Your library has duplicate groups that may be different versions, so review them carefully before cleanup." Not just a number. An explanation of what the number means and what to do about it.

4,615 files scanned in 10 seconds. 1 exact duplicate — safe. 35 possible duplicates — manual review required. 368 similar tracks — review only, not automatic. That breakdown is the tool respecting the fact that similar tracks aren't the same as duplicate tracks. A live version and a studio version of the same song look similar to a naive algorithm. Library Doctor flags them for review. You decide what stays.

The Artwork section shows what "Review only" means in practice. Def Leppard albums flagged for artwork issues — current artwork visible, suggested artwork unavailable, and the honest verdict. The tool found the problem. It can't fix this specific one automatically. It tells you that rather than substituting something wrong.

Stack

macOS Native Swift + SwiftUI Xcode Claude + Codex FFmpeg + FFprobe Library XML Import Local-first · No Upload Read-only Default

EarMark

A video clip extractor that does one thing and doesn't make it complicated.

Status

V1.1 · Distributable DMG

Stack

macOS Swift SwiftUI VLCKit FFmpeg FFprobe

The Origin

Video editing tools for extracting clips fall into two categories. Professional applications that do everything and cost accordingly, where extracting a simple clip requires navigating a timeline editor designed for feature film production. And free command-line tools that work perfectly if you're comfortable typing FFmpeg flags from memory at 11pm. Neither of those is what I wanted. I wanted to drop a video file, set a start point, set an end point, and get a clip. That's it. EarMark does exactly that.

EarMark V1.1 interface

EarMark V1.1 — drop video, set range, clip queue, two export modes · FFmpeg + VLCKit confirmed at top

What It Does

Drop a video. The VLC-powered preview handles MP4, MOV, AVI, MKV, WMV, FLV, and more. Set a start point using frame-level controls — jumps of 10 seconds, 5 seconds, 1 second, half a second, tenth of a second. Set an end point the same way. Clip duration calculates automatically. Add to queue. Repeat. Export all at once.

Two export modes. Precise MP4 re-encodes for frame-accurate cuts. Original Format Copy does a lossless stream copy — faster, no quality loss, cuts land near keyframes rather than exactly on them. The interface tells you this directly: "Fast, lossless stream copy using the source format. Cuts may land near keyframes." You pick based on whether you need exact frame accuracy or lossless speed. Both are legitimate answers depending on what you're doing.

The dependency check at the top shows FFmpeg, FFprobe, and VLCKit status with installation paths. Green checkmarks mean everything's working. Queue state saves and loads. Close the app, come back, load the queue, pick up where you left off.

The App Icon

The icon is Thor. His face on a macOS application icon, sitting in the dock on a Mac Studio that runs continuously. That's not a design decision that needed explaining anywhere in the interface. It's just there.

Why It Exists

EarMark started as a practical need around the Lore A Plenty YouTube channel — extracting clips from long video files without pulling up a full production suite every time. It also became a way to learn desktop application development on macOS — Xcode, Swift, working with FFmpeg as a backend, packaging a proper distributable DMG. The technical learning was the point as much as the output. The app works. It's the most technically modest tool in this portfolio — no AI, no server-side processing, no auth, no pricing tiers. Just FFmpeg wrapped in a clean native interface that doesn't require you to know what FFmpeg is.

Stack

macOS Native Swift + SwiftUI VLCKit FFmpeg FFprobe Clip Queue Precise MP4 Original Format Copy DMG Package

I don't chase AI for its own sake. I chase problems worth solving. Sometimes that means writing code. Sometimes it means a sharper prompt. Sometimes it means throwing out the workflow and starting over. The tool was never the point — reducing the friction for whoever's actually using it is.