{"id":"mark-marks/rubine","name":"rubine","scope":"mark-marks","platform":"roblox","description":"Mirrored from the Wally registry.","version":"0.2.0","latest":"0.2.0","versions":["0.1.0-rc.2","0.1.0-rc.3","0.1.0-rc.4","0.1.0-rc.5","0.1.0-rc.6","0.1.0-rc.7","0.1.0-rc.8","0.2.0","0.3.0-alpha.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{"ukendio/jecs":{"version":"^0.5.3","alias":"jecs"}},"integrity":"6a98b6ac3f640805be8fb2da45bc6d84347ced14cc2ad6b7a57e578d650d9ccf","likes":0,"downloads":0,"install":"forest install mark-marks/rubine","url":"https://forest.dev/p/roblox/mark-marks/rubine","files":"https://api.forest.dev/ai/package/roblox/mark-marks/rubine/files","readme":"<p align=\"center\">\r\n    <img src=\"assets/rubine-poster.png\">\r\n</p>\r\n\r\n[![CI](https://img.shields.io/github/actions/workflow/status/mark-marks/rubine/ci.yml?style=for-the-badge&label=CI)](https://github.com/mark-marks/rubine/actions/workflows/ci.yml)\r\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](https://github.com/Mark-Marks/rubine/blob/main/LICENSE)\r\n<a href=\"https://wally.run/package/mark-marks/rubine\"><img alt=\"Wally\" src=\"https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fmark-marks%2Frubine%2Frefs%2Fheads%2Fmain%2Fwally.toml&query=package.version&prefix=mark-marks%2Frubine%40&style=for-the-badge&label=Wally&color=ad4646&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+V2FsbHk8L3RpdGxlPjxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0yMC4zMjUgMTguMTkxYy0xLjkxNSAyLjU5OS01LjEyNyA0LjI1NC04LjM1OCA0LjE4MS0uMjk2LS41MjgtLjc2My0xLjY3My4zNDgtMS4yOTcgMi4zNTUtLjA3NiA0Ljc3LTEuMDE0IDYuMzc1LTIuNzYxLjI5OS0uODUzLjgyLS45ODcgMS4zOC0uMzAxbC4xMjcuMDkuMTI4LjA4OHpNMTIuNzg1IDYuMmMtLjg5Mi4yNjQtLjEwNCAyLjY2LjQ1OSAxLjI3Mi0uMDc1LS40MDcuMjItMS4yODgtLjQ1OC0xLjI3MnptLS41OS0uMjQyYy0uNjY0LTEuMzM1IDEuOTY2LS4zNTMgMS44ODItLjIyOC0uMzI2LS44NTYtMi4zMDItMS4yNC0yLjI2My0uMTA4bC4xNzMuMTk3ek0xMS41NCAxOS4zOGMtLjI4LTEuMzY0IDEuOTY1LS45NTggMS45My0xLjgwMS0uOTkyLS4xNi0yLjM4Mi0uODMyLTEuMzQtMS45NjMgMS4wMjctMS4wMjIgMi41MzMtMS45NTYgMi40OTItMy42NDktLjI4NS42MTItLjkyIDEuOTMtMS44MzUgMi4zODctMS41NzMgMS4wOC00LjA5IDEuMTc5LTUuMjYtLjU1LS4zNDktLjQ2My0uNjg3LTEuNDkxLS40NC0uMzQyLjQ2Ni42NjguNiAxLjcwMi0uNTYxIDEuNDUzLTEuMjQ1LS40NDEtLjM2Mi0xLjc2NC0uNC0yLjY0Ni0uNi0xLjE0NCAxLjM3Ni0uNjA4IDEuNjIzLTEuNjk0QzguNjQgOS40MyA2LjcyIDguODMgNS44NDggOC45MWMtLjk5Ni4xNjUuODUxLS40OTUgMS4xOC0uNzkuNzczLS40NTMgMS41MDYtLjk5NiAyLjA5LTEuNjgyLS41NjIuNDgyLS43NjEuNTE2LS43NDktLjI4LTEuMTUyLS41Ny0uMTM3IDEuNjkzLTEuMzk3IDEuNjY4LS45MTIuNjA1LjYxOS0xLjE0NC4yMzItMS43ODctLjIxOS0xLjIzNCAxLjUtMS4zMjIgMS40My0uMjMuNzYyLS42MjQtLjYxNi0xLjAyMy0uNjE2LTEuMTczIDEuMzQ3LTEuMzA3IDMuNDEzLTEuMzk1IDUuMTItLjg3My45MTYuMjUgMS43MDQuODYyIDIuMDA2IDEuNzg2Ljg5NCAyLjA2NC40NzMgNC4zNTEuMjc4IDYuNTA0LS4xOCAxLjExNi40OTMgMi4wNzcgMS4zODEgMi40NjYuNDI2LjkxNyAxLjkxIDEuNzUyLjU3NSAyLjYwOC0xLjUzOSAxLjQ4OC0zLjY2MyAyLjQ3Ny01LjgzOCAyLjI1MnptOS4xMjMtMS42NjVjLTEuMjctLjQ3MS0xLjc3My0xLjc0Mi0yLjg4NC0yLjM2NS0uNTMzLS42MzgtLjk2LTEuMTU0LS4yOS0xLjc4My4yOTktMS4zNjggMS43OC0xLjg1MiAyLjQ1NC0yLjk4Ljc4Ny0uOTY4LjcwNC0yLjQzMS0uMjAyLTMuMjkxLS43OTctLjg2LTIuMDc2LTEuMjA2LTIuNTI3LTIuMzg1LTEuMjMtMS4wMi0zLjAyMS0xLjA1NS00LjQ5OS0xLjY3NS0xLjMyOC0uMTk0LTIuOTA1LS4yNjEtNC4wMjEuNjA2LTEuNDkyLjAzLTEuODA3IDEuNzc3LTIuNTk0IDIuNzI2LS43My42NDktMS42NTMgMS4yNjYtMS4xNTMgMi4zMzQtMS4wNDguNzE3LjE3OCAyLjAzNi42OTIgMi43NTQuMzA3IDEuMjAyLS45OTQgMy4xNzYuOTY4IDMuNTM4Ljc4NC4wMjYgMS4xNzMtLjg2OCAxLjc5Ni0uMDQzIDEuMzc1LjIyNSAxLjA5IDEuODk4IDEuMDE4IDIuOTM2LjA4Mi45MDItMS4wMiAxLjU2NS0uMzI5IDIuNS0uMTQuODc4LS4zMDMgMS42Ni0xLjI3Ni45MjMtMy45OTktMS43MTgtNi42NDktNi4xMy02LjE2Ny0xMC40NzMuMzM0LTQuMTIyIDMuMzc3LTcuODM0IDcuMzQ1LTguOTg4IDQuMDgtMS4zMSA4Ljg0Ny4yODggMTEuMzUzIDMuNzU1IDIuNTg0IDMuNDAxIDIuNzMxIDguMzguMzE2IDExLjkxWk0xMS43NjguMDAzQzYuODQ4LjAzOSAyLjE4NSAzLjQ0NS42NTIgOC4xMmMtMS40OTUgNC4xOC0uMzU4IDkuMTEzIDIuNzc2IDEyLjI0OSAzLjI1NiAzLjQ0IDguNjMzIDQuNTY5IDEzLjAxIDIuNzc0IDQuNjM2LTEuNzg5IDcuODMtNi42OTIgNy41NDItMTEuNjYtLjE1NS00LjY2My0zLjMtOS4wNC03LjY3MS0xMC42NzJhMTEuODcyIDExLjg3MiAwIDAgMC00LjU0LS44MVoiIHN0eWxlPSJmaWxsOiNGRkY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiLz48L3N2Zz4=\" /></a>\r\n<a href=\"https://pesde.dev/packages/mark_marks/rubine\"><img alt=\"Pesde\" src=\"https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fmark-marks%2Frubine%2Frefs%2Fheads%2Fmain%2Fpesde.toml&query=version&prefix=mark_marks%2Frubine%40&style=for-the-badge&label=pesde&color=F19D1E&logo=data:image/svg%2bxml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00OS42MDI1IDBMOTIuOTAzOCAyNVY3NUw0OS42MDI1IDEwMEw2LjMwMTI3IDc1VjI1TDQ5LjYwMjUgMFpNMTQuMzAxMyAyOS42MTg4TDQ5LjYwMjUgOS4yMzc2TDg0LjkwMzggMjkuNjE4OFY3MC4zODEyTDQ5LjYwMjUgOTAuNzYyNEwzMy42MTQ4IDgxLjUzMTlWNjcuMzg0OEMzNC41MTY3IDY4LjUwNzEgMzUuNjM4OCA2OS40MjE1IDM2Ljk4MSA3MC4xMjc5QzM4Ljk3MDEgNzEuMTQ4IDQxLjAzNTcgNzEuNjU4IDQzLjE3NzkgNzEuNjU4QzQ2LjQ0MiA3MS42NTggNDkuMTQ1MiA3MC44OTI5IDUxLjI4NzMgNjkuMzYyOUM1My40ODA1IDY3Ljc4MTggNTUuMTEyNiA2NS43NjcyIDU2LjE4MzYgNjMuMzE5QzU3LjA5MTUgNjEuMzM4MiA1Ny42MzIgNTkuMjc0IDU3LjgwNTQgNTcuMTI2M0M1OS44NzIzIDU3Ljc0NTcgNjIuMjE1NyA1OC4wNTU0IDY0LjgzNTYgNTguMDU1NEM2Ny42OTE4IDU4LjA1NTQgNzAuMzY5NSA1Ny42NDczIDcyLjg2ODYgNTYuODMxM0M3NS4zNjc4IDU1Ljk2NDIgNzcuNDA3OSA1NC44MTY3IDc4Ljk4OSA1My4zODg2TDc1Ljc3NTggNDcuODAzOEM3NC41NTE3IDQ4LjkyNTggNzIuOTk2MSA0OS44NDM5IDcxLjEwOSA1MC41NTc5QzY5LjIyMTkgNTEuMjIxIDY3LjIwNzMgNTEuNTUyNSA2NS4wNjUyIDUxLjU1MjVDNjEuMzkyOSA1MS41NTI1IDU4LjY2NDMgNTAuNjg1NCA1Ni44NzkyIDQ4Ljk1MTNDNTYuNzE5NSA0OC43OTYyIDU2LjU2NyA0OC42MzY1IDU2LjQyMTcgNDguNDcyQzU1LjYxMDIgNDcuNTUzOSA1NS4wMjExIDQ2LjQ4OTYgNTQuNjU0NiA0NS4yNzkxTDU0LjY0NDMgNDUuMjQ1Mkw1NC42NjkgNDUuMjc5MUg3OS4yMTg1VjQxLjk4OTRDNzkuMjE4NSAzOS4wMzEzIDc4LjU1NTUgMzYuMzUzNiA3Ny4yMjk0IDMzLjk1NjVDNzUuOTU0MyAzMS41NTkzIDc0LjA5MjcgMjkuNjQ2NyA3MS42NDQ1IDI4LjIxODZDNjkuMjQ3NCAyNi43Mzk1IDY2LjM2NTcgMjYgNjIuOTk5NSAyNkM1OS42ODQzIDI2IDU2LjgwMjcgMjYuNzM5NSA1NC4zNTQ1IDI4LjIxODZDNTEuOTA2NCAyOS42NDY3IDUwLjAxOTMgMzEuNTU5MyA0OC42OTMyIDMzLjk1NjVDNDcuNjc0MyAzNS43OTgzIDQ3LjA0NjkgMzcuODA1NyA0Ni44MTA4IDM5Ljk3ODhDNDUuNjg4OCAzOS43MjggNDQuNDc3OCAzOS42MDI2IDQzLjE3NzkgMzkuNjAyNkM0MS4wMzU3IDM5LjYwMjYgMzguOTcwMSA0MC4xMTI3IDM2Ljk4MSA0MS4xMzI3QzM1LjMxNjIgNDEuOTY1MSAzMy45OTAyIDQzLjE1NDkgMzMuMDAyOCA0NC43MDIzVjQwLjM2NzdIMjAuNjg1NVY0Ni4yNTg1SDI1LjgxMTNWNzcuMDI2NkwxNC4zMDEzIDcwLjM4MTJWMjkuNjE4OFpNNTUuMTk2MSAzNi4wOTg2QzU0LjY1MjggMzcuMTAxNSA1NC4zMzIxIDM4LjEyMTYgNTQuMjM0IDM5LjE1ODhINzEuNzk3NkM3MS43OTc2IDM4LjAzNjcgNzEuNDQwNSAzNi45NDAxIDcwLjcyNjUgMzUuODY5MUM3MC4wNjM0IDM0Ljc0NyA2OS4wNjg5IDMzLjgwMzUgNjcuNzQyOCAzMy4wMzg0QzY2LjQ2NzcgMzIuMjczNCA2NC44ODY3IDMxLjg5MDggNjIuOTk5NSAzMS44OTA4QzYxLjExMjQgMzEuODkwOCA1OS41MDU4IDMyLjI5ODkgNTguMTc5OCAzMy4xMTQ5QzU2LjkwNDcgMzMuODggNTUuOTEwMSAzNC44NzQ1IDU1LjE5NjEgMzYuMDk4NlpNNDkuNjQ1MSA1MS41NjkyQzQ5LjMwNzYgNTAuNjY0MSA0OC44MzgxIDQ5Ljg3MSA0OC4yMzY3IDQ5LjE4OThDNDguMDg4NSA0OS4wMjE5IDQ3LjkzMjMgNDguODYwOSA0Ny43NjgxIDQ4LjcwNjdDNDYuMDg1IDQ3LjA3NDYgNDQuMDQ0OSA0Ni4yNTg1IDQxLjY0NzggNDYuMjU4NUM0MC4xMTc3IDQ2LjI1ODUgMzguNjEzMSA0Ni41NjQ1IDM3LjEzNCA0Ny4xNzY2QzM1Ljg1OTQgNDcuNjc3MyAzNC42ODYzIDQ4LjU0MzggMzMuNjE0OCA0OS43NzU5VjYxLjQ3QzM0LjY4NjMgNjIuNjY2NCAzNS44NTk0IDYzLjUzNzggMzcuMTM0IDY0LjA4NEMzOC42MTMxIDY0LjY5NjEgNDAuMTE3NyA2NS4wMDIxIDQxLjY0NzggNjUuMDAyMUM0NC4wNDQ5IDY1LjAwMjEgNDYuMDg1IDY0LjE4NjEgNDcuNzY4MSA2Mi41NTRDNDkuNDUxMiA2MC45MjE5IDUwLjI5MjggNTguNjAxMiA1MC4yOTI4IDU1LjU5MjFDNTAuMjkyOCA1NC4wNjc5IDUwLjA3NjkgNTIuNzI3IDQ5LjY0NTEgNTEuNTY5MloiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KPC9zdmc+\" /></a>\r\n[![Typescript Version](https://img.shields.io/npm/v/@rbxts/rubine.svg?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/@rbxts/rubine)\r\n\r\nAn ergonomic, runtime agnostic scheduler for [Jecs](https://github.com/ukendio/jecs)\r\n<br/>\r\n\r\n</div>\r\n\r\n## Features\r\n\r\n### 1. Phases\r\nRubine uses phases to bind systems to events and order them.\r\n\r\nPhases live in rubine's Jecs world, having the `Phase` tag, and either the `Event` component or a dependant pair (`pair(DependsOn, another_phase)`).\r\n\r\nPhases can be ordered implicitly:\r\n```luau\r\nlocal event = signal()\r\nlocal my_phase = scheduler.phase(\"my_phase\", event)\r\nlocal my_phase_b = scheduler.phase(\"my_phase_b\", event) -- Ordered after `my_phase`\r\n```\r\nor explicitly:\r\n```luau\r\nlocal event = signal()\r\nlocal my_phase = scheduler.phase(\"my_phase\", event)\r\nlocal my_phase_b = scheduler.phase(\"my_phase_b\", my_phase) -- Ordered after `my_phase`\r\n```\r\nMultiple phases cannot be bound to the same event, but instead depend on one another.\r\n\r\n### 2. Systems\r\nSystems are bound to phases. Whenever an event the system is (indirectly) on is fired, it's ran.\r\n\r\nSystems live in rubine's Jecs world, having the `System` component describing it, and a pair describing what phase it runs on (`pair(DependsOn, phase)`).\r\n\r\nSystems are created with `scheduler.on`:\r\n```luau\r\nlocal function system()\r\nend\r\n\r\nlocal my_system = scheduler.on(my_phase, system)\r\n```\r\ncan have their execution paused:\r\n```luau\r\nscheduler.pause(my_system)\r\n```\r\nand unpaused:\r\n```luau\r\nscheduler.unpause(my_system)\r\n```\r\n\r\nSystems also contain data about the moment they started running and ended, being reset on every run.\r\n```luau\r\ntype System = {\r\n    run: (...any) -> (),\r\n    paused: boolean,\r\n    frame_start: number,\r\n    frame_end: number,\r\n}\r\n```\r\n\r\nSystems cannot yield without `_G.__RUBINE_DEBUG_MODE` being true.\r\n\r\n### 3. Hooks\r\nHooks are available via the `abstractions` module.\r\nUnder the hood, they use Jecs hooks to observe changes to the world and run user defined callbacks on them.\r\n\r\nWith them, you can hook onto system calls\r\n```luau\r\nabstractions.hook(\"SystemCall\", function(system_id: Entity, system_data: System, previous_data: System)\r\nend)\r\n```\r\nsystem additions\r\n```luau\r\nabstractions.hook(\"SystemAdd\", function(system_id: Entity, system_data: System)\r\nend)\r\n```\r\nsystem removals\r\n```luau\r\nabstractions.hook(\"SystemRemove\", function(system_id: Entity)\r\nend)\r\n```\r\nand all system changes\r\n```luau\r\nabstractions.hook(\"SystemChange\", function(systme_id: Entity, system_data: System, previous_data: System)\r\nend)\r\n```\r\n\r\n### 4. Pipes\r\nPipes are a tiny abstraction over phases, mainly meant to be used with pipelines.\r\nAll pipe names are unique, being the script name and the line number of where they were defined.\r\n```luau\r\nlocal my_pipe = abstractions.pipe()\r\nscheduler.phase(my_pipe, event)\r\n```\r\n\r\n### 5. Pipelines\r\nPipelines are an abstraction over phases, allowing for handy implicit ordering.\r\n```luau\r\nlocal pipe_a = abstractions.pipe()\r\nlocal pipe_b = abstractions.pipe()\r\nlocal pipe_c = abstractions.pipe()\r\n\r\n-- Pipe A is bound to the given event\r\n-- Pipe B depends on Pipe A\r\n-- Pipe C depends on Pipe B\r\nabstractions.pipeline()\r\n    :with(pipe_a)\r\n    :with(pipe_b)\r\n    :with(pipe_c)\r\n    :build(event)\r\n```\r\n\r\n## Installation\r\n\r\n### Pesde\r\nAvailable for use in standalone luau.\r\n\r\n1. `pesde add mark_marks/rubine`\r\n2. `pesde install`\r\n\r\n### Wally\r\nAvailable for use in Roblox.\r\n\r\n1. Add it to your wally manifest\r\n```toml\r\n[dependencies]\r\nrubine = \"mark-marks/rubine@LATEST\" # Replace LATEST with the latest version\r\n```\r\n2. `wally install`\r\n\r\n### NPM (roblox-ts)\r\n1. `npm add @rbxts/rubine`\r\n2. `npm install`\r\n\r\n## Honorable Mentions\r\n\r\n- Abstractions were inspired by the ecs agnostic [Planck scheduler](https://github.com/YetAnotherClown/Planck).\r\n- Logo was kindly created by [alice](https://github.com/alicesaidhi).\r\n","readmeTruncated":false}