Chance is a combination of Charm + Instance: a declarative approach to Instance properties and hierarchy in Roblox with reactivity, animation, and lifecycle management.
Chance enables:
- declarative definition of any
Instanceproperties - binding values to reactive computations via
Charm - animating properties using
Ripple(spring,tween) - managing child instance lists with
setChildren - automatic resource cleanup using scopes (
createScope/fastHydrate)
Chance = "alexeylegasov63/chance@latest"local Charm = require(path.to.Charm)
local Chance = require(path.to.Chance)
local part = Instance.new("Part")
local nameAtom = Charm.atom("CoolName")
local destroy = Chance.fastHydrate(part, {
Name = function()
local name = nameAtom()
print("Current name:", name)
return name
end,
})
task.wait(1)
nameAtom("NotCoolName")
-- When you need to remove all subscriptions and animations:
destroy()Chance.createScope(callback)— create a scope where cleanup can be registeredChance.fastHydrate(instance, props)— hydrate an instance and return a destroy functionChance.hydrate(cleanup, instance, props)— apply properties to an instance within an existing scopeChance.setChildren(selector, constructor)— declare a list of childInstancesChance.setSpring(callback, config?)— bind a property to a spring animationChance.setTween(callback, config?)— bind a property to a tween animationChance.derive(value)— extract a value from aDerivableChance.setRendered,Chance.setInterval— useful hooks (render / heartbeat interval)
Chance supports plain values and computed functions.
local color = Charm.atom(Color3.new(1, 1, 1))
local big = Charm.atom(false)
local props = {
-- Just values
Name = "MyPart",
Transparency = 0.5,
Position = Vector3.new(1, 2, 3),
Color = color, -- Computed
Size = function() -- Computed
local isBig = big()
return Vector3.one * (isBig and 30 or 3)
end,
}If a value is a function, Chance automatically computes it, subscribes to updates, and applies changes.
Use setChildren to manage a list of child instances.
local Chance = require(path.to.Chance)
local data = Charm.atom({
{ Name = "A", Position = Vector3.new(0, 5, 0) },
{ Name = "B", Position = Vector3.new(2, 5, 0) },
})
local root = Instance.new("Folder")
local destroy = Chance.fastHydrate(root, {
Children = Chance.setChildren(function()
return items
end, function(data)
local part = Instance.new("Part")
part.Name = data.Name
part.Position = data.Position
part.Anchored = true
return part -- Will be destroyed automatically
end),
})
-- If `items` changes, Chance automatically updates the child instances.setChildren returns a prepared object with a selector and constructor.
Chance observes the selector, creates an Instance for each item, and destroys old objects when the list changes.
Chance integrates Ripple for property animation.
local targetPosition = Vector3.new(0, 10, 0)
local destroy = Chance.fastHydrate(part, {
Position = Chance.setSpring(function()
return targetPosition
end, {
frequency = 4,
dampingRatio = 0.8,
}),
})
-- When targetPosition changes, the spring smoothly moves the part.The tween syntax is the same:
local destroy = Chance.fastHydrate(part, {
Position = Chance.setTween(function()
return targetPosition + Vector3.new(1, 0, 3) -- Apply an offset for example
end, { -- Just different configuration
duration = 0.5,
easing = "quadInOut",
}),
})A scope ensures that all subscriptions and resources are cleaned up when it is destroyed.
local Chance = require(path.to.Chance)
local destroy = Chance.createScope(function(cleanup, extend)
local part = Instance.new("Part")
part.Parent = workspace
cleanup(Chance.hydrate(cleanup, part, {
Position = Chance.setRendered(function()
return Vector3.new(0, math.sin(os.clock()) * 5, 0)
end),
}))
cleanup(part) -- Will be destroyed
print("Hello world!")
cleanup(function()
print("Bye world!")
end)
local destroySub = extend(function(cleanup2, extend2)
print("Sub scope!")
end)
-- destroySub() -- Optional, will be destroyed automatically with the root scope
end)
-- When the scope is no longer needed:
destroy()createScope passes two functions to the callback:
cleanup(item)— register a resource for automatic cleanupextend(callback)— create a nested scope within the current one
local Chance = require(path.to.Chance)
local position = Charm.atom(Vector3.zero)
local part = Instance.new("Part")
part.Anchored = true
part.Parent = workspace
local destroy = Chance.fastHydrate(part, {
Position = Chance.setSpring(position, { -- Animated moving
frequency = 10
}),
Color = function()
local color = if position().Y > 0 then 1 else 0 -- White when above Y 0
return Color3.new(color, color, color)
end,
})
-- Move it every second
while task.wait(1) do
position(Vector3.new(math.random(-5, 5), math.random(-5, 5), math.random(-5, 5)))
end
Chance is a bridge between reactive Charm and Roblox's object model. It makes working with Instance declarative, manages the animations and subscriptions automatically.
Littensy (https://github.com/littensy) for the amazing libraries: Charm and Ripple :3