@springbrand/message-panel 0.1.3-alpha.9 → 0.2.0-alpha.37

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 (67) hide show
  1. package/cloud-os/README.md +4 -3
  2. package/cloud-os/assets/followup-arrow.svg +3 -0
  3. package/cloud-os/assets/loading-corner.svg +3 -0
  4. package/cloud-os/assets/loading-mark.svg +16 -0
  5. package/cloud-os/assets/loading-spark.svg +3 -0
  6. package/cloud-os/assets/model-selected.svg +5 -0
  7. package/cloud-os/assets/thinking-star.svg +9 -0
  8. package/cloud-os/capability-chip.tsx +1 -1
  9. package/cloud-os/chat/cloud-os-chat-messages.tsx +441 -98
  10. package/cloud-os/chat/code-runner.tsx +106 -0
  11. package/cloud-os/chat/image-generation.tsx +76 -0
  12. package/cloud-os/chat/loading-state.tsx +25 -0
  13. package/cloud-os/chat/markdown-message.tsx +144 -41
  14. package/cloud-os/chat/range.ts +8 -0
  15. package/cloud-os/chat/rich-blocks.tsx +285 -227
  16. package/cloud-os/chat/surfaces.tsx +90 -0
  17. package/cloud-os/chat/tool-call.tsx +94 -0
  18. package/cloud-os/chat/tool-presentation.ts +31 -22
  19. package/cloud-os/chat/tool-rows.tsx +195 -143
  20. package/cloud-os/chat/tool-timeline.tsx +123 -0
  21. package/cloud-os/chat/transcript-model.ts +258 -20
  22. package/cloud-os/chat/web-search.tsx +135 -0
  23. package/cloud-os/composer/cloud-os-chat-input.tsx +29 -88
  24. package/cloud-os/composer/cloud-os-model-select.tsx +105 -0
  25. package/cloud-os/file-view.tsx +195 -12
  26. package/cloud-os/index.ts +24 -3
  27. package/cloud-os/layout/cloud-os-workspace-split.tsx +60 -3
  28. package/cloud-os/primitives/collapsible.tsx +21 -0
  29. package/cloud-os/primitives/workshop-controls.tsx +2 -2
  30. package/cloud-os/styles/cloud-os.css +132 -1
  31. package/demo/camel-chat-showcase.tsx +21 -13
  32. package/demo/chat-scenarios.ts +214 -40
  33. package/demo/cloud-os-chat-showcase.tsx +37 -14
  34. package/demo/fixtures.ts +4 -5
  35. package/demo/message-panel-gallery.tsx +16 -2
  36. package/package.json +8 -4
  37. package/springbrand-pet/LICENSE.bloub +21 -0
  38. package/springbrand-pet/bot/cycles.test.ts +221 -0
  39. package/springbrand-pet/bot/cycles.ts +225 -0
  40. package/springbrand-pet/bot/decor.ts +285 -0
  41. package/springbrand-pet/bot/engine.test.ts +543 -0
  42. package/springbrand-pet/bot/engine.ts +558 -0
  43. package/springbrand-pet/bot/expressions.test.ts +135 -0
  44. package/springbrand-pet/bot/expressions.ts +192 -0
  45. package/springbrand-pet/bot/eyefit.ts +455 -0
  46. package/springbrand-pet/bot/face.test.ts +101 -0
  47. package/springbrand-pet/bot/face.ts +179 -0
  48. package/springbrand-pet/bot/math.ts +42 -0
  49. package/springbrand-pet/bot/profiles.ts +22 -0
  50. package/springbrand-pet/bot/repere.ts +31 -0
  51. package/springbrand-pet/bot/shape.test.ts +97 -0
  52. package/springbrand-pet/bot/shape.ts +310 -0
  53. package/springbrand-pet/bot/skins.test.ts +325 -0
  54. package/springbrand-pet/bot/skins.ts +161 -0
  55. package/springbrand-pet/bot/states.ts +616 -0
  56. package/springbrand-pet/drag.test.ts +19 -0
  57. package/springbrand-pet/index.tsx +569 -0
  58. package/springbrand-pet/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  59. package/springbrand-pet/vitest.config.ts +9 -0
  60. package/src/camel/camel-chat-messages.tsx +78 -78
  61. package/src/camel/camel-tool-presentation.tsx +19 -15
  62. package/src/camel/camel-turn.ts +1 -17
  63. package/src/composer/composer-attachments.tsx +1 -1
  64. package/src/composer/composer.tsx +2 -2
  65. package/src/contracts.ts +0 -2
  66. package/src/message-panel.tsx +1 -24
  67. package/src/parts/index.tsx +103 -64
@@ -0,0 +1,161 @@
1
+ import { PROFILE_SAMPLES } from './profiles'
2
+ import {
3
+ hullOfCircles,
4
+ profileFromPolygon,
5
+ regularPolygonProfile,
6
+ superellipseProfile,
7
+ unionOfCirclesProfile
8
+ } from './shape'
9
+
10
+ /**
11
+ * Formes et couleurs proposees par le personnalisateur du bot.
12
+ *
13
+ * A la difference des silhouettes d'animation (`profiles.ts`), celles-ci ne sont
14
+ * PAS relevees sur la video : elles sont construites analytiquement d'apres la
15
+ * grille du personnalisateur d'origine. Deux sources distinctes, donc, et c'est
16
+ * volontaire — les etats animes doivent rester fideles a la video, les formes de
17
+ * base sont un choix d'utilisateur.
18
+ */
19
+
20
+ /**
21
+ * Les identifiants sont enumeres plutot que deduits du tableau : c'est ce qui
22
+ * permet a la couche i18n de verifier A LA COMPILATION que chaque forme a bien
23
+ * sa traduction dans les trois langues (`t(\`shapes.${id}\`)` ne compile que si
24
+ * la cle existe). Un `as const` sur le tableau aurait le meme effet mais
25
+ * rendrait `radii` en lecture seule, alors que le moteur le passe tel quel.
26
+ */
27
+ export type ShapeId =
28
+ | 'springbrand'
29
+ | 'cercle'
30
+ | 'galet'
31
+ | 'squircle'
32
+ | 'capsule'
33
+ | 'triangle'
34
+ | 'hexagone'
35
+ | 'nuage'
36
+ | 'goutte'
37
+
38
+ export interface BotShape {
39
+ id: ShapeId
40
+ radii: number[]
41
+ }
42
+
43
+ /** Ramene le rayon maximal a `max` pour que toutes les formes pesent pareil a l'oeil. */
44
+ function normalize(radii: number[], max = 1): number[] {
45
+ const peak = Math.max(...radii)
46
+ if (peak <= 0) return radii
47
+ const k = max / peak
48
+ return radii.map((r) => r * k)
49
+ }
50
+
51
+ const ANGLES = Array.from({ length: PROFILE_SAMPLES }, (_, i) => (i / PROFILE_SAMPLES) * Math.PI * 2)
52
+
53
+ /** SpringBrand: soft spring tension, biased from top-right to bottom-left. */
54
+ const springbrand = normalize(
55
+ ANGLES.map(
56
+ (a) =>
57
+ 1 +
58
+ 0.055 * Math.cos(2 * a - 0.62) +
59
+ 0.026 * Math.sin(3 * a + 0.8) +
60
+ 0.012 * Math.sin(5 * a)
61
+ ),
62
+ 1.04
63
+ )
64
+
65
+ /** Galet : cercle deforme par deux harmoniques basses, donc irregulier mais lisse. */
66
+ const pebble = normalize(
67
+ ANGLES.map((a) => 1 + 0.075 * Math.cos(2 * a + 0.5) + 0.035 * Math.cos(3 * a + 2.1)),
68
+ 1.02
69
+ )
70
+
71
+ /** Nuage : union de bosses, large en bas, deux lobes en haut. */
72
+ const cloud = normalize(
73
+ unionOfCirclesProfile([
74
+ { x: -0.44, y: 0.2, r: 0.54 },
75
+ { x: 0.46, y: 0.2, r: 0.5 },
76
+ { x: 0.02, y: 0.3, r: 0.6 },
77
+ { x: -0.24, y: -0.3, r: 0.48 },
78
+ { x: 0.3, y: -0.24, r: 0.44 }
79
+ ]),
80
+ 1.02
81
+ )
82
+
83
+ /** Goutte : gros disque en bas, pointe effilee en haut. */
84
+ const droplet = normalize(
85
+ profileFromPolygon(hullOfCircles(0, 0.28, 0.66, 0, -0.96, 0.05), 0, 0),
86
+ 1.04
87
+ )
88
+
89
+ /** Capsule couchee : enveloppe de deux disques cote a cote. */
90
+ const capsule = profileFromPolygon(hullOfCircles(-0.42, 0, 0.62, 0.42, 0, 0.62), 0, 0)
91
+
92
+ export const SHAPES: BotShape[] = [
93
+ { id: 'springbrand', radii: springbrand },
94
+ { id: 'cercle', radii: new Array(PROFILE_SAMPLES).fill(1) },
95
+ { id: 'galet', radii: pebble },
96
+ // 1.15 et pas 1.02 : sur une superellipse le rayon maximal est la diagonale,
97
+ // donc normaliser dessus donne une forme qui parait plus petite que le cercle.
98
+ { id: 'squircle', radii: normalize(superellipseProfile(4.2), 1.15) },
99
+ { id: 'capsule', radii: capsule },
100
+ // -90deg : un sommet vers le haut de l'ecran (y est oriente vers le bas)
101
+ { id: 'triangle', radii: regularPolygonProfile(3, 1.12, 0.34, -90) },
102
+ // 0deg : sommets a gauche et a droite, donc aretes du haut et du bas plates
103
+ { id: 'hexagone', radii: regularPolygonProfile(6, 1.04, 0.26, 0) },
104
+ { id: 'nuage', radii: cloud },
105
+ { id: 'goutte', radii: droplet }
106
+ ]
107
+
108
+ // Map indexee par `string` et non par `ShapeId` : les appelants interrogent avec
109
+ // une valeur relue du localStorage ou d'une prop, donc non validee.
110
+ export const SHAPE_BY_ID = new Map<string, BotShape>(SHAPES.map((s) => [s.id, s]))
111
+ export const DEFAULT_SHAPE = 'cercle'
112
+
113
+ export type ColorId =
114
+ | 'encre'
115
+ | 'creme'
116
+ | 'brun'
117
+ | 'rouge'
118
+ | 'orange'
119
+ | 'ambre'
120
+ | 'vert'
121
+ | 'turquoise'
122
+ | 'bleu'
123
+ | 'violet'
124
+ | 'rose'
125
+ | 'gris'
126
+
127
+ export interface BotColor {
128
+ id: ColorId
129
+ hex: string
130
+ }
131
+
132
+ /** Palette du personnalisateur d'origine. */
133
+ export const COLORS: BotColor[] = [
134
+ { id: 'encre', hex: '#0a0a0c' },
135
+ { id: 'brun', hex: '#8b5e3c' },
136
+ { id: 'rouge', hex: '#e8483f' },
137
+ { id: 'orange', hex: '#f08a24' },
138
+ { id: 'ambre', hex: '#f0b429' },
139
+ { id: 'vert', hex: '#3ecf8e' },
140
+ { id: 'turquoise', hex: '#2fbfa0' },
141
+ { id: 'bleu', hex: '#3b93f0' },
142
+ { id: 'violet', hex: '#8b5cf6' },
143
+ { id: 'rose', hex: '#e152b0' },
144
+ { id: 'gris', hex: '#a3a3a3' },
145
+ { id: 'creme', hex: '#f1efe9' }
146
+ ]
147
+
148
+ export const COLOR_BY_ID = new Map<string, BotColor>(COLORS.map((c) => [c.id, c]))
149
+ export const DEFAULT_COLOR = 'encre'
150
+
151
+ /** Melange deux couleurs hex. Sert a la brume de profondeur des particules. */
152
+ export function mixHex(from: string, to: string, t: number): string {
153
+ const parse = (h: string) => {
154
+ const v = parseInt(h.slice(1), 16)
155
+ return [(v >> 16) & 255, (v >> 8) & 255, v & 255]
156
+ }
157
+ const a = parse(from)
158
+ const b = parse(to)
159
+ const c = a.map((x, i) => Math.round(x + (b[i]! - x) * t))
160
+ return `#${c.map((x) => x.toString(16).padStart(2, '0')).join('')}`
161
+ }