{"id":"thereplicatedfirst/riptide","name":"riptide","scope":"thereplicatedfirst","platform":"roblox","description":"A lightweight and professional framework for Roblox.","version":"0.5.0","latest":"0.5.0","versions":["0.1.0","0.1.1","0.2.0","0.3.0","0.4.0","0.5.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":["License identified from the packaged LICENSE file; the manifest declared none."],"licenseVerified":true,"dependencies":{},"integrity":"b70d9e4451d2ef757ee219018390aee4c971b4503612cd53f5cf36b5c08a1223","likes":0,"downloads":0,"install":"forest install thereplicatedfirst/riptide","url":"https://forest.dev/p/roblox/thereplicatedfirst/riptide","files":"https://api.forest.dev/ai/package/roblox/thereplicatedfirst/riptide/files","readme":"```text\n    ____  _       __  _     __   \n   / __ \\(_)___  / /_(_)___/ /__ \n  / /_/ / / __ \\/ __/ / __  / _ \\\n / _, _/ / /_/ / /_/ / /_/ /  __/\n/_/ |_/_/ .___/\\__/_/\\__,_/\\___/ \n       /_/                       \n```\n\n# 🌊 Riptide Framework\n\nRiptide is a lightweight, strictly-typed, and modular Roblox framework. It features phased initialization, safe dependency injection, a robust unified networking layer, and a shared ComponentService for managing tagged instances.\n\n## 📦 Installation\n\n> [!WARNING]\n> `v0.5.0` is the last release with first-class Wally support.\n> Starting from the next major cycle, Pesde is the primary package manager.\n\n### Via Pesde (recommended)\nAdd Riptide to your `pesde.toml` dependencies:\n```toml\n[dependencies]\nRiptide = { name = \"riptide/core\", version = \"^0.5.0\", target = \"roblox\" }\n```\n\nThen install dependencies:\n```bash\npesde install\n```\n\n### Via Wally\nAdd Riptide to your `wally.toml`:\n```toml\n[dependencies]\nRiptide = \"thereplicatedfirst/riptide@^0.5.0\"\n```\n\n### Manual\nDownload `Riptide.rbxm` from the [latest release](https://github.com/riptide-project/framework/releases/latest) and insert it into `ReplicatedStorage`.\n\n## 🏁 How to Start\n\nRiptide does not start automatically. You must launch the framework from your own Server and Client entry points.\n\n### Server Initialization (`main.server.lua`)\n```lua\nlocal Riptide = require(ReplicatedStorage.Packages.Riptide)\nlocal MyServerModules = ServerScriptService:WaitForChild(\"MyServerModules\")\nlocal MySharedModules = ReplicatedStorage:WaitForChild(\"SharedModules\")\nlocal MyComponents = ReplicatedStorage:WaitForChild(\"Components\") -- optional\n\nRiptide.Server.Launch({\n    ModulesFolder = MyServerModules, -- Folder or { Folder, ... }\n    SharedModulesFolder = MySharedModules, -- optional: Folder or { Folder, ... }\n    ComponentsFolder = MyComponents, -- optional\n})\n```\n\n### Client Initialization (`main.client.lua`)\n```lua\nlocal Riptide = require(ReplicatedStorage.Packages.Riptide)\nlocal MyClientModules = ReplicatedStorage:WaitForChild(\"MyClientModules\")\nlocal MySharedModules = ReplicatedStorage:WaitForChild(\"SharedModules\")\nlocal MyComponents = ReplicatedStorage:WaitForChild(\"Components\") -- optional\n\nRiptide.Client.Launch({\n    ModulesFolder = { MyClientModules }, -- Folder or { Folder, ... }\n    SharedModulesFolder = { MySharedModules }, -- optional: Folder or { Folder, ... }\n    ComponentsFolder = MyComponents, -- optional\n})\n```\n\n## 🚀 Module Lifecycle & Dependency Injection (DI)\n\nRiptide completely eliminates the need for `require()` circles. Any `ModuleScript` inside your designated `ModulesFolder` will be automatically loaded into the Riptide Registry.\n\n> [!NOTE]\n> Services and Controllers are registered by canonical module ID (relative path from `ModulesFolder`, e.g. `Economy/PlayerData`).\n> Short names are still supported as aliases when unique.\n\nIf two modules share the same short name, Riptide marks that alias as ambiguous and requires full canonical path lookups.\n\nExamples:\n- `Riptide.GetService(\"Economy/PlayerData\")` ✅ always deterministic\n- `Riptide.GetService(\"PlayerData\")` ✅ only if alias is unique\n- `Riptide.GetService(\"Data\")` ⚠️ returns `nil` when alias is ambiguous\n\nMethods are executed in strict phases:\n1. **`Init(Riptide)`**: Called synchronously. Use this to `GetService` or `GetController` and set up your variables.\n2. **`Start(Riptide)`**: Called asynchronously via `task.spawn`. All modules are fully initialized at this point, so it is safe to interact with them and run game logic.\n\n### Example DI Module\n```lua\n--!strict\nlocal RiptidePkg = require(ReplicatedStorage.Packages.Riptide)\ntype Riptide = RiptidePkg.Riptide\n\nlocal PlayerState = {}\n\nfunction PlayerState:Init(Riptide: Riptide)\n    -- Easily inject other modules\n    self.DataService = Riptide.GetService(\"DataService\")\n    \n    -- Listen to the unified Network layer\n    Riptide.Network.Register(\"PlayerJumped\", function(player, height)\n        print(player.Name .. \" jumped \" .. height .. \" studs!\")\n    end)\nend\n\nfunction PlayerState:Start(Riptide: Riptide)\n    self.DataService:GiveMoney(100)\nend\n\nreturn PlayerState\n```\n\n## 📡 Networking (`Riptide.Network`)\n\nRiptide automatically creates a single RemoteEvent and RemoteFunction inside its own package under the hood. No `ReplicatedStorage` clutter!\n\nAs of `v0.4.0`, network event dispatch uses a reusable trampoline handler in the hot-path to reduce closure allocations during heavy event traffic.\n\n**Client-Side API**\n- `Network.Register(name, callback)`: Listen for server events.\n- `Network.Unregister(name, callback)`: Remove a previously registered handler.\n- `Network.FireServer(name, ...)`: Send event data to the server.\n- `Network.InvokeServer(name, ...)`: Request data from the server.\n\n**Server-Side API**\n- `Network.Register(name, callback)`: Listen for client events. Callback automatically receives `player` as the first argument.\n- `Network.Unregister(name, callback)`: Remove a previously registered handler.\n- `Network.FireClient(player, name, ...)`: Send event data to a specific player.\n- `Network.FireAllClients(name, ...)`: Broadcast event data to everyone.\n- `Network.InvokeClient(player, name, ...)`: Request data from a client.\n\n## 🧩 ComponentService (`Riptide.ComponentService`)\n\nA shared (server & client) system for managing component objects linked to tagged Instances via `CollectionService`.\n\nAs of `v0.4.0`, ComponentService startup is idempotent: repeated `_start(...)` calls are ignored to prevent duplicated CollectionService listeners.\n\nEach Component is a `ModuleScript` whose name matches the tag. It must expose a `new(instance)` constructor and optionally a `Destroy(self)` cleanup method.\n\n### Example Component (`Lava.lua`)\n```lua\nlocal Lava = {}\nLava.__index = Lava\n\nfunction Lava.new(instance: BasePart)\n    local self = setmetatable({\n        _instance = instance,\n        _connection = nil :: RBXScriptConnection?,\n    }, Lava)\n\n    self._connection = instance.Touched:Connect(function(hit)\n        local humanoid = hit.Parent and hit.Parent:FindFirstChild(\"Humanoid\")\n        if humanoid then\n            (humanoid :: Humanoid):TakeDamage(10)\n        end\n    end)\n\n    return self\nend\n\nfunction Lava:Destroy()\n    if self._connection then\n        self._connection:Disconnect()\n        self._connection = nil\n    end\nend\n\nreturn Lava\n```\n\n**API**\n- `ComponentService:Get(instance)`: Get the first component attached to an instance.\n- `ComponentService:Get(instance, tagName)`: Get a specific component by tag name.\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.","readmeTruncated":false}