Vibecode Kittl
track this build4 phases, 12 steps, beginner friendly0%The core loop is buildable, but a dependable replacement becomes a real weekend or multi-day project. For Kittl, create typography-heavy graphics, labels, posters, and merchandise-ready exports. The hard boundary is specialized templates, fonts, vector effects, asset library, and mockups, plus editor polish, assets, collaboration, and distribution.
You are building a lean indie version of Kittl. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Kittl · indie build A vector design tool for typographic work, where the engineering is text on curved paths and true print output, and the constraint is that every font carries a licence the export path enforces. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Canvas | A vector scene graph with text as live editable objects | text that has been converted to curves cannot be corrected later | | Typography | Text on paths, with real font shaping | shaping is what makes typography look right and cannot be approximated | | Effects | Warp, offset and shadow computed on outlines | raster effects do not survive print resolution | | Export | Vector formats with correct colour and bleed for print | merchandise printing has requirements a screen export does not meet | | Licensing | Per-font permissions checked at export against a declared use | the restriction is on the use, and the use is only known at export | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the editor and the export pipeline. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A real text shaping engine** · free - Why: Kerning, ligatures and alternates are the whole point of a typographic tool and cannot be approximated by advancing a fixed width. - Get it: A maintained shaping library with bindings for your runtime. - Verify: A kerning pair and a ligature render identically to a reference - [ ] **A robust 2D geometry library** · free - Why: Offsetting glyph outlines produces self-intersections routinely, and resolving them by hand is a research project. - Get it: A library with reliable boolean operations and offsetting on paths. - Verify: Offsetting a complex glyph produces clean geometry - [ ] **Fonts whose licences you have read** · free for open fonts; commercial licences vary widely - Why: The build enforces per-font permissions, and you cannot record permissions you have not read. Assume nothing about merchandise use. - Get it: Take three or four typefaces you would actually use and read each licence, noting desktop, webfont, merchandise and embedding permissions separately. - Verify: A written record exists per font with four separate permissions - [ ] **A print target and its specification** · free to obtain - Why: Bleed, colour profile and minimum line width come from the actual printer, and an export built to a guess gets rejected or prints badly. - Get it: Pick a print or merchandise service and download its artwork specification. - Verify: The specification is saved and its requirements are encoded in the export settings ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - A licensed font library. - Raster image editing. - Print fulfilment and mockups. - Legal advice about a specific licence. - specialized templates, fonts, vector effects, asset library, and mockups - huge template and asset libraries - real-time multiplayer - brand governance - professional print workflows If one of those is essential to you, that is the reason to keep paying for Kittl, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Kittl The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me typography-heavy graphics with print-ready export and licences you can account for to replace Kittl. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero The output of this tool goes on merchandise that gets sold, and the fonts in it are licensed software rather than files you own. Font licences are tiered and the tiers matter: a desktop licence typically covers making artwork, a webfont licence covers serving it on a page, and putting a typeface on products for sale usually needs a separate commercial or extended licence, sometimes with a unit limit. Embedding a font in an exported vector file is itself a distribution the licence may or may not permit. So every font in this build carries a licence record with those permissions as separate fields, and export is blocked where the licence does not cover the intended use, naming the restriction. The intended use is asked for at export rather than assumed. This is not pedantry. Foundries do enforce, the person who gets the letter is the seller rather than the tool, and by the time it arrives the products are already out there. ### Stack (fixed, do not substitute) - Canvas: A vector scene graph with text as live editable objects · text that has been converted to curves cannot be corrected later - Typography: Text on paths, with real font shaping · shaping is what makes typography look right and cannot be approximated - Effects: Warp, offset and shadow computed on outlines · raster effects do not survive print resolution - Export: Vector formats with correct colour and bleed for print · merchandise printing has requirements a screen export does not meet - Licensing: Per-font permissions checked at export against a declared use · the restriction is on the use, and the use is only known at export ### Data model (create this before Phase 1) - documents(id, name, width_mm, height_mm, bleed_mm, colour_profile, created_at) - layers(id, document_id, ordinal, kind, transform_json, style_json) - text_objects(layer_id, content, font_id, size_pt, tracking, path_id, shaping_features_json) - fonts(id, family, style, file_path, licence_id, embedding_allowed) - licences(id, name, allows_desktop, allows_webfont, allows_merchandise, allows_embedding, unit_limit, source_url) - exports(id, document_id, format, declared_use, blocked_reason, fonts_used_json, at) - An export records which fonts it used and the use declared, so a licence question months later has an answer. ### Phase 1 · Text that is really text Build: A vector canvas with text objects using real font shaping, including ligatures, kerning and alternate glyphs. Keep text editable rather than converting to curves. Handle a font missing from the machine. Trap: Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. Done when: Kerning pairs and ligatures render correctly, compared against a reference rendering. Alternate glyphs and stylistic sets can be applied. Text remains editable rather than being converted to curves. A missing font is reported clearly rather than substituted silently. Do not build yet: No paths, effects or export. ### Phase 2 · Text on a curve, correctly Build: Place text along an arbitrary path, distributing glyphs by arc length rather than by parameter, with rotation per glyph. Handle tight curves where glyphs would overlap, and text longer than its path. Trap: Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. Done when: Text on a circular path is evenly spaced all the way round, verified by measurement rather than by eye. A tight curve either adjusts spacing or reports that glyphs would overlap. Text longer than its path is handled by a stated rule rather than running off. Each glyph's rotation follows the tangent. Do not build yet: No effects or export yet. ### Phase 3 · Effects that survive print resolution Build: Implement warp, offset outline and layered shadow as operations on the glyph outlines themselves. Handle self-intersecting outlines from an offset. Keep effects non-destructive so the underlying text stays editable. Trap: Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. Done when: An offset outline is real geometry that scales to any resolution, verified by exporting at print size. Self-intersections from an offset are resolved rather than producing artefacts. Effects are non-destructive and the text underneath remains editable. A warped text object still shapes correctly when its content is changed. Do not build yet: No export or licensing yet. ### Phase 4 · Output a printer will accept Build: Export vector formats with bleed, a stated colour profile, and outlines or embedded fonts as the target requires. Warn where a colour is outside the printable range. Include a preflight report of what the file contains. Trap: Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. Done when: An export includes bleed and carries the correct colour profile. Colours outside the printable range are warned about before export rather than converted silently. The preflight report lists fonts, colours, minimum line widths and image resolutions. A printer accepts the file without querying it. Do not build yet: No licence enforcement yet. ### Phase 5 · Licences enforced where it matters Build: Record per-font permissions for desktop, webfont, merchandise and embedding, with any unit limit. Ask for the intended use at export and block where the licence does not cover it, naming the restriction. Record every export's fonts and declared use. Trap: Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file. Done when: Exporting for merchandise with a font lacking that permission is blocked, naming the restriction, tested directly. The intended use is asked at export rather than read from a setting. Embedding permission is checked separately from merchandise permission. Every export records its fonts and declared use, exportable as a document. Do not build yet: Nothing after this. ### Out of scope (and why) - A font library, which is what the hosted products actually license on your behalf and is most of what you pay them for. - Raster image editing, which is a different tool and a different set of problems. - Print fulfilment and product mockups, which is the commerce half of this category. - Legal advice about a specific font licence, which varies by foundry and needs reading rather than assuming. ### README must contain - That font licences are tiered and merchandise use usually needs a separate permission - That the intended use is asked at export rather than stored as a setting - That embedding a font in an exported file is a distribution the licence may not permit - That text is placed by arc length on a path, not by parameter - That outline effects are real geometry because raster strokes print blurred ===== AGENTS.md ===== # Agent instructions · Kittl indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: A vector scene graph with text as live editable objects, Text on paths, with real font shaping, Warp, offset and shadow computed on outlines, Vector formats with correct colour and bleed for print, Per-font permissions checked at export against a declared use. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. ===== BUILD_PLAN.md ===== # Build plan · Kittl A vector design tool for typographic work, where the engineering is text on curved paths and true print output, and the constraint is that every font carries a licence the export path enforces. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Text that is really text Typography is shaped correctly and stays editable. ### Steps 1. Use a real shaping engine Kerning and ligatures are the difference between typography and text. Files: `src/shape.ts` 2. Expose the font's own features Alternates and stylistic sets are why display faces are bought. Files: `src/features.ts` 3. Never substitute silently A missing font changing the design without saying so is the worst outcome. Files: `src/fonts.ts` ### Done when - [ ] Kerning and ligatures match a reference - [ ] Alternates and stylistic sets apply - [ ] Text stays editable - [ ] A missing font is reported, not substituted ### Watch out - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. ## Phase 2 · Text on a curve, correctly Type follows an arc without distorting or bunching. ### Steps 1. Place by arc length Not by parameter. Parameter placement bunches on tight curves. Files: `src/textpath.ts`, `src/textpath.test.ts` 2. Rotate each glyph to the tangent Otherwise the letters stay upright on a curve, which looks broken. Files: `src/textpath.ts` 3. Handle overflow and tight curves explicitly A stated rule beats text running off the end. Files: `src/textpath.ts` ### Done when - [ ] Circular text is evenly spaced by measurement - [ ] Tight curves adjust or report overlap - [ ] Overflow follows a stated rule - [ ] Glyph rotation follows the tangent ### Watch out - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. ## Phase 3 · Effects that survive print resolution Warps and outlines are vector operations, not filters. ### Steps 1. Offset the outline geometry A raster stroke prints blurred at merchandise resolutions. Files: `src/offset.ts` 2. Resolve self-intersections Offsetting a complex glyph produces them reliably. Files: `src/geometry.ts`, `tests/offset.test.ts` 3. Keep effects non-destructive Editing the words afterwards is the normal case. Files: `src/effects.ts` ### Done when - [ ] An offset outline scales to print resolution - [ ] Self-intersections are resolved - [ ] Effects are non-destructive - [ ] Warped text reshapes when edited ### Watch out - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. ## Phase 4 · Output a printer will accept An export meets the requirements of an actual print process. ### Steps 1. Convert colour deliberately with warnings Silent conversion is how vivid artwork prints dull. Files: `src/colour.ts` 2. Include bleed and the profile Print requirements a screen export does not meet. Files: `src/export.ts` 3. Produce a preflight report Fonts, colours, line widths, resolutions. What a printer would check. Files: `src/preflight.ts` ### Done when - [ ] Exports include bleed and a colour profile - [ ] Unprintable colours are warned about - [ ] A preflight report lists what the file contains - [ ] A printer accepts the file without querying ### Watch out - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. ## Not in this build - A licensed font library. - Raster image editing. - Print fulfilment and mockups. - Legal advice about a specific licence. ## After v1, if you want it - Variable font axes, which display faces increasingly ship with - Colour separation preview, which is what catches print surprises before the proof - A template system, since most merchandise work is variations on a layout ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Fonts with their licence records. A font without one cannot be used. FONT_DIR=./fonts # Required. Per-font permissions, read before every export. LICENCE_DB=./config/licences.json # Required. The print profile. Screen export is the exception here, not the default. DEFAULT_COLOUR_PROFILE=FOGRA39 # Required. From your printer's specification rather than a guess. DEFAULT_BLEED_MM=3 # Required. Present as a constant so the answer is visible. A stored use is answered optimistically once. ASK_USE_AT_EXPORT=always # Required. Below this a line disappears in print. Flagged in preflight. MIN_LINE_WIDTH_MM=0.25
You are building a lean indie version of Kittl. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Kittl · indie build A vector design tool for typographic work, where the engineering is text on curved paths and true print output, and the constraint is that every font carries a licence the export path enforces. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Canvas | A vector scene graph with text as live editable objects | text that has been converted to curves cannot be corrected later | | Typography | Text on paths, with real font shaping | shaping is what makes typography look right and cannot be approximated | | Effects | Warp, offset and shadow computed on outlines | raster effects do not survive print resolution | | Export | Vector formats with correct colour and bleed for print | merchandise printing has requirements a screen export does not meet | | Licensing | Per-font permissions checked at export against a declared use | the restriction is on the use, and the use is only known at export | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the editor and the export pipeline. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A real text shaping engine** · free - Why: Kerning, ligatures and alternates are the whole point of a typographic tool and cannot be approximated by advancing a fixed width. - Get it: A maintained shaping library with bindings for your runtime. - Verify: A kerning pair and a ligature render identically to a reference - [ ] **A robust 2D geometry library** · free - Why: Offsetting glyph outlines produces self-intersections routinely, and resolving them by hand is a research project. - Get it: A library with reliable boolean operations and offsetting on paths. - Verify: Offsetting a complex glyph produces clean geometry - [ ] **Fonts whose licences you have read** · free for open fonts; commercial licences vary widely - Why: The build enforces per-font permissions, and you cannot record permissions you have not read. Assume nothing about merchandise use. - Get it: Take three or four typefaces you would actually use and read each licence, noting desktop, webfont, merchandise and embedding permissions separately. - Verify: A written record exists per font with four separate permissions - [ ] **A print target and its specification** · free to obtain - Why: Bleed, colour profile and minimum line width come from the actual printer, and an export built to a guess gets rejected or prints badly. - Get it: Pick a print or merchandise service and download its artwork specification. - Verify: The specification is saved and its requirements are encoded in the export settings ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - A licensed font library. - Raster image editing. - Print fulfilment and mockups. - Legal advice about a specific licence. - specialized templates, fonts, vector effects, asset library, and mockups - huge template and asset libraries - real-time multiplayer - brand governance - professional print workflows If one of those is essential to you, that is the reason to keep paying for Kittl, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Kittl The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me typography-heavy graphics with print-ready export and licences you can account for to replace Kittl. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero The output of this tool goes on merchandise that gets sold, and the fonts in it are licensed software rather than files you own. Font licences are tiered and the tiers matter: a desktop licence typically covers making artwork, a webfont licence covers serving it on a page, and putting a typeface on products for sale usually needs a separate commercial or extended licence, sometimes with a unit limit. Embedding a font in an exported vector file is itself a distribution the licence may or may not permit. So every font in this build carries a licence record with those permissions as separate fields, and export is blocked where the licence does not cover the intended use, naming the restriction. The intended use is asked for at export rather than assumed. This is not pedantry. Foundries do enforce, the person who gets the letter is the seller rather than the tool, and by the time it arrives the products are already out there. ### Stack (fixed, do not substitute) - Canvas: A vector scene graph with text as live editable objects · text that has been converted to curves cannot be corrected later - Typography: Text on paths, with real font shaping · shaping is what makes typography look right and cannot be approximated - Effects: Warp, offset and shadow computed on outlines · raster effects do not survive print resolution - Export: Vector formats with correct colour and bleed for print · merchandise printing has requirements a screen export does not meet - Licensing: Per-font permissions checked at export against a declared use · the restriction is on the use, and the use is only known at export ### Data model (create this before Phase 1) - documents(id, name, width_mm, height_mm, bleed_mm, colour_profile, created_at) - layers(id, document_id, ordinal, kind, transform_json, style_json) - text_objects(layer_id, content, font_id, size_pt, tracking, path_id, shaping_features_json) - fonts(id, family, style, file_path, licence_id, embedding_allowed) - licences(id, name, allows_desktop, allows_webfont, allows_merchandise, allows_embedding, unit_limit, source_url) - exports(id, document_id, format, declared_use, blocked_reason, fonts_used_json, at) - An export records which fonts it used and the use declared, so a licence question months later has an answer. ### Phase 1 · Text that is really text Build: A vector canvas with text objects using real font shaping, including ligatures, kerning and alternate glyphs. Keep text editable rather than converting to curves. Handle a font missing from the machine. Trap: Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. Done when: Kerning pairs and ligatures render correctly, compared against a reference rendering. Alternate glyphs and stylistic sets can be applied. Text remains editable rather than being converted to curves. A missing font is reported clearly rather than substituted silently. Do not build yet: No paths, effects or export. ### Phase 2 · Text on a curve, correctly Build: Place text along an arbitrary path, distributing glyphs by arc length rather than by parameter, with rotation per glyph. Handle tight curves where glyphs would overlap, and text longer than its path. Trap: Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. Done when: Text on a circular path is evenly spaced all the way round, verified by measurement rather than by eye. A tight curve either adjusts spacing or reports that glyphs would overlap. Text longer than its path is handled by a stated rule rather than running off. Each glyph's rotation follows the tangent. Do not build yet: No effects or export yet. ### Phase 3 · Effects that survive print resolution Build: Implement warp, offset outline and layered shadow as operations on the glyph outlines themselves. Handle self-intersecting outlines from an offset. Keep effects non-destructive so the underlying text stays editable. Trap: Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. Done when: An offset outline is real geometry that scales to any resolution, verified by exporting at print size. Self-intersections from an offset are resolved rather than producing artefacts. Effects are non-destructive and the text underneath remains editable. A warped text object still shapes correctly when its content is changed. Do not build yet: No export or licensing yet. ### Phase 4 · Output a printer will accept Build: Export vector formats with bleed, a stated colour profile, and outlines or embedded fonts as the target requires. Warn where a colour is outside the printable range. Include a preflight report of what the file contains. Trap: Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. Done when: An export includes bleed and carries the correct colour profile. Colours outside the printable range are warned about before export rather than converted silently. The preflight report lists fonts, colours, minimum line widths and image resolutions. A printer accepts the file without querying it. Do not build yet: No licence enforcement yet. ### Phase 5 · Licences enforced where it matters Build: Record per-font permissions for desktop, webfont, merchandise and embedding, with any unit limit. Ask for the intended use at export and block where the licence does not cover it, naming the restriction. Record every export's fonts and declared use. Trap: Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file. Done when: Exporting for merchandise with a font lacking that permission is blocked, naming the restriction, tested directly. The intended use is asked at export rather than read from a setting. Embedding permission is checked separately from merchandise permission. Every export records its fonts and declared use, exportable as a document. Do not build yet: Nothing after this. ### Out of scope (and why) - A font library, which is what the hosted products actually license on your behalf and is most of what you pay them for. - Raster image editing, which is a different tool and a different set of problems. - Print fulfilment and product mockups, which is the commerce half of this category. - Legal advice about a specific font licence, which varies by foundry and needs reading rather than assuming. ### README must contain - That font licences are tiered and merchandise use usually needs a separate permission - That the intended use is asked at export rather than stored as a setting - That embedding a font in an exported file is a distribution the licence may not permit - That text is placed by arc length on a path, not by parameter - That outline effects are real geometry because raster strokes print blurred ===== AGENTS.md ===== # Agent instructions · Kittl indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: A vector scene graph with text as live editable objects, Text on paths, with real font shaping, Warp, offset and shadow computed on outlines, Vector formats with correct colour and bleed for print, Per-font permissions checked at export against a declared use. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. ===== BUILD_PLAN.md ===== # Build plan · Kittl A vector design tool for typographic work, where the engineering is text on curved paths and true print output, and the constraint is that every font carries a licence the export path enforces. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Text that is really text Typography is shaped correctly and stays editable. ### Steps 1. Use a real shaping engine Kerning and ligatures are the difference between typography and text. Files: `src/shape.ts` 2. Expose the font's own features Alternates and stylistic sets are why display faces are bought. Files: `src/features.ts` 3. Never substitute silently A missing font changing the design without saying so is the worst outcome. Files: `src/fonts.ts` ### Done when - [ ] Kerning and ligatures match a reference - [ ] Alternates and stylistic sets apply - [ ] Text stays editable - [ ] A missing font is reported, not substituted ### Watch out - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. ## Phase 2 · Text on a curve, correctly Type follows an arc without distorting or bunching. ### Steps 1. Place by arc length Not by parameter. Parameter placement bunches on tight curves. Files: `src/textpath.ts`, `src/textpath.test.ts` 2. Rotate each glyph to the tangent Otherwise the letters stay upright on a curve, which looks broken. Files: `src/textpath.ts` 3. Handle overflow and tight curves explicitly A stated rule beats text running off the end. Files: `src/textpath.ts` ### Done when - [ ] Circular text is evenly spaced by measurement - [ ] Tight curves adjust or report overlap - [ ] Overflow follows a stated rule - [ ] Glyph rotation follows the tangent ### Watch out - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. ## Phase 3 · Effects that survive print resolution Warps and outlines are vector operations, not filters. ### Steps 1. Offset the outline geometry A raster stroke prints blurred at merchandise resolutions. Files: `src/offset.ts` 2. Resolve self-intersections Offsetting a complex glyph produces them reliably. Files: `src/geometry.ts`, `tests/offset.test.ts` 3. Keep effects non-destructive Editing the words afterwards is the normal case. Files: `src/effects.ts` ### Done when - [ ] An offset outline scales to print resolution - [ ] Self-intersections are resolved - [ ] Effects are non-destructive - [ ] Warped text reshapes when edited ### Watch out - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. ## Phase 4 · Output a printer will accept An export meets the requirements of an actual print process. ### Steps 1. Convert colour deliberately with warnings Silent conversion is how vivid artwork prints dull. Files: `src/colour.ts` 2. Include bleed and the profile Print requirements a screen export does not meet. Files: `src/export.ts` 3. Produce a preflight report Fonts, colours, line widths, resolutions. What a printer would check. Files: `src/preflight.ts` ### Done when - [ ] Exports include bleed and a colour profile - [ ] Unprintable colours are warned about - [ ] A preflight report lists what the file contains - [ ] A printer accepts the file without querying ### Watch out - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. ## Not in this build - A licensed font library. - Raster image editing. - Print fulfilment and mockups. - Legal advice about a specific licence. ## After v1, if you want it - Variable font axes, which display faces increasingly ship with - Colour separation preview, which is what catches print surprises before the proof - A template system, since most merchandise work is variations on a layout ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Fonts with their licence records. A font without one cannot be used. FONT_DIR=./fonts # Required. Per-font permissions, read before every export. LICENCE_DB=./config/licences.json # Required. The print profile. Screen export is the exception here, not the default. DEFAULT_COLOUR_PROFILE=FOGRA39 # Required. From your printer's specification rather than a guess. DEFAULT_BLEED_MM=3 # Required. Present as a constant so the answer is visible. A stored use is answered optimistically once. ASK_USE_AT_EXPORT=always # Required. Below this a line disappears in print. Flagged in preflight. MIN_LINE_WIDTH_MM=0.25
You are building a production product version of Kittl. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== PRODUCT.md ===== # Kittl · product brief ## Problem The core loop is buildable, but a dependable replacement becomes a real weekend or multi-day project. For Kittl, create typography-heavy graphics, labels, posters, and merchandise-ready exports. The hard boundary is specialized templates, fonts, vector effects, asset library, and mockups, plus editor polish, assets, collaboration, and distribution. ## Product outcome A typographic tool whose curved text is evenly spaced, whose effects survive print resolution, and which will not let you export artwork for a use its fonts do not license. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - modern desktop browser - local fonts and images - optional image-generation API key ## Explicit non-goals for v1 - A licensed font library. - Raster image editing. - Print fulfilment and mockups. - Legal advice about a specific licence. - specialized templates, fonts, vector effects, asset library, and mockups - huge template and asset libraries - real-time multiplayer - brand governance - professional print workflows ## Success criteria - Kerning and ligatures are confirmed to match a reference - Circular text is confirmed evenly spaced by measurement - An offset outline is confirmed to scale to print resolution - Unprintable colours are confirmed warned about - An unpermitted merchandise export is confirmed blocked with a reason ===== BRIEF.md ===== # Build brief · Kittl The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me typography-heavy graphics with print-ready export and licences you can account for to replace Kittl. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero The output of this tool goes on merchandise that gets sold, and the fonts in it are licensed software rather than files you own. Font licences are tiered and the tiers matter: a desktop licence typically covers making artwork, a webfont licence covers serving it on a page, and putting a typeface on products for sale usually needs a separate commercial or extended licence, sometimes with a unit limit. Embedding a font in an exported vector file is itself a distribution the licence may or may not permit. So every font in this build carries a licence record with those permissions as separate fields, and export is blocked where the licence does not cover the intended use, naming the restriction. The intended use is asked for at export rather than assumed. This is not pedantry. Foundries do enforce, the person who gets the letter is the seller rather than the tool, and by the time it arrives the products are already out there. ### Stack (fixed, do not substitute) - Canvas: A vector scene graph with text as live editable objects · text that has been converted to curves cannot be corrected later - Typography: Text on paths, with real font shaping · shaping is what makes typography look right and cannot be approximated - Effects: Warp, offset and shadow computed on outlines · raster effects do not survive print resolution - Export: Vector formats with correct colour and bleed for print · merchandise printing has requirements a screen export does not meet - Licensing: Per-font permissions checked at export against a declared use · the restriction is on the use, and the use is only known at export ### Data model (create this before Phase 1) - documents(id, name, width_mm, height_mm, bleed_mm, colour_profile, created_at) - layers(id, document_id, ordinal, kind, transform_json, style_json) - text_objects(layer_id, content, font_id, size_pt, tracking, path_id, shaping_features_json) - fonts(id, family, style, file_path, licence_id, embedding_allowed) - licences(id, name, allows_desktop, allows_webfont, allows_merchandise, allows_embedding, unit_limit, source_url) - exports(id, document_id, format, declared_use, blocked_reason, fonts_used_json, at) - An export records which fonts it used and the use declared, so a licence question months later has an answer. ### Phase 1 · Text that is really text Build: A vector canvas with text objects using real font shaping, including ligatures, kerning and alternate glyphs. Keep text editable rather than converting to curves. Handle a font missing from the machine. Trap: Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. Done when: Kerning pairs and ligatures render correctly, compared against a reference rendering. Alternate glyphs and stylistic sets can be applied. Text remains editable rather than being converted to curves. A missing font is reported clearly rather than substituted silently. Do not build yet: No paths, effects or export. ### Phase 2 · Text on a curve, correctly Build: Place text along an arbitrary path, distributing glyphs by arc length rather than by parameter, with rotation per glyph. Handle tight curves where glyphs would overlap, and text longer than its path. Trap: Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. Done when: Text on a circular path is evenly spaced all the way round, verified by measurement rather than by eye. A tight curve either adjusts spacing or reports that glyphs would overlap. Text longer than its path is handled by a stated rule rather than running off. Each glyph's rotation follows the tangent. Do not build yet: No effects or export yet. ### Phase 3 · Effects that survive print resolution Build: Implement warp, offset outline and layered shadow as operations on the glyph outlines themselves. Handle self-intersecting outlines from an offset. Keep effects non-destructive so the underlying text stays editable. Trap: Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. Done when: An offset outline is real geometry that scales to any resolution, verified by exporting at print size. Self-intersections from an offset are resolved rather than producing artefacts. Effects are non-destructive and the text underneath remains editable. A warped text object still shapes correctly when its content is changed. Do not build yet: No export or licensing yet. ### Phase 4 · Output a printer will accept Build: Export vector formats with bleed, a stated colour profile, and outlines or embedded fonts as the target requires. Warn where a colour is outside the printable range. Include a preflight report of what the file contains. Trap: Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. Done when: An export includes bleed and carries the correct colour profile. Colours outside the printable range are warned about before export rather than converted silently. The preflight report lists fonts, colours, minimum line widths and image resolutions. A printer accepts the file without querying it. Do not build yet: No licence enforcement yet. ### Phase 5 · Licences enforced where it matters Build: Record per-font permissions for desktop, webfont, merchandise and embedding, with any unit limit. Ask for the intended use at export and block where the licence does not cover it, naming the restriction. Record every export's fonts and declared use. Trap: Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file. Done when: Exporting for merchandise with a font lacking that permission is blocked, naming the restriction, tested directly. The intended use is asked at export rather than read from a setting. Embedding permission is checked separately from merchandise permission. Every export records its fonts and declared use, exportable as a document. Do not build yet: Nothing after this. ### Out of scope (and why) - A font library, which is what the hosted products actually license on your behalf and is most of what you pay them for. - Raster image editing, which is a different tool and a different set of problems. - Print fulfilment and product mockups, which is the commerce half of this category. - Legal advice about a specific font licence, which varies by foundry and needs reading rather than assuming. ### README must contain - That font licences are tiered and merchandise use usually needs a separate permission - That the intended use is asked at export rather than stored as a setting - That embedding a font in an exported file is a distribution the licence may not permit - That text is placed by arc length on a path, not by parameter - That outline effects are real geometry because raster strokes print blurred ===== ARCHITECTURE.md ===== # Architecture · Kittl ## Stack | Part | Choice | Why | | --- | --- | --- | | Canvas | A vector scene graph with text as live editable objects | text that has been converted to curves cannot be corrected later | | Typography | Text on paths, with real font shaping | shaping is what makes typography look right and cannot be approximated | | Effects | Warp, offset and shadow computed on outlines | raster effects do not survive print resolution | | Export | Vector formats with correct colour and bleed for print | merchandise printing has requirements a screen export does not meet | | Licensing | Per-font permissions checked at export against a declared use | the restriction is on the use, and the use is only known at export | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Shaping | Real font shaping and features. | Any engine, provided it is a real shaper rather than fixed advance positioning. | | Text on path | Arc-length placement and tangent rotation. | Any implementation, provided placement is by distance rather than parameter. | | Effects | Outline geometry operations. | Any geometry library, provided effects are vector rather than raster. | | Export | Print colour, bleed and preflight. | Any target, provided colour conversion is deliberate and warned about. | | Licensing | Per-font permissions enforced at export. | Not swappable for a note in the documentation. It is enforced where files are produced. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `FONT_DIR` · required · Fonts with their licence records. A font without one cannot be used. - `LICENCE_DB` · required · Per-font permissions, read before every export. - `DEFAULT_COLOUR_PROFILE` · required · The print profile. Screen export is the exception here, not the default. - `DEFAULT_BLEED_MM` · required · From your printer's specification rather than a guess. - `ASK_USE_AT_EXPORT` · required · Present as a constant so the answer is visible. A stored use is answered optimistically once. - `MIN_LINE_WIDTH_MM` · required · Below this a line disappears in print. Flagged in preflight. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it. ===== AGENTS.md ===== # Agent instructions · Kittl product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: A vector scene graph with text as live editable objects, Text on paths, with real font shaping, Warp, offset and shadow computed on outlines, Vector formats with correct colour and bleed for print, Per-font permissions checked at export against a declared use. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. - Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file. ===== MILESTONES.md ===== # Delivery milestones · Kittl Estimated effort: **multi-day** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · Text that is really text Typography is shaped correctly and stays editable. ### Steps 1. Use a real shaping engine Kerning and ligatures are the difference between typography and text. Files: `src/shape.ts` 2. Expose the font's own features Alternates and stylistic sets are why display faces are bought. Files: `src/features.ts` 3. Never substitute silently A missing font changing the design without saying so is the worst outcome. Files: `src/fonts.ts` ### Done when - [ ] Kerning and ligatures match a reference - [ ] Alternates and stylistic sets apply - [ ] Text stays editable - [ ] A missing font is reported, not substituted ### Watch out - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. ## M2 · Text on a curve, correctly Type follows an arc without distorting or bunching. ### Steps 1. Place by arc length Not by parameter. Parameter placement bunches on tight curves. Files: `src/textpath.ts`, `src/textpath.test.ts` 2. Rotate each glyph to the tangent Otherwise the letters stay upright on a curve, which looks broken. Files: `src/textpath.ts` 3. Handle overflow and tight curves explicitly A stated rule beats text running off the end. Files: `src/textpath.ts` ### Done when - [ ] Circular text is evenly spaced by measurement - [ ] Tight curves adjust or report overlap - [ ] Overflow follows a stated rule - [ ] Glyph rotation follows the tangent ### Watch out - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. ## M3 · Effects that survive print resolution Warps and outlines are vector operations, not filters. ### Steps 1. Offset the outline geometry A raster stroke prints blurred at merchandise resolutions. Files: `src/offset.ts` 2. Resolve self-intersections Offsetting a complex glyph produces them reliably. Files: `src/geometry.ts`, `tests/offset.test.ts` 3. Keep effects non-destructive Editing the words afterwards is the normal case. Files: `src/effects.ts` ### Done when - [ ] An offset outline scales to print resolution - [ ] Self-intersections are resolved - [ ] Effects are non-destructive - [ ] Warped text reshapes when edited ### Watch out - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. ## M4 · Output a printer will accept An export meets the requirements of an actual print process. ### Steps 1. Convert colour deliberately with warnings Silent conversion is how vivid artwork prints dull. Files: `src/colour.ts` 2. Include bleed and the profile Print requirements a screen export does not meet. Files: `src/export.ts` 3. Produce a preflight report Fonts, colours, line widths, resolutions. What a printer would check. Files: `src/preflight.ts` ### Done when - [ ] Exports include bleed and a colour profile - [ ] Unprintable colours are warned about - [ ] A preflight report lists what the file contains - [ ] A printer accepts the file without querying ### Watch out - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. ## M5 · Licences enforced where it matters (production only) You cannot export artwork for a use its fonts do not permit. ### Steps 1. Model permissions as separate fields Desktop, webfont, merchandise, embedding. Four questions, four answers. Files: `src/licences.ts` 2. Ask for the use at export Not in settings. A setting is answered once, optimistically. Files: `src/export.ts` 3. Block and name the restriction A silent failure teaches nothing and looks like a bug. Files: `src/export.ts`, `tests/licence.test.ts` ### Done when - [ ] An unpermitted merchandise export is blocked with a reason - [ ] The intended use is asked at export - [ ] Embedding is checked separately from merchandise - [ ] Exports record fonts and declared use ### Watch out - Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file. ===== OPERATIONS.md ===== # Operations · Kittl ## Backup Documents and the licence database are the irreplaceable parts. Fonts you licensed are replaceable but their licence records may not be, so keep the recorded permissions with their source references. ## Restore Restore and confirm licence records survived, since a document whose font permissions are lost should be treated as unexportable rather than assumed fine. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring For a design tool the check that matters lives in the suite: no export path can produce a file without consulting the licence record, which is an invariant worth asserting rather than watching. ## Incident checklist Artwork sold on merchandise using a font that did not permit it is the failure this build exists to prevent, and the export record is what tells you which files are affected and which font caused it. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Kerning and ligatures are confirmed to match a reference - [ ] Circular text is confirmed evenly spaced by measurement - [ ] An offset outline is confirmed to scale to print resolution - [ ] Unprintable colours are confirmed warned about - [ ] An unpermitted merchandise export is confirmed blocked with a reason ## Launch constraint Do not market omitted Kittl capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered. ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Fonts with their licence records. A font without one cannot be used. FONT_DIR=./fonts # Required. Per-font permissions, read before every export. LICENCE_DB=./config/licences.json # Required. The print profile. Screen export is the exception here, not the default. DEFAULT_COLOUR_PROFILE=FOGRA39 # Required. From your printer's specification rather than a guess. DEFAULT_BLEED_MM=3 # Required. Present as a constant so the answer is visible. A stored use is answered optimistically once. ASK_USE_AT_EXPORT=always # Required. Below this a line disappears in print. Flagged in preflight. MIN_LINE_WIDTH_MM=0.25
# Kittl · indie build A vector design tool for typographic work, where the engineering is text on curved paths and true print output, and the constraint is that every font carries a licence the export path enforces. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Canvas | A vector scene graph with text as live editable objects | text that has been converted to curves cannot be corrected later | | Typography | Text on paths, with real font shaping | shaping is what makes typography look right and cannot be approximated | | Effects | Warp, offset and shadow computed on outlines | raster effects do not survive print resolution | | Export | Vector formats with correct colour and bleed for print | merchandise printing has requirements a screen export does not meet | | Licensing | Per-font permissions checked at export against a declared use | the restriction is on the use, and the use is only known at export | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the editor and the export pipeline. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A real text shaping engine** · free - Why: Kerning, ligatures and alternates are the whole point of a typographic tool and cannot be approximated by advancing a fixed width. - Get it: A maintained shaping library with bindings for your runtime. - Verify: A kerning pair and a ligature render identically to a reference - [ ] **A robust 2D geometry library** · free - Why: Offsetting glyph outlines produces self-intersections routinely, and resolving them by hand is a research project. - Get it: A library with reliable boolean operations and offsetting on paths. - Verify: Offsetting a complex glyph produces clean geometry - [ ] **Fonts whose licences you have read** · free for open fonts; commercial licences vary widely - Why: The build enforces per-font permissions, and you cannot record permissions you have not read. Assume nothing about merchandise use. - Get it: Take three or four typefaces you would actually use and read each licence, noting desktop, webfont, merchandise and embedding permissions separately. - Verify: A written record exists per font with four separate permissions - [ ] **A print target and its specification** · free to obtain - Why: Bleed, colour profile and minimum line width come from the actual printer, and an export built to a guess gets rejected or prints badly. - Get it: Pick a print or merchandise service and download its artwork specification. - Verify: The specification is saved and its requirements are encoded in the export settings ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - A licensed font library. - Raster image editing. - Print fulfilment and mockups. - Legal advice about a specific licence. - specialized templates, fonts, vector effects, asset library, and mockups - huge template and asset libraries - real-time multiplayer - brand governance - professional print workflows If one of those is essential to you, that is the reason to keep paying for Kittl, and the README should say so rather than pretend.
# Build brief · Kittl The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me typography-heavy graphics with print-ready export and licences you can account for to replace Kittl. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero The output of this tool goes on merchandise that gets sold, and the fonts in it are licensed software rather than files you own. Font licences are tiered and the tiers matter: a desktop licence typically covers making artwork, a webfont licence covers serving it on a page, and putting a typeface on products for sale usually needs a separate commercial or extended licence, sometimes with a unit limit. Embedding a font in an exported vector file is itself a distribution the licence may or may not permit. So every font in this build carries a licence record with those permissions as separate fields, and export is blocked where the licence does not cover the intended use, naming the restriction. The intended use is asked for at export rather than assumed. This is not pedantry. Foundries do enforce, the person who gets the letter is the seller rather than the tool, and by the time it arrives the products are already out there. ### Stack (fixed, do not substitute) - Canvas: A vector scene graph with text as live editable objects · text that has been converted to curves cannot be corrected later - Typography: Text on paths, with real font shaping · shaping is what makes typography look right and cannot be approximated - Effects: Warp, offset and shadow computed on outlines · raster effects do not survive print resolution - Export: Vector formats with correct colour and bleed for print · merchandise printing has requirements a screen export does not meet - Licensing: Per-font permissions checked at export against a declared use · the restriction is on the use, and the use is only known at export ### Data model (create this before Phase 1) - documents(id, name, width_mm, height_mm, bleed_mm, colour_profile, created_at) - layers(id, document_id, ordinal, kind, transform_json, style_json) - text_objects(layer_id, content, font_id, size_pt, tracking, path_id, shaping_features_json) - fonts(id, family, style, file_path, licence_id, embedding_allowed) - licences(id, name, allows_desktop, allows_webfont, allows_merchandise, allows_embedding, unit_limit, source_url) - exports(id, document_id, format, declared_use, blocked_reason, fonts_used_json, at) - An export records which fonts it used and the use declared, so a licence question months later has an answer. ### Phase 1 · Text that is really text Build: A vector canvas with text objects using real font shaping, including ligatures, kerning and alternate glyphs. Keep text editable rather than converting to curves. Handle a font missing from the machine. Trap: Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. Done when: Kerning pairs and ligatures render correctly, compared against a reference rendering. Alternate glyphs and stylistic sets can be applied. Text remains editable rather than being converted to curves. A missing font is reported clearly rather than substituted silently. Do not build yet: No paths, effects or export. ### Phase 2 · Text on a curve, correctly Build: Place text along an arbitrary path, distributing glyphs by arc length rather than by parameter, with rotation per glyph. Handle tight curves where glyphs would overlap, and text longer than its path. Trap: Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. Done when: Text on a circular path is evenly spaced all the way round, verified by measurement rather than by eye. A tight curve either adjusts spacing or reports that glyphs would overlap. Text longer than its path is handled by a stated rule rather than running off. Each glyph's rotation follows the tangent. Do not build yet: No effects or export yet. ### Phase 3 · Effects that survive print resolution Build: Implement warp, offset outline and layered shadow as operations on the glyph outlines themselves. Handle self-intersecting outlines from an offset. Keep effects non-destructive so the underlying text stays editable. Trap: Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. Done when: An offset outline is real geometry that scales to any resolution, verified by exporting at print size. Self-intersections from an offset are resolved rather than producing artefacts. Effects are non-destructive and the text underneath remains editable. A warped text object still shapes correctly when its content is changed. Do not build yet: No export or licensing yet. ### Phase 4 · Output a printer will accept Build: Export vector formats with bleed, a stated colour profile, and outlines or embedded fonts as the target requires. Warn where a colour is outside the printable range. Include a preflight report of what the file contains. Trap: Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. Done when: An export includes bleed and carries the correct colour profile. Colours outside the printable range are warned about before export rather than converted silently. The preflight report lists fonts, colours, minimum line widths and image resolutions. A printer accepts the file without querying it. Do not build yet: No licence enforcement yet. ### Phase 5 · Licences enforced where it matters Build: Record per-font permissions for desktop, webfont, merchandise and embedding, with any unit limit. Ask for the intended use at export and block where the licence does not cover it, naming the restriction. Record every export's fonts and declared use. Trap: Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file. Done when: Exporting for merchandise with a font lacking that permission is blocked, naming the restriction, tested directly. The intended use is asked at export rather than read from a setting. Embedding permission is checked separately from merchandise permission. Every export records its fonts and declared use, exportable as a document. Do not build yet: Nothing after this. ### Out of scope (and why) - A font library, which is what the hosted products actually license on your behalf and is most of what you pay them for. - Raster image editing, which is a different tool and a different set of problems. - Print fulfilment and product mockups, which is the commerce half of this category. - Legal advice about a specific font licence, which varies by foundry and needs reading rather than assuming. ### README must contain - That font licences are tiered and merchandise use usually needs a separate permission - That the intended use is asked at export rather than stored as a setting - That embedding a font in an exported file is a distribution the licence may not permit - That text is placed by arc length on a path, not by parameter - That outline effects are real geometry because raster strokes print blurred
# Agent instructions · Kittl indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: A vector scene graph with text as live editable objects, Text on paths, with real font shaping, Warp, offset and shadow computed on outlines, Vector formats with correct colour and bleed for print, Per-font permissions checked at export against a declared use. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently.
# Build plan · Kittl A vector design tool for typographic work, where the engineering is text on curved paths and true print output, and the constraint is that every font carries a licence the export path enforces. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Text that is really text Typography is shaped correctly and stays editable. ### Steps 1. Use a real shaping engine Kerning and ligatures are the difference between typography and text. Files: `src/shape.ts` 2. Expose the font's own features Alternates and stylistic sets are why display faces are bought. Files: `src/features.ts` 3. Never substitute silently A missing font changing the design without saying so is the worst outcome. Files: `src/fonts.ts` ### Done when - [ ] Kerning and ligatures match a reference - [ ] Alternates and stylistic sets apply - [ ] Text stays editable - [ ] A missing font is reported, not substituted ### Watch out - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. ## Phase 2 · Text on a curve, correctly Type follows an arc without distorting or bunching. ### Steps 1. Place by arc length Not by parameter. Parameter placement bunches on tight curves. Files: `src/textpath.ts`, `src/textpath.test.ts` 2. Rotate each glyph to the tangent Otherwise the letters stay upright on a curve, which looks broken. Files: `src/textpath.ts` 3. Handle overflow and tight curves explicitly A stated rule beats text running off the end. Files: `src/textpath.ts` ### Done when - [ ] Circular text is evenly spaced by measurement - [ ] Tight curves adjust or report overlap - [ ] Overflow follows a stated rule - [ ] Glyph rotation follows the tangent ### Watch out - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. ## Phase 3 · Effects that survive print resolution Warps and outlines are vector operations, not filters. ### Steps 1. Offset the outline geometry A raster stroke prints blurred at merchandise resolutions. Files: `src/offset.ts` 2. Resolve self-intersections Offsetting a complex glyph produces them reliably. Files: `src/geometry.ts`, `tests/offset.test.ts` 3. Keep effects non-destructive Editing the words afterwards is the normal case. Files: `src/effects.ts` ### Done when - [ ] An offset outline scales to print resolution - [ ] Self-intersections are resolved - [ ] Effects are non-destructive - [ ] Warped text reshapes when edited ### Watch out - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. ## Phase 4 · Output a printer will accept An export meets the requirements of an actual print process. ### Steps 1. Convert colour deliberately with warnings Silent conversion is how vivid artwork prints dull. Files: `src/colour.ts` 2. Include bleed and the profile Print requirements a screen export does not meet. Files: `src/export.ts` 3. Produce a preflight report Fonts, colours, line widths, resolutions. What a printer would check. Files: `src/preflight.ts` ### Done when - [ ] Exports include bleed and a colour profile - [ ] Unprintable colours are warned about - [ ] A preflight report lists what the file contains - [ ] A printer accepts the file without querying ### Watch out - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. ## Not in this build - A licensed font library. - Raster image editing. - Print fulfilment and mockups. - Legal advice about a specific licence. ## After v1, if you want it - Variable font axes, which display faces increasingly ship with - Colour separation preview, which is what catches print surprises before the proof - A template system, since most merchandise work is variations on a layout
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Fonts with their licence records. A font without one cannot be used. FONT_DIR=./fonts # Required. Per-font permissions, read before every export. LICENCE_DB=./config/licences.json # Required. The print profile. Screen export is the exception here, not the default. DEFAULT_COLOUR_PROFILE=FOGRA39 # Required. From your printer's specification rather than a guess. DEFAULT_BLEED_MM=3 # Required. Present as a constant so the answer is visible. A stored use is answered optimistically once. ASK_USE_AT_EXPORT=always # Required. Below this a line disappears in print. Flagged in preflight. MIN_LINE_WIDTH_MM=0.25
# Kittl · product brief ## Problem The core loop is buildable, but a dependable replacement becomes a real weekend or multi-day project. For Kittl, create typography-heavy graphics, labels, posters, and merchandise-ready exports. The hard boundary is specialized templates, fonts, vector effects, asset library, and mockups, plus editor polish, assets, collaboration, and distribution. ## Product outcome A typographic tool whose curved text is evenly spaced, whose effects survive print resolution, and which will not let you export artwork for a use its fonts do not license. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - modern desktop browser - local fonts and images - optional image-generation API key ## Explicit non-goals for v1 - A licensed font library. - Raster image editing. - Print fulfilment and mockups. - Legal advice about a specific licence. - specialized templates, fonts, vector effects, asset library, and mockups - huge template and asset libraries - real-time multiplayer - brand governance - professional print workflows ## Success criteria - Kerning and ligatures are confirmed to match a reference - Circular text is confirmed evenly spaced by measurement - An offset outline is confirmed to scale to print resolution - Unprintable colours are confirmed warned about - An unpermitted merchandise export is confirmed blocked with a reason
# Build brief · Kittl The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me typography-heavy graphics with print-ready export and licences you can account for to replace Kittl. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero The output of this tool goes on merchandise that gets sold, and the fonts in it are licensed software rather than files you own. Font licences are tiered and the tiers matter: a desktop licence typically covers making artwork, a webfont licence covers serving it on a page, and putting a typeface on products for sale usually needs a separate commercial or extended licence, sometimes with a unit limit. Embedding a font in an exported vector file is itself a distribution the licence may or may not permit. So every font in this build carries a licence record with those permissions as separate fields, and export is blocked where the licence does not cover the intended use, naming the restriction. The intended use is asked for at export rather than assumed. This is not pedantry. Foundries do enforce, the person who gets the letter is the seller rather than the tool, and by the time it arrives the products are already out there. ### Stack (fixed, do not substitute) - Canvas: A vector scene graph with text as live editable objects · text that has been converted to curves cannot be corrected later - Typography: Text on paths, with real font shaping · shaping is what makes typography look right and cannot be approximated - Effects: Warp, offset and shadow computed on outlines · raster effects do not survive print resolution - Export: Vector formats with correct colour and bleed for print · merchandise printing has requirements a screen export does not meet - Licensing: Per-font permissions checked at export against a declared use · the restriction is on the use, and the use is only known at export ### Data model (create this before Phase 1) - documents(id, name, width_mm, height_mm, bleed_mm, colour_profile, created_at) - layers(id, document_id, ordinal, kind, transform_json, style_json) - text_objects(layer_id, content, font_id, size_pt, tracking, path_id, shaping_features_json) - fonts(id, family, style, file_path, licence_id, embedding_allowed) - licences(id, name, allows_desktop, allows_webfont, allows_merchandise, allows_embedding, unit_limit, source_url) - exports(id, document_id, format, declared_use, blocked_reason, fonts_used_json, at) - An export records which fonts it used and the use declared, so a licence question months later has an answer. ### Phase 1 · Text that is really text Build: A vector canvas with text objects using real font shaping, including ligatures, kerning and alternate glyphs. Keep text editable rather than converting to curves. Handle a font missing from the machine. Trap: Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. Done when: Kerning pairs and ligatures render correctly, compared against a reference rendering. Alternate glyphs and stylistic sets can be applied. Text remains editable rather than being converted to curves. A missing font is reported clearly rather than substituted silently. Do not build yet: No paths, effects or export. ### Phase 2 · Text on a curve, correctly Build: Place text along an arbitrary path, distributing glyphs by arc length rather than by parameter, with rotation per glyph. Handle tight curves where glyphs would overlap, and text longer than its path. Trap: Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. Done when: Text on a circular path is evenly spaced all the way round, verified by measurement rather than by eye. A tight curve either adjusts spacing or reports that glyphs would overlap. Text longer than its path is handled by a stated rule rather than running off. Each glyph's rotation follows the tangent. Do not build yet: No effects or export yet. ### Phase 3 · Effects that survive print resolution Build: Implement warp, offset outline and layered shadow as operations on the glyph outlines themselves. Handle self-intersecting outlines from an offset. Keep effects non-destructive so the underlying text stays editable. Trap: Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. Done when: An offset outline is real geometry that scales to any resolution, verified by exporting at print size. Self-intersections from an offset are resolved rather than producing artefacts. Effects are non-destructive and the text underneath remains editable. A warped text object still shapes correctly when its content is changed. Do not build yet: No export or licensing yet. ### Phase 4 · Output a printer will accept Build: Export vector formats with bleed, a stated colour profile, and outlines or embedded fonts as the target requires. Warn where a colour is outside the printable range. Include a preflight report of what the file contains. Trap: Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. Done when: An export includes bleed and carries the correct colour profile. Colours outside the printable range are warned about before export rather than converted silently. The preflight report lists fonts, colours, minimum line widths and image resolutions. A printer accepts the file without querying it. Do not build yet: No licence enforcement yet. ### Phase 5 · Licences enforced where it matters Build: Record per-font permissions for desktop, webfont, merchandise and embedding, with any unit limit. Ask for the intended use at export and block where the licence does not cover it, naming the restriction. Record every export's fonts and declared use. Trap: Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file. Done when: Exporting for merchandise with a font lacking that permission is blocked, naming the restriction, tested directly. The intended use is asked at export rather than read from a setting. Embedding permission is checked separately from merchandise permission. Every export records its fonts and declared use, exportable as a document. Do not build yet: Nothing after this. ### Out of scope (and why) - A font library, which is what the hosted products actually license on your behalf and is most of what you pay them for. - Raster image editing, which is a different tool and a different set of problems. - Print fulfilment and product mockups, which is the commerce half of this category. - Legal advice about a specific font licence, which varies by foundry and needs reading rather than assuming. ### README must contain - That font licences are tiered and merchandise use usually needs a separate permission - That the intended use is asked at export rather than stored as a setting - That embedding a font in an exported file is a distribution the licence may not permit - That text is placed by arc length on a path, not by parameter - That outline effects are real geometry because raster strokes print blurred
# Architecture · Kittl ## Stack | Part | Choice | Why | | --- | --- | --- | | Canvas | A vector scene graph with text as live editable objects | text that has been converted to curves cannot be corrected later | | Typography | Text on paths, with real font shaping | shaping is what makes typography look right and cannot be approximated | | Effects | Warp, offset and shadow computed on outlines | raster effects do not survive print resolution | | Export | Vector formats with correct colour and bleed for print | merchandise printing has requirements a screen export does not meet | | Licensing | Per-font permissions checked at export against a declared use | the restriction is on the use, and the use is only known at export | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Shaping | Real font shaping and features. | Any engine, provided it is a real shaper rather than fixed advance positioning. | | Text on path | Arc-length placement and tangent rotation. | Any implementation, provided placement is by distance rather than parameter. | | Effects | Outline geometry operations. | Any geometry library, provided effects are vector rather than raster. | | Export | Print colour, bleed and preflight. | Any target, provided colour conversion is deliberate and warned about. | | Licensing | Per-font permissions enforced at export. | Not swappable for a note in the documentation. It is enforced where files are produced. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `FONT_DIR` · required · Fonts with their licence records. A font without one cannot be used. - `LICENCE_DB` · required · Per-font permissions, read before every export. - `DEFAULT_COLOUR_PROFILE` · required · The print profile. Screen export is the exception here, not the default. - `DEFAULT_BLEED_MM` · required · From your printer's specification rather than a guess. - `ASK_USE_AT_EXPORT` · required · Present as a constant so the answer is visible. A stored use is answered optimistically once. - `MIN_LINE_WIDTH_MM` · required · Below this a line disappears in print. Flagged in preflight. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it.
# Agent instructions · Kittl product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: A vector scene graph with text as live editable objects, Text on paths, with real font shaping, Warp, offset and shadow computed on outlines, Vector formats with correct colour and bleed for print, Per-font permissions checked at export against a declared use. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. - Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file.
# Delivery milestones · Kittl Estimated effort: **multi-day** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · Text that is really text Typography is shaped correctly and stays editable. ### Steps 1. Use a real shaping engine Kerning and ligatures are the difference between typography and text. Files: `src/shape.ts` 2. Expose the font's own features Alternates and stylistic sets are why display faces are bought. Files: `src/features.ts` 3. Never substitute silently A missing font changing the design without saying so is the worst outcome. Files: `src/fonts.ts` ### Done when - [ ] Kerning and ligatures match a reference - [ ] Alternates and stylistic sets apply - [ ] Text stays editable - [ ] A missing font is reported, not substituted ### Watch out - Positioning glyphs by advancing a fixed width per character ignores kerning and ligatures, which is precisely the difference between typography and text, and it is most visible in exactly the display faces this kind of design uses. Use a real shaping engine and pass through the font's own features. ## M2 · Text on a curve, correctly Type follows an arc without distorting or bunching. ### Steps 1. Place by arc length Not by parameter. Parameter placement bunches on tight curves. Files: `src/textpath.ts`, `src/textpath.test.ts` 2. Rotate each glyph to the tangent Otherwise the letters stay upright on a curve, which looks broken. Files: `src/textpath.ts` 3. Handle overflow and tight curves explicitly A stated rule beats text running off the end. Files: `src/textpath.ts` ### Done when - [ ] Circular text is evenly spaced by measurement - [ ] Tight curves adjust or report overlap - [ ] Overflow follows a stated rule - [ ] Glyph rotation follows the tangent ### Watch out - Distributing glyphs by the path's parameter rather than by arc length bunches them where the curve is tight and spreads them where it is flat, which on a circular badge is immediately visible and looks like a mistake. Compute arc length and place by distance along it. ## M3 · Effects that survive print resolution Warps and outlines are vector operations, not filters. ### Steps 1. Offset the outline geometry A raster stroke prints blurred at merchandise resolutions. Files: `src/offset.ts` 2. Resolve self-intersections Offsetting a complex glyph produces them reliably. Files: `src/geometry.ts`, `tests/offset.test.ts` 3. Keep effects non-destructive Editing the words afterwards is the normal case. Files: `src/effects.ts` ### Done when - [ ] An offset outline scales to print resolution - [ ] Self-intersections are resolved - [ ] Effects are non-destructive - [ ] Warped text reshapes when edited ### Watch out - Implementing an outline effect as a raster stroke looks correct on screen and prints as a blurred edge, because merchandise printing works at resolutions where any raster step in the chain becomes visible. Offset the actual outline geometry, and handle the self-intersections that produces rather than ignoring them. ## M4 · Output a printer will accept An export meets the requirements of an actual print process. ### Steps 1. Convert colour deliberately with warnings Silent conversion is how vivid artwork prints dull. Files: `src/colour.ts` 2. Include bleed and the profile Print requirements a screen export does not meet. Files: `src/export.ts` 3. Produce a preflight report Fonts, colours, line widths, resolutions. What a printer would check. Files: `src/preflight.ts` ### Done when - [ ] Exports include bleed and a colour profile - [ ] Unprintable colours are warned about - [ ] A preflight report lists what the file contains - [ ] A printer accepts the file without querying ### Watch out - Exporting in the screen colour space produces artwork whose vivid colours print noticeably duller, and the designer sees the difference only when the physical product arrives. Convert deliberately to the print profile, and warn about colours that cannot be reproduced rather than converting them silently. ## M5 · Licences enforced where it matters (production only) You cannot export artwork for a use its fonts do not permit. ### Steps 1. Model permissions as separate fields Desktop, webfont, merchandise, embedding. Four questions, four answers. Files: `src/licences.ts` 2. Ask for the use at export Not in settings. A setting is answered once, optimistically. Files: `src/export.ts` 3. Block and name the restriction A silent failure teaches nothing and looks like a bug. Files: `src/export.ts`, `tests/licence.test.ts` ### Done when - [ ] An unpermitted merchandise export is blocked with a reason - [ ] The intended use is asked at export - [ ] Embedding is checked separately from merchandise - [ ] Exports record fonts and declared use ### Watch out - Asking for the intended use once, in settings, means it is answered optimistically and never revisited, and every export afterwards inherits an assumption nobody re-examined. Ask at export, when the person knows what this particular file is for, and record the answer with the file.
# Operations · Kittl ## Backup Documents and the licence database are the irreplaceable parts. Fonts you licensed are replaceable but their licence records may not be, so keep the recorded permissions with their source references. ## Restore Restore and confirm licence records survived, since a document whose font permissions are lost should be treated as unexportable rather than assumed fine. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring For a design tool the check that matters lives in the suite: no export path can produce a file without consulting the licence record, which is an invariant worth asserting rather than watching. ## Incident checklist Artwork sold on merchandise using a font that did not permit it is the failure this build exists to prevent, and the export record is what tells you which files are affected and which font caused it. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Kerning and ligatures are confirmed to match a reference - [ ] Circular text is confirmed evenly spaced by measurement - [ ] An offset outline is confirmed to scale to print resolution - [ ] Unprintable colours are confirmed warned about - [ ] An unpermitted merchandise export is confirmed blocked with a reason ## Launch constraint Do not market omitted Kittl capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered.
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Fonts with their licence records. A font without one cannot be used. FONT_DIR=./fonts # Required. Per-font permissions, read before every export. LICENCE_DB=./config/licences.json # Required. The print profile. Screen export is the exception here, not the default. DEFAULT_COLOUR_PROFILE=FOGRA39 # Required. From your printer's specification rather than a guess. DEFAULT_BLEED_MM=3 # Required. Present as a constant so the answer is visible. A stored use is answered optimistically once. ASK_USE_AT_EXPORT=always # Required. Below this a line disappears in print. Flagged in preflight. MIN_LINE_WIDTH_MM=0.25
$ choose a build depth, inspect the files, then open the complete pack in your agent
People still pay for Kittl because people pay for a vast ready-made design system and a collaboration surface that behaves predictably under deadline. The recurring cost buys canvas correctness, fonts, exports, templates, asset rights, multiplayer state, and accessibility, not just the visible interface.
xspecialized templates, fonts, vector effects, asset library, and mockups
xhuge template and asset libraries
xreal-time multiplayer
xbrand governance
xprofessional print workflows
Don't feel like building it? These folks already made it free.
no votes, no pay-to-list · just what's real
Kittl pricing
| plan | monthly | annual (per mo) | what you get |
|---|---|---|---|
| free | $0/user | $0/user | 5 projects and 200 one-time AI tokens; personal use only. |
| pro | $19/user | $14/user | Unlimited projects; 2,000 AI tokens/month; 10 GB storage; commercial licence up to 500,000 copies. |
| expert | $45/user | $34/user | 6,000 AI tokens/month plus 200 daily tokens; 100 GB storage; commercial licence up to 500,000 copies. |
| max | custom | — | 600 daily AI tokens plus a monthly balance; public plan card price and exact monthly balance were not exposed. |
| business | custom | — | Enhanced commercial licence beyond 500,000 copies and team collaboration; public price is not listed. |
free tier5 projects and 200 one-time AI tokens; personal use only.
billingmonthly + annual
hidden costsMonthly AI tokens expire at the end of each cycle; daily tokens reset every 24 hours. Extra editors are charged, and commercial reproduction above 500,000 copies requires Business.
verified 2026-08-14 · source ↗
Vibecode Kittl
Kinda. The core of Kittl is buildable in a weekend with the prompt on this page, but there are real gaps: specialized templates, fonts, vector effects, asset library, and mockups, huge template and asset libraries. Read the honest list above before committing.
How much does Kittl cost?
Kittl costs about $19/month (Pro, checked 2026-08-14), which is $228 per year.
What do I lose by replacing Kittl?
Honestly: specialized templates, fonts, vector effects, asset library, and mockups; huge template and asset libraries; real-time multiplayer; brand governance; professional print workflows. If any of those are load-bearing for you, keep paying.
Is there an open-source alternative to Kittl?
Yes: Inkscape (Serious vector lettering, paths, labels, posters, and print-ready SVG/PDF export; stock mockups and one-click effects are your problem.) Affinity (A fully featured vector, raster, and layout suite now free forever; bring your own templates and taste.) The prompt is for when you want it exactly your way.