npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@brotskyllc/prompt-this-spot

v0.1.0

Published

Point at a spot in a React app, capture it, and hand an AI coding agent a ready-made prompt — or file it as user feedback.

Readme

prompt-this-spot: click any element in your React app and get a ready-made prompt for an AI coding agent

prompt-this-spot is an open-source React component library that turns "this button here" into a precise prompt for an AI coding agent such as Claude Code, Cursor or GitHub Copilot. You click the parts of a page you want changed, type what you want, and it writes a prompt that names each element by its visible text, HTML tag, attributes, CSS classes and DOM path, with a screenshot link attached. The same capture core also powers an in-app user feedback widget with screenshots and bug reports.

  • License: MIT
  • Works with: React 19, Next.js, Tailwind CSS v3 and v4, shadcn/ui, and apps without Tailwind through a prebuilt stylesheet
  • Output: plain-text prompts you can paste into any AI coding assistant, plus one-click links for Claude Code on the web and the Claude Code desktop and CLI app
  • Backend: none included; you plug in your own screenshot storage and feedback endpoint

Contents

Why prompt-this-spot

AI coding agents are good at changing code but bad at guessing which part of the UI you mean. "Make the upgrade button bigger" leaves the agent searching the codebase for the right button on the right page. prompt-this-spot gives the agent the missing context: the route, the exact element, its classes and test ID, its location in the DOM, and a picture of it. The agent can go straight to the component instead of guessing.

It helps two groups of people:

  • Developers, designers and product reviewers doing visual QA who want to hand UI changes to an AI agent without describing the page in words.
  • Users of your app who want to report a bug or suggest an improvement by pointing at it. Their report arrives with the same AI-ready prompt already written, so triage can go straight to an agent.

Features

It ships two tools that share one capture core:

  • Prompt this spot (element inspector for AI prompts): an engineer clicks the parts of a page they want changed, types what they want, and gets a prompt for an AI coding agent. The prompt describes each element (DOM path, visible text, styles) and links a screenshot of it. They can copy the prompt, open it in Claude Code on the web, or open it in a local Claude Code install. The keyboard shortcut is ⌘/Ctrl + Shift + P.
  • Send feedback (in-app feedback and bug report widget): a user of the app points at what's wrong, adds screenshots, picks a category and describes the problem. The report goes to your backend with the same AI prompt already assembled, so someone triaging it can hand it straight to an agent.

Both tools also:

  • Select several elements at once, even across page navigations, and describe them in one numbered prompt.
  • Capture element and full-page screenshots in the browser with modern-screenshot, with an optional note on each.
  • Mark up any screenshot with arrows, boxes, freehand lines and text labels before sending it. The marked-up image replaces the plain one, and the prompt tells the agent the markup is the user's, not part of the app.
  • Open as a left-hand drawer that pushes the app aside, so the page stays visible and clickable.
  • Pick elements inside open dialogs, popovers and menus.
  • Offer launchers that can be dragged to any corner and remember their position.
  • Support light and dark mode, and take your brand colors through Tailwind class overrides.
  • Stay out of the bundle for users who aren't allowed to use them (the heavy code loads on demand).

Example prompt

Clicking an "Upgrade plan" button on /settings/billing and typing a request produces this prompt:

Repository: your-org/your-repo
Page URL: https://app.example.com/settings/billing?tab=plans

In our app on the page "/settings/billing", I'm pointing at this element:

- What it shows: "Upgrade plan"
- Element: <button> data-testid="upgrade-plan"
- Classes: btn btn-primary
- Location (DOM path): button[data-testid="upgrade-plan"]

What I want changed here: Make this button full width on mobile

The repository comes from repoSlug, and the page URL is the one in the browser when the element was picked, so the agent can tell apart two apps with the same route, or a preview deployment from local development. Secrets in the URL (credentials, tokens, API keys, OAuth codes, signed-URL signatures, in the query or the fragment) are replaced with REDACTED before the URL is shown or stored. When spots come from different pages, each carries its own URL. The drawer shows the current page's URL and keeps it up to date as the app navigates.

When screenshots are on, each element also gets a public screenshot URL the agent can open. An optional checkbox appends a request for unit and end-to-end test coverage.

How it works

  1. Pick. Pick mode highlights the element under the cursor. A click records a description of the element straight away, so it survives the element unmounting later (for example, when its dialog closes).
  2. Capture. The package renders a screenshot of the element and its surroundings in the browser and hands the PNG to your upload function, which returns a public URL.
  3. Assemble. It builds a plain-text prompt from the repository, the page URL, element descriptions, screenshot links and your request.
  4. Hand off. "Prompt this spot" copies the prompt or opens it in Claude Code. "Send feedback" passes it, with the rest of the report, to your submitFeedback function.

The package ships as TypeScript source. It uses React 19, Tailwind CSS classes, shadcn/ui theme tokens, Radix primitives and modern-screenshot. It has no backend: your app supplies the pieces that differ between apps (who may use each tool, where screenshots are stored, where feedback goes) through one provider.

Install

Adding prompt-this-spot to a React app takes six steps. The examples use Next.js with the App Router and Bun; other setups need the same pieces.

Then check that it works. If something looks wrong, see Troubleshooting.

Before you start, your app needs React 19. With Tailwind CSS (v3 or v4) the package's classes compile with the rest of your app; without it, import the prebuilt stylesheet instead (see step 3). shadcn/ui is not required.

Let an AI coding agent install it

You can hand the whole job to Claude Code or another coding agent. Paste this prompt in your app's repository:

Install the prompt-this-spot package in this app by following the Install
section of https://github.com/AEGIS-Security-Investigations/prompt-this-spot#install.
Pin it to the newest commit on main. Show "Prompt this spot" to admins only and
"Send feedback" to every signed-in user, using this app's existing auth and toast
helpers. Store screenshots in the object storage this app already uses. Save
feedback where this app keeps similar records, or ask me if there is no obvious
place. Then run the app's typecheck, lint and tests.

Change who sees each tool to suit your app.

1. Add the package

The npm package name is @brotskyllc/prompt-this-spot. After its first release, install a pinned version with npm install --save-exact @brotskyllc/[email protected].

For source installs from GitHub, pin a commit so every install gets the same code:

# Find the newest commit on main
git ls-remote https://github.com/AEGIS-Security-Investigations/prompt-this-spot refs/heads/main

# Add the package pinned to that commit
bun add github:AEGIS-Security-Investigations/prompt-this-spot#<commit-sha>

# Add the peer dependencies your app doesn't already have
bun add lucide-react @uiw/react-codemirror @codemirror/view

npm, pnpm and Yarn take the same github:owner/repo#sha spec. Pinning to a commit also lets the update workflow open a pull request whenever this repository changes.

Pin a commit that is on main. A commit from a pull request's branch can disappear once the branch is deleted, and every install of it then fails. The update workflow also refuses to move such a pin.

Once a version is on npm, depend on that instead, pinned exactly: bun add @brotskyllc/prompt-this-spot@<version> --exact.

2. Let your bundler compile it

The package ships as TypeScript source, so your bundler has to compile it. In Next.js:

// next.config.js (or next.config.mjs / next.config.ts)
module.exports = {
  transpilePackages: ["@brotskyllc/prompt-this-spot"],
};

3. Let Tailwind see its classes

Tailwind only generates classes it finds in files it scans, and it does not scan node_modules by default. Add the package to the scan:

// Tailwind v3: tailwind.config.js
content: [
  // ...
  "./node_modules/@brotskyllc/prompt-this-spot/src/**/*.{ts,tsx}",
],
/* Tailwind v4: your global stylesheet. The path is relative to this file. */
@source "../../node_modules/@brotskyllc/prompt-this-spot/src";

The tools use shadcn/ui theme tokens (bg-card, text-muted-foreground, bg-popover, ring-ring, bg-primary, text-destructive) and tailwindcss-animate classes (animate-in, fade-in-0, zoom-in-95). If your app uses shadcn/ui, these are already defined. If it doesn't, define those colors in your Tailwind theme and add tailwindcss-animate (or tw-animate-css on v4). Dark mode follows the class strategy (<html class="dark">).

No Tailwind? Import the prebuilt stylesheet

Apps that don't run Tailwind import the compiled stylesheet once, for example in the root layout, and skip the content scan above:

import "@brotskyllc/prompt-this-spot/styles.css";

It holds only the classes the package uses, a reset scoped to the tools' own elements (everything marked data-inspect-ignore), the enter and exit animations, and default light and dark values for the theme colors. It doesn't restyle the rest of your app. To change a theme color, set its --pts-* custom property, for example :root { --pts-primary: #0f766e; }. The properties are --pts-background, --pts-foreground, --pts-card, --pts-card-foreground, --pts-popover, --pts-popover-foreground, --pts-primary, --pts-primary-foreground, --pts-muted, --pts-muted-foreground, --pts-accent, --pts-accent-foreground, --pts-destructive, --pts-border, --pts-input and --pts-ring.

Don't import it in an app that already scans the package with Tailwind: the two would define the same classes twice.

Bundlers without tree shaking (Expo web)

Metro, the bundler for Expo web, doesn't tree-shake, so importing from @brotskyllc/prompt-this-spot bundles both tools into your first page load, even for users who never see them. An app that only mounts "Prompt this spot" imports from @brotskyllc/prompt-this-spot/inspect-prompt instead. It has the provider, createScreenshotUploader, the preferences and launcher-stack providers and InspectPromptToolGate, and it loads the tool itself only when the gate opens.

4. Add a provider component

Create one client component that wraps your app. It supplies your app's adapters and mounts the two tools:

// src/components/PromptThisSpot.tsx
"use client";

import {
  createScreenshotUploader,
  FloatingLauncherStackProvider,
  InspectPromptPreferencesProvider,
  InspectPromptToolGate,
  type PromptThisSpotConfig,
  PromptThisSpotProvider,
  UserFeedbackToolGate,
} from "@brotskyllc/prompt-this-spot";
import { useMemo } from "react";

export function PromptThisSpot({ children }: { children: React.ReactNode }) {
  const { user } = useCurrentUser(); // your auth
  const { toast } = useToast(); // your toasts

  const config = useMemo<PromptThisSpotConfig>(
    () => ({
      notify: toast,
      repoSlug: "your-org/your-repo",
      uploadPromptScreenshot: createScreenshotUploader("/api/prompt-this-spot/screenshot"),
      uploadFeedbackScreenshot: createScreenshotUploader("/api/feedback/screenshot"),
      submitFeedback: async (submission) => {
        const res = await fetch("/api/feedback", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(submission),
        });
        if (!res.ok) throw new Error("Couldn't save your feedback.");
      },
    }),
    [toast]
  );

  return (
    <PromptThisSpotProvider config={config}>
      <InspectPromptPreferencesProvider>
        <FloatingLauncherStackProvider>
          <div data-app-push-root className="min-h-svh">
            {children}
          </div>
          <InspectPromptToolGate eligible={Boolean(user?.isAdmin)} />
          <UserFeedbackToolGate eligible={Boolean(user)} />
        </FloatingLauncherStackProvider>
      </InspectPromptPreferencesProvider>
    </PromptThisSpotProvider>
  );
}

What each part does:

  • data-app-push-root marks the element the drawers push aside when they open. Keep the two gates outside it so the drawers stay fixed at the left edge.
  • eligible decides who sees each tool. A gate renders nothing until it is true, and a user who isn't eligible never downloads the tools' heavy code (the screenshot renderer, CodeMirror). The feedback tool also waits for the first click on its launcher, because it's usually shown to every signed-in user.
  • Only mount the gates you want. An app that only wants "Send feedback" can leave out InspectPromptToolGate and uploadPromptScreenshot.
  • repoSlug is the GitHub repository the "Send to Claude Code" buttons open. It is also named at the top of every prompt, including feedback reports' promptText.

5. Mount it in your root layout

// app/layout.tsx
import { PromptThisSpot } from "@/components/PromptThisSpot";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <PromptThisSpot>{children}</PromptThisSpot>
      </body>
    </html>
  );
}

Put it inside your auth and toast providers so useCurrentUser and useToast work.

6. Add the backend routes

The package never talks to storage or a database itself. You provide:

| Adapter | Receives | Must return | |---|---|---| | uploadPromptScreenshot, uploadFeedbackScreenshot | a PNG data: URL | { url, expiresAt? }, where url is publicly readable (an AI agent opens it from the prompt) and expiresAt is an ISO date, or null if the image is kept | | submitFeedback | a UserFeedbackSubmission (message, category, pathname, assembled prompt, selections, screenshots, viewport) | nothing; throw an Error to show its message in the drawer |

createScreenshotUploader(path) covers the client side of the upload: it POSTs { dataUrl } as JSON to your route and returns the JSON response. The route checks that the caller is allowed, decodes the PNG, stores it in public object storage, and responds with { url, expiresAt }. On an error it returns { error } with a non-2xx status, and the drawer shows that message. Here is a Next.js route that stores screenshots in Vercel Blob:

// app/api/prompt-this-spot/screenshot/route.ts
import { put } from "@vercel/blob";
import { NextResponse } from "next/server";

export async function POST(request: Request) {
  const user = await getCurrentUser(); // your auth
  if (!user?.isAdmin) {
    return NextResponse.json({ error: "Not allowed." }, { status: 403 });
  }

  const { dataUrl } = await request.json();
  const prefix = "data:image/png;base64,";
  if (typeof dataUrl !== "string" || !dataUrl.startsWith(prefix)) {
    return NextResponse.json({ error: "Expected a PNG." }, { status: 400 });
  }

  const png = Buffer.from(dataUrl.slice(prefix.length), "base64");
  const blob = await put(`@brotskyllc/prompt-this-spot/${crypto.randomUUID()}.png`, png, {
    access: "public",
    contentType: "image/png",
  });

  // Return an expiry date instead of null if you delete old screenshots.
  return NextResponse.json({ url: blob.url, expiresAt: null });
}

Any storage that gives back a public URL works the same way (S3, Cloudflare R2, Google Cloud Storage and so on). The feedback screenshot route is the same, with the check changed to "any signed-in user". The /api/feedback route receives the UserFeedbackSubmission as JSON and saves it wherever your app keeps records; promptText is the ready-made AI prompt.

Screenshot URLs are public, so anyone with a link can open the image. If your app shows sensitive data, keep the links unguessable (as above) and delete old screenshots on a schedule.

Check that it works

  1. Sign in as a user who is eligible for "Prompt this spot" and reload the app. Its launcher appears in a corner of the page.
  2. Press ⌘/Ctrl + Shift + P, click a button on the page, type a request and copy the prompt. It should name the page and the button.
  3. Take a screenshot in the drawer. It should upload and its link should open in a new tab.
  4. Open "Send feedback", point at something, describe it and send it. The report should reach your /api/feedback route.
  5. Switch to dark mode and a phone-width window and check both drawers still read well.

Troubleshooting

| Symptom | Fix | |---|---| | The build fails with "Unexpected token" or "Module parse failed" in @brotskyllc/prompt-this-spot | Add the package to transpilePackages (step 2). | | The drawers or launchers are unstyled, transparent or oddly placed | Tailwind isn't scanning the package (step 3), or the shadcn/ui color tokens aren't defined. Without Tailwind, import @brotskyllc/prompt-this-spot/styles.css. | | The drawer covers the page instead of pushing it aside | Add data-app-push-root to the element that wraps your app, and keep the gates outside it (step 4). | | No launcher appears | Check that eligible is true for the signed-in user. The "Prompt this spot" launcher can also be switched off through its enabled preference, which is stored in localStorage; read or reset it with useInspectPromptPreferences(). | | The feedback launcher is missing in Playwright or Cypress | Automated browsers don't see it unless the sessionStorage key in feedbackE2eOptInStorageKey is "1" (see Configuration). | | Screenshots fail with an error on the row | The message comes from your upload route's { error } response. Check the route's auth check and storage credentials. | | An image or logo is blank in a screenshot | The image is served from another origin without CORS headers, so the browser won't let it be copied into the screenshot. Allow your app's origin on that storage bucket or CDN. | | "Send to Claude Code" opens without a repository selected | Set repoSlug in the config. |

Configuration

Every field of PromptThisSpotConfig is optional:

| Field | Default | What it does | |---|---|---| | notify(toast) | no-op | Shows { title, description?, variant? } toasts (shadcn/ui's toast() fits) | | logError(message, context) | console.error | Reports a screenshot that failed | | repoSlug | none | GitHub owner/name that "Send to Claude Code" opens, and that prompts name | | uploadPromptScreenshot / uploadFeedbackScreenshot | throws | Screenshot storage (see above) | | promptScreenshotRetentionDays | 7 | How many days "Prompt this spot" tells the agent the screenshot links last; match it to what your storage keeps | | promptScreenshotsToggle | false | Shows a "Capture screenshots" checkbox in the "Prompt this spot" drawer, for apps without a settings UI of their own for that preference | | submitFeedback | throws | Feedback storage (see above) | | feedbackCategories | Broken / Confusing / Idea / Praise / Other | { value, label }[] for the feedback form; the first one is preselected | | feedbackTheme | neutral blue | Tailwind class overrides for any part of the feedback widget (see defaultUserFeedbackTheme) | | feedbackE2eOptInStorageKey | prompt-this-spot:e2e-user-feedback | Automated browsers (navigator.webdriver) don't see the feedback launcher unless this sessionStorage key is "1" |

The "Prompt this spot" preferences are stored per browser in localStorage: whether the launcher shows, its corner, whether screenshots are captured, and whether the prompt asks for test coverage. Read and set them with useInspectPromptPreferences() to build your own settings UI.

Matching your brand

Pass any subset of defaultUserFeedbackTheme's keys. Unset keys keep the defaults:

feedbackTheme: {
  userFeedbackLauncher: "… your launcher classes …",
  userFeedbackPrimaryAction: "… your button classes …",
},

If the classes live in your app's source files, Tailwind already scans them.

Keeping apps up to date

An app pinned to a commit or a version doesn't pick up changes by itself. docs/consumer-update-workflow.yml is a GitHub Actions workflow you can copy into an app's .github/workflows/. On a schedule (and whenever this repo notifies it), it finds the newest version on npm (for an app on a version) or the newest commit on main (for an app on a commit), updates the dependency and lockfile, and opens a pull request that lists the changes. You review and merge it like any other PR.

The workflow only moves the dependency forward. If an app is pinned to a commit that is not on main, it fails and leaves the pin alone instead of replacing it with an older main. It never replaces a version with an older one either.

To get those PRs right after a merge here, not just on the schedule, add a CONSUMER_DISPATCH_TOKEN secret to this repository and list the apps in .github/workflows/notify-consumers.yml. The token needs permission to send repository_dispatch events to those apps (for a fine-grained token, contents read and write).

FAQ

What is prompt-this-spot?

A React library that lets you click an element in a running web app and get a text prompt describing that element for an AI coding agent. It also includes an in-app feedback widget that attaches the same prompt and screenshots to user bug reports.

Which AI coding agents does it work with?

Any agent that accepts text. The prompt is plain text, so you can paste it into Claude Code, Cursor, GitHub Copilot, Windsurf, ChatGPT or another assistant. There are also one-click buttons that open the prompt in Claude Code on the web (with your repository pre-selected) or in a local Claude Code install.

Does it work with Next.js?

Yes. Add the package to transpilePackages and to Tailwind's content scan, as shown in Install, which uses Next.js throughout. Other React 19 setups should work too, as long as their bundler compiles TypeScript from node_modules and Tailwind scans the package's source.

Does it need a backend or a paid service?

No hosted service is involved. You provide two small routes of your own: one that stores a PNG and returns a public URL, and one that saves feedback. createScreenshotUploader handles the client side of the upload.

Can end users see it?

Only if you let them. Each tool has an eligible flag, so you can show "Prompt this spot" to admins or internal staff and "Send feedback" to every signed-in user, or neither.

How are screenshots taken?

In the browser, with no extension or screen-recording permission. The package copies the page with every computed style inlined into an SVG <foreignObject> and has the browser draw it, so fonts, shadows, object-fit, gradients, truncated text and modern color functions look the way they do on screen. Sticky headers, fixed bars and scrolled panels are drawn where the user sees them. Embedded frames and images served from another origin without CORS headers come out blank, and the prompt tells the agent so.

Can users draw on a screenshot?

Yes. Each uploaded screenshot has a Mark up button that opens an editor with arrow, box, freehand and text tools in four colors, plus undo and clear. It works with a mouse, a finger or a stylus. Saving uploads the marked-up image through the same uploader in place of the plain one. The original capture stays in memory, so reopening the editor lets the user change or remove earlier marks instead of drawing over them. The earlier, unmarked upload is not deleted; it expires under your normal retention.

Is it on npm?

The public npm package is named @brotskyllc/prompt-this-spot. Check npm view @brotskyllc/prompt-this-spot version for availability; source installs can use a pinned GitHub commit (see Add the package). The optional publish workflow adds provenance and a GitHub release when enabled.

Developing

bun install
bun run check      # typecheck + biome + unit tests
bun run test:e2e   # Playwright, against the fixture app in e2e/fixture

The end-to-end specs need Chromium: run bunx playwright install chromium once, or point PLAYWRIGHT_CHROMIUM_EXECUTABLE at a Chromium you already have.

If you add or change a Tailwind class in src, rebuild the prebuilt stylesheet and commit it with the change (CI fails when it's out of date):

bun run build:css

Releasing

With publishing on (the NPM_PUBLISH repository variable set to true), every merge to main whose version in package.json is not on npm yet is published, tagged v<version> and released on GitHub, with that version's CHANGELOG.md section as the release notes. The apps are then notified. A pull request that changes src, the prebuilt stylesheet or the dependencies must raise version and add a CHANGELOG.md entry, and CI checks the version: patch for fixes, minor for new options or exports, major for breaking changes.

Nothing is published while NPM_PUBLISH is unset, whatever triggers the workflow. A manual run of Publish to npm is a dry run unless its "publish" input is ticked as well. The workflow stops, rather than publishing, if it cannot tell whether the version is already on npm.

Before any release, check exactly what would be uploaded:

bun run check:package     # packs the tarball: allowlisted files only, no secrets
npm publish --dry-run --provenance=false   # uploads nothing
bun run test:consumer     # installs the tarball into a fresh Next.js app and builds it

CI runs all three on every pull request.

For an approved one-time release, publish the audited tarball with npm publish <tarball> --access public --provenance=false --registry=https://registry.npmjs.org/ using an authorized npm account. This local route has no CI provenance and does not notify consumer apps. Leave NPM_PUBLISH unset unless ongoing automatic releases and consumer notifications are separately intended. Trusted publishing can be configured later by an owner; it is not required for this manual release.

Trying a change in an app

To try a change in an app before it's merged, link your local checkout:

# in this repo
bun link
# in the app
bun link @brotskyllc/prompt-this-spot

Keep the package app-neutral. Anything that differs between apps (auth, storage, copy about a specific product, brand colors) belongs behind PromptThisSpotConfig, not in the code. Keep data-testid values stable, because apps' end-to-end tests select on them.

License

MIT