{"id":18046725,"url":"https://github.com/icy-arctic-fox/espresso","last_synced_at":"2025-04-10T04:53:49.429Z","repository":{"id":44587862,"uuid":"195872758","full_name":"icy-arctic-fox/espresso","owner":"icy-arctic-fox","description":"Lightweight wrapper around GLFW for Crystal","archived":false,"fork":false,"pushed_at":"2022-04-10T16:13:01.000Z","size":436,"stargazers_count":16,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T06:05:00.699Z","etag":null,"topics":["crystal","glfw","glfw-bindings","glfw3","opengl"],"latest_commit_sha":null,"homepage":"https://gitlab.com/arctic-fox/espresso","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/icy-arctic-fox.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2019-07-08T19:19:28.000Z","updated_at":"2024-12-14T21:33:19.000Z","dependencies_parsed_at":"2022-09-25T00:51:22.013Z","dependency_job_id":null,"html_url":"https://github.com/icy-arctic-fox/espresso","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icy-arctic-fox%2Fespresso","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icy-arctic-fox%2Fespresso/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icy-arctic-fox%2Fespresso/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icy-arctic-fox%2Fespresso/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/icy-arctic-fox","download_url":"https://codeload.github.com/icy-arctic-fox/espresso/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248161255,"owners_count":21057553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","glfw","glfw-bindings","glfw3","opengl"],"created_at":"2024-10-30T19:08:50.030Z","updated_at":"2025-04-10T04:53:49.390Z","avatar_url":"https://github.com/icy-arctic-fox.png","language":"Crystal","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Espresso\n\nLightweight wrapper around GLFW for Crystal.\nProvides an OOP and \"Crystal-like\" interface to GLFW.\n\n## Installation\n\n1. Add the dependency to your `shard.yml`:\n\n```yaml\ndependencies:\n  espresso:\n    gitlab: arctic-fox/espresso\n```\n\n2. Run `shards install`\n\n3. Make sure you have GLFW 3.3 installed to your system.\n\n### Install GLFW 3.3\n\nDownload the packages from [GLFW's website](https://www.glfw.org/download.html)\nor compile from source.\n\nIf you're on Linux or MacOS, and want to build from source,\nrun `./install-glfw.sh` with sudo in this directory.\nYou will need [CMake](https://cmake.org/), git, and a C compiler installed.\nYou will probably also need Xorg development libraries.\nOn Ubuntu, those can be installed with `apt-get install xorg-dev`.\n\n## Usage\n\nHere's an example of displaying a window:\n\n```crystal\nrequire \"espresso\"\n\nEspresso.run do\n  Espresso::Window.open(800, 600, \"Espresso\") do |window|\n    until window.closing?\n      window.swap_buffers\n      Espresso::Window.poll_events\n    end\n  end\nend\n```\n\nGLFW must be initialized before most of its operations can be performed.\nThe best way to do this is by using\n[`Espresso.run`](https://arctic-fox.gitlab.io/espresso/Espresso.html#run%28joystick_hat_buttons%3ABool%3F%3Dnil%2Ccocoa_chdir_resources%3ABool%3F%3Dnil%2Ccocoa_menubar%3ABool%3F%3Dnil%2C%26block%29-instance-method),\nlike so:\n\n```crystal\nEspresso.run do\n  # Use GLFW here.\nend\n```\n\nGLFW will be initialized before calling the block,\nand terminated after the block is done.\n\nAlternatively,\n[`Espresso.init`](https://arctic-fox.gitlab.io/espresso/Espresso.html#init%28joystick_hat_buttons%3ABool%3F%3Dnil%2Ccocoa_chdir_resources%3ABool%3F%3Dnil%2Ccocoa_menubar%3ABool%3F%3Dnil%29%3ANil-instance-method)\nand\n[`Espresso.terminate`](https://arctic-fox.gitlab.io/espresso/Espresso.html#terminate%3ANil-instance-method)\ncan be used,\nbut you are responsible for ensuring they get called correctly.\n\nMost of the functions from GLFW are wrapped by instance methods.\nThey are placed into a type that corresponds with their purpose.\n\nFor example, functions in GLFW that would normally take a monitor pointer as the first argument,\nare now instances methods in a [`Monitor`](https://arctic-fox.gitlab.io/espresso/Espresso/Monitor.html) struct.\n\n```crystal\nmonitor = Monitor.primary\nputs monitor.name\n```\n\nis equivalent to the C code:\n\n```c\nGLFWmonitor *monitor = glfwGetPrimaryMonitor();\nprintf(\"%s\\n\", glfwGetMonitorName(monitor));\n```\n\nAdditionally, the pointer is the only instance variable in the struct.\n\nWhen compiled, this indirection is removed, so it's as fast as calling the method itself.\nThis provides a friendlier object-oriented approach without sacrificing speed.\n\n### Windows\n\nWindows are the biggest part of GLFW.\nAs such, there is a lot of functionality put behind them.\nThe easiest way to get a window in Espresso, is to call\n[`Window.open`](https://arctic-fox.gitlab.io/espresso/Espresso/Window.html#open%28width%3AInt32%2Cheight%3AInt32%2Ctitle%3AString%2C%26block%29-class-method)\nor\n[`Window.full_screen`](https://arctic-fox.gitlab.io/espresso/Espresso/Window.html#full_screen%28title%3AString%2C%26block%29-class-method).\nA block can be provided to these methods.\nWhen present, Espresso will automatically make the window's context current and ensure proper cleanup of its resources.\nWithout a block, use\n[`Window.new`](https://arctic-fox.gitlab.io/espresso/Espresso/Window.html#new%28width%3AInt32%2Cheight%3AInt32%2Ctitle%3AString%29-class-method)\nor\n[`Window.full_screen`](https://arctic-fox.gitlab.io/espresso/Espresso/Window.html#full_screen%28title%3AString%29-class-method).\nThese methods simply return a [`Window`](https://arctic-fox.gitlab.io/espresso/Espresso/Window.html) instance.\n\n```crystal\n# For windowed mode.\nEspresso::Window.open(800, 600, \"Espresso\") do\n  # Use the window here.\nend\n\n# For full-screen mode.\nEspresso::Window.full_screen(\"Espresso\") do\n  # Use the window here.\nend\n\n# Alternatively, without the block form:\nwindow = Espresso::Window.new(800, 600, \"Espresso\")\n# or for full screen...\nwindow = Espresso::Window.full_screen(\"Espresso\")\n# Make sure to set the context and destroy when done.\nwindow.current!\nwindow.destroy!\n```\n\nYou may want to customize the window before creating it.\nTo do so, use [`WindowBuilder`](https://arctic-fox.gitlab.io/espresso/Espresso/WindowBuilder.html).\nUse one of the `build_*` methods to create the window.\n\n```crystal\nbuilder = Espresso::WindowBuilder.new\nbuilder.context_version(3, 3)\nbuilder.resizable = false\nwindow = builder.build(800, 600, \"Espresso\")\n```\n\n### Input\n\nMost input types are tied to GLFW windows.\nTo access them, use\n[`Window#mouse`](https://arctic-fox.gitlab.io/espresso/Espresso/Window.html#mouse-instance-method) and\n[`Window#keyboard`](https://arctic-fox.gitlab.io/espresso/Espresso/Window.html#keyboard-instance-method).\nFor joystick input, use the [`Joystick`](https://arctic-fox.gitlab.io/espresso/Espresso/Joystick.html)\ntype, since it isn't tied to a window.\n\n### Events\n\nIf you're familiar with how GLFW handles events,\nyou'll know that it uses callbacks like `glfwSetKeyCallback`.\nHowever, Espresso changes how event callbacks are exposed.\nInstead of setting a single callback for an event, Espresso allows setting multiple.\nAdditionally, native blocks and closures can be used (which isn't allowed with normal C callbacks).\nRegistering an event listener in Espresso is as easy as passing a  block to any `#on_*` method.\n\n```crystal\nwindow.keyboard.on_key do |event|\n  # The `event` argument contains all event information.\n  puts \"Key #{event.pressed? ? \"pressed\" : \"released\"} #{event.key}\"\nend\n```\n\nTo remove a callback at a later point in time, call the corresponding `#remove_*_listener`.\nThe `#on_*` method returns a proc, which needs to be passed to the `#remove_*_listener`.\nRemoving a listener is optional - they will automatically be cleaned up when the resource they're tied to is destroyed.\n\n```crystal\nproc = window.keyboard.on_key do |event|\n  # ...\nend\n\n# ...\n\nwindow.keyboard.remove_key_listener(proc)\n```\n\nEvents are typically tied to an instance, but some events aren't (or can't be) tied to an instance.\nThose exceptions are the `#on_connect` events for monitors and joysticks.\nListeners can be set up for disconnect of all monitors and joysticks, or just one instance.\n\n```crystal\nEspresso::Monitor.on_connect do |monitor|\n  if event.connected?\n    # New monitor connected.\n  else\n    # Monitor disconnected.\n  end\nend\n\n# The instance-specific variant.\n# This is only invoked for the monitor instance it is associated with.\nmonitor = Espresso::Monitor.primary\nmonitor.on_disconnect do |monitor|\n  # Called when the primary monitor is disconnected.\nend\n```\n\n### Errors\n\nGLFW errors have been changed to exceptions in Espresso.\nAll calls that could possibly cause an error are wrapped and checks handled by Espresso.\nIf GLFW reports an error, it will be raised from within Espresso (as to not break out of the stack).\nAll errors inherit from a base [`GLFWError`](https://arctic-fox.gitlab.io/espresso/Espresso/GLFWError.html) class.\n\n```crystal\nbegin\n  window.resize(800, 600)\nrescue ex : Espresso::PlatformError\n  # Handle error.\nend\n```\n\n## Documentation\n\nDocumentation is automatically generated and published [here](https://arctic-fox.gitlab.io/espresso/).\nThe primary pages you will be interested in are:\n\n- [Espresso](https://arctic-fox.gitlab.io/espresso/Espresso.html)\n- [Window](https://arctic-fox.gitlab.io/espresso/Espresso/Window.html)\n- [WindowBuilder](https://arctic-fox.gitlab.io/espresso/Espresso/WindowBuilder.html)\n- [Keyboard](https://arctic-fox.gitlab.io/espresso/Espresso/Keyboard.html)\n- [Mouse](https://arctic-fox.gitlab.io/espresso/Espresso/Mouse.html)\n- [Joystick](https://arctic-fox.gitlab.io/espresso/Espresso/Joystick.html)\n- [Monitor](https://arctic-fox.gitlab.io/espresso/Espresso/Monitor.html)\n\n## Development\n\n[Ameba](https://github.com/veelenga/ameba) is used for linting.\nThe CI build ensures that proper formatting and style is applied.\n\nA docker image is generated to run tests in.\nIt runs Ubuntu 18 and installs Crystal, GLFW, and everything else needed for simulating an environment.\nSpecs are run in the docker container as part of the CI build.\nDue to the difficulty, writing tests is not required, but encouraged if it can be done.\nSpecs might not pass on your system, but should pass in the docker container.\n\n## Contributing\n\n1. Fork it (\u003chttps://gitlab.com/arctic-fox/espresso/forks/new\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 Merge Request\n\n## Contributors\n\n- [Michael Miller](https://gitlab.com/arctic-fox) - creator and maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficy-arctic-fox%2Fespresso","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficy-arctic-fox%2Fespresso","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficy-arctic-fox%2Fespresso/lists"}