{"id":32173161,"url":"https://github.com/ndreynolds/ex_termbox","last_synced_at":"2026-02-20T16:01:34.520Z","repository":{"id":40605259,"uuid":"119096006","full_name":"ndreynolds/ex_termbox","owner":"ndreynolds","description":"Low-level termbox bindings for Elixir","archived":false,"fork":false,"pushed_at":"2023-05-14T07:04:37.000Z","size":136,"stargazers_count":57,"open_issues_count":10,"forks_count":21,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-21T18:51:23.455Z","etag":null,"topics":["elixir","termbox","terminal-ui"],"latest_commit_sha":null,"homepage":"","language":"Elixir","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/ndreynolds.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-26T19:47:15.000Z","updated_at":"2025-03-29T14:29:44.000Z","dependencies_parsed_at":"2022-09-04T11:20:54.445Z","dependency_job_id":null,"html_url":"https://github.com/ndreynolds/ex_termbox","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ndreynolds/ex_termbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndreynolds%2Fex_termbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndreynolds%2Fex_termbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndreynolds%2Fex_termbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndreynolds%2Fex_termbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ndreynolds","download_url":"https://codeload.github.com/ndreynolds/ex_termbox/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndreynolds%2Fex_termbox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29656589,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T09:27:29.698Z","status":"ssl_error","status_checked_at":"2026-02-20T09:26:12.373Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6: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":["elixir","termbox","terminal-ui"],"created_at":"2025-10-21T18:50:02.204Z","updated_at":"2026-02-20T16:01:34.506Z","avatar_url":"https://github.com/ndreynolds.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ExTermbox\n\n[![Hex.pm](https://img.shields.io/hexpm/v/ex_termbox.svg)](https://hex.pm/packages/ex_termbox)\n[![Hexdocs.pm](https://img.shields.io/badge/api-hexdocs-brightgreen.svg)](https://hexdocs.pm/ex_termbox)\n[![Travis CI](https://img.shields.io/travis/ndreynolds/ex_termbox/master.svg)](https://travis-ci.org/ndreynolds/ex_termbox)\n\nLow-level [termbox](https://github.com/nsf/termbox) bindings for Elixir.\n\nFor high-level, declarative terminal UIs in Elixir, see\n[Ratatouille](https://github.com/ndreynolds/ratatouille). It builds on top of\nthis library and the termbox API to provide an HTML-like DSL for defining views.\n\nFor the API Reference, see: [https://hexdocs.pm/ex_termbox](https://hexdocs.pm/ex_termbox).\n\n## Getting Started\n\n### Termbox bindings\n\nExTermbox implements the termbox API functions via NIFs:\n\n* [`ExTermbox.Bindings`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html)\n  * [`init/0`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#init/0)\n  * [`shutdown/0`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#shutdown/0)\n  * [`width/0`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#width/0)\n  * [`height/0`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#height/0)\n  * [`clear/0`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#clear/0)\n  * [`present/0`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#present/0)\n  * [`put_cell/1`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#put_cell/1)\n  * [`change_cell/5`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#change_cell/5)\n  * [`poll_event/1`](https://hexdocs.pm/ex_termbox/ExTermbox.Bindings.html#poll_event/1)\n\n### Hello World\n\nLet's go through the bundled [hello world example](./examples/hello_world.exs).\nTo follow along, clone this repo and edit the example.\n\nThis repository makes use of [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules), so make sure you include them in your clone. In recent versions of git, this can be accomplished by including the `--recursive` flag, e.g.\n\n```bash\ngit clone --recursive git@github.com:ndreynolds/ex_termbox.git\n```\n\nWhen the clone is complete, the `c_src/termbox/` directory should have files in it.\n\nYou can also create an\nElixir script in any Mix project with `ex_termbox` in the dependencies list.\nLater, we'll run the example with `mix run \u003cfile\u003e`.\n\nIn a real project, you'll probably want to use an OTP application with a proper\nsupervision tree, but here we'll keep it as simple as possible.\n\nFirst, some aliases for the modules we'll use.\n\n```elixir\nalias ExTermbox.Bindings, as: Termbox\nalias ExTermbox.{Cell, EventManager, Event, Position}\n```\n\nNext, we initialize the termbox application. This initialization should come\nbefore any other termbox functions are called. (Otherwise, your program will\nprobably crash.)\n\n```elixir\n:ok = Termbox.init()\n```\n\nIn order to react to keyboard, click or resize events later, we need to start\nthe event manager and subscribe the current process to any events. The event\nmanager is an abstraction over `poll_event/1` that constantly polls for events\nand notifies its subscribers whenever one is received.\n\n```elixir\n{:ok, _pid} = EventManager.start_link()\n:ok = EventManager.subscribe(self())\n```\n\nTo render content to the screen, we use `put_cell/1`. We pass it\n`%Cell{}` structs that each have a `position` and a `ch`.\n\nThe `position` is a struct representing an (x, y) cartesian coordinate. The\ntop-left-most cell of the screen represents the origin (0, 0).\n\nThe `ch` should be an integer representing the character (e.g., ?a or 97).\nIn the example, we're using charlists for this reason.\n\n```elixir\nfor {ch, x} \u003c- Enum.with_index('Hello, World!') do\n  :ok = Termbox.put_cell(%Cell{position: %Position{x: x, y: 0}, ch: ch})\nend\n\nfor {ch, x} \u003c- Enum.with_index('(Press \u003cq\u003e to quit)') do\n  :ok = Termbox.put_cell(%Cell{position: %Position{x: x, y: 2}, ch: ch})\nend\n```\n\nSince Elixir is a functional language, it's good practice to avoid this sort of\nimperative style in real applications. Instead, you might build and transform a\ncanvas defined as map or list of cells. Then, when your canvas is ready for\nrendering, it can be synced to termbox via `put_cell/1` in one sweep. This is\nhow the Ratatouille library works.\n\nUntil now, we've only updated termbox's internal buffer. To actually render the\ncontent to the screen, we need to call `present/0`:\n\n```elixir\nTermbox.present()\n```\n\nWhen a key is pressed, it'll be sent to us by the event manager. Once we receive\na 'q' key press, we'll shut down the application.\n\n```elixir\nreceive do\n  {:event, %Event{ch: ?q}} -\u003e\n    :ok = Termbox.shutdown()\nend\n```\n\nYou can use this event-handling logic to respond to events any way you\nlike---e.g., render different content, switch tabs, resize content, etc.\n\nFinally, run the example like this:\n\n```bash\n$ mix run examples/hello_world.exs\n```\n\nYou shuld see the text we rendered and be able to quit with 'q'.\n\n## Installation\n\n### From Hex\n\nAdd ExTermbox as a dependency in your project's `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:ex_termbox, \"~\u003e 0.3\"}\n  ]\nend\n```\n\nThe Hex package bundles a compatible version of termbox. There are some compile\nhooks to automatically build and link a local copy of `ltermbox` for your\napplication. This should happen the first time you build ExTermbox (e.g., via\n`mix deps.compile`).\n\nSo far the build has been tested on macOS and a few Linux distros. Please add\nan issue if you encounter any problems with the build.\n\n### From Source\n\nTo try out the master branch, first clone the repo:\n\n```bash\ngit clone --recurse-submodules https://github.com/ndreynolds/ex_termbox.git\ncd ex_termbox\n```\n\nThe `--recurse-submodules` flag (`--recursive` before Git 2.13) is necessary in\norder to additionally clone the termbox source code, which is required to\nbuild this project.\n\nNext, fetch the deps:\n\n```\nmix deps.get\n```\n\nFinally, try out the included event viewer application:\n\n```\nmix run examples/event_viewer.exs\n```\n\nIf you see the application drawn and can trigger events, you're good to go. Use\n'q' to quit the examples.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fndreynolds%2Fex_termbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fndreynolds%2Fex_termbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fndreynolds%2Fex_termbox/lists"}