@vibes.diy/prompts 14.3.45 → 14.3.47

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.
@@ -94,6 +94,33 @@ Do **not** invent wrappers like `images={x?.file ? something : undefined}` — p
94
94
 
95
95
  Do **not** set `model` for img2img: when an input image is present the platform automatically selects its image-**edit** default, which is tuned to produce edits faithful to the source. An explicit `model` override bypasses that routing — only use one when the app has a specific, stated reason.
96
96
 
97
+ ## Restyling a Captured Photo
98
+
99
+ A photo booth, a style camera or an avatar-from-a-selfie app keeps the camera frame on the shot's own record and gives every styled result its own `_id` (bump it to start a fresh attempt). The styled picture's frame is simply `<ImgGen>`, shown at full size: ImgGen paints the saved result when there is one, and otherwise its own progress bar, its own message when a picture needs another try, and — in the Vibes iPhone app — the **Create with Image Playground** button that a picture started by the camera (rather than a tap) waits on. The person sees each of those right in the frame. Your own words about the shot sit beside or below the frame.
100
+
101
+ Mount that same `<ImgGen>` wherever an unstyled shot is shown in full — the fresh-capture card and the detail view — so a shot saved in one visit styles the next time it opens. Gallery tiles read the saved result through `useImgGen` and show the original until it arrives.
102
+
103
+ ```jsx
104
+ import { ImgGen, useImgGen } from "use-vibes";
105
+
106
+ function StyledShot({ shot, database }) {
107
+ const { document: styled } = useImgGen({ _id: shot.styledId, database });
108
+ const version = styled?.versions?.[styled.currentVersion ?? 0];
109
+ const ready = Boolean(version?.id && styled?._files?.[version.id]);
110
+ return (
111
+ <figure>
112
+ <div className="aspect-square w-full overflow-hidden rounded-md">
113
+ {shot._files?.original && (
114
+ <ImgGen _id={shot.styledId} database={database} prompt={shot.prompt}
115
+ images={[shot._files.original]} alt={`${shot.style} version`} className="h-full w-full object-contain" />
116
+ )}
117
+ </div>
118
+ <figcaption>{ready ? shot.style : `Styling as ${shot.style}. Your original is saved.`}</figcaption>
119
+ </figure>
120
+ );
121
+ }
122
+ ```
123
+
97
124
  ## Loading a Specific Doc
98
125
 
99
126
  Load a previously generated image by `_id` — if the doc has a `prompt` but no `_files` yet, the component generates one: `<ImgGen _id="my-image-id" database={database} />`
package/llms/image-gen.md CHANGED
@@ -94,6 +94,33 @@ Do **not** invent wrappers like `images={x?.file ? something : undefined}` — p
94
94
 
95
95
  Do **not** set `model` for img2img: when an input image is present the platform automatically selects its image-**edit** default, which is tuned to produce edits faithful to the source. An explicit `model` override bypasses that routing — only use one when the app has a specific, stated reason.
96
96
 
97
+ ## Restyling a Captured Photo
98
+
99
+ A photo booth, a style camera or an avatar-from-a-selfie app keeps the camera frame on the shot's own record and gives every styled result its own `_id` (bump it to start a fresh attempt). The styled picture's frame is simply `<ImgGen>`, shown at full size: ImgGen paints the saved result when there is one, and otherwise its own progress bar, its own message when a picture needs another try, and — in the Vibes iPhone app — the **Create with Image Playground** button that a picture started by the camera (rather than a tap) waits on. The person sees each of those right in the frame. Your own words about the shot sit beside or below the frame.
100
+
101
+ Mount that same `<ImgGen>` wherever an unstyled shot is shown in full — the fresh-capture card and the detail view — so a shot saved in one visit styles the next time it opens. Gallery tiles read the saved result through `useImgGen` and show the original until it arrives.
102
+
103
+ ```jsx
104
+ import { ImgGen, useImgGen } from "use-vibes";
105
+
106
+ function StyledShot({ shot, database }) {
107
+ const { document: styled } = useImgGen({ _id: shot.styledId, database });
108
+ const version = styled?.versions?.[styled.currentVersion ?? 0];
109
+ const ready = Boolean(version?.id && styled?._files?.[version.id]);
110
+ return (
111
+ <figure>
112
+ <div className="aspect-square w-full overflow-hidden rounded-md">
113
+ {shot._files?.original && (
114
+ <ImgGen _id={shot.styledId} database={database} prompt={shot.prompt}
115
+ images={[shot._files.original]} alt={`${shot.style} version`} className="h-full w-full object-contain" />
116
+ )}
117
+ </div>
118
+ <figcaption>{ready ? shot.style : `Styling as ${shot.style}. Your original is saved.`}</figcaption>
119
+ </figure>
120
+ );
121
+ }
122
+ ```
123
+
97
124
  ## Loading a Specific Doc
98
125
 
99
126
  Load a previously generated image by `_id` — if the doc has a `prompt` but no `_files` yet, the component generates one: `<ImgGen _id="my-image-id" database={database} />`
@@ -293,6 +293,19 @@ Keep the guest's composed text across sign-in. Draft input lives in component st
293
293
  <ViewerTag userHandle={member.userHandle} className="mt-1" />
294
294
  ```
295
295
 
296
+ **Tapping a tag opens that handle's profile.** Pass `onClick` and bind the handle the tag displays — the app owns the navigation and chooses the profile view. Opening a profile follows nobody: follow stays behind its own button. The tap carries the handle the tag shows, so each row opens its own person.
297
+
298
+ ```jsx
299
+ const { ViewerTag } = useViewer();
300
+ const [profileHandle, setProfileHandle] = React.useState(null);
301
+
302
+ {/* Pass the handle you render: a tap opens that handle's profile. */}
303
+ <ViewerTag userHandle={member.userHandle} onClick={() => setProfileHandle(member.userHandle)} />
304
+ {profileHandle && <ProfileView handle={profileHandle} />}
305
+ ```
306
+
307
+ **Hero avatars render natively.** `size` draws the avatar circle at that diameter and `avatarOnly` drops the handle text — and the pill chrome with it, so the header is the circle itself. `<ViewerTag userHandle={profileHandle} size={120} avatarOnly />` is a profile header, with or without a profile action. Give the tag its profile action and the clickable shape needs no wrapper: the tag is already one native button, and a plain tag without `onClick` stays a quiet span. A no-prop `<ViewerTag />` is the viewer's own photo action at every size — its click opens the photo picker, so `onClick` belongs on explicit references.
308
+
296
309
  **The current viewer's pill is system chrome, not app UI.** The platform already shows the current user inside the Vibes Switch that opens from the logo, so don't add a no-prop `<ViewerTag />` as a header pill just to show who's signed in; reach for `userHandle` to render someone else instead. To *ask* an anonymous visitor to sign in, use `requestLogin()` and your own copy (see **Asking a visitor to sign in**) — that ask belongs at the moment of value, which is a place only your app knows.
297
310
 
298
311
  **The one in-app reason to render a no-prop `<ViewerTag />` is inline avatar self-edit.** A no-prop tag shows the signed-in viewer a dashed edit ring that lets them change their _own_ avatar in place, and that works for **every** signed-in viewer — the Switch's avatar editing is owner-only. So if your app wants any member (not just the owner) to update their photo without leaving the app, render a guarded `{viewer && <ViewerTag />}` for that — otherwise leave the current-viewer pill to the Switch.
@@ -284,6 +284,30 @@ Keep the guest's composed text across sign-in. Draft input lives in component st
284
284
  <ViewerTag userHandle={member.userHandle} className="mt-1" />
285
285
  ```
286
286
 
287
+ **Tapping a tag opens that handle's profile.** Anywhere a ViewerTag shows, a tap opens that handle's profile — pass `onClick` and bind the handle the tag displays. The app owns the navigation: it binds the displayed handle and chooses the profile view.
288
+
289
+ ```jsx
290
+ const { ViewerTag } = useViewer();
291
+ const [profileHandle, setProfileHandle] = React.useState(null);
292
+
293
+ {/* Pass the handle you render: a tap opens that handle's profile. */}
294
+ <ViewerTag userHandle={member.userHandle} onClick={() => setProfileHandle(member.userHandle)} />
295
+ {profileHandle && <ProfileView handle={profileHandle} />}
296
+ ```
297
+
298
+ Opening a profile follows nobody and fetches nothing on its own — follow stays behind its own button, and the profile view reads what it needs. The tap carries the handle the tag shows, so each row opens its own person.
299
+
300
+ **Hero avatars render natively.** `size` draws the avatar circle at that diameter with the badge and initial in proportion, and `avatarOnly` drops the handle text — and the pill chrome with it, so the header is the circle itself — for headers, pins and stacks. Both work with and without a profile action:
301
+
302
+ ```jsx
303
+ {/* Profile header: big circle, no handle text, still one native button. */}
304
+ <ViewerTag userHandle={profileHandle} size={120} avatarOnly onClick={() => setProfileHandle(profileHandle)} />
305
+ ```
306
+
307
+ Give the tag its profile action and the clickable shape needs no wrapper. The tag is already one native button with its accessible name, so it answers keyboard and screen readers as written — `size` and `avatarOnly` shape the header, and a plain tag without `onClick` stays a quiet span.
308
+
309
+ **The no-prop tag is the viewer's own photo action.** A no-prop `<ViewerTag />` offers its avatar upload at every size, avatar-only included — its click opens the photo picker, so `onClick` belongs on explicit references. An explicit `userHandle` is always a plain reference, even when it names the viewer.
310
+
287
311
  **The current viewer's pill is system chrome, not app UI.** The platform already shows the current user inside the Vibes Switch that opens from the logo, so don't add a no-prop `<ViewerTag />` as a header pill just to show who's signed in; reach for `userHandle` to render someone else instead. To *ask* an anonymous visitor to sign in, use `requestLogin()` and your own copy (see **Asking a visitor to sign in**) — that ask belongs at the moment of value, which is a place only your app knows.
288
312
 
289
313
  **The one in-app reason to render a no-prop `<ViewerTag />` is inline avatar self-edit.** A no-prop tag shows the signed-in viewer a dashed edit ring that lets them change their _own_ avatar in place, and that works for **every** signed-in viewer — the Switch's avatar editing is owner-only. So if your app wants any member (not just the owner) to update their photo without leaving the app, render a guarded `{viewer && <ViewerTag />}` for that — otherwise leave the current-viewer pill to the Switch.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/prompts",
3
- "version": "14.3.45",
3
+ "version": "14.3.47",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "exports": {
@@ -37,9 +37,9 @@
37
37
  "license": "Apache-2.0",
38
38
  "dependencies": {
39
39
  "@adviser/cement": "~0.5.34",
40
- "@vibes.diy/call-ai-v2": "14.3.45",
41
- "@vibes.diy/identity": "14.3.45",
42
- "@vibes.diy/use-vibes-types": "14.3.45",
40
+ "@vibes.diy/call-ai-v2": "14.3.47",
41
+ "@vibes.diy/identity": "14.3.47",
42
+ "@vibes.diy/use-vibes-types": "14.3.47",
43
43
  "arktype": "~2.2.3",
44
44
  "json-schema-faker": "~0.6.3"
45
45
  },
@@ -116,5 +116,6 @@ Draft note: the owner's corner will want sign-in rules and an email on new notes
116
116
  - **The named interaction works end to end**: the person's sentence names it, and the draft builds that and only that, with realistic data. Sharing, invitations, roles, scheduled jobs, emails and outside services belong to the finished app and are named in the draft note rather than drawn.
117
117
  - **Seed content** is realistic and specific to the app's world, with a `key` per item and the exact fields the app reads.
118
118
  - **Utilities the theme backs** (`bg-background`, `bg-card text-card-foreground`, `bg-primary text-primary-foreground`, `text-muted-foreground`, `rounded-lg`, `shadow-md`, spacing like `p-6`, `gap-4`, `mt-8`); the look brief below says how the page is composed.
119
+ - **Tapping a person opens their profile**: `<ViewerTag userHandle={m.userHandle} onClick={() => setProfile(m.userHandle)} />` binds the handle the tag shows, and a hero header is `<ViewerTag userHandle={profile} size={120} avatarOnly />` — the tag itself is the button, drawn natively. Opening a profile follows nobody.
119
120
 
120
121
  {{CONCATENATED_LLMS}}