GpuFiles
In the client's tab

Shredding

Everything on this page happens in the client's browser, before a single byte is sent.

Reading files

The app reads .txt and .md as text (Markdown is stripped of code blocks, links and markup) and.pdf with pdf.js, page by page. Files never leave the tab; only fragments do.

Fragments

Text is split on sentence boundaries and packed into fragments of about 150 to 300 characters. A sentence longer than 300 characters is cut on a word boundary; a short tail is merged into its neighbour. The pool refuses any fragment over 400 characters, which keeps a fragment at the size of a thought rather than a paragraph.

Scrub

On by default. Before fragmenting, the app replaces with neutral tokens:

  • email addresses → [email]
  • EVM and Bitcoin addresses → [address]
  • IBAN-shaped strings → [iban], card-length digit runs → [number]
  • phone numbers in common international and national formats → [phone]

The scrub uses patterns, so it catches the obvious; names and free-form secrets are not detected.

Ids, lanes, decoys

Each fragment gets a random 64-bit id. Its lane is drawn at random from 6, then moved if it equals the lane of the fragment before it. About 15 % more fragments are added as decoys: sentences assembled locally from a neutral word stock, with random lanes. The whole list is shuffled. The pool receives { id, text, lane }triples and nothing else.

// in the browser
fragments = split(scrub(text))            // order known here only
lanes     = colour(fragments)             // lane[i] != lane[i - 1]
wire      = shuffle(fragments + decoys)   // { id, t, l }
IndexedDB <- { id -> (document, position, text) }

The map

The map from id to document and position is written to IndexedDB under this site's origin. Decoy ids are not stored: when the vectors come back, the vectors of decoys have nowhere to go and are dropped. Erasing the library in the app deletes the map and the index.