{"id":34245389,"url":"https://github.com/omarluq/termisu","last_synced_at":"2026-02-26T10:52:07.775Z","repository":{"id":324156018,"uuid":"1096187349","full_name":"omarluq/termisu","owner":"omarluq","description":"🍮 Minimalistic API for writing text-based user interfaces in pure Crystal","archived":false,"fork":false,"pushed_at":"2026-02-25T07:36:59.000Z","size":6903,"stargazers_count":20,"open_issues_count":9,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-25T09:11:17.435Z","etag":null,"topics":["crystal-lang","crystal-language","term","termbox","terminal-applications","terminal-io","terminal-user-interface","text-based-in","tui"],"latest_commit_sha":null,"homepage":"","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/omarluq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","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":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-14T03:57:59.000Z","updated_at":"2026-02-25T03:18:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"e20344aa-1856-457d-8732-83aa9721d1c5","html_url":"https://github.com/omarluq/termisu","commit_stats":null,"previous_names":["omarluq/termisu"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/omarluq/termisu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarluq%2Ftermisu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarluq%2Ftermisu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarluq%2Ftermisu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarluq%2Ftermisu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/omarluq","download_url":"https://codeload.github.com/omarluq/termisu/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omarluq%2Ftermisu/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29856758,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T08:51:08.701Z","status":"ssl_error","status_checked_at":"2026-02-26T08:50:19.607Z","response_time":89,"last_error":"SSL_read: 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":["crystal-lang","crystal-language","term","termbox","terminal-applications","terminal-io","terminal-user-interface","text-based-in","tui"],"created_at":"2025-12-16T06:59:55.159Z","updated_at":"2026-02-26T10:52:07.767Z","avatar_url":"https://github.com/omarluq.png","language":"Crystal","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Termisu\n\n[![Crystal Version](https://img.shields.io/badge/Crystal-%3E%3D1.18.2-000000?style=flat\u0026labelColor=24292e\u0026color=000000\u0026logo=crystal\u0026logoColor=white)](https://crystal-lang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue?style=flat\u0026labelColor=24292e\u0026logo=opensourceinitiative\u0026logoColor=white)](LICENSE)\n[![Tests](https://img.shields.io/github/actions/workflow/status/omarluq/termisu/test.yml?style=flat\u0026labelColor=24292e\u0026label=Tests\u0026logo=github\u0026logoColor=white)](https://github.com/omarluq/termisu/actions/workflows/test.yml)\n[![Version](https://img.shields.io/github/release/omarluq/termisu?style=flat\u0026labelColor=24292e\u0026color=28a745\u0026label=Version\u0026logo=semver\u0026logoColor=white)](https://github.com/omarluq/termisu/releases)\\\n[![codecov](https://img.shields.io/codecov/c/github/omarluq/termisu?style=flat\u0026labelColor=24292e\u0026logo=codecov\u0026logoColor=white\u0026token=YW23EDL5T5)](https://codecov.io/gh/omarluq/termisu)\n[![Docs](https://img.shields.io/badge/Docs-API%20Reference-5e5086?style=flat\u0026labelColor=24292e\u0026logo=gitbook\u0026logoColor=white)](https://crystaldoc.info/github/omarluq/termisu)\n[![Maintained](https://img.shields.io/badge/Maintained%3F-yes-28a745?style=flat\u0026labelColor=24292e\u0026logo=checkmarx\u0026logoColor=white)](https://github.com/omarluq/termisu)\n[![Made with Love](https://img.shields.io/badge/Made%20with-Love-ff69b4?style=flat\u0026labelColor=24292e\u0026logo=githubsponsors\u0026logoColor=white)](https://github.com/omarluq/termisu)\n\n\u003c!--  [![All Contributors](https://img.shields.io/github/all-contributors/omarluq/termisu?style=flat\u0026labelColor=24292e\u0026color=7f8c8d)](https://github.com/omarluq/termisu/graphs/contributors)--\u003e\n\n\u003cimg src=\"assets/termisu.png\" align=\"right\" alt=\"Termisu Logo\" width=\"200\"/\u003e\n\nTermisu _(/ˌtɛr.mɪˈsuː/ — like tiramisu, but for terminals)_ is a library that provides a sweet and minimalistic API for writing text-based user interfaces in pure Crystal. It offers an abstraction layer over terminal capabilities through cell-based rendering with double buffering, allowing efficient and flicker-free TUI development. The API is intentionally small and focused, making it easy to learn, test, and maintain. Inspired by termbox, Termisu brings similar simplicity and elegance to the Crystal ecosystem.\n\n\u003e [!WARNING]\n\u003e Termisu is still in development and is considered unstable. The API is subject to change, and you may encounter bugs or incomplete features.\n\u003e Use it at your own risk, and contribute by reporting issues or suggesting improvements!\n\n## Installation\n\n1. Add the dependency to your `shard.yml`:\n\n```yaml\ndependencies:\n  termisu:\n    github: omarluq/termisu\n```\n\n2. Run `shards install`\n\n## Usage\n\n```crystal\nrequire \"termisu\"\n\ntermisu = Termisu.new\n\nbegin\n  # Set cells with colors and attributes\n  termisu.set_cell(0, 0, 'H', fg: Termisu::Color.red, attr: Termisu::Attribute::Bold)\n  termisu.set_cell(1, 0, 'i', fg: Termisu::Color.green)\n  termisu.set_cursor(2, 0)\n  termisu.render\n\n  # Event loop with keyboard and mouse support\n  termisu.enable_mouse\n  loop do\n    if event = termisu.poll_event(100)\n      case event\n      when Termisu::Event::Key\n        break if event.key.escape?\n        break if event.key.lower_q?\n      when Termisu::Event::Mouse\n        termisu.set_cell(event.x, event.y, '*', fg: Termisu::Color.cyan)\n        termisu.render\n      end\n    end\n  end\nensure\n  termisu.close\nend\n```\n\nSee `examples/` for complete demonstrations:\n\n- `showcase.cr` - Colors, attributes, and input handling\n- `animation.cr` - Timer-based animation with async events\n\n![Termisu Showcase](assets/demo-screenshot.png)\n\n## API\n\n### Initialization\n\n```crystal\ntermisu = Termisu.new  # Enters raw mode + alternate screen\ntermisu.close          # Cleanup (always call in ensure block)\n```\n\n### Terminal\n\n```crystal\ntermisu.size                  # =\u003e {width, height}\ntermisu.alternate_screen?     # =\u003e true/false\ntermisu.raw_mode?             # =\u003e true/false\ntermisu.current_mode          # =\u003e Mode flags or nil\n```\n\n### Cell Buffer\n\n```crystal\ntermisu.set_cell(x, y, 'A', fg: Color.red, bg: Color.black, attr: Termisu::Attribute::Bold)\ntermisu.clear                 # Clear buffer\ntermisu.render                # Apply changes (diff-based)\ntermisu.sync                  # Force full redraw\n```\n\n### Cursor\n\n```crystal\ntermisu.set_cursor(x, y)\ntermisu.hide_cursor\ntermisu.show_cursor\n```\n\n### Events\n\n```crystal\n# Blocking\nevent = termisu.poll_event                # Block until event\nevent = termisu.wait_event                # Alias\n\n# With timeout\nevent = termisu.poll_event(100)           # Timeout (ms), nil on timeout\nevent = termisu.poll_event(100.milliseconds)\n\n# Non-blocking (select/else pattern)\nevent = termisu.try_poll_event            # Returns nil immediately if no event\n\n# Iterator\ntermisu.each_event do |event|\n  case event\n  when Termisu::Event::Key        then # keyboard\n  when Termisu::Event::Mouse      then # mouse click/move\n  when Termisu::Event::Resize     then # terminal resized\n  when Termisu::Event::Tick       then # timer tick (if enabled)\n  when Termisu::Event::ModeChange then # mode switched\n  end\nend\n```\n\n### Event Types\n\n`Event::Any` is the union type: `Event::Key | Event::Mouse | Event::Resize | Event::Tick | Event::ModeChange`\n\n```crystal\n# Event::Key - Keyboard input\nevent.key                          # =\u003e Input::Key\nevent.char                         # =\u003e Char?\nevent.modifiers                    # =\u003e Input::Modifier\nevent.ctrl? / event.alt? / event.shift? / event.meta?\n\n# Event::Mouse - Mouse input\nevent.x, event.y                   # Position (1-based)\nevent.button                       # =\u003e Mouse::Button\nevent.motion?                      # Mouse moved while button held\nevent.press?                       # Button press (not release/motion)\nevent.wheel?                       # Scroll wheel event\nevent.ctrl? / event.alt? / event.shift?\n\n# Mouse::Button enum\nevent.button.left?\nevent.button.middle?\nevent.button.right?\nevent.button.release?\nevent.button.wheel_up?\nevent.button.wheel_down?\n\n# Event::Resize - Terminal resized\nevent.width, event.height          # New dimensions\nevent.old_width, event.old_height  # Previous (nil if unknown)\nevent.changed?                     # Dimensions changed?\n\n# Event::Tick - Timer tick (for animations)\nevent.frame                        # Frame counter (UInt64)\nevent.elapsed                      # Time since timer started\nevent.delta                        # Time since last tick\nevent.missed_ticks                 # Ticks missed due to slow processing (UInt64)\n\n# Event::ModeChange - Terminal mode changed\nevent.mode                         # New mode (Terminal::Mode)\nevent.previous_mode                # Previous mode (Terminal::Mode?)\nevent.changed?                     # Did mode actually change?\nevent.to_raw?                      # Transitioning to raw mode?\nevent.from_raw?                    # Transitioning from raw mode?\nevent.to_user_interactive?         # Entering canonical/echo mode?\nevent.from_user_interactive?       # Leaving canonical/echo mode?\n```\n\n### Mouse \u0026 Keyboard\n\n```crystal\ntermisu.enable_mouse               # Enable mouse tracking\ntermisu.disable_mouse\ntermisu.mouse_enabled?\n\ntermisu.enable_enhanced_keyboard   # Kitty protocol (Tab vs Ctrl+I)\ntermisu.disable_enhanced_keyboard\ntermisu.enhanced_keyboard?\n```\n\n### Timer (for animations)\n\n```crystal\n# Sleep-based timer (portable, good for most use cases)\ntermisu.enable_timer(16.milliseconds)    # ~60 FPS tick events\n\n# Kernel-level timer (Linux timerfd/epoll, macOS kqueue)\n# More precise timing, better for high frame rates\ntermisu.enable_system_timer(16.milliseconds)\n\ntermisu.disable_timer                    # Disable either timer type\ntermisu.timer_enabled?\ntermisu.timer_interval = 8.milliseconds  # Change interval at runtime\n```\n\n#### Timer Comparison\n\n| Feature               | Timer (sleep)              | SystemTimer (kernel)                  |\n| --------------------- | -------------------------- | ------------------------------------- |\n| Mechanism             | `sleep` in fiber           | timerfd/epoll (Linux), kqueue (macOS) |\n| Precision             | ~1-2ms jitter              | Sub-millisecond                       |\n| Max FPS               | ~48 FPS reliable           | ~90 FPS reliable                      |\n| Missed tick detection | No                         | Yes (`event.missed_ticks`)            |\n| Portability           | All platforms              | Linux, macOS, BSD                     |\n| Best for              | Simple animations, low FPS | Games, smooth animations              |\n\n#### Benchmark Results\n\n| Target FPS | Target Interval | Timer (sleep)     | SystemTimer (kernel) | Notes                  |\n| ---------- | --------------- | ----------------- | -------------------- | ---------------------- |\n| 30         | 33ms            | ⚠️ 41ms (~24 FPS) | ✅ 33ms (~30 FPS)    | Sleep overshoots       |\n| 60         | 16ms            | ⚠️ 21ms (~48 FPS) | ✅ 17ms (~60 FPS)    | Sleep hits ~21ms floor |\n| 90         | 11ms            | ⚠️ 21ms (~48 FPS) | ✅ 11ms (~90 FPS)    | Sleep stuck at floor   |\n| 120        | 8ms             | ⚠️ 11ms (~91 FPS) | ⚠️ 11ms (~91 FPS)    | Both hit I/O ceiling   |\n| 144        | 7ms             | ⚠️ 11ms (~91 FPS) | ⚠️ 11ms (~91 FPS)    | Same ceiling           |\n\n**Key Findings:**\n\n- **SystemTimer accuracy:** Kernel timers hit target intervals precisely up to ~90 FPS\n- **Sleep timer quirks:** Has a ~21ms floor at mid-range targets, overshoots at low FPS\n- **Terminal I/O ceiling:** Both timers cap at ~91 FPS (~11ms) due to render/flush overhead\n- **Missed ticks:** SystemTimer detects and reports frame drops via `missed_ticks` field\n\n**Open Questions:**\n\n- Why does sleep timer overshoot at 30 FPS (41ms vs 33ms target)?\n- Can terminal I/O be batched more aggressively to push the ~91 FPS ceiling higher?\n- Would async rendering with double-buffered I/O help reduce the ~11ms floor?\n\n### Terminal Modes\n\nTemporarily switch terminal modes for shell-out, password input, or custom I/O.\nMode changes emit `Event::ModeChange` events and automatically coordinate with the event loop.\n\n```crystal\n# Shell-out: Exit TUI, run shell commands, return seamlessly\ntermisu.with_cooked_mode(preserve_screen: false) do\n  puts \"You're in the normal terminal!\"\n  system(\"vim file.txt\")\nend\n# TUI automatically restored with full redraw\n\n# Suspend alias (same as with_cooked_mode, preserve_screen: false)\ntermisu.suspend do\n  system(\"git commit\")\nend\n\n# Password input: Hidden typing (no echo)\ntermisu.with_password_mode do\n  print \"Password: \"\n  password = gets.try(\u0026.chomp)\nend\n\n# Cbreak mode: Character-by-character with echo (Ctrl+C works)\ntermisu.with_cbreak_mode do\n  print \"Press any key: \"\n  char = STDIN.read_char\nend\n\n# Custom mode with specific flags\ncustom = Termisu::Terminal::Mode::Echo | Termisu::Terminal::Mode::Signals\ntermisu.with_mode(custom, preserve_screen: true) do\n  # Your custom mode code\nend\n\n# Check current mode\ntermisu.current_mode  # =\u003e Mode flags or nil (raw mode)\n```\n\n#### Mode Flags\n\nIndividual flags map to POSIX termios settings:\n\n```crystal\nTermisu::Terminal::Mode::None             # Raw mode (no processing)\nTermisu::Terminal::Mode::Canonical        # Line-buffered input (ICANON)\nTermisu::Terminal::Mode::Echo             # Echo typed characters (ECHO)\nTermisu::Terminal::Mode::Signals          # Ctrl+C/Z signals (ISIG)\nTermisu::Terminal::Mode::Extended         # Extended input processing (IEXTEN)\nTermisu::Terminal::Mode::FlowControl      # XON/XOFF flow control (IXON)\nTermisu::Terminal::Mode::OutputProcessing # Output processing (OPOST)\nTermisu::Terminal::Mode::CrToNl           # CR to NL translation (ICRNL)\n\n# Combine flags with |\ncustom = Mode::Echo | Mode::Signals\n```\n\n#### Mode Presets\n\n```crystal\nMode.raw         # Full TUI control\nMode.cbreak      # Char-by-char with feedback\nMode.cooked      # Shell-out, external programs\nMode.full_cooked # Complete shell emulation\nMode.password    # Secure input (no echo)\nMode.semi_raw    # TUI with Ctrl+C support\n```\n\n| Preset      | Canonical | Echo | Signals | Use Case                     |\n| ----------- | --------- | ---- | ------- | ---------------------------- |\n| raw         | -         | -    | -       | Full TUI control             |\n| cbreak      | -         | ✓    | ✓       | Char-by-char with feedback   |\n| cooked      | ✓         | ✓    | ✓       | Shell-out, external programs |\n| full_cooked | ✓         | ✓    | ✓       | Complete shell emulation     |\n| password    | ✓         | -    | ✓       | Secure text entry            |\n| semi_raw    | -         | -    | ✓       | TUI with Ctrl+C support      |\n\n#### Convenience Methods\n\n```crystal\ntermisu.with_cooked_mode { }      # Shell-out mode\ntermisu.with_cbreak_mode { }      # Char-by-char with echo\ntermisu.with_password_mode { }    # Hidden input\ntermisu.suspend { }               # Alias for with_cooked_mode(preserve_screen: false)\ntermisu.with_mode(mode) { }       # Custom mode\n```\n\n#### Options\n\n- `preserve_screen: true` - Stay in alternate screen (overlay mode)\n- `preserve_screen: false` - Exit alternate screen (shell-out mode)\n\n### Colors\n\n```crystal\nColor.red, Color.green, Color.blue       # ANSI-8\nColor.bright_red, Color.bright_green     # Bright variants\nColor.ansi256(208)                       # 256-color palette\nColor.rgb(255, 128, 64)                  # TrueColor\nColor.from_hex(\"#FF8040\")                # Hex string\nColor.grayscale(12)                      # Grayscale (0-23)\n\ncolor.to_rgb                             # Convert to RGB\ncolor.to_ansi256                         # Convert to 256\ncolor.to_ansi8                           # Convert to 8\n```\n\n### Attributes\n\n```crystal\nTermisu::Attribute::None\nTermisu::Attribute::Bold\nTermisu::Attribute::Dim\nTermisu::Attribute::Cursive      # Italic\nTermisu::Attribute::Italic       # Alias for Cursive\nTermisu::Attribute::Underline\nTermisu::Attribute::Blink\nTermisu::Attribute::Reverse\nTermisu::Attribute::Hidden\nTermisu::Attribute::Strikethrough\n\n# Combine with |\nattr = Termisu::Attribute::Bold | Termisu::Attribute::Underline\nstrike = Termisu::Attribute::Strikethrough | Termisu::Attribute::Dim\n```\n\n### Keys\n\n```crystal\n# Key event properties\ncase event\nwhen Termisu::Event::Key\n  event.key                      # =\u003e Input::Key enum\n  event.char                     # =\u003e Char? (printable character)\n  event.modifiers                # =\u003e Input::Modifier flags\nend\n\n# Modifier checks (on Event::Key)\nevent.ctrl?                      # Ctrl held\nevent.alt?                       # Alt/Option held\nevent.shift?                     # Shift held\nevent.meta?                      # Meta/Super/Windows held\n\n# Common shortcuts\nevent.ctrl_c?\nevent.ctrl_d?\nevent.ctrl_q?\nevent.ctrl_z?\n\n# Check for any modifier\nevent.modifiers.none?            # No modifiers held\nevent.modifiers.ctrl?            # Direct modifier check\nevent.modifiers \u0026 Input::Modifier::Ctrl  # Bitwise check\n\n# Key matching - Special keys\nevent.key.escape?\nevent.key.enter?\nevent.key.tab?\nevent.key.back_tab?              # Shift+Tab\nevent.key.backspace?\nevent.key.space?\nevent.key.delete?\nevent.key.insert?\n\n# Key matching - Arrow keys\nevent.key.up?\nevent.key.down?\nevent.key.left?\nevent.key.right?\n\n# Key matching - Navigation\nevent.key.home?\nevent.key.end?\nevent.key.page_up?\nevent.key.page_down?\n\n# Key matching - Function keys (F1-F24)\nevent.key.f1?\nevent.key.f12?\n\n# Key matching - Letters\nevent.key.q?                     # Case-insensitive (a? - z?)\nevent.key.lower_q?               # Case-sensitive lowercase\nevent.key.upper_q?               # Case-sensitive uppercase\n\n# Key matching - Numbers\nevent.key.num_0?                 # num_0? - num_9?\n\n# Key predicates\nevent.key.letter?                # A-Z or a-z\nevent.key.digit?                 # 0-9\nevent.key.function_key?          # F1-F24\nevent.key.navigation?            # Arrows + Home/End/PageUp/PageDown\nevent.key.printable?             # Has character representation\nevent.key.to_char                # =\u003e Char? for printable keys\n```\n\n### Modifiers\n\n```crystal\nInput::Modifier::None\nInput::Modifier::Shift\nInput::Modifier::Alt             # Alt/Option\nInput::Modifier::Ctrl\nInput::Modifier::Meta            # Super/Windows\n\n# Combine with |\nmods = Input::Modifier::Ctrl | Input::Modifier::Shift\n\n# Check modifiers\nmods.ctrl?\nmods.shift?\nmods.alt?\nmods.meta?\n```\n\n## Roadmap\n\n**Current Status: v0.1.0 (async event system complete)**\n\n| Component            | Status      |\n| -------------------- | ----------- |\n| Terminal I/O         | ✅ Complete |\n| Terminfo             | ✅ Complete |\n| Double Buffering     | ✅ Complete |\n| Colors               | ✅ Complete |\n| Termisu::Attributes  | ✅ Complete |\n| Keyboard Input       | ✅ Complete |\n| Mouse Input          | ✅ Complete |\n| Event System         | ✅ Complete |\n| Async Event Loop     | ✅ Complete |\n| Resize Events        | ✅ Complete |\n| Timer/Tick Events    | ✅ Complete |\n| Terminal Modes       | ✅ Complete |\n| Synchronized Updates | ✅ Complete |\n| Unicode/Wide Chars   | ✅ Complete |\n\n### Completed\n\n- **Terminal I/O** - Raw mode, alternate screen, EINTR handling\n- **Terminfo** - Binary parser (16/32-bit), 414 capabilities, builtin fallbacks\n- **Double Buffering** - Diff-based rendering, cell batching, state caching\n- **Colors** - ANSI-8, ANSI-256, RGB/TrueColor with conversions\n- **Termisu::Attributes** - Bold, underline, blink, reverse, dim, italic, hidden, strikethrough\n- **Keyboard Input** - 170+ keys, F1-F24, modifiers (Ctrl/Alt/Shift/Meta)\n- **Mouse Input** - SGR (mode 1006), normal (mode 1000), motion events\n- **Event System** - Unified Key/Mouse events, Kitty protocol, modifyOtherKeys\n- **Async Event Loop** - Crystal fiber/channel-based multiplexer\n- **Resize Events** - SIGWINCH-based with debouncing\n- **Timer Events** - Sleep-based and kernel-level (timerfd/kqueue) timers\n- **Terminal Modes** - Cooked, cbreak, password modes with seamless TUI restoration\n- **Performance** - RenderState optimization, escape sequence batching\n- **Terminfo tparm** - Full processor with conditionals, stack, variables\n- **Logging** - Structured async/sync dispatch, zero hot-path overhead\n- **Synchronized Updates** - DEC mode 2026 (prevents screen tearing)\n- **Unicode/wide character support** - CJK, emoji (wcwidth)\n\n### Planned\n\n- **Image protocols** - Sixel and Kitty graphics for inline images\n\n## Inspiration\n\nTermisu is inspired by and follows some of the design philosophy of:\n\n- [nsf/termbox](https://github.com/nsf/termbox) - The original termbox library\n- [nsf/termbox-go](https://github.com/nsf/termbox-go) - Go implementation of termbox\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.\n\n1. Fork it (\u003chttps://github.com/omarluq/termisu/fork\u003e)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## Contributors\n\n- [omarluq](https://github.com/omarluq) - creator and maintainer\n\n## License\n\nThe shard is available as open source under the terms of the [MIT License](LICENSE.txt).\n\n## Code of conduct\n\nEveryone interacting in this project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fomarluq%2Ftermisu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fomarluq%2Ftermisu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fomarluq%2Ftermisu/lists"}