# inktype.cc — Extended Developer & AI Agent Documentation > inktype.cc is a free, browser-only tool that converts handwriting into a real OpenType font (.otf file). There is no backend, no server-side compilation, and no user accounts. Everything runs locally in the browser — your images never leave your device. --- ## 1. Core Architecture The application is structured as a lightweight single-page application (SPA) built using **Vite** and **Vanilla ES Modules (Vanilla JS)**. It intentionally avoids framework overlays (like React, Vue, or Svelte) to maintain performance, immediate startup, and a simple browser execution model. ### Key Libraries & Stack - **opentype.js:** Main font engine wrapper that parses, mutates, and compiles the final OpenType (.otf) binary. - **ImageTracer.js:** A raster-to-SVG vectorisation engine that converts extracted pixel outlines into mathematical SVG bezier curves. - **js-aruco2:** Detects ArUco fiducial markers on the uploaded capture sheet to establish a stable canonical layout grid. - **qrcode / jsqr:** Encodes/decodes page metadata on the printed sheets. - **perspective-transform:** Calculates the 4-point homography transform to correct perspective distortion in handheld smartphone photographs. - **jspdf:** Generates the highly detailed vector-based PDF printable templates. --- ## 2. Directory Layout & File Structure The project has a flat structure where HTML files act as discrete stages, style sheets manage the brand aesthetics, and scripts encapsulate the pipeline tasks. ``` index.html Markup for all 3 application views: intro, upload modal, editor how-to.html Step-by-step tutorial page licenses.html Open-source license attributions privacy.html Privacy policy detailing 100% browser-local computation package.json Vite configuration scripts and dependencies vite.config.js CJS interop filters (crucial for js-aruco2 & perspective-transform) src/ ├─ style.css Tailored theme styles, layout grids, variables, typography ├─ main.js UI driver: page stage transitions, grid rendering, and storage ├─ config.js Shared metrics: geometric shapes, coordinates, marker versions ├─ template.js Generates PDF & PNG printable capture templates with ArUco corners ├─ processor.js CV pipeline: marker detection, de-warping, QR parsing, glyph vectorisation └─ font-engine.js opentype.js wrapper: composes adjustments, handles winding, exports OTF public/ ├─ favicon.svg Primary SVG icon ├─ site.webmanifest PWA manifest parameters ├─ llms.txt Summary AI agent map └─ llms-full.txt Detailed AI agent developer guidelines (this file) tests/ └─ config.test.js Vitest unit tests verifying geometries and math transforms ``` --- ## 3. The Processing Pipeline (Image to Glyphs) The workflow consists of three core phases that run sequentially: ### Phase 1: Capture & Alignment (Computer Vision) 1. **ArUco Detection:** Finds 4 ArUco markers (dict 7x7) placed in the corners of the capture sheet. The marker IDs are mathematically mapped to denote versioning and corner positions: `ID = version * 4 + corner` (where TL=0, TR=1, BL=2, BR=3). Current version 1 uses IDs 4–7. 2. **Homography Transform:** Constructs a perspective projection matrix from the 4 detected corners to map the physical photograph onto a canonical A4 aspect ratio sheet space. 3. **Metadata Extraction:** Extracts the QR code at the top-center of the de-warped space and decodes the metadata format: `{version}:{lang}:{cols}x{rows}`. ### Phase 2: Extraction & Vectorisation (Raster to Vector) 1. **Grid Parsing:** Walks the canonical grid based on the QR metadata (default 11 cols x 10 rows). 2. **Cell Binarisation:** Crops out each individual cell space, applies adaptive thresholding, and binarises pixels to black/white. 3. **Bezier Vectorisation:** Runs ImageTracer on the binary cell outlines to construct closed path loops. Holes (counter-spaces) are detected and their coordinate winding direction is reversed (clockwise vs counter-clockwise) to compile cleanly into fonts. ### Phase 3: Fine-Tuning & Engine Mathematics (Editor) The `FontEngine` manages two levels of transformations: - **Global Adjustments:** Applied to every glyph: `{ shiftX, shiftY, scale, advance }`. - **Local Adjustments:** Applied to a specific glyph index: `{ shiftX, shiftY, scale, advance }`. The final glyph transform is a composition of both spaces: `FinalTransform = GlobalAdjustments ∘ LocalAdjustments` #### Math Specifics: - **Units:** Calculated in Font Units (unitsPerEm = 1000, see `src/config.js`). - **Scale:** Expressed as a percentage (100 = 1x). - **Default Spacing:** Standard default per-glyph advance width is `unitsPerEm * 0.6`. - **Auto-Process Layout:** Computes bounding boxes in post-global space and crops glyph margins based on cap-height of the reference glyph 'O'. --- ## 4. UI Stage Transitions The application is a single-page app utilizing three main view states toggled via the `.hidden` class: 1. `#view-intro` — Landing page containing charset options, PDF/PNG template download dropdown, and upload trigger. 2. `#scrim` — Progress overlay modal showing the live multi-stage CV processing status. 3. `#view-editor` — Grid view of all captured glyphs alongside the adjustment side-panel, live preview, and export actions. Persistence is maintained in browser LocalStorage keyed as `fontMaker__`, storing `{ globals, locals[] }` so progress is fully restored upon re-uploading the same scan. --- ## 5. Key Developer Guidelines & Interop Constraints - **CommonJS (CJS) Interop:** `js-aruco2` and `perspective-transform` write to global scope using `this.X = X`. Vite 8's strict-mode IIFE compilation breaks this, which is bypassed with source transforms defined in `vite.config.js`. Do not remove or alter these Vite plugin configurations. - **Original Path Winding:** The `processImage` routine outputs characters with `originalPath` strings. The font engine mutates `glyph.path` *in-place* from the immutable `originalPath` on every update slider event. Do not replace or delete `originalPath`. - **Weight Axis:** inktype.cc has no active font weight synthesis axis. The UI intentionally dropped the weight slider. Do not attempt to add one without designing a solid glyph skeleton dilation synthesis path in the engine. - **Vitest Testing:** Run `npm run test` to verify changes. All math coordinates, schema metrics, and template layouts must satisfy existing tests.