Right place, wrong hands
A normal <img> tag is a public URL. View-source, DevTools, or one bulk scraper later, your full-resolution master is on someone else’s storefront — metadata, quality and all.
For photographers, galleries & shops who sell pictures
In server mode, Archnemix serves authorized images in scrambled pieces
behind one-time tokens, reassembled inside a guarded viewer. Keep masters
outside every declared public root. The server bounds each derivative by
its configured entitlement and width caps; set maxWidthFraction
below 1 if native-resolution pixels must never be delivered. Extraction
tools get permuted tiles and decoys; visitors get the photograph.
The 3D illustration needs WebGL. The idea, in one line: the picture travels as 64 permuted, mirrored tiles and only becomes a picture inside the viewer.
Reassembled, per-viewer, inside a canvas — never as an <img> with an address. Drag to orbit it, hover a tile to trace it, click to scatter.
No live demo on this static website: the hero is an explanatory illustration only. There is no Archx server here to authorize a viewer, mint and spend a token, keep a master private, or build a Sharp derivative — that server is the main protection boundary. The real end-to-end demo is run locally from the GitHub repository. The grid choices above (8–32) are the same range the product permits for new payloads: coarser grids are refused at creation because tile-edge jigsaw solvers reassemble them without any key.
npm install @archnemix/image-protection
Node ≥ 20.9 · pure-JS client · Sharp on the server · free for any use
A normal <img> tag is a public URL. View-source, DevTools, or one bulk scraper later, your full-resolution master is on someone else’s storefront — metadata, quality and all.
Visible marks can be cropped or obscured; metadata is often stripped by re-upload. Neither controls who receives the pixels or stops an authorized viewer from capturing them.
It annoys your customers and stops nobody. Real protection has to change what the server delivers: keep the master private, authorize each view, and apply quotas plus a width policy. Scraping can be limited, not eliminated.
Keep originals outside every public root and declare those roots
with publicDir/publicDirs. The middleware checks
declared overlaps at startup; undeclared host mounts remain your
responsibility. The middleware is the only intended reader.
Your authorize callback decides who may see what, and how
large. The server applies the signed entitlement and configured width
caps, permutes the tiles under a 128-bit-seeded plan, optionally seals
them with AES-256-GCM, and issues a short-lived token with one-time
claim enforcement while its spend record is retained. The default
maxWidthFraction is 1, so set it below 1 when native-width
pixels must be withheld.
Canvas/WebGL rendering with no ordinary image URL to copy. Read-back gets a decoy; capture signals may trigger a black or degraded frame. Deliveries can carry an invisible StegoMark fingerprint tied to an issuance record; in the project’s 99-case fixed image-transform bench it recovered in 85 cases. The matrix has no screenshot/camera capture, and is not a universal recovery rate.
| Layer | What it does | What it costs |
|---|---|---|
| Private masters | Keep originals outside public roots; startup rejects overlaps with roots declared to Archx. | Nothing at runtime |
| Entitled derivatives | Only the authorized, width-capped derivative leaves; with the default fraction of 1, native-width pixels may be allowed. Set maxWidthFraction below 1 for preview-only delivery. | One Sharp transform, cached |
| Tile scramble + optional AES-256-GCM | Raw network capture gets scrambled bytes; reconstruction is possible with enough work. AES-GCM optionally protects the payload from parties without its key. | Fused pad + scramble measured at ≈2 ms at 960 px; Sharp decode/resize/encode is separate |
| One-time signed tokens | HMAC tokens are spent on first use; sender constraints and authorization reduce replay and hot-linking, while new mints remain subject to host policy. | Microseconds |
| Guarded viewer | No src to steal; poisoned read-back; screenshot-degrading temporal interlace at 60 Hz. | GPU-cheap canvas work |
| StegoMark fingerprint | Invisible per-recipient mark with BCH error correction; identified later by rescan, no original needed. | ≈9 ms at 960px, opt-in |
| Abuse budgets | Rate limits and distinct-image quotas bound collection and resource use; public anonymous minting can still be harvested within active limits. | Counters, not compute |
Every number below comes from the benchmark and attack suites shipped in the repository. Run them yourself: npm run bench:stego, npm run redteam.
import { createArchxMiddleware }
from '@archnemix/image-protection/server';
app.use(createArchxMiddleware({
imagesDir: '/private/masters', // outside public/
publicDirs: ['/var/www/public'], // declare every static root for overlap checks
maxWidthFraction: 0.6, // omit native-width pixels for preview-only delivery
secret: process.env.ARCHX_SECRET,
authorize: async (req, image) =>
req.user ? { maxWidth: 1600 } : false,
}));
import Archx from '@archnemix/image-protection';
Archx.load.image('#hero-photo', { id: 'aurora-valley' }, {
tokenEndpoint: '/archx/token/',
profile: 'elite', // lite · performance · elite — or custom flags
temporalInterlace: { refreshHz: 60 },
});
Three profiles set the defaults — lite spends the least CPU and memory, performance balances protection and cost, elite turns every hardening layer on — and any individual setting can still override them.
Prefer static hosting? npx archx-build creates scrambled derivatives and a manifest for CDN delivery. Its keys are browser-delivered, so a public manifest is not access control or DRM; keep private catalogs behind your own authorization/CDN layer. The dynamic server middleware works with Express, Fastify, or plain node:http.
The guided path: install, quick starts, the three profiles, key options, the five server rules, and ownership proof.
Twenty-one engineering decisions with the alternatives we rejected — and the measurements that settled them.
Eight attacker classes, what each one walks away with, and the limits no browser tool can cross.
The complete reference — every option, CLI flag, and the deployment runbook — lives in the project README and operations guide on GitHub.
Archnemix Image Protection is released under the BSD Zero Clause License (0BSD). Use it, copy it, modify it, ship it in commercial products — for any purpose, with or without fee. No attribution is required and no permission need be asked.
If it saves your work from being lifted, a credit line or a link back is warmly appreciated — and entirely optional. That is the deal, in full; the license text fits in a paragraph in the repository.