I’m currently working on a personal project that needed a way to instantly capture UI context from a user and hand it off to an AI layer. Basically, letting the user show what they’re seeing instead of typing it out.
My first instinct was to just build this internally and move on. But the more I built it, the more I realized it wasn’t really tied to that project at all, instead, it was a generic problem: “let a user snip part of the screen and pass it somewhere useful,” which is something a lot of people building AI-powered tools probably need. So instead of keeping it in one codebase, I pulled it out and published it to npm. That way it can actually grow, get used in things I’m not even thinking about, and hopefully be useful to other people.
That’s how truden came to be.
Problems I think it solves
Assuming you have an in-app/in-SaaS assistant—for example, one in a CRM, ERP, HRMS, project management tools etc and a user tells it that something is broken, the assistant has no idea what “it” looks like. The user types out a description, the assistant asks a couple of follow-up questions, and a few messages later, you’ve burned a bunch of back-and-forth on something that would’ve taken two seconds to just see.
Truden fixes that by letting users show the assistant directly, without leaving the page. Just hold Alt and shake your mouse, and a snipping overlay appears, then elect a region, or hit Enter to capture the whole window, and the capture goes straight into your app’s own AI assistant—either as an image or as a text description generated by a vision LLM. Your choice.
The gesture
import truden from "truden";
truden.init({
onResult: (blob) => {
// attach directly to your chat UI
attachToChat(blob);
},
});
Enter fullscreen mode Exit fullscreen mode
That’s the entire setup for the simplest case. Hold Alt, shake left-right a few times, drag to select, done.
Alt+shake is just the default and not the only way in. Truden also ships a keyboard shortcut, an opt-in floating trigger button, a custom DOM event you can wire into your own UI, touch long-press for mobile, and a plain truden.open() you can call from literally anywhere. All of them funnel through the same core trigger.
Two modes, depending on where the capture needs to go
Mode A: straight to your chat interface. If you already have a multimodal AI assistant, there’s no reason to round-trip through a backend first. Truden hands you the raw image Blob and gets out of the way.
Mode B: vision LLM backend, adapter-based. If you don’t have a multimodal chat UI — bug trackers, support tools, anything that wants plain text instead of an image, truden can POST the capture to a route you control, and you plug in whatever provider you’re already using:
// app/api/truden/route.ts
import { handler } from "truden/server";
import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";
export const POST = handler({
analyze: async ({ image, prompt }) => {
const { text } = await generateText({
model: openai("gpt-4o"),
messages: [{ role: "user", content: [{ type: "image", image }, { type: "text", text: prompt }] }],
});
return text;
},
});
Enter fullscreen mode Exit fullscreen mode
I went back and forth on this one. My first instinct was to have truden own the provider logic directly, read an API key from .env, sniff the key format, branch into an Anthropic or OpenAI request shape. But that means truden has to keep up with every provider’s API changes forever, and it only covers two providers out of the box.
The adapter shape flips that around: truden’s job stops at “here’s the image and the prompt,” and you own the actual LLM call with whatever SDK, provider, or self-hosted model you’re already using.
Why I swapped html2canvas for snapdom
The capture engine itself was the other real decision here. My first pass used html2canvas, which is the default reach for “screenshot the DOM”. html2canvas is effectively unmaintained at this point, and it’s noticeably slow on anything beyond a small element.
I switched to snapdom instead: zero dependencies of its own, actively maintained, and dramatically faster on larger captures, roughly an order of magnitude on complex pages, by their own benchmarks. It also captures with real fidelity; styles, pseudo-elements, embedded fonts, same-origin iframes, which is exactly what “full fidelity screenshot” has to mean for this to actually be useful.
Try it (it’s still in beta tho)
npm install truden
Enter fullscreen mode Exit fullscreen mode
or
pnpm install truden
Enter fullscreen mode Exit fullscreen mode
Repo and full docs –> framework guides for React, Next.js, Svelte, Vue, Angular, TanStack Start, Solid, and vanilla JS, plus trigger config, both modes, and known limitations — are here:
Repo: https://github.com/Igwefran6/truden
Doc: https://igwefran6.github.io/truden-docs