@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
@@ -1,8 +1,8 @@
1
- # Pouf Kanban
1
+ # Kanban
2
2
 
3
3
  A board of cards in columns that move left to right as work gets done: a renovation's to do, doing and done, a sprint board, a hiring pipeline, a content calendar from idea to published. Reach for it whenever the app's core is items that pass through a fixed set of stages and the person wants to see every stage at once. Cards and the column each sits in persist, so the board looks the same on the next visit and for everyone who opens it.
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: the board. The `Heading` and a muted count open the page,
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, DropdownMenu, 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, DropdownMenu, Toaster, toast } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const COLUMNS = [
20
20
  { key: "todo", title: "To do", tone: "idle" },
@@ -217,7 +217,7 @@ export default function App() {
217
217
  })}
218
218
  </Grid>
219
219
  </Stack>
220
- <div className="pouf-toasts">
220
+ <div className="ui-toasts">
221
221
  <Toaster />
222
222
  </div>
223
223
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiLandingConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiLandingConfig = {
2
+ name: "ui-landing",
3
+ aliases: ["pouf-landing"],
4
+ label: "Landing block",
5
+ description: "Marketing landing page with hero, features, story and a waitlist sign-up",
6
+ };
7
+ //# sourceMappingURL=ui-landing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-landing.js","sourceRoot":"","sources":["../../jsr/llms/ui-landing.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,CAAC,cAAc,CAAC;IACzB,KAAK,EAAE,eAAe;IACtB,WAAW,EAAE,0EAA0E;CACxF,CAAC"}
@@ -1,19 +1,19 @@
1
- # Pouf Landing
1
+ # Landing
2
2
 
3
3
  A one-page marketing site with a waitlist: the launch page for a pottery class, a neighbourhood tool library, a new podcast, a supper club, a side-project app before it opens. Reach for it when the app's job is to explain one thing well (a hero, what it does, a story from someone who tried it) and to let interested people put their name down. Each person on the waitlist is one small document, so the count on the page is real and nobody signs up twice.
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
- One page with one job: get the reader onto the waitlist. A `Navbar` carries the brand (a decorative `orange` `Blob` and the name), in-page links and a quiet `Join` that scrolls to the sign-up. The hero is a `Grid cols="sidebar"`: an `info` `Badge`, the `Heading level={1}` with one word in an `orange` `Highlight`, a muted pitch, the waitlist action and a muted count of who has joined; beside it a `Card` of `Metric`s says what the reader gets. The waitlist action is the page's one lead: `Join the waitlist`, with `loading` from the click until the live query shows the new sign-up, so the button can't reappear and fire twice in between. Once joined it turns into an `up` `Badge` and a quiet `Leave the list`. Three feature `Card`s (each fronted by a decorative `orange` `Blob`, tilted with `motion`) explain how it works, a `Card` holds one story from an early user, and a closing `CTA` on the quiet `surface` tone sends the reader back up to the sign-up with a quiet button, so the page never shows two leads. A `Footer` repeats the in-page links. Joining waits on its `can` verdict from `useVibe("waitlist")`, the database the sign-ups live in: a `Skeleton` inside an `aria-busy` wrapper while it resolves, a `Sign in to join the waitlist` lead wired to `useViewer().requestLogin()` for a visitor who has not signed in, and a neutral sentence in the app's own words when sign-ups are closed. `Leave the list` renders only where `can.delete` allows it. The list keeps who joined and when, never an email address.
9
+ One page with one job: get the reader onto the waitlist. A `Navbar` carries the brand (a decorative `orange` `IconTile` and the name), in-page links and a quiet `Join` that scrolls to the sign-up. The hero is a `Grid cols="sidebar"`: an `info` `Badge`, the `Heading level={1}` with one word in an `orange` `Highlight`, a muted pitch, the waitlist action and a muted count of who has joined; beside it a `Card` of `Metric`s says what the reader gets. The waitlist action is the page's one lead: `Join the waitlist`, with `loading` from the click until the live query shows the new sign-up, so the button can't reappear and fire twice in between. Once joined it turns into an `up` `Badge` and a quiet `Leave the list`. Three feature `Card`s (each fronted by a decorative `orange` `IconTile`, tilted with `motion`) explain how it works, a `Card` holds one story from an early user, and a closing `CTA` on the quiet `surface` tone sends the reader back up to the sign-up with a quiet button, so the page never shows two leads. A `Footer` repeats the in-page links. Joining waits on its `can` verdict from `useVibe("waitlist")`, the database the sign-ups live in: a `Skeleton` inside an `aria-busy` wrapper while it resolves, a `Sign in to join the waitlist` lead wired to `useViewer().requestLogin()` for a visitor who has not signed in, and a neutral sentence in the app's own words when sign-ups are closed. `Leave the list` renders only where `can.delete` allows it. The list keeps who joined and when, never an email address.
10
10
 
11
11
  ### `App.jsx`
12
12
  ```jsx
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, Blob, Button, Card, CTA, Eyebrow, Footer, Grid, Heading, Highlight, Metric, Navbar, Row, Skeleton, Stack, Text } from "@vibes.diy/pouf";
16
+ import { Badge, IconTile, Button, Card, CTA, Eyebrow, Footer, Grid, Heading, Highlight, Metric, Navbar, Row, Skeleton, Stack, Text } from "@vibes.diy/ui";
17
17
 
18
18
  const NAME = "The Tool Shed";
19
19
  const STEPS = [
@@ -28,7 +28,7 @@ const LINKS = [
28
28
 
29
29
  const brand = (
30
30
  <Row gap={2} wrap={false}>
31
- <Blob icon="home" tone="orange" size="sm" />
31
+ <IconTile icon="home" tone="orange" size="sm" />
32
32
  <Text>{NAME}</Text>
33
33
  </Row>
34
34
  );
@@ -165,7 +165,7 @@ export default function App() {
165
165
  {STEPS.map((s, i) => (
166
166
  <Card key={s.title} motion={i % 2 === 0 ? "tilt-left" : "tilt-right"}>
167
167
  <Stack gap={3}>
168
- <Blob icon={s.icon} tone="orange" />
168
+ <IconTile icon={s.icon} tone="orange" />
169
169
  <Heading level={3}>{s.title}</Heading>
170
170
  <Text size="sm" muted>
171
171
  {s.body}
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiLoginConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiLoginConfig = {
2
+ name: "ui-login",
3
+ aliases: ["pouf-login"],
4
+ label: "Login block",
5
+ description: "App-local join form for display name and bio; not sign-in auth",
6
+ };
7
+ //# sourceMappingURL=ui-login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-login.js","sourceRoot":"","sources":["../../jsr/llms/ui-login.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,CAAC,YAAY,CAAC;IACvB,KAAK,EAAE,aAAa;IACpB,WAAW,EAAE,gEAAgE;CAC9E,CAAC"}
@@ -1,20 +1,20 @@
1
- # Pouf Login
1
+ # Login
2
2
 
3
3
  The join step a member sees once they are signed in: a quilting circle's "tell us who you are", a writing group's member card, a team space's first-visit profile. Reach for it whenever the app wants its own profile for each person (the name they go by here, a short bio) before they take part. It is **not** a sign-in form: the platform owns sign-in, so this block never asks for an email, a password or a magic link. The visitor signs in through `useViewer().requestLogin()`, and only then fills in the profile the app keeps. Each profile persists, so a member joins once and finds their card on every visit and device.
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
- One centred `Card` with one job: get this person a profile. A `Blob` (`info`, user), the `Heading` and a muted line open it, and a muted count says how many members have joined. A visitor who has not signed in gets a `Sign in to join` button, the card's one lead, wired to `requestLogin()`; there is no email or password field anywhere, because sign-in is the platform's. A signed-in visitor gets the profile form: a display name `Input` and a short-bio `Textarea`, each in its own `Field` with its own error and `invalid` control, validated in plain state on submit; `Join the club` (or `Save profile` once they have one) is the lead and shows `loading` while the write lands. Each profile is one document with a deterministic `_id` per person (`profile:<handle>`), so saving twice updates the same card instead of adding a second. The write waits on its `can` verdict from `useVibe("members")`: `can.create` of the draft for a new profile, `can.edit` of the saved one after that; while the verdict resolves a `Skeleton` sits inside an `aria-busy` wrapper, and a sentence in the app's own words replaces the form when joining is closed to this visitor. A saved profile shows as a `Badge` toned `up` and a `toast`.
9
+ One centred `Card` with one job: get this person a profile. An `IconTile` (`info`, user), the `Heading` and a muted line open it, and a muted count says how many members have joined. A visitor who has not signed in gets a `Sign in to join` button, the card's one lead, wired to `requestLogin()`; there is no email or password field anywhere, because sign-in is the platform's. A signed-in visitor gets the profile form: a display name `Input` and a short-bio `Textarea`, each in its own `Field` with its own error and `invalid` control, validated in plain state on submit; `Join the club` (or `Save profile` once they have one) is the lead and shows `loading` while the write lands. Each profile is one document with a deterministic `_id` per person (`profile:<handle>`), so saving twice updates the same card instead of adding a second. The write waits on its `can` verdict from `useVibe("members")`: `can.create` of the draft for a new profile, `can.edit` of the saved one after that; while the verdict resolves a `Skeleton` sits inside an `aria-busy` wrapper, and a sentence in the app's own words replaces the form when joining is closed to this visitor. A saved profile shows as a `Badge` toned `up` and a `toast`.
10
10
 
11
11
  ### `App.jsx`
12
12
  ```jsx
13
13
  import React, { useState } from "react";
14
14
  import { useFireproof } from "use-fireproof";
15
15
  import { useViewer, useVibe } from "use-vibes";
16
- import { Badge, Blob, Button, Card, Field, Heading, Input, Row, Skeleton, Stack, Text, Textarea } from "@vibes.diy/pouf";
17
- import { Toaster, toast } from "@vibes.diy/pouf/interactive";
16
+ import { Badge, IconTile, Button, Card, Field, Heading, Input, Row, Skeleton, Stack, Text, Textarea } from "@vibes.diy/ui";
17
+ import { Toaster, toast } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const BIO_MAX = 160;
20
20
 
@@ -116,7 +116,7 @@ export default function App() {
116
116
  <Card>
117
117
  <Stack gap={5}>
118
118
  <Stack gap={3}>
119
- <Blob icon="user" tone="info" />
119
+ <IconTile icon="user" tone="info" />
120
120
  <Stack gap={1}>
121
121
  <Heading level={1}>{saved ? `Hi, ${saved.name}` : "Join the club"}</Heading>
122
122
  <Text muted>{saved ? "Update how other members see you." : "Pick the name you go by here and say hello."}</Text>
@@ -143,7 +143,7 @@ export default function App() {
143
143
  )}
144
144
  </Stack>
145
145
  </Card>
146
- <div className="pouf-toasts">
146
+ <div className="ui-toasts">
147
147
  <Toaster />
148
148
  </div>
149
149
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiMusicConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiMusicConfig = {
2
+ name: "ui-music",
3
+ aliases: ["pouf-music"],
4
+ label: "Music block",
5
+ description: "Music player UI with a queue, transport and saved likes",
6
+ };
7
+ //# sourceMappingURL=ui-music.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-music.js","sourceRoot":"","sources":["../../jsr/llms/ui-music.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,CAAC,YAAY,CAAC;IACvB,KAAK,EAAE,aAAa;IACpB,WAAW,EAAE,yDAAyD;CACvE,CAAC"}
@@ -1,20 +1,20 @@
1
- # Pouf Music
1
+ # Music
2
2
 
3
3
  A player screen for a short list of tracks: a band's demos, a choir's rehearsal parts, a podcast's episodes, a class's listening list. Reach for it whenever the app's core is picking something from a queue and moving through it with play, skip and a scrubber. The track list stays inline in the code and playback lives in the page; each like is its own document per person and track, so a visitor's favourites are still marked on the next visit and on every device, and the like count is real.
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
- One view with one job: choose a track and move through it. A `Card` holds the player: a decorative `orange` `Blob` as the cover, a `Badge` for the transport's state (`up` playing, `idle` paused), the title as the `Heading` with the artist and like count in muted `Text`, a quiet heart `IconButton` to like the track, a `Slider` scrubber with numeric elapsed and total times, and the transport row of quiet `IconButton`s (previous, play/pause, next). The scrubber's filled range is the view's one lead mark: `Slider` always paints its range in the lead colour and takes no `tone`, so every button beside it stays quiet. Nothing plays until the person presses play, and the example carries no audio of its own: the track list is placeholder metadata and the scrubber is driven by a timer, ready to be wired to the app's own files. Under the player an `Eyebrow` heads the queue, one clickable `RowCard` per track with its title and artist in `Text`, a heart `Icon` on the visitor's liked tracks and the length in numeric muted `Text`. Liking waits on its `can` verdict from `useVibe("music")`, the database the likes live in: a `Skeleton` inside an `aria-busy` wrapper while it resolves, the heart wired to `useViewer().requestLogin()` with the label `Sign in to like` for a visitor who has not signed in, and a sentence in the app's own words when likes are closed; unliking waits on `can.delete` of the visitor's own like.
9
+ One view with one job: choose a track and move through it. A `Card` holds the player: a decorative `orange` `IconTile` as the cover, a `Badge` for the transport's state (`up` playing, `idle` paused), the title as the `Heading` with the artist and like count in muted `Text`, a quiet heart `IconButton` to like the track, a `Slider` scrubber with numeric elapsed and total times, and the transport row of quiet `IconButton`s (previous, play/pause, next). The scrubber's filled range is the view's one lead mark: `Slider` always paints its range in the lead colour and takes no `tone`, so every button beside it stays quiet. Nothing plays until the person presses play, and the example carries no audio of its own: the track list is placeholder metadata and the scrubber is driven by a timer, ready to be wired to the app's own files. Under the player an `Eyebrow` heads the queue, one clickable `RowCard` per track with its title and artist in `Text`, a heart `Icon` on the visitor's liked tracks and the length in numeric muted `Text`. Liking waits on its `can` verdict from `useVibe("music")`, the database the likes live in: a `Skeleton` inside an `aria-busy` wrapper while it resolves, the heart wired to `useViewer().requestLogin()` with the label `Sign in to like` for a visitor who has not signed in, and a sentence in the app's own words when likes are closed; unliking waits on `can.delete` of the visitor's own like.
10
10
 
11
11
  ### `App.jsx`
12
12
  ```jsx
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, Blob, Card, Eyebrow, Heading, Icon, IconButton, Row, RowCard, Skeleton, Spacer, Stack, Text } from "@vibes.diy/pouf";
17
- import { Slider } from "@vibes.diy/pouf/interactive";
16
+ import { Badge, IconTile, Card, Eyebrow, Heading, Icon, IconButton, Row, RowCard, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
17
+ import { Slider } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  // Placeholder metadata: swap in the app's own tracks. No audio ships with this example.
20
20
  const QUEUE = [
@@ -110,7 +110,7 @@ export default function App() {
110
110
  <Card>
111
111
  <Stack gap={5}>
112
112
  <Row justify="between" align="top">
113
- <Blob icon="music" tone="orange" size="lg" />
113
+ <IconTile icon="music" tone="orange" size="lg" />
114
114
  <Badge tone={playing ? "up" : "idle"}>{playing ? "Playing" : "Paused"}</Badge>
115
115
  </Row>
116
116
  <Row justify="between" align="top" wrap={false}>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiOnboardingConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiOnboardingConfig = {
2
+ name: "ui-onboarding",
3
+ aliases: ["pouf-onboarding"],
4
+ label: "Onboarding block",
5
+ description: "Step-by-step setup wizard with progress; answers saved on finish",
6
+ };
7
+ //# sourceMappingURL=ui-onboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-onboarding.js","sourceRoot":"","sources":["../../jsr/llms/ui-onboarding.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,kBAAkB,GAAc;IAC3C,IAAI,EAAE,eAAe;IACrB,OAAO,EAAE,CAAC,iBAAiB,CAAC;IAC5B,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,kEAAkE;CAChF,CAAC"}
@@ -1,8 +1,8 @@
1
- # Pouf Onboarding
1
+ # Onboarding
2
2
 
3
3
  A short setup wizard that walks a newcomer through a few questions, one at a time: a study group's "who are you and which team", a freelance tool's business name and plan, a club's first-visit questions. Reach for it whenever the app needs a handful of answers before it is useful and they read better as steps than as one long form. The answers persist as the person's own document, so a finished setup stays finished and can be revisited and changed later.
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 `Card` with one job per step. An `Eyebrow` names the step ("Step 2 of 3 · W
13
13
  import React, { useState } from "react";
14
14
  import { useFireproof } from "use-fireproof";
15
15
  import { useViewer, useVibe } from "use-vibes";
16
- import { Button, Card, Eyebrow, Field, Heading, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/pouf";
17
- import { Progress, RadioGroup, Toaster, toast } from "@vibes.diy/pouf/interactive";
16
+ import { Button, Card, Eyebrow, Field, Heading, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
17
+ import { Progress, RadioGroup, Toaster, toast } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const STEPS = ["About you", "Workspace", "How you'll use it"];
20
20
  const PLANS = [
@@ -208,7 +208,7 @@ export default function App() {
208
208
  </form>
209
209
  )}
210
210
  </Card>
211
- <div className="pouf-toasts">
211
+ <div className="ui-toasts">
212
212
  <Toaster />
213
213
  </div>
214
214
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiPricingConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiPricingConfig = {
2
+ name: "ui-pricing",
3
+ aliases: ["pouf-pricing"],
4
+ label: "Pricing block",
5
+ description: "Pricing plans with a billing-cycle toggle; records plan requests, no payment",
6
+ };
7
+ //# sourceMappingURL=ui-pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-pricing.js","sourceRoot":"","sources":["../../jsr/llms/ui-pricing.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,8EAA8E;CAC5F,CAAC"}
@@ -1,8 +1,8 @@
1
- # Pouf Pricing
1
+ # Pricing
2
2
 
3
3
  A plans page that compares a few tiers and lets someone ask for one: a yoga studio's memberships, a tutor's packages, a club's season passes, a freelancer's retainers. Reach for it whenever the app's core is "here is what each option costs, pick one". The plans themselves stay inline in the code. Picking a paid plan saves a request document, so the person sees what they asked for on the next visit and the app keeps a record of who asked for what; the owner's view of those requests is a short addition sketched under Adapting. It takes no payment and pretends to take none: settling up is arranged after the request, or by a separate payment integration.
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: compare and choose. An `Eyebrow` and a `Heading` with one
13
13
  import React, { useState } from "react";
14
14
  import { useFireproof } from "use-fireproof";
15
15
  import { useViewer, useVibe } from "use-vibes";
16
- import { Badge, Button, Card, Eyebrow, Grid, Heading, Highlight, Icon, Row, Segmented, Skeleton, Stack, Text } from "@vibes.diy/pouf";
17
- import { Toaster, toast } from "@vibes.diy/pouf/interactive";
16
+ import { Badge, Button, Card, Eyebrow, Grid, Heading, Highlight, Icon, Row, Segmented, Skeleton, Stack, Text } from "@vibes.diy/ui";
17
+ import { Toaster, toast } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const PLANS = [
20
20
  { id: "taster", name: "Taster", monthly: 0, blurb: "Try a class before you choose.", features: ["Your first class free", "Mat hire included"] },
@@ -174,7 +174,7 @@ export default function App() {
174
174
  No card needed here. Choosing a plan sends us a request, and we arrange payment with you before it starts.
175
175
  </Text>
176
176
  </Stack>
177
- <div className="pouf-toasts">
177
+ <div className="ui-toasts">
178
178
  <Toaster />
179
179
  </div>
180
180
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiProfileConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiProfileConfig = {
2
+ name: "ui-profile",
3
+ aliases: ["pouf-profile"],
4
+ label: "Profile block",
5
+ description: "Public profile page with stats, tabs and a saved follow button",
6
+ };
7
+ //# sourceMappingURL=ui-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-profile.js","sourceRoot":"","sources":["../../jsr/llms/ui-profile.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,gEAAgE;CAC9E,CAAC"}
@@ -1,8 +1,8 @@
1
- # Pouf Profile
1
+ # Profile
2
2
 
3
3
  A public page about one maker, coach or group that visitors can follow: an illustrator's page, a running coach's profile, a band's home, a club captain's corner. Reach for it whenever the app's core is "who is this, what have they made, and how do I keep up". The profile's own words and posts stay inline in the code; each follow is its own document, so the follower count is real, it survives the next visit, and two people following at once both count.
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: get to know the person, then follow. A `Card` holds the h
13
13
  import React, { useState } from "react";
14
14
  import { useFireproof } from "use-fireproof";
15
15
  import { useViewer, useVibe } from "use-vibes";
16
- import { Badge, Button, Card, Empty, Eyebrow, Heading, Metric, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/pouf";
17
- import { Avatar, Tabs } from "@vibes.diy/pouf/interactive";
16
+ import { Badge, Button, Card, Empty, Eyebrow, Heading, Metric, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/ui";
17
+ import { Avatar, Tabs } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const PROFILE = {
20
20
  name: "Mira Okafor",
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiQuizConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiQuizConfig = {
2
+ name: "ui-quiz",
3
+ aliases: ["pouf-quiz"],
4
+ label: "Quiz block",
5
+ description: "Multiple-choice quiz with instant feedback, a scored result and saved attempts",
6
+ };
7
+ //# sourceMappingURL=ui-quiz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-quiz.js","sourceRoot":"","sources":["../../jsr/llms/ui-quiz.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,CAAC,WAAW,CAAC;IACtB,KAAK,EAAE,YAAY;IACnB,WAAW,EAAE,gFAAgF;CAC9F,CAAC"}
@@ -1,20 +1,20 @@
1
- # Pouf Quiz
1
+ # Quiz
2
2
 
3
3
  A short multiple-choice quiz that keeps score: an astronomy club's star-chart check, a refresher round before a test, a pub quiz warm-up, a training check for new staff. Reach for it when the app asks a handful of questions one at a time, says right or wrong after each answer, ends on a score and lets people come back to beat it. Each finished attempt someone saves is its own document, so their past scores are there on the next visit and on any device.
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
- One view with one job: answer the questions, then keep the score. A `Heading` and a muted line open the page. The quiz sits on a `Card`: an `Eyebrow` with the question number beside an `info` `Badge` counting correct answers so far (it steps aside on the result, which states the score once), and a `Progress` (`info`) across the top. Each question is a `Heading level={2}` over a `RadioGroup`; `Check answer` is the view's one lead, then the answer shows as a `Badge` (`up` right, `down` wrong) with the right option in muted `Text`, and the lead becomes `Next question`. The result swaps in a `Blob` (`up` for a pass, `warn` otherwise), the score and a recap of every question with its own `up` or `down` `Badge`. `Save score` is then the lead, with `loading` while the write lands, beside a quiet `Play again`. A signed-in person's earlier attempts sit below as `RowCard`s, newest first, each with a `Badge` toned by how it went. Saving waits on its `can` verdict from `useVibe("quiz")`, the database the attempts live in: a `Skeleton` inside an `aria-busy` wrapper while it resolves, a `Sign in to save your score` lead wired to `useViewer().requestLogin()` for a visitor who has not signed in, and a sentence in the app's own words when saving is closed. Anyone can take the quiz without signing in; the attempt lives only in the page until it is saved, and the copy says so.
9
+ One view with one job: answer the questions, then keep the score. A `Heading` and a muted line open the page. The quiz sits on a `Card`: an `Eyebrow` with the question number beside an `info` `Badge` counting correct answers so far (it steps aside on the result, which states the score once), and a `Progress` (`info`) across the top. Each question is a `Heading level={2}` over a `RadioGroup`; `Check answer` is the view's one lead, then the answer shows as a `Badge` (`up` right, `down` wrong) with the right option in muted `Text`, and the lead becomes `Next question`. The result swaps in an `IconTile` (`up` for a pass, `warn` otherwise), the score and a recap of every question with its own `up` or `down` `Badge`. `Save score` is then the lead, with `loading` while the write lands, beside a quiet `Play again`. A signed-in person's earlier attempts sit below as `RowCard`s, newest first, each with a `Badge` toned by how it went. Saving waits on its `can` verdict from `useVibe("quiz")`, the database the attempts live in: a `Skeleton` inside an `aria-busy` wrapper while it resolves, a `Sign in to save your score` lead wired to `useViewer().requestLogin()` for a visitor who has not signed in, and a sentence in the app's own words when saving is closed. Anyone can take the quiz without signing in; the attempt lives only in the page until it is saved, and the copy says so.
10
10
 
11
11
  ### `App.jsx`
12
12
  ```jsx
13
13
  import React, { useState } from "react";
14
14
  import { useFireproof } from "use-fireproof";
15
15
  import { useViewer, useVibe } from "use-vibes";
16
- import { Badge, Blob, Button, Card, Eyebrow, Heading, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/pouf";
17
- import { Progress, RadioGroup } from "@vibes.diy/pouf/interactive";
16
+ import { Badge, IconTile, Button, Card, Eyebrow, Heading, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/ui";
17
+ import { Progress, RadioGroup } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const QUIZ_ID = "houseplants";
20
20
  const QUESTIONS = [
@@ -177,7 +177,7 @@ export default function App() {
177
177
  {done ? (
178
178
  <Stack gap={4}>
179
179
  <Row gap={3} wrap={false}>
180
- <Blob icon={passed ? "trophy" : "flame"} tone={passed ? "up" : "warn"} />
180
+ <IconTile icon={passed ? "trophy" : "flame"} tone={passed ? "up" : "warn"} />
181
181
  <Stack gap={1}>
182
182
  <Heading level={2}>{score === TOTAL ? "Perfect score!" : passed ? "Nice work" : "Keep practising"}</Heading>
183
183
  <Text muted>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiSettingsConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiSettingsConfig = {
2
+ name: "ui-settings",
3
+ aliases: ["pouf-settings"],
4
+ label: "Settings block",
5
+ description: "Per-person settings with tabs, switches and a save bar",
6
+ };
7
+ //# sourceMappingURL=ui-settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-settings.js","sourceRoot":"","sources":["../../jsr/llms/ui-settings.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,gBAAgB,GAAc;IACzC,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,CAAC,eAAe,CAAC;IAC1B,KAAK,EAAE,gBAAgB;IACvB,WAAW,EAAE,wDAAwD;CACtE,CAAC"}
@@ -1,8 +1,8 @@
1
- # Pouf Settings
1
+ # Settings
2
2
 
3
3
  A settings screen for each person's own preferences: the display name in a sleep log, reminder emails for a reading log, a compact or comfortable layout, how loud an alert should be. Reach for it whenever the app lets someone tune how it treats them and expects those choices to stick. Each person's settings persist as their own document, so a choice made on the phone is there on the laptop.
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: change your settings and save them. An `Eyebrow`, the `He
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, Eyebrow, Field, Heading, Input, Row, Skeleton, Stack, Text, Textarea } from "@vibes.diy/pouf";
17
- import { RadioGroup, Separator, Slider, Switch, Tabs, Toaster, toast } from "@vibes.diy/pouf/interactive";
16
+ import { Badge, Button, Card, Eyebrow, Field, Heading, Input, Row, Skeleton, Stack, Text, Textarea } from "@vibes.diy/ui";
17
+ import { RadioGroup, Separator, Slider, Switch, Tabs, Toaster, toast } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const DEFAULTS = { name: "", bio: "", density: "comfortable", emailNotif: true, pushNotif: false, volume: 60 };
20
20
  const KEYS = Object.keys(DEFAULTS);
@@ -201,7 +201,7 @@ export default function App() {
201
201
  // Re-keyed when the saved copy first arrives, so the form starts from it.
202
202
  <SettingsForm key={saved ? "saved" : "new"} saved={saved} database={database} can={can} me={me} />
203
203
  )}
204
- <div className="pouf-toasts">
204
+ <div className="ui-toasts">
205
205
  <Toaster />
206
206
  </div>
207
207
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiStorefrontConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiStorefrontConfig = {
2
+ name: "ui-storefront",
3
+ aliases: ["pouf-storefront"],
4
+ label: "Storefront block",
5
+ description: "Product grid with filters, a shopping bag and checkout, no payments",
6
+ };
7
+ //# sourceMappingURL=ui-storefront.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-storefront.js","sourceRoot":"","sources":["../../jsr/llms/ui-storefront.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,kBAAkB,GAAc;IAC3C,IAAI,EAAE,eAAe;IACrB,OAAO,EAAE,CAAC,iBAAiB,CAAC;IAC5B,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,qEAAqE;CACnF,CAAC"}
@@ -1,12 +1,12 @@
1
- # Pouf Storefront
1
+ # Storefront
2
2
 
3
3
  A small shop: product cards to browse, a category filter and a search, a bag that adds things up, and a checkout that places the order. It fits a potter's ceramics, a bakery's preorders, a club's merch table or a school fair's stall. Reach for it whenever the app's core is a short catalogue that people pick from and then order. The catalogue stays inline in the code, and the bag lives in the page while someone shops. Each placed order persists as its own document, so the shop can see what to make and the buyer can see what they ordered. It records orders only; taking payment is a separate integration this block does not pretend to do.
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
- One view with one job: fill the bag and place the order. A `Navbar` carries the brand and a quiet bag button with a live count, and the `Heading` puts an `orange` `Highlight` on one word beside a muted line. A `Segmented` category filter (`tone="info"`) and a search `Input` in a `Field` sit above a `Grid cols="sidebar"`: on the main side a two-column grid of product `Card`s, each with a decorative `orange` `Blob`, an `info` `Badge` for "New" or "Bestseller", the price in numeric `Text` and a quiet `Add to bag` (an `Empty` stands in when nothing matches); on the side the bag's `Card`, one line per product with its total and `IconButton`s to take one away or add one, then the subtotal, shipping and total. `Place order` is the view's one lead; it shows `loading` while the write lands, and the bag empties only after it does. An order is one document holding a snapshot of each line's name, price and quantity, the totals and the buyer's handle, so a later price change never rewrites an order already placed; the person's own orders list under the bag, each with a `Badge` for its status (`info` received, `warn` ready to collect, `up` collected). Checkout waits on its `can` verdict from `useVibe("shop")`: a `Skeleton` inside an `aria-busy` wrapper while it resolves, a sentence in the app's own words when ordering is closed, and for a visitor who has not signed in a `Sign in to place your order` lead wired to `useViewer().requestLogin()`, with the bag they filled kept in place. Sign-in is required here, unlike a local-first note, because a signed-out write stays on the device until sign-in: an order placed that way would never reach the shop.
9
+ One view with one job: fill the bag and place the order. A `Navbar` carries the brand and a quiet bag button with a live count, and the `Heading` puts an `orange` `Highlight` on one word beside a muted line. A `Segmented` category filter (`tone="info"`) and a search `Input` in a `Field` sit above a `Grid cols="sidebar"`: on the main side a two-column grid of product `Card`s, each with a decorative `orange` `IconTile`, an `info` `Badge` for "New" or "Bestseller", the price in numeric `Text` and a quiet `Add to bag` (an `Empty` stands in when nothing matches); on the side the bag's `Card`, one line per product with its total and `IconButton`s to take one away or add one, then the subtotal, shipping and total. `Place order` is the view's one lead; it shows `loading` while the write lands, and the bag empties only after it does. An order is one document holding a snapshot of each line's name, price and quantity, the totals and the buyer's handle, so a later price change never rewrites an order already placed; the person's own orders list under the bag, each with a `Badge` for its status (`info` received, `warn` ready to collect, `up` collected). Checkout waits on its `can` verdict from `useVibe("shop")`: a `Skeleton` inside an `aria-busy` wrapper while it resolves, a sentence in the app's own words when ordering is closed, and for a visitor who has not signed in a `Sign in to place your order` lead wired to `useViewer().requestLogin()`, with the bag they filled kept in place. Sign-in is required here, unlike a local-first note, because a signed-out write stays on the device until sign-in: an order placed that way would never reach the shop.
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,
@@ -34,8 +34,8 @@ import {
34
34
  Spacer,
35
35
  Stack,
36
36
  Text,
37
- } from "@vibes.diy/pouf";
38
- import { Separator, Toaster, toast } from "@vibes.diy/pouf/interactive";
37
+ } from "@vibes.diy/ui";
38
+ import { Separator, Toaster, toast } from "@vibes.diy/ui/interactive";
39
39
 
40
40
  const PRODUCTS = [
41
41
  { id: "mug", name: "Speckled mug", blurb: "Holds a generous coffee, glazed oatmeal.", price: 28, category: "table", icon: "drop", badge: "Bestseller" },
@@ -133,7 +133,7 @@ export default function App() {
133
133
  <Navbar
134
134
  brand={
135
135
  <Row gap={2} wrap={false}>
136
- <Blob icon="sparkle" tone="orange" size="sm" />
136
+ <IconTile icon="sparkle" tone="orange" size="sm" />
137
137
  <Text>Kiln &amp; Co.</Text>
138
138
  </Row>
139
139
  }
@@ -171,7 +171,7 @@ export default function App() {
171
171
  <Card key={p.id}>
172
172
  <Stack gap={3}>
173
173
  <Row justify="between" align="top">
174
- <Blob icon={p.icon} tone="orange" />
174
+ <IconTile icon={p.icon} tone="orange" />
175
175
  {p.badge && <Badge tone="info">{p.badge}</Badge>}
176
176
  </Row>
177
177
  <Stack gap={1}>
@@ -274,7 +274,7 @@ export default function App() {
274
274
  </div>
275
275
  </Grid>
276
276
  </Stack>
277
- <div className="pouf-toasts">
277
+ <div className="ui-toasts">
278
278
  <Toaster />
279
279
  </div>
280
280
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiSupportConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiSupportConfig = {
2
+ name: "ui-support",
3
+ aliases: ["pouf-support"],
4
+ label: "Support block",
5
+ description: "Support desk to log tickets, filter the queue, reply, resolve",
6
+ };
7
+ //# sourceMappingURL=ui-support.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-support.js","sourceRoot":"","sources":["../../jsr/llms/ui-support.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,+DAA+D;CAC7E,CAAC"}
@@ -1,8 +1,8 @@
1
- # Pouf Support
1
+ # Support
2
2
 
3
3
  A help desk where questions come in as tickets and get answered, chased and closed: a small shop's customer questions, an IT volunteer queue, a landlord's repair requests, a club's member help. Reach for it whenever the app's core is requests that each carry a status (open, waiting on the asker, solved) and get worked through by replying. Tickets, their status and every reply persist, so the queue is where it was left on the next visit and for everyone working it.
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 @@ Two views, one job each. The queue opens with the `Heading` and a muted count of
13
13
  import React, { 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, Heading, Icon, IconButton, Input, Row, RowCard, Skeleton, Spacer, Stack, Text, Textarea } from "@vibes.diy/pouf";
17
- import { Checkbox, Dialog, Select, Toaster, toast } from "@vibes.diy/pouf/interactive";
16
+ import { Badge, Button, Card, Empty, Field, Heading, Icon, IconButton, Input, Row, RowCard, Skeleton, Spacer, Stack, Text, Textarea } from "@vibes.diy/ui";
17
+ import { Checkbox, Dialog, Select, Toaster, toast } from "@vibes.diy/ui/interactive";
18
18
 
19
19
  const STATUS = {
20
20
  open: { label: "Open", tone: "info" },
@@ -313,7 +313,7 @@ export default function App() {
313
313
  )}
314
314
  </Stack>
315
315
  )}
316
- <div className="pouf-toasts">
316
+ <div className="ui-toasts">
317
317
  <Toaster />
318
318
  </div>
319
319
  </main>
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const uiTestimonialsConfig: LlmConfig;
@@ -0,0 +1,7 @@
1
+ export const uiTestimonialsConfig = {
2
+ name: "ui-testimonials",
3
+ aliases: ["pouf-testimonials"],
4
+ label: "Testimonials block",
5
+ description: "Testimonials section with category filter, story carousel and reported outcomes",
6
+ };
7
+ //# sourceMappingURL=ui-testimonials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-testimonials.js","sourceRoot":"","sources":["../../jsr/llms/ui-testimonials.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,oBAAoB,GAAc;IAC7C,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,CAAC,mBAAmB,CAAC;IAC9B,KAAK,EAAE,oBAAoB;IAC3B,WAAW,EAAE,iFAAiF;CAC/F,CAAC"}