Skip to content
pips-appPublic

About

Pixel-art swap cards that travel by QR code

Resources

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

Pips

Pixel-art swap cards that travel by QR code. Draw or import a small picture, put your handle on the back, sign it, and hand it over: the other phone scans it, checks the signature, and the card joins their collection with its history — who drew it, who passed it on, which copy of how many.

No server, no accounts, no tracking. Everything lives on the device; a card moves only as the person sends it: a QR code on the screen, or a link, a .pips file or a picture of the card, each carrying the same signed envelope.

Status: early. The core is complete and tested; the app works end to end but its design is still a first draft. Formats may change before 1.0.

What works

  • Identity: an Ed25519 key, restored from 24 words or a paper QR code.
  • Cards up to 64×64 px in the app (the format holds 128), 32 colours, animation; 33 built-in palettes; a pixel editor with layers, frames that last as long as they need, and an undo tree.
  • New cards from pictures: PNG and Aseprite files as they are (layers, frames, upscaled exports), photos and larger pictures (JPEG, WebP — whatever the browser opens) through a square crop; semi-transparent pixels are made solid, and the app says how many; a picture of a Pips card opens as the card itself.
  • Several cards at once: as one .pips file or as a picture of each; several files received at once.
  • Giving and receiving by QR — one code, or a fountain-coded carousel for large cards; every card and envelope signature is checked. QR codes are read by the browser where it can, by our own reader everywhere else.
  • Numbered copies: the artist scans the recipient's code and issues "№3 of 50", signed and bound to that person.
  • Collection by weeks and months, a feed and single cards; archive, bin, personal notes and tags.
  • Encrypted backups that open only with the same key (its words or paper QR); restoring brings back the key and the collection in one step.
  • Titles and names in any script, the same length in each (32 and 24 characters), emoji included; nothing invisible or text-reversing — the same rule in the core and in what the app lets be typed.
  • A card from a newer version of Pips is said to be one, not called damaged.
  • Russian and English; installable, works offline.

Layout

Path What
crates/pips-base45 Base45 (RFC 9285), the text inside QR codes
crates/pips-palette built-in palettes, .hex / .gpl import
crates/pips-format the card format: strict codec, canonical form, digest
crates/pips-sign keys, signatures, edition certificates, envelopes, recovery words
crates/pips-qr single QR codes and the carousel
crates/pips-raster PNG / Aseprite import
crates/pips-store backups
crates/pips-wasm one facade over all of the above for the web app
crates/pips-scan QR reading for browsers without BarcodeDetector, loaded on demand
web/ the app: plain ES modules, no build step, strict CSP
web-next/ the app written again, layer by layer, not published yet (docs/REWRITE.md)
vendor/rqrr the QR reader pips-qr uses, with fixes of ours (PIPS.md)

Each crate does one thing and is no_std where it can be; most come with a small command-line tool (pips-card, pips-sign, pips-qr, pips-raster, pips-backup…) that reads standard input and writes standard output. Every parser is strict: it refuses rather than repairs, and checks sizes before allocating. Design decisions and their reasons are in DECISIONS.md (Russian).

Build and run

Needs Rust (stable, with the wasm32-unknown-unknown target), the matching wasm-bindgen-cli, and Python 3 for the local server. On NixOS, nix-shell provides all of it.

cargo test --workspace      # the core
scripts/build-wasm.sh       # the core for the browser, into web/pkg/ (and web-next/pkg/)
scripts/serve.sh            # http://localhost:8000

Browser tests drive the app in Chromium (and, in CI, Firefox) through its real journeys — import, exchange by QR, link, file and picture, refusals, numbered copies, backups, restoring, the editor, the published site with no network and its next release — and keep each screen's layout at three sizes (and in English at the narrowest) and the collection's zoom from laying the page out on every frame; unit tests (tests/unit, plain node) cover the app's logic:

node --test tests/unit/*.test.mjs
cd tests/e2e && npm ci && npx playwright install chromium && npm test

The new app's tests (tests/next) run the same way, in Chromium, Firefox and WebKit alike:

cd tests/next && npm ci && npm test       # BROWSER=firefox, BROWSER=webkit

What the tests reach of the app's code can be measured (Chromium and node), with the functions no test runs and the files no test loads listed:

cd tests/e2e && COVERAGE=/tmp/cov npm test && cd ../..
NODE_V8_COVERAGE=/tmp/cov node --test tests/unit/*.test.mjs
node tests/coverage-report.mjs /tmp/cov

Every parser of outside input has a fuzz target (fuzz/, nightly Rust):

cargo install cargo-fuzz
cd fuzz && cargo +nightly fuzz run card corpus/card seeds/card

scripts/build-site.sh assembles what GitHub Pages publishes. CI runs formatting, clippy, tests, the minimum Rust version, a RustSec check of the dependencies, a type check of the app and the browser tests (Chromium and Firefox, a seeded "monkey" among them), and deploys main — on each push to main and each pull request; a second workflow fuzzes every target on the same and for longer once a week. A third, run by hand (Actions → Repeat browser tests), runs the browser tests many rounds over in both browsers, to find any that pass only sometimes.

Contributing

Start with docs/GUIDE.md (Russian): how the project is put together, where things live, how to fix a bug properly and what not to touch. First project ever? docs/FIRST-STEPS.md. AI assistants: AGENTS.md. Plans for an Android app: docs/ANDROID.md (Russian).

Licence

Code: Apache-2.0. vendor/rqrr: rqrr 0.11.0 with one fix of ours (see its PIPS.md), MIT or Apache-2.0, and ISC. Fonts in web/fonts: SIL Open Font Licence (see the files there). Test pictures in crates/pips-raster/tests/aseprite: MIT, from the asefile project. web/dev/qrcode.js (development only, not published): MIT, Kazuhiko Arase.


По-русски. Pips — пиксельные карточки для обмена через QR-код, без сервера и аккаунтов. Проект на ранней стадии: ядро готово и покрыто тестами, приложение работает целиком, дизайн — первый черновик. Решения и их причины — в DECISIONS.md; как устроен проект и как в нём работать — в docs/GUIDE.md, первый шаг для новичков — docs/FIRST-STEPS.md, для ИИ — AGENTS.md.

About

Pixel-art swap cards that travel by QR code

Resources

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages