Open-source project
zhengkyl/qrframe avatar
zhengkyl/qrframe

qrframe: a code-based QR code designer for scripted, version-controlled styling

code-based qr code designer

3,376 stars108 forksTypeScriptMIT

At a glance

What is it?
qrframe turns QR code styling into a preset you write in JavaScript and run in a browser web worker. It suits developers who want reproducible designs, not a drag-and-drop generator.
Who is it for?
qrframe fits developers who want QR styling defined in code, reviewed in a repository and rendered locally, and it is a poor fit for anyone who needs a guaranteed-scannable code from a form-driven tool with no JavaScript involved. Before adopting it, check the self-hosting limitation the README states for non-root paths, confirm that your scanner tolerates the design you produce, and note that the README marks the example codes as unreliable to scan by design.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem qrframe solves: styling a QR code without a form

Most QR generators give you a panel of toggles: dot shape, corner style, logo upload, color picker. That works once. It does not work when you need the same treatment applied to two hundred codes, or when a designer hands you a look and you have to reproduce it exactly six months later.

qrframe takes the opposite route. A design is a JavaScript module that exports a parameter schema and a render function. The schema declares the controls the UI should show; the render function receives the QR matrix plus the current parameter values and returns an SVG string or draws to a canvas. The README describes the project as a tool to create designs, and it is explicit that the bundled examples exist to show what is possible rather than to serve as production codes.

That framing matters. This is not a service that hands you a scannable code. It is an editor and a runtime for design code, and the person using it is expected to be comfortable writing and debugging JavaScript. The encoder underneath is fuqr, a separate QR generator by the same author, which supplies the matrix and the metadata about which modules are finder patterns, alignment patterns, timing, format and version information. The README credits QRBTF and Anthony Fu's QR Toolkit as the inspirations for the project, and it credits QRBTF specifically for the styles behind the blocks, bubbles and alien examples.

How a qrframe preset actually works

The contract is small. A preset must export paramsSchema and either renderSVG or renderCanvas. The schema is a plain object; each key becomes a UI control, and each control's value arrives in the params object passed to the render function. Supported types include number, boolean, color, select, file and array. The README notes that select requires a nonempty options array and that array requires a valid props value, and that every property other than type is optional.

The render side receives a Qr object with four fields: matrix, version, mask and ecl. The matrix is a Uint8Array where each byte is a bit field, and the Module constants in the README define what each bit means: ON, DATA, FINDER, ALIGNMENT, TIMING, FORMAT, VERSION and MODIFIER. Because the flags are separate bits, a renderer can ask whether a module is data or a finder pattern and style them differently, which is how the exotic examples in the repository are built. The README states that MODIFIER is set for finder and alignment centers and for format and version copies, which gives a preset a way to target those specific cells rather than guessing at coordinates.

The encoder settings are exposed too. The README lists encoder, version, error tolerance and mask pattern among the customizable data options, so a preset author can trade capacity against redundancy deliberately instead of accepting whatever the library picks.

The execution model is worth understanding before you trust it. Preset code runs in the browser inside a web worker with no restrictions, and there is a five second timeout to stop infinite loops. The README also states that generated SVGs are not sanitized, and that there is nothing to exploit and no risk from bad code except crashing your tab. That is a reasonable position for code you wrote yourself, and a different proposition for a preset copied from a stranger. The worker boundary is the only containment described, and the timeout bounds runaway loops rather than malicious ones.

Installing qrframe and writing a first preset

The repository is a SolidStart application managed with pnpm, and package.json declares a node engine of 18 or above. To run it locally, install dependencies and start the dev server.

bash
pnpm install
pnpm run dev

The dev script is vite dev, so the terminal prints a local URL to open. From there you can pick a preset, edit it in the built-in CodeMirror editor and see the rendered result update.

To define your own preset, start with a schema that declares the controls. This example is the shape the README gives, with a number, a boolean and a color.

js
export const paramsSchema = {
  Example1: { type: "number", min: 0, max: 10, step: 0.1, default: 0 },
  Example2: { type: "boolean", default: false },
  Example3: { type: "color", default: "#000000" },
};

Each key becomes a control in the parameter editor, and the default value is what the control starts at. A color default is a CSS color string, so hex, rgba and hsla all work. The README's fuller example also shows file controls with an accept list and array controls with a props field and a resizable flag.

The render function then consumes those values along with the QR data. The signature the README gives for the SVG path takes the Qr object and the params object and returns a string.

ts
type renderSVG = (qr: Qr, params: Params) => string;

Inside that function you have qr.matrix, qr.version, qr.mask and qr.ecl. Walking the matrix and emitting one rect per module is the straightforward approach; reading the Module flags lets you branch on data versus finder modules. If you prefer canvas output, renderCanvas receives an OffscreenCanvas as a third argument and draws into it instead of returning a string.

For self-hosting, the README gives a build command and names the output directory.

bash
pnpm run build

The static files land in .output/public. One caveat is stated plainly in the README: serving under a non-root path is broken until an upstream SolidStart pull request is merged and released, and fixing it afterwards means updating @solidjs/vite-plugin-nitro-2 and modifying base in vite.config.ts. If your deployment target is a subdirectory rather than a domain root, treat that as an open issue rather than a configuration detail. The README also lists a start script, vite start, for running the built app.

Where qrframe is the wrong tool

The README opens its example gallery with a caution: the example QR codes may not be reliably scannable, results vary drastically by device and scanner, and the project is a tool to create designs. That is not modesty, it is the core limitation. Error correction and mask selection give you room to restyle a code, but they do not give you unlimited room, and a preset that pushes contrast, module shape or overlay density too far will produce something that looks right on screen and fails on a phone.

qrframe offers no scanning verification. Nothing in the README describes a decode step or a confidence check after rendering, so the feedback loop is your own device. If you are producing codes for print, packaging or a payment flow, you are responsible for testing each design against the scanners your audience actually uses. The examples in the repository include styles named quantum, camo and glass, and the README's caution applies to all of them.

The second limitation is the deployment one already noted: non-root paths are broken pending an upstream fix. The third is the trust model. Preset code runs with no restrictions in a worker and the SVGs are not sanitized, so importing a preset from an untrusted source is a decision about running someone else's JavaScript, not about loading a theme file.

Finally, the project is a designer, not a bulk generator. There is no documented CLI that takes a list of URLs and emits a folder of styled codes. If your need is ten thousand codes with consistent styling and no human in the loop, qrframe gives you the render function but leaves the pipeline around it to you. The README documents a web UI and a build step, nothing more.

qrframe against QRBTF and Anthony Fu's QR Toolkit

The README names both inspirations directly: QRBTF and Anthony Fu's QR Toolkit, and it credits QRBTF for the styles behind the blocks, bubbles and alien examples. The difference is where the design lives.

QRBTF and the QR Toolkit are preset-driven interfaces. You choose from a curated set of styles, adjust the exposed sliders and export. That is faster for a one-off poster and requires no code. The trade-off is that the set of knobs is fixed by whoever built the tool, and a style that is not in the list is not reachable.

qrframe inverts that. The preset list is a starting point, and the editor is the product. Anything the matrix and the canvas or SVG API can express is available, including fetching external files and importing external libraries, which the README lists among the example capabilities. The cost is that you write the renderer, and the benefit is that the design becomes a file you can commit, diff and reuse. For a team that already treats visual assets as code, that is a real gain. For a marketing page that needs one nice code by Friday, it is overhead with no payoff.

There is a middle position worth naming. If you like a QRBTF style and want it in qrframe, the README shows that copying is an accepted practice within this family of tools: the blocks, bubbles and alien examples are reproduced styles, credited in the README. That tells you the visual vocabulary is portable even though the runtime is not.

Maintenance, upgrades and the MIT licence

The last push to the repository was on 2026-08-07, and the repository is not archived. The dependency list is the part to watch on upgrades. The app depends on @solidjs/start at 2.0.0-alpha.3, an alpha release, and on @solidjs/vite-plugin-nitro-2, which the README ties directly to the non-root path fix. Upgrading that plugin and editing base in vite.config.ts is the documented path once the upstream pull request ships, which means the deployment workaround is coupled to a dependency bump rather than a local patch. Vite is pinned at ^8.1.4 and UnoCSS at ^66.7.5, so a routine install already pulls a fairly current toolchain.

The dependency set is otherwise ordinary for a Solid app: CodeMirror packages for the editor, @kobalte/core for UI primitives, @thisbeyond/solid-dnd for drag and drop, @melloware/coloris for the color picker, lucide-solid for icons, and fuqr for the encoding. There is a devDependency on oxfmt and a fmt script that runs it, so formatting is part of the repository's own workflow rather than something you have to add.

The licence is MIT. That permits use, modification and redistribution with the copyright notice and permission notice preserved, and it comes with no warranty. It does not cover the QR code itself: the README's example gallery includes styles credited to QRBTF, so if you copy a preset or a visual treatment from another project, that project's terms are a separate question from qrframe's licence. This is not legal advice, and anyone shipping codes commercially should read the LICENSE file in the repository rather than take a summary.

Who should adopt qrframe, and what to check first

Adopt it if you want QR styling expressed as code that lives next to the rest of your front end, if you are comfortable with TypeScript and the SolidStart build, and if you can test the output on real scanners yourself. The preset contract is small enough to learn in an afternoon, and the Module bit flags give you precise control over which parts of the code get which treatment.

Do not adopt it if you need a guaranteed-scannable code with no verification step, if you cannot serve from a domain root until the upstream SolidStart fix lands, or if you want a hosted generator with no build pipeline. In those cases the preset-driven tools the README credits are the more direct answer.

What to verify first: run pnpm run build and confirm the output in .output/public serves correctly at your intended path, since the README states non-root serving is broken. Then scan your design on the devices your audience uses, because the README's own examples carry a warning that they may not be reliably scannable. If you plan to import presets written by other people, decide how you feel about running their JavaScript in a worker with no restrictions and unsanitized SVG output before you paste anything in.

Editorial conclusion

qrframe fits developers who want QR styling defined in code, reviewed in a repository and rendered locally, and it is a poor fit for anyone who needs a guaranteed-scannable code from a form-driven tool with no JavaScript involved. Before adopting it, check the self-hosting limitation the README states for non-root paths, confirm that your scanner tolerates the design you produce, and note that the README marks the example codes as unreliable to scan by design.

Frequently asked questions

What is qrframe?

qrframe is a code-based QR code generator and designer written in TypeScript. Presets export a paramsSchema and a renderSVG or renderCanvas function, and all preset code runs in the browser in a web worker.

Is there a free QR code generator like qrframe?

qrframe itself is MIT licensed and the repository can be built and self-hosted, with static files produced in .output/public by pnpm run build. The README also credits QRBTF and Anthony Fu's QR Toolkit as inspirations, both of which are web-based tools.

How do I install and run qrframe locally?

The repository uses pnpm and package.json requires node 18 or above. Run pnpm install, then pnpm run dev, which runs vite dev and prints a local URL. For a static build, run pnpm run build.

What is the downside of QR codes made with qrframe?

The README warns that the example QR codes may not be reliably scannable and that results vary drastically by device and scanner, because the project is a tool to create designs. Nothing in the README describes a built-in scan verification step.

Can qrframe be self-hosted under a subdirectory?

The README states that serving under a non-root path is broken until an upstream SolidStart pull request is merged and released. Once fixed, the documented change is to update @solidjs/vite-plugin-nitro-2 and modify base in vite.config.ts.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. zhengkyl/qrframe on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zhengkyl-qrframe.svg)](https://hysenlabs.com/projects/zhengkyl-qrframe)