{"id":38269750,"url":"https://github.com/varrockbank/buffee","last_synced_at":"2026-01-17T01:49:05.235Z","repository":{"id":316533228,"uuid":"1063705685","full_name":"varrockbank/buffee","owner":"varrockbank","description":"The netizen's text slayer and editor. ","archived":false,"fork":false,"pushed_at":"2026-01-12T22:13:58.000Z","size":47572,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T00:16:33.560Z","etag":null,"topics":["microlibrary","text-editor","tui","vim"],"latest_commit_sha":null,"homepage":"https://varrockbank.github.io/buffee/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/varrockbank.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-25T02:23:27.000Z","updated_at":"2026-01-12T22:14:02.000Z","dependencies_parsed_at":"2025-10-03T02:40:01.233Z","dependency_job_id":"f3845612-c139-4b1a-9026-157be8ae38ad","html_url":"https://github.com/varrockbank/buffee","commit_stats":null,"previous_names":["varrockbank/warrenbuffer","varrockbank/warrenbuf","varrockbank/vbuf"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/varrockbank/buffee","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varrockbank%2Fbuffee","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varrockbank%2Fbuffee/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varrockbank%2Fbuffee/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varrockbank%2Fbuffee/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/varrockbank","download_url":"https://codeload.github.com/varrockbank/buffee/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varrockbank%2Fbuffee/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28491667,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T00:50:05.742Z","status":"ssl_error","status_checked_at":"2026-01-17T00:43:11.982Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["microlibrary","text-editor","tui","vim"],"created_at":"2026-01-17T01:49:05.142Z","updated_at":"2026-01-17T01:49:05.223Z","avatar_url":"https://github.com/varrockbank.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Buffee - netizen's text buffer \n\n![Screenshot Tests](https://github.com/varrockbank/buffee/actions/workflows/screenshots.yml/badge.svg)\n\nInspired by the experience of terminal interfaces and Vim, Buffee is a microlibrary optimized for rendering plaintext text on the web. Fixed-width grid layout is not a bug, it's the core feature! \n\n### Priorities:\n\n- tiny: ~2kb (gz+min) fooprint, low memory/CPU overhead\n- performant: rivals native editors like Vim - no slowdown on large files\n- hassle-free: no build step, no NPM, no dependencies\n- programmable: combinators, hackable internals, minimal API\n- heavy-duty: ~70m SLOC file capacity, 1B+ in high-capacity mode \n\nYes - like Emacs, it includes a text editor too.\n\n![](assets/preview.png)\n\n[Live Demo](https://varrockbank.github.io/buffee/)\n\n[Unit Tests](https://varrockbank.github.io/buffee/test/)\n\n## An Embeddable Building Block\n\n1. spartan (minimal, performant, capable)\n2. programmable\n3. tiny \n\nThis trifecta uniquely positions buffee as a building block for rich editing experience, IDEs and apps. In fact, this guides the scope and omission.\n\nSee [comparison](https://varrockbank.github.io/buffee/web/comparison.html) and [performance](https://varrockbank.github.io/buffee/web/performance.html) for more on Buffee's niche.\n\n## The Magic Trick\n\nThe crux is maintaining a small DOM footprint. This is achieved by maintain a virtual viewport and being smart in surgically rendering only what's changed. \n\nThe zeitgeist of webdev is VDOM. This does not come free. VDOM libraries are bulkier than Buffee in its entirety because they deal with arbitrary trees. Buffee avoids this \nwith a predictable and narrowly constrained UI surface space. \n\nThe fixed-width grid layout constraint drastically reduce complexity. \n\nFinally, (V8) arrays, not being real arrays, prove miraculuously viable as a buffer data structure. VScode's Piecetree datastructure along is 10x the size of Buffee's entire source.\n\n## Usage\n\n### Monowidth Character Handling\n\nBuffee's fixed-width grid layout requires all characters to occupy exactly one cell. This section covers common issues that break grid alignment.\n\n#### Font Requirements\n\nBuffee assumes monospace fonts having accurate CSS `ch` values. If this assumption breaks, the cursor position\nwill be visually misaligned from true position. This is  evident with variable-width\ntext but some monospace fonts can cause \"drift\", fractions of a pixel per character, that accumulate numerical errors.\n\n- **Good:** Menlo, Consolas, `monospace` (generic)\n- **Bad:** Monaco\n\nTo test: type \"A\" 100+ times and move cursor to end. If misaligned, try a different font.\n\n#### Tab Sanitization\n\nTab characters (`\\t`) break grid alignment because browsers render them as variable-width. Buffee core does not sanitize input—if you set content containing tabs via `Model.s` or `Span.ins()`, they appear as-is.\n\n**Solutions:**\n- **BuffeeSanitize combinator** — Automatically converts tabs to spaces, removes zero-width characters, and normalizes multi-width Unicode spaces. See [Sanitize combinator](web/combinators.html#sanitize).\n- **Pre-sanitize** — Clean your text before passing to Buffee: `text.replace(/\\t/g, '    ')`\n\nThe keyboard controller already handles Tab key presses by inserting spaces (based on `Mode.s`), so typed tabs are not an issue—only programmatic content.\n\n### CSS \n\n[style.css](style.css) contains structural styles. Bring-your-own cursor and selection color: \n\n```css\n.buffee { background-color: #282C34; color: #B2B2B2 }\n.buffee .buffee-zsel \u003e div { background-color: #EDAD10 }\n.buffee .buffee-caret { background-color: #FF6B6B }\n.buffee .buffee-rail, .buffee .buffee-status { background-color: #21252B; color: #636D83 }\n```\n\nsee [themes](https://varrockbank.github.io/buffee/web/themes.html) for inspiration.\n\n### HTML\n\nEditor instances attach to a root node having such structure:\n\n```html\n\u003cdiv class=\"buffee\" id=\"editor\"\u003e\n  \u003cdiv class=\"no-select buffee-pane\"\u003e\n    \u003c!-- Can omit optional gutter rail --\u003e\n    \u003cdiv class=\"buffee-rail\"\u003e\u003c/div\u003e\n    \u003cdiv class=\"buffee-lines\" tabindex=\"0\"\u003e\n      \u003cblockquote class=\"buffee-ztxt\"\u003e\u003c/blockquote\u003e\n      \u003cdiv class=\"buffee-layer-elements\"\u003e\u003c/div\u003e\n      \u003cdiv class=\"buffee-caret\"\u003e\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\nThe status line component additional expects this directly under the root element.\n\n```html\n\u003cdiv class=\"buffee-status\"\u003e\n    \u003cdiv class=\"buffee-status-left\"\u003e\n      \u003cspan class=\"buffee-linecount\"\u003e\u003c/span\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"buffee-status-right\"\u003e\n      Ln \u003cspan class=\"buffee-head-row\"\u003e\u003c/span\u003e, Col \u003cspan class=\"buffee-head-col\"\u003e\u003c/span\u003e|\n      \u003cspan class=\"buffee-spaces\"\u003e\u003c/span\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n```\n\n### JavaScript\n\n```javascript\nconst editor = new Buffee(document.getElementById(\"editor\"), {});\n```\n\nEditor auto-fits to its container size. For fixed dimensions:\n\n```javascript\nnew Buffee(el, { h: 20 });      // Fixed row count\nnew Buffee(el, { w: 80 });      // Fixed column width\nnew Buffee(el, { h: 20, w: 80 }); // Both fixed\n```\n\nContainer should have explicit height inherit some percentage from parent. \n\n### Model-view-selection API\n\n**Model** `editor.Model` contains text buffer and metadata \n  \n`editor.Model._` is the raw list of text buffer lines \n\n**View** `editor.View` represents the virtual viewport\n\n**Span** `editor.Span` represents a text selection. Cursors are the special case of this where the\nanchor and the head/dot are the same. Text editing operations are defined relative to this selection.\n\nThe controller are keyboard event handlers which route to operations on the selection. In the future, the basic controller will be refactored out of Buffee.js as a Combinator such that you will have to bring-your-own controller by default. e.g. a \"vim normal mode controller\".\n\nSee: [API Reference](docs/api.txt) | [Getting Started](docs/onboarding.md)\n\n## Combinators\n\nCombinators use the decorator pattern - pure functions that wrap the editor, being an editor instance themselves, meaning they can be combined:\n\n```javascript\n// Single combinator\nconst editor = BuffeeHistory(new Buffee(container, config));\n\n// Multiple combinators (compose by nesting)\nconst editor = BuffeeElementals(\n  BuffeeSyntax(\n    BuffeeHistory(\n      new Buffee(container, config)\n    )\n  )\n);\n\n// Combinators expose APIs on the editor instance\neditor.History.undo();\neditor.Syntax.setLanguage('javascript');\neditor.Elementals.addButton({ row: 0, col: 0, label: 'OK' });\n```\n\nAvailable combinators:\n- **History** - Undo/redo with operation coalescing\n- **Syntax** - Regex-based syntax highlighting\n- **Elementals** - DOM-based UI elements (buttons, inputs)\n- **TUI** - Terminal UI via text manipulation\n- **FileLoader** - Multiple strategies for large file loading\n- **UltraHighCapacity** - Gzip-compressed storage for 1B+ lines\n- **iOS** - Touch and on-screen keyboard support\n- **Sanitize** - Tab/Unicode normalization for programmatic content\n\nSee: [Dev Guide on Combinators](docs/combinators.md)\nSee: [Combinator Gallery](web/combinators.html)\n\n## Versioning \n\n`style.css`, `template.html` and `buffer.js` share a version sequence. \n\nif buffer.js changes, its version need to be bumped up, past the version of style.css.\n\nif style.css changes, its version needs to be bumped past buffer.js. \n\nA given version `X` if a set of `style.css`, `template.html` and `buffer.js` with version being the largest value not exceeding `X`. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvarrockbank%2Fbuffee","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvarrockbank%2Fbuffee","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvarrockbank%2Fbuffee/lists"}