import React from 'react'; import { ContentPage } from '../components/ContentPage'; import { CodeBlock } from '../components/CodeBlock'; export const IntroductionPage: React.FC = () => { const intro = ( <>

Chemical is a Luau library designed for building applications with a reactive programming paradigm, primarily within environments like Roblox. It provides tools for managing state, creating derived data, handling side effects, and composing user interfaces in a declarative way.

Inspired by modern frontend frameworks, Chemical aims to simplify complex state interactions and UI logic by providing a structured and predictable way to handle data flow.

); const sections = [ { title: "Key Features", entries: [ { signature: "Reactive Primitives", description: "Includes `Value`, `Computed`, and `Effect` for fine-grained reactive control.", example: ` local Chemical = require(game.ReplicatedStorage.Chemical) local Value = Chemical.Value local Computed = Chemical.Computed local Effect = Chemical.Effect -- Create a reactive value local count = Value(0) -- Create a computed value derived from count local doubled = Computed(function() return count:get() * 2 end) -- Create an effect that runs when count changes Effect(function() print("Count changed to:", count:get()) print("Doubled is:", doubled:get()) end) count:set(5) -- This will trigger the effect -- Output: -- Count changed to: 5 -- Doubled is: 10 `, }, { signature: "Stateful Collections", description: "Manage lists and dictionaries with `Table` and `Map`, which propagate changes reactively.", example: ` local Chemical = require(game.ReplicatedStorage.Chemical) local Table = Chemical.Table local Effect = Chemical.Effect local items = Table({"apple", "banana"}) Effect(function() print("Items:", table.concat(items:get(), ", ")) end) items:insert("cherry") -- Output: -- Items: apple, banana -- (After scheduler runs) -- Items: apple, banana, cherry `, }, { signature: "Declarative UI Composition", description: "Use the `Compose` API to build and update UI elements based on reactive state.", example: ` local Chemical = require(game.ReplicatedStorage.Chemical) local Value = Chemical.Value local Computed = Chemical.Computed local Compose = Chemical.Compose local Children = Chemical.Symbols.Children -- Alias for Children key -- Assuming playerGui is defined: local playerGui = game.Players.LocalPlayer:WaitForChild("PlayerGui") local name = Value("Player") local score = Value(100) local MyScreenGui = Compose("ScreenGui")({ Parent = playerGui, [Children] = { -- Use the aliased Children symbol Compose("TextLabel")({ Name = "PlayerName", Position = UDim2.new(0.5, 0, 0.1, 0), AnchorPoint = Vector2.new(0.5, 0.5), Text = Computed(function() return "Name: " .. name:get() end), TextColor3 = Color3.new(1,1,1), BackgroundTransparency = 1, Size = UDim2.new(0, 200, 0, 30) }), Compose("TextLabel")({ Name = "PlayerScore", Position = UDim2.new(0.5, 0, 0.2, 0), AnchorPoint = Vector2.new(0.5, 0.5), Text = Computed(function() return "Score: " .. score:get() end), TextColor3 = Color3.new(1,1,1), BackgroundTransparency = 1, Size = UDim2.new(0, 200, 0, 30) }) } }) -- Later, when state changes, the UI updates automatically name:set("Hero") score:set(150) `, }, { signature: "Networked State with Reactors", description: "Synchronize state across server and clients using `Reactor` and `Reaction` objects for multiplayer experiences.", example: ` local Chemical = require(game.ReplicatedStorage.Chemical) local Value = Chemical.Value local Reactor = Chemical.Reactor local Effect = Chemical.Effect -- Server-side local PlayerDataReactor = Reactor({ Name = "PlayerData" }, function(key_playerIdString, initialData) -- 'key_playerIdString' is the key, typically not stored in this returned table. initialData = initialData or {} return { Health = Value(initialData.Health or 100), Mana = Value(initialData.Mana or 50) } end) local player1DataReaction = PlayerDataReactor:create("player1_id", { Health = 90 }) -- Access properties directly on the reaction: player1DataReaction.Health:set(80) -- Change will replicate -- Client-side local player1DataClient = PlayerDataReactor:await("player1_id") -- player1DataClient is now the Reaction object if player1DataClient then Effect(function() print("Player 1 Health:", player1DataClient.Health:get()) end) end `, }, ], }, { title: "Philosophy", entries: [ { signature: "Data Flow", description: "Chemical promotes a unidirectional data flow. State changes trigger computations, which in turn can trigger effects (like UI updates or network calls). This makes applications easier to reason about.", example: ` local Chemical = require(game.ReplicatedStorage.Chemical) local Value = Chemical.Value local Computed = Chemical.Computed local Effect = Chemical.Effect -- State (Value) -> Derived State (Computed) -> Side Effect (Effect) local function UpdateDisplay(text) print("Display: " .. text) end local price = Value(10) local quantity = Value(2) local totalCost = Computed(function() return price:get() * quantity:get() end) Effect(function() UpdateDisplay("Total Cost: $" .. totalCost:get()) end) price:set(12) -- Triggers totalCost recomputation, then updates display quantity:set(3) -- Triggers totalCost recomputation, then updates display ` }, { signature: "Modularity", description: "The library is structured with clear separation of concerns: core reactivity, state management, UI composition, and networking are distinct but interoperable parts.", example: ` local Chemical = require(game.ReplicatedStorage.Chemical) -- Assuming modules are set up in ReplicatedStorage.Chemical.Modules -- local PlayerProfileReactor = require(game.ReplicatedStorage.Chemical.Modules.PlayerProfileReactor) -- Uses Reactor -- local HUD = require(game.ReplicatedStorage.Chemical.Modules.HUDComponent) -- Uses Compose -- Mock for example purposes local PlayerProfileReactor = { await = function(playerId) print("Mock Reactor: Awaiting profile for", playerId) -- Simulate awaiting a profile by returning it directly for example simplicity -- In a real scenario, this would yield until the data is available. return { UserId = playerId, Name = Chemical.Value("MockPlayer-" .. playerId:sub(1,4)) } end } local HUD = { Render = function(profile) print("Rendering HUD for", profile.Name:get()) end } -- End Mock local player = game.Players.LocalPlayer local profileReaction = PlayerProfileReactor:await(tostring(player.UserId)) if profileReaction then HUD.Render(profileReaction) -- HUD component consumes reactive profile data end ` } ] } ]; return ; };