diff --git a/astro.config.mjs b/astro.config.mjs index a02cb24..97d9800 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -4,6 +4,10 @@ import starlight from "@astrojs/starlight"; import ecTwoSlash from "expressive-code-twoslash"; import topics from "starlight-sidebar-topics"; import starlightMarkdown from "starlight-markdown"; +import mermaid from "astro-mermaid"; +import { fileURLToPath } from "node:url"; + +const docsRoot = fileURLToPath(new URL(".", import.meta.url)); const site = "https://bomb.sh/docs/"; @@ -21,6 +25,7 @@ export default defineConfig({ } }, integrations: [ + mermaid({ autoTheme: true }), starlight({ title: "Bombshell", logo: { @@ -40,7 +45,18 @@ export default defineConfig({ cursorColor: 'rgba(255 0 210)' } }, - plugins: [ecTwoSlash()], + plugins: [ecTwoSlash({ + twoslashOptions: { + compilerOptions: { + module: 99, + moduleResolution: 100, + baseUrl: docsRoot, + paths: { + "@bomb.sh/tty": ["node_modules/@bomb.sh/tty/esm/mod.d.ts"], + }, + }, + }, + })], }, editLink: { baseUrl: "https://github.com/bombshell-dev/docs/edit/main/", @@ -124,6 +140,27 @@ export default defineConfig({ link: "/tab/", items: [], }, + { + label: "TTY", + id: "tty", + icon: "seti:config", + link: "/tty/basics/getting-started", + items: [ + { label: "Basics", autogenerate: { directory: "tty/basics" } }, + { label: "Guides", autogenerate: { directory: "tty/guides" } }, + { + label: "API", + items: [ + { label: "Overview", link: "/tty/api/" }, + { label: "Ops", link: "/tty/api/ops" }, + { label: "Term", link: "/tty/api/term" }, + { label: "Input", link: "/tty/api/input" }, + { label: "Settings", link: "/tty/api/settings" }, + { label: "Termcodes", link: "/tty/api/termcodes" }, + ], + }, + ], + }, ]), ], }), diff --git a/package.json b/package.json index 8a96b00..bdb034c 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dependencies": { "@astrojs/starlight": "^0.37.1", "@bomb.sh/args": "^0.3.1", + "@bomb.sh/tty": "^0.8.0", "@clack/core": "^1.4.3", "@clack/prompts": "^1.7.0", "@types/node": "^22.19.3", @@ -26,7 +27,9 @@ "@xterm/xterm": "^6.0.0", "arktype": "^2.2.0", "astro": "^5.16.6", + "astro-mermaid": "^2.1.0", "expressive-code-twoslash": "^0.5.3", + "mermaid": "^11.16.0", "sharp": "^0.33.5", "starlight-markdown": "^0.1.5", "starlight-sidebar-topics": "^0.6.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fdbb90e..2bc24ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@bomb.sh/args': specifier: ^0.3.1 version: 0.3.1 + '@bomb.sh/tty': + specifier: ^0.8.0 + version: 0.8.0 '@clack/core': specifier: ^1.4.3 version: 1.4.3 @@ -44,9 +47,15 @@ importers: astro: specifier: ^5.16.6 version: 5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2) + astro-mermaid: + specifier: ^2.1.0 + version: 2.1.0(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2))(mermaid@11.16.0) expressive-code-twoslash: specifier: ^0.5.3 version: 0.5.3(@expressive-code/core@0.41.5)(expressive-code@0.41.5)(typescript@5.8.2) + mermaid: + specifier: ^11.16.0 + version: 11.16.0 sharp: specifier: ^0.33.5 version: 0.33.5 @@ -75,6 +84,9 @@ importers: packages: + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + '@ark/schema@0.56.0': resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} @@ -136,10 +148,20 @@ packages: '@bomb.sh/args@0.3.1': resolution: {integrity: sha512-CwxKrfgcorUPP6KfYD59aRdBYWBTsfsxT+GmoLVnKo5Tmyoqbpo0UNcjngRMyU+6tiPbd18RuIYxhgAn44wU/Q==} + '@bomb.sh/tty@0.8.0': + resolution: {integrity: sha512-tEE0mtqnEp2uJt4kQS5AjdghCD5KN4BobqHOlfhaiNyrigxFBKk61XkDy//4D7V/AejrTvubh44B4NV35lsnxw==} + engines: {node: '>= 22'} + + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + '@capsizecss/unpack@3.0.1': resolution: {integrity: sha512-8XqW8xGn++Eqqbz3e9wKuK7mxryeRjs4LOHLxbh2lwKeSbuNR4NFifDZT4KzvjU6HMOPbiNTsWpniK5EJfTWkg==} engines: {node: '>=18'} + '@chevrotain/types@11.1.2': + resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} + '@clack/core@1.4.3': resolution: {integrity: sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==} engines: {node: '>= 20.12.0'} @@ -572,6 +594,12 @@ packages: '@expressive-code/plugin-text-markers@0.41.5': resolution: {integrity: sha512-0DSiTsjWFEz6/iuLOGNNy2GaeCW41OwnVJMKx1tS+XKeQxAL89UkZP3egWNzxjWNHNMzEv3ZWWWYqbonEQlv/Q==} + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.4': + resolution: {integrity: sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==} + '@img/colour@1.0.0': resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} @@ -855,6 +883,9 @@ packages: '@mdx-js/mdx@3.1.1': resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + '@mermaid-js/parser@1.2.0': + resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} + '@msgpack/msgpack@3.1.3': resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==} engines: {node: '>= 18'} @@ -1082,6 +1113,99 @@ packages: '@swc/helpers@0.5.18': resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.4': + resolution: {integrity: sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -1094,6 +1218,9 @@ packages: '@types/fontkit@2.0.8': resolution: {integrity: sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -1121,6 +1248,9 @@ packages: '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1136,6 +1266,9 @@ packages: resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} deprecated: Potential CWE-502 - Update to 1.3.1 or higher + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + '@webcontainer/api@1.6.1': resolution: {integrity: sha512-2RS2KiIw32BY1Icf6M1DvqSmcon9XICZCDgS29QJb2NmF12ZY2V5Ia+949hMKB3Wno+P/Y8W+sPP59PZeXSELg==} @@ -1209,6 +1342,16 @@ packages: peerDependencies: astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 + astro-mermaid@2.1.0: + resolution: {integrity: sha512-fFRUN0BTZh+DZhDiLyblXoO26XqJ1Rr+qK3JGgSu7OBspKHDm59jkztg/aHsrdo1vO/tIq/+xhP/vgT8Mp92XA==} + peerDependencies: + '@mermaid-js/layout-elk': ^0.2.0 + astro: '>=4' + mermaid: ^10.0.0 || ^11.0.0 + peerDependenciesMeta: + '@mermaid-js/layout-elk': + optional: true + astro@5.16.6: resolution: {integrity: sha512-6mF/YrvwwRxLTu+aMEa5pwzKUNl5ZetWbTyZCs9Um0F12HUmxUiF5UHiZPy4rifzU3gtpM3xP2DfdmkNX9eZRg==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} @@ -1313,6 +1456,14 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} @@ -1323,6 +1474,12 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + crossws@0.3.5: resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} @@ -1353,6 +1510,165 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.34.0: + resolution: {integrity: sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + + dayjs@1.11.21: + resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1368,6 +1684,9 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1413,6 +1732,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.4.11: + resolution: {integrity: sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -1440,6 +1762,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-toolkit@1.49.0: + resolution: {integrity: sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==} + esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -1546,6 +1871,9 @@ packages: h3@1.15.4: resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + hast-util-embedded@3.0.0: resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} @@ -1621,12 +1949,23 @@ packages: i18next@23.16.8: resolution: {integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + import-meta-resolve@4.2.0: resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} @@ -1671,6 +2010,13 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + katex@0.16.47: + resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -1683,6 +2029,15 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -1702,6 +2057,11 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + mdast-util-definitions@6.0.0: resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} @@ -1762,6 +2122,9 @@ packages: mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + mermaid@11.16.0: + resolution: {integrity: sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==} + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -1955,6 +2318,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} @@ -1979,6 +2345,12 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss-nested@6.2.0: resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} engines: {node: '>=12.0'} @@ -2092,11 +2464,23 @@ packages: retext@9.0.0: resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + rollup@4.55.1: resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.4.3: resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} @@ -2181,6 +2565,9 @@ packages: style-to-object@1.0.14: resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + stylis@4.4.0: + resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} + supports-color@10.2.2: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} @@ -2207,6 +2594,10 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-dedent@2.3.0: + resolution: {integrity: sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==} + engines: {node: '>=6.10'} + tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} engines: {node: ^18 || >=20} @@ -2368,6 +2759,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@14.0.1: + resolution: {integrity: sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==} + hasBin: true + vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -2538,6 +2933,11 @@ packages: snapshots: + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.0.2 + '@ark/schema@0.56.0': dependencies: '@ark/util': 0.56.0 @@ -2666,10 +3066,16 @@ snapshots: '@bomb.sh/args@0.3.1': {} + '@bomb.sh/tty@0.8.0': {} + + '@braintree/sanitize-url@7.1.2': {} + '@capsizecss/unpack@3.0.1': dependencies: fontkit: 2.0.4 + '@chevrotain/types@11.1.2': {} + '@clack/core@1.4.3': dependencies: fast-wrap-ansi: 0.2.0 @@ -2922,6 +3328,14 @@ snapshots: dependencies: '@expressive-code/core': 0.41.5 + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.4': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + import-meta-resolve: 4.2.0 + '@img/colour@1.0.0': {} '@img/sharp-darwin-arm64@0.33.5': @@ -3132,6 +3546,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@mermaid-js/parser@1.2.0': + dependencies: + '@chevrotain/types': 11.1.2 + '@msgpack/msgpack@3.1.3': {} '@oslojs/encoding@1.1.0': {} @@ -3292,6 +3710,123 @@ snapshots: dependencies: tslib: 2.8.1 + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.4': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -3306,6 +3841,8 @@ snapshots: dependencies: '@types/node': 22.19.3 + '@types/geojson@7946.0.16': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -3334,6 +3871,9 @@ snapshots: dependencies: '@types/node': 22.19.3 + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -3347,6 +3887,11 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + '@webcontainer/api@1.6.1': {} '@webcontainer/snapshot@0.1.0': @@ -3405,6 +3950,14 @@ snapshots: astro: 5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2) rehype-expressive-code: 0.41.5 + astro-mermaid@2.1.0(astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2))(mermaid@11.16.0): + dependencies: + astro: 5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2) + import-meta-resolve: 4.2.0 + mdast-util-to-string: 4.0.0 + mermaid: 11.16.0 + unist-util-visit: 5.0.0 + astro@5.16.6(@types/node@22.19.3)(rollup@4.55.1)(typescript@5.8.2): dependencies: '@astrojs/compiler': 2.13.0 @@ -3590,12 +4143,24 @@ snapshots: commander@11.1.0: {} + commander@7.2.0: {} + + commander@8.3.0: {} + common-ancestor-path@1.0.1: {} cookie-es@1.2.2: {} cookie@1.1.1: {} + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + crossws@0.3.5: dependencies: uncrypto: 0.1.3 @@ -3628,6 +4193,192 @@ snapshots: dependencies: css-tree: 2.2.1 + cytoscape-cose-bilkent@4.1.0(cytoscape@3.34.0): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.34.0 + + cytoscape-fcose@2.2.0(cytoscape@3.34.0): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.34.0 + + cytoscape@3.34.0: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.1.0 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.18.1 + + dayjs@1.11.21: {} + debug@4.4.3: dependencies: ms: 2.1.3 @@ -3638,6 +4389,10 @@ snapshots: defu@6.1.4: {} + delaunator@5.1.0: + dependencies: + robust-predicates: 3.0.3 + dequal@2.0.3: {} destr@2.0.5: {} @@ -3674,6 +4429,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.4.11: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -3694,6 +4453,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-toolkit@1.49.0: {} + esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -3880,6 +4641,8 @@ snapshots: ufo: 1.6.1 uncrypto: 0.1.3 + hachure-fill@0.5.2: {} + hast-util-embedded@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -4081,10 +4844,18 @@ snapshots: dependencies: '@babel/runtime': 7.28.4 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + import-meta-resolve@4.2.0: {} inline-style-parser@0.2.7: {} + internmap@1.0.1: {} + + internmap@2.0.3: {} + iron-webcrypto@1.2.1: {} is-alphabetical@2.0.1: {} @@ -4118,12 +4889,24 @@ snapshots: dependencies: argparse: 2.0.1 + katex@0.16.47: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} + kleur@3.0.3: {} kleur@4.1.5: {} klona@2.0.6: {} + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + + lodash-es@4.18.1: {} + longest-streak@3.1.0: {} lru-cache@10.4.3: {} @@ -4142,6 +4925,8 @@ snapshots: markdown-table@3.0.4: {} + marked@16.4.2: {} + mdast-util-definitions@6.0.0: dependencies: '@types/mdast': 4.0.4 @@ -4329,6 +5114,30 @@ snapshots: mdn-data@2.12.2: {} + mermaid@11.16.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.4 + '@mermaid-js/parser': 1.2.0 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.34.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.34.0) + cytoscape-fcose: 2.2.0(cytoscape@3.34.0) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.21 + dompurify: 3.4.11 + es-toolkit: 1.49.0 + katex: 0.16.47 + khroma: 2.1.0 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.4.0 + ts-dedent: 2.3.0 + uuid: 14.0.1 + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.2.0 @@ -4712,6 +5521,8 @@ snapshots: dependencies: entities: 6.0.1 + path-data-parser@0.1.0: {} + path-to-regexp@6.3.0: {} pathe@2.0.3: {} @@ -4726,6 +5537,13 @@ snapshots: picomatch@4.0.4: {} + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + postcss-nested@6.2.0(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -4920,6 +5738,8 @@ snapshots: retext-stringify: 4.0.0 unified: 11.0.5 + robust-predicates@3.0.3: {} + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 @@ -4951,6 +5771,17 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + + rw@1.3.3: {} + + safer-buffer@2.1.2: {} + sax@1.4.3: {} semver@7.7.3: {} @@ -5088,6 +5919,8 @@ snapshots: dependencies: inline-style-parser: 0.2.7 + stylis@4.4.0: {} + supports-color@10.2.2: {} svgo@4.0.0: @@ -5113,6 +5946,8 @@ snapshots: trough@2.2.0: {} + ts-dedent@2.3.0: {} + tsconfck@3.1.6(typescript@5.8.2): optionalDependencies: typescript: 5.8.2 @@ -5234,6 +6069,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@14.0.1: {} + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 diff --git a/scripts/generate-docs-index.ts b/scripts/generate-docs-index.ts index 0a96d51..a1608ab 100644 --- a/scripts/generate-docs-index.ts +++ b/scripts/generate-docs-index.ts @@ -103,7 +103,7 @@ function generateLlmsTxt(pages: DocPage[]): string { const lines = [ '# Bombshell Documentation', '', - '> Effortlessly build beautiful command-line apps. Docs for Clack, Args, and Tab.', + '> Effortlessly build beautiful command-line apps. Docs for Clack, Args, Tab, and TTY.', '', `Canonical docs: ${BASE_URL}/`, '', diff --git a/src/assets/tty/keyboard-key-events.gif b/src/assets/tty/keyboard-key-events.gif new file mode 100644 index 0000000..a23b852 Binary files /dev/null and b/src/assets/tty/keyboard-key-events.gif differ diff --git a/src/assets/tty/keyboard-pointer-events.gif b/src/assets/tty/keyboard-pointer-events.gif new file mode 100644 index 0000000..0034013 Binary files /dev/null and b/src/assets/tty/keyboard-pointer-events.gif differ diff --git a/src/content/docs/tty/api/index.mdx b/src/content/docs/tty/api/index.mdx new file mode 100644 index 0000000..7890c2f --- /dev/null +++ b/src/content/docs/tty/api/index.mdx @@ -0,0 +1,44 @@ +--- +title: API Overview +description: Overview of the @bomb.sh/tty public API +--- + +`@bomb.sh/tty` exports five modules from a single entry point. Everything is available from `@bomb.sh/tty`: + +```ts twoslash +import { + open, text, close, snapshot, rgba, fit, grow, percent, fixed, + createTerm, + createInput, + settings, alternateBuffer, cursor, mouseTracking, +} from "@bomb.sh/tty"; +``` + +## Modules + +| Module | Description | +|---|---| +| [Ops](/docs/tty/api/ops) | UI directive builders: `open`, `text`, `close`, sizing, colors, transitions | +| [Term](/docs/tty/api/term) | Renderer: `createTerm`, `render`, pointer events, layout info | +| [Input](/docs/tty/api/input) | Input parser: `createInput`, `scan`, keyboard/mouse/resize events | +| [Settings](/docs/tty/api/settings) | Terminal mode helpers: alternate buffer, cursor, mouse tracking | +| [Termcodes](/docs/tty/api/termcodes) | Low-level ANSI escape sequence bytes | + +## Typical app structure + +1. Apply [settings](/docs/tty/api/settings) to stdout (alternate buffer, cursor, mouse) +2. Create a [term](/docs/tty/api/term) and [input](/docs/tty/api/input) instance +3. Set stdin to raw mode +4. On each frame: build [ops](/docs/tty/api/ops) → `term.render()` → write `output` +5. On stdin data: `input.scan()` → handle events +6. If `renderResult.animating`, schedule another frame +7. On exit: revert settings and restore terminal state + +## Deno-only exports + +The Deno source tree includes `@bomb.sh/tty/validate` with runtime op validation (`validate`, `assert`, `validated`). This subpath is not in the published npm `exports` map for v0.8.0. + +## Next steps + +- [Getting Started](/docs/tty/basics/getting-started) +- [Examples](/docs/tty/guides/examples) diff --git a/src/content/docs/tty/api/input.mdx b/src/content/docs/tty/api/input.mdx new file mode 100644 index 0000000..a77b9c2 --- /dev/null +++ b/src/content/docs/tty/api/input.mdx @@ -0,0 +1,127 @@ +--- +title: Input +description: Terminal input parser API for @bomb.sh/tty +--- + +import { Aside } from '@astrojs/starlight/components'; + +The input module decodes raw terminal bytes into structured events. All parsing logic lives in WASM. The TypeScript layer is a thin wrapper. + +## createInput(options?) + +Creates an input parser instance. + +```ts twoslash +import { createInput } from "@bomb.sh/tty"; + +async function main() { + let input = await createInput({ escLatency: 25 }); +} +``` + +### InputOptions + +| Option | Type | Default | Description | +|---|---|---|---| +| `escLatency` | `number` | `25` | Milliseconds to wait before resolving a lone ESC as the Escape key | +| `terminfo` | `Uint8Array` | xterm defaults | Compiled terminfo binary for terminal-specific sequences | + + + +## input.scan(bytes?) + +Feed raw bytes from stdin and return parsed events. Call with no arguments to flush a pending ESC after the latency period. + +```ts twoslash +import { createInput } from "@bomb.sh/tty"; + +async function main() { + let input = await createInput({ escLatency: 25 }); + + process.stdin.setRawMode(true); + let timer: ReturnType | undefined; + + process.stdin.on("data", (buf) => { + clearTimeout(timer); + + let { events, pending } = input.scan(new Uint8Array(buf)); + + for (let event of events) { + console.log(event); + } + + if (pending) { + timer = setTimeout(() => { + let flush = input.scan(); + for (let event of flush.events) { + console.log(event); + } + }, pending.delay); + } + }); +} +``` + +### ScanResult + +| Property | Type | Description | +|---|---|---| +| `events` | `InputEvent[]` | Events produced from this scan | +| `pending` | `{ delay: number }` | Present when a lone ESC is buffered. Re-call `scan()` after `delay` ms | + +## Event types + +### Keyboard events + +| Type | Description | +|---|---| +| `keydown` | Key was pressed | +| `keyrepeat` | Key auto-repeat (Kitty enhancement level 2+) | +| `keyup` | Key was released (Kitty enhancement level 2+) | + +All keyboard events include: + +| Property | Type | Description | +|---|---|---| +| `key` | `string` | Key value (e.g. `"a"`, `"Enter"`, `"ArrowUp"`) | +| `code` | `KeyCode` | Physical key identity (US PC-101 layout) | +| `text` | `string?` | Typed character, if applicable | +| `shifted` | `string?` | Shifted character variant | +| `alt`, `ctrl`, `shift` | `true?` | Modifier keys held | + +### Mouse events + +| Type | Description | +|---|---| +| `mousedown` | Button pressed (`left`, `right`, `middle`) | +| `mouseup` | Button released | +| `mousemove` | Movement while button held | +| `wheel` | Scroll wheel (`direction: "up"` \| `"down"`) | + +Mouse events include `x` and `y` coordinates (0-based) and optional modifiers. + +### Other events + +| Type | Description | +|---|---| +| `resize` | Terminal resized. Returns `{ width, height }` | +| `cursor` | DSR cursor position report. Returns `{ row, column }` (1-based) | + +Pointer events (`pointerenter`, `pointerleave`, `pointerclick`) are produced by the [renderer](/docs/tty/api/term), not the input parser. + +## Supported protocols + +The parser recognizes: + +- VT/ANSI escape sequences +- UTF-8 codepoints +- Mouse protocols (VT200, SGR, urxvt) +- Progressive keyboard protocol (via [settings](/docs/tty/api/settings)) +- Partial sequence reassembly across read boundaries + +## Next steps + +- [Settings API](/docs/tty/api/settings) (enable mouse tracking and keyboard protocols) +- [Term API](/docs/tty/api/term) (pointer hit testing on the render side) diff --git a/src/content/docs/tty/api/ops.mdx b/src/content/docs/tty/api/ops.mdx new file mode 100644 index 0000000..89fb632 --- /dev/null +++ b/src/content/docs/tty/api/ops.mdx @@ -0,0 +1,168 @@ +--- +title: Ops +description: UI directive builders for @bomb.sh/tty +--- + +import { Aside } from '@astrojs/starlight/components'; + +The ops module provides builders for describing terminal UI as a flat array of directives. Each frame is a complete snapshot. Build ops, pass them to [`term.render()`](/docs/tty/api/term), and write the output bytes. + +## Building a frame + +```ts twoslash +import { close, open, rgba, text, grow } from "@bomb.sh/tty"; + +let ops = [ + open("root", { + layout: { width: grow(), height: grow(), direction: "ttb" }, + }), + open("panel", { + layout: { padding: { left: 1, right: 1, top: 1, bottom: 1 } }, + border: { color: rgba(0, 255, 0), left: 1, right: 1, top: 1, bottom: 1 }, + cornerRadius: { tl: 1, tr: 1, bl: 1, br: 1 }, + }), + text("Hello, World!"), + close(), + close(), +]; +``` + +## open(id, props?) + +Opens a layout element. Every element needs a unique string `id` for pointer hit-testing and layout queries. + +### Layout + +| Property | Type | Description | +|---|---|---| +| `width` | `SizingAxis` | Horizontal sizing (`fit`, `grow`, `percent`, `fixed`) | +| `height` | `SizingAxis` | Vertical sizing | +| `padding` | `{ left?, right?, top?, bottom? }` | Inner padding in cells | +| `gap` | `number` | Gap between children | +| `direction` | `"ltr"` \| `"ttb"` | Child layout direction | +| `alignX` | `"left"` \| `"center"` \| `"right"` | Horizontal alignment | +| `alignY` | `"top"` \| `"center"` \| `"bottom"` | Vertical alignment | + +### Style + +| Property | Type | Description | +|---|---|---| +| `bg` | `number` | Background color (packed RGBA via `rgba()`) | +| `cornerRadius` | `{ tl?, tr?, bl?, br? }` | Rounded corners | +| `border` | `{ color, bg?, left?, right?, top?, bottom? }` | Border sides (number or `{ width, color?, bg? }`) | +| `clip` | `{ horizontal?, vertical? }` | Clip overflowing content | + +### Floating + +| Property | Type | Description | +|---|---|---| +| `floating.x`, `floating.y` | `number` | Position offset | +| `floating.expand` | `{ width?, height? }` | Expand floating bounds | +| `floating.attachTo` | `"none"` \| `"parent"` \| `"element"` \| `"root"` | Attachment target | +| `floating.attachPoints` | `{ element?, parent? }` | Anchor points | +| `floating.pointerCaptureMode` | `"capture"` \| `"passthrough"` | Pointer event capture | +| `floating.clipTo` | `"none"` \| `"attached-parent"` | Clip to attached parent | +| `floating.zIndex` | `number` | Stacking order | + +### Transitions + +```ts twoslash +import { open, rgba } from "@bomb.sh/tty"; + +open("sidebar", { + layout: { width: { type: "fixed", value: 20 } }, + bg: rgba(30, 30, 40), + transition: { + duration: 0.3, + easing: "easeInOut", + properties: ["width", "bg"], + }, +}); +``` + +| Property | Type | Description | +|---|---|---| +| `duration` | `number` | Duration in seconds | +| `easing` | `"linear"` \| `"easeIn"` \| `"easeOut"` \| `"easeInOut"` | Easing function | +| `properties` | `TransitionProperty[]` | Properties to animate | +| `interactive` | `boolean` | Allow interaction during transition | + +Transition properties: `"x"`, `"y"`, `"position"`, `"width"`, `"height"`, `"size"`, `"bg"`, `"overlay"`, `"borderColor"`, `"borderWidth"`, `"all"`. + +## text(content, props?) + +Renders a text node inside the current open element. + +| Property | Type | Description | +|---|---|---| +| `color` | `number` | Foreground color | +| `bg` | `number` | Background color | +| `fontSize` | `number` | Font size | +| `fontId` | `number` | Font identifier | +| `wrap` | `number` | Wrap width | +| `attrs` | `number` | Text attributes (bold, italic, etc.) | + +## close() + +Closes the current open element. Ops must be properly nested. Every `open` needs a matching `close`. + +## snapshot(ops) + +Pre-packs an op array into a reusable snapshot op. Useful when part of the UI is static across frames. + +```ts twoslash +import { close, open, snapshot, text, grow } from "@bomb.sh/tty"; + +let chrome = snapshot([ + open("header", { layout: { width: grow(), height: { type: "fixed", value: 1 } } }), + text("My App"), + close(), +]); + +// Each frame: [chrome, ...dynamicOps] +``` + +## rgba(r, g, b, a?) + +Packs an RGBA color into a 32-bit integer. Alpha defaults to 255. + +```ts twoslash +import { rgba } from "@bomb.sh/tty"; + +rgba(255, 0, 0); // red +rgba(0, 255, 0, 128); // semi-transparent green +``` + +## Sizing helpers + +```ts twoslash +import { fit, grow, percent, fixed } from "@bomb.sh/tty"; + +fit(); // shrink to content +fit(10, 40); // fit with min/max +grow(); // expand to fill available space +grow(5, 50); // grow with min/max +percent(0.5); // 50% of parent +fixed(20); // exactly 20 cells +``` + +## Types + +| Type | Description | +|---|---| +| `Op` | Union of all directive types | +| `OpenElement` | Element opened by `open()` | +| `Text` | Text node | +| `CloseElement` | Element closed by `close()` | +| `SizingAxis` | `{ type: "fit" \| "grow" \| "percent" \| "fixed", ... }` | +| `Transition` | Transition configuration | +| `BorderSide` | `number` or `{ width, color?, bg? }` | + + + +## Next steps + +- [Term API](/docs/tty/api/term) (rendering ops to the terminal) +- [Examples](/docs/tty/guides/examples) (transitions and layout demos) diff --git a/src/content/docs/tty/api/settings.mdx b/src/content/docs/tty/api/settings.mdx new file mode 100644 index 0000000..cfbb55f --- /dev/null +++ b/src/content/docs/tty/api/settings.mdx @@ -0,0 +1,142 @@ +--- +title: Settings +description: Terminal mode helpers for @bomb.sh/tty +--- + +The settings module provides composable terminal mode changes. Each setting produces `apply` and `revert` byte sequences you write to stdout. + +## `Setting` + +Every setting helper returns: + +```ts +interface Setting { + apply: Uint8Array; + revert: Uint8Array; +} +``` + +Write `apply` on startup and `revert` on exit to restore the terminal. + +## `settings(...sequence)` + +Compose multiple settings into one. Revert runs in reverse order. + +```ts twoslash +import { + alternateBuffer, + cursor, + mouseTracking, + settings, +} from "@bomb.sh/tty"; + +let tty = settings( + alternateBuffer(), + cursor(false), + mouseTracking(), +); + +process.stdout.write(tty.apply); + +// on exit: +process.stdout.write(tty.revert); +``` + +## `alternateBuffer(options?)` + +Switch to the alternate screen buffer. + +| Option | Type | Default | Description | +|---|---|---|---| +| `clear` | `boolean` | `true` | Clear the alternate buffer on entry | + +```ts twoslash +import { alternateBuffer } from "@bomb.sh/tty"; + +alternateBuffer(); // enter, clear +alternateBuffer({ clear: false }); // enter, preserve contents +``` + +Revert switches back to the main screen with scrollback intact. + +## `cursor(visible)` + +Show or hide the terminal cursor (DEC private mode 25). + +```ts twoslash +import { cursor } from "@bomb.sh/tty"; + +cursor(false); // hide +cursor(true); // show +``` + +## `saveCursorPosition()` + +Save and restore cursor position using DECSC (`ESC 7`) / DECRC (`ESC 8`). + +```ts twoslash +import { saveCursorPosition } from "@bomb.sh/tty"; + +let pos = saveCursorPosition(); +process.stdout.write(pos.apply); +// ... render ... +process.stdout.write(pos.revert); +``` + +## `progressiveInput(level)` + +Enable the progressive keyboard enhancement protocol. + +```ts twoslash +import { progressiveInput } from "@bomb.sh/tty"; + +progressiveInput(2); // Kitty enhancement level 2+ +``` + +Revert sends `CSI +Line mode (`mode: "line"`) renders into a region of the main screen scrollback instead of the alternate buffer. See the [inline regions example](https://github.com/bombshell-dev/tty/blob/main/examples/inline-regions/index.ts). + + +## Next steps + +- [Ops API](/docs/tty/api/ops) (building UI directives) +- [Input API](/docs/tty/api/input) (parsing stdin events) diff --git a/src/content/docs/tty/api/termcodes.mdx b/src/content/docs/tty/api/termcodes.mdx new file mode 100644 index 0000000..64a9985 --- /dev/null +++ b/src/content/docs/tty/api/termcodes.mdx @@ -0,0 +1,76 @@ +--- +title: Termcodes +description: Low-level ANSI escape sequence builders for @bomb.sh/tty +--- + +import { Aside } from '@astrojs/starlight/components'; + +The termcodes module provides low-level escape sequence builders. Each function returns a `Uint8Array` you can write directly to stdout. + + + +## ESC(str) + +Encode a plain escape sequence. Prepends `ESC` (`\x1b`) to the given string. + +```ts twoslash +import { ESC } from "@bomb.sh/tty"; + +process.stdout.write(ESC("7")); // save cursor (DECSC) +``` + +## CSI(str) + +Encode a Control Sequence Introducer command. Prepends `ESC[` to the given string. + +```ts twoslash +import { CSI } from "@bomb.sh/tty"; + +process.stdout.write(CSI("2J")); // clear screen +``` + +## DSR() + +Request cursor position via Device Status Report. Sends `CSI 6n`. The terminal responds with a Cursor Position Report (`CSI row ; column R`) where row and column are 1-based. + +```ts twoslash +import { DSR } from "@bomb.sh/tty"; + +process.stdout.write(DSR()); +``` + +The response is parsed as a `cursor` event by the [input parser](/docs/tty/api/input). Used by the [inline regions example](https://github.com/bombshell-dev/tty/blob/main/examples/inline-regions/index.ts) to place animated output in scrollback. + +## SHOWCURSOR() / HIDECURSOR() + +Show or hide the cursor (DEC private mode 25, DECTCEM). + +```ts twoslash +import { HIDECURSOR, SHOWCURSOR } from "@bomb.sh/tty"; + +process.stdout.write(HIDECURSOR()); +process.stdout.write(SHOWCURSOR()); +``` + +Equivalent to [`cursor(false)`](/docs/tty/api/settings) / [`cursor(true)`](/docs/tty/api/settings). + +## ALTSCREEN(options?) / MAINSCREEN() + +Switch between main and alternate screen buffers. + +```ts twoslash +import { ALTSCREEN, MAINSCREEN } from "@bomb.sh/tty"; + +process.stdout.write(ALTSCREEN()); // enter, clear +process.stdout.write(ALTSCREEN({ clear: false })); // enter, preserve +process.stdout.write(MAINSCREEN()); // return to main screen +``` + +Equivalent to [`alternateBuffer()`](/docs/tty/api/settings) / its revert sequence. + +## Next steps + +- [Settings API](/docs/tty/api/settings) (composable terminal mode helpers) +- [Getting Started](/docs/tty/basics/getting-started) diff --git a/src/content/docs/tty/basics/getting-started.mdx b/src/content/docs/tty/basics/getting-started.mdx new file mode 100644 index 0000000..70c8fc3 --- /dev/null +++ b/src/content/docs/tty/basics/getting-started.mdx @@ -0,0 +1,208 @@ +--- +title: Getting Started +description: Learn how to get started with @bomb.sh/tty +--- + +import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'; + +`@bomb.sh/tty` is a low-level, platform-independent terminal renderer and event parser for JavaScript. Use it directly to build full-screen or inline terminal UIs, or as the foundation for your own framework. + +## Features + +- **Declarative terminal UI:** Flexbox-like layout powered by [Clay](https://github.com/nicbarker/clay), with borders, colors, floating elements, scroll containers, and pointer hit-testing +- **Zero I/O:** Never reads stdin or writes stdout. Feed bytes in, get bytes and events back +- **Runs everywhere:** The entire engine is compiled to WebAssembly with no native dependencies for consumers + +## When to use it + +Reach for `@bomb.sh/tty` when you need a **rendering engine** for terminal UI: layout, styling, diffing, and input parsing, without committing to a particular app framework or I/O model. + +### Good fits + +- **Full-screen applications:** Dashboards, tools, and games that take over the alternate screen buffer with layouts, borders, mouse hover, and keyboard input (see the [2048](/docs/tty/guides/examples) and [keyboard](/docs/tty/guides/examples) demos) +- **Inline animated output:** Spinners, progress bars, or live status regions embedded in normal scrollback without switching to a full-screen mode (see [inline regions](/docs/tty/guides/examples)) +- **Rich, structured output:** Diff views, panels, sidebars, and multi-pane layouts where hand-written ANSI becomes unmaintainable +- **Interactive layouts with pointer support:** Hover states, clickable regions, and drag-style interactions driven by terminal mouse reporting +- **Animated UI:** Transitions on width, color, position, and other properties with efficient cell-level diffing between frames +- **Custom TUI frameworks:** Zero I/O means you wire stdin/stdout (or any byte stream) yourself; the engine stays a pure compute layer you can embed in Node, Deno, Bun, or the browser + +### When to pick something else + +- **One-shot CLI prompts** (text input, selects, confirms): use [`@clack/prompts`](/docs/clack/basics/getting-started); it targets a different problem and uses Node's built-in `tty` module, not this package +- **Component-based UI with state and bindings:** use `@clack/ui`, which is built on `@bomb.sh/tty` and handles the higher-level framework concerns for you + +## Requirements + +Node >= 22. Also works in Deno, Bun, and browsers. + +## Installation + + + + ```bash + npm install @bomb.sh/tty + ``` + + + ```bash + pnpm add @bomb.sh/tty + ``` + + + ```bash + yarn add @bomb.sh/tty + ``` + + + +## Core concepts + +**Frames as snapshots.** Each frame is a complete, independent UI description. Build an array of ops (`open`, `text`, `close`), pass it to `term.render()`, and write the returned ANSI bytes to stdout. The renderer carries layout and diff state between frames, not a persistent component tree. + +**Zero I/O boundary.** You own stdin/stdout. `@bomb.sh/tty` is pure computation: one WASM call per frame on the output side, and a byte-stream parser on the input side. + +**Efficient output.** Clay runs layout, walks render commands into a cell buffer, and diffs against the previous frame. Only changed cells produce ANSI escape sequences. + +## Architecture + +### Output + +```mermaid +flowchart LR + subgraph ts [TypeScript] + Ops["UI ops"] + Stdout["stdout.write"] + end + subgraph wasm [WASM] + Clay["Clay layout"] + Diff["Cell diff"] + Esc["Escape bytes"] + end + Ops -->|"Uint32Array"| Clay + Clay --> Diff + Diff --> Esc + Esc -->|"ANSI bytes"| Stdout +``` + +### Input + +```mermaid +flowchart LR + subgraph ts [TypeScript] + Stdin["stdin.read"] + Events["InputEvent[]"] + end + subgraph wasm [WASM] + Parse["Trie match"] + Decode["UTF-8 / mouse / ESC"] + end + Stdin -->|"raw bytes"| Parse + Parse --> Decode + Decode --> Events +``` + +Raw bytes are fed into a WASM parser that recognizes VT/ANSI escape sequences, UTF-8 codepoints, and mouse protocols. Partial sequences that arrive across read boundaries are reassembled automatically. A lone ESC byte is held for a configurable latency window (default 25ms) before being emitted. + +## Quick start: rendering + +To render this: + +``` +╭───────────────╮ +│ Hello, World! │ +╰───────────────╯ +``` + +```ts twoslash +import { close, createTerm, grow, open, rgba, text } from "@bomb.sh/tty"; + +async function main() { + let term = await createTerm({ width: 80, height: 24 }); + + let { output } = term.render([ + open("root", { + layout: { width: grow(), height: grow(), direction: "ttb" }, + }), + open("greeting", { + layout: { padding: { left: 1, right: 1, top: 1, bottom: 1 } }, + border: { + color: rgba(0, 255, 0), + left: 1, right: 1, top: 1, bottom: 1, + }, + cornerRadius: { tl: 1, tr: 1, bl: 1, br: 1 }, + }), + text("Hello, World!"), + close(), + close(), + ]); + + process.stdout.write(output); +} +``` + +## Quick start: input + +```ts twoslash +import { createInput } from "@bomb.sh/tty"; + +async function main() { + let input = await createInput({ escLatency: 25 }); + + process.stdin.setRawMode(true); + let timer: ReturnType | undefined; + + process.stdin.on("data", (buf) => { + clearTimeout(timer); + + let { events, pending } = input.scan(new Uint8Array(buf)); + + for (let event of events) { + console.log(event); + } + + if (pending) { + timer = setTimeout(() => { + let flush = input.scan(); + for (let event of flush.events) { + console.log(event); + } + }, pending.delay); + } + }); +} +``` + +## Quick start: terminal modes + +Use composable settings to enter alternate buffer mode, hide the cursor, and enable mouse tracking: + +```ts twoslash +import { + alternateBuffer, + cursor, + mouseTracking, + settings, +} from "@bomb.sh/tty"; + +let tty = settings(alternateBuffer(), cursor(false), mouseTracking()); +process.stdout.write(tty.apply); + +// on exit: +process.stdout.write(tty.revert); +``` + +## Demos + +The input parser decodes raw terminal bytes into structured events. Here you can see each key event as the string "hello world" is typed: + +![Keyboard events demo](/src/assets/tty/keyboard-key-events.gif) + +Hover styles applied to UI elements in response to pointer state. Clay drives hit testing, so you don't need manual coordinate math: + +![Pointer events demo](/src/assets/tty/keyboard-pointer-events.gif) + +## Next steps + +1. Explore [runnable examples](/docs/tty/guides/examples) on GitHub +2. Read the [Ops API](/docs/tty/api/ops) for layout and styling directives +3. Join our [Discord community](https://bomb.sh/chat) for support and discussions diff --git a/src/content/docs/tty/guides/examples.mdx b/src/content/docs/tty/guides/examples.mdx new file mode 100644 index 0000000..c040039 --- /dev/null +++ b/src/content/docs/tty/guides/examples.mdx @@ -0,0 +1,120 @@ +--- +title: Examples +description: Runnable @bomb.sh/tty demos and what to learn from each +--- + +import { Aside } from '@astrojs/starlight/components'; + +The best way to learn `@bomb.sh/tty` after the [getting started guide](/docs/tty/basics/getting-started) is to run the demos in the [tty repository](https://github.com/bombshell-dev/tty). Each one is a small app that shows how the pieces fit together: render loop, input parsing, terminal modes, transitions. + + + +## Get set up + +```bash +git clone https://github.com/bombshell-dev/tty.git +cd tty +make # build the WASM bundle +node examples/keyboard/index.ts +``` + + + +## Which demo should I run? + +| Demo | Start here if you want to… | Key APIs | +|---|---|---| +| [Keyboard](#keyboard) | Wire up input, pointer hover, and terminal modes | [`createInput`](/docs/tty/api/input), [`settings`](/docs/tty/api/settings), [`render` pointer option](/docs/tty/api/term) | +| [Transitions](#transitions) | Animate layout and color between frames | [`open` transitions](/docs/tty/api/ops), [`animating`](/docs/tty/api/term) | +| [Inline regions](#inline-regions) | Draw animated output in scrollback, not full-screen | [`render` line mode](/docs/tty/api/term), [`DSR`](/docs/tty/api/termcodes) | +| [2048](#2048) | See everything combined in a real app | ops, term, input, settings | +| [Diff](#diff) | Highlight per-glyph in a layout | [`text` `bg`](/docs/tty/api/ops) | + +**Suggested order:** keyboard → transitions → inline regions → 2048. Diff is a focused layout exercise you can skip until you need it. + +## Keyboard + +[`examples/keyboard/index.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/keyboard/index.ts) + +```bash +node examples/keyboard/index.ts +``` + +This is the best first demo. It shows the full loop most apps follow: + +1. Apply [terminal settings](/docs/tty/api/settings) (alternate buffer, hidden cursor, mouse tracking) +2. Create a [term](/docs/tty/api/term) and feed [pointer state](/docs/tty/api/term) each frame +3. Parse stdin through [`createInput`](/docs/tty/api/input) and dispatch events +4. Revert settings on exit + +Type on the keyboard to see decoded key events. Move the mouse to see hover styles. Clay handles hit testing, so you don't need manual coordinate math. + +![Keyboard events demo](/src/assets/tty/keyboard-key-events.gif) + +![Pointer events demo](/src/assets/tty/keyboard-pointer-events.gif) + +## Transitions + +[`examples/transitions/sidebar.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/transitions/sidebar.ts) · [`examples/transitions/notecards.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/transitions/notecards.ts) + +```bash +node examples/transitions/sidebar.ts +node examples/transitions/notecards.ts +``` + +Change layout or style properties between frames and attach a [`transition`](/docs/tty/api/ops) to elements. Gate your render loop on [`animating`](/docs/tty/api/term) so you only redraw while motion is in progress. + +The sidebar demo animates width with keyboard shortcuts. Notecards interpolates layout and background color. + +{/* TODO: add transitions-sidebar.gif (record `node examples/transitions/sidebar.ts`) */} +{/* TODO: add transitions-notecards.gif (record `node examples/transitions/notecards.ts`) */} + +## Inline regions + +[`examples/inline-regions/index.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/inline-regions/index.ts) + +```bash +node examples/inline-regions/index.ts +``` + +Renders spinners, progress bars, and small animations into **normal scrollback** instead of taking over the screen. Uses [`DSR`](/docs/tty/api/termcodes) to query cursor position and [`render` in line mode](/docs/tty/api/term) to update a fixed region. + +Reach for this pattern when you want live output inside a regular CLI workflow (build logs, install progress, status lines) without switching to the alternate buffer. + +{/* TODO: add inline-regions.gif (record `node examples/inline-regions/index.ts`) */} + +## 2048 + +[`examples/2048/index.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/2048/index.ts) + +```bash +node examples/2048/index.ts +``` + +A complete game combining transitions, keyboard focus, pointer clicks, live resize, and an fps counter. Good reference once you understand the basics. + +**Controls:** arrows or `wasd` to move · `Tab`/`Shift+Tab` for focus · `Enter`/`Space` to activate · `n` new game · `u` undo · `q` or `Ctrl+C` to quit + +{/* TODO: add 2048.gif (record `node examples/2048/index.ts`) */} + +## Diff + +[`examples/diff/index.ts`](https://github.com/bombshell-dev/tty/blob/main/examples/diff/index.ts) + +```bash +node examples/diff/index.ts +``` + +A code-review diff view with per-glyph `bg` highlighting on [`text`](/docs/tty/api/ops) nodes. Useful if you're building structured, read-only output rather than interactive UI. + +{/* TODO: add diff.gif (record `node examples/diff/index.ts`) */} + +## Next steps + +- [Getting Started](/docs/tty/basics/getting-started) (install, architecture, quick starts) +- [Term API](/docs/tty/api/term) (render loop and pointer events) +- [Input API](/docs/tty/api/input) (stdin event parsing)