為連結或任何文字建立一個屬於您的 QR 碼,並在列印前進行檢查。完全免費:無需註冊。該 QR 碼會直接開啟您的連結,而非透過我們,因此只要您的連結有效,它就永遠有效。我們從不
AI 翻譯
Make a QR code for a link or any text, checked before you print it. Free as free gets: no sign-up. The code opens your link directly, not through us, so it works for as long as your link does. We neve
生產力HTML · JavaScriptGitHub @honestrobin上線中營運者未確認
試用過了嗎? 點一下就好,不需要登入。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Honest Robin: QR。一個屬於您的 QR 碼。
AI 翻譯
Honest Robin: QR. A QR code that's yours to keep.
正在載入完整 README。 以下為已儲存的摘錄。
A QR code that's yours to keep, at qr.honestrobin.com. Type or paste
a link, or any text, and the code appears as you type. The page reads its own code back with a QR
reader and says whether it scans, and how small you can print it. Take it as PNG or SVG.檢視完整 README ↗A QR code that's yours to keep, at qr.honestrobin.com. Type or paste a link, or any text, and the code appears as you type. The page reads its own code back with a QR reader and says whether it scans, and how small you can print it. Take it as PNG or SVG.
What's planned, in order and without dates, is in ROADMAP.md.
Made with AI: Claude, Anthropic's AI, wrote it. The maintainer, Marko Kruljac, gives the
instructions, tests it and approves every release. Every promise it makes, and what guards it, is
in PROMISES.md. It follows the Robin's Code.
| Company | Country | What it does |
|---|---|---|
| Cloudflare | United States | Serves the page and runs its one piece of server code. Counts visits with its cookie-free Web Analytics: the counter records the page's address, the site a visit came from, the country, browser, system, device type and load times. It runs inside the page and sends nothing you type. Keeps the counts of what's done on the page (below) for three months, in its own store (Workers Analytics Engine), with nothing of yours: not your address, not your browser. We use Cloudflare because it already serves honestrobin.com and serves static pages well at no cost; we'll move to a European host that serves you as well. |
Nobody else. The page's security policy (public/_headers) lets it talk to nothing but its own address
and Cloudflare's counter. Our server code sends nothing anywhere. A copy of QR anywhere else sends us nothing: Cloudflare adds the
visit counter only at qr.honestrobin.com, and a copy's server code keeps its counts in the store
of whoever deploys it.
Visits, by Cloudflare's counter, and what's done on the page, never what's in it:
| Count | With |
|---|---|
| A code made (the first on a page view) | link or text |
| A code taken | how (PNG or SVG downloaded, copied, shared, or a sheet sent to print), link or text, the image (none, the robin, your own), colours and background (as they are, or chosen), on a sheet, which layout (how many on a page, or a size of one's own) and whether the codes have a caption |
| A suggested fix taken | which: adding https://, or removing spaces |
| A code that doesn't scan | why: colours too alike, the image, or the reader couldn't read it |
Each count also has the page's language and a random id made for that page view, so counts from one
visit can be seen together, and the id doesn't link one visit to another. The page keeps the id
nowhere and forgets it when it closes. worker/counts.js holds the list and refuses anything else.
About 60 counts a minute are kept from one address: Cloudflare's limiter uses the address only to
apply the limit, and it isn't stored with the counts. The limiter is approximate, and counts in each
Cloudflare location apart. Cloudflare keeps no log of the count requests for us: the Worker's logs
are off.
To read them, query the dataset qr_counts with Cloudflare's Analytics Engine SQL API, with a
token that can read Account Analytics. Each count is one row: index1 is the page view's id, and
the blobs and doubles are in the order worker/counts.js lists them (blob1 is the event).
Count rows with SUM(_sample_interval), not COUNT(), since Cloudflare samples at high volume.
Plain HTML, CSS and JavaScript, with no build step and no dependencies at run time, and one small piece of server code that stores the counts.
| Path | What |
|---|---|
tools/page.html | The page, with a {{key}} for every word |
words/<language>.json | The words, one file per language, with the same keys as en.json |
tools/pages.py | Writes public/index.html (English), public/<language>/index.html, sitemap.xml and robots.txt from the two above, with what search engines and chats read (the preview card's tags and the structured data), and stamps each stylesheet and script link (in 404.html too) with its version. Run it after changing either; CI fails if a page is out of date |
tools/cards.py | Draws the preview card a shared link shows, one per language (public/assets/cards/): the page's headline, and a code that opens that language's page, read back before it's kept. Run it after a headline changes; it needs Chromium |
public/ | Everything that's served, and nothing else: the pages, 404.html, _headers, the icons and assets/ |
public/assets/qr.js | Makes the code, checks it, and hands it over |
public/assets/language.js | Picks the language: what you picked, else your browser's list, never your IP address |
public/assets/qr.css | The look: a mat of small squares, a sticker, and a field drawn like the robin |
public/assets/vendor/ | The QR encoder and the reader for the check, copied in (public/assets/vendor/README.md) |
public/assets/fonts/ | Archivo, under the SIL Open Font License |
public/_headers, wrangler.jsonc | How Cloudflare serves it |
worker/index.js, worker/counts.js | The one piece of server code: it stores the page's counts, as listed above, in Cloudflare's store, and does nothing else |
tests/ | The checks every change runs before it merges and before it goes live |
docs/releases/ | The record of each release |
English, Spanish, Portuguese (Brazil), French, German, Italian, Dutch, Polish, Croatian, Turkish,
Indonesian, Japanese and Korean. A new language is a new words/<code>.json and its code in
LANGUAGES in tools/pages.py. Words that change with a number ("1 znak", "3 znaka", "5
znakova") can be plural forms, chosen with Intl.PluralRules. Translations are made by an AI and
checked by a second one translating them back to English.
When typing stops, the page draws the exact PNG it would download and reads it back with jsQR. It says "Scans fine" only when what it reads is, byte for byte, what was typed, and "Doesn't scan" otherwise. Colours too alike for a phone (a contrast under 3:1) are called out even when the reader manages. jsQR isn't a phone camera, which is why the page also says how small you can print.
Every pull request runs .github/workflows/checks.yml, and every deploy runs it first: the pages
are up to date with their words, the HTML is valid, Cloudflare would accept the deploy, and in
desktop Chrome, Chrome on Android and Safari on iPhone the tests in tests/ pass. They use the
page as a person does, mistakes included, and read back every code they make with their own copy
of jsQR. Each run keeps a picture of every screen (the screens artifact).
To run them yourself:
cd tests && npm ci && npx playwright install chromium webkit
npm run html && npx playwright test
.github/workflows/deploy.yml runs the checks, then wrangler deploy, which uploads public/
(minus the one file in public/.assetsignore) and the server code to Cloudflare Workers at
qr.honestrobin.com. For now it runs only when
started by hand (Actions → Deploy → Run workflow). The Cloudflare token lives in GitHub's secrets,
never in the files.
Visits are counted by Cloudflare Web Analytics: its automatic setup for honestrobin.com adds the cookie-free counter to every page at Cloudflare's edge, so QR's own files have none, and a copy of QR anywhere else counts nothing. QR's visits show in honestrobin.com's Web Analytics, under the hostname qr.honestrobin.com. The tests add the same tag to check what it sends.
The page is plain files. Serve public/ from the root of an address, with any web server, and
it works the same; without worker/, its counts go nowhere. public/_headers is Cloudflare's format, so
on another server, set the same headers yourself. To run it on your own Cloudflare account, put
your address in wrangler.jsonc and run npx wrangler deploy. On your own address, also put it in
SITE in tools/pages.py and run python3 tools/pages.py and python3 tools/cards.py: the
addresses search engines read, and the preview picture a shared link shows, then point to your
copy, not to ours.
Issues and pull requests are welcome: CONTRIBUTING.md says how. Report a security problem privately, as SECURITY.md says.
The code is under the GNU AGPL v3, with no contributor licence agreement. The libraries
in public/assets/vendor/ keep their own licences (public/assets/vendor/README.md),
and the font is under the SIL Open Font License. The name and the robin aren't part of the
licence: TRADEMARKS.md says what's fine.