{"id":28637734,"url":"https://github.com/jonasgeiler/lua-fenster","last_synced_at":"2025-06-12T18:33:27.309Z","repository":{"id":231892991,"uuid":"643648746","full_name":"jonasgeiler/lua-fenster","owner":"jonasgeiler","description":"📚 The most minimal cross-platform GUI library - now in Lua!","archived":false,"fork":false,"pushed_at":"2025-06-06T21:25:49.000Z","size":508,"stargazers_count":41,"open_issues_count":3,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-06T21:57:42.275Z","etag":null,"topics":["cross-platform-gui","fenster","framebuffer","graphics","graphics-programming","gui","gui-framework","gui-library","library","lua","lua-fenster","luajit","minifb","pixels","raylib","softbuffer","ui","user-interface","window","windowing"],"latest_commit_sha":null,"homepage":"https://zserge.com/posts/fenster/","language":"C","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/jonasgeiler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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},"funding":{"github":"jonasgeiler","ko_fi":"jonasgeiler","liberapay":"jonasgeiler"}},"created_at":"2023-05-21T20:25:29.000Z","updated_at":"2025-05-25T15:45:29.000Z","dependencies_parsed_at":"2024-04-06T16:28:31.219Z","dependency_job_id":"01e4e815-0302-42b5-ad5c-bd5bf5cb4edc","html_url":"https://github.com/jonasgeiler/lua-fenster","commit_stats":null,"previous_names":["jonasgeiler/lua-fenster"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/jonasgeiler/lua-fenster","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonasgeiler%2Flua-fenster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonasgeiler%2Flua-fenster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonasgeiler%2Flua-fenster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonasgeiler%2Flua-fenster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonasgeiler","download_url":"https://codeload.github.com/jonasgeiler/lua-fenster/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonasgeiler%2Flua-fenster/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259519264,"owners_count":22870328,"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":["cross-platform-gui","fenster","framebuffer","graphics","graphics-programming","gui","gui-framework","gui-library","library","lua","lua-fenster","luajit","minifb","pixels","raylib","softbuffer","ui","user-interface","window","windowing"],"created_at":"2025-06-12T18:33:27.185Z","updated_at":"2025-06-12T18:33:27.270Z","avatar_url":"https://github.com/jonasgeiler.png","language":"C","readme":"# lua-fenster\n\n\u003e The most minimal cross-platform GUI library - now in Lua!\n\n[![LuaRocks](https://img.shields.io/luarocks/v/jonasgeiler/fenster?style=for-the-badge\u0026color=%232c3e67)](https://luarocks.org/modules/jonasgeiler/fenster)\n[![Downloads](https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Fluarocks.org%2Fmodules%2Fjonasgeiler%2Ffenster\u0026query=%2F%2Fdiv%5B%40class%3D%22metadata_columns_inner%22%5D%2Fdiv%5B%40class%3D%22column%22%5D%5Blast()%5D%2Ftext()\u0026style=for-the-badge\u0026label=Downloads\u0026color=099dff\u0026cacheSeconds=86400)](https://luarocks.org/modules/jonasgeiler/fenster)\n[![Projects using lua-fenster](https://img.shields.io/badge/2%2B-2c3e67?style=for-the-badge\u0026label=Projects%20using%20lua-fenster)](#projects-using-lua-fenster)\n[![License](https://img.shields.io/github/license/jonasgeiler/lua-fenster?style=for-the-badge\u0026color=%23099dff)](./LICENSE.md)\n\nA Lua binding for the [fenster](https://github.com/zserge/fenster) GUI library,\nproviding the most minimal and highly opinionated way to display a\ncross-platform 2D canvas. It's basic idea is giving you the simplest means\npossible to \"just put pixels on the screen\" without any of the fancy stuff. As a\nnice bonus you also get cross-platform keyboard/mouse input and frame timing in\nonly a few lines of code.\n\nRead more about the idea behind fenster here:\n[Minimal cross-platform graphics - zserge.com](https://zserge.com/posts/fenster/)\n\n\u003e [!NOTE]\n\u003e This library is primarily intended for educational and prototyping purposes\n\u003e and may not include all the features you would expect from a proper GUI\n\u003e library. If you're looking for something more feature-rich and\n\u003e production-ready, you might want to check out [LÖVE](https://love2d.org/)\n\u003e or [raylib](https://www.raylib.com/).\n\n## Installation\n\nFrom LuaRocks server:\n\n```shell\nluarocks install fenster\n```\n\nFrom source:\n\n```shell\ngit clone https://github.com/jonasgeiler/lua-fenster.git\ncd lua-fenster\nluarocks make\n```\n\n## Simple Example\n\nHere is a simple example that opens a 500x300 window, draws a red rectangle and\nexits when pressing the Escape key:\n\n```lua\n-- rectangle.lua\nlocal fenster = require('fenster')\n\nlocal window = fenster.open(500, 300, 'Hello fenster!')\n\nwhile window:loop() and not window.keys[27] do\n\twindow:clear()\n\n\tfor y = 100, 200 do\n\t\tfor x = 200, 300 do\n\t\t\twindow:set(x, y, 0xff0000)\n\t\tend\n\tend\nend\n```\n\nTo run the example:\n\n```shell\nlua rectangle.lua\n```\n\nHere is what you should see:\n\n![rectangle screenshot](https://github.com/jonasgeiler/lua-fenster/assets/10259118/7c9e495e-409b-4b3b-b232-c20da1ebfc88)\n\n## Demos\n\nCheck out the [./demos](./demos) folder for more elaborate example applications!  \nTo run a demo use:\n\n```shell\nlua demos/\u003cdemo\u003e.lua\n```\n\nSome of the demos are user-contributed. If you have a demo you'd like to share,\nfeel free to [create a pull request](https://github.com/jonasgeiler/lua-fenster/new/main/demos)!\n\n## Useful Snippets\n\nI have compiled a collection of useful snippets in\n[this discussion (#11)](https://github.com/jonasgeiler/lua-fenster/discussions/11).  \nCheck them out and maybe add your own!\n\n## Type Definitions\n\nI have created type definitions for lua-fenster for the\n[Teal Programming Language](https://github.com/teal-language/tl) and\n[Sumneko's Lua Language Server](https://github.com/LuaLS/lua-language-server).\nYou can find the Teal type definitions in the\n[teal-language/teal-types](https://github.com/teal-language/teal-types/tree/master/types/fenster)\nrepository and the Lua Language Server type definitions in the\n[LuaLS/LLS-Addons](https://github.com/LuaLS/LLS-Addons/tree/main/addons/fenster)\nrepository.\nConsult their respective documentation on how to use these type definitions in\nyour projects.\n\n## Projects using lua-fenster\n\nHere is a list of projects that use lua-fenster:\n\n- [3d-soft-engine-lua](https://github.com/jonasgeiler/3d-soft-engine-lua) - A simple 3D engine, by [Jonas Geiler (@jonasgeiler)](https://github.com/jonasgeiler).\n- [3d-raycaster-lua](https://github.com/jonasgeiler/3d-raycaster-lua) - A Wolfenstein-like 3D raycaster, by [Jonas Geiler (@jonasgeiler)](https://github.com/jonasgeiler).\n\n\u003c!--\nIf you want to add your own projects here, please format the entries as follows,\nincluding the extra newline between each entry:\n\n- [Name](Link) - Description, by Author.\n\n- [Name](Link) - Description, by [Full Name (@Username)](https://github.com/Username).\n\n- [Name](Link) - Description, by [@Username](https://github.com/Username).\n\n--\u003e\n\nFeel free to add your own projects to this list by [creating a pull request](https://github.com/jonasgeiler/lua-fenster/edit/main/README.md)!\n\n## API Documentation\n\nHere is a documentation of all functions, methods and properties provided by the\nfenster Lua module:\n\n- [`fenster.open(width: integer, height: integer, title: string | nil, scale: integer | nil, targetfps: number | nil): userdata`](#fensteropenwidth-integer-height-integer-title-string--nil-scale-integer--nil-targetfps-number--nil-userdata)\n\n- [`fenster.sleep(milliseconds: integer)`](#fenstersleepmilliseconds-integer)\n\n- [`fenster.time(): integer`](#fenstertime-integer)\n\n- [`fenster.rgb(redorcolor: integer, green: integer | nil, blue: integer | nil): integer, integer | nil, integer | nil`](#fensterrgbredorcolor-integer-green-integer--nil-blue-integer--nil-integer-integer--nil-integer--nil)\n\n- [`window:close()`](#windowclose)\n\n- [`window:loop()`](#windowloop-boolean)\n\n- [`window:set(x: integer, y: integer, color: integer)`](#windowsetx-integer-y-integer-color-integer)\n\n- [`window:get(x: integer, y: integer): integer`](#windowgetx-integer-y-integer-integer)\n\n- [`window:clear(color: integer | nil)`](#windowclearcolor-integer--nil)\n\n- [`window.keys: boolean[]`](#windowkeys-boolean)\n\n- [`window.delta: number`](#windowdelta-number)\n\n- [`window.mousex: integer`](#windowmousex-integer)\n\n- [`window.mousey: integer`](#windowmousey-integer)\n\n- [`window.mousedown: boolean`](#windowmousedown-boolean)\n\n- [`window.modcontrol: boolean`](#windowmodcontrol-boolean)\n\n- [`window.modshift: boolean`](#windowmodshift-boolean)\n\n- [`window.modalt: boolean`](#windowmodalt-boolean)\n\n- [`window.modgui: boolean`](#windowmodgui-boolean)\n\n- [`window.width: integer`](#windowwidth-integer)\n\n- [`window.height: integer`](#windowheight-integer)\n\n- [`window.title: string`](#windowtitle-string)\n\n- [`window.scale: integer`](#windowscale-integer)\n\n- [`window.targetfps: number`](#windowtargetfps-number)\n\n### `fenster.open(width: integer, height: integer, title: string | nil, scale: integer | nil, targetfps: number | nil): userdata`\n\nThis function is used to create a new window for your application.\n\n**Parameters:**\n\n- `width` (integer): The width of the window in pixels.\n\n- `height` (integer): The height of the window in pixels.\n\n- `title` (string, optional): The title of the window. If not provided, the\n  default title 'fenster' will be used.\n\n- `scale` (integer, optional): The scale factor for the window. This should be a\n  power of 2 (e.g., 1, 2, 4, 8). If not provided, the default scale factor of 1\n  will be used. This means that each pixel in your application corresponds to\n  one pixel on the screen. A scale factor of 2 would mean that each pixel in\n  your application corresponds to a 2x2 square of pixels on the screen, and so\n  on. The scaling happens completely internally, and you won't have to worry\n  about it in your code. It is just a way to make your application more visible\n  on high-resolution screens without sacrificing performance.\n\n- `targetfps` (number, optional): The target frames per second (FPS) for the\n  window. If not provided, the default target FPS of 60 will be used. This is\n  used to limit the CPU usage of your application and get more consistent frame\n  durations by pausing for a short time after each frame to reach the target\n  FPS. You can set it to 0 to disable FPS handling and let your application run\n  as fast as possible, but generally, you should keep it at the default value of\n  60 FPS.\n\n**Returns:**\n\nAn userdata object representing the created window. This object can be used to\ninteract with the window, such as drawing pixels, handling input, and\nreading the window's properties.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Create a new window with a width of 500 pixels, a height of 300 pixels, a title of 'My Application', a scale factor of 2, and a target FPS of 60.\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n```\n\n### `fenster.sleep(milliseconds: integer)`\n\nThis utility function is used to pause the program execution for a specified\namount of time.\n\n**Parameters:**\n\n- `milliseconds` (integer): The amount of time, in milliseconds, for which the\n  program execution should be paused.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Pause the program execution for 2 seconds (2000 milliseconds)\nfenster.sleep(2000)\n```\n\n### `fenster.time(): integer`\n\nThis utility function is used to get the current time in milliseconds since the\nUnix epoch (January 1, 1970). This is similar to `os.time()`, but with\nmilliseconds instead of seconds.\n\n**Returns:**\n\nThe current time in milliseconds since the Unix epoch as an integer.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Get the current time in milliseconds\nlocal time = fenster.time()\n```\n\n### `fenster.rgb(redorcolor: integer, green: integer | nil, blue: integer | nil): integer, integer | nil, integer | nil`\n\nThis utility function is used to convert RGB values to a single color integer or\nvice versa.\n\n**Parameters:**\n\n- `redorcolor` (integer): If only one argument is given, it is assumed to be a\n  color integer and the function returns the red, green and blue components as\n  separate values. If three arguments are given, this represents the red\n  component of the color.\n\n- `green` (integer, optional): The green component of the color. This is\n  required if `redorcolor` is the red component.\n\n- `blue` (integer, optional): The blue component of the color. This is required\n  if `redorcolor` is the red component.\n\n**Returns:**\n\n- If only `redorcolor` is provided, the function returns three integers\n  representing the red, green, and blue components of the color.\n- If `redorcolor`, `green`, and `blue` are provided, the function returns a\n  single integer representing the color.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Convert RGB values to a single color integer\nlocal color = fenster.rgb(255, 0, 0) -- Returns: 0xff0000 (16711680 in decimal)\n\n-- Convert a single color integer to RGB values\nlocal red, green, blue = fenster.rgb(0xff0000) -- Returns: 255, 0, 0\n```\n\n### `window:close()`\n\nThis method is used to close a window that was previously opened\nwith `fenster.open`.\nThe `__gc` and `__close` (Lua 5.4) metamethods call this function internally to\nautomatically close the window when it goes out of scope, so you won't\nhave to call this function manually in most cases.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Close the window immediately\nwindow:close()\n```\n\n**Note:**\n\nIn Lua 5.4 you can use\n[local variable attributes](https://www.lua.org/manual/5.4/manual.html#3.3.8)\nto immediately close the window when the `window` variable goes out of scope:\n\n```lua\nlocal fenster = require('fenster')\n\nfunction main()\n  -- Open a new window (note the \u003cclose\u003e attribute!)\n  local window \u003cclose\u003e = fenster.open(500, 300, 'My Application', 2, 60)\n\n  -- The window will be immediately closed when this function returns\n  -- (Normally, garbage collection will also close the window but only at an\n  -- undetermined time later on)\nend\n```\n\n### `window:loop(): boolean`\n\nThis method is used to handle the main loop for the window. It takes care of\nFPS limiting, updates delta time, keys, mouse coordinates, modifier keys, and\nthe whole screen.\n\n**Returns:**\n\nA boolean value indicating whether the window is still open. It returns true if\nthe window is still open and false if it's closed.\n\n\u003e [!WARNING]\n\u003e Currently it looks like only Windows returns false when the window is closed.\n\u003e On Linux and macOS `fenster` just throws an error when closing the window...\n\u003e\n\u003e I am currently contemplating forking fenster in\n\u003e [#24](https://github.com/jonasgeiler/lua-fenster/issues/24)\n\u003e to fix this problem.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Handle the main loop for the window\nwhile window:loop() do\n  -- ... Your code here...\nend\n```\n\n### `window:set(x: integer, y: integer, color: integer)`\n\nThis method is used to set a pixel in the window buffer at the given\ncoordinates to the given color.\n\n**Parameters:**\n\n- `x` (integer): The x-coordinate of the pixel.\n\n- `y` (integer): The y-coordinate of the pixel.\n\n- `color` (integer): The color to set the pixel to.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Set the pixel at coordinates (10, 20) to red\nwindow:set(10, 20, 0xff0000)\n```\n\n### `window:get(x: integer, y: integer): integer`\n\nThis method is used to get the color of a pixel in the window buffer at the\ngiven coordinates.\n\n**Parameters:**\n\n- `x` (integer): The x-coordinate of the pixel.\n\n- `y` (integer): The y-coordinate of the pixel.\n\n**Returns:**\n\nAn integer representing the color of the pixel at the given coordinates.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Set the pixel at coordinates (10, 20) to green\nwindow:set(10, 20, 0x00ff00)\n\n-- Get the color of the pixel at coordinates (10, 20)\nlocal color = window:get(10, 20) -- Returns: 0x00ff00 (65280 in decimal)\n```\n\n### `window:clear(color: integer | nil)`\n\nThis method is used to clear the window buffer with a given color. This can\nalso be used to set a background color for the window.\n\n**Parameters:**\n\n- `color` (integer, optional): The color to fill the window buffer with. If not\n  provided, the default color `0x000000` (black) is used.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Clear the window buffer with the color blue\nwindow:clear(0x0000ff)\n```\n\n### `window.keys: boolean[]`\n\nThis property is an array of boolean values representing the state of each key\non the keyboard. Each index in the array corresponds to a specific key, and the\nvalue at that index is `true` if the key is currently pressed, and `false`\notherwise.\nThe key codes are mostly ASCII, but arrow keys are 17 to 20.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Get the ASCII code for the \"F\" key (70)\nlocal fkey = string.byte('F')\n\n-- Handle the main loop for the window\nwhile window:loop() do\n  -- Check if the \"F\" key is pressed\n  if window.keys[fkey] then\n    -- Print a message\n    print('F is pressed.')\n  end\nend\n```\n\n### `window.delta: number`\n\nThis property contains the time in seconds that has passed since the last\nframe was rendered. This property is useful for creating smooth animations\nand movement, as you can use it to adjust the speed of an object based on the\nframe rate.\n\nRead more about delta time here:\n[Delta timing - Wikipedia](https://wikipedia.org/wiki/Delta_timing)\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Try out these values and notice the difference:\nlocal targetfps = 60\n--local targetfps = 30\n--local targetfps = 15\n\n-- Open a new window (very wide and scaled to see the pixels moving)\nlocal window = fenster.open(100, 40, 'My Application', 4, targetfps)\n\n-- Calculate the y position of the first pixel (center minus 10)\nlocal pixel1y = window.height / 2 - 10\n\n-- Initialize the x position of the first pixel\nlocal pixel1x = 0\n\n-- Calculate the x position of the second pixel (center plus 10)\nlocal pixel2y = window.height / 2 + 10\n\n-- Initialize the x position of the second pixel\nlocal pixel2x = 0\n\n-- Handle the main loop for the window\nwhile window:loop() do\n  -- Clear the screen for redraw\n  window:clear()\n\n  -- Draw the first pixel in red (we have to floor the x position, because it has to be an integer)\n  window:set(math.floor(pixel1x), pixel1y, 0xff0000)\n\n  -- Move the first pixel to the right (no delta time)\n  pixel1x = pixel1x + 0.35\n\n  -- Reset the first pixel if it reaches the right edge of the window\n  if pixel1x \u003e= window.width then pixel1x = 0 end\n\n  -- Draw the second pixel in green (also floor here)\n  window:set(math.floor(pixel2x), pixel2y, 0x00ff00)\n\n  -- Move the second pixel to the right (with delta time)\n  pixel2x = pixel2x + 20 * window.delta\n\n  -- Reset the second pixel if it reaches the right edge of the window\n  if pixel2x \u003e= window.width then pixel2x = 0 end\nend\n```\n\n### `window.mousex: integer`\n\nThis property contains the x-coordinate of the mouse cursor relative to the\nwindow. The coordinate system is the same as the window buffer, so you can pass\nit directly to the `window:set(...)` method to draw on the screen.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Handle the main loop for the window\nwhile window:loop() do\n  -- Draw a cyan pixel at the mouse position\n  window:set(window.mousex, window.mousey, 0x00ffff)\nend\n```\n\n### `window.mousey: integer`\n\nThis property contains the y-coordinate of the mouse cursor relative to the\nwindow. See [`window.mousex`](#windowmousex-integer) for more information.\n\n### `window.mousedown: boolean`\n\nThis property contains the state of the mouse button. If the mouse button is\ncurrently pressed, the value will be `true`, otherwise it will be `false`.\nCurrently, all mouse buttons are treated as the same button, so you can't\ndistinguish between left, right, or middle mouse buttons.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Handle the main loop for the window\nwhile window:loop() do\n  -- Check if the mouse is pressed\n  if window.mousedown then\n    -- Draw a yellow pixel at the mouse position\n    window:set(window.mousex, window.mousey, 0xffff00)\n  end\nend\n```\n\n### `window.modcontrol: boolean`\n\nThis property contains the state of the Control key, also known as the Ctrl key.\nIf the Control key is currently pressed, the value will be `true`, otherwise it\nwill be `false`.\n\n\u003e [!WARNING]\n\u003e In my experience, the states of the modifier keys are only updated when\n\u003e another key is pressed simultaneously, so you might not get the expected\n\u003e behavior if you only check the modifier property.\n\u003e\n\u003e I am currently contemplating forking fenster in\n\u003e [#24](https://github.com/jonasgeiler/lua-fenster/issues/24)\n\u003e to fix this problem.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Get the ASCII code for the \"G\" key (71)\nlocal gkey = string.byte('G')\n\n-- Handle the main loop for the window\nwhile window:loop() do\n  -- Check if the \"G\" key is pressed\n  if window.keys[gkey] then\n    local keycombination = {}\n\n    -- Check which modifier key is pressed and add it to the key combination\n    if window.modcontrol then\n      keycombination[#keycombination + 1] = 'Ctrl'\n    end\n    if window.modshift then\n      keycombination[#keycombination + 1] = 'Shift'\n    end\n    if window.modalt then\n      keycombination[#keycombination + 1] = 'Alt'\n    end\n    if window.modgui then\n      keycombination[#keycombination + 1] = 'GUI'\n    end\n\n    -- Add the \"G\" key to the key combination\n    keycombination[#keycombination + 1] = 'G'\n\n    -- Print the key combination that is pressed\n    print(table.concat(keycombination, ' + ') .. ' is pressed.')\n  end\nend\n```\n\n### `window.modshift: boolean`\n\nThis property contains the state of the Shift key. See\n[`window.modcontrol`](#windowmodcontrol-boolean) for more information.\n\n### `window.modalt: boolean`\n\nThis property contains the state of the Alt key. See\n[`window.modcontrol`](#windowmodcontrol-boolean) for more information.\n\n### `window.modgui: boolean`\n\nThis property contains the state of the GUI key, also known as the Windows,\nCommand or Meta key. See [`window.modcontrol`](#windowmodcontrol-boolean) for\nmore information.\n\n### `window.width: integer`\n\nThis property contains the width of the window. Note that the width of the\nwindow is read-only and cannot be updated, like all other properties of the\nwindow object.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Print the width of the window\nprint(window.width) -- Output: 500\n```\n\n### `window.height: integer`\n\nThis property contains the height of the window. Note that the height of the\nwindow is read-only and cannot be updated, like all other properties of the\nwindow object.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Print the height of the window\nprint(window.height) -- Output: 300\n```\n\n### `window.title: string`\n\nThis property contains the title of the window. Note that the title of the\nwindow is read-only and cannot be updated, like all other properties of the\nwindow object.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Print the title of the window\nprint(window.title) -- Output: My Application\n```\n\n### `window.scale: integer`\n\nThis property contains the scale factor of the window. Note that the scale of\nthe window is read-only and cannot be updated, like all other properties of the\nwindow object. If you are using this property for reasons other than debugging,\nyou are probably doing something wrong, as the scaling happens completely\ninternally and you won't have to worry about it in your code.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Print the scale of the window\nprint(window.scale) -- Output: 2\n```\n\n### `window.targetfps: number`\n\nThis property contains the target frames per second (FPS) of the window. Note\nthat the target FPS of the window is read-only and cannot be updated, like all\nother properties of the window object.\n\n**Example:**\n\n```lua\nlocal fenster = require('fenster')\n\n-- Open a new window\nlocal window = fenster.open(500, 300, 'My Application', 2, 60)\n\n-- Print the target FPS of the window\nprint(window.targetfps) -- Output: 60.0\n```\n\n## Development\n\nI am developing on Linux, so I will only be able to provide a guide for Linux.\n\n### Building\n\nBuilding the library from the source code requires:\n\n- GCC or similar (f.e. `apt install build-essential`)\n- X11 Development Files (f.e. `apt install libx11-dev`)\n- Lua (f.e. `apt install lua5.4`)\n- Lua Development Files (f.e. `apt install liblua5.4-dev`)\n- LuaRocks (f.e. `apt install luarocks`)\n\nTo build the library from the source code, use:\n\n```shell\nluarocks make\n```\n\n\u003e [!TIP]\n\u003e If you have multiple Lua versions installed on your system, you can specify\n\u003e the version to build for with the `--lua-version` LuaRocks flag. For\n\u003e example, to build for Lua 5.4, use:\n\u003e\n\u003e ```shell\n\u003e luarocks --lua-version=5.4 make\n\u003e ```\n\n### Testing\n\nBefore you can run the test you should [build the library](#building) first.\n\nAfterward, to run the tests, use:\n\n```shell\nluarocks test\n```\n\n\u003e [!TIP]\n\u003e If you have multiple Lua versions installed on your system, you can specify\n\u003e the version to use for testing with the `--lua-version` LuaRocks flag. For\n\u003e example, to test with Lua 5.4, use:\n\u003e\n\u003e ```shell\n\u003e luarocks --lua-version=5.4 test\n\u003e ```\n\n### Testing using Docker\n\nIf you don't want to install the dependencies above on your system, or want to\ntest on all Lua versions simultaneously in a clean environment, you can use\nDocker with Docker Compose.\n\nJust run the following command to build the Docker images for all Lua\nversions and run the tests on each:\n\n```shell\ndocker compose up --build --force-recreate --abort-on-container-failure\n```\n\n## Credits\n\nMany thanks to [Serge Zaitsev (@zserge)](https://github.com/zserge) for creating\nthe original [fenster](https://github.com/zserge/fenster) library and making it\navailable to the public. This Lua binding wouldn't have been possible without\ntheir work.\n\n## License\n\nThis project is licensed under the [MIT License](./LICENSE.md). Feel free to use\nit in your own proprietary or open-source projects. If you have any questions,\nplease open an issue or discussion!\n","funding_links":["https://github.com/sponsors/jonasgeiler","https://ko-fi.com/jonasgeiler","https://liberapay.com/jonasgeiler"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonasgeiler%2Flua-fenster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonasgeiler%2Flua-fenster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonasgeiler%2Flua-fenster/lists"}