1size 960 600
2background #1a1030
3timeline 30 300
4
5// Cinq lampions pendus à une perche. Le lampion est UN symbole : sa couleur et la longueur de son fil sont
6// des réglages exposés (`params`), donnés à chaque instance. Secoue la perche : chaque lampion est un vrai
7// pendule (`every frame`, DT = 1/60 s), poussé par l'ACCÉLÉRATION de la perche. Un fil long balance plus
8// lentement ; un petit geste fait un petit balancement, une secousse en rythme le fait monter haut.
9def g = 2600
10var px = 480
11var py = 150
12var phi = [0, 0, 0, 0, 0]
13var om = [0, 0, 0, 0, 0]
14var len = [130, 210, 160, 240, 145]
15var bx = 480
16var vs = 0
17var vn = 0
18var acc = 0
19
20symbol "Lampion" {
21 params {
22 color teinte = #ff5a3c "couleur du papier"
23 number fil = 120 range 60 240 "longueur du fil"
24 }
25 layer "c" {
26 group "Fil" pivot 0,0 expr scaleY "fil" {
27 layer "c" { rect -1 0 2 1 fill #2b1d24 }
28 }
29 group "Corps" pivot 0,0 expr y "fil" {
30 layer "halo" {
31 group "Lueur" expr opacity "0.82 + 0.18 * sin(clock * 11 + fil) * sin(clock * 7.3)" {
32 layer "c" { circle 0 38 96 fill radial(0.5, 0.5, 0.5, 0:teinte@0.42, 0.45:teinte@0.14, 1:teinte@0) }
33 }
34 }
35 layer "lampe" {
36 rect -11 -4 22 10 3 fill #2b1d24
37 ellipse 0 38 34 38 fill radial(0.5, 0.42, 0.62, 0:#fffbe8, 0.38:teinte, 1:teinte@0.8)
38 ellipse 0 38 22 38 nofill stroke #00000026 1.5
39 ellipse 0 38 9 38 nofill stroke #00000020 1.5
40 path "M-33 30 C-12 36 12 36 33 30" nofill stroke #00000018 1.5
41 path "M-33 46 C-12 52 12 52 33 46" nofill stroke #00000018 1.5
42 rect -12 74 24 8 3 fill #2b1d24
43 path "M0 82 L0 104" nofill stroke teinte 3 cap round
44 circle 0 106 4 fill teinte
45 }
46 }
47 }
48}
49
50scene {
51 layer "Ciel" {
52 rect 0 0 960 600 fill linear(90, 0:#1a1030, 0.55:#5a2a5a, 0.85:#c4566a, 1:#f08a5d)
53 repeat i from 0 to 34 { circle $(mod(i * 271, 960)) $(mod(i * 97, 260)) $(0.7 + mod(i, 3) * 0.5) fill #ffffff opacity $(0.25 + mod(i, 4) * 0.12) }
54 circle 790 120 34 fill #ffe9c4 opacity 0.9
55 circle 790 120 70 fill radial(0.5, 0.5, 0.5, 0:#ffe9c455, 1:#ffe9c400)
56 }
57 layer "Collines" {
58 path "M0 470 C140 410 260 440 380 420 C520 396 640 440 760 412 C860 392 920 420 960 410 L960 600 L0 600 Z" fill #3a1f45
59 path "M0 520 C160 480 300 510 460 490 C620 470 760 520 960 486 L960 600 L0 600 Z" fill #281434
60 path "M0 560 C200 540 420 566 620 548 C760 536 880 560 960 550 L960 600 L0 600 Z" fill #170b22
61 }
62 layer "Lampions" {
63 instance "Lampion" as "L1" at 300,150 { teinte = #ff5a3c, fil = 90 }
64 instance "Lampion" as "L2" at 390,150 { teinte = #ffb52e, fil = 170 }
65 instance "Lampion" as "L3" at 480,150 { teinte = #5ad1a4, fil = 120 }
66 instance "Lampion" as "L4" at 570,150 { teinte = #4aa3ff, fil = 200 }
67 instance "Lampion" as "L5" at 660,150 { teinte = #e06cff, fil = 105 }
68 }
69 layer "Perche" {
70 group "Perche" at 480,150 pivot 0,0 hitbox 560 60 {
71 layer "c" {
72 rect -270 -7 540 14 7 fill linear(90, 0:#a8744a, 1:#5e3a22)
73 rect -270 -7 540 4 2 fill #ffffff22
74 circle -272 0 10 fill #4a2c18
75 circle 272 0 10 fill #4a2c18
76 repeat i from 0 to 4 { circle $(-180 + i * 90) 0 5 fill #2b1d24 }
77 }
78 }
79 }
80 layer "Textes" {
81 text "LES LAMPIONS" at 32,28 font "Geist, system-ui, sans-serif" size 26 bold align left line 1.2 color #ffe9c4 box 400 34
82 text "attrape la perche et secoue-la" at 32,62 font "Geist, system-ui, sans-serif" size 15 align left line 1.2 color #d9a8c8 box 400 22
83 }
84}
85
86object "Perche" {
87 drag px, py
88 x = clamp(px, 290, 670)
89 y = clamp(py, 90, 260)
90 scaleY = self.grabbed ? 1.15 : 1
91}
92
93// Chaque pendule : φ'' = −(g/L)·sin φ − (a/L)·cos φ − c·φ', où a est l'accélération (lissée) de la perche
94// et L la longueur du fil jusqu'au centre du lampion. L'accélération est bornée : un geste brusque penche
95// un lampion, il ne le fait pas tourner.
96every frame {
97 vn = vs + ((clamp(px, 290, 670) - bx) / DT - vs) * 0.25
98 acc = clamp((vn - vs) / DT, -2000, 2000)
99 vs = vn
100 bx = clamp(px, 290, 670)
101 repeat i from 0 to 4 {
102 om[i] = om[i] + (-$(g) / len[i] * sin(phi[i]) - acc / len[i] * cos(phi[i]) - 1.6 * om[i]) * DT
103 phi[i] = clamp(phi[i] + om[i] * DT, -1.25, 1.25)
104 }
105}
106
107object "L1" {
108 x = clamp(px, 290, 670) - 180
109 y = clamp(py, 90, 260)
110 rotation = -phi[0]
111}
112object "L2" {
113 x = clamp(px, 290, 670) - 90
114 y = clamp(py, 90, 260)
115 rotation = -phi[1]
116}
117object "L3" {
118 x = clamp(px, 290, 670)
119 y = clamp(py, 90, 260)
120 rotation = -phi[2]
121}
122object "L4" {
123 x = clamp(px, 290, 670) + 90
124 y = clamp(py, 90, 260)
125 rotation = -phi[3]
126}
127object "L5" {
128 x = clamp(px, 290, 670) + 180
129 y = clamp(py, 90, 260)
130 rotation = -phi[4]
131}