Monorepo for Aesthetic.Computer
aesthetic.computer
1// KidLisp Mini Transforms
2// Fade gradient background, timing forms
3// ~100 lines, produces ~2-3 KB minified
4
5import { resolveColor, rainbowColor, hslToRgb } from './color.mjs';
6
7class TransformState {
8 constructor(width, height) {
9 this.width = width;
10 this.height = height;
11 this.frame = 0;
12 this.fadeColors = null;
13 this.pendingTransforms = [];
14 }
15
16 tick() {
17 this.frame++;
18 }
19
20 setFade(colors) {
21 // Parse color names: "red-blue-black-blue-red" → resolve to RGB
22 this.fadeColors = colors.map(name => resolveColor(name));
23 }
24
25 applyFade(renderer) {
26 if (!this.fadeColors) return;
27
28 // Cycle through fade colors based on frame
29 const idx = Math.floor(this.frame / 20) % this.fadeColors.length;
30 const color = this.fadeColors[idx];
31 renderer.wipe(color[0], color[1], color[2], color[3]);
32 }
33
34 evaluateTimingExpr(expr, startVal, endVal) {
35 if (typeof expr === 'object' && expr.type === 'timing-repeating') {
36 const ms = expr.ms;
37 const elapsed = (this.frame * 16) % ms; // assume ~16ms per frame
38 const progress = elapsed / ms;
39 return startVal + (endVal - startVal) * progress;
40 }
41
42 if (typeof expr === 'object' && expr.type === 'timing-once') {
43 const ms = expr.ms;
44 const elapsed = this.frame * 16;
45 const progress = Math.min(1, elapsed / ms);
46 return startVal + (endVal - startVal) * progress;
47 }
48
49 // Not a timing expression, return as-is
50 return expr;
51 }
52
53 interpolate(value, startVal, endVal) {
54 // If value is between 0 and 1, it's a progress value
55 if (typeof value === 'number' && value >= 0 && value <= 1) {
56 return startVal + (endVal - startVal) * value;
57 }
58 return value;
59 }
60}
61
62// Helper: parse and apply an interpolated timing form
63// e.g., (1s... 24 64) → current alpha value interpolated between 24-64
64function evalTimingForm(timingExpr, frame, ms, repeating) {
65 if (!timingExpr) return 0;
66
67 let elapsed;
68 if (repeating) {
69 elapsed = (frame * 16) % ms; // repeat
70 } else {
71 elapsed = frame * 16; // one-shot
72 elapsed = Math.min(elapsed, ms); // clamp
73 }
74
75 const progress = elapsed / ms;
76 return progress;
77}
78
79function applyInterpolation(progress, startVal, endVal) {
80 if (typeof startVal !== 'number' || typeof endVal !== 'number') {
81 return startVal;
82 }
83 return startVal + (endVal - startVal) * progress;
84}
85
86export { TransformState, evalTimingForm, applyInterpolation };