Best Practices

Examples Updated: Dec 10, 2025

Best Practices

Tips for building quality addons with cLib.

1. Always Wait for cLib

-- ✅ Good
hook.Add("cLib.OnLoaded", "MyAddon", function()
    -- Initialize here
end)

-- ❌ Bad - cLib might not be loaded
MyAddon.Init()

2. Use Unique Prefixes

-- ✅ Good
cLib.AddColor("MyAddon.Primary", Color(100, 150, 200))
cLib.CreateFont("MyAddon.Title", "Roboto", 0.03)
cLib.Net.SetPrefix("MyAddon.")

-- ❌ Bad - might conflict with other addons
cLib.AddColor("Primary", Color(100, 150, 200))

3. Use cLib.Scale for UI

-- ✅ Good - scales on all resolutions
panel:SetSize(cLib.Scale(500), cLib.Scale(400))

-- ❌ Bad - too small on 4K, too big on 720p
panel:SetSize(500, 400)

4. Validate Network Data

-- ✅ Good
cLib.Net.Receive("Data", function(data, ply)
    -- Server: validate player
    if SERVER and (not IsValid(ply) or not ply:IsAdmin()) then
        return
    end
    
    -- Validate data
    if not data or type(data.value) ~= "number" then
        return
    end
    
    ProcessData(data)
end)

-- ❌ Bad - no validation
cLib.Net.Receive("Data", function(data, ply)
    ProcessData(data)  -- Exploitable!
end)

5. Clean Up Resources

-- ✅ Good
function PANEL:OnRemove()
    if self._animId then
        cLib.StopAnimation(self._animId)
    end
    if timer.Exists(self._timerName) then
        timer.Remove(self._timerName)
    end
end

-- ❌ Bad - animations/timers keep running

6. Use Debug During Development

-- ✅ Good
if MyAddon.Config.DebugMode then
    cLib.Debug.SetEnabled(true)
    cLib.Debug.SetPrefix("[MyAddon]")
    cLib.Debug.SetLevel("DEBUG")
end

cLib.Debug.Info("Player loaded:", ply:Nick())
cLib.Debug.Time("DataProcess", function()
    ProcessLargeData()
end)

7. Use i18n for Text

-- ✅ Good
button:SetText(cLib.L("myaddon.save"))
cLib.Alert(cLib.L("myaddon.error"), cLib.L("myaddon.error.save"))

-- ❌ Bad - hardcoded English
button:SetText("Save")

8. Handle Edge Cases

-- ✅ Good
function MyAddon.GetPlayerData(ply)
    if not IsValid(ply) then return {} end
    if not ply:IsPlayer() then return {} end
    
    local steamid = ply:SteamID64()
    if not steamid then return {} end
    
    return MyAddon.Data[steamid] or {}
end

9. Use Proper Animations

-- ✅ Good - smooth easing
cLib.AnimateAlpha(panel, 0, 0.3, cLib.Ease.OutQuad, function()
    panel:Remove()
end)

-- ❌ Bad - abrupt
panel:Remove()

10. Organize Code Logically

-- ✅ Good file structure
myaddon/
  sh_config.lua      -- Configuration first
  sh_lang.lua        -- Then language
  sv_database.lua    -- Server systems
  sv_network.lua
  sv_functions.lua
  cl_network.lua     -- Client systems
  cl_menu.lua
  cl_hud.lua

Performance Tips

-- Cache lookups
local myColor = cLib.GetColor("MyAddon.Primary")

function PANEL:Paint(w, h)
    -- ✅ Good - use cached color
    draw.RoundedBox(8, 0, 0, w, h, myColor)
    
    -- ❌ Bad - lookup every frame
    draw.RoundedBox(8, 0, 0, w, h, cLib.GetColor("MyAddon.Primary"))
end

-- Use Think sparingly
function PANEL:Think()
    -- Only update when needed
    if CurTime() < self._nextUpdate then return end
    self._nextUpdate = CurTime() + 0.1  -- 10 times per second
    
    self:UpdateContent()
end