____ _ __ _ __
/ __ \(_)___ / /_(_)___/ /__
/ /_/ / / __ \/ __/ / __ / _ \
/ _, _/ / /_/ / /_/ / /_/ / __/
/_/ |_/_/ .___/\__/_/\__,_/\___/
/_/
Riptide 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.
Warning
v0.5.0 is the last release with first-class Wally support.
Starting from the next major cycle, Pesde is the primary package manager.
Add Riptide to your pesde.toml dependencies:
[dependencies]
Riptide = { name = "riptide/core", version = "^0.5.0", target = "roblox" }Then install dependencies:
pesde installAdd Riptide to your wally.toml:
[dependencies]
Riptide = "thereplicatedfirst/riptide@^0.5.0"Download Riptide.rbxm from the latest release and insert it into ReplicatedStorage.
Riptide does not start automatically. You must launch the framework from your own Server and Client entry points.
local Riptide = require(ReplicatedStorage.Packages.Riptide)
local MyServerModules = ServerScriptService:WaitForChild("MyServerModules")
local MySharedModules = ReplicatedStorage:WaitForChild("SharedModules")
local MyComponents = ReplicatedStorage:WaitForChild("Components") -- optional
Riptide.Server.Launch({
ModulesFolder = MyServerModules, -- Folder or { Folder, ... }
SharedModulesFolder = MySharedModules, -- optional: Folder or { Folder, ... }
ComponentsFolder = MyComponents, -- optional
})local Riptide = require(ReplicatedStorage.Packages.Riptide)
local MyClientModules = ReplicatedStorage:WaitForChild("MyClientModules")
local MySharedModules = ReplicatedStorage:WaitForChild("SharedModules")
local MyComponents = ReplicatedStorage:WaitForChild("Components") -- optional
Riptide.Client.Launch({
ModulesFolder = { MyClientModules }, -- Folder or { Folder, ... }
SharedModulesFolder = { MySharedModules }, -- optional: Folder or { Folder, ... }
ComponentsFolder = MyComponents, -- optional
})Riptide completely eliminates the need for require() circles. Any ModuleScript inside your designated ModulesFolder will be automatically loaded into the Riptide Registry.
Note
Services and Controllers are registered by canonical module ID (relative path from ModulesFolder, e.g. Economy/PlayerData).
Short names are still supported as aliases when unique.
If two modules share the same short name, Riptide marks that alias as ambiguous and requires full canonical path lookups.
Examples:
Riptide.GetService("Economy/PlayerData")β always deterministicRiptide.GetService("PlayerData")β only if alias is uniqueRiptide.GetService("Data")β οΈ returnsnilwhen alias is ambiguous
Methods are executed in strict phases:
Init(Riptide): Called synchronously. Use this toGetServiceorGetControllerand set up your variables.Start(Riptide): Called asynchronously viatask.spawn. All modules are fully initialized at this point, so it is safe to interact with them and run game logic.
--!strict
local RiptidePkg = require(ReplicatedStorage.Packages.Riptide)
type Riptide = RiptidePkg.Riptide
local PlayerState = {}
function PlayerState:Init(Riptide: Riptide)
-- Easily inject other modules
self.DataService = Riptide.GetService("DataService")
-- Listen to the unified Network layer
Riptide.Network.Register("PlayerJumped", function(player, height)
print(player.Name .. " jumped " .. height .. " studs!")
end)
end
function PlayerState:Start(Riptide: Riptide)
self.DataService:GiveMoney(100)
end
return PlayerStateRiptide automatically creates a single RemoteEvent and RemoteFunction inside its own package under the hood. No ReplicatedStorage clutter!
As of v0.4.0, network event dispatch uses a reusable trampoline handler in the hot-path to reduce closure allocations during heavy event traffic.
Client-Side API
Network.Register(name, callback): Listen for server events.Network.Unregister(name, callback): Remove a previously registered handler.Network.FireServer(name, ...): Send event data to the server.Network.InvokeServer(name, ...): Request data from the server.
Server-Side API
Network.Register(name, callback): Listen for client events. Callback automatically receivesplayeras the first argument.Network.Unregister(name, callback): Remove a previously registered handler.Network.FireClient(player, name, ...): Send event data to a specific player.Network.FireAllClients(name, ...): Broadcast event data to everyone.Network.InvokeClient(player, name, ...): Request data from a client.
A shared (server & client) system for managing component objects linked to tagged Instances via CollectionService.
As of v0.4.0, ComponentService startup is idempotent: repeated _start(...) calls are ignored to prevent duplicated CollectionService listeners.
Each Component is a ModuleScript whose name matches the tag. It must expose a new(instance) constructor and optionally a Destroy(self) cleanup method.
local Lava = {}
Lava.__index = Lava
function Lava.new(instance: BasePart)
local self = setmetatable({
_instance = instance,
_connection = nil :: RBXScriptConnection?,
}, Lava)
self._connection = instance.Touched:Connect(function(hit)
local humanoid = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if humanoid then
(humanoid :: Humanoid):TakeDamage(10)
end
end)
return self
end
function Lava:Destroy()
if self._connection then
self._connection:Disconnect()
self._connection = nil
end
end
return LavaAPI
ComponentService:Get(instance): Get the first component attached to an instance.ComponentService:Get(instance, tagName): Get a specific component by tag name.
This project is licensed under the MIT License - see the LICENSE file for details.