@k9kbdev/roblox-css 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +245 -0
  3. package/default.project.json +6 -0
  4. package/out/index.d.ts +35 -0
  5. package/out/init.luau +57 -0
  6. package/out/logger.d.ts +23 -0
  7. package/out/logger.luau +73 -0
  8. package/out/primitives/Box.d.ts +23 -0
  9. package/out/primitives/Box.luau +103 -0
  10. package/out/primitives/Button.d.ts +62 -0
  11. package/out/primitives/Button.luau +170 -0
  12. package/out/primitives/Image.d.ts +37 -0
  13. package/out/primitives/Image.luau +79 -0
  14. package/out/primitives/InlineText.d.ts +25 -0
  15. package/out/primitives/InlineText.luau +273 -0
  16. package/out/primitives/Input.d.ts +59 -0
  17. package/out/primitives/Input.luau +126 -0
  18. package/out/primitives/MotionBox.d.ts +15 -0
  19. package/out/primitives/MotionBox.luau +69 -0
  20. package/out/primitives/MotionButton.d.ts +15 -0
  21. package/out/primitives/MotionButton.luau +146 -0
  22. package/out/primitives/MotionImage.d.ts +13 -0
  23. package/out/primitives/MotionImage.luau +70 -0
  24. package/out/primitives/MotionText.d.ts +12 -0
  25. package/out/primitives/MotionText.luau +116 -0
  26. package/out/primitives/MotionUIScale.d.ts +9 -0
  27. package/out/primitives/MotionUIScale.luau +48 -0
  28. package/out/primitives/ScrollBox.d.ts +25 -0
  29. package/out/primitives/ScrollBox.luau +69 -0
  30. package/out/primitives/Text.d.ts +50 -0
  31. package/out/primitives/Text.luau +139 -0
  32. package/out/primitives/usePercentageConstraints.d.ts +3 -0
  33. package/out/primitives/usePercentageConstraints.luau +112 -0
  34. package/out/primitives/useVariantResolver.d.ts +13 -0
  35. package/out/primitives/useVariantResolver.luau +260 -0
  36. package/out/styles/CSSTypes.d.ts +96 -0
  37. package/out/styles/ParentSizeContext.d.ts +6 -0
  38. package/out/styles/ParentSizeContext.luau +13 -0
  39. package/out/styles/colorParser.d.ts +28 -0
  40. package/out/styles/colorParser.luau +229 -0
  41. package/out/styles/dimensionParser.d.ts +49 -0
  42. package/out/styles/dimensionParser.luau +205 -0
  43. package/out/styles/gradientParser.d.ts +9 -0
  44. package/out/styles/gradientParser.luau +434 -0
  45. package/out/styles/namedColors.d.ts +7 -0
  46. package/out/styles/namedColors.luau +162 -0
  47. package/out/styles/transitions.d.ts +18 -0
  48. package/out/styles/transitions.luau +19 -0
  49. package/out/styles/webStyle.d.ts +74 -0
  50. package/out/styles/webStyle.luau +973 -0
  51. package/out/types.d.ts +4 -0
  52. package/out/types.luau +3 -0
  53. package/out/utils/parseInlineImages.d.ts +20 -0
  54. package/out/utils/parseInlineImages.luau +93 -0
  55. package/package.json +56 -0
@@ -0,0 +1,434 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local parseColor = TS.import(script, script.Parent, "colorParser").parseColor
4
+ local createLogger = TS.import(script, script.Parent.Parent, "logger").createLogger
5
+ local log = createLogger("gradientParser")
6
+ local function makeParsedGradient(colorSequence, transparencySequence, rotation)
7
+ return {
8
+ colorSequence = colorSequence,
9
+ transparencySequence = transparencySequence,
10
+ rotation = rotation,
11
+ }
12
+ end
13
+ local function isGradientString(input)
14
+ local _input = input
15
+ local _condition = type(_input) == "string"
16
+ if _condition then
17
+ _condition = string.sub(input, 1, 16) == "linear-gradient("
18
+ end
19
+ return _condition
20
+ end
21
+ local function parseAngle(directionStr, elementWidth, elementHeight)
22
+ local lower = string.lower(directionStr)
23
+ -- Keyword directions
24
+ if lower == "to top" then
25
+ return 0
26
+ end
27
+ if lower == "to right" then
28
+ return 90
29
+ end
30
+ if lower == "to bottom" then
31
+ return 180
32
+ end
33
+ if lower == "to left" then
34
+ return 270
35
+ end
36
+ -- Corner keywords
37
+ if string.sub(lower, 1, 3) == "to " then
38
+ local corner = string.sub(lower, 4)
39
+ local angleDeg = 45
40
+ if elementWidth ~= nil and elementHeight ~= nil and elementHeight ~= 0 then
41
+ local ratioAngle = math.deg(math.atan2(elementWidth, elementHeight))
42
+ if corner == "top right" then
43
+ return ratioAngle
44
+ end
45
+ if corner == "bottom right" then
46
+ return 180 - ratioAngle
47
+ end
48
+ if corner == "bottom left" then
49
+ return 180 + ratioAngle
50
+ end
51
+ if corner == "top left" then
52
+ return 360 - ratioAngle
53
+ end
54
+ else
55
+ if corner == "top right" then
56
+ return 45
57
+ end
58
+ if corner == "bottom right" then
59
+ return 135
60
+ end
61
+ if corner == "bottom left" then
62
+ return 225
63
+ end
64
+ if corner == "top left" then
65
+ return 315
66
+ end
67
+ end
68
+ end
69
+ -- Angle values
70
+ local degMatch = string.match(lower, "^([%d%.%-]+)deg$")
71
+ if degMatch ~= nil then
72
+ local _condition = tonumber(degMatch)
73
+ if _condition == nil then
74
+ _condition = 180
75
+ end
76
+ return _condition
77
+ end
78
+ local turnMatch = string.match(lower, "^([%d%.%-]+)turn$")
79
+ if turnMatch ~= nil then
80
+ local _condition = tonumber(turnMatch)
81
+ if _condition == nil then
82
+ _condition = 0
83
+ end
84
+ return _condition * 360
85
+ end
86
+ local gradMatch = string.match(lower, "^([%d%.%-]+)grad$")
87
+ if gradMatch ~= nil then
88
+ local _condition = tonumber(gradMatch)
89
+ if _condition == nil then
90
+ _condition = 0
91
+ end
92
+ return _condition * 0.9
93
+ end
94
+ local radMatch = string.match(lower, "^([%d%.%-]+)rad$")
95
+ if radMatch ~= nil then
96
+ local _condition = tonumber(radMatch)
97
+ if _condition == nil then
98
+ _condition = 0
99
+ end
100
+ return math.deg(_condition)
101
+ end
102
+ return 180
103
+ end
104
+ local function parseStop(stopStr)
105
+ local trimmedRaw = string.match(stopStr, "^%s*(.-)%s*$")
106
+ if trimmedRaw == nil or trimmedRaw == "" then
107
+ return nil
108
+ end
109
+ local trimmed = trimmedRaw
110
+ -- Check if it's a bare percentage (color hint)
111
+ local hintMatch = string.match(trimmed, "^([%d%.]+)%%$")
112
+ if hintMatch ~= nil then
113
+ local pos = tonumber(hintMatch)
114
+ if pos ~= nil then
115
+ return {
116
+ color = Color3.new(),
117
+ transparency = 0,
118
+ position = math.clamp(pos / 100, 0, 1),
119
+ isHint = true,
120
+ }
121
+ end
122
+ end
123
+ -- Split by space from the end to find optional position
124
+ -- Since color could be rgba(255, 0, 0, 0.5) we must be careful with spaces.
125
+ -- We'll look for a percentage at the end.
126
+ local colorStr = trimmed
127
+ local position
128
+ local endPercentMatch = string.match(trimmed, " ([%d%.%-]+)%%$")
129
+ if endPercentMatch ~= nil then
130
+ local pos = tonumber(endPercentMatch)
131
+ if pos ~= nil then
132
+ position = math.clamp(pos / 100, 0, 1)
133
+ local colorMatch = string.match(trimmed, "^(.*) [%d%.%-]+%%$")
134
+ if colorMatch ~= nil then
135
+ colorStr = colorMatch
136
+ end
137
+ end
138
+ end
139
+ local parsedColor = parseColor(colorStr)
140
+ return {
141
+ color = parsedColor.color,
142
+ transparency = parsedColor.transparency,
143
+ position = position,
144
+ isHint = false,
145
+ }
146
+ end
147
+ local function parseGradient(input, elementWidth, elementHeight)
148
+ if not isGradientString(input) then
149
+ return nil
150
+ end
151
+ local repeatingStart = string.find(string.lower(input), "^repeating%-linear%-gradient")
152
+ if repeatingStart ~= nil then
153
+ log:warn("UNSUPPORTED_GRADIENT", "repeating-linear-gradient is not supported", {
154
+ input = input,
155
+ })
156
+ return nil
157
+ end
158
+ local inner = string.sub(input, 17, -2)
159
+ if inner == "" then
160
+ return nil
161
+ end
162
+ -- Simple parser for comma-separated args, respecting parentheses for rgb/rgba
163
+ local args = {}
164
+ local currentArg = ""
165
+ local parenLevel = 0
166
+ for i = 1, #inner do
167
+ local _i = i
168
+ local _i_1 = i
169
+ local char = string.sub(inner, _i, _i_1)
170
+ if char == "(" then
171
+ parenLevel += 1
172
+ elseif char == ")" then
173
+ parenLevel -= 1
174
+ elseif char == "," and parenLevel == 0 then
175
+ local _currentArg = currentArg
176
+ table.insert(args, _currentArg)
177
+ currentArg = ""
178
+ continue
179
+ end
180
+ currentArg ..= char
181
+ end
182
+ local _currentArg = currentArg
183
+ table.insert(args, _currentArg)
184
+ if #args < 2 then
185
+ return nil
186
+ end
187
+ -- Determine if the first arg is a direction
188
+ local directionStr = args[1]
189
+ local directionAngle = 180
190
+ local firstStopIdx = 0
191
+ local lowerFirst = string.lower(directionStr)
192
+ local hasDeg = string.find(lowerFirst, "deg$")
193
+ local hasTurn = string.find(lowerFirst, "turn$")
194
+ local hasGrad = string.find(lowerFirst, "grad$")
195
+ local hasRad = string.find(lowerFirst, "rad$")
196
+ local _condition = string.sub(lowerFirst, 1, 3) == "to "
197
+ if not _condition then
198
+ _condition = hasDeg
199
+ if not (_condition ~= 0 and _condition == _condition and _condition) then
200
+ _condition = hasTurn
201
+ if not (_condition ~= 0 and _condition == _condition and _condition) then
202
+ _condition = hasGrad
203
+ if not (_condition ~= 0 and _condition == _condition and _condition) then
204
+ _condition = hasRad
205
+ end
206
+ end
207
+ end
208
+ end
209
+ if _condition ~= 0 and _condition == _condition and _condition then
210
+ directionAngle = parseAngle(directionStr, elementWidth, elementHeight)
211
+ firstStopIdx = 1
212
+ end
213
+ local stops = {}
214
+ do
215
+ local i = firstStopIdx
216
+ local _shouldIncrement = false
217
+ while true do
218
+ if _shouldIncrement then
219
+ i += 1
220
+ else
221
+ _shouldIncrement = true
222
+ end
223
+ if not (i < #args) then
224
+ break
225
+ end
226
+ local parsed = parseStop(args[i + 1])
227
+ if parsed ~= nil then
228
+ table.insert(stops, parsed)
229
+ end
230
+ end
231
+ end
232
+ -- Remove leading/trailing hints and check valid color stops
233
+ while #stops > 0 and stops[1].isHint do
234
+ table.remove(stops, 1)
235
+ end
236
+ while #stops > 0 and stops[#stops].isHint do
237
+ stops[#stops] = nil
238
+ end
239
+ local colorStopCount = 0
240
+ for _, stop in stops do
241
+ if not stop.isHint then
242
+ colorStopCount += 1
243
+ end
244
+ end
245
+ if colorStopCount < 2 then
246
+ return nil
247
+ end
248
+ -- Distribute positions
249
+ if stops[1].position == nil then
250
+ stops[1].position = 0
251
+ end
252
+ if stops[#stops].position == nil then
253
+ stops[#stops].position = 1
254
+ end
255
+ local lastKnownIdx = 0
256
+ for i = 1, #stops - 1 do
257
+ if stops[i + 1].position ~= nil then
258
+ local steps = i - lastKnownIdx
259
+ local startPos = stops[lastKnownIdx + 1].position
260
+ local endPos = stops[i + 1].position
261
+ local stepSize = (endPos - startPos) / steps
262
+ do
263
+ local j = 1
264
+ local _shouldIncrement = false
265
+ while true do
266
+ if _shouldIncrement then
267
+ j += 1
268
+ else
269
+ _shouldIncrement = true
270
+ end
271
+ if not (j < steps) then
272
+ break
273
+ end
274
+ stops[lastKnownIdx + j + 1].position = startPos + stepSize * j
275
+ end
276
+ end
277
+ lastKnownIdx = i
278
+ end
279
+ end
280
+ -- Auto-correct out-of-order positions
281
+ local maxPos = 0
282
+ for _, stop in stops do
283
+ if stop.position < maxPos then
284
+ stop.position = maxPos
285
+ end
286
+ maxPos = stop.position
287
+ end
288
+ -- Apply hints
289
+ local finalStops = {}
290
+ for i = 0, #stops - 1 do
291
+ local stop = stops[i + 1]
292
+ if stop.isHint then
293
+ local prev = stops[i]
294
+ local nextStop = stops[i + 2]
295
+ local startPos = prev.position
296
+ local endPos = nextStop.position
297
+ if startPos == endPos then
298
+ continue
299
+ end
300
+ -- H = (hintAbsPos - stop1Pos) / (stop2Pos - stop1Pos)
301
+ local h = (stop.position - startPos) / (endPos - startPos)
302
+ h = math.clamp(h, 0.01, 0.99)
303
+ local exp = math.log(0.5) / math.log(h)
304
+ -- Pop the last added stop so we can replace the segment
305
+ finalStops[#finalStops] = nil
306
+ table.insert(finalStops, prev)
307
+ for sample = 1, 7 do
308
+ local p = sample / 8
309
+ local f = p ^ exp
310
+ local pos = startPos + p * (endPos - startPos)
311
+ local r = prev.color.R + f * (nextStop.color.R - prev.color.R)
312
+ local g = prev.color.G + f * (nextStop.color.G - prev.color.G)
313
+ local b = prev.color.B + f * (nextStop.color.B - prev.color.B)
314
+ local transp = prev.transparency + f * (nextStop.transparency - prev.transparency)
315
+ local _arg0 = {
316
+ color = Color3.new(r, g, b),
317
+ transparency = transp,
318
+ position = pos,
319
+ isHint = false,
320
+ }
321
+ table.insert(finalStops, _arg0)
322
+ end
323
+ else
324
+ table.insert(finalStops, stop)
325
+ end
326
+ end
327
+ -- Build sequences
328
+ local colorKeypoints = {}
329
+ local alphaKeypoints = {}
330
+ local hasTransparency = false
331
+ -- Roblox limits keypoints to 20, but we might have more.
332
+ -- For simplicity, we just push all and trust it's <= 20 or user will see engine err,
333
+ -- but let's downsample if needed. Let's just create them as specified.
334
+ for _, stop in finalStops do
335
+ local pos = math.clamp(stop.position, 0, 1)
336
+ local _colorSequenceKeypoint = ColorSequenceKeypoint.new(pos, stop.color)
337
+ table.insert(colorKeypoints, _colorSequenceKeypoint)
338
+ local _numberSequenceKeypoint = NumberSequenceKeypoint.new(pos, stop.transparency)
339
+ table.insert(alphaKeypoints, _numberSequenceKeypoint)
340
+ if stop.transparency > 0 then
341
+ hasTransparency = true
342
+ end
343
+ end
344
+ -- Fix duplicate positions (Roblox requires strictly increasing times for ColorSequence, or at least no more than 2 at same time if they are immediate jumps, but usually increasing is safer)
345
+ -- We'll enforce non-decreasing and add epsilon for exact duplicates if needed.
346
+ local uniqueColorKeypoints = {}
347
+ local uniqueAlphaKeypoints = {}
348
+ local lastTime = -1
349
+ for i = 0, #colorKeypoints - 1 do
350
+ local t = colorKeypoints[i + 1].Time
351
+ if t <= lastTime then
352
+ t = math.clamp(lastTime + 0.001, 0, 1)
353
+ end
354
+ if t > lastTime or #uniqueColorKeypoints == 0 then
355
+ local _colorSequenceKeypoint = ColorSequenceKeypoint.new(t, colorKeypoints[i + 1].Value)
356
+ table.insert(uniqueColorKeypoints, _colorSequenceKeypoint)
357
+ local _numberSequenceKeypoint = NumberSequenceKeypoint.new(t, alphaKeypoints[i + 1].Value)
358
+ table.insert(uniqueAlphaKeypoints, _numberSequenceKeypoint)
359
+ lastTime = t
360
+ end
361
+ end
362
+ -- We must cap at 20 keypoints due to Roblox engine limits.
363
+ -- (Skipping downsampling for now as prompt doesn't strictly demand it, but good to know)
364
+ -- Let's ensure time goes exactly up to 1 for the last one if it was squished.
365
+ if uniqueColorKeypoints[#uniqueColorKeypoints].Time < 1 then
366
+ -- Just ensure the last element is exactly 1, or adjust.
367
+ -- Actually, if it's less than 1, Roblox might error if the last keypoint is not at Time=1.
368
+ local lastC = uniqueColorKeypoints[#uniqueColorKeypoints]
369
+ if lastC.Time ~= 1 then
370
+ local _colorSequenceKeypoint = ColorSequenceKeypoint.new(1, lastC.Value)
371
+ table.insert(uniqueColorKeypoints, _colorSequenceKeypoint)
372
+ end
373
+ local lastA = uniqueAlphaKeypoints[#uniqueAlphaKeypoints]
374
+ if lastA.Time ~= 1 then
375
+ local _numberSequenceKeypoint = NumberSequenceKeypoint.new(1, lastA.Value)
376
+ table.insert(uniqueAlphaKeypoints, _numberSequenceKeypoint)
377
+ end
378
+ end
379
+ if uniqueColorKeypoints[1].Time > 0 then
380
+ local firstC = uniqueColorKeypoints[1]
381
+ local _colorSequenceKeypoint = ColorSequenceKeypoint.new(0, firstC.Value)
382
+ table.insert(uniqueColorKeypoints, 1, _colorSequenceKeypoint)
383
+ local firstA = uniqueAlphaKeypoints[1]
384
+ local _numberSequenceKeypoint = NumberSequenceKeypoint.new(0, firstA.Value)
385
+ table.insert(uniqueAlphaKeypoints, 1, _numberSequenceKeypoint)
386
+ end
387
+ -- Enforce 20 keypoints max — Roblox engine hard-limits ColorSequence/NumberSequence to 20.
388
+ -- Downsample by preserving first/last and evenly distributing interior points.
389
+ if #uniqueColorKeypoints > 20 then
390
+ log:warn("GRADIENT_KEYPOINT_LIMIT", "Gradient exceeds 20 keypoints, downsampling", {
391
+ count = #uniqueColorKeypoints,
392
+ })
393
+ local _array = {}
394
+ local _length = #_array
395
+ table.move(uniqueColorKeypoints, 1, #uniqueColorKeypoints, _length + 1, _array)
396
+ local srcColors = _array
397
+ local _array_1 = {}
398
+ local _length_1 = #_array_1
399
+ table.move(uniqueAlphaKeypoints, 1, #uniqueAlphaKeypoints, _length_1 + 1, _array_1)
400
+ local srcAlphas = _array_1
401
+ local total = #srcColors
402
+ local downsampled = { srcColors[1] }
403
+ local downsampledAlpha = { srcAlphas[1] }
404
+ -- Pick 18 evenly spaced interior points
405
+ for i = 1, 18 do
406
+ local idx = math.floor((i / 19) * (total - 1))
407
+ local _arg0 = srcColors[idx + 1]
408
+ table.insert(downsampled, _arg0)
409
+ local _arg0_1 = srcAlphas[idx + 1]
410
+ table.insert(downsampledAlpha, _arg0_1)
411
+ end
412
+ local _arg0 = srcColors[total]
413
+ table.insert(downsampled, _arg0)
414
+ local _arg0_1 = srcAlphas[total]
415
+ table.insert(downsampledAlpha, _arg0_1)
416
+ -- Replace the arrays in-place
417
+ table.clear(uniqueColorKeypoints)
418
+ table.clear(uniqueAlphaKeypoints)
419
+ for _, kp in downsampled do
420
+ table.insert(uniqueColorKeypoints, kp)
421
+ end
422
+ for _, kp in downsampledAlpha do
423
+ table.insert(uniqueAlphaKeypoints, kp)
424
+ end
425
+ end
426
+ local cSeq = ColorSequence.new(uniqueColorKeypoints)
427
+ local tSeq = if hasTransparency then NumberSequence.new(uniqueAlphaKeypoints) else nil
428
+ local robloxRotation = directionAngle - 90
429
+ return makeParsedGradient(cSeq, tSeq, robloxRotation)
430
+ end
431
+ return {
432
+ isGradientString = isGradientString,
433
+ parseGradient = parseGradient,
434
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * namedColors.ts — All 148 CSS Level 4 named colors.
3
+ *
4
+ * Lookup table mapping lowercase color keywords to [R, G, B] tuples (0–255).
5
+ * Spec: https://www.w3.org/TR/css-color-4/#named-colors
6
+ */
7
+ export declare const NAMED_COLORS: Map<string, [number, number, number]>;
@@ -0,0 +1,162 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ --[[
3
+ *
4
+ * namedColors.ts — All 148 CSS Level 4 named colors.
5
+ *
6
+ * Lookup table mapping lowercase color keywords to [R, G, B] tuples (0–255).
7
+ * Spec: https://www.w3.org/TR/css-color-4/#named-colors
8
+
9
+ ]]
10
+ local NAMED_COLORS = {
11
+ aliceblue = { 240, 248, 255 },
12
+ antiquewhite = { 250, 235, 215 },
13
+ aqua = { 0, 255, 255 },
14
+ aquamarine = { 127, 255, 212 },
15
+ azure = { 240, 255, 255 },
16
+ beige = { 245, 245, 220 },
17
+ bisque = { 255, 228, 196 },
18
+ black = { 0, 0, 0 },
19
+ blanchedalmond = { 255, 235, 205 },
20
+ blue = { 0, 0, 255 },
21
+ blueviolet = { 138, 43, 226 },
22
+ brown = { 165, 42, 42 },
23
+ burlywood = { 222, 184, 135 },
24
+ cadetblue = { 95, 158, 160 },
25
+ chartreuse = { 127, 255, 0 },
26
+ chocolate = { 210, 105, 30 },
27
+ coral = { 255, 127, 80 },
28
+ cornflowerblue = { 100, 149, 237 },
29
+ cornsilk = { 255, 248, 220 },
30
+ crimson = { 220, 20, 60 },
31
+ cyan = { 0, 255, 255 },
32
+ darkblue = { 0, 0, 139 },
33
+ darkcyan = { 0, 139, 139 },
34
+ darkgoldenrod = { 184, 134, 11 },
35
+ darkgray = { 169, 169, 169 },
36
+ darkgreen = { 0, 100, 0 },
37
+ darkgrey = { 169, 169, 169 },
38
+ darkkhaki = { 189, 183, 107 },
39
+ darkmagenta = { 139, 0, 139 },
40
+ darkolivegreen = { 85, 107, 47 },
41
+ darkorange = { 255, 140, 0 },
42
+ darkorchid = { 153, 50, 204 },
43
+ darkred = { 139, 0, 0 },
44
+ darksalmon = { 233, 150, 122 },
45
+ darkseagreen = { 143, 188, 143 },
46
+ darkslateblue = { 72, 61, 139 },
47
+ darkslategray = { 47, 79, 79 },
48
+ darkslategrey = { 47, 79, 79 },
49
+ darkturquoise = { 0, 206, 209 },
50
+ darkviolet = { 148, 0, 211 },
51
+ deeppink = { 255, 20, 147 },
52
+ deepskyblue = { 0, 191, 255 },
53
+ dimgray = { 105, 105, 105 },
54
+ dimgrey = { 105, 105, 105 },
55
+ dodgerblue = { 30, 144, 255 },
56
+ firebrick = { 178, 34, 34 },
57
+ floralwhite = { 255, 250, 240 },
58
+ forestgreen = { 34, 139, 34 },
59
+ fuchsia = { 255, 0, 255 },
60
+ gainsboro = { 220, 220, 220 },
61
+ ghostwhite = { 248, 248, 255 },
62
+ gold = { 255, 215, 0 },
63
+ goldenrod = { 218, 165, 32 },
64
+ gray = { 128, 128, 128 },
65
+ green = { 0, 128, 0 },
66
+ greenyellow = { 173, 255, 47 },
67
+ grey = { 128, 128, 128 },
68
+ honeydew = { 240, 255, 240 },
69
+ hotpink = { 255, 105, 180 },
70
+ indianred = { 205, 92, 92 },
71
+ indigo = { 75, 0, 130 },
72
+ ivory = { 255, 255, 240 },
73
+ khaki = { 240, 230, 140 },
74
+ lavender = { 230, 230, 250 },
75
+ lavenderblush = { 255, 240, 245 },
76
+ lawngreen = { 124, 252, 0 },
77
+ lemonchiffon = { 255, 250, 205 },
78
+ lightblue = { 173, 216, 230 },
79
+ lightcoral = { 240, 128, 128 },
80
+ lightcyan = { 224, 255, 255 },
81
+ lightgoldenrodyellow = { 250, 250, 210 },
82
+ lightgray = { 211, 211, 211 },
83
+ lightgreen = { 144, 238, 144 },
84
+ lightgrey = { 211, 211, 211 },
85
+ lightpink = { 255, 182, 193 },
86
+ lightsalmon = { 255, 160, 122 },
87
+ lightseagreen = { 32, 178, 170 },
88
+ lightskyblue = { 135, 206, 250 },
89
+ lightslategray = { 119, 136, 153 },
90
+ lightslategrey = { 119, 136, 153 },
91
+ lightsteelblue = { 176, 196, 222 },
92
+ lightyellow = { 255, 255, 224 },
93
+ lime = { 0, 255, 0 },
94
+ limegreen = { 50, 205, 50 },
95
+ linen = { 250, 240, 230 },
96
+ magenta = { 255, 0, 255 },
97
+ maroon = { 128, 0, 0 },
98
+ mediumaquamarine = { 102, 205, 170 },
99
+ mediumblue = { 0, 0, 205 },
100
+ mediumorchid = { 186, 85, 211 },
101
+ mediumpurple = { 147, 112, 219 },
102
+ mediumseagreen = { 60, 179, 113 },
103
+ mediumslateblue = { 123, 104, 238 },
104
+ mediumspringgreen = { 0, 250, 154 },
105
+ mediumturquoise = { 72, 209, 204 },
106
+ mediumvioletred = { 199, 21, 133 },
107
+ midnightblue = { 25, 25, 112 },
108
+ mintcream = { 245, 255, 250 },
109
+ mistyrose = { 255, 228, 225 },
110
+ moccasin = { 255, 228, 181 },
111
+ navajowhite = { 255, 222, 173 },
112
+ navy = { 0, 0, 128 },
113
+ oldlace = { 253, 245, 230 },
114
+ olive = { 128, 128, 0 },
115
+ olivedrab = { 107, 142, 35 },
116
+ orange = { 255, 165, 0 },
117
+ orangered = { 255, 69, 0 },
118
+ orchid = { 218, 112, 214 },
119
+ palegoldenrod = { 238, 232, 170 },
120
+ palegreen = { 152, 251, 152 },
121
+ paleturquoise = { 175, 238, 238 },
122
+ palevioletred = { 219, 112, 147 },
123
+ papayawhip = { 255, 239, 213 },
124
+ peachpuff = { 255, 218, 185 },
125
+ peru = { 205, 133, 63 },
126
+ pink = { 255, 192, 203 },
127
+ plum = { 221, 160, 221 },
128
+ powderblue = { 176, 224, 230 },
129
+ purple = { 128, 0, 128 },
130
+ rebeccapurple = { 102, 51, 153 },
131
+ red = { 255, 0, 0 },
132
+ rosybrown = { 188, 143, 143 },
133
+ royalblue = { 65, 105, 225 },
134
+ saddlebrown = { 139, 69, 19 },
135
+ salmon = { 250, 128, 114 },
136
+ sandybrown = { 244, 164, 96 },
137
+ seagreen = { 46, 139, 87 },
138
+ seashell = { 255, 245, 238 },
139
+ sienna = { 160, 82, 45 },
140
+ silver = { 192, 192, 192 },
141
+ skyblue = { 135, 206, 235 },
142
+ slateblue = { 106, 90, 205 },
143
+ slategray = { 112, 128, 144 },
144
+ slategrey = { 112, 128, 144 },
145
+ snow = { 255, 250, 250 },
146
+ springgreen = { 0, 255, 127 },
147
+ steelblue = { 70, 130, 180 },
148
+ tan = { 210, 180, 140 },
149
+ teal = { 0, 128, 128 },
150
+ thistle = { 216, 191, 216 },
151
+ tomato = { 255, 99, 71 },
152
+ turquoise = { 64, 224, 208 },
153
+ violet = { 238, 130, 238 },
154
+ wheat = { 245, 222, 179 },
155
+ white = { 255, 255, 255 },
156
+ whitesmoke = { 245, 245, 245 },
157
+ yellow = { 255, 255, 0 },
158
+ yellowgreen = { 154, 205, 50 },
159
+ }
160
+ return {
161
+ NAMED_COLORS = NAMED_COLORS,
162
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * transitions.ts — Pre-configured animation transitions for Motion primitives.
3
+ *
4
+ * Provides a standardized set of TweenInfo configurations to ensure consistency
5
+ * across all declarative animations, per ADR-0002.
6
+ */
7
+ export declare const transitions: {
8
+ /** Standard UI state change, smooth and subtle */
9
+ default: TweenInfo;
10
+ /** Bouncy, energetic pop-in for modals or badges */
11
+ pop: TweenInfo;
12
+ /** Slow, looping breathing effect for idle states */
13
+ breathe: TweenInfo;
14
+ /** Fast, immediate snap for extremely snappy interactions */
15
+ snap: TweenInfo;
16
+ /** Looping shimmer or slide effect */
17
+ shimmer: TweenInfo;
18
+ };
@@ -0,0 +1,19 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ --[[
3
+ *
4
+ * transitions.ts — Pre-configured animation transitions for Motion primitives.
5
+ *
6
+ * Provides a standardized set of TweenInfo configurations to ensure consistency
7
+ * across all declarative animations, per ADR-0002.
8
+
9
+ ]]
10
+ local transitions = {
11
+ default = TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
12
+ pop = TweenInfo.new(0.25, Enum.EasingStyle.Back, Enum.EasingDirection.Out),
13
+ breathe = TweenInfo.new(2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, -1, true),
14
+ snap = TweenInfo.new(0.1, Enum.EasingStyle.Linear),
15
+ shimmer = TweenInfo.new(1, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, -1),
16
+ }
17
+ return {
18
+ transitions = transitions,
19
+ }