@springbrand/message-panel 0.1.3-alpha.9 → 0.2.0-alpha.38
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.
- package/cloud-os/README.md +4 -3
- package/cloud-os/assets/followup-arrow.svg +3 -0
- package/cloud-os/assets/loading-corner.svg +3 -0
- package/cloud-os/assets/loading-mark.svg +16 -0
- package/cloud-os/assets/loading-spark.svg +3 -0
- package/cloud-os/assets/model-selected.svg +5 -0
- package/cloud-os/assets/thinking-star.svg +9 -0
- package/cloud-os/capability-chip.tsx +1 -1
- package/cloud-os/chat/cloud-os-chat-messages.tsx +441 -98
- package/cloud-os/chat/code-runner.tsx +106 -0
- package/cloud-os/chat/image-generation.tsx +76 -0
- package/cloud-os/chat/loading-state.tsx +25 -0
- package/cloud-os/chat/markdown-message.tsx +144 -41
- package/cloud-os/chat/range.ts +8 -0
- package/cloud-os/chat/rich-blocks.tsx +285 -227
- package/cloud-os/chat/surfaces.tsx +90 -0
- package/cloud-os/chat/tool-call.tsx +94 -0
- package/cloud-os/chat/tool-presentation.ts +31 -22
- package/cloud-os/chat/tool-rows.tsx +195 -143
- package/cloud-os/chat/tool-timeline.tsx +123 -0
- package/cloud-os/chat/transcript-model.ts +258 -20
- package/cloud-os/chat/web-search.tsx +135 -0
- package/cloud-os/composer/cloud-os-chat-input.tsx +29 -88
- package/cloud-os/composer/cloud-os-model-select.tsx +105 -0
- package/cloud-os/file-view.tsx +195 -12
- package/cloud-os/index.ts +24 -3
- package/cloud-os/layout/cloud-os-workspace-split.tsx +60 -3
- package/cloud-os/primitives/collapsible.tsx +21 -0
- package/cloud-os/primitives/workshop-controls.tsx +2 -2
- package/cloud-os/styles/cloud-os.css +114 -1
- package/demo/camel-chat-showcase.tsx +21 -13
- package/demo/chat-scenarios.ts +214 -40
- package/demo/cloud-os-chat-showcase.tsx +37 -14
- package/demo/fixtures.ts +4 -5
- package/demo/message-panel-gallery.tsx +16 -2
- package/package.json +8 -4
- package/springbrand-pet/LICENSE.bloub +21 -0
- package/springbrand-pet/bot/cycles.test.ts +221 -0
- package/springbrand-pet/bot/cycles.ts +225 -0
- package/springbrand-pet/bot/decor.ts +285 -0
- package/springbrand-pet/bot/engine.test.ts +543 -0
- package/springbrand-pet/bot/engine.ts +558 -0
- package/springbrand-pet/bot/expressions.test.ts +135 -0
- package/springbrand-pet/bot/expressions.ts +192 -0
- package/springbrand-pet/bot/eyefit.ts +455 -0
- package/springbrand-pet/bot/face.test.ts +101 -0
- package/springbrand-pet/bot/face.ts +179 -0
- package/springbrand-pet/bot/math.ts +42 -0
- package/springbrand-pet/bot/profiles.ts +22 -0
- package/springbrand-pet/bot/repere.ts +31 -0
- package/springbrand-pet/bot/shape.test.ts +97 -0
- package/springbrand-pet/bot/shape.ts +310 -0
- package/springbrand-pet/bot/skins.test.ts +325 -0
- package/springbrand-pet/bot/skins.ts +161 -0
- package/springbrand-pet/bot/states.ts +616 -0
- package/springbrand-pet/drag.test.ts +19 -0
- package/springbrand-pet/index.tsx +569 -0
- package/springbrand-pet/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/springbrand-pet/vitest.config.ts +9 -0
- package/src/camel/camel-chat-messages.tsx +78 -78
- package/src/camel/camel-tool-presentation.tsx +19 -15
- package/src/camel/camel-turn.ts +1 -17
- package/src/composer/composer-attachments.tsx +1 -1
- package/src/composer/composer.tsx +2 -2
- package/src/contracts.ts +0 -2
- package/src/message-panel.tsx +1 -24
- package/src/parts/index.tsx +103 -64
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { TAU, clamp, createRng, r2 } from './math'
|
|
2
|
+
|
|
3
|
+
/* ------------------------------------------------------------------ couleurs */
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Les anneaux ne sont pas des couleurs plates : la video montre une roue de
|
|
7
|
+
* teintes complete a luminosite constante, avec un degrade le long de chaque
|
|
8
|
+
* trace. Mesure : S 45-62 %, L 50-67 %.
|
|
9
|
+
*/
|
|
10
|
+
function wheel(hue: number, s = 0.55, l = 0.62): string {
|
|
11
|
+
const h = ((hue % 360) + 360) % 360
|
|
12
|
+
const c = (1 - Math.abs(2 * l - 1)) * s
|
|
13
|
+
const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
|
|
14
|
+
const m = l - c / 2
|
|
15
|
+
const [r, g, b] =
|
|
16
|
+
h < 60
|
|
17
|
+
? [c, x, 0]
|
|
18
|
+
: h < 120
|
|
19
|
+
? [x, c, 0]
|
|
20
|
+
: h < 180
|
|
21
|
+
? [0, c, x]
|
|
22
|
+
: h < 240
|
|
23
|
+
? [0, x, c]
|
|
24
|
+
: h < 300
|
|
25
|
+
? [x, 0, c]
|
|
26
|
+
: [c, 0, x]
|
|
27
|
+
const hex = (v: number) =>
|
|
28
|
+
Math.round((v + m) * 255)
|
|
29
|
+
.toString(16)
|
|
30
|
+
.padStart(2, '0')
|
|
31
|
+
return `#${hex(r)}${hex(g)}${hex(b)}`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* ------------------------------------------------------------- types de rendu */
|
|
35
|
+
|
|
36
|
+
export interface DotRender {
|
|
37
|
+
x: number
|
|
38
|
+
y: number
|
|
39
|
+
r: number
|
|
40
|
+
opacity: number
|
|
41
|
+
/** couleur explicite ; par defaut le rendu prend celle du corps */
|
|
42
|
+
color?: string
|
|
43
|
+
/**
|
|
44
|
+
* Brume de profondeur : 0 = fondu dans le fond, 1 = couleur du corps pleine.
|
|
45
|
+
* Le melange se fait au rendu, qui seul connait la couleur choisie.
|
|
46
|
+
*/
|
|
47
|
+
depth?: number
|
|
48
|
+
/**
|
|
49
|
+
* Forme non circulaire, en unites de rayon de boule et centree sur l'origine
|
|
50
|
+
* (le point du "!" penche est une goutte, pas un disque). Quand elle est
|
|
51
|
+
* fournie, `r` n'est plus utilise pour le trace.
|
|
52
|
+
*/
|
|
53
|
+
d?: string
|
|
54
|
+
/** rotation appliquee a `d`, en degres */
|
|
55
|
+
rot?: number
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Ce qu'un etat declare : la geometrie de l'arc reste en unites de rayon de
|
|
60
|
+
* boule, c'est le moteur (seul a connaitre l'echelle du viewBox) qui la
|
|
61
|
+
* rasterise. Sans ca les etats devraient connaitre le viewBox.
|
|
62
|
+
*/
|
|
63
|
+
export interface ArcSpec {
|
|
64
|
+
id: string
|
|
65
|
+
seed: ArcSeed
|
|
66
|
+
t: number
|
|
67
|
+
opacity: number
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ArcRender {
|
|
71
|
+
id: string
|
|
72
|
+
/** portion devant le corps */
|
|
73
|
+
front: string
|
|
74
|
+
/** portion derriere le corps (dessinee avant, donc masquee par la silhouette) */
|
|
75
|
+
back: string
|
|
76
|
+
width: number
|
|
77
|
+
opacity: number
|
|
78
|
+
/** degrade de teinte le long du trace */
|
|
79
|
+
grad: { x1: number; y1: number; x2: number; y2: number; stops: string[] }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* --------------------------------------------------------- arc elliptique 3D */
|
|
83
|
+
|
|
84
|
+
export interface ArcSeed {
|
|
85
|
+
/** demi-grand axe, en unites de rayon de boule */
|
|
86
|
+
a: number
|
|
87
|
+
/** aplatissement b/a : mesure <= 0.45, les plans d'orbite sont vus par la tranche */
|
|
88
|
+
k: number
|
|
89
|
+
/** inclinaison du grand axe a l'ecran, radians */
|
|
90
|
+
tilt: number
|
|
91
|
+
/** tours par seconde */
|
|
92
|
+
speed: number
|
|
93
|
+
phase: number
|
|
94
|
+
/** fraction du tour reellement tracee */
|
|
95
|
+
sweep: number
|
|
96
|
+
hue: number
|
|
97
|
+
hueSpan: number
|
|
98
|
+
width: number
|
|
99
|
+
cx: number
|
|
100
|
+
cy: number
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Projette un cercle 3D incline en orthographique.
|
|
105
|
+
*
|
|
106
|
+
* Le cercle vit dans le plan engendre par u (dans l'ecran) et v (qui plonge
|
|
107
|
+
* dans la profondeur). La composante z sert a couper l'arc en deux : la moitie
|
|
108
|
+
* arriere est dessinee avant le corps, donc occultee par lui. C'est ce vrai tri
|
|
109
|
+
* en profondeur qui fait lire les anneaux comme des orbites et pas comme un
|
|
110
|
+
* dessin plat.
|
|
111
|
+
*/
|
|
112
|
+
export function arcRender(seed: ArcSeed, t: number, scale: number, id: string, opacity = 1): ArcRender {
|
|
113
|
+
const spin = seed.phase + t * seed.speed * TAU
|
|
114
|
+
const cu = Math.cos(seed.tilt)
|
|
115
|
+
const su = Math.sin(seed.tilt)
|
|
116
|
+
const kz = Math.sqrt(Math.max(0, 1 - seed.k * seed.k))
|
|
117
|
+
|
|
118
|
+
const N = 64
|
|
119
|
+
const span = seed.sweep * TAU
|
|
120
|
+
let front = ''
|
|
121
|
+
let back = ''
|
|
122
|
+
let prev: boolean | null = null
|
|
123
|
+
|
|
124
|
+
for (let i = 0; i <= N; i++) {
|
|
125
|
+
const th = spin + (i / N) * span
|
|
126
|
+
const ct = Math.cos(th)
|
|
127
|
+
const st = Math.sin(th)
|
|
128
|
+
// u = (cos tilt, sin tilt, 0) ; v = (-sin tilt * k, cos tilt * k, kz)
|
|
129
|
+
const x = seed.a * (ct * cu + st * -su * seed.k) + seed.cx
|
|
130
|
+
const y = seed.a * (ct * su + st * cu * seed.k) + seed.cy
|
|
131
|
+
const z = seed.a * st * kz
|
|
132
|
+
|
|
133
|
+
const behind = z < 0
|
|
134
|
+
const sx = r2(x * scale)
|
|
135
|
+
const sy = r2(y * scale)
|
|
136
|
+
const cmd = behind !== prev ? 'M' : 'L'
|
|
137
|
+
if (behind) back += `${cmd}${sx} ${sy}`
|
|
138
|
+
else front += `${cmd}${sx} ${sy}`
|
|
139
|
+
prev = behind
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const gx = Math.cos(seed.tilt) * seed.a * scale
|
|
143
|
+
const gy = Math.sin(seed.tilt) * seed.a * scale
|
|
144
|
+
return {
|
|
145
|
+
id,
|
|
146
|
+
front,
|
|
147
|
+
back,
|
|
148
|
+
width: seed.width * scale,
|
|
149
|
+
opacity,
|
|
150
|
+
grad: {
|
|
151
|
+
x1: r2(seed.cx * scale - gx),
|
|
152
|
+
y1: r2(seed.cy * scale - gy),
|
|
153
|
+
x2: r2(seed.cx * scale + gx),
|
|
154
|
+
y2: r2(seed.cy * scale + gy),
|
|
155
|
+
stops: [wheel(seed.hue), wheel(seed.hue + seed.hueSpan * 0.5), wheel(seed.hue + seed.hueSpan)]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* ---------------------------------------------------------------- anneaux */
|
|
161
|
+
|
|
162
|
+
const RING_RNG = createRng(0xa11ce)
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 6 anneaux, demi-grand axe 1.30-1.40 (donc nettement plus grands que la
|
|
166
|
+
* boule), aplatissement toujours <= 0.45, epaisseur 0.055, ~3.3 tours/s.
|
|
167
|
+
*/
|
|
168
|
+
export const RINGS: ArcSeed[] = Array.from({ length: 6 }, (_, i) => ({
|
|
169
|
+
a: 1.3 + RING_RNG() * 0.1,
|
|
170
|
+
k: 0.05 + RING_RNG() * 0.4,
|
|
171
|
+
tilt: (i / 6) * Math.PI + RING_RNG() * 0.5,
|
|
172
|
+
speed: 3 + RING_RNG() * 0.7,
|
|
173
|
+
phase: RING_RNG() * TAU,
|
|
174
|
+
sweep: 0.6 + RING_RNG() * 0.25,
|
|
175
|
+
hue: (i * 360) / 6 + RING_RNG() * 30,
|
|
176
|
+
hueSpan: 60 + RING_RNG() * 60,
|
|
177
|
+
width: 0.05 + RING_RNG() * 0.012,
|
|
178
|
+
cx: 0,
|
|
179
|
+
cy: 0.1
|
|
180
|
+
}))
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Bouquet d'arcs emboites qui balaie le triangle juste avant les orbites.
|
|
184
|
+
* Vus quasiment par la tranche (d'ou la forme en epingle a cheveux), rmax 1.37.
|
|
185
|
+
*/
|
|
186
|
+
export const SWOOSH: ArcSeed[] = Array.from({ length: 4 }, (_, i) => ({
|
|
187
|
+
a: 0.78 + i * 0.2,
|
|
188
|
+
k: 0.05 + i * 0.02,
|
|
189
|
+
tilt: -0.62 + i * 0.05,
|
|
190
|
+
speed: 0.3,
|
|
191
|
+
phase: 0.06 * i,
|
|
192
|
+
sweep: 0.4,
|
|
193
|
+
hue: 95 + i * 62,
|
|
194
|
+
hueSpan: 100,
|
|
195
|
+
width: 0.05,
|
|
196
|
+
cx: 0,
|
|
197
|
+
cy: -0.12
|
|
198
|
+
}))
|
|
199
|
+
|
|
200
|
+
/* ------------------------------------------------------------- 3 points */
|
|
201
|
+
|
|
202
|
+
/** x mesures : -0.557 / -0.013 / +0.532, y = 0. */
|
|
203
|
+
export const DOT_X = [-0.557, -0.013, 0.532] as const
|
|
204
|
+
export const DOT_R = 0.165
|
|
205
|
+
export const DOT_PEAK = 1.25
|
|
206
|
+
|
|
207
|
+
/* ------------------------------------------------------------ particules */
|
|
208
|
+
|
|
209
|
+
const P_RNG = createRng(0xbeef)
|
|
210
|
+
|
|
211
|
+
/** 5 particules, une nouvelle toutes les 0.2 s, duree de vie 0.55 s. */
|
|
212
|
+
const PARTICLES = Array.from({ length: 5 }, (_, i) => ({
|
|
213
|
+
birth: i * 0.2,
|
|
214
|
+
angle: P_RNG() * TAU,
|
|
215
|
+
rho: 0.58 + P_RNG() * 0.18
|
|
216
|
+
}))
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Les particules ne partent pas en ligne droite : elles spiralent vers le
|
|
220
|
+
* centre (rayon x0.75 par frame, angle +100 deg/s) en grossissant, et passent
|
|
221
|
+
* derriere le noyau ou elles sont avalees.
|
|
222
|
+
*/
|
|
223
|
+
export function particles(t: number, scale: number): DotRender[] {
|
|
224
|
+
const out: DotRender[] = []
|
|
225
|
+
for (const p of PARTICLES) {
|
|
226
|
+
const u = t - p.birth
|
|
227
|
+
if (u < 0 || u > 0.62) continue
|
|
228
|
+
const rho = p.rho * Math.pow(0.75, u * 10)
|
|
229
|
+
const a = p.angle + (u * 100 * Math.PI) / 180
|
|
230
|
+
out.push({
|
|
231
|
+
x: Math.cos(a) * rho * scale,
|
|
232
|
+
y: Math.sin(a) * rho * scale,
|
|
233
|
+
r: (0.04 + 0.028 * clamp(u / 0.55)) * scale,
|
|
234
|
+
depth: clamp(1 - rho / 0.8),
|
|
235
|
+
opacity: clamp(u / 0.06) * clamp((0.62 - u) / 0.08)
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
return out
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ------------------------------------------------------------------ comete */
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Contrairement a l'intuition, le point ne traverse pas l'ecran : il reste au
|
|
245
|
+
* centre et c'est la trainee qui l'orbite. Ellipse a = 0.85, b = 0.15,
|
|
246
|
+
* grand axe incline de +34deg, 4 rubans, ~210 deg/s.
|
|
247
|
+
*/
|
|
248
|
+
const COMET_RNG = createRng(0xc0e7)
|
|
249
|
+
export const COMET_RIBBONS: ArcSeed[] = Array.from({ length: 4 }, (_, i) => {
|
|
250
|
+
const d = i - 1.5
|
|
251
|
+
return {
|
|
252
|
+
a: 0.85 * (1 + d * 0.03),
|
|
253
|
+
// meme aplatissement a +-5 % pres : les rubans forment un faisceau serre
|
|
254
|
+
k: (0.15 / 0.85) * (1 + d * 0.16),
|
|
255
|
+
tilt: (34 * Math.PI) / 180 + d * 0.035,
|
|
256
|
+
speed: 210 / 360,
|
|
257
|
+
// dephasage mesure : 10 a 20 degres entre rubans, pas davantage
|
|
258
|
+
phase: -i * 0.045 + COMET_RNG() * 0.012,
|
|
259
|
+
sweep: 0.34,
|
|
260
|
+
hue: i * 85 + COMET_RNG() * 20,
|
|
261
|
+
hueSpan: 80,
|
|
262
|
+
width: 0.095,
|
|
263
|
+
cx: 0,
|
|
264
|
+
cy: 0
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
/** Rayon du point de la comete, mesure a 0.129. */
|
|
269
|
+
export const COMET_DOT = 0.129
|
|
270
|
+
|
|
271
|
+
/* --------------------------------------------------- pastille notification */
|
|
272
|
+
|
|
273
|
+
/** Bleu releve au pixel. */
|
|
274
|
+
export const NOTIF_BLUE = '#2496e8'
|
|
275
|
+
/** La pastille est posee exactement sur la circonference, a -42deg. */
|
|
276
|
+
export const NOTIF_ANGLE = -42
|
|
277
|
+
export const NOTIF_DIST = 1.003
|
|
278
|
+
/** Rayon au repos ; le pop culmine 14 % au-dessus. */
|
|
279
|
+
export const NOTIF_R = 0.15
|
|
280
|
+
export const NOTIF_POP = 1.14
|
|
281
|
+
/**
|
|
282
|
+
* L'encoche est un disque concentrique a la pastille, soustrait du corps.
|
|
283
|
+
* La marge est constante (0.054 R) et suit l'echelle du corps.
|
|
284
|
+
*/
|
|
285
|
+
export const NOTIF_MARGIN = 0.054
|