DEV Community

Maria Dunning
Maria Dunning

Posted on Fully Autonomous

Badge Studio: Private, Local AI Sticker Ideas for Any Celebration

Hacktoberfest Weekend Challenge: Build for a Friend Submission 🤝

This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend

What I Built

A friend of mine recently got married and wanted to make their own version of the familiar “I Demoed” sticker with custom wording. The existing design was great inspiration, but it was not flexible enough for the moment. I've done custom hexes before, and the curve of the text is super annoying to self make for someone less familiar with design. So moving forward, I wanted a tool to make this easier.

So I "built" Badge Studio, a browser-based sticker maker for any accomplishment, milestone, joke, or delightfully specific life event. I did this using ChatGPT 5.6 Sol to help me create this new website based on existing concepts used to make I demoed stickers.

You can:

  • Change the curved sticker text
  • Generate three sticker concepts from a plain-language description with Badge Copilot
  • Pick a playful, heartfelt, proud, or chaotic tone (AI helped me with these ideas!)
  • Customize the badge, frame, artwork circle, and text with color wheels or hex codes
  • Toggle the artwork circle on or off
  • Upload your own PNG, JPEG, WebP, or SVG artwork
  • Resize the artwork
  • Download a print-ready PNG or editable SVG

The text automatically scales to remain inside the frame. The artwork also moves based on the actual painted pixels of the curved letters, rather than the text element's rectangular box, so the spacing remains visually balanced across short and long phrases. The AI actually sucked at these, for design elements it needed more guidance, but had great add-ons like a new color wheel picker instead of only hex code.

Most importantly, this is not a wedding-only tool. My friend inspired it, but anyone can use it to celebrate a marathon, graduation, birthday, shipped project, new job, inside joke, or something nobody else has thought of yet.

Demo

Try Badge Studio here:

https://made-together-sticker.maria648542.chatgpt.site/

To try the AI flow, describe a moment in Badge Copilot, choose a tone, and click Make ideas. Pick any result to apply its phrase and complete visual style, then keep editing manually.

The model downloads on the first run and is cached by the browser afterward, so the first generation takes longer than later ones.

Code

The project is deliberately lightweight: one client-side HTML app containing the interface, SVG sticker renderer, layout logic, export tools, and local inference integration.

Repository: https://github.com/mdunn09045/badge-studio

The core local-model setup looks like this:

const { pipeline } = await import(
  "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.1/+esm"
);

const generator = await pipeline(
  "text-generation",
  "onnx-community/SmolLM2-135M-Instruct-ONNX-MHA",
  { dtype: "q4" }
);
Enter fullscreen mode Exit fullscreen mode

No backend, API key, or hosted inference endpoint is required.

How I Built It

Badge Studio uses plain HTML, CSS, JavaScript, and SVG. The sticker stays as vector artwork until export, which keeps the live preview crisp and makes SVG downloads genuinely editable.

Badge Copilot runs the open-weight SmolLM2-135M-Instruct model in the browser through Transformers.js and ONNX Runtime. The model turns a description of a real moment into short celebration language. The app validates the output against the sticker's 28-character design limit, combines it with locally curated accessible palettes, and presents three complete concepts that can be applied with one click.

Very small local models can occasionally ignore output-format instructions, so I added a celebration-aware local fallback for common milestones. That keeps the interface reliable without sending the prompt to a server or silently switching to a closed model. The generative model remains the idea engine; the surrounding deterministic layer makes its output safe for a constrained design tool.

Several non-AI details took just as much care/human prompted fixes:

  • Curved type fitting: the SVG text is measured and its font size is reduced automatically when necessary.
  • Pixel-aware spacing: a text-only SVG is rendered to an offscreen canvas, its alpha pixels are scanned, and the artwork is positioned with a consistent visible gap from the real letterforms.
  • Private image uploads: FileReader creates a local data URL; the image never leaves the browser.
  • Manual control: AI suggestions are a starting point, never a locked result.

Why Does Open Innovation Matter?

Running an open-weight model locally means that description does not need to be sent to an AI provider. This should be a fun easy thing to do, not need an API key to get running.

Open tooling also makes the project inexpensive and adaptable:

  • There is no API key to expose or usage bill to surprise me.
  • The model can be inspected, replaced, or upgraded without rebuilding the product around a proprietary endpoint.
  • Prompts and generated ideas stay on the user's device.
  • Once the model assets are cached, repeated generations do not need another model download.
  • The same browser app can combine generative behavior with deterministic design constraints.

A closed API would have been easier to call, but it would have made privacy, cost, and long-term control somebody else's decision. Transformers.js and an openly available ONNX model let those decisions remain part of the product design.

My Agent Session

I built Badge Studio iteratively with Codex and tested each requested behavior in the browser. The most interesting part of the process was getting it to respond to real visual feedback: removing hallucinate branding, fixing image uploads, separating frame and circle colors, scaling the curved text, and replacing box-based spacing with actual pixel-aware spacing.

That feedback loop is exactly why human input mattered. The result became much more useful than the AI's first interpretation of the idea, where it functionally did not work because it failed to understand/do functional tests.

Top comments (0)