[{"data":1,"prerenderedAt":620},["ShallowReactive",2],{"navigation_docs":3,"-decisions-0022-the-logo-is-text":223,"-decisions-0022-the-logo-is-text-surround":615},[4,26,96,105,202],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":25},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20],{"title":11,"path":12,"stem":13,"icon":14},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F1.installation","i-lucide-download",{"title":16,"path":17,"stem":18,"icon":19},"The first app","\u002Fgetting-started\u002Ffirst-app","1.getting-started\u002F2.first-app","i-lucide-play",{"title":21,"path":22,"stem":23,"icon":24},"The first test","\u002Fgetting-started\u002Ffirst-test","1.getting-started\u002F3.first-test","i-lucide-flask-conical",false,{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":25},"Guide","i-lucide-book-open","\u002Fguide","2.guide",[32,37,42,47,52,57,62,67,72,77,81,86,91],{"title":33,"path":34,"stem":35,"icon":36},"Components","\u002Fguide\u002Fcomponents","2.guide\u002F01.components","i-lucide-component",{"title":38,"path":39,"stem":40,"icon":41},"Inputs and forms","\u002Fguide\u002Finputs-and-forms","2.guide\u002F02.inputs-and-forms","i-lucide-text-cursor-input",{"title":43,"path":44,"stem":45,"icon":46},"Scrolling and viewports","\u002Fguide\u002Fscrolling","2.guide\u002F03.scrolling","i-lucide-scroll-text",{"title":48,"path":49,"stem":50,"icon":51},"Overlays and layers","\u002Fguide\u002Foverlays","2.guide\u002F04.overlays","i-lucide-layers",{"title":53,"path":54,"stem":55,"icon":56},"Styles and theme","\u002Fguide\u002Fstyles","2.guide\u002F05.styles","i-lucide-palette",{"title":58,"path":59,"stem":60,"icon":61},"Composables","\u002Fguide\u002Fcomposables","2.guide\u002F06.composables","i-lucide-puzzle",{"title":63,"path":64,"stem":65,"icon":66},"Widgets","\u002Fguide\u002Fwidgets","2.guide\u002F07.widgets","i-lucide-blocks",{"title":68,"path":69,"stem":70,"icon":71},"The assistant","\u002Fguide\u002Fassistant","2.guide\u002F08.assistant","i-lucide-message-square",{"title":73,"path":74,"stem":75,"icon":76},"The same app on the web","\u002Fguide\u002Fweb","2.guide\u002F09.web","i-lucide-globe",{"title":78,"path":79,"stem":80,"icon":24},"Testing","\u002Fguide\u002Ftesting","2.guide\u002F10.testing",{"title":82,"path":83,"stem":84,"icon":85},"Running and packaging","\u002Fguide\u002Fpackaging","2.guide\u002F11.packaging","i-lucide-package",{"title":87,"path":88,"stem":89,"icon":90},"The terminal contract","\u002Fguide\u002Fterminal","2.guide\u002F12.terminal","i-lucide-square-terminal",{"title":92,"path":93,"stem":94,"icon":95},"Benchmarks","\u002Fguide\u002Fbenchmarks","2.guide\u002F13.benchmarks","i-lucide-gauge",{"title":97,"icon":98,"path":99,"stem":100,"children":101,"page":25},"AI and agents","i-lucide-bot","\u002Fai","3.ai",[102],{"title":97,"path":103,"stem":104,"icon":98},"\u002Fai\u002Fagents","3.ai\u002F1.agents",{"title":106,"icon":107,"path":108,"stem":109,"children":110},"Decisions","i-lucide-scale","\u002Fdecisions","4.decisions",[111,114,118,122,126,130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,194,198],{"title":112,"path":108,"stem":113,"icon":46},"All decisions","4.decisions\u002Findex",{"title":115,"path":116,"stem":117},"0001. kyo-ui is the DSL","\u002Fdecisions\u002F0001-kyo-ui-is-the-dsl","4.decisions\u002F0001-kyo-ui-is-the-dsl",{"title":119,"path":120,"stem":121},"0002. jatatui renders the cells","\u002Fdecisions\u002F0002-jatatui-renders-the-cells","4.decisions\u002F0002-jatatui-renders-the-cells",{"title":123,"path":124,"stem":125},"0003. Pin Kyo 1.0.0-RC7 and JDK 25","\u002Fdecisions\u002F0003-pin-kyo-rc7-and-jdk-25","4.decisions\u002F0003-pin-kyo-rc7-and-jdk-25",{"title":127,"path":128,"stem":129},"0004. Public Kyo APIs only","\u002Fdecisions\u002F0004-public-kyo-apis-only","4.decisions\u002F0004-public-kyo-apis-only",{"title":131,"path":132,"stem":133},"0005. A SOFT frame contract and an own watcher loop","\u002Fdecisions\u002F0005-soft-frame-contract-and-own-watcher-loop","4.decisions\u002F0005-soft-frame-contract-and-own-watcher-loop",{"title":135,"path":136,"stem":137},"0006. Purity: edge files, lint and a pure painter","\u002Fdecisions\u002F0006-purity-edge-files-and-lint","4.decisions\u002F0006-purity-edge-files-and-lint",{"title":139,"path":140,"stem":141},"0007. Compiler flags from sbt-tpolecat","\u002Fdecisions\u002F0007-compiler-flags-from-sbt-tpolecat","4.decisions\u002F0007-compiler-flags-from-sbt-tpolecat",{"title":143,"path":144,"stem":145},"0008. The artifact split: runner, app, testkit and core","\u002Fdecisions\u002F0008-artifact-split-runner-app-testkit-core","4.decisions\u002F0008-artifact-split-runner-app-testkit-core",{"title":147,"path":148,"stem":149},"0009. tui4s-use and tui4s-widgets, cross-built","\u002Fdecisions\u002F0009-use-and-widgets-cross-built","4.decisions\u002F0009-use-and-widgets-cross-built",{"title":151,"path":152,"stem":153},"0010. The flagship assistant is the blueprint of a real app","\u002Fdecisions\u002F0010-the-flagship-assistant-as-blueprint","4.decisions\u002F0010-the-flagship-assistant-as-blueprint",{"title":155,"path":156,"stem":157},"0011. The web target: a standalone Scala.js app and one theme","\u002Fdecisions\u002F0011-web-target-standalone-scalajs-and-one-theme","4.decisions\u002F0011-web-target-standalone-scalajs-and-one-theme",{"title":159,"path":160,"stem":161},"0012. The documentation is example-first","\u002Fdecisions\u002F0012-documentation-is-example-first","4.decisions\u002F0012-documentation-is-example-first",{"title":163,"path":164,"stem":165},"0013. Benchmarks in the repository, with their own build","\u002Fdecisions\u002F0013-benchmarks-in-repo-with-own-build","4.decisions\u002F0013-benchmarks-in-repo-with-own-build",{"title":167,"path":168,"stem":169},"0014. Release per module, by tag, as 0.1.0-RC1","\u002Fdecisions\u002F0014-release-per-module-tags-and-rc1","4.decisions\u002F0014-release-per-module-tags-and-rc1",{"title":171,"path":172,"stem":173},"0015. Packaging: the AOT cache in the start scripts, native-image as an option","\u002Fdecisions\u002F0015-packaging-aot-cache-and-native-image","4.decisions\u002F0015-packaging-aot-cache-and-native-image",{"title":175,"path":176,"stem":177},"0016. Process: lean mode and agent roles","\u002Fdecisions\u002F0016-process-lean-mode-and-agent-roles","4.decisions\u002F0016-process-lean-mode-and-agent-roles",{"title":179,"path":180,"stem":181},"0017. Deferred: templates, mouse, the kitty keyboard protocol and Windows","\u002Fdecisions\u002F0017-deferred-templates-mouse-and-kitty","4.decisions\u002F0017-deferred-templates-mouse-and-kitty",{"title":183,"path":184,"stem":185},"0018. pini4s is a vendored Git submodule","\u002Fdecisions\u002F0018-pini4s-as-a-vendored-submodule","4.decisions\u002F0018-pini4s-as-a-vendored-submodule",{"title":187,"path":188,"stem":189},"0019. Upstream issues are drafts that the user posts","\u002Fdecisions\u002F0019-upstream-kyo-issues-as-drafts","4.decisions\u002F0019-upstream-kyo-issues-as-drafts",{"title":191,"path":192,"stem":193},"0020. Release from the Actions form","\u002Fdecisions\u002F0020-release-from-the-actions-form","4.decisions\u002F0020-release-from-the-actions-form",{"title":195,"path":196,"stem":197},"0021. The rulebook is CONTRIBUTING.md","\u002Fdecisions\u002F0021-the-rulebook-is-contributing-md","4.decisions\u002F0021-the-rulebook-is-contributing-md",{"title":199,"path":200,"stem":201},"0022. The logo is text","\u002Fdecisions\u002F0022-the-logo-is-text","4.decisions\u002F0022-the-logo-is-text",{"title":203,"icon":204,"path":205,"stem":206,"children":207,"page":25},"Project","i-lucide-compass","\u002Fproject","5.project",[208,213,218],{"title":209,"path":210,"stem":211,"icon":212},"Roadmap","\u002Fproject\u002Froadmap","5.project\u002F1.roadmap","i-lucide-map",{"title":214,"path":215,"stem":216,"icon":217},"Contributing","\u002Fproject\u002Fcontributing","5.project\u002F2.contributing","i-lucide-git-pull-request",{"title":219,"path":220,"stem":221,"icon":222},"Security","\u002Fproject\u002Fsecurity","5.project\u002F3.security","i-lucide-shield",{"id":224,"title":199,"body":225,"description":608,"extension":609,"links":610,"meta":611,"navigation":612,"path":200,"seo":613,"stem":201,"__hash__":614},"docs\u002F4.decisions\u002F0022-the-logo-is-text.md",{"type":226,"value":227,"toc":597},"minimark",[228,233,237,241,244,248,277,281,503,507,533,537,569,573],[229,230,232],"h2",{"id":231},"status","Status",[234,235,236],"p",{},"Accepted.",[229,238,240],{"id":239},"date","Date",[234,242,243],{},"2026-10-20.",[229,245,247],{"id":246},"context","Context",[249,250,251,255,271,274],"ul",{},[252,253,254],"li",{},"tui4s had no logo. The header of the docs site showed the word \"tui4s\", and the favicon was the favicon of the Docus scaffold.",[252,256,257,258,262,263,266,267,270],{},"tui4s is a terminal runner. The maintainer drew the logotype as ASCII art in the style of figlet: \"tui4s\" in 11 lines of 73 characters. The art uses only the characters ",[259,260,261],"code",{},"\u002F",", ",[259,264,265],{},"\\"," and ",[259,268,269],{},"_",".",[252,272,273],{},"A browser tab, a phone home screen and a social preview need image files of fixed sizes. A favicon needs a square mark.",[252,275,276],{},"A logo file that a person draws by hand drifts from the text.",[229,278,280],{"id":279},"decision","Decision",[249,282,283,290,293,351,358,361,368,384,395,400,403,444,454,482,493],{},[252,284,285,286,289],{},"The logotype is ",[259,287,288],{},"assets\u002Flogo\u002Ftui4s.txt",", the text of the maintainer. No script edits it.",[252,291,292],{},"The isomark is the \"4\" of the logotype: the columns 39 to 56 of the text, counted from 0. In the logotype, the \"4\" has the accent colour.",[252,294,295,296,299,300,303,304,307,308,311,312,262,315,262,318,262,321,262,324,327,328,262,331,262,334,337,338,262,341,262,344,266,347,350],{},"One script, ",[259,297,298],{},"scripts\u002Flogo\u002Fbuild.mjs"," (Node.js), makes all the assets from the text. It writes ",[259,301,302],{},"assets\u002Flogo\u002Fisomark.txt"," and the logotype block of ",[259,305,306],{},"README.md",". In ",[259,309,310],{},"docs\u002Fpublic",", it writes ",[259,313,314],{},"logo.svg",[259,316,317],{},"logo-light.svg",[259,319,320],{},"logo-dark.svg",[259,322,323],{},"isomark.svg",[259,325,326],{},"favicon.ico"," (PNG entries of 16, 32 and 48 px), ",[259,329,330],{},"favicon-16x16.png",[259,332,333],{},"favicon-32x32.png",[259,335,336],{},"apple-touch-icon.png"," (180 px), ",[259,339,340],{},"icon-192.png",[259,342,343],{},"icon-512.png",[259,345,346],{},"site.webmanifest",[259,348,349],{},"og-image.png"," (1200 by 630 px). The outputs are in the repository, so the site and the README need no build step.",[252,352,353,354,357],{},"The script takes the outline route. Each character is the outline of its glyph in DejaVu Sans Mono 2.37. The glyphs sit on the grid of a terminal: the advance width of the font (1233 units) by its ascent plus its descent (2384 units). The SVG files hold only paths, so they need no font. ",[259,355,356],{},"scripts\u002Flogo\u002Fglyphs.py"," reads the outlines with fontTools. The generator keeps them as constants, so it needs no font file and no Python.",[252,359,360],{},"DejaVu Sans Mono has the Bitstream Vera licence, and the DejaVu changes are in the public domain. The licence lets anyone use, copy and change the font. The logo holds three glyph outlines, not a font.",[252,362,363,364,367],{},"Each path has a stroke of 0.8 CSS px that does not scale (",[259,365,366],{},"vector-effect=\"non-scaling-stroke\"","). The lines of the art are thin: with no stroke, they almost disappear when the logo is small. An icon gets a stroke in proportion to its size.",[252,369,370,371,373,374,376,377,379,380,383],{},"The light files have dark letters (",[259,372,317],{},", and ",[259,375,314],{}," is the same), and ",[259,378,320],{}," has light letters. An ",[259,381,382],{},"\u003Cimg>"," cannot take the colour of the page, so each scheme has its own file.",[252,385,386,387,389,390,266,392,394],{},"The icons show the isomark on the brand background. The favicons have round corners. ",[259,388,336],{}," has no transparent pixels. In ",[259,391,340],{},[259,393,343],{},", the mark is inside the safe circle of a maskable icon (a diameter of 80 percent).",[252,396,397,399],{},[259,398,349],{}," shows the logotype with light letters on the brand background, and the line \"A terminal runner for kyo-ui, in Scala 3\" under it. The line is text in the system font DejaVu Sans Mono.",[252,401,402],{},"Headless Chromium (Playwright) draws each PNG file at its exact size, with a device scale factor of 1. The script writes the ICO file itself.",[252,404,405,406],{},"The colours are in one block at the top of the generator:\n",[249,407,408,426,437],{},[252,409,410,411,414,415,418,419,262,422,425],{},"the accent, ",[259,412,413],{},"#eab308",": the default value of ",[259,416,417],{},"--tui4s-accent"," in tui4s-widgets (",[259,420,421],{},"Colors.defaults",[259,423,424],{},"Theme.terminal",");",[252,427,428,429,432,433,436],{},"the letters on a light page, ",[259,430,431],{},"#0f172a",", and on a dark page, ",[259,434,435],{},"#f8fafc",";",[252,438,439,440,443],{},"the brand background, ",[259,441,442],{},"#18181b",": the dark background of the docs site (Nuxt UI with the neutral colour zinc). It is also the theme colour of the site and of the manifest.",[252,445,446,449,450,453],{},[259,447,448],{},"node scripts\u002Flogo\u002Fbuild.mjs --check"," compares the text outputs (",[259,451,452],{},"isomark.txt",", the README block, the SVG files and the manifest) with what the script writes for the current text. For the PNG and ICO files, it compares only the pixel sizes. It starts no browser. The CI step \"Logo assets\" runs it.",[252,455,456,457,460,461,464,465,468,469,472,473,476,477,480,481],{},"The docs site shows the logotype in the header, 48 px high (",[259,458,459],{},"header.logo"," in ",[259,462,463],{},"docs\u002Fapp\u002Fapp.config.ts","). The links to the icons and to the manifest, the theme colour and the Twitter card type are in ",[259,466,467],{},"app.head"," of ",[259,470,471],{},"docs\u002Fnuxt.config.ts",". The home page sets ",[259,474,475],{},"\u002Fog-image.png"," as its preview image in its front matter, and nuxt-og-image makes it absolute with ",[259,478,479],{},"site.url",", the production domain, not the URL of one deployment. "," Each other page keeps the preview image that nuxt-og-image makes from its title.",[252,483,484,485,488,489,492],{},"The site serves the images as they are (",[259,486,487],{},"image.provider: 'none'","). The image optimizer of the site (IPX) gave the SVG logo the type ",[259,490,491],{},"text\u002Fplain",", so the browser did not show it. Its SVGO pass also removed the stroke that does not scale.",[252,494,495,496,460,499,270],{},"The social preview of the GitHub repository is a setting, not a file. A person uploads ",[259,497,498],{},"docs\u002Fpublic\u002Fog-image.png",[500,501,502],"strong",{},"Settings > General > Social preview",[229,504,506],{"id":505},"alternatives-considered","Alternatives considered",[249,508,509,515,521,527],{},[252,510,511,514],{},[500,512,513],{},"(a) A box-drawing wordmark that the agent draws."," Rejected by the maintainer: the figlet art is the brand.",[252,516,517,520],{},[500,518,519],{},"(b) SVG files that a person draws by hand."," Rejected: they drift from the text.",[252,522,523,526],{},[500,524,525],{},"(c) SVG text that uses the font of the viewer"," (the text route, the fallback of the plan). Rejected: fontTools was available, so the script takes the outline route. With the text route, the shape of each glyph depends on the font of the viewer.",[252,528,529,532],{},[500,530,531],{},"(d) No mark, only the word."," Rejected: a favicon and a social preview need a square mark.",[229,534,536],{"id":535},"consequences","Consequences",[249,538,539,545,548,551,554,557,564],{},[252,540,541,542,544],{},"Good: a change of the art is one edit of ",[259,543,288],{}," and one run of the generator.",[252,546,547],{},"Good: the SVG files look the same in all browsers, because they hold no text.",[252,549,550],{},"Good: CI finds an output that does not agree with the text.",[252,552,553],{},"Bad: the art has 11 rows of thin lines. In the 16 px favicon, the isomark is only the yellow shape of a 4.",[252,555,556],{},"Bad: the build of the PNG files needs Playwright and Chromium. The check needs only Node.js.",[252,558,559,560,563],{},"Bad: on another machine, the PNG files can change by some bytes (another Chromium, or another system font for the line of the preview image). The check compares their pixel sizes, and a stamp (",[259,561,562],{},"assets\u002Flogo\u002Fstamp.txt",", the hash of the text and of the generator, written after the last raster) that a change of the text or of the generator without a new run of the generator invalidates. ",[252,565,566,567,270],{},"Bad: the site uses no image optimizer. It has no other images, so nothing is lost now. A large image on a page later must be small before it goes in ",[259,568,310],{},[229,570,572],{"id":571},"references","References",[249,574,575,591],{},[252,576,577,262,579,262,581,262,583,262,585,262,587,590],{},[259,578,288],{},[259,580,298],{},[259,582,356],{},[259,584,463],{},[259,586,471],{},[259,588,589],{},"CONTRIBUTING.md"," (section \"Docs\").",[252,592,593,270],{},[594,595,596],"a",{"href":160},"ADR 0012",{"title":598,"searchDepth":599,"depth":599,"links":600},"",2,[601,602,603,604,605,606,607],{"id":231,"depth":599,"text":232},{"id":239,"depth":599,"text":240},{"id":246,"depth":599,"text":247},{"id":279,"depth":599,"text":280},{"id":505,"depth":599,"text":506},{"id":535,"depth":599,"text":536},{"id":571,"depth":599,"text":572},"The ASCII logotype of the maintainer is the logo of tui4s, and its 4 is the isomark. One script makes all the logo assets from the text file, and CI checks them.","md",null,{},true,{"title":199,"description":608},"h4RP7pV4uUrBM-224eMDlh3bZB6DfSSbqIXjakRiMrs",[616,618],{"title":195,"path":196,"stem":197,"description":617,"children":-1},"CONTRIBUTING.md is the rulebook for humans and for AI agents; ARCHITECTURE.md tells how the runner works; AGENTS.md is short, holds the rules for agents only, and imports the two other files.",{"title":209,"path":210,"stem":211,"description":619,"icon":212,"children":-1},"The planned and deferred features of tui4s, each with its GitHub issue.",1792528757850]