{"id":22454404,"url":"https://github.com/NightLapse-Studios/Pumpkin","last_synced_at":"2025-08-02T02:31:25.470Z","repository":{"id":227583584,"uuid":"771818787","full_name":"NightLapse-Studios/Pumpkin","owner":"NightLapse-Studios","description":"A neat, pragmatic UI builder library for Roblox that wraps Roact.","archived":false,"fork":false,"pushed_at":"2024-04-11T06:02:50.000Z","size":663,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-04-11T07:22:46.757Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NightLapse-Studios.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}},"created_at":"2024-03-14T02:18:06.000Z","updated_at":"2024-04-11T07:22:51.497Z","dependencies_parsed_at":"2024-03-19T23:26:14.046Z","dependency_job_id":"b9cf0d13-b719-40df-98c8-9d7b54a2ad2d","html_url":"https://github.com/NightLapse-Studios/Pumpkin","commit_stats":null,"previous_names":["nightlapse-studios/pumpkin"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NightLapse-Studios%2FPumpkin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NightLapse-Studios%2FPumpkin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NightLapse-Studios%2FPumpkin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NightLapse-Studios%2FPumpkin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NightLapse-Studios","download_url":"https://codeload.github.com/NightLapse-Studios/Pumpkin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228426123,"owners_count":17917790,"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-12-06T07:07:33.116Z","updated_at":"2025-08-02T02:31:25.447Z","avatar_url":"https://github.com/NightLapse-Studios.png","language":"Lua","funding_links":[],"categories":["Other"],"sub_categories":["Pumpkin \u003cimg src=\"luau.svg\" width=\"18px\" /\u003e"],"readme":"![A Pumpkin](PumpkingWithTitleNoBG.png)\n\n---\n\nPumpkin is a UI library that wraps Roact and Flipper to achieve better expressiveness and ease of writing components. Most functionality is implemented in a single file: [Pumpkin](src/Pumpkin/init.lua). Check out the [wiki](https://github.com/NightLapse-Studios/Pumpkin/wiki) to learn more.\n\n### Main Attractions\n* Short Syntax/Builder Pattern\n* Bindings class functions exposed and joining made easier\n* Flipper (an animation library) is available directly through bindings\n* Custom properties (PropSet Modifiers), as opposed to just custom elements\n* Props can receive datatype arguments instead of the datatype directly\n* Attributes work\n* Edit element properties after creation\n* Multiple utility/custom properties have already been made like ScaledTextGroup\n\n### Projects\n* [Clash!](https://www.roblox.com/games/8256020164/Clash-KNIGHT) \n* [src/example/DebugMenu](src/example/DebugMenu/init.lua)\n\n## Installation\nPlace the `src/Pumpkin` folder in your project library folder and require it.\n\n## Overview\n\n### Short Syntax/Builder Pattern\n\n```lua\nlocal Pumpkin = require(game.ReplicatedFirst.Pumpkin)\nlocal I, P = Pumpkin, Pumpkin.P\n\nI:ImageButton(P()\n\t:Center()\n\t:BackgroundColor3(1, 0, 0)\n\t:Activated(function()\n\t\tprint(\"Clicked!\")\n\tend)\n)(\n\t-- more elements\n)\n\nlocal Roact, RoactRbx = Pumpkin.Roact, Pumpkin.RoactRbx\n-- Equivalent to:\nRoact.createElement(\"ImageButton\", {\n\tAnchorPoint = Vector2.new(0.5, 0.5),\n\tPosition = UDim2.fromScale(0.5, 0.5),\n\tBackgroundColor3 = Color3.new(1, 0, 0),\n\t[Roact.Event.Activated] = function()\n\t\tprint(\"Clicked!\")\n\tend,\n}, {\n\t-- more elements\n})\n```\n\n\n### Improved Bindings/Tweens\n\nBindings provide direct access to their internals, freeing us from having two return vales from `createBinding`\n```lua\nlocal pulse, updPulse = I:Binding(0)\n\n-- Equivalent:\nupdPulse(0.5)\npulse.update(0.5)\n```\nAlso exposed is subscribe\n```lua\nlocal disconnect_func = pulse.subscribe(function(newPulseValue) end)\n```\n\n\nWhen joining bindings, everything goes. Mostly useful for general purpose UI components, we no longer have to check if passed in props are bindings or pure values:\n```lua\nlocal pulse = I:Binding(0)\nlocal pulse2 = 0.5\n\nI:JoinBindings({pulse, pulse2}):map(function(table)\n\tlocal pulseValue = table[1]\t\t--0\n\tlocal pulseValue2 = table[2]\t--0.5\nend)\n```\n\n### PropSet modifiers\n\nConstructing props through the builder pattern lets us put names on our ways of setting props:\n```lua\nI:Frame(P()\n\t-- no border and no background\n\t:Invisible()\n\t\n\t-- center anchor and center position\n\t:Center()\n\t-- Position it 5 pixels away from the left side of its parent, (overwriting the :Center() call above)\n\t-- The parameters are interpreted as UDim parameters\n\t:JustifyLeft(0, 5)\n\t\n\t-- Propset modifiers can do a lot more than modify props\n\t-- This example involves inserting children into the props as well, a UIAspectRatioConstraint\n\t:AspectRatioProp(1/3)\n)\n```\n\nCustom modifiers can get pretty advanced, for example we have implemented this:\n\n```lua\nI:Frame(P()\n\t-- Make this frame a 3 pixel line from the top left of the parent to the bottom right\n\t:Line(UDim2.fromScale(0, 0), UDim2.fromScale(1, 1), 3)\n)\n```\n\n\n### Tweens\n\nPumpkin Tweens are implemented as an extension to bindings and use Flippers UI Animation Library, they start playing when they are attached to an instance, and reset to the beginning when unattached. A tween with no sequences will start playing once sequences have been added to it, which is what you should do if you don't want your tween to play until you tell it to\n\n```lua\n-- define a tween with value 0 (default start value)\n-- spring to 1 with speed of 2 and damping of 1.3, go back to 0, wait half a second, repeat this forever\nlocal pulse = I:Tween():spring(1, 2, 1.3):instant(0):pause(0.5):repeatAll(-1)\n\nI:ImageButton(P()\n\t:BackgroundColor3(pulse:map(function(v)-- the tween is a binding with extra functionality.\n\t\treturn Color3.new(v, 0, 0)\n\tend))\n\t:Activated(function()\n\t\tpulse:wipe()-- when the buttons is clicked, clear the animation steps and reset to start value (0)\n\tend)\n)\n```\n\nSo essentially, Pumpkin Tweens are bindings with a sequence of animation steps. As you can see, despite the complex nature of this tween, the syntax remains relatively short. The animation sequence can be defined or changed at any time. You can read more about other functions related to tweens at the top of [Pumpkin](src/Pumpkin/init.lua)\n\n## Shared functionality\n\nPumpkin provides a way for modules to define shared custom PropSet modifiers, elements, and components. As you'd expect, you can only use shared things after they've been defined.\n\n```lua\n--[[ Shared custom modifiers ]]\n\n-- definition\nI:RegisterModifier(\"CustomModifier\", function(props, a, b)\n\tprops:AnchorPoint(math.random(), math.random())\n\tprops:Position(0.5, 0, 0.5, 0)\n\tprops:BackgroundTransparency(a - b^2)\n\n\treturn props\nend)\n\n-- use (directly by name)\nI:Frame(P()\n\t:CustomModifier(1, 0.2)\n)\n\n\n--[[ Shared custom elements ]]\n\n-- definition\nI:NewElement(\"MyElement\", I:Frame(P()))\n\nI:NewElement(\"MyElement2\", function(props)\n\treturn I:Frame(P())\nend)\n\n-- instantiation (directly by name)\nI:Element(\"MyElement\", P())\nI:Element(\"MyElement2\", P())\n\n\n--[[ Shared stateful components ]]\n\n-- definition\nI:Stateful(P()\n\t:Name(\"MyStateful\")\n\t:Init(function(self)\n\tend)\n\t:Render(function(self)\n\tend)\n)\n\n-- instantiation (directly by name)\nlocal root = I:Mount(I:MyStateful(P()), game.Players.LocalPlayer.PlayerGui.ScreenGui)\n```\n\nFor convenience, we made the `ASYNC_DEFINITIONS` flag. It is on by default. It simply causes an undefined Element or field in Pumpkin/PropSets to yield for its definition. After a short timeout, anything still undefined will trigger the expected error, the only difference is that it was delayed. Async definitions can be leveraged with certain frameworks such as Knit to create a \"definitions\" stage of startup.\n\n## Misc\n\n* More wrappers exist in [Pumpkin](src/Pumpkin/init.lua), such as Refs, Portals, and Change Events.\n* Custom Props had to be wrapped: `propSet:Prop(name, value)`.\n* [DebugMenu](src/example/DebugMenu/init.lua) for a fully fledged client and server debug menu with sliders, color pickers, plotting, checkboxes, and textboxes.\n* Props for host attribute's bindings `:Attribute(\"AttributeName\", value/binding)`.\n* The Roact Type table has been exposed: `local isBinding = pulse[\"$$typeof\"] == Roact.Type.Binding`.\n* Roact elements fall back to pumpkin prop sets:\n\t```lua\n\tRoact.createElement(\"Frame\", {})\n\t\t:JustifyLeft(0, 5)\n\t\t:Children(\n\t\t\n\t\t)\n\t```\n\n* There exists `I:IsPositionInObject`, `I:IsScrollBarAtEnd`.\n* `PropSet:ScaledTextGroup` is the better TextScaled that works with multiple TextLabels instead of just one.\n* `propSet:Run()` exists to maintain the tree structure of the code by offering in-tree custom modifiers that may be too niche to deserve a full on RegisteredModifier. The classic example is conditionals, without :Run, you may constantly be scrolling up and down leaving the tree to perform logic and then coming back.\n\t```lua\n\t-- Conditionally set props without bindings\n\tlocal function createFrame(disabled: boolean)\n\t\tlocal props = P():Center()\n\t\t\n\t\tif disabled then\n\t\t\tprops:BackgroundTransparency(0.7)\n\t\t\tprops:BackgroundColor3(--[[Some disabled color]])\n\t\telse\n\t\t\tprops:BackgroundTransparency(0)\n\t\t\tprops:BackgroundColor3(--[[Some enabled color]])\n\t\tend\n\n\t\treturn I:Frame(props)\n\tend\n\n\t-- Now do it without destructuring the tree\n\tlocal function createFrame(disabled: boolean)\n\t\treturn I:Frame(P()\n\t\t\t:Center()\n\t\t\t:Run(function(props)\n\t\t\t\tif disabled then\n\t\t\t\t\tprops:BackgroundTransparency(0.7)\n\t\t\t\t\tprops:BackgroundColor3(--[[Some disabled color]])\n\t\t\t\telse\n\t\t\t\t\tprops:BackgroundTransparency(0)\n\t\t\t\t\tprops:BackgroundColor3(--[[Some enabled color]])\n\t\t\t\tend\n\t\t\tend)\n\t\t)\n\tend\n\t```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNightLapse-Studios%2FPumpkin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNightLapse-Studios%2FPumpkin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNightLapse-Studios%2FPumpkin/lists"}