@vibes.diy/prompts 14.3.203 → 14.3.204

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 (243) hide show
  1. package/llms/access.md +4 -4
  2. package/llms/backend.md +1 -1
  3. package/llms/blockly.md +2 -2
  4. package/llms/bluesky.md +1 -1
  5. package/llms/board-games.md +3 -3
  6. package/llms/calendar.md +1 -1
  7. package/llms/callai.md +4 -4
  8. package/llms/connections.md +1 -1
  9. package/llms/create-vibe.md +3 -3
  10. package/llms/fireproof.md +7 -7
  11. package/llms/github.md +2 -2
  12. package/llms/image-gen.md +2 -2
  13. package/llms/index.d.ts +28 -28
  14. package/llms/index.js +84 -84
  15. package/llms/index.js.map +1 -1
  16. package/llms/maps.md +1 -1
  17. package/llms/match-style.md +1 -1
  18. package/llms/motion.md +7 -7
  19. package/llms/p5.md +1 -1
  20. package/llms/physics.md +2 -2
  21. package/llms/reskin.md +21 -21
  22. package/llms/richtext.md +5 -5
  23. package/llms/spotify.md +1 -1
  24. package/llms/stripe-subscriptions.md +1 -1
  25. package/llms/stripe.md +3 -3
  26. package/llms/strudel.md +3 -3
  27. package/llms/three-js.md +4 -4
  28. package/llms/touch-games.js +1 -1
  29. package/llms/touch-games.js.map +1 -1
  30. package/llms/touch-games.md +3 -3
  31. package/llms/ui-blog.d.ts +2 -0
  32. package/llms/ui-blog.js +7 -0
  33. package/llms/ui-blog.js.map +1 -0
  34. package/llms/{pouf-blog.md → ui-blog.md} +10 -10
  35. package/llms/ui-booking.d.ts +2 -0
  36. package/llms/ui-booking.js +7 -0
  37. package/llms/ui-booking.js.map +1 -0
  38. package/llms/{pouf-booking.md → ui-booking.md} +8 -8
  39. package/llms/ui-calendar.d.ts +2 -0
  40. package/llms/ui-calendar.js +7 -0
  41. package/llms/ui-calendar.js.map +1 -0
  42. package/llms/{pouf-calendar.md → ui-calendar.md} +5 -5
  43. package/llms/ui-chat.d.ts +2 -0
  44. package/llms/ui-chat.js +7 -0
  45. package/llms/ui-chat.js.map +1 -0
  46. package/llms/{pouf-chat.md → ui-chat.md} +4 -4
  47. package/llms/ui-contact.d.ts +2 -0
  48. package/llms/ui-contact.js +7 -0
  49. package/llms/ui-contact.js.map +1 -0
  50. package/llms/{pouf-contact.md → ui-contact.md} +7 -7
  51. package/llms/ui-course.d.ts +2 -0
  52. package/llms/ui-course.js +7 -0
  53. package/llms/ui-course.js.map +1 -0
  54. package/llms/{pouf-course.md → ui-course.md} +9 -9
  55. package/llms/ui-crm.d.ts +2 -0
  56. package/llms/ui-crm.js +7 -0
  57. package/llms/ui-crm.js.map +1 -0
  58. package/llms/{pouf-crm.md → ui-crm.md} +5 -5
  59. package/llms/ui-dashboard.d.ts +2 -0
  60. package/llms/ui-dashboard.js +7 -0
  61. package/llms/ui-dashboard.js.map +1 -0
  62. package/llms/{pouf-dashboard.md → ui-dashboard.md} +7 -7
  63. package/llms/ui-editorial.d.ts +2 -0
  64. package/llms/ui-editorial.js +7 -0
  65. package/llms/ui-editorial.js.map +1 -0
  66. package/llms/{pouf-editorial.md → ui-editorial.md} +5 -5
  67. package/llms/ui-event.d.ts +2 -0
  68. package/llms/ui-event.js +7 -0
  69. package/llms/ui-event.js.map +1 -0
  70. package/llms/{pouf-event.md → ui-event.md} +5 -5
  71. package/llms/ui-feed.d.ts +2 -0
  72. package/llms/ui-feed.js +7 -0
  73. package/llms/ui-feed.js.map +1 -0
  74. package/llms/{pouf-feed.md → ui-feed.md} +5 -5
  75. package/llms/ui-game.d.ts +2 -0
  76. package/llms/ui-game.js +7 -0
  77. package/llms/ui-game.js.map +1 -0
  78. package/llms/{pouf-game.md → ui-game.md} +6 -6
  79. package/llms/ui-inbox.d.ts +2 -0
  80. package/llms/ui-inbox.js +7 -0
  81. package/llms/ui-inbox.js.map +1 -0
  82. package/llms/{pouf-inbox.md → ui-inbox.md} +5 -5
  83. package/llms/ui-inventory.d.ts +2 -0
  84. package/llms/ui-inventory.js +7 -0
  85. package/llms/ui-inventory.js.map +1 -0
  86. package/llms/{pouf-inventory.md → ui-inventory.md} +5 -5
  87. package/llms/ui-kanban.d.ts +2 -0
  88. package/llms/ui-kanban.js +7 -0
  89. package/llms/ui-kanban.js.map +1 -0
  90. package/llms/{pouf-kanban.md → ui-kanban.md} +5 -5
  91. package/llms/ui-landing.d.ts +2 -0
  92. package/llms/ui-landing.js +7 -0
  93. package/llms/ui-landing.js.map +1 -0
  94. package/llms/{pouf-landing.md → ui-landing.md} +6 -6
  95. package/llms/ui-login.d.ts +2 -0
  96. package/llms/ui-login.js +7 -0
  97. package/llms/ui-login.js.map +1 -0
  98. package/llms/{pouf-login.md → ui-login.md} +7 -7
  99. package/llms/ui-music.d.ts +2 -0
  100. package/llms/ui-music.js +7 -0
  101. package/llms/ui-music.js.map +1 -0
  102. package/llms/{pouf-music.md → ui-music.md} +6 -6
  103. package/llms/ui-onboarding.d.ts +2 -0
  104. package/llms/ui-onboarding.js +7 -0
  105. package/llms/ui-onboarding.js.map +1 -0
  106. package/llms/{pouf-onboarding.md → ui-onboarding.md} +5 -5
  107. package/llms/ui-pricing.d.ts +2 -0
  108. package/llms/ui-pricing.js +7 -0
  109. package/llms/ui-pricing.js.map +1 -0
  110. package/llms/{pouf-pricing.md → ui-pricing.md} +5 -5
  111. package/llms/ui-profile.d.ts +2 -0
  112. package/llms/ui-profile.js +7 -0
  113. package/llms/ui-profile.js.map +1 -0
  114. package/llms/{pouf-profile.md → ui-profile.md} +4 -4
  115. package/llms/ui-quiz.d.ts +2 -0
  116. package/llms/ui-quiz.js +7 -0
  117. package/llms/ui-quiz.js.map +1 -0
  118. package/llms/{pouf-quiz.md → ui-quiz.md} +6 -6
  119. package/llms/ui-settings.d.ts +2 -0
  120. package/llms/ui-settings.js +7 -0
  121. package/llms/ui-settings.js.map +1 -0
  122. package/llms/{pouf-settings.md → ui-settings.md} +5 -5
  123. package/llms/ui-storefront.d.ts +2 -0
  124. package/llms/ui-storefront.js +7 -0
  125. package/llms/ui-storefront.js.map +1 -0
  126. package/llms/{pouf-storefront.md → ui-storefront.md} +9 -9
  127. package/llms/ui-support.d.ts +2 -0
  128. package/llms/ui-support.js +7 -0
  129. package/llms/ui-support.js.map +1 -0
  130. package/llms/{pouf-support.md → ui-support.md} +5 -5
  131. package/llms/ui-testimonials.d.ts +2 -0
  132. package/llms/ui-testimonials.js +7 -0
  133. package/llms/ui-testimonials.js.map +1 -0
  134. package/llms/{pouf-testimonials.md → ui-testimonials.md} +6 -6
  135. package/llms/ui-todo.d.ts +2 -0
  136. package/llms/ui-todo.js +7 -0
  137. package/llms/ui-todo.js.map +1 -0
  138. package/llms/{pouf-todo.md → ui-todo.md} +5 -5
  139. package/llms/ui-weather.d.ts +2 -0
  140. package/llms/ui-weather.js +7 -0
  141. package/llms/ui-weather.js.map +1 -0
  142. package/llms/{pouf-weather.md → ui-weather.md} +5 -5
  143. package/llms/use-vibe.md +4 -4
  144. package/llms/use-viewer.md +5 -5
  145. package/llms/voxel.md +1 -1
  146. package/llms/web-audio.md +12 -12
  147. package/llms/worlds.md +3 -3
  148. package/llms/youtube.md +1 -1
  149. package/package.json +5 -5
  150. package/system-prompt-initial-instant.md +3 -3
  151. package/system-prompt.md +3 -3
  152. package/themes/colorsets.js +7 -7
  153. package/themes/colorsets.js.map +1 -1
  154. package/themes/looks/pouf/brief.md +87 -87
  155. package/themes/looks/pouf/catalog.generated.d.ts +1 -1
  156. package/themes/looks/pouf/catalog.generated.js +17 -17
  157. package/themes/looks/pouf/catalog.generated.js.map +1 -1
  158. package/themes/looks/pouf/variety.js +4 -4
  159. package/themes/looks/pouf/variety.js.map +1 -1
  160. package/llms/pouf-blog.d.ts +0 -2
  161. package/llms/pouf-blog.js +0 -6
  162. package/llms/pouf-blog.js.map +0 -1
  163. package/llms/pouf-booking.d.ts +0 -2
  164. package/llms/pouf-booking.js +0 -6
  165. package/llms/pouf-booking.js.map +0 -1
  166. package/llms/pouf-calendar.d.ts +0 -2
  167. package/llms/pouf-calendar.js +0 -6
  168. package/llms/pouf-calendar.js.map +0 -1
  169. package/llms/pouf-chat.d.ts +0 -2
  170. package/llms/pouf-chat.js +0 -6
  171. package/llms/pouf-chat.js.map +0 -1
  172. package/llms/pouf-contact.d.ts +0 -2
  173. package/llms/pouf-contact.js +0 -6
  174. package/llms/pouf-contact.js.map +0 -1
  175. package/llms/pouf-course.d.ts +0 -2
  176. package/llms/pouf-course.js +0 -6
  177. package/llms/pouf-course.js.map +0 -1
  178. package/llms/pouf-crm.d.ts +0 -2
  179. package/llms/pouf-crm.js +0 -6
  180. package/llms/pouf-crm.js.map +0 -1
  181. package/llms/pouf-dashboard.d.ts +0 -2
  182. package/llms/pouf-dashboard.js +0 -6
  183. package/llms/pouf-dashboard.js.map +0 -1
  184. package/llms/pouf-editorial.d.ts +0 -2
  185. package/llms/pouf-editorial.js +0 -6
  186. package/llms/pouf-editorial.js.map +0 -1
  187. package/llms/pouf-event.d.ts +0 -2
  188. package/llms/pouf-event.js +0 -6
  189. package/llms/pouf-event.js.map +0 -1
  190. package/llms/pouf-feed.d.ts +0 -2
  191. package/llms/pouf-feed.js +0 -6
  192. package/llms/pouf-feed.js.map +0 -1
  193. package/llms/pouf-game.d.ts +0 -2
  194. package/llms/pouf-game.js +0 -6
  195. package/llms/pouf-game.js.map +0 -1
  196. package/llms/pouf-inbox.d.ts +0 -2
  197. package/llms/pouf-inbox.js +0 -6
  198. package/llms/pouf-inbox.js.map +0 -1
  199. package/llms/pouf-inventory.d.ts +0 -2
  200. package/llms/pouf-inventory.js +0 -6
  201. package/llms/pouf-inventory.js.map +0 -1
  202. package/llms/pouf-kanban.d.ts +0 -2
  203. package/llms/pouf-kanban.js +0 -6
  204. package/llms/pouf-kanban.js.map +0 -1
  205. package/llms/pouf-landing.d.ts +0 -2
  206. package/llms/pouf-landing.js +0 -6
  207. package/llms/pouf-landing.js.map +0 -1
  208. package/llms/pouf-login.d.ts +0 -2
  209. package/llms/pouf-login.js +0 -6
  210. package/llms/pouf-login.js.map +0 -1
  211. package/llms/pouf-music.d.ts +0 -2
  212. package/llms/pouf-music.js +0 -6
  213. package/llms/pouf-music.js.map +0 -1
  214. package/llms/pouf-onboarding.d.ts +0 -2
  215. package/llms/pouf-onboarding.js +0 -6
  216. package/llms/pouf-onboarding.js.map +0 -1
  217. package/llms/pouf-pricing.d.ts +0 -2
  218. package/llms/pouf-pricing.js +0 -6
  219. package/llms/pouf-pricing.js.map +0 -1
  220. package/llms/pouf-profile.d.ts +0 -2
  221. package/llms/pouf-profile.js +0 -6
  222. package/llms/pouf-profile.js.map +0 -1
  223. package/llms/pouf-quiz.d.ts +0 -2
  224. package/llms/pouf-quiz.js +0 -6
  225. package/llms/pouf-quiz.js.map +0 -1
  226. package/llms/pouf-settings.d.ts +0 -2
  227. package/llms/pouf-settings.js +0 -6
  228. package/llms/pouf-settings.js.map +0 -1
  229. package/llms/pouf-storefront.d.ts +0 -2
  230. package/llms/pouf-storefront.js +0 -6
  231. package/llms/pouf-storefront.js.map +0 -1
  232. package/llms/pouf-support.d.ts +0 -2
  233. package/llms/pouf-support.js +0 -6
  234. package/llms/pouf-support.js.map +0 -1
  235. package/llms/pouf-testimonials.d.ts +0 -2
  236. package/llms/pouf-testimonials.js +0 -6
  237. package/llms/pouf-testimonials.js.map +0 -1
  238. package/llms/pouf-todo.d.ts +0 -2
  239. package/llms/pouf-todo.js +0 -6
  240. package/llms/pouf-todo.js.map +0 -1
  241. package/llms/pouf-weather.d.ts +0 -2
  242. package/llms/pouf-weather.js +0 -6
  243. package/llms/pouf-weather.js.map +0 -1
package/llms/motion.md CHANGED
@@ -14,7 +14,7 @@ stops when the component goes away.
14
14
 
15
15
  The sibling boundary: a list whose items fade and rise as they enter uses
16
16
  the house flourish, the `starting:` Tailwind classes, with no engine at all;
17
- a canvas that redraws every frame is `p5`, `worlds` or `physics`; pouf
17
+ a canvas that redraws every frame is `p5`, `worlds` or `physics`; the UI's
18
18
  components carry their own motion (a `Card` with `motion="lift"`, the
19
19
  toasts, the sheets). Motion is the right call when something on the page
20
20
  responds to scroll, to time, or to touch.
@@ -52,8 +52,8 @@ before the engine lands cancels the setup (measured: a `move` stopped during
52
52
  the load moved nothing). `motionScope()` is the collector.
53
53
 
54
54
  **Every helper reads the reduced-motion setting when it runs** and lands on
55
- the end state instead of animating. Pouf's own reduced-motion rule is scoped
56
- to pouf's elements, so an animation the app authors gets no safety net from
55
+ the end state instead of animating. The UI's own reduced-motion rule is scoped
56
+ to the UI's elements, so an animation the app authors gets no safety net from
57
57
  it; the helpers are the net (measured with the media feature emulated: lists
58
58
  land visible, reveals leave everything visible, the count shows its final
59
59
  number, the press does nothing, scroll progress still reports).
@@ -212,7 +212,7 @@ export function pressSquash(target, { scale = 0.94 } = {}) {
212
212
  ### `App.jsx`
213
213
  ```jsx app=story
214
214
  import React, { useEffect, useRef } from "react";
215
- import { Button, Card, Heading, Row, Spacer, Stack, Text } from "@vibes.diy/pouf";
215
+ import { Button, Card, Heading, Row, Spacer, Stack, Text } from "@vibes.diy/ui";
216
216
  import { countUp, motionScope, onEnter, pressSquash, reveal, scrollProgress, sequence, staggerIn } from "./lib/motion.js";
217
217
 
218
218
  const CHAPTERS = [
@@ -297,7 +297,7 @@ export default function App() {
297
297
  ```
298
298
 
299
299
  The JSX stays class-only: positions, sizes and colours are Tailwind classes
300
- and pouf props, and Motion writes transforms and opacity onto the elements
300
+ and component props, and Motion writes transforms and opacity onto the elements
301
301
  through refs and selectors. The one place a style is set in the app's own
302
302
  code is the progress bar's `transform` inside the scroll callback, through
303
303
  its ref, which is what a scroll binding is for.
@@ -434,7 +434,7 @@ export function pressSquash(target, { scale = 0.94 } = {}) {
434
434
  import React, { useEffect, useMemo, useRef, useState } from "react";
435
435
  import { useFireproof } from "use-fireproof";
436
436
  import { useVibe, useViewer } from "use-vibes";
437
- import { Button, Card, Field, Heading, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/pouf";
437
+ import { Button, Card, Field, Heading, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
438
438
  import { motionScope, move, pressSquash } from "./lib/motion.js";
439
439
 
440
440
  export default function App() {
@@ -544,7 +544,7 @@ is the baseline and animates nothing, every later snapshot's ids are
544
544
  remembered, and only a top note nobody has seen springs in, so a board that
545
545
  loaded with twenty notes stands still and a reorder moves nothing. (A board
546
546
  that is empty when it opens treats its first note as the baseline too; the
547
- second note is the first to spring.) Pouf's `Card motion="lift"` carries
547
+ second note is the first to spring.) The UI's `Card motion="lift"` carries
548
548
  the hover, so the app writes none of its own.
549
549
 
550
550
  ## Mobile
package/llms/p5.md CHANGED
@@ -24,7 +24,7 @@ the instance so remounts do not leak a second draw loop.
24
24
  ```jsx
25
25
  import React from "react";
26
26
  import p5 from "https://esm.sh/p5@1.11.13";
27
- import { Button, Row, Stack } from "@vibes.diy/pouf";
27
+ import { Button, Row, Stack } from "@vibes.diy/ui";
28
28
 
29
29
  const TAU = Math.PI * 2;
30
30
 
package/llms/physics.md CHANGED
@@ -225,7 +225,7 @@ from the pieces so the next drop replays the last one exactly.
225
225
  import React, { useEffect, useMemo, useRef, useState } from "react";
226
226
  import { useFireproof } from "use-fireproof";
227
227
  import { useVibe, useViewer } from "use-vibes";
228
- import { Badge, Button, Card, Field, Heading, Input, Row, Segmented, Skeleton, Spacer, Stack, Text } from "@vibes.diy/pouf";
228
+ import { Badge, Button, Card, Field, Heading, Input, Row, Segmented, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
229
229
  import { createWorld } from "./lib/physics.js";
230
230
 
231
231
  const WIDTH = 360;
@@ -495,7 +495,7 @@ button that applies a force to every body.
495
495
  ### `App.jsx`
496
496
  ```jsx app=tumble
497
497
  import React, { useEffect, useRef, useState } from "react";
498
- import { Button, Field, Heading, Input, Row, Spacer, Stack, Text } from "@vibes.diy/pouf";
498
+ import { Button, Field, Heading, Input, Row, Spacer, Stack, Text } from "@vibes.diy/ui";
499
499
  import { Matter, createWorld, cssColor } from "./lib/physics.js";
500
500
 
501
501
  const { Bodies, Body, Composite } = Matter;
package/llms/reskin.md CHANGED
@@ -7,8 +7,8 @@ the app keeps its look's components, its logic and its Look tab, and wears that
7
7
  appearance on top of them. Every `Card`, `Button`, `RowCard` and `Heading`
8
8
  stays exactly where it is; what changes is how they are drawn.
9
9
 
10
- This works on every look that shares the component surface (pouf today, and the
11
- looks built on its API): the same tokens, the same hook classes, the same
10
+ This works on every look that shares the component surface (the default look today,
11
+ and the looks built on its API): the same tokens, the same hook classes, the same
12
12
  technique.
13
13
 
14
14
  - Colour, a catalogue font or spacing alone is the Look tab (`set_app_style`);
@@ -30,24 +30,24 @@ so the wrapper's values are the ones every component reads.
30
30
  The tokens: `--bg --surface --ink --text-secondary --purple --on-accent
31
31
  --orange --info --up --down --idle --warn` (colour), `--r-card --r-control
32
32
  --r-pill` (corners), `--lip --lip-row` (the cushion's edge), `--font-family`,
33
- `--s1` … `--s7` (spacing), and the composite surfaces `--pouf-card --pouf-row
34
- --pouf-control --pouf-control-active --pouf-field --pouf-field-focus`. A
33
+ `--s1` … `--s7` (spacing), and the composite surfaces `--ui-card --ui-row
34
+ --ui-control --ui-control-active --ui-field --ui-field-focus`. A
35
35
  composite is resolved where it is declared, so a skin that changes the shadows
36
36
  or the edge re-declares those composites on the wrapper too (`none` for a flat
37
37
  skin).
38
38
 
39
39
  **2. The look's parts are styled through their hook classes, from the wrapper.**
40
- Every component carries a stable class: `.pouf-h1 .pouf-h2 .pouf-h3 .pouf-card
41
- .pouf-rowcard .pouf-btn .pouf-blob .pouf-empty .pouf-stat .pouf-eyebrow
42
- .pouf-grid .pouf-input .pouf-field .pouf-badge .pouf-tabs .pouf-dialog`, and the
43
- rest of the package's `pouf-*` names. Write the skin as `[data-reskin] .pouf-card
40
+ Every component carries a stable class: `.ui-h1 .ui-h2 .ui-h3 .ui-card
41
+ .ui-rowcard .ui-btn .ui-blob .ui-empty .ui-stat .ui-eyebrow
42
+ .ui-grid .ui-input .ui-field .ui-badge .ui-tabs .ui-dialog`, and the
43
+ rest of the package's `ui-*` names. Write the skin as `[data-reskin] .ui-card
44
44
  { … }`. The components themselves take no `className` and no `style`: they keep
45
45
  their props (`tone`, `size`, `variant`), and the skin reaches them by class.
46
46
 
47
47
  **Portaled parts stay in the skin.** `Dialog`, `Select`, `Popover`, `Tooltip`
48
48
  and `AlertDialog` render their open content under `<body>`, outside the
49
49
  wrapper. So the token block is declared on `[data-reskin], body:has([data-reskin])`,
50
- and a rule for a portaled part is written `body:has([data-reskin]) .pouf-dialog
50
+ and a rule for a portaled part is written `body:has([data-reskin]) .ui-dialog
51
51
  { … }`. `body` sits below `:root`, so its tokens win for the whole page, the
52
52
  open modal and dropdown included.
53
53
 
@@ -83,7 +83,7 @@ cushions, Chicago-like bitmap type (`Silkscreen`) over a plain grotesk body
83
83
  import React, { useState } from "react";
84
84
  import { useFireproof } from "use-fireproof";
85
85
  import { useVibe } from "use-vibes";
86
- import { Button, Card, Empty, Field, Heading, Input, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/pouf";
86
+ import { Button, Card, Empty, Field, Heading, Input, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/ui";
87
87
 
88
88
  const SKIN = `
89
89
  @import url('https://fonts.googleapis.com/css2?family=Silkscreen&family=Space+Grotesk:wght@400;600&display=swap');
@@ -92,8 +92,8 @@ const SKIN = `
92
92
  --purple: #000000; --on-accent: #ffffff;
93
93
  --r-card: 0px; --r-control: 0px; --r-pill: 0px; --lip: 0px; --lip-row: 0px;
94
94
  --font-family: 'Space Grotesk', system-ui, sans-serif;
95
- --pouf-card: none; --pouf-row: none; --pouf-control: none; --pouf-control-active: none;
96
- --pouf-field: inset 0 0 0 1px #000000; --pouf-field-focus: inset 0 0 0 2px #000000;
95
+ --ui-card: none; --ui-row: none; --ui-control: none; --ui-control-active: none;
96
+ --ui-field: inset 0 0 0 1px #000000; --ui-field-focus: inset 0 0 0 2px #000000;
97
97
  min-height: 100vh; background: var(--bg); color: var(--ink); font-family: var(--font-family);
98
98
  }
99
99
  [data-reskin] .menubar { background: #ffffff; border-bottom: 1px solid #000000; padding: 2px 12px; font-family: 'Silkscreen', monospace; }
@@ -101,12 +101,12 @@ const SKIN = `
101
101
  [data-reskin] .titlebar { height: 20px; border-bottom: 1px solid #000000; text-align: center; font-family: 'Silkscreen', monospace; font-size: 12px; line-height: 20px;
102
102
  background: repeating-linear-gradient(#ffffff 0 1px, #000000 1px 2px); }
103
103
  [data-reskin] .titlebar span { background: #ffffff; padding: 0 8px; }
104
- [data-reskin] .pouf-h1, [data-reskin] .pouf-h2 { font-family: 'Silkscreen', monospace; letter-spacing: 0; }
105
- [data-reskin] .pouf-card, [data-reskin] .pouf-rowcard { border: 1px solid #000000; }
106
- [data-reskin] .pouf-btn { border: 1px solid #000000; background: #ffffff; color: #000000; border-radius: 6px; }
107
- [data-reskin] .pouf-btn:active { background: #000000; color: #ffffff; }
108
- [data-reskin] .pouf-empty { border: 1px dashed #000000; }
109
- body:has([data-reskin]) .pouf-dialog { border: 1px solid #000000; border-radius: 0; box-shadow: 2px 2px 0 #000000; }
104
+ [data-reskin] .ui-h1, [data-reskin] .ui-h2 { font-family: 'Silkscreen', monospace; letter-spacing: 0; }
105
+ [data-reskin] .ui-card, [data-reskin] .ui-rowcard { border: 1px solid #000000; }
106
+ [data-reskin] .ui-btn { border: 1px solid #000000; background: #ffffff; color: #000000; border-radius: 6px; }
107
+ [data-reskin] .ui-btn:active { background: #000000; color: #ffffff; }
108
+ [data-reskin] .ui-empty { border: 1px dashed #000000; }
109
+ body:has([data-reskin]) .ui-dialog { border: 1px solid #000000; border-radius: 0; box-shadow: 2px 2px 0 #000000; }
110
110
  `;
111
111
 
112
112
  export default function App() {
@@ -232,7 +232,7 @@ let the components edit it.
232
232
 
233
233
  ```jsx
234
234
  import React, { useState } from "react";
235
- import { Button, Field, Input, Stack } from "@vibes.diy/pouf";
235
+ import { Button, Field, Input, Stack } from "@vibes.diy/ui";
236
236
 
237
237
  const SKIN = `
238
238
  @import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,wght@0,600;1,400&display=swap');
@@ -289,7 +289,7 @@ example.
289
289
  Name the five things a stranger would recognise and set each one:
290
290
 
291
291
  - **Ground and surfaces:** `--bg`, `--surface`, `--ink`, `--text-secondary`.
292
- - **Type:** one display face for `.pouf-h1`/`.pouf-h2`/`.pouf-eyebrow`, one body
292
+ - **Type:** one display face for `.ui-h1`/`.ui-h2`/`.ui-eyebrow`, one body
293
293
  face on `--font-family`, the heading scale and tracking.
294
294
  - **Edges:** corners (`--r-card`, `--r-control`, `--r-pill`), borders on the
295
295
  hook classes, and the composite surfaces (`none` for flat, a hard offset for
@@ -302,5 +302,5 @@ Name the five things a stranger would recognise and set each one:
302
302
  A newspaper is a cream ground, black ink, a serif masthead over a rule, column
303
303
  grids and no shadows; a terminal is black, one phosphor green, a mono face and
304
304
  a blinking cursor that starts lit; Y2K is chrome gradients, pill corners and a
305
- glossy highlight on `.pouf-btn`. The words on screen stay the app's own: the
305
+ glossy highlight on `.ui-btn`. The words on screen stay the app's own: the
306
306
  style is borrowed, the names and logos of whoever made it famous are not.
package/llms/richtext.md CHANGED
@@ -10,8 +10,8 @@ in Fireproof, saves after typing pauses, loads a document without echoing it
10
10
  back as a save, and styles the written text with Tailwind on the host.
11
11
 
12
12
  The sibling boundary: a short field (a title, a comment, a caption) is
13
- pouf's `Textarea` in a `Field`; a feed of posts is `pouf-feed`; a pipeline
14
- of stories with stages is `pouf-editorial`. Rich text is the right call when
13
+ the UI's `Textarea` in a `Field`; a feed of posts is `ui-feed`; a pipeline
14
+ of stories with stages is `ui-editorial`. Rich text is the right call when
15
15
  the person is writing a page.
16
16
 
17
17
  The worked examples below were built and measured for this doc (Chromium,
@@ -165,7 +165,7 @@ export function createEditor(host, { content = EMPTY_DOC, placeholder = "Start w
165
165
  import React, { useEffect, useMemo, useRef, useState } from "react";
166
166
  import { useFireproof } from "use-fireproof";
167
167
  import { useVibe, useViewer } from "use-vibes";
168
- import { Badge, Button, Card, Heading, IconButton, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/pouf";
168
+ import { Badge, Button, Card, Heading, IconButton, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
169
169
  import { EMPTY_DOC, createEditor, titleOf } from "./lib/editor.js";
170
170
 
171
171
  // The written page is styled from the host: Tailwind reaches into the editor with arbitrary
@@ -471,7 +471,7 @@ through Tailwind's arbitrary variants**: `[&_h1]:text-2xl`,
471
471
  `[&_.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]`.
472
472
  The JSX stays class-only and the theme tokens (`text-primary`,
473
473
  `text-muted-foreground`, `bg-muted`) carry the owner's restyle into the
474
- written page. Measured: the pouf lint passes a host carrying these classes.
474
+ written page. Measured: the design lint passes a host carrying these classes.
475
475
 
476
476
  ## Commands and the toolbar
477
477
 
@@ -553,7 +553,7 @@ export function createEditor(host, { content = EMPTY_DOC, placeholder = "Start w
553
553
  import React, { useEffect, useRef, useState } from "react";
554
554
  import { useFireproof } from "use-fireproof";
555
555
  import { useVibe, useViewer } from "use-vibes";
556
- import { Badge, Button, Card, Heading, Row, Spacer, Stack, Text } from "@vibes.diy/pouf";
556
+ import { Badge, Button, Card, Heading, Row, Spacer, Stack, Text } from "@vibes.diy/ui";
557
557
  import { EMPTY_DOC, createEditor } from "./lib/editor.js";
558
558
 
559
559
  const PAGE_ID = "page:home";
package/llms/spotify.md CHANGED
@@ -325,7 +325,7 @@ function artistRow(a) {
325
325
  ```jsx app=spotify-browser
326
326
  import React, { useEffect, useRef, useState } from "react";
327
327
  import { apiFetch } from "use-vibes";
328
- import { Badge, Button, Field, Heading, Input, Row, Stack, Text } from "@vibes.diy/pouf";
328
+ import { Badge, Button, Field, Heading, Input, Row, Stack, Text } from "@vibes.diy/ui";
329
329
 
330
330
  // The setup verdict, read on mount and again whenever the app comes back into view: the owner
331
331
  // sets the pair in another tab and returns, and search unlocks without a reload.
@@ -683,7 +683,7 @@ export function club(doc, oldDoc, user, ctx) {
683
683
  import React, { useEffect, useRef, useState } from "react";
684
684
  import { useFireproof } from "use-fireproof";
685
685
  import { apiFetch, useViewer } from "use-vibes";
686
- import { Badge, Button, Heading, Row, Stack, Text } from "@vibes.diy/pouf";
686
+ import { Badge, Button, Heading, Row, Stack, Text } from "@vibes.diy/ui";
687
687
 
688
688
  // The setup verdict, read on mount and again whenever the app comes back into view: the owner
689
689
  // connects Stripe or saves the portal in another tab and returns, and the Join buttons unlock
package/llms/stripe.md CHANGED
@@ -570,7 +570,7 @@ export function orders(doc, oldDoc, user, ctx) {
570
570
  import React, { useEffect, useRef, useState } from "react";
571
571
  import { useFireproof } from "use-fireproof";
572
572
  import { apiFetch, useVibe } from "use-vibes";
573
- import { Badge, Button, Heading, Row, Stack, Text } from "@vibes.diy/pouf";
573
+ import { Badge, Button, Heading, Row, Stack, Text } from "@vibes.diy/ui";
574
574
 
575
575
  // The setup verdict, read on mount and again whenever the app comes back into view: the owner
576
576
  // connects Stripe in another tab and returns, and the Pay buttons unlock without a reload.
@@ -1184,8 +1184,8 @@ export function checks(doc, oldDoc, user, ctx) {
1184
1184
  import React, { useEffect, useRef, useState } from "react";
1185
1185
  import { useFireproof } from "use-fireproof";
1186
1186
  import { apiFetch } from "use-vibes";
1187
- import { Badge, Button, Field, Figure, Heading, Input, Metric, Row, Segmented, Stack, Text } from "@vibes.diy/pouf";
1188
- import { Checkbox } from "@vibes.diy/pouf/interactive";
1187
+ import { Badge, Button, Field, Figure, Heading, Input, Metric, Row, Segmented, Stack, Text } from "@vibes.diy/ui";
1188
+ import { Checkbox } from "@vibes.diy/ui/interactive";
1189
1189
 
1190
1190
  const money = (cents) => `$${(cents / 100).toFixed(2)}`;
1191
1191
  const post = (body) => ({ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
package/llms/strudel.md CHANGED
@@ -207,7 +207,7 @@ with every write gated on `can`.
207
207
  import React, { useEffect, useMemo, useState } from "react";
208
208
  import { useFireproof } from "use-fireproof";
209
209
  import { callAI, useVibe, useViewer } from "use-vibes";
210
- import { Badge, Button, Card, Field, Heading, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/pouf";
210
+ import { Badge, Button, Card, Field, Heading, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
211
211
  import { EXAMPLES, onPatternError, play, stop } from "./lib/strudel.js";
212
212
  import { rewritePrompt } from "./lib/pattern-prompt.js";
213
213
 
@@ -446,8 +446,8 @@ A groovebox whose lights follow the music, built on the same module:
446
446
  import React, { useEffect, useRef, useState } from "react";
447
447
  import { useFireproof } from "use-fireproof";
448
448
  import { useVibe, useViewer } from "use-vibes";
449
- import { Badge, Button, Card, Field, Heading, Icon, IconButton, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/pouf";
450
- import { Slider } from "@vibes.diy/pouf/interactive";
449
+ import { Badge, Button, Card, Field, Heading, Icon, IconButton, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
450
+ import { Slider } from "@vibes.diy/ui/interactive";
451
451
  import { gridToCode, play, stop } from "./lib/strudel.js";
452
452
 
453
453
  const ROWS = ["bd", "sd", "hh", "cp"];
package/llms/three-js.md CHANGED
@@ -1258,7 +1258,7 @@ import React, { useState, useEffect, useRef, useCallback } from "react";
1258
1258
  import { useFireproof } from "use-fireproof";
1259
1259
  import * as THREE from "three";
1260
1260
  import { useWorldControls } from "use-vibes";
1261
- import { Card, Heading, IconButton, Stack, Text } from "@vibes.diy/pouf";
1261
+ import { Card, Heading, IconButton, Stack, Text } from "@vibes.diy/ui";
1262
1262
 
1263
1263
  export default function SkyGlider() {
1264
1264
  const { database, useLiveQuery } = useFireproof("skyGliderScores");
@@ -1705,8 +1705,8 @@ import { OrbitControls } from "three/addons/controls/OrbitControls.js";
1705
1705
  import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
1706
1706
  import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
1707
1707
  import { HalftonePass } from "three/addons/postprocessing/HalftonePass.js";
1708
- import { Button, Card, Field, Heading, Input, RowCard, Stack, Text } from "@vibes.diy/pouf";
1709
- import { Checkbox, Select, Separator, Slider } from "@vibes.diy/pouf/interactive";
1708
+ import { Button, Card, Field, Heading, Input, RowCard, Stack, Text } from "@vibes.diy/ui";
1709
+ import { Checkbox, Select, Separator, Slider } from "@vibes.diy/ui/interactive";
1710
1710
 
1711
1711
  export default function HalftoneArtStudio() {
1712
1712
  const { database, useLiveQuery } = useFireproof("halftoneStudio");
@@ -2061,7 +2061,7 @@ export default function HalftoneArtStudio() {
2061
2061
  <div className="relative h-dvh w-full overflow-hidden bg-background text-foreground font-sans">
2062
2062
  <canvas ref={canvasRef} className="absolute inset-0 select-none touch-none" />
2063
2063
 
2064
- {/* One control panel. The pouf `Card` IS the panel — it takes no className,
2064
+ {/* One control panel. The UI's `Card` IS the panel — it takes no className,
2065
2065
  so a plain wrapper carries its placement; the cushion, corner and ink are its own. */}
2066
2066
  <div className="absolute inset-y-4 left-4 w-80 overflow-y-auto">
2067
2067
  <Card>
@@ -2,7 +2,7 @@ export const touchGamesConfig = {
2
2
  name: "touch-games",
3
3
  label: "Touch games",
4
4
  description: "Phone-first controls for anything played or steered in real time — load it beside three-js, voxel, " +
5
- "physics, p5, worlds or pouf-game for every game, 3D scene you move through, or canvas toy: the play area " +
5
+ "physics, p5, worlds or ui-game for every game, 3D scene you move through, or canvas toy: the play area " +
6
6
  "is the controller (select-none touch-none surface, Pointer Events with pointer capture), swipes that fire " +
7
7
  "mid-move with chaining, tap vs swipe on one surface, a floating ghost stick under the thumb, hold-to-boost " +
8
8
  "with drag steering, pull-back-and-release aiming, gesture trails and feedback, keyboard twins for desktop, " +
@@ -1 +1 @@
1
- {"version":3,"file":"touch-games.js","sourceRoot":"","sources":["../../jsr/llms/touch-games.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAc;IACzC,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,aAAa;IACpB,WAAW,EACT,qGAAqG;QACrG,2GAA2G;QAC3G,4GAA4G;QAC5G,6GAA6G;QAC7G,6GAA6G;QAC7G,iHAAiH;QACjH,2DAA2D;QAC3D,uGAAuG;QACvG,mEAAmE;IAKrE,IAAI,EAAE;QACJ,OAAO;QACP,gBAAgB;QAChB,aAAa;QACb,YAAY;QACZ,YAAY;QACZ,aAAa;QACb,cAAc;QACd,aAAa;QACb,UAAU;QACV,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,OAAO;QACP,SAAS;QACT,YAAY;QACZ,gBAAgB;QAChB,SAAS;QACT,aAAa;QACb,aAAa;QACb,OAAO;QACP,SAAS;QACT,WAAW;QACX,SAAS;QACT,WAAW;QACX,UAAU;QACV,QAAQ;QACR,YAAY;QACZ,cAAc;QACd,cAAc;QACd,aAAa;QACb,SAAS;KACV;CACF,CAAC"}
1
+ {"version":3,"file":"touch-games.js","sourceRoot":"","sources":["../../jsr/llms/touch-games.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAc;IACzC,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,aAAa;IACpB,WAAW,EACT,qGAAqG;QACrG,yGAAyG;QACzG,4GAA4G;QAC5G,6GAA6G;QAC7G,6GAA6G;QAC7G,iHAAiH;QACjH,2DAA2D;QAC3D,uGAAuG;QACvG,mEAAmE;IAKrE,IAAI,EAAE;QACJ,OAAO;QACP,gBAAgB;QAChB,aAAa;QACb,YAAY;QACZ,YAAY;QACZ,aAAa;QACb,cAAc;QACd,aAAa;QACb,UAAU;QACV,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,OAAO;QACP,SAAS;QACT,YAAY;QACZ,gBAAgB;QAChB,SAAS;QACT,aAAa;QACb,aAAa;QACb,OAAO;QACP,SAAS;QACT,WAAW;QACX,SAAS;QACT,WAAW;QACX,UAAU;QACV,QAAQ;QACR,YAAY;QACZ,cAAc;QACd,cAAc;QACd,aAAa;QACb,SAAS;KACV;CACF,CAAC"}
@@ -1,7 +1,7 @@
1
1
  # Touch games — the play area is the controller
2
2
 
3
3
  Load this beside whatever draws the game — `three-js`, `voxel`, `physics`, `p5`, `worlds`,
4
- `pouf-game`, a plain `<canvas>` — whenever the app is something you play or steer in real time:
4
+ `ui-game`, a plain `<canvas>` — whenever the app is something you play or steer in real time:
5
5
  a runner, a racer, a flyer, a shooter, a snake, a launcher, a platformer, a pinball table, a
6
6
  marble maze, a 3D scene you move through, a toy you drag around. Most people open a vibe on a
7
7
  phone, one-handed. The game that feels great there is the one where the thumb rests **on the
@@ -208,7 +208,7 @@ orbits, a click is `onTap`, a right-click is `onHold`, and the wheel zooms.
208
208
  import React from "react";
209
209
  import * as THREE from "three";
210
210
  import { useWorldControls } from "use-vibes";
211
- import { Button, Card, Heading, IconButton, Stack, Text } from "@vibes.diy/pouf";
211
+ import { Button, Card, Heading, IconButton, Stack, Text } from "@vibes.diy/ui";
212
212
 
213
213
  const VIEWS = ["Free cam", "First person", "Shoulder view"];
214
214
  const HINT = {
@@ -407,7 +407,7 @@ snake by changing what `move()` does.
407
407
  ### `App.jsx`
408
408
  ```jsx
409
409
  import React from "react";
410
- import { Card, Heading, IconButton, Stack, Text } from "@vibes.diy/pouf";
410
+ import { Card, Heading, IconButton, Stack, Text } from "@vibes.diy/ui";
411
411
 
412
412
  const TUNE = {
413
413
  swipePx: 26, // travel from the anchor before a swipe fires (raise to 30–34 if a resting thumb misfires)
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiBlogConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiBlogConfig = {
2
+ name: "ui-blog",
3
+ aliases: ["pouf-blog"],
4
+ label: "Blog block",
5
+ description: "Blog with a featured post, category filter, pages and a writer",
6
+ };
7
+ //# sourceMappingURL=ui-blog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-blog.js","sourceRoot":"","sources":["../../jsr/llms/ui-blog.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,CAAC,WAAW,CAAC;IACtB,KAAK,EAAE,YAAY;IACnB,WAAW,EAAE,gEAAgE;CAC9E,CAAC"}
@@ -1,12 +1,12 @@
1
- # Pouf Blog
1
+ # Blog
2
2
 
3
3
  A blog with a front page and a reading view: a bakery's recipe notes, a travel journal, a club's match reports, a studio's news. Reach for it whenever the app's core is posts written by a few people and read by many, newest first, sorted into a handful of categories. Each post is its own document, so the blog is there on the next visit and on every device, and a new post appears for every reader as soon as it is published.
4
4
 
5
- Built from @vibes.diy/pouf components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
5
+ Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
6
6
 
7
7
  ## The block
8
8
 
9
- Two views, one job each. The front page opens with an `Eyebrow`, the `Heading` and a muted post count beside a `Write a post` button, the front page's one lead, which opens a `Dialog` with the writing form (title, category, body, each in its own `Field` with its own error). The newest post leads on a `Card` laid out with `Grid cols="sidebar"` beside a decorative `orange` `Blob`; under it a `Segmented` category filter (`tone="info"`) narrows a two-column `Grid` of post `Card`s, each with an `info` category `Badge`, the title, an excerpt in muted `Text`, the writer as a `ViewerTag` with a muted date, and a quiet `Read` button; `Pagination` pages through them and an `Empty` stands in when a category has nothing. Opening a post swaps in the reading view: a quiet `IconButton` back, the title as the `Heading`, the byline and the body as `Text` paragraphs, with a quiet `Delete post` (toned `down`) behind a `Confirm` wearing `tone="down"`, both showing `loading` while the delete lands. Every write waits on its `can` verdict from `useVibe("blog")`, the database the posts live in: the write button gives way to a `Skeleton` inside an `aria-busy` wrapper while the verdict resolves, to a quiet `Sign in to write` wired to `useViewer().requestLogin()` for a visitor who has not signed in, and to a sentence in the app's own words when writing is closed; `Delete post` renders only where `can.delete(post).ok`.
9
+ Two views, one job each. The front page opens with an `Eyebrow`, the `Heading` and a muted post count beside a `Write a post` button, the front page's one lead, which opens a `Dialog` with the writing form (title, category, body, each in its own `Field` with its own error). The newest post leads on a `Card` laid out with `Grid cols="sidebar"` beside a decorative `orange` `IconTile`; under it a `Segmented` category filter (`tone="info"`) narrows a two-column `Grid` of post `Card`s, each with an `info` category `Badge`, the title, an excerpt in muted `Text`, the writer as a `ViewerTag` with a muted date, and a quiet `Read` button; `Pagination` pages through them and an `Empty` stands in when a category has nothing. Opening a post swaps in the reading view: a quiet `IconButton` back, the title as the `Heading`, the byline and the body as `Text` paragraphs, with a quiet `Delete post` (toned `down`) behind a `Confirm` wearing `tone="down"`, both showing `loading` while the delete lands. Every write waits on its `can` verdict from `useVibe("blog")`, the database the posts live in: the write button gives way to a `Skeleton` inside an `aria-busy` wrapper while the verdict resolves, to a quiet `Sign in to write` wired to `useViewer().requestLogin()` for a visitor who has not signed in, and to a sentence in the app's own words when writing is closed; `Delete post` renders only where `can.delete(post).ok`.
10
10
 
11
11
  ### `App.jsx`
12
12
  ```jsx
@@ -15,7 +15,7 @@ import { useFireproof } from "use-fireproof";
15
15
  import { useViewer, useVibe } from "use-vibes";
16
16
  import {
17
17
  Badge,
18
- Blob,
18
+ IconTile,
19
19
  Button,
20
20
  Card,
21
21
  Empty,
@@ -33,8 +33,8 @@ import {
33
33
  Stack,
34
34
  Text,
35
35
  Textarea,
36
- } from "@vibes.diy/pouf";
37
- import { Confirm, Dialog, Select, Toaster, toast } from "@vibes.diy/pouf/interactive";
36
+ } from "@vibes.diy/ui";
37
+ import { Confirm, Dialog, Select, Toaster, toast } from "@vibes.diy/ui/interactive";
38
38
 
39
39
  const CATEGORIES = [
40
40
  { value: "recipes", label: "Recipes" },
@@ -164,7 +164,7 @@ export default function App() {
164
164
  </Row>
165
165
  )}
166
166
  </Stack>
167
- <div className="pouf-toasts">
167
+ <div className="ui-toasts">
168
168
  <Toaster />
169
169
  </div>
170
170
  </main>
@@ -246,7 +246,7 @@ export default function App() {
246
246
  </Button>
247
247
  </Row>
248
248
  </Stack>
249
- <Blob icon="sparkle" tone="orange" size="lg" />
249
+ <IconTile icon="sparkle" tone="orange" size="lg" />
250
250
  </Grid>
251
251
  </Card>
252
252
 
@@ -286,7 +286,7 @@ export default function App() {
286
286
  </>
287
287
  )}
288
288
  </Stack>
289
- <div className="pouf-toasts">
289
+ <div className="ui-toasts">
290
290
  <Toaster />
291
291
  </div>
292
292
  </main>
@@ -298,7 +298,7 @@ export default function App() {
298
298
 
299
299
  - Swap `CATEGORIES` for the blog's own sections; the filter and the form's `Select` both read from it, so a new section appears in both. Keep the category `Badge`s on one neutral tone (`info`): a category is a label, not a verdict.
300
300
  - Keep one document per post with its `authorHandle`; the byline is always a `ViewerTag`, never a typed name.
301
- - A cover photo is a `_files` attachment on the post, shown with `Figure` in place of the featured `Blob`; drafts that aren't ready yet are a `status` field filtered out of the front page (the editorial block walks posts through that pipeline).
301
+ - A cover photo is a `_files` attachment on the post, shown with `Figure` in place of the featured `IconTile`; drafts that aren't ready yet are a `status` field filtered out of the front page (the editorial block walks posts through that pipeline).
302
302
  - Editing a post is the same form, prefilled, writing behind `can.edit(post)`; keep `Delete post` quiet and behind its `Confirm`.
303
303
  - A new write surface gets its own verdict: `can.create(draft)` with the fields the write stamps, `can.edit(doc)` or `can.delete(doc)` on the document it changes, always on `useVibe` of the database it writes.
304
304
 
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiBookingConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiBookingConfig = {
2
+ name: "ui-booking",
3
+ aliases: ["pouf-booking"],
4
+ label: "Booking block",
5
+ description: "Appointment booking: pick a service, day and free slot, confirm",
6
+ };
7
+ //# sourceMappingURL=ui-booking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-booking.js","sourceRoot":"","sources":["../../jsr/llms/ui-booking.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,CAAC,cAAc,CAAC;IACzB,KAAK,EAAE,eAAe;IACtB,WAAW,EAAE,iEAAiE;CAC/E,CAAC"}
@@ -1,12 +1,12 @@
1
- # Pouf Booking
1
+ # Booking
2
2
 
3
3
  An appointment booker: pick a service, a day and a free time, add a name, review, confirm. It fits a massage practice's sessions, a tutor's lessons, a studio's portrait slots or a repair café's drop-in times. Reach for it whenever the app's core is people claiming time slots that only one person can hold. Every booking persists as its own document and availability is worked out from them, so a taken time disappears for everyone and the booker finds their sessions on every visit.
4
4
 
5
- Built from @vibes.diy/pouf components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
5
+ Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
6
6
 
7
7
  ## The block
8
8
 
9
- Two cards beside each other in a `Grid cols="sidebar"`. The main side opens with an `Eyebrow`, the `Heading` and a muted promise, then the person's own bookings on a `Card`. Each booking shows a `Badge`: `up` when confirmed, `warn` when someone else got the time first. Each one has a quiet `Cancel` behind a `Confirm` wearing `tone="down"`, offered only where `can.delete(booking).ok`. The side holds the wizard, one step at a time under an `Eyebrow` and a `Progress` bar (`tone="info"`): each service is a clickable `RowCard` with a decorative `orange` `Blob`; the day is a `Segmented` (`tone="info"`) and the time a `RadioGroup` of only the free times, with a muted line when a day is full; the details are a name `Input` in a `Field` with its own error (nothing private, because every booking is readable so free times can be worked out); and the review ends in `Confirm booking`, that step's one lead, which shows `loading` while the write lands. Each booking is its own document, never a flag on a shared calendar document. Two people can confirm the same time at once, and sync keeps both documents, so availability is derived: a slot belongs to its earliest booking (by `createdAt`, then `_id`). A later one is shown to its booker as a clash, with a `Pick another time` button that removes it and keeps their details. Confirming waits on its `can` verdict from `useVibe("bookings")`: a `Skeleton` inside an `aria-busy` wrapper while it resolves, and a sentence in the app's own words when booking is closed. For a visitor who has not signed in, the lead is `Sign in to confirm`, wired to `useViewer().requestLogin()`, and their choices stay in place. Sign-in is required here, unlike a local-first note, because a signed-out write stays on the device until sign-in: a booking made that way would never reach the practice or hold the slot against anyone else. Between the write and the live query catching up, the wizard shows a confirming `Skeleton` rather than the review again, so the lead can't book twice; cancelling the booking just made resets the wizard.
9
+ Two cards beside each other in a `Grid cols="sidebar"`. The main side opens with an `Eyebrow`, the `Heading` and a muted promise, then the person's own bookings on a `Card`. Each booking shows a `Badge`: `up` when confirmed, `warn` when someone else got the time first. Each one has a quiet `Cancel` behind a `Confirm` wearing `tone="down"`, offered only where `can.delete(booking).ok`. The side holds the wizard, one step at a time under an `Eyebrow` and a `Progress` bar (`tone="info"`): each service is a clickable `RowCard` with a decorative `orange` `IconTile`; the day is a `Segmented` (`tone="info"`) and the time a `RadioGroup` of only the free times, with a muted line when a day is full; the details are a name `Input` in a `Field` with its own error (nothing private, because every booking is readable so free times can be worked out); and the review ends in `Confirm booking`, that step's one lead, which shows `loading` while the write lands. Each booking is its own document, never a flag on a shared calendar document. Two people can confirm the same time at once, and sync keeps both documents, so availability is derived: a slot belongs to its earliest booking (by `createdAt`, then `_id`). A later one is shown to its booker as a clash, with a `Pick another time` button that removes it and keeps their details. Confirming waits on its `can` verdict from `useVibe("bookings")`: a `Skeleton` inside an `aria-busy` wrapper while it resolves, and a sentence in the app's own words when booking is closed. For a visitor who has not signed in, the lead is `Sign in to confirm`, wired to `useViewer().requestLogin()`, and their choices stay in place. Sign-in is required here, unlike a local-first note, because a signed-out write stays on the device until sign-in: a booking made that way would never reach the practice or hold the slot against anyone else. Between the write and the live query catching up, the wizard shows a confirming `Skeleton` rather than the review again, so the lead can't book twice; cancelling the booking just made resets the wizard.
10
10
 
11
11
  ### `App.jsx`
12
12
  ```jsx
@@ -15,7 +15,7 @@ import { useFireproof } from "use-fireproof";
15
15
  import { useViewer, useVibe } from "use-vibes";
16
16
  import {
17
17
  Badge,
18
- Blob,
18
+ IconTile,
19
19
  Button,
20
20
  Card,
21
21
  Empty,
@@ -31,8 +31,8 @@ import {
31
31
  Spacer,
32
32
  Stack,
33
33
  Text,
34
- } from "@vibes.diy/pouf";
35
- import { Confirm, Progress, RadioGroup, Toaster, toast } from "@vibes.diy/pouf/interactive";
34
+ } from "@vibes.diy/ui";
35
+ import { Confirm, Progress, RadioGroup, Toaster, toast } from "@vibes.diy/ui/interactive";
36
36
 
37
37
  const SERVICES = [
38
38
  { id: "relax", name: "Relaxation massage", blurb: "A slow, full-body session to unwind.", minutes: 60, price: 80, icon: "sparkle" },
@@ -227,7 +227,7 @@ export default function App() {
227
227
  }}
228
228
  >
229
229
  <Row gap={3} wrap={false} align="top">
230
- <Blob icon={s.icon} tone="orange" size="sm" />
230
+ <IconTile icon={s.icon} tone="orange" size="sm" />
231
231
  <Stack gap={1}>
232
232
  <Text>{s.name}</Text>
233
233
  <Text size="sm" muted>
@@ -378,7 +378,7 @@ export default function App() {
378
378
  </Stack>
379
379
  <Card>{wizard}</Card>
380
380
  </Grid>
381
- <div className="pouf-toasts">
381
+ <div className="ui-toasts">
382
382
  <Toaster />
383
383
  </div>
384
384
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiCalendarConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiCalendarConfig = {
2
+ name: "ui-calendar",
3
+ aliases: ["pouf-calendar"],
4
+ label: "Calendar block",
5
+ description: "Calendar agenda/month view UI: month grid, day timeline, saved events",
6
+ };
7
+ //# sourceMappingURL=ui-calendar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-calendar.js","sourceRoot":"","sources":["../../jsr/llms/ui-calendar.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,gBAAgB,GAAc;IACzC,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,CAAC,eAAe,CAAC;IAC1B,KAAK,EAAE,gBAAgB;IACvB,WAAW,EAAE,uEAAuE;CACrF,CAAC"}
@@ -1,8 +1,8 @@
1
- # Pouf Calendar
1
+ # Calendar
2
2
 
3
3
  An on-screen calendar of timed events: a studio's class timetable, a family's appointments, a club's practice schedule, a shared room's bookings for the week. Reach for it when the app shows a month at a glance and one day's agenda in time order, with the free gaps between events and a line where "now" falls, and lets people add and remove events. This is the calendar people look at inside the app; a subscribable phone-calendar feed (webcal or `.ics`) is a different job, served from the backend. Each event is its own document, so everyone who opens the app sees the same schedule.
4
4
 
5
- Built from @vibes.diy/pouf components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
5
+ Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
6
6
 
7
7
  ## The block
8
8
 
@@ -13,8 +13,8 @@ One view with one job: see what is on and add to it. The `Heading` and a muted l
13
13
  import React, { useEffect, useState } from "react";
14
14
  import { useFireproof } from "use-fireproof";
15
15
  import { useViewer, useVibe } from "use-vibes";
16
- import { Badge, Button, Card, Empty, Field, Grid, Heading, Icon, IconButton, Input, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/pouf";
17
- import { Confirm, Dialog, Select, Toaster, toast } from "@vibes.diy/pouf/interactive";
16
+ import { Badge, Button, Card, Empty, Field, Grid, Heading, Icon, IconButton, Input, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/ui";
17
+ import { Confirm, Dialog, Select, Toaster, toast } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const pad = (n) => String(n).padStart(2, "0");
20
20
  // Dates are kept as local YYYY-MM-DD strings, so an event never drifts a day across time zones.
@@ -332,7 +332,7 @@ export default function App() {
332
332
  </Stack>
333
333
  </Card>
334
334
  </Stack>
335
- <div className="pouf-toasts">
335
+ <div className="ui-toasts">
336
336
  <Toaster />
337
337
  </div>
338
338
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiChatConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiChatConfig = {
2
+ name: "ui-chat",
3
+ aliases: ["pouf-chat"],
4
+ label: "Chat block",
5
+ description: "Group chat with rooms, live message threads and a composer",
6
+ };
7
+ //# sourceMappingURL=ui-chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-chat.js","sourceRoot":"","sources":["../../jsr/llms/ui-chat.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,CAAC,WAAW,CAAC;IACtB,KAAK,EAAE,YAAY;IACnB,WAAW,EAAE,4DAA4D;CAC1E,CAAC"}