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

vibe-img

v1.0.1

Published

AI image generation via a single HTML tag. Drop in a script, use <vibe-img>.

Readme

<vibe-img>

🚧 Beta

Image generation for prototyping, built for lazy LLMs and lazy developers. Choose your favorite model, bring your own API key.

preview

Getting Started

1. Ask your LLM to use vibe-img

It will include the library:

<script src="https://cdn.jsdelivr.net/npm/vibe-img@1/dist/vibeimg.js"></script>

And generate images with a single tag:

<vibe-img 
  model="recraft" 
  prompt="Miami Beach at sunset">
</vibe-img>

🚧 vibe-img is brand new. Help your LLM get it right — pass the docs: https://www.vibe-img.com/llms.txt

2. Add your API keys

Once the page loads, click the ⋯ button on any image to enter your API key.

That's it — images generate automatically and you're ready to ship.

3. Using with AI coding agents

If you use Claude Code, Cursor, Codex, or other AI coding agents, install the vibe-img skill:

npx skills add devhashfortheweb/vibe-img

Your agent will automatically know how to generate correct <vibe-img> tags.

Why?

Some vibe builders suck at image generation and give you zero control. Others don't even let you try. vibe-img tries to fix that.

Your LLM can generate images, maintain visual consistency across a page with <vibe-theme>, chain operations with image references, and switch provider with a single attribute change.

One API, any provider. Write the same tag regardless of provider. Switch from model="openai" to model="recraft" and nothing else changes.

No wasted tokens on refresh. Generated images are cached in the browser and on a CDN. A repeated page load never hits the AI provider.

Share freely. Generated images are cached on a CDN and served from a public URL — no API key needed to view them.

Your keys stay yours. API calls go straight from your browser to the provider — no middleman storing your credentials. See Security for details.

⚠️ Free CDN cache lasts 1 hour — perfect for a vibe session. If your project needs permanent hosting or longer retention, let’s talk about it. I’m happy to build more if there’s enough interest (and to keep the servers running!).

Are you still reading, human? Just ask your LLM to use this library and let it handle the rest.


<vibe-img> attributes

| Attribute | Values | Default | Description | |-----------|--------|---------|-------------| | model | openai, recraft | — | Required. Provider to use. | | prompt | string | — | Text prompt. Required for generate, img2img, replace-bg. | | op | generate, img2img, upscale, remove-bg, replace-bg, vectorize | generate | Operation to perform. | | aspect | square, landscape, portrait, wide, tall | square | Output aspect ratio. | | img-style | See Styles | — | Visual style. | | quality | draft, standard, hd | standard | Generation quality. | | format | png, webp, jpeg | (provider default) | Output image format. | | img-ref | URL or #id | — | Reference image. Required for img2img, upscale, remove-bg, replace-bg, vectorize. | | seed | integer | — | Reproducible generation (provider support varies). | | negative-prompt | string | — | What to avoid in the image (provider support varies). | | params | JSON string | — | Raw provider params, merged last. Override anything. | | alt | string | — | Alt text for the generated <img>. |

Note on model vs params.model: The model attribute selects the provider (openai, recraft). To override the specific API model within a provider (e.g. recraftv4, gpt-image-1), use params='{"model":"recraftv4"}'.

⚠️ Always use a closing tag. <vibe-img /> does not work — the HTML parser treats custom elements as open tags when self-closed. Always write <vibe-img ...></vibe-img>.

Styles

These map to native provider style parameters where available, otherwise they're injected into the prompt automatically.

realistic · natural · vivid · illustration · 3d · pixel · anime · sketch · watercolor · oil-painting · comic · retro · cinematic · vector · minimalist · flat · icon · logo · neon · fantasy · abstract · isometric · kawaii

Operations

| Operation | Required attributes | Description | |-----------|-------------------|-------------| | generate | prompt | Text to image. | | img2img | prompt, img-ref | Edit an image with a prompt. | | upscale | img-ref | Increase resolution. | | remove-bg | img-ref | Remove background, returns transparent image. | | replace-bg | prompt, img-ref | Replace background with prompt. | | vectorize | img-ref | Convert to SVG. |

Provider support

| Operation | openai | recraft | |-----------|----------|-----------| | generate | ✓ | ✓ | | img2img | ✓ | ✓ | | upscale | — | ✓ | | remove-bg | — | ✓ | | replace-bg | ✓ | ✓ | | vectorize | — | ✓ |


<vibe-theme>

Apply a shared style prompt to a group of images. Closest ancestor wins on nesting.

<vibe-theme prompt="warm editorial, soft lighting, muted earth tones">
  <vibe-img model="recraft" prompt="coffee cup"></vibe-img>
  <vibe-img model="recraft" prompt="open notebook"></vibe-img>

  <vibe-theme prompt="dark cinematic, dramatic shadows">
    <vibe-img model="recraft" prompt="whiskey glass"></vibe-img>
  </vibe-theme>
</vibe-theme>

The theme prompt is appended to each child's prompt at generation time. Changing the prompt attribute regenerates affected images automatically.


Image references

Use img-ref to chain operations. Pass a URL or point to another <vibe-img> by ID.

<!-- External URL -->
<vibe-img
  model="recraft"
  op="remove-bg"
  img-ref="https://example.com/photo.jpg"
></vibe-img>

<!-- Reference another vibe-img by ID -->
<vibe-img id="source"
  model="recraft"
  prompt="a cat sitting on a windowsill"
></vibe-img>

<vibe-img
  model="recraft"
  op="upscale"
  img-ref="#source"
></vibe-img>

When img-ref="#id" is used, the second element waits for the first to finish before starting. Cache lookups for both happen in parallel, so repeated page loads are instant.


Advanced: raw provider params

params accepts the original provider API parameters directly — not a vibe-img abstraction. These are merged last and override everything else, so you have full access to whatever the provider supports.

<!-- Recraft: custom brand colors -->
<vibe-img
  model="recraft"
  prompt="company logo"
  params='{"controls":{"colors":[{"rgb":[46,125,50]}]}}'
></vibe-img>

<!-- OpenAI: transparent background -->
<vibe-img
  model="openai"
  prompt="app icon, minimal"
  format="png"
  params='{"background":"transparent"}'
></vibe-img>

<!-- Recraft: use V4 model -->
<vibe-img
  model="recraft"
  prompt="product photo"
  params='{"model":"recraftv4"}'
></vibe-img>

<!-- Recraft: use a provider-specific style via params -->
<vibe-img
  model="recraft"
  prompt="city at night"
  params='{"style":"Neon Calm"}'
></vibe-img>

Configuration

API keys

Configure keys programmatically, as an alternative to the built-in modal:

await VibeImg.configure({
  openai:  'sk-...',
  recraft: 'rk-...',
});

Or open the key modal for a specific provider:

VibeImg.openKeyModal('recraft');

Runtime options

VibeImg.setup({
  corsProxyUrl:          'https://your-proxy.com/proxy?url=',
  serverStorageEndpoint: null,    // disable remote caching
  r2PublicUrl:           null,
  useServerStorage:      false,
  requestTimeoutMs:      60_000,
  debug:                 true,    // verbose logs for bug reports
});

Debug mode

Logs every step — cache lookups, key resolution, HTTP requests, polling. Enable before reproducing an issue and include the output in bug reports.

<script type="module">
  VibeImg.setup({ debug: true });
</script>

Security

Two phases, two threat models

vibe-img operates in two distinct phases, each with a different security profile:

Generation (prototyping). In this phase, you use an API key in your browser. You are typically on localhost or within your private dev environment. Images are generated and then cached on the CDN.

Sharing (viewing). Once you share the URL or deploy the page, visitors see cached images served directly from the CDN. No API key is present, required, or even requested during this phase. There is simply nothing to steal.

This separation is intentional. The API key only exists while you are prototyping on your own machine. Once the images are cached, the key's job is done.

How keys are stored

vibe-img follows the BYOK (Bring Your Own Key) model. Your key never leaves your device except to make a direct request to the AI provider. There is no central server storing user keys, which eliminates "honeypots" or any single point of compromise.

Keys are encrypted with AES-GCM 256-bit via the Web Crypto API and stored in IndexedDB. The encryption key is set to non-extractable. This means even with direct access to IndexedDB, an attacker would only find ciphertext.

Transparency note: AES-GCM requires crypto.subtle, which is only available in secure contexts like HTTPS or localhost. If you run vibe-img over plain HTTP (for example, behind a dev proxy or Burp Suite), keys are stored unencrypted in IndexedDB. This is an intentional fallback for development tools.

What about XSS?

In a real-world scenario, XSS is not a viable threat to your API key given how vibe-img is used. While you are prototyping (and the key exists), you are on localhost or a controlled environment where there is no attack surface for third-party scripts. By the time you share the project and an attack surface exists, the key is no longer there.

Cached images are public but unguessable

Generated images are stored on a public CDN so anyone can view shared projects without needing an API key. Image URLs are derived from a SHA-256 hash of every generation parameter:

cdn.vibe-img.com/vibeimg-4479b58ffa14e53da9ec06e3feedcdb802dbca14b5c4a42fba6c093ba31ef5bc.webp

There is no directory listing, no sequential IDs, and no way to enumerate endpoints. Finding a specific image would require knowing the exact combination of prompt, style, model, and every other attribute used to create it.

The CORS proxy

Some providers, such as OpenAI, do not allow direct requests from a browser. To handle this, vibe-img routes requests through a CORS proxy (api.vibe-img.com/proxy by default). Your API key passes through this proxy in memory only for the duration of the request. It is never written to disk, logged, or stored.

Providers that support browser CORS, like Recraft, bypass this proxy entirely. In those cases, requests go straight from your browser to the provider.

If you prefer not to use the default proxy, you can set up your own or disable it entirely (though this only works with CORS-enabled providers):

// Use your own proxy
VibeImg.setup({ corsProxyUrl: '[https://your-proxy.com/proxy?url=](https://your-proxy.com/proxy?url=)' });

// Or disable it 
VibeImg.setup({ corsProxyUrl: null });

What vibe-img does NOT do

  • Store keys on any server
  • Send keys to any endpoint other than the AI provider (or the CORS proxy when required)
  • Log, track, or transmit key material
  • Hardcode keys in generated HTML — keys are entered at runtime via the built-in modal

Development

Local setup

git clone https://github.com/user/vibe-img.git
cd vibe-img
npm install
npm run dev       # dev server
npm test          # adapter fixture tests
npm run typecheck
npm run build     

Project structure

src/
  adapters/       Model adapters (one file per provider)
  core/           Execution engine
  dom-adapter/    Web component + hooks
  storage/        IndexedDB + server cache
  utils/          Network, hashing, error handling

Adding a provider

Copy src/adapters/_template.ts, fill in the mapping tables and buildRequest(), write at least 5 fixtures, then register in src/adapters/index.ts.

cp src/adapters/_template.ts src/adapters/my-provider.ts

Fixtures cover request building only. It's still recommended to test your adapter against the real API before submitting.

npm test

Contributing

Your favorite provider isn't here? Don't be sad — read a bit of docs, implement an adapter, and join the vibe-img family. It's less work than it sounds. No one is perfect either — found a bug? Open an issue or send a PR.