Open-source project
p2r3/ha.mr avatar
p2r3/ha.mr

ha.mr: a back-end-free URL compressor and QR code optimizer

Static URL compressor and QR code optimizer

981 stars92 forksJavaScriptMIT

At a glance

What is it?
ha.mr is a static JavaScript tool that compresses links and shrinks QR codes in the browser, with no database and no server-side shortening. It is small on purpose, and that scope is both its selling point and its main constraint.
Who is it for?
Adopt ha.mr if you want a link and QR compression utility that runs entirely in the browser and can be served as static files, for example through the provided nginx image on port 8080. Do not adopt it if you need server-side shortening, redirects, analytics or link management, because the README describes no back end and no database.
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 7 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

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

DEEP OPEN-SOURCE ANALYSIS

What ha.mr compresses, and who it is for

ha.mr is a static URL compressor and QR code optimizer. The README describes the goal plainly: it compresses links and optimizes QR codes entirely in the browser, without a back-end database. That single sentence rules out a whole category of expectations. There is no shortening service, no stored mapping, no redirect endpoint. Whatever compression happens, happens on the client, and the result is a string the user carries, not an identifier the server resolves.

That makes it useful to a narrow set of people. If you generate QR codes for printed material, signage or packaging, and you want the encoded URL to be as short as possible so the QR modules stay large and scannable, this is the problem ha.mr addresses. If you build a browser-based tool that needs to squeeze a URL into a smaller payload without calling an API, the same mechanism applies. It is not for anyone who wants a link shortener in the conventional sense. The README's contributing section reinforces the intent: keep the scope small, and the author states that one day the project might reach a state where nothing has to be changed. That is a deliberate design position, not an unfinished roadmap.

How the compression pipeline works

The README lays out the mechanism in five steps, and the ordering matters. First, common parts of the link are manually detected and reduced to individual bits. Protocol, a www. prefix and index.html are the examples given. If a port is present, it is encoded as a raw numeric value rather than as text. This is a hand-written set of rules, which means it is tuned to the shapes of URLs the author expected to see.

Second, second-level and top-level domains are matched against a Huffman-coded dictionary of common websites and TLDs. A Huffman code assigns shorter bit sequences to more frequent symbols, so a domain that appears in the dictionary costs fewer bits than one that does not. Third, the remainder of the link is split into parts, and each segment is either fitted to a predefined character set or Huffman coded. Fourth, the output for links is encoded in the full character set of a URL. Fifth, and separately, QR code output uses the alphanumeric character set, which the README says removes overhead compared to other QR code generators.

That fifth point is the one with real technical weight. QR codes have different encoding modes, and the alphanumeric mode is a restricted set of characters that packs more data per module than the general byte mode. Staying inside that set is what makes the generated code smaller. It also means the compressor cannot emit arbitrary characters for the QR path. The README admits a wart here: square brackets are not supposed to be part of the URL character set, but the author notes it is too late to change that now. If your URLs contain brackets, that is worth knowing before you rely on the output.

Installing ha.mr and generating your first compressed link

The repository ships a Dockerfile and a compose.yml, so the documented path to a running instance is container-based. The compose file defines a single web service that builds from the current directory and maps host port 8080 to port 80 in the container.

yaml
services:
  web:
    build: .
    ports:
      - "8080:80"

The Dockerfile explains what actually gets served. It starts from nginx:alpine, copies nginx.conf into the nginx config directory, and copies docs/404.html, docs/alphabets.js, docs/compress.js, docs/main.js, docs/lean-qr/ and standalone.js into the web root. So the browser app lives under docs/, and the QR generation depends on the bundled lean-qr files, which the README credits in its acknowledgements. There is also a standalone.js at the top level, and the releases list a standalone tool at v1 and v1.1, so a single-file variant exists alongside the served app.

Once the container is up, open the page, paste a URL, and the compression runs in the browser. Nothing is sent to a server, because there is no server-side component beyond nginx serving files. The README does not document a CLI flag set, an API, or an environment variable for configuration, so treat the web interface as the entry point.

The limits you inherit from a no-back-end design

The absence of a database is not a minor implementation detail. It determines what the tool can and cannot do. A conventional shortener maps a short code to a long URL on the server, which is why the link keeps working when someone else clicks it. ha.mr cannot do that. The compressed form has to be self-contained, which is why the README spends its effort on bit packing and Huffman dictionaries rather than on storage.

The practical consequence is that compression ratios depend on how well your URL matches the author's assumptions. The first step is manual detection of protocol, www., index.html and port. The second step matches domains against a dictionary of common websites and TLDs. A URL on an obscure domain with an unusual path structure gets less benefit than one on a domain the dictionary knows. The README does not publish a ratio table or a benchmark, so there is no documented figure for expected savings. Anyone evaluating this should compress their own representative URLs rather than assume a number.

The bracket issue is the second limit. The README states that square brackets are included in the output character set even though they are not supposed to be part of a URL's full character set. That is an acknowledged deviation, and the author's phrasing suggests it will not be corrected. If downstream systems reject brackets in URLs, that matters. The third limit is scope by design. The contributing guidelines explicitly ask for bug fixes and standard maintenance rather than stacked features, and the author states pull requests that have not been discussed and are not trivial will be closed. If your use case needs a feature the project does not have, the contribution path is deliberately narrow.

How ha.mr differs from a hosted shortener or a QR generator library

The obvious comparison is a hosted link shortener. Those services store a mapping, return a short code, and resolve it on request. The difference is not just where the code runs. A hosted shortener can change the destination later, count clicks, and expire links. ha.mr can do none of those things, because there is no record of the link anywhere. What you get instead is portability: the compressed string is the whole artifact, and serving it requires nothing but static files.

The second comparison is a QR code library such as lean-qr, which ha.mr itself bundles and credits. A general QR library takes your input and encodes it, typically in byte mode. ha.mr's contribution is the compression step in front of that, plus the choice to target the alphanumeric character set for QR output. If you only need to draw a QR code from a URL and size is not a concern, a plain library is simpler and has fewer assumptions about your input. ha.mr earns its place when the URL is long enough that module density becomes a scanning problem, and when you control the URLs being encoded well enough that the dictionary and the manual rules actually fire.

Maintenance, licensing and upgrade cost

The repository is not archived, and the last push was on 2026-09-13. Releases are recent: v1 on 2026-08-09 and v1.1 on 2026-08-16, both labelled as the standalone tool. The commit history is not visible here, so the cadence of change beyond those releases cannot be judged from the repository listing.

The licence is MIT, which permits use, modification and redistribution with the licence and copyright notice retained. That is permissive and imposes no copyleft obligation on your own code. This is a statement about the licence text, not legal advice; if you are embedding the project in a product, confirm the terms with your own counsel.

Upgrade cost is low in one sense and uncertain in another. The deployed artifact is a set of static files copied into an nginx image, so upgrading means rebuilding the image and redeploying. There is no database migration, no schema, no state to preserve. But the compressed output format is the interface, and the README does not document a version field or a compatibility guarantee for previously emitted strings. If you have already printed QR codes or published compressed links, verify that a new release still decodes them before you roll it out. The README does not document rollback.

Editorial conclusion

Adopt ha.mr if you want a link and QR compression utility that runs entirely in the browser and can be served as static files, for example through the provided nginx image on port 8080. Do not adopt it if you need server-side shortening, redirects, analytics or link management, because the README describes no back end and no database. Before relying on it, verify the exact URL character set it emits, since the README notes square brackets are included even though they are not supposed to be part of that set.

Frequently asked questions

What does ha.mr mean?

The README does not explain the name. It describes the project only as a static URL compressor and QR code optimizer that runs entirely in the browser without a back-end database.

What is the difference between ha.mr and a hosted link shortener?

ha.mr has no back-end database, so it does not store a mapping or resolve a short code on request. The README describes compression that happens entirely in the browser, producing a self-contained string rather than a server-side redirect.

How do I install and run ha.mr?

The repository provides a Dockerfile and a compose.yml. The compose file builds a web service from the current directory and maps host port 8080 to port 80, so the container serves the app on that port.

Does ha.mr produce smaller QR codes than other generators?

The README states that QR output uses the alphanumeric character set to remove overhead compared to other QR code generators. No measured comparison or ratio is published, so the claim is the author's stated design intent.

Official sources

  1. License: MIT
  2. p2r3/ha.mr on GitHub
  3. Project website
  4. README
  5. Releases
Community notes

Community notes