{"id":"itzmrratsp/jinx","name":"jinx","scope":"itzmrratsp","platform":"roblox","description":"A lightweight and flexible StateMachine library for Roblox Luau.","version":"0.1.3","latest":"0.1.3","versions":["0.1.3"],"license":"MIT","licenseRating":"safe","licenseCaveats":["The package archive does not include its license text; the license is declared in its manifest metadata."],"licenseVerified":false,"dependencies":{},"integrity":"9872703675b6270b80ad0aca6459da5562d722268945b402ef159f2aa432dc1f","likes":0,"downloads":0,"install":"forest install itzmrratsp/jinx","url":"https://forest.dev/p/roblox/itzmrratsp/jinx","files":"https://api.forest.dev/ai/package/roblox/itzmrratsp/jinx/files","readme":"# Jinx\r\n\r\n> A lightweight and flexible StateMachine library for Roblox Luau.\r\n\r\nJinx is a StateMachine framework created for Roblox development. It provides a clean and structured way to organize behaviors by separating logic into independent states.\r\n\r\nInstead of managing complex behavior through large conditional statements, Jinx allows developers to create reusable states with their own lifecycle, validation, and update logic.\r\n\r\nJinx supports:\r\n- State modules\r\n- Direct state tables\r\n- State lifecycle callbacks\r\n- State validation\r\n- Shared state data through Blackboard\r\n- State change signals\r\n\r\n---\r\n\r\n# Features\r\n\r\n- ⚡ Lightweight StateMachine implementation\r\n- 🧩 Modular state architecture\r\n- 📦 Supports ModuleScript states\r\n- 🔄 State enter, update, and exit lifecycle\r\n- ✅ State transition validation\r\n- 🧠 Built-in Blackboard system\r\n- 📡 State change signals\r\n- 🔒 Strict Luau type support\r\n- 🔤 Case-insensitive state names\r\n- ➕ Dynamic state registration\r\n- ➖ Dynamic state removal\r\n\r\n---\r\n\r\n# Installation\r\n\r\nRequire Jinx:\r\n\r\n```lua\r\nlocal Jinx = require(path.To.Jinx)\r\n```\r\n\r\nCreate a StateMachine:\r\n\r\n```lua\r\nlocal Machine = Jinx()\r\n```\r\n\r\n---\r\n\r\n# Creating States\r\n\r\nJinx supports two ways of creating states:\r\n\r\n1. State tables\r\n2. ModuleScripts\r\n\r\n---\r\n\r\n# State Tables\r\n\r\nA state can be created as a normal Luau table.\r\n\r\n```lua\r\nlocal Idle = {\r\n\tenter = function()\r\n\t\tprint(\"Entered Idle\")\r\n\tend,\r\n\r\n\tupdate = function(dt)\r\n\t\tprint(\"Updating Idle:\", dt)\r\n\tend,\r\n\r\n\texit = function()\r\n\t\tprint(\"Exited Idle\")\r\n\tend,\r\n}\r\n```\r\n\r\n---\r\n\r\n# ModuleScript States\r\n\r\nStates can also be stored inside ModuleScripts.\r\n\r\nExample:\r\n\r\n```\r\nStates\r\n├── Idle\r\n├── Running\r\n└── Jumping\r\n```\r\n\r\nIdle ModuleScript:\r\n\r\n```lua\r\nreturn {\r\n\tenter = function()\r\n\t\tprint(\"Idle started\")\r\n\tend,\r\n\r\n\tupdate = function(dt)\r\n\t\tprint(\"Idle:\", dt)\r\n\tend,\r\n\r\n\texit = function()\r\n\t\tprint(\"Idle ended\")\r\n\tend,\r\n}\r\n```\r\n\r\nThen pass them when creating the StateMachine:\r\n\r\n```lua\r\nlocal Machine = Jinx({\r\n\tIdle = States.Idle,\r\n\tRunning = States.Running,\r\n})\r\n```\r\n\r\nJinx automatically detects ModuleScripts and requires them internally.\r\n\r\n---\r\n\r\n# Creating a StateMachine\r\n\r\nThe constructor accepts an optional state dictionary.\r\n\r\n```lua\r\nlocal Machine = Jinx({\r\n\tIdle = IdleState,\r\n\tRunning = RunningState,\r\n})\r\n```\r\n\r\nStates are automatically registered during creation.\r\n\r\n---\r\n\r\n# Constructor\r\n\r\n```lua\r\nJinx(\r\n\tstates?: {[any]: State | ModuleScript},\r\n\tenterExactState?: boolean,\r\n\tsilence?: boolean\r\n)\r\n```\r\n\r\n---\r\n\r\n## states\r\n\r\nA table containing the initial states.\r\n\r\nSupports:\r\n\r\n```lua\r\n{\r\n\tStateName = StateTable\r\n}\r\n```\r\n\r\nor:\r\n\r\n```lua\r\n{\r\n\tStateName = ModuleScript\r\n}\r\n```\r\n\r\nExample:\r\n\r\n```lua\r\nlocal Machine = Jinx({\r\n\tIdle = IdleState,\r\n\tRunning = RunningState,\r\n})\r\n```\r\n\r\n---\r\n\r\n## enterExactState\r\n\r\nAllows entering the same state multiple times.\r\n\r\nDefault:\r\n\r\n```lua\r\nfalse\r\n```\r\n\r\nExample:\r\n\r\n```lua\r\nMachine:switch(\"Idle\")\r\nMachine:switch(\"Idle\")\r\n```\r\n\r\nWith `enterExactState` enabled, both transitions will execute.\r\n\r\n---\r\n\r\n## silence\r\n\r\nDisables internal Jinx logging.\r\n\r\nDefault:\r\n\r\n```lua\r\nfalse\r\n```\r\n\r\nExample:\r\n\r\n```lua\r\nlocal Machine = Jinx(nil, false, true)\r\n```\r\n\r\n---\r\n\r\n# State Lifecycle\r\n\r\nEach state can define these callbacks:\r\n\r\n---\r\n\r\n## enter()\r\n\r\nCalled when the state becomes active.\r\n\r\n```lua\r\nenter = function(...)\r\n\tprint(\"State entered\")\r\nend\r\n```\r\n\r\n---\r\n\r\n## update()\r\n\r\nCalled every update cycle.\r\n\r\n```lua\r\nupdate = function(dt)\r\n\tprint(dt)\r\nend\r\n```\r\n\r\nYou must update the StateMachine manually.\r\n\r\nExample:\r\n\r\n```lua\r\nRunService.Heartbeat:Connect(function(dt)\r\n\tMachine:update(dt)\r\nend)\r\n```\r\n\r\n---\r\n\r\n## exit()\r\n\r\nCalled when leaving a state.\r\n\r\n```lua\r\nexit = function(...)\r\n\tprint(\"State exited\")\r\nend\r\n```\r\n\r\n---\r\n\r\n## canEnter()\r\n\r\nDetermines if the state is allowed to start.\r\n\r\n```lua\r\ncanEnter = function(...)\r\n\treturn true\r\nend\r\n```\r\n\r\nReturning `false` prevents entering.\r\n\r\n---\r\n\r\n## canExit()\r\n\r\nDetermines if the state is allowed to stop.\r\n\r\n```lua\r\ncanExit = function(...)\r\n\treturn true\r\nend\r\n```\r\n\r\nReturning `false` prevents leaving.\r\n\r\n---\r\n\r\n# Complete Example\r\n\r\n```lua\r\nlocal Jinx = require(path.To.Jinx)\r\nlocal RunService = game:GetService(\"RunService\")\r\n\r\n\r\nlocal Machine = Jinx({\r\n\tIdle = {\r\n\t\tenter = function()\r\n\t\t\tprint(\"Idle\")\r\n\t\tend,\r\n\r\n\t\tupdate = function(dt)\r\n\t\t\tprint(\"Idle update\", dt)\r\n\t\tend,\r\n\r\n\t\texit = function()\r\n\t\t\tprint(\"Leaving idle\")\r\n\t\tend,\r\n\t},\r\n\r\n\tRunning = {\r\n\t\tenter = function()\r\n\t\t\tprint(\"Running\")\r\n\t\tend,\r\n\r\n\t\tupdate = function(dt)\r\n\t\t\tprint(\"Running update\", dt)\r\n\t\tend,\r\n\t},\r\n})\r\n\r\n\r\nMachine:switch(\"Idle\")\r\n\r\n\r\nRunService.Heartbeat:Connect(function(dt)\r\n\tMachine:update(dt)\r\nend)\r\n```\r\n\r\n---\r\n\r\n# Blackboard\r\n\r\nEvery StateMachine has its own Blackboard instance.\r\n\r\nThe Blackboard can be used to store shared data between states.\r\n\r\nExample:\r\n\r\n```lua\r\nMachine.blackboard:Set(\"Speed\", 20)\r\n```\r\n\r\nAnother state:\r\n\r\n```lua\r\nlocal speed = Machine.blackboard:Get(\"Speed\")\r\n```\r\n\r\nThis allows states to communicate without directly depending on each other.\r\n\r\n---\r\n\r\n# State Change Signal\r\n\r\nJinx provides a `changed` signal.\r\n\r\n```lua\r\nMachine.changed:Connect(function(stateName)\r\n\tprint(\"Changed to:\", stateName)\r\nend)\r\n```\r\n\r\nExample output:\r\n\r\n```\r\nChanged to: running\r\n```\r\n\r\n---\r\n\r\n# Adding States\r\n\r\nStates can be added after creation.\r\n\r\n```lua\r\nMachine:add(\"Jumping\", JumpState)\r\n```\r\n\r\n---\r\n\r\n# Removing States\r\n\r\nStates can be removed dynamically.\r\n\r\n```lua\r\nMachine:remove(\"Jumping\")\r\n```\r\n\r\nIf the state is currently active, Jinx will attempt to exit it before removal.\r\n\r\n---\r\n\r\n# API Reference\r\n\r\n## Jinx()\r\n\r\nCreates a new StateMachine.\r\n\r\n```lua\r\nJinx(\r\n\tstates?,\r\n\tenterExactState?,\r\n\tsilence?\r\n)\r\n```\r\n\r\nReturns:\r\n\r\n```lua\r\nStateMachine\r\n```\r\n\r\n---\r\n\r\n## StateMachine:add()\r\n\r\nAdds a state.\r\n\r\n```lua\r\nMachine:add(\r\n\tname,\r\n\tstate\r\n)\r\n```\r\n\r\n---\r\n\r\n## StateMachine:switch()\r\n\r\nChanges the active state.\r\n\r\n```lua\r\nMachine:switch(\r\n\tname,\r\n\t...\r\n)\r\n```\r\n\r\n---\r\n\r\n## StateMachine:update()\r\n\r\nUpdates the active state.\r\n\r\n```lua\r\nMachine:update(dt)\r\n```\r\n\r\n---\r\n\r\n## StateMachine:remove()\r\n\r\nRemoves a state.\r\n\r\n```lua\r\nMachine:remove(name)\r\n```\r\n\r\n---\r\n\r\n## StateMachine:exit()\r\n\r\nAttempts to exit the current state.\r\n\r\n```lua\r\nMachine:exit(...)\r\n```\r\n\r\n---\r\n\r\n# Recommended Usage\r\n\r\nJinx works well for:\r\n\r\n- Character controllers\r\n- NPC AI\r\n- Enemy behavior\r\n- Animation controllers\r\n- Weapon systems\r\n- Ability systems\r\n- UI navigation\r\n- Game progression systems\r\n\r\nExample:\r\n\r\n```\r\nCharacterController\r\n\r\n├── Idle\r\n├── Walking\r\n├── Running\r\n├── Jumping\r\n└── Falling\r\n```\r\n\r\nEach state manages only its own behavior, making systems easier to maintain.\r\n\r\n---\r\n\r\n# Design Philosophy\r\n\r\nJinx follows one simple rule:\r\n\r\n> A state should only manage its own behavior.\r\n\r\nInstead of:\r\n\r\n```lua\r\nif state == \"Idle\" then\r\n\t-- idle logic\r\nelseif state == \"Running\" then\r\n\t-- running logic\r\nend\r\n```\r\n\r\nJinx separates behavior:\r\n\r\n```lua\r\nIdle.update()\r\n\r\nRunning.update()\r\n```\r\n\r\nThis keeps code cleaner, more scalable, and easier to debug.\r\n\r\n---\r\n\r\n# Creator\r\n\r\nCreated by **ItzMrRatsP**\r\n\r\nJinx was created for educational purposes and private Roblox development.\r\n\r\n---\r\n\r\n# License\r\n\r\nJinx is not currently licensed for public redistribution.\r\n\r\nSharing or modifying this package outside approved usage is not permitted.\r\n","readmeTruncated":false}