{"id":13571064,"url":"https://github.com/potch/playout","last_synced_at":"2025-04-13T18:04:39.494Z","repository":{"id":217047958,"uuid":"620637064","full_name":"potch/playout","owner":"potch","description":"UI library and box model for Playdate","archived":false,"fork":false,"pushed_at":"2024-05-03T23:46:43.000Z","size":57,"stargazers_count":59,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-27T08:48:44.164Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://twentyminutemile.itch.io/playout","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/potch.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-29T04:32:25.000Z","updated_at":"2025-03-17T15:33:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"231eb3c9-27e9-48ce-9590-6a84e6e8f1ba","html_url":"https://github.com/potch/playout","commit_stats":null,"previous_names":["potch/playout"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/potch%2Fplayout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/potch%2Fplayout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/potch%2Fplayout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/potch%2Fplayout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/potch","download_url":"https://codeload.github.com/potch/playout/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248758442,"owners_count":21156957,"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":[],"created_at":"2024-08-01T14:00:58.086Z","updated_at":"2025-04-13T18:04:39.457Z","avatar_url":"https://github.com/potch.png","language":"Lua","funding_links":[],"categories":["Lua"],"sub_categories":[],"readme":"# Playout\n\nUI library and box model for Playdate\n\n[Support this project on Itch.io 🕹](https://twentyminutemile.itch.io/playout)\n\n## Installation\n\nIf you are using [toybox](https://github.com/jm/toybox), you can run\n\n```\ntoybox add potch/playout\n```\n\nOtherwise the library is a single file you can clone/copy into your project.\n\n## Demo\n\nIf you'd like to run the demo, you'll need the Playdate SDK. Then run:\n```sh\npdc demo\n```\nand open the resulting packaged in the Playdate Simulator.\n\nIf you want to develop/experiment on the library or demo and you have `node` installed you can run the following:\n\n```\nnpm install\nnpm start\n```\n\nWhich will build and launch the demo, and re-build after any changes.\n\n# API Docs\n\n# `playout.box`\n\nBox-based layout element. supports 1-dimensional layout (horizontal or vertical) with 2-dimensional alignment and flexible sizing.\n\n## Methods\n\n### `playout.box.new(properties, [children])`\n\nCreates a new `playout.box`. Takes a table of `properties` and a list of `children`.\n\nChildren can be other `box`es, `image`s, or `text`.\n\nReturns a `playout.box`.\n\n#### Supported `properties`:\n\n| property | description | default value |\n| -------- | ----------- | ------------- |\nbackgroundAlpha | opacity of box fill, drawn as a dither pattern. | 0 (full)\nbackgroundColor | color to fill the box when drawing | `nil` (transparent)\nborder | thickness of border on box | 0\nborderColor | color of border (if \u003e 0) | `playdate.graphics.kColorBlack`\nborderRadius | corner radius to use when drawing the box | 0\ndirection | direction of layout. can be horizontal (children will be in a row) or vertical (children will be in a column) | `playout.kDirectionVertical`\nflex | if set (non-zero), box will grow proporitonally to fill extra layout space in its parent. | `nil`\nfont | font to use when drawing text in children. | `nil` (default)\nfontFamily | font family to use when drawing text in children. takes precedence over `font`, and allows for rich formatting. | `nil`\nhAlign | how to horizontally align children. see [Alignment](#alignment) | `playout.kAlignCenter`\nheight | height of the box. if not specified, box will be the height of its contents plus padding, spacing, etc. (but no larger than `maxHeight`) | `nil`\nid | unique `string` used for lookups via [`playout.tree.get`](#playout-tree-get-id) | nil\nmaxHeight | maximum height of the box | 240\nmaxWidth | maximum width of the box | 400\nminHeight | minimum height of the box | 1\nminWidth | minimum width of the box | 1\npadding | amount of inset, in pixels, between box children and the edge | 0\npaddingBottom | bottom padding. defaults to `paddingTop` or `padding` value if provided, in that order | `nil`\npaddingLeft | left padding. defaults to `padding` value if provided, in that order | `nil`\npaddingRight | right padding. defaults to `paddingLeft` or `padding` value if provided, in that order | `nil`\npaddingTop | top padding. defaults to `padding` value if provided | `nil`\nselfAlign | override the box alignment from that provided by its parent. if parent's `direction` is horizontal, affects vertical alignment, if vertical, affects horizontal alignment | `nil` (no override)\nshadow | size of shadow in pixels to draw under the box. note the shadow subtracts from the overall available height of the box | `nil` (no shaow)\nshadowAlpha | how \"dark\" the shadow is, from 0..1. drawn using dither. | 0 (full opacity)\nspacing | how much space should be between each child of the box | 0\nstyle | see [Style Reuse](#styling) | nill\ntabIndex | defines position for sequential lookups by `playout.tree.tabIndex`. | nil\nvAlign | how to vertically align children. see [Alignment](#alignment) | `playout.kAlignCenter`\nwidth | width of the box. if not specified, box will be the width of its contents plus padding, spacing, etc. (but no larger than `maxWidth`) | `nil`\n\n\n### `playout.box:appendChild(child)`\n\nAdd a child (text, image, or other box) to the box.\n\n\n### `playout.box:insertChild(child, position)`\n\nAdd a child (text, image, or other box) to the box at a specified position. e.g. `insertChild(child, 1)` would add the child as the first child.\n\n\n### `playout.box:layout([context])`\n\nComputes the layout of the box and all children recursively. Returns a `playout.geometry.rect` with the computed size. Usually indirectly called by `playout.tree:layout`.\n\n`context` is a table with the following properties:\n\nproperty | description | default\n--- | --- | ---\nmaxWidth | maximum width the box can be, regardless of its contents | `math.huge` (no limit)\nmaxHeight | maximum height the box can be, regardless of its content | `math.huge` (no limit)\n\n\n### `playout.box:draw(rect)`\n\nDraw the box and all its children using their visual properties in the current drawing context within the specified `rect`. Usually called indirectly by `playout.tree.draw` with pre-computed `rect`s generated during `:layout`.\n\n\n\n## properties\n\n### `playout.box.properties`\n\ntable of properties, provided via initial creation.\n\n### `playout.box.children`\n\nlist of children, managed via `appendChild`, `insertChild`, or `playout.tree`.\n\n### `playout.box.childRects`\n\nList of rects corresponding to `children`, determined during `:layout`. Will be `nil` if layout hasn't been called yet.\n\n### `playout.box.parent`\n\nReference to a parent `box`, if any. set by `appendChild`, `insertChild`, or `playout.tree`. If children were changed directly via `.children`, their `parent` will not be set. read only.\n\n### `playout.box.style`\n\nsee [Style Reuse](#styling).\n\n\n\n# `playout.text`\n\nLayout element for text content. supports fonts, outlines, and text wrapping.\n\n## methods\n\n### `playout.text.new(text, [properties])`\n\nCreates a new `playout.text`. Takes a string of `text` and an optional table of `properties`.\n\nReturns a `playout.text`\n\n#### Supported `properties`:\n\nproperty | description | default\n--- | --- | ---\nfont | which `playdate.graphics.font` to use to render text. this property can be inherited from parent `box`es. | `nil` (currently set font),\nfontFamily | which `playdate.graphics.fontFamily` to use to render text. allows for rich text formatting. If set, overrides `font`. this property can be inherited from parent `box`es. | `nil`,\nalignment | text alignment | `kTextAlignment.left`,\nleading | leading adjusment | `nil` (none),\nflex | if set (non-zero), text will grow proporitonally to fill extra layout space in its parent. | `nil`,\nwrap | whether to line-wrap text | true,\nstroke | radius of outline to render around the text- will be rendered in white. useful to contrast text against a background. | 0,\ncolor | color to render text- overrides `font`'s natural color. `playdate.graphics.kColorBlack` or `kColorWhite`. | `nil` (use defualt font color)\n\n### `playout.text:layout(context)`\n\nComputes the layout and dimensions of renderered text. Returns a `playout.geometry.rect` with the computed size. Usually indirectly called by `playout.tree:layout`.\n\n### `playout.text:draw(rect)`\n\nRenders text into the provided `playout.geometry.rect`. Usually called indirectly by `playout.tree:draw`.\n\n## Properties\n\nChanging properties will require re-running `layout` and `draw` to see the changes.\n\n### `playout.text.text`\n\nValue of text string to render. changing this will likely require re-computing layout.\n\n### `playout.text.properties`\n\nTable of properties, provided via initial creation.\n\n### `playout.text.parent`\n\nReference to a parent `box`, if any. set by `appendChild`, `insertChild`, or `playout.tree`. If children were changed directly via `.children`, their `parent` will not be set. read only.\n\n### `playout.text.style`\n\nSee [Style Reuse](#styling).\n\n\n# `playout.image`\n\nAllows for the incorporation of `playdate.graphics.image` into a layout.\n\n## Methods\n\n### `playout.image.new(image, [properties])`\n\nCreates a new `playout.image`. Takes a `playdate.graphics.image` and an optional table of `properties`.\n\n`image` nodes are sized to the `width` and `height` of their corresponding `playdate.graphics.image`, which is used in layout.\n\nReturns a `playout.image`.\n\n### `playout.text:layout(context)`\n\nCalculates a `play\n\n### `playout.text:draw(rect)`\n\n## Properties\n\n### `playout.text.parent`\n\nReference to a parent `box`, if any. set by `appendChild`, `insertChild`, or `playout.tree`. If children were changed directly via `.children`, their `parent` will not be set. Read only.\n\n\n\n# `playout.tree`\n\nStructure for creating/accessing a tree of `playout` nodes. This is the recommended way to create, layout, and draw layouts.\n\n## Methods\n\n### `playout.tree.new([root, [options])`\n\nCreate a new `playout.tree`. Takes `root`, the top-level note of the tree (a `box`, `text`, or `image`), as well as a table of `options`.\n\n#### Supported `options`:\n\noption | description | default\n--- | --- | ---\nuseCache | Whether or not to cache nodes looked up using `tree:get(id)`. Makes subsequent lookups faster. | true\n\n### `playout.tree:layout()`\n\nCompute the layout of all children recursively, starting at `root`.\n\n### `playout.tree.draw()`\n\nReturns a `playdate.graphics.image` containing the rendered tree. Will run `tree:layout` if it has not yet been run. To save on memory, this method will store and re-use the same image for subsequent re-renders (at `tree.img`), provided the computed layout dimensions of the tree haven't changed. Will automatically update an associated sprite if created with `playout.tree:asSprite`\n\n### `playout.tree:asSprite()`\n\nCreates a new `playdate.graphics.sprite`, draws the tree into the sprite, and returns the sprite. Future calls to `tree:draw` will automatically update the sprite's image.\n\n### `playout.tree:get(id)`\n\nFind a node in the tree based on its `properties.id`. Will recursively walk the tree to find the node. Returns the first node with matching `id`, or `nil` if no match was found. If `tree.useCache` is `true`, subsequent lookups will skip walking the tree.\n\n### `playout.tree:computeTabIndex()`\n\nComputes a sequential list of nodes in the tree which have the `tabIndex` property set. Higher `tabIndex` values will be sorted later in the list. Useful for interactivity and menuing. The computed list will be store in the `playout.tree.tabIndex` property, which is `nil` until this method is called.\n\n## Properties\n\n### `playout.tree.root`\n\nThe top node of the layout tree.\n\n### `playout.tree.tabIndex`\n\nAn ordered list of nodes, sorted by their `tabIndex` property. Useful for interactivity and menuing. Will be `nil` until `playout.tree:computeTabIndex()` is called.\n\n### `playout.tree.rect`\n\nA `playdate.geometry.rect` representing the dimensions of the tree after the last call to `playout.tree:layout()`\n\n### `playout.tree.img`\n\nA `playdate.graphics.image` containing the latest results of calling `playout.tree:draw()`\n\n### `playout.tree.sprite`\n\nA `playout.graphics.sprite`, populated after calling `playout.tree:asSprite()`\n\n\n# Utilities and Constants\n\n## Alignment\n\nUsed for `hAlign` and `vAlign` properties:\n\n### `playout.kAlignStart`\n\nChildren are aligned to the start of the box (left for `hAlign`, top for `vAlign`).\n\n### `playout.kAlignCenter`\n\nChildren are aligned to the center of the box (rounded down in the case of an odd width).\n\n### `playout.kAlignEnd`\n\nChildren are aligned to the end of the box (right for `hAlign`, bottom for `vAlign`).\n\n### `playout.kAlignStretch`\n\nResizes children to fill the available remaining space.\n\nOnly valid for off-axis alignment. If `direction` is vertical, valid for `hAlign`, if `directon` is horizontal, valid for `vAlign`. When used in `selfAlign`, always refers to the off-axis direction.\n\n\n## Anchoring\n\n### `playout.getRectAnchor(r, anchor)`\n\nReturns a `playdate.geometry.point` for a given `anchor` position on the the provided `playdate.geometry.rect`:\n\n```\nplayout.kAnchorTopLeft\nplayout.kAnchorTopCenter\nplayout.kAnchorTopRight\nplayout.kAnchorCenterLeft\nplayout.kAnchorCenter\nplayout.kAnchorCenterRight\nplayout.kAnchorBottomLeft\nplayout.kAnchorBottomCenter\nplayout.kAnchorBottomRight\n```\n\n## Direction\n\nUsed for specifying the direction of box layout, horizontal or vertical:\n\n```\nplayout.kDirectionVertical\nplayout.kDirectionHorizontal\n```\n\n# Styling\n\nAll node types (`box`, `image`, and `text`) can take an optional `style` property. This is a table of properties that will override any properties provided at creation or default values. Can be used to define repeatable common collections of properties.\n\nExample\n\n```lua\nlocal button = {\n  padding = 4,\n  border = 2,\n  borderRadius = 4,\n  shadow = 2\n}\n\nlocal options = playout.tree.new(\n  playout.box.new({\n    direction = playout.kDirectionHorizontal,\n    spacing = 8\n  }, {\n    playout.box.new({ style = button, tabIndex = 1 }, { playout.text.new(\"Cancel\") }),\n    playout.box.new({ style = button, tabIndex = 2 }, { playout.text.new(\"Okay\") }),\n  })\n)\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpotch%2Fplayout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpotch%2Fplayout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpotch%2Fplayout/lists"}