@vibes.diy/prompts 14.3.202 → 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 (247) 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 +95 -1
  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 +6 -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.js +14 -2
  17. package/llms/maps.js.map +1 -1
  18. package/llms/maps.md +212 -9
  19. package/llms/match-style.md +1 -1
  20. package/llms/motion.md +7 -7
  21. package/llms/p5.md +1 -1
  22. package/llms/physics.md +2 -2
  23. package/llms/reskin.js +8 -1
  24. package/llms/reskin.js.map +1 -1
  25. package/llms/reskin.md +99 -20
  26. package/llms/richtext.md +5 -5
  27. package/llms/spotify.md +1 -1
  28. package/llms/stripe-subscriptions.md +1 -1
  29. package/llms/stripe.md +3 -3
  30. package/llms/strudel.md +3 -3
  31. package/llms/three-js.md +4 -4
  32. package/llms/touch-games.js +1 -1
  33. package/llms/touch-games.js.map +1 -1
  34. package/llms/touch-games.md +3 -3
  35. package/llms/ui-blog.d.ts +2 -0
  36. package/llms/ui-blog.js +7 -0
  37. package/llms/ui-blog.js.map +1 -0
  38. package/llms/{pouf-blog.md → ui-blog.md} +10 -10
  39. package/llms/ui-booking.d.ts +2 -0
  40. package/llms/ui-booking.js +7 -0
  41. package/llms/ui-booking.js.map +1 -0
  42. package/llms/{pouf-booking.md → ui-booking.md} +8 -8
  43. package/llms/ui-calendar.d.ts +2 -0
  44. package/llms/ui-calendar.js +7 -0
  45. package/llms/ui-calendar.js.map +1 -0
  46. package/llms/{pouf-calendar.md → ui-calendar.md} +5 -5
  47. package/llms/ui-chat.d.ts +2 -0
  48. package/llms/ui-chat.js +7 -0
  49. package/llms/ui-chat.js.map +1 -0
  50. package/llms/{pouf-chat.md → ui-chat.md} +4 -4
  51. package/llms/ui-contact.d.ts +2 -0
  52. package/llms/ui-contact.js +7 -0
  53. package/llms/ui-contact.js.map +1 -0
  54. package/llms/{pouf-contact.md → ui-contact.md} +7 -7
  55. package/llms/ui-course.d.ts +2 -0
  56. package/llms/ui-course.js +7 -0
  57. package/llms/ui-course.js.map +1 -0
  58. package/llms/{pouf-course.md → ui-course.md} +9 -9
  59. package/llms/ui-crm.d.ts +2 -0
  60. package/llms/ui-crm.js +7 -0
  61. package/llms/ui-crm.js.map +1 -0
  62. package/llms/{pouf-crm.md → ui-crm.md} +5 -5
  63. package/llms/ui-dashboard.d.ts +2 -0
  64. package/llms/ui-dashboard.js +7 -0
  65. package/llms/ui-dashboard.js.map +1 -0
  66. package/llms/{pouf-dashboard.md → ui-dashboard.md} +7 -7
  67. package/llms/ui-editorial.d.ts +2 -0
  68. package/llms/ui-editorial.js +7 -0
  69. package/llms/ui-editorial.js.map +1 -0
  70. package/llms/{pouf-editorial.md → ui-editorial.md} +5 -5
  71. package/llms/ui-event.d.ts +2 -0
  72. package/llms/ui-event.js +7 -0
  73. package/llms/ui-event.js.map +1 -0
  74. package/llms/{pouf-event.md → ui-event.md} +5 -5
  75. package/llms/ui-feed.d.ts +2 -0
  76. package/llms/ui-feed.js +7 -0
  77. package/llms/ui-feed.js.map +1 -0
  78. package/llms/{pouf-feed.md → ui-feed.md} +5 -5
  79. package/llms/ui-game.d.ts +2 -0
  80. package/llms/ui-game.js +7 -0
  81. package/llms/ui-game.js.map +1 -0
  82. package/llms/{pouf-game.md → ui-game.md} +6 -6
  83. package/llms/ui-inbox.d.ts +2 -0
  84. package/llms/ui-inbox.js +7 -0
  85. package/llms/ui-inbox.js.map +1 -0
  86. package/llms/{pouf-inbox.md → ui-inbox.md} +5 -5
  87. package/llms/ui-inventory.d.ts +2 -0
  88. package/llms/ui-inventory.js +7 -0
  89. package/llms/ui-inventory.js.map +1 -0
  90. package/llms/{pouf-inventory.md → ui-inventory.md} +5 -5
  91. package/llms/ui-kanban.d.ts +2 -0
  92. package/llms/ui-kanban.js +7 -0
  93. package/llms/ui-kanban.js.map +1 -0
  94. package/llms/{pouf-kanban.md → ui-kanban.md} +5 -5
  95. package/llms/ui-landing.d.ts +2 -0
  96. package/llms/ui-landing.js +7 -0
  97. package/llms/ui-landing.js.map +1 -0
  98. package/llms/{pouf-landing.md → ui-landing.md} +6 -6
  99. package/llms/ui-login.d.ts +2 -0
  100. package/llms/ui-login.js +7 -0
  101. package/llms/ui-login.js.map +1 -0
  102. package/llms/{pouf-login.md → ui-login.md} +7 -7
  103. package/llms/ui-music.d.ts +2 -0
  104. package/llms/ui-music.js +7 -0
  105. package/llms/ui-music.js.map +1 -0
  106. package/llms/{pouf-music.md → ui-music.md} +6 -6
  107. package/llms/ui-onboarding.d.ts +2 -0
  108. package/llms/ui-onboarding.js +7 -0
  109. package/llms/ui-onboarding.js.map +1 -0
  110. package/llms/{pouf-onboarding.md → ui-onboarding.md} +5 -5
  111. package/llms/ui-pricing.d.ts +2 -0
  112. package/llms/ui-pricing.js +7 -0
  113. package/llms/ui-pricing.js.map +1 -0
  114. package/llms/{pouf-pricing.md → ui-pricing.md} +5 -5
  115. package/llms/ui-profile.d.ts +2 -0
  116. package/llms/ui-profile.js +7 -0
  117. package/llms/ui-profile.js.map +1 -0
  118. package/llms/{pouf-profile.md → ui-profile.md} +4 -4
  119. package/llms/ui-quiz.d.ts +2 -0
  120. package/llms/ui-quiz.js +7 -0
  121. package/llms/ui-quiz.js.map +1 -0
  122. package/llms/{pouf-quiz.md → ui-quiz.md} +6 -6
  123. package/llms/ui-settings.d.ts +2 -0
  124. package/llms/ui-settings.js +7 -0
  125. package/llms/ui-settings.js.map +1 -0
  126. package/llms/{pouf-settings.md → ui-settings.md} +5 -5
  127. package/llms/ui-storefront.d.ts +2 -0
  128. package/llms/ui-storefront.js +7 -0
  129. package/llms/ui-storefront.js.map +1 -0
  130. package/llms/{pouf-storefront.md → ui-storefront.md} +9 -9
  131. package/llms/ui-support.d.ts +2 -0
  132. package/llms/ui-support.js +7 -0
  133. package/llms/ui-support.js.map +1 -0
  134. package/llms/{pouf-support.md → ui-support.md} +5 -5
  135. package/llms/ui-testimonials.d.ts +2 -0
  136. package/llms/ui-testimonials.js +7 -0
  137. package/llms/ui-testimonials.js.map +1 -0
  138. package/llms/{pouf-testimonials.md → ui-testimonials.md} +6 -6
  139. package/llms/ui-todo.d.ts +2 -0
  140. package/llms/ui-todo.js +7 -0
  141. package/llms/ui-todo.js.map +1 -0
  142. package/llms/{pouf-todo.md → ui-todo.md} +5 -5
  143. package/llms/ui-weather.d.ts +2 -0
  144. package/llms/ui-weather.js +7 -0
  145. package/llms/ui-weather.js.map +1 -0
  146. package/llms/{pouf-weather.md → ui-weather.md} +5 -5
  147. package/llms/use-vibe.md +4 -4
  148. package/llms/use-viewer.md +5 -5
  149. package/llms/voxel.md +1 -1
  150. package/llms/web-audio.md +49 -26
  151. package/llms/worlds.md +3 -3
  152. package/llms/youtube.md +1 -1
  153. package/package.json +5 -5
  154. package/system-prompt-initial-instant.md +3 -3
  155. package/system-prompt.md +3 -3
  156. package/themes/colorsets.js +7 -7
  157. package/themes/colorsets.js.map +1 -1
  158. package/themes/looks/pouf/brief.md +87 -85
  159. package/themes/looks/pouf/catalog.generated.d.ts +1 -1
  160. package/themes/looks/pouf/catalog.generated.js +47 -17
  161. package/themes/looks/pouf/catalog.generated.js.map +1 -1
  162. package/themes/looks/pouf/variety.js +4 -4
  163. package/themes/looks/pouf/variety.js.map +1 -1
  164. package/llms/pouf-blog.d.ts +0 -2
  165. package/llms/pouf-blog.js +0 -6
  166. package/llms/pouf-blog.js.map +0 -1
  167. package/llms/pouf-booking.d.ts +0 -2
  168. package/llms/pouf-booking.js +0 -6
  169. package/llms/pouf-booking.js.map +0 -1
  170. package/llms/pouf-calendar.d.ts +0 -2
  171. package/llms/pouf-calendar.js +0 -6
  172. package/llms/pouf-calendar.js.map +0 -1
  173. package/llms/pouf-chat.d.ts +0 -2
  174. package/llms/pouf-chat.js +0 -6
  175. package/llms/pouf-chat.js.map +0 -1
  176. package/llms/pouf-contact.d.ts +0 -2
  177. package/llms/pouf-contact.js +0 -6
  178. package/llms/pouf-contact.js.map +0 -1
  179. package/llms/pouf-course.d.ts +0 -2
  180. package/llms/pouf-course.js +0 -6
  181. package/llms/pouf-course.js.map +0 -1
  182. package/llms/pouf-crm.d.ts +0 -2
  183. package/llms/pouf-crm.js +0 -6
  184. package/llms/pouf-crm.js.map +0 -1
  185. package/llms/pouf-dashboard.d.ts +0 -2
  186. package/llms/pouf-dashboard.js +0 -6
  187. package/llms/pouf-dashboard.js.map +0 -1
  188. package/llms/pouf-editorial.d.ts +0 -2
  189. package/llms/pouf-editorial.js +0 -6
  190. package/llms/pouf-editorial.js.map +0 -1
  191. package/llms/pouf-event.d.ts +0 -2
  192. package/llms/pouf-event.js +0 -6
  193. package/llms/pouf-event.js.map +0 -1
  194. package/llms/pouf-feed.d.ts +0 -2
  195. package/llms/pouf-feed.js +0 -6
  196. package/llms/pouf-feed.js.map +0 -1
  197. package/llms/pouf-game.d.ts +0 -2
  198. package/llms/pouf-game.js +0 -6
  199. package/llms/pouf-game.js.map +0 -1
  200. package/llms/pouf-inbox.d.ts +0 -2
  201. package/llms/pouf-inbox.js +0 -6
  202. package/llms/pouf-inbox.js.map +0 -1
  203. package/llms/pouf-inventory.d.ts +0 -2
  204. package/llms/pouf-inventory.js +0 -6
  205. package/llms/pouf-inventory.js.map +0 -1
  206. package/llms/pouf-kanban.d.ts +0 -2
  207. package/llms/pouf-kanban.js +0 -6
  208. package/llms/pouf-kanban.js.map +0 -1
  209. package/llms/pouf-landing.d.ts +0 -2
  210. package/llms/pouf-landing.js +0 -6
  211. package/llms/pouf-landing.js.map +0 -1
  212. package/llms/pouf-login.d.ts +0 -2
  213. package/llms/pouf-login.js +0 -6
  214. package/llms/pouf-login.js.map +0 -1
  215. package/llms/pouf-music.d.ts +0 -2
  216. package/llms/pouf-music.js +0 -6
  217. package/llms/pouf-music.js.map +0 -1
  218. package/llms/pouf-onboarding.d.ts +0 -2
  219. package/llms/pouf-onboarding.js +0 -6
  220. package/llms/pouf-onboarding.js.map +0 -1
  221. package/llms/pouf-pricing.d.ts +0 -2
  222. package/llms/pouf-pricing.js +0 -6
  223. package/llms/pouf-pricing.js.map +0 -1
  224. package/llms/pouf-profile.d.ts +0 -2
  225. package/llms/pouf-profile.js +0 -6
  226. package/llms/pouf-profile.js.map +0 -1
  227. package/llms/pouf-quiz.d.ts +0 -2
  228. package/llms/pouf-quiz.js +0 -6
  229. package/llms/pouf-quiz.js.map +0 -1
  230. package/llms/pouf-settings.d.ts +0 -2
  231. package/llms/pouf-settings.js +0 -6
  232. package/llms/pouf-settings.js.map +0 -1
  233. package/llms/pouf-storefront.d.ts +0 -2
  234. package/llms/pouf-storefront.js +0 -6
  235. package/llms/pouf-storefront.js.map +0 -1
  236. package/llms/pouf-support.d.ts +0 -2
  237. package/llms/pouf-support.js +0 -6
  238. package/llms/pouf-support.js.map +0 -1
  239. package/llms/pouf-testimonials.d.ts +0 -2
  240. package/llms/pouf-testimonials.js +0 -6
  241. package/llms/pouf-testimonials.js.map +0 -1
  242. package/llms/pouf-todo.d.ts +0 -2
  243. package/llms/pouf-todo.js +0 -6
  244. package/llms/pouf-todo.js.map +0 -1
  245. package/llms/pouf-weather.d.ts +0 -2
  246. package/llms/pouf-weather.js +0 -6
  247. package/llms/pouf-weather.js.map +0 -1
package/llms/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../jsr/llms/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../jsr/llms/index.ts"],"names":[],"mappings":"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"}
package/llms/maps.js CHANGED
@@ -1,7 +1,19 @@
1
1
  export const mapsConfig = {
2
2
  name: "maps",
3
3
  label: "maps",
4
- description: "world maps, countries, travel journals, places visited, best places to live, territory games and choropleths: bundled country outlines and SVG markers that render immediately, with tap-to-select and a legend; world overviews use the platform's tile-free geography module",
5
- cues: ["world map", "countries", "places visited", "choropleth", "travel map", "geography"],
4
+ description: "maps of every kind. World overviews (countries, travel journals, places visited, best places to live, territory games, choropleths) use bundled country outlines and SVG markers that render immediately. Street maps of places near the person (restaurants, coffee, parks, \"near me\", a city or zip, directions) use MapLibre vector tiles plus an OpenStreetMap place search that opens already full of real places, with friends' ratings and directions links on top",
5
+ cues: [
6
+ "world map",
7
+ "countries",
8
+ "places visited",
9
+ "choropleth",
10
+ "travel map",
11
+ "geography",
12
+ "near me",
13
+ "nearby",
14
+ "local map",
15
+ "street map",
16
+ "driving directions",
17
+ ],
6
18
  };
7
19
  //# sourceMappingURL=maps.js.map
package/llms/maps.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"maps.js","sourceRoot":"","sources":["../../jsr/llms/maps.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAc;IACnC,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IACb,WAAW,EACT,gRAAgR;IAClR,IAAI,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,CAAC;CAC5F,CAAC"}
1
+ {"version":3,"file":"maps.js","sourceRoot":"","sources":["../../jsr/llms/maps.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAc;IACnC,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IACb,WAAW,EACT,6cAA6c;IAC/c,IAAI,EAAE;QACJ,WAAW;QACX,WAAW;QACX,gBAAgB;QAChB,YAAY;QACZ,YAAY;QACZ,WAAW;QACX,SAAS;QACT,QAAQ;QACR,WAAW;QACX,YAAY;QACZ,oBAAoB;KACrB;CACF,CAAC"}
package/llms/maps.md CHANGED
@@ -1,4 +1,13 @@
1
- # Maps — a world overview that opens with the app
1
+ # Maps — a world overview, or a street map of places near the person
2
+
3
+ Maps come in two shapes, and the ask picks one. Countries, travel journals,
4
+ territory games and choropleths get the **world overview** below, drawn from
5
+ bundled outlines. An ask about places someone can walk or drive to (restaurants,
6
+ coffee, parks, "near me", "local", a city or zip, directions) gets the
7
+ **street map of places near the person** further down: vector tiles, a place
8
+ search, and a feed of real places that is full on the first screen.
9
+
10
+ ## World overview
2
11
 
3
12
  For world maps, travel journals, country comparisons and territory games, import
4
13
  shapes and geometry from `@vibes.diy/geo`. The platform bundles the data and
@@ -21,7 +30,7 @@ oriented for D3; keep its rings intact.
21
30
 
22
31
  ```jsx
23
32
  import React, { useState } from "react";
24
- import { Button } from "@vibes.diy/pouf";
33
+ import { Button } from "@vibes.diy/ui";
25
34
  import { countries, geoNaturalEarth1, geoPath } from "@vibes.diy/geo";
26
35
 
27
36
  const projection = geoNaturalEarth1().fitExtent([[12, 12], [788, 408]], { type: "Sphere" });
@@ -65,12 +74,206 @@ country IDs and display the units and range in their legend; missing data has
65
74
  its own fill and label.
66
75
 
67
76
  World outlines come with the app; no runtime shape fetch is needed.
68
- The data is generalized Natural Earth 4.1.0 via world-atlas 2.0.2. It is appropriate
69
- for world overviews. Street-level zoom, routes and address lookup need a separate
70
- map provider with its own coverage, credentials and attribution. Keep that choice
71
- separate from a request to show results on a world map.
77
+ The data is generalized Natural Earth 4.1.0 via world-atlas 2.0.2. It is made for
78
+ world overviews; streets, neighborhoods and places to go are the street map's job.
72
79
 
73
- Verify the first preview at phone width: outlines, matching fills and place
80
+ Verify a world overview at phone width: outlines, matching fills and place
74
81
  markers appear, tapping a result opens its details, the legend is readable, and
75
- no third-party shape or tile request occurs. A map is complete when the preview
76
- shows those results; the person does not need to arrange a data download.
82
+ the outlines arrive with the app rather than from a shape download.
83
+
84
+ ## Street map of places near the person
85
+
86
+ **A local ask opens on results.** "Vegan restaurants I can share with friends",
87
+ "coffee near me", "dog parks in my city": the first screen is a street map with
88
+ numbered pins and a feed of real places beside it, with no form to fill first.
89
+ The area comes from, in order: the area the person picked last time (kept in
90
+ `localStorage`), a city-level guess from their connection
91
+ (`https://get.geojs.io/v1/ip/geo.json`: `city`, `region`, `latitude`,
92
+ `longitude`; no permission prompt), and a well-known city when neither answers.
93
+ One line beside the results says what it shows and how the area was chosen: "38
94
+ spots within 5 mi of Portland, Oregon (a guess from your connection)".
95
+
96
+ That opening is for places the public world holds. When the ask is the person's
97
+ own collection ("places I've been", "my favorite spots", "my trips"), the app
98
+ opens on their own records and the place search is how they add the next one.
99
+ A public list never stands in for their own.
100
+
101
+ **The first paint reads well with no network.** Above the map, the area line,
102
+ the city or zip box and the location button render from code alone. The feed
103
+ holds framed placeholders until the places arrive, and the map box shows a quiet
104
+ background color until its tiles arrive. Keep the last good answer for each area
105
+ in `localStorage` and paint it before the next search goes out, so a return
106
+ visit opens instantly and a busy place search still shows real places.
107
+
108
+ **The location prompt runs only inside the handler of a button the person taps.**
109
+ A "Use my location" button calls `navigator.geolocation.getCurrentPosition`
110
+ from its click handler, rounds to three decimals (a block, not a doorstep), and
111
+ searches there. Never call it from an effect or at load: the guess already gave
112
+ them a map, and the button is the upgrade they choose. A city or zip box sits
113
+ beside it, looked up on submit with Photon
114
+ (`https://photon.komoot.io/api/?q=<text>&limit=5&lat=<lat>&lon=<lng>`, biased
115
+ toward the current area so "97214" finds Portland, not a village abroad).
116
+ Reverse lookups for a friendly label use `https://photon.komoot.io/reverse?lat=…&lon=…`.
117
+
118
+ **Draw the map with MapLibre and OpenFreeMap vector tiles**: free, keyless and
119
+ sharp at every zoom. Load the library on first render from its pinned URL, give
120
+ the map a container with a real height, and theme the pins with the app's own
121
+ classes:
122
+
123
+ ```jsx
124
+ import React, { useEffect, useRef, useState } from "react";
125
+
126
+ let lib;
127
+ const loadMapLibre = () => (lib ??= (() => {
128
+ const css = document.createElement("link");
129
+ css.rel = "stylesheet";
130
+ css.href = "https://unpkg.com/maplibre-gl@5.6.0/dist/maplibre-gl.css";
131
+ document.head.appendChild(css);
132
+ return import("https://esm.sh/maplibre-gl@5.6.0").then((m) => m.default ?? m);
133
+ })());
134
+
135
+ const styleUrl = () => matchMedia("(prefers-color-scheme: dark)").matches
136
+ ? "https://tiles.openfreemap.org/styles/dark"
137
+ : "https://tiles.openfreemap.org/styles/positron"; // also: liberty, bright
138
+
139
+ export function PlaceMap({ places, center, selectedId, onPick }) {
140
+ const box = useRef(null);
141
+ const map = useRef(null);
142
+ const pins = useRef(new Map());
143
+ const [ready, setReady] = useState(false);
144
+ useEffect(() => {
145
+ let alive = true;
146
+ loadMapLibre().then((ml) => {
147
+ if (!alive) return;
148
+ map.current = new ml.Map({ container: box.current, style: styleUrl(),
149
+ center: [center.lng, center.lat], zoom: 12, attributionControl: false, cooperativeGestures: true });
150
+ map.current.addControl(new ml.NavigationControl({ showCompass: false }), "top-right");
151
+ map.current.on("load", () => alive && setReady(true));
152
+ });
153
+ return () => { alive = false; map.current?.remove(); };
154
+ }, []);
155
+ // Places arrive after the map: redraw whenever the list changes, once the map is ready.
156
+ const ids = places.map((p) => p.id).join("|");
157
+ useEffect(() => {
158
+ if (!ready) return;
159
+ loadMapLibre().then((ml) => {
160
+ pins.current.forEach((pin) => pin.remove());
161
+ pins.current = new Map();
162
+ places.forEach((place, i) => {
163
+ const el = document.createElement("button");
164
+ el.className = "grid size-8 place-items-center rounded-full border-2 border-background bg-primary text-xs font-bold text-primary-foreground shadow";
165
+ el.textContent = String(i + 1); // the same number the feed shows
166
+ el.setAttribute("aria-label", `${i + 1}. ${place.name}`);
167
+ el.onclick = () => onPick(place.id);
168
+ pins.current.set(place.id, new ml.Marker({ element: el }).setLngLat([place.lng, place.lat]).addTo(map.current));
169
+ });
170
+ if (places.length > 1) {
171
+ const b = new ml.LngLatBounds();
172
+ places.forEach((p) => b.extend([p.lng, p.lat]));
173
+ map.current.fitBounds(b, { padding: 48, maxZoom: 14 });
174
+ }
175
+ });
176
+ }, [ready, ids]);
177
+ useEffect(() => {
178
+ const pin = pins.current.get(selectedId);
179
+ if (pin) map.current.easeTo({ center: pin.getLngLat(), zoom: Math.max(map.current.getZoom(), 14) });
180
+ }, [selectedId]);
181
+ return <div className="relative h-80 overflow-hidden rounded-lg border border-border lg:h-screen">
182
+ <div ref={box} className="h-full w-full" role="region" aria-label="Map of places" />
183
+ <span className="absolute bottom-1 left-2 text-xs text-muted-foreground">© OpenFreeMap · © OpenStreetMap contributors</span>
184
+ </div>;
185
+ }
186
+ ```
187
+
188
+ MapLibre sets `position: relative` on the element it is handed, so size that
189
+ element with `h-full w-full` inside a sized wrapper; an `absolute inset-0` map
190
+ box collapses to zero height. Once the person drags the map, offer a "Search
191
+ this area" button that searches the map's center with a radius taken from its
192
+ bounds.
193
+
194
+ **Places come from OpenStreetMap through the app's own `backend.js`.** A `GET
195
+ /_api/places?lat=…&lng=…&r=…` route asks Overpass and answers the raw elements.
196
+ A read the backend makes is shared through the platform's read cache, so
197
+ friends opening the same area share one answer. When the owner has set a
198
+ `GEOAPIFY_KEY` secret, the same route asks Geoapify's hosted copy of
199
+ OpenStreetMap instead, which answers steadily:
200
+
201
+ ```js
202
+ const MIRRORS = ["https://overpass-api.de/api/interpreter", "https://overpass.private.coffee/api/interpreter"];
203
+ const json = (d, status = 200) => new Response(JSON.stringify(d), { status, headers: { "content-type": "application/json" } });
204
+
205
+ export async function fetch(request, ctx) {
206
+ const url = new URL(request.url);
207
+ if (url.pathname !== "/places") return json({ ok: false }, 404);
208
+ const lat = Number(url.searchParams.get("lat")), lng = Number(url.searchParams.get("lng"));
209
+ const r = Math.min(Number(url.searchParams.get("r")) || 8000, 40000);
210
+ if (!Number.isFinite(lat) || !Number.isFinite(lng)) return json({ ok: false, reason: "Pick a spot on the map." }, 400);
211
+ try {
212
+ const key = ctx.secrets.GEOAPIFY_KEY;
213
+ if (key) {
214
+ const res = await ctx.fetch(`https://api.geoapify.com/v2/places?categories=catering.restaurant,catering.cafe` +
215
+ `&conditions=vegan&filter=circle:${lng},${lat},${r}&limit=100&apiKey=${encodeURIComponent(key)}`);
216
+ const d = await res.json();
217
+ // datasource.raw carries the OSM tags, so the page reads one shape either way.
218
+ const TYPES = { n: "node", w: "way", r: "relation" };
219
+ return json({ ok: true, elements: d.features.map(({ properties: p }) => {
220
+ const raw = p.datasource?.raw ?? {};
221
+ // Keep the OSM identity (osm-way-12 stays osm-way-12); a result with none gets its own namespace.
222
+ const osm = TYPES[raw.osm_type] && raw.osm_id;
223
+ return { type: osm ? TYPES[raw.osm_type] : "geoapify", id: osm ? raw.osm_id : p.place_id,
224
+ lat: p.lat, lon: p.lon, tags: { name: p.name, ...raw } };
225
+ }) });
226
+ }
227
+ const q = `[out:json][timeout:20];nwr["amenity"~"^(restaurant|cafe|fast_food)$"]["diet:vegan"~"^(only|yes)$"](around:${r},${lat},${lng});out center tags 300;`;
228
+ const elements = await Promise.any(MIRRORS.map(async (base) => {
229
+ const res = await ctx.fetch(`${base}?data=${encodeURIComponent(q)}`);
230
+ if (!res.ok) throw new Error(String(res.status));
231
+ return (await res.json()).elements;
232
+ }));
233
+ return json({ ok: true, elements });
234
+ } catch {
235
+ return json({ ok: false, reason: "The place list is taking its time." }, 502);
236
+ }
237
+ }
238
+ ```
239
+
240
+ Write the Overpass filter for what the person asked about, using the tags
241
+ OpenStreetMap actually carries: `diet:vegan` / `diet:vegetarian` (`only` or
242
+ `yes`), `cuisine=…`, `amenity=cafe|restaurant|bar|ice_cream`, `shop=bakery`,
243
+ `leisure=park|playground|dog_park`, `tourism=museum`. Geoapify names the same
244
+ things as `categories` (`catering.cafe`, `leisure.park`) and `conditions`
245
+ (`vegan`, `vegan.only`, `dogs`, `wheelchair`). Each element becomes a place:
246
+ `id: "osm-" + type + "-" + id`, name, coordinates (`lat`/`lon`, or `center` for a
247
+ building), `addr:*` for the address, `website`, `opening_hours`, `cuisine`.
248
+ Round the search point to two decimals so nearby visitors share a cached answer.
249
+
250
+ Overpass is run by volunteers and is often slow or busy. Give the search about
251
+ 20 seconds, then show a "Try again" button and a link that opens the same area
252
+ on a directory that covers it (HappyCow for vegan food, the phone's maps app for
253
+ anything else). Real places only: an empty area says so and suggests the
254
+ nearest city or widening the circle. The person's own pins and notes are how a
255
+ missing spot gets in, never invented names.
256
+
257
+ "Top" and "best" name their ranking in that one line: "fully vegan first, then
258
+ friends' favorites, then the closest". Show up to 50, start with a circle of
259
+ about 5 miles, and widen it when fewer than 25 come back. Rank on what the data
260
+ holds: a strong tag such as `diet:vegan=only`, the friends' own ratings, how
261
+ complete the listing is (website, hours, cuisine, address), and distance.
262
+
263
+ **The person's layer sits on top of the places.** Ratings, comments, saves and
264
+ "been there" checks are the app's own records, keyed to the place's id
265
+ (`restaurantId: "osm-node-123"`) and carrying a snapshot of its name, address
266
+ and coordinates, so a note still reads well if the listing changes. Every
267
+ signed-in friend writes as themselves; pins the owner adds by hand join the feed
268
+ with their own note.
269
+
270
+ **Directions open the phone's maps app**:
271
+ `https://www.google.com/maps/dir/?api=1&destination=<lat>,<lng>&travelmode=driving`,
272
+ or `https://maps.apple.com/?daddr=<lat>,<lng>&dirflg=d` on Apple devices. A place
273
+ shares as the app's public address with `#place=<id>&at=<lat>,<lng>` in the
274
+ fragment. A friend opening it lands on that area with the place open.
275
+
276
+ Verify the first preview at phone width. The map paints, the numbered pins match
277
+ the feed, and tapping a pin brings its card into view. The location prompt
278
+ appears only after "Use my location". A typed zip moves the map, and the page
279
+ credits OpenStreetMap.
@@ -95,7 +95,7 @@ Plain Tailwind utilities read the variables:
95
95
  `font-sans` goes once on the root element and every child inherits the face.
96
96
 
97
97
  **Every component is plain JSX with Tailwind utilities, written in the app itself.**
98
- A match-style app imports no look package (`@vibes.diy/pouf`, `@vibes.diy/look`):
98
+ A match-style app imports no look package (`@vibes.diy/ui`, `@vibes.diy/look`):
99
99
  its buttons, cards, rows and fields are a few lines of JSX each, shaped by the
100
100
  recipe below. Each extracted component file paints with the same utilities.
101
101
 
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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export const reskinConfig = {
2
2
  name: "reskin",
3
3
  label: "Reskin",
4
- description: 'The person says "look like…", "make it feel…" or names a style or mood — "a 90s Mac app", "a newspaper", "chopped and screwed", "Y2K", "neo-brutalist", "like Stripe\'s dashboard" — with nothing to copy supplied: keep the look\'s components, logic and Look tab, and give them that appearance — the look\'s tokens re-scoped on one wrapper, its hook classes styled from a <style> string, web fonts, borders, texture, motion and a recomposed layout',
4
+ description: 'The person says "look like…", "make it feel…" or names a style or mood — "a 90s Mac app", "a newspaper", "chopped and screwed", "Y2K", "neo-brutalist", "like Stripe\'s dashboard" — with nothing to copy supplied: keep the look\'s components, logic and Look tab, and give them that appearance — the look\'s tokens re-scoped on one wrapper, its hook classes styled from a <style> string, web fonts, borders, texture, motion and a recomposed layout. Also the keepsake pattern for a thing people print, share or hand out — a ticket, invitation, menu, poster or certificate: one framed artifact drawn by the skin, with the components as its editing controls and a print style',
5
5
  cues: [
6
6
  "look like a",
7
7
  "looks like a",
@@ -26,6 +26,13 @@ export const reskinConfig = {
26
26
  "linear style",
27
27
  "like linear",
28
28
  "like stripe",
29
+ "printable",
30
+ "to print",
31
+ "print out",
32
+ "invitation card",
33
+ "a poster",
34
+ "certificate",
35
+ "place card",
29
36
  ],
30
37
  };
31
38
  //# sourceMappingURL=reskin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reskin.js","sourceRoot":"","sources":["../../jsr/llms/reskin.ts"],"names":[],"mappings":"AAqBA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,WAAW,EACT,8bAA8b;IAChc,IAAI,EAAE;QACJ,aAAa;QACb,cAAc;QACd,mBAAmB;QACnB,mBAAmB;QACnB,cAAc;QACd,aAAa;QACb,iBAAiB;QACjB,SAAS;QACT,aAAa;QACb,YAAY;QACZ,KAAK;QACL,WAAW;QACX,qBAAqB;QACrB,iBAAiB;QACjB,eAAe;QACf,cAAc;QACd,cAAc;QACd,gBAAgB;QAChB,kBAAkB;QAClB,iBAAiB;QACjB,cAAc;QACd,aAAa;QACb,aAAa;KACd;CACF,CAAC"}
1
+ {"version":3,"file":"reskin.js","sourceRoot":"","sources":["../../jsr/llms/reskin.ts"],"names":[],"mappings":"AAyBA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,WAAW,EACT,+pBAA+pB;IACjqB,IAAI,EAAE;QACJ,aAAa;QACb,cAAc;QACd,mBAAmB;QACnB,mBAAmB;QACnB,cAAc;QACd,aAAa;QACb,iBAAiB;QACjB,SAAS;QACT,aAAa;QACb,YAAY;QACZ,KAAK;QACL,WAAW;QACX,qBAAqB;QACrB,iBAAiB;QACjB,eAAe;QACf,cAAc;QACd,cAAc;QACd,gBAAgB;QAChB,kBAAkB;QAClB,iBAAiB;QACjB,cAAc;QACd,aAAa;QACb,aAAa;QACb,WAAW;QACX,UAAU;QACV,WAAW;QACX,iBAAiB;QACjB,UAAU;QACV,aAAa;QACb,YAAY;KACb;CACF,CAAC"}
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() {
@@ -205,12 +205,91 @@ export default function App() {
205
205
  }
206
206
  ```
207
207
 
208
+ ## Keepsake — the thing they print, share or hand out
209
+
210
+ Tickets, invitations, menus, posters, certificates, place cards, a recipe
211
+ card: the designed object is the point, and a page of `Card`s and `RowCard`s
212
+ around it makes it look like an admin screen. Build one framed artifact and
213
+ let the components edit it.
214
+
215
+ - **The keepsake is plain elements styled by the skin.** One `.keepsake`
216
+ element with a fixed shape (`aspect-ratio: 5 / 7` for a card, `2 / 1` for a
217
+ ticket, `1 / 1.414` for an A-size poster) holds the words as `div`s and
218
+ `span`s with the app's own classes (`.keepsake-title`, `.keepsake-meta`), set
219
+ in the display face, with the border, ornament, paper and stamp drawn in the
220
+ `SKIN` string. It is never a `Card`, and its words are never `Heading`s:
221
+ the hook classes belong to the screen, the keepsake has its own.
222
+ - **The components are the editing controls around it.** `Field` and `Input`
223
+ for the words, `Segmented` for a variant (theme, size), `Button` for Print
224
+ and Share. On a wide screen they sit beside the keepsake; on a phone the
225
+ keepsake comes first and the controls follow, so the first frame is the
226
+ thing itself, filled with a believable example rather than blanks.
227
+ - **Print shows only the keepsake.** A `@media print` block in the skin hides
228
+ everything else and sets `@page` to the keepsake's size; the Print button
229
+ calls `window.print()`.
230
+ - **Its colours come from the wrapper's tokens**, so the Look tab and a later
231
+ reskin restyle the keepsake along with the controls.
232
+
233
+ ```jsx
234
+ import React, { useState } from "react";
235
+ import { Button, Field, Input, Stack } from "@vibes.diy/ui";
236
+
237
+ const SKIN = `
238
+ @import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,wght@0,600;1,400&display=swap');
239
+ [data-reskin] .studio { display: grid; gap: 24px; padding: 16px; grid-template-columns: 1fr; }
240
+ @media (min-width: 48rem) { [data-reskin] .studio { grid-template-columns: 22rem 1fr; align-items: start; } [data-reskin] .studio > .keepsake { order: 2; } }
241
+ [data-reskin] .keepsake { aspect-ratio: 5 / 7; width: min(100%, 26rem); margin-inline: auto; padding: 12%; display: grid; place-content: center; gap: 14px;
242
+ text-align: center; background: var(--surface); color: var(--ink); outline: 1px solid var(--ink); outline-offset: -14px;
243
+ box-shadow: 0 18px 40px color-mix(in srgb, var(--ink) 18%, transparent); font-family: 'Fraunces', serif; }
244
+ [data-reskin] .keepsake-eyebrow { font-style: italic; color: var(--text-secondary); }
245
+ [data-reskin] .keepsake-title { font-size: clamp(28px, 7vw, 44px); font-weight: 600; line-height: 1.05; }
246
+ [data-reskin] .keepsake-rule { width: 40%; height: 1px; margin-inline: auto; background: var(--purple); }
247
+ @media print {
248
+ @page { size: 5in 7in; margin: 0; }
249
+ body:has([data-reskin]) * { visibility: hidden; }
250
+ [data-reskin] .keepsake, [data-reskin] .keepsake * { visibility: visible; }
251
+ [data-reskin] .keepsake { position: fixed; inset: 0; width: 100%; box-shadow: none; }
252
+ }
253
+ `;
254
+
255
+ export default function App() {
256
+ const [title, setTitle] = useState("Maya turns thirty");
257
+ const [when, setWhen] = useState("Saturday 14 June · 7pm · The Rooftop");
258
+
259
+ return (
260
+ <div data-reskin>
261
+ <style>{SKIN}</style>
262
+ <div className="studio">
263
+ <div className="keepsake">
264
+ <span className="keepsake-eyebrow">You are invited</span>
265
+ <span className="keepsake-title">{title}</span>
266
+ <span className="keepsake-rule" />
267
+ <span>{when}</span>
268
+ </div>
269
+ <Stack gap={3}>
270
+ <Field label="Headline">{(id, d) => <Input id={id} describedBy={d} value={title} onChange={setTitle} />}</Field>
271
+ <Field label="When and where">{(id, d) => <Input id={id} describedBy={d} value={when} onChange={setWhen} />}</Field>
272
+ <Button onClick={() => window.print()}>Print the invitation</Button>
273
+ </Stack>
274
+ </div>
275
+ </div>
276
+ );
277
+ }
278
+ ```
279
+
280
+ ## Board surface
281
+
282
+ A game board, a puzzle or a card table is the same split: the board is plain
283
+ elements the skin draws, the look's components frame it (score, buttons, the
284
+ win dialog). The board-games skill's _Board surface_ section has the worked
285
+ example.
286
+
208
287
  ## Reading a named style
209
288
 
210
289
  Name the five things a stranger would recognise and set each one:
211
290
 
212
291
  - **Ground and surfaces:** `--bg`, `--surface`, `--ink`, `--text-secondary`.
213
- - **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
214
293
  face on `--font-family`, the heading scale and tracking.
215
294
  - **Edges:** corners (`--r-card`, `--r-control`, `--r-pill`), borders on the
216
295
  hook classes, and the composite surfaces (`none` for flat, a hard offset for
@@ -223,5 +302,5 @@ Name the five things a stranger would recognise and set each one:
223
302
  A newspaper is a cream ground, black ink, a serif masthead over a rule, column
224
303
  grids and no shadows; a terminal is black, one phosphor green, a mono face and
225
304
  a blinking cursor that starts lit; Y2K is chrome gradients, pill corners and a
226
- 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
227
306
  style is borrowed, the names and logos of whoever made it famous are not.