riptide/core
A lightweight and professional framework for Roblox.
____ _ __ _ __
/ __ \(_)___ / /_(_)___/ /__
/ /_/ / / __ \/ __/ / __ / _ \
/ _, _/ / /_/ / /_/ / /_/ / __/
/_/ |_/_/ .___/\__/_/\__,_/\___/
/_/
๐ Riptide Framework
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.
๐ฆ Installation
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.
Via Pesde (recommended)
Add Riptide to your pesde.toml dependencies:
[dependencies]
Riptide = { name = "riptide/core", version = "^0.5.0", target = "roblox" }
Then install dependencies:
pesde install
Via Wally
Add Riptide to your wally.toml:
[dependencies]
Riptide = "thereplicatedfirst/riptide@^0.5.0"
Manual
Download Riptide.rbxm from the latest release and insert it into ReplicatedStorage.
๐ How to Start
Riptide does not start automatically. You must launch the framework from your own Server and Client entry points.
Server Initialization (main.server.lua)
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
})
Client Initialization (main.client.lua)
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
})
๐ Module Lifecycle & Dependency Injection (DI)
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.
Example DI Module
--!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 PlayerState
๐ก Networking (Riptide.Network)
Riptide 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.
๐งฉ ComponentService (Riptide.ComponentService)
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.
Example Component (Lava.lua)
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 Lava
API
ComponentService:Get(instance): Get the first component attached to an instance.ComponentService:Get(instance, tagName): Get a specific component by tag name.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.