Skip to content

riptide-project/framework

Repository files navigation

    ____  _       __  _     __   
   / __ \(_)___  / /_(_)___/ /__ 
  / /_/ / / __ \/ __/ / __  / _ \
 / _, _/ / /_/ / /_/ / /_/ /  __/
/_/ |_/_/ .___/\__/_/\__,_/\___/ 
       /_/                       

🌊 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 deterministic
  • Riptide.GetService("PlayerData") βœ… only if alias is unique
  • Riptide.GetService("Data") ⚠️ returns nil when alias is ambiguous

Methods are executed in strict phases:

  1. Init(Riptide): Called synchronously. Use this to GetService or GetController and set up your variables.
  2. 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.

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 receives player as 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.

About

🌊 A lightweight, strictly-typed, and modular framework for Roblox

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages