@vibes.diy/prompts 14.3.20 → 14.3.21
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.
- package/llms/access.md +40 -49
- package/llms/backend.md +41 -27
- package/llms/bluesky.md +4 -2
- package/llms/calendar.md +4 -2
- package/llms/callai.initial.md +2 -1
- package/llms/callai.md +4 -2
- package/llms/connections.md +8 -4
- package/llms/create-vibe.md +4 -2
- package/llms/d3.md +2 -1
- package/llms/fireproof.initial.md +16 -29
- package/llms/fireproof.md +21 -32
- package/llms/image-gen.initial.md +2 -4
- package/llms/image-gen.md +3 -5
- package/llms/p5.md +2 -3
- package/llms/spotify.md +4 -2
- package/llms/three-js.md +2 -3
- package/llms/use-vibe.md +2 -1
- package/llms/use-viewer.initial.md +5 -10
- package/llms/use-viewer.md +6 -11
- package/llms/webxr.md +2 -1
- package/llms/youtube.md +4 -2
- package/package.json +4 -4
- package/recovery-stitch-addendum.md +3 -2
- package/system-prompt-initial-oneshot.md +14 -6
- package/system-prompt-initial.md +13 -5
- package/system-prompt.md +32 -24
|
@@ -47,7 +47,8 @@ Wire these visible actions in the first working app, using its own record names.
|
|
|
47
47
|
|
|
48
48
|
With the callai skill available, submitting words extracts and normalizes every task they name, then immediately saves one document per task. The saved task is the confirmation and remains editable, with Undo beside the intake after each save. The parent keeps the ids from the last creation or the previous version from an edit, so intake and saved-detail editors share one Undo action. `useLiveQuery` keeps saved tasks visible; `useDocument` supplies the detail editor only after a record exists. For a plain message whose text is already the whole record, save that text directly.
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
### `App.jsx`
|
|
51
|
+
```jsx
|
|
51
52
|
import React, { useState } from "react";
|
|
52
53
|
import { callAI } from "call-ai";
|
|
53
54
|
import { useFireproof } from "use-fireproof";
|
|
@@ -350,8 +351,7 @@ Don't stamp `Date.now()` or other changing values into seed documents — that m
|
|
|
350
351
|
|
|
351
352
|
To update an existing document from a click handler or callback, use `database.put()` directly. Never call `useDocument` inside an event handler — that violates React's Rules of Hooks. Adding a toggle to list items:
|
|
352
353
|
|
|
353
|
-
App.jsx
|
|
354
|
-
|
|
354
|
+
### `App.jsx`
|
|
355
355
|
```jsx
|
|
356
356
|
<<<<<<< SEARCH
|
|
357
357
|
const { useDocument, useLiveQuery } = useFireproof("myLedger");
|
|
@@ -360,8 +360,7 @@ App.jsx
|
|
|
360
360
|
>>>>>>> REPLACE
|
|
361
361
|
```
|
|
362
362
|
|
|
363
|
-
App.jsx
|
|
364
|
-
|
|
363
|
+
### `App.jsx`
|
|
365
364
|
```jsx
|
|
366
365
|
<<<<<<< SEARCH
|
|
367
366
|
<li key={doc._id}>{doc.text}</li>
|
|
@@ -381,8 +380,7 @@ Never call hooks inside handlers — `const { doc, save } = useDocument({ _id: i
|
|
|
381
380
|
|
|
382
381
|
A continuous control (slider, drag, color picker, live-typed text bound to one doc) fires many events in quick succession. **Never call `database.put()` or `save()` on every `onChange`** — that floods the server with rapid concurrent writes to the same `_id`, which collide on the per-document sequence and get rejected (`Failed to put document …`). Instead, `merge()` locally on each event to keep the UI live, and `save()` once when the interaction commits (`onPointerUp`, `onBlur`, `onChange` for a range input's final value, or a debounced trailing call). Editing a single doc with a slider:
|
|
383
382
|
|
|
384
|
-
App.jsx
|
|
385
|
-
|
|
383
|
+
### `App.jsx`
|
|
386
384
|
```jsx
|
|
387
385
|
<<<<<<< SEARCH
|
|
388
386
|
const { useDocument, useLiveQuery, database } = useFireproof("myLedger");
|
|
@@ -394,8 +392,7 @@ App.jsx
|
|
|
394
392
|
>>>>>>> REPLACE
|
|
395
393
|
```
|
|
396
394
|
|
|
397
|
-
App.jsx
|
|
398
|
-
|
|
395
|
+
### `App.jsx`
|
|
399
396
|
```jsx
|
|
400
397
|
<<<<<<< SEARCH
|
|
401
398
|
<h3>Recent Documents</h3>
|
|
@@ -423,8 +420,7 @@ Data is queried by sorted indexes defined by the application. Sort by strings, n
|
|
|
423
420
|
|
|
424
421
|
Passing a string to `useLiveQuery` will index by that field. Use the key argument to filter by a specific value, or range for bounded queries. Switching from temporal to filtered query:
|
|
425
422
|
|
|
426
|
-
App.jsx
|
|
427
|
-
|
|
423
|
+
### `App.jsx`
|
|
428
424
|
```jsx
|
|
429
425
|
<<<<<<< SEARCH
|
|
430
426
|
const { docs } = useLiveQuery("_id", { descending: true, limit: 100 });
|
|
@@ -436,8 +432,7 @@ App.jsx
|
|
|
436
432
|
|
|
437
433
|
Or query a numeric range:
|
|
438
434
|
|
|
439
|
-
App.jsx
|
|
440
|
-
|
|
435
|
+
### `App.jsx`
|
|
441
436
|
```jsx
|
|
442
437
|
<<<<<<< SEARCH
|
|
443
438
|
const { docs } = useLiveQuery("agentName", { key: "agent-1" });
|
|
@@ -451,8 +446,7 @@ App.jsx
|
|
|
451
446
|
|
|
452
447
|
Documents can be updated by multiple clients, and synced later. To create an event counter, don't increment a number on a single doc, instead write a small document per counted event, and query them with an index:
|
|
453
448
|
|
|
454
|
-
App.jsx
|
|
455
|
-
|
|
449
|
+
### `App.jsx`
|
|
456
450
|
```jsx
|
|
457
451
|
<<<<<<< SEARCH
|
|
458
452
|
const { docs } = useLiveQuery("agentRating", { range: [3, 5] });
|
|
@@ -477,8 +471,7 @@ This pattern ensures the count is accurate even during sync — each event is it
|
|
|
477
471
|
|
|
478
472
|
Use a custom index function to normalize and transform document data, for instance if you have both new and old document versions in your app:
|
|
479
473
|
|
|
480
|
-
App.jsx
|
|
481
|
-
|
|
474
|
+
### `App.jsx`
|
|
482
475
|
```jsx
|
|
483
476
|
<<<<<<< SEARCH
|
|
484
477
|
// The counter's scope: the board being viewed and who is counting (useVibe from "use-vibes", as above).
|
|
@@ -507,8 +500,7 @@ App.jsx
|
|
|
507
500
|
|
|
508
501
|
When you want to group rows easily, you can use an array index key. This is great for grouping records by year/month/day or other paths. The prefix query is a shorthand for a key range:
|
|
509
502
|
|
|
510
|
-
App.jsx
|
|
511
|
-
|
|
503
|
+
### `App.jsx`
|
|
512
504
|
```jsx
|
|
513
505
|
<<<<<<< SEARCH
|
|
514
506
|
const { docs } = useLiveQuery(
|
|
@@ -534,8 +526,7 @@ App.jsx
|
|
|
534
526
|
|
|
535
527
|
Sortable lists are a common pattern. Use evenly spaced positions and insert between items using midpoint calculation:
|
|
536
528
|
|
|
537
|
-
App.jsx
|
|
538
|
-
|
|
529
|
+
### `App.jsx`
|
|
539
530
|
```jsx
|
|
540
531
|
<<<<<<< SEARCH
|
|
541
532
|
const { docs } = useLiveQuery(
|
|
@@ -595,8 +586,7 @@ Data lives in a local replica (IndexedDB) that the app reads and writes instantl
|
|
|
595
586
|
|
|
596
587
|
You can use the core API outside a React component — in a plain script or a helper module. Instead of hooks, import the core API directly:
|
|
597
588
|
|
|
598
|
-
App.jsx
|
|
599
|
-
|
|
589
|
+
### `App.jsx`
|
|
600
590
|
```jsx
|
|
601
591
|
<<<<<<< SEARCH
|
|
602
592
|
import React from "react";
|
|
@@ -634,8 +624,7 @@ A save that carries `_files` uploads the bytes before the doc lands, so unlike a
|
|
|
634
624
|
|
|
635
625
|
Building an image uploader with `_files`:
|
|
636
626
|
|
|
637
|
-
App.jsx
|
|
638
|
-
|
|
627
|
+
### `App.jsx`
|
|
639
628
|
```jsx
|
|
640
629
|
import React from "react";
|
|
641
630
|
import { useFireproof } from "use-fireproof";
|
|
@@ -716,8 +705,7 @@ For multi-file uploads (e.g. `<input multiple>`), build the `_files` map keyed b
|
|
|
716
705
|
|
|
717
706
|
Adding multi-file support:
|
|
718
707
|
|
|
719
|
-
App.jsx
|
|
720
|
-
|
|
708
|
+
### `App.jsx`
|
|
721
709
|
```jsx
|
|
722
710
|
<<<<<<< SEARCH
|
|
723
711
|
const onPickFile = (e) => {
|
|
@@ -745,8 +733,7 @@ App.jsx
|
|
|
745
733
|
|
|
746
734
|
You can use React's `useState` to manage validation states and error messages. Validate inputs at the UI level before allowing submission. Adding validation to the uploader:
|
|
747
735
|
|
|
748
|
-
App.jsx
|
|
749
|
-
|
|
736
|
+
### `App.jsx`
|
|
750
737
|
```jsx
|
|
751
738
|
<<<<<<< SEARCH
|
|
752
739
|
const onSubmit = async (e) => {
|
package/llms/fireproof.md
CHANGED
|
@@ -47,7 +47,8 @@ Wire these visible actions in the first working app, using its own record names.
|
|
|
47
47
|
|
|
48
48
|
With the callai skill available, submitting words extracts and normalizes every task they name, then immediately saves one document per task. The saved task is the confirmation and remains editable, with Undo beside the intake after each save. The parent keeps the ids from the last creation or the previous version from an edit, so intake and saved-detail editors share one Undo action. `useLiveQuery` keeps saved tasks visible; `useDocument` supplies the detail editor only after a record exists. For a plain message whose text is already the whole record, save that text directly.
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
### `App.jsx`
|
|
51
|
+
```jsx
|
|
51
52
|
import React, { useState } from "react";
|
|
52
53
|
import { callAI } from "call-ai";
|
|
53
54
|
import { useFireproof } from "use-fireproof";
|
|
@@ -278,7 +279,8 @@ When an app ships with default content — starter slides, template rows, exampl
|
|
|
278
279
|
|
|
279
280
|
The trap is the live-query empty state. `useLiveQuery` renders empty before data arrives, so `docs.length === 0` is briefly true on **every** fresh load — and a `useRef`/`useState` "already seeded" flag only guards the current session, never the next reload, a second device, or another collaborator. With **auto-generated** `_id`s, each of those re-seeds the full set and duplicate copies pile up without bound. Deterministic `_id`s collapse every re-seed back onto the same N documents.
|
|
280
281
|
|
|
281
|
-
|
|
282
|
+
### `App.jsx`
|
|
283
|
+
```jsx
|
|
282
284
|
import React from "react";
|
|
283
285
|
import { useFireproof } from "use-fireproof";
|
|
284
286
|
import { useVibe } from "use-vibes";
|
|
@@ -319,8 +321,7 @@ Don't stamp `Date.now()` or other changing values into seed documents — that m
|
|
|
319
321
|
|
|
320
322
|
To update an existing document from a click handler or callback, use `database.put()` directly. Never call `useDocument` inside an event handler — that violates React's Rules of Hooks. Adding a toggle to list items:
|
|
321
323
|
|
|
322
|
-
App.jsx
|
|
323
|
-
|
|
324
|
+
### `App.jsx`
|
|
324
325
|
```jsx
|
|
325
326
|
<<<<<<< SEARCH
|
|
326
327
|
const { useDocument, useLiveQuery } = useFireproof("myLedger");
|
|
@@ -329,8 +330,7 @@ App.jsx
|
|
|
329
330
|
>>>>>>> REPLACE
|
|
330
331
|
```
|
|
331
332
|
|
|
332
|
-
App.jsx
|
|
333
|
-
|
|
333
|
+
### `App.jsx`
|
|
334
334
|
```jsx
|
|
335
335
|
<<<<<<< SEARCH
|
|
336
336
|
<li key={doc._id}>{doc.text}</li>
|
|
@@ -350,8 +350,7 @@ Never call hooks inside handlers — `const { doc, save } = useDocument({ _id: i
|
|
|
350
350
|
|
|
351
351
|
A continuous control (slider, drag, color picker, live-typed text bound to one doc) fires many events in quick succession. **Never call `database.put()` or `save()` on every `onChange`** — that floods the server with rapid concurrent writes to the same `_id`, which collide on the per-document sequence and get rejected (`Failed to put document …`). Instead, `merge()` locally on each event to keep the UI live, and `save()` once when the interaction commits (`onPointerUp`, `onBlur`, `onChange` for a range input's final value, or a debounced trailing call). Editing a single doc with a slider:
|
|
352
352
|
|
|
353
|
-
App.jsx
|
|
354
|
-
|
|
353
|
+
### `App.jsx`
|
|
355
354
|
```jsx
|
|
356
355
|
<<<<<<< SEARCH
|
|
357
356
|
const { useDocument, useLiveQuery, database } = useFireproof("myLedger");
|
|
@@ -363,8 +362,7 @@ App.jsx
|
|
|
363
362
|
>>>>>>> REPLACE
|
|
364
363
|
```
|
|
365
364
|
|
|
366
|
-
App.jsx
|
|
367
|
-
|
|
365
|
+
### `App.jsx`
|
|
368
366
|
```jsx
|
|
369
367
|
<<<<<<< SEARCH
|
|
370
368
|
<h3>Recent Documents</h3>
|
|
@@ -392,8 +390,7 @@ Data is queried by sorted indexes defined by the application. Sort by strings, n
|
|
|
392
390
|
|
|
393
391
|
Passing a string to `useLiveQuery` will index by that field. Use the key argument to filter by a specific value, or range for bounded queries. Switching from temporal to filtered query:
|
|
394
392
|
|
|
395
|
-
App.jsx
|
|
396
|
-
|
|
393
|
+
### `App.jsx`
|
|
397
394
|
```jsx
|
|
398
395
|
<<<<<<< SEARCH
|
|
399
396
|
const { docs } = useLiveQuery("_id", { descending: true, limit: 100 });
|
|
@@ -405,8 +402,7 @@ App.jsx
|
|
|
405
402
|
|
|
406
403
|
Or query a numeric range:
|
|
407
404
|
|
|
408
|
-
App.jsx
|
|
409
|
-
|
|
405
|
+
### `App.jsx`
|
|
410
406
|
```jsx
|
|
411
407
|
<<<<<<< SEARCH
|
|
412
408
|
const { docs } = useLiveQuery("agentName", { key: "agent-1" });
|
|
@@ -420,8 +416,7 @@ App.jsx
|
|
|
420
416
|
|
|
421
417
|
Documents can be updated by multiple clients, and synced later. To create an event counter, don't increment a number on a single doc, instead write a small document per counted event, and query them with an index:
|
|
422
418
|
|
|
423
|
-
App.jsx
|
|
424
|
-
|
|
419
|
+
### `App.jsx`
|
|
425
420
|
```jsx
|
|
426
421
|
<<<<<<< SEARCH
|
|
427
422
|
const { docs } = useLiveQuery("agentRating", { range: [3, 5] });
|
|
@@ -441,8 +436,7 @@ This pattern ensures the count is accurate even during sync — each event is it
|
|
|
441
436
|
|
|
442
437
|
Use a custom index function to normalize and transform document data, for instance if you have both new and old document versions in your app:
|
|
443
438
|
|
|
444
|
-
App.jsx
|
|
445
|
-
|
|
439
|
+
### `App.jsx`
|
|
446
440
|
```jsx
|
|
447
441
|
<<<<<<< SEARCH
|
|
448
442
|
const { docs } = useLiveQuery("counter", { key: "my-event-name" });
|
|
@@ -466,8 +460,7 @@ App.jsx
|
|
|
466
460
|
|
|
467
461
|
When you want to group rows easily, you can use an array index key. This is great for grouping records by year/month/day or other paths. The prefix query is a shorthand for a key range:
|
|
468
462
|
|
|
469
|
-
App.jsx
|
|
470
|
-
|
|
463
|
+
### `App.jsx`
|
|
471
464
|
```jsx
|
|
472
465
|
<<<<<<< SEARCH
|
|
473
466
|
const { docs } = useLiveQuery(
|
|
@@ -493,8 +486,7 @@ App.jsx
|
|
|
493
486
|
|
|
494
487
|
Sortable lists are a common pattern. Use evenly spaced positions and insert between items using midpoint calculation:
|
|
495
488
|
|
|
496
|
-
App.jsx
|
|
497
|
-
|
|
489
|
+
### `App.jsx`
|
|
498
490
|
```jsx
|
|
499
491
|
<<<<<<< SEARCH
|
|
500
492
|
const { docs } = useLiveQuery(
|
|
@@ -557,8 +549,7 @@ Data lives in a local replica (IndexedDB) that the app reads and writes instantl
|
|
|
557
549
|
|
|
558
550
|
You can use the core API in HTML or on the backend. Instead of hooks, import the core API directly:
|
|
559
551
|
|
|
560
|
-
App.jsx
|
|
561
|
-
|
|
552
|
+
### `App.jsx`
|
|
562
553
|
```jsx
|
|
563
554
|
<<<<<<< SEARCH
|
|
564
555
|
import React from "react";
|
|
@@ -608,9 +599,8 @@ A save that carries `_files` uploads the bytes before the doc lands, so unlike a
|
|
|
608
599
|
|
|
609
600
|
Building an image uploader with `_files`:
|
|
610
601
|
|
|
611
|
-
App.jsx
|
|
612
|
-
|
|
613
|
-
```jsx file=App.jsx
|
|
602
|
+
### `App.jsx`
|
|
603
|
+
```jsx
|
|
614
604
|
import React from "react";
|
|
615
605
|
import { useFireproof } from "use-fireproof";
|
|
616
606
|
import { Button, Card, CardContent, Input, Label } from "@vibes.diy/look";
|
|
@@ -690,8 +680,7 @@ For multi-file uploads (e.g. `<input multiple>`), build the `_files` map keyed b
|
|
|
690
680
|
|
|
691
681
|
Adding multi-file support:
|
|
692
682
|
|
|
693
|
-
App.jsx
|
|
694
|
-
|
|
683
|
+
### `App.jsx`
|
|
695
684
|
```jsx
|
|
696
685
|
<<<<<<< SEARCH
|
|
697
686
|
const onPickFile = (e) => {
|
|
@@ -719,8 +708,7 @@ App.jsx
|
|
|
719
708
|
|
|
720
709
|
You can use React's `useState` to manage validation states and error messages. Validate inputs at the UI level before allowing submission. Adding validation to the uploader:
|
|
721
710
|
|
|
722
|
-
App.jsx
|
|
723
|
-
|
|
711
|
+
### `App.jsx`
|
|
724
712
|
```jsx
|
|
725
713
|
<<<<<<< SEARCH
|
|
726
714
|
const onSubmit = async (e) => {
|
|
@@ -747,7 +735,8 @@ App.jsx
|
|
|
747
735
|
|
|
748
736
|
Code listing for todo tracker App.jsx. Note the code ordering: hooks, then handlers, then classNames right before JSX.
|
|
749
737
|
|
|
750
|
-
|
|
738
|
+
### `App.jsx`
|
|
739
|
+
```js
|
|
751
740
|
import React from "react";
|
|
752
741
|
import { useFireproof } from "use-fireproof";
|
|
753
742
|
import { Button, Card, CardContent, Input, Label } from "@vibes.diy/look";
|
|
@@ -8,8 +8,7 @@ Generate and edit images from a text prompt. Each generated image lands as a fil
|
|
|
8
8
|
|
|
9
9
|
Start with a minimal image generation component:
|
|
10
10
|
|
|
11
|
-
App.jsx
|
|
12
|
-
|
|
11
|
+
### `App.jsx`
|
|
13
12
|
```jsx
|
|
14
13
|
import React from "react";
|
|
15
14
|
import { useFireproof } from "use-fireproof";
|
|
@@ -61,8 +60,7 @@ This is the same `_files`-shape contract documented in `fireproof.md`'s "Working
|
|
|
61
60
|
|
|
62
61
|
Pass a `File` object via `images` to run img2img. Adding a file picker that feeds into ImgGen:
|
|
63
62
|
|
|
64
|
-
App.jsx
|
|
65
|
-
|
|
63
|
+
### `App.jsx`
|
|
66
64
|
```jsx
|
|
67
65
|
<<<<<<< SEARCH
|
|
68
66
|
export default function App() {
|
package/llms/image-gen.md
CHANGED
|
@@ -8,9 +8,8 @@ Generate and edit images from a text prompt. Each generated image lands as a fil
|
|
|
8
8
|
|
|
9
9
|
Start with a minimal image generation component:
|
|
10
10
|
|
|
11
|
-
App.jsx
|
|
12
|
-
|
|
13
|
-
```jsx file=App.jsx
|
|
11
|
+
### `App.jsx`
|
|
12
|
+
```jsx
|
|
14
13
|
import React from "react";
|
|
15
14
|
import { useFireproof } from "use-fireproof";
|
|
16
15
|
import { ImgGen } from "use-vibes";
|
|
@@ -61,8 +60,7 @@ This is the same `_files`-shape contract documented in `fireproof.md`'s "Working
|
|
|
61
60
|
|
|
62
61
|
Pass a `File` object via `images` to run img2img. Adding a file picker that feeds into ImgGen:
|
|
63
62
|
|
|
64
|
-
App.jsx
|
|
65
|
-
|
|
63
|
+
### `App.jsx`
|
|
66
64
|
```jsx
|
|
67
65
|
<<<<<<< SEARCH
|
|
68
66
|
export default function App() {
|
package/llms/p5.md
CHANGED
|
@@ -20,9 +20,8 @@ factory function that receives the host element, the instance is built once in
|
|
|
20
20
|
one `useEffect([])`, the canvas is sized from the host, and the cleanup removes
|
|
21
21
|
the instance so remounts do not leak a second draw loop.
|
|
22
22
|
|
|
23
|
-
App.jsx
|
|
24
|
-
|
|
25
|
-
```jsx file=App.jsx
|
|
23
|
+
### `App.jsx`
|
|
24
|
+
```jsx
|
|
26
25
|
import React from "react";
|
|
27
26
|
import p5 from "https://esm.sh/p5@1.11.13";
|
|
28
27
|
import { Button } from "@vibes.diy/look";
|
package/llms/spotify.md
CHANGED
|
@@ -159,7 +159,8 @@ when the route names it.
|
|
|
159
159
|
|
|
160
160
|
## Complete backend.js
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
### `backend.js`
|
|
163
|
+
```js app=spotify-browser
|
|
163
164
|
const TOKEN_URL = "https://accounts.spotify.com/api/token";
|
|
164
165
|
const API = "https://api.spotify.com/v1";
|
|
165
166
|
|
|
@@ -302,7 +303,8 @@ function artistRow(a) {
|
|
|
302
303
|
|
|
303
304
|
## App.jsx sketch
|
|
304
305
|
|
|
305
|
-
|
|
306
|
+
### `App.jsx`
|
|
307
|
+
```jsx app=spotify-browser
|
|
306
308
|
import React, { useState } from "react";
|
|
307
309
|
|
|
308
310
|
const SETUP_STEPS = [
|
package/llms/three-js.md
CHANGED
|
@@ -15,9 +15,8 @@ one `useEffect([])`, the animation loop is a `requestAnimationFrame`, resize
|
|
|
15
15
|
keeps the camera aspect correct, and the cleanup disposes geometry, material,
|
|
16
16
|
and renderer so remounts don't leak GPU memory.
|
|
17
17
|
|
|
18
|
-
App.jsx
|
|
19
|
-
|
|
20
|
-
```jsx file=App.jsx
|
|
18
|
+
### `App.jsx`
|
|
19
|
+
```jsx
|
|
21
20
|
import React from "react";
|
|
22
21
|
import * as THREE from "three";
|
|
23
22
|
|
package/llms/use-vibe.md
CHANGED
|
@@ -26,7 +26,8 @@ Never stamp author fields from `me` while the verdict is pending — `me` is nul
|
|
|
26
26
|
|
|
27
27
|
Gate every write affordance on `can.*`. Hold it while `pending`, and write your own copy when denied. Never branch write permission on `viewer`, `access.hasRole()`/`access.hasChannel()`, or document fields — those drift from what `access.js` actually does. Rendering **other** users (authors, rosters) is `useViewer()`'s `<ViewerTag userHandle={...} />`, not `useVibe`. The current viewer's own pill and the "signed in as" label are system chrome in the Vibes Switch (the logo) — don't build them into the app. Asking an anonymous visitor to sign in is a different thing and it IS yours: `useViewer().requestLogin()`, at the moment their work becomes worth keeping (see use-viewer docs). A resolved denial is one such moment — write the sign-in copy in your app's own words and wire it to that callable, never to a sentence about the logo. (The one exception is inline avatar self-edit: a guarded no-prop `{viewer && <ViewerTag />}` lets any signed-in member change their own photo in place — see use-viewer docs.)
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
### `App.jsx`
|
|
30
|
+
```jsx
|
|
30
31
|
import { useVibe } from "use-vibes";
|
|
31
32
|
import { Button, Input, Skeleton } from "@vibes.diy/look";
|
|
32
33
|
|
|
@@ -12,8 +12,7 @@ Use `useViewer()` to render **other** people's identity — comment authors, ros
|
|
|
12
12
|
|
|
13
13
|
Start with a minimal component that reads the viewer identity. You don't render a current-user pill — that lives in the Vibes Switch (click the logo). Branch on `viewer` for any welcome/empty copy. Note there is **no sign-in button here**: the ask belongs at the moment the visitor has made something worth keeping, not on arrival — see **Asking a visitor to sign in** below.
|
|
14
14
|
|
|
15
|
-
App.jsx
|
|
16
|
-
|
|
15
|
+
### `App.jsx`
|
|
17
16
|
```jsx
|
|
18
17
|
import React from "react";
|
|
19
18
|
import { useFireproof } from "use-fireproof";
|
|
@@ -50,8 +49,7 @@ export default function App() {
|
|
|
50
49
|
|
|
51
50
|
Gate the comment form on `useVibe("comments").can` — not on `viewer`. The current viewer never needs a pill here (that's in the Vibes Switch); just render the gated form, and on a denial a sentence in your app's own words — `reason` is a machine token that informs that sentence and is never printed:
|
|
52
51
|
|
|
53
|
-
App.jsx
|
|
54
|
-
|
|
52
|
+
### `App.jsx`
|
|
55
53
|
```jsx
|
|
56
54
|
<<<<<<< SEARCH
|
|
57
55
|
import { useViewer } from "use-vibes";
|
|
@@ -60,8 +58,7 @@ import { useViewer, useVibe } from "use-vibes";
|
|
|
60
58
|
>>>>>>> REPLACE
|
|
61
59
|
```
|
|
62
60
|
|
|
63
|
-
App.jsx
|
|
64
|
-
|
|
61
|
+
### `App.jsx`
|
|
65
62
|
```jsx
|
|
66
63
|
<<<<<<< SEARCH
|
|
67
64
|
const { viewer, isViewerPending } = useViewer();
|
|
@@ -71,8 +68,7 @@ App.jsx
|
|
|
71
68
|
>>>>>>> REPLACE
|
|
72
69
|
```
|
|
73
70
|
|
|
74
|
-
App.jsx
|
|
75
|
-
|
|
71
|
+
### `App.jsx`
|
|
76
72
|
```jsx
|
|
77
73
|
<<<<<<< SEARCH
|
|
78
74
|
{viewer ? (
|
|
@@ -105,8 +101,7 @@ When one user writes content others will see (comments, posts, messages), **stam
|
|
|
105
101
|
|
|
106
102
|
Wire up a full comment thread with Fireproof and viewer attribution:
|
|
107
103
|
|
|
108
|
-
App.jsx
|
|
109
|
-
|
|
104
|
+
### `App.jsx`
|
|
110
105
|
```jsx
|
|
111
106
|
<<<<<<< SEARCH
|
|
112
107
|
import { useViewer, useVibe } from "use-vibes";
|
package/llms/use-viewer.md
CHANGED
|
@@ -12,9 +12,8 @@ Use `useViewer()` to render **other** people's identity — comment authors, ros
|
|
|
12
12
|
|
|
13
13
|
Start with a minimal component that reads the viewer identity. You don't render a current-user pill — that lives in the Vibes Switch (click the logo). Branch on `viewer` for any welcome/empty copy. Note there is **no sign-in button here**: the ask belongs at the moment the visitor has made something worth keeping, not on arrival — see **Asking a visitor to sign in** below.
|
|
14
14
|
|
|
15
|
-
App.jsx
|
|
16
|
-
|
|
17
|
-
```jsx file=App.jsx
|
|
15
|
+
### `App.jsx`
|
|
16
|
+
```jsx
|
|
18
17
|
import React from "react";
|
|
19
18
|
import { useFireproof } from "use-fireproof";
|
|
20
19
|
import { useViewer } from "use-vibes";
|
|
@@ -51,8 +50,7 @@ export default function App() {
|
|
|
51
50
|
|
|
52
51
|
Gate the comment form on `useVibe("comments").can` — not on `viewer`. The current viewer never needs a pill here (that's in the Vibes Switch); just render the gated form, and on a denial a sentence in your app's own words — `reason` is a machine token that informs that sentence and is never printed:
|
|
53
52
|
|
|
54
|
-
App.jsx
|
|
55
|
-
|
|
53
|
+
### `App.jsx`
|
|
56
54
|
```jsx
|
|
57
55
|
<<<<<<< SEARCH
|
|
58
56
|
import { useViewer } from "use-vibes";
|
|
@@ -61,8 +59,7 @@ import { useViewer, useVibe } from "use-vibes";
|
|
|
61
59
|
>>>>>>> REPLACE
|
|
62
60
|
```
|
|
63
61
|
|
|
64
|
-
App.jsx
|
|
65
|
-
|
|
62
|
+
### `App.jsx`
|
|
66
63
|
```jsx
|
|
67
64
|
<<<<<<< SEARCH
|
|
68
65
|
const { viewer, isViewerPending } = useViewer();
|
|
@@ -72,8 +69,7 @@ App.jsx
|
|
|
72
69
|
>>>>>>> REPLACE
|
|
73
70
|
```
|
|
74
71
|
|
|
75
|
-
App.jsx
|
|
76
|
-
|
|
72
|
+
### `App.jsx`
|
|
77
73
|
```jsx
|
|
78
74
|
<<<<<<< SEARCH
|
|
79
75
|
{viewer ? (
|
|
@@ -106,8 +102,7 @@ When one user writes content others will see (comments, posts, messages), **stam
|
|
|
106
102
|
|
|
107
103
|
Wire up a full comment thread with Fireproof and viewer attribution:
|
|
108
104
|
|
|
109
|
-
App.jsx
|
|
110
|
-
|
|
105
|
+
### `App.jsx`
|
|
111
106
|
```jsx
|
|
112
107
|
<<<<<<< SEARCH
|
|
113
108
|
import { useViewer, useVibe } from "use-vibes";
|
package/llms/webxr.md
CHANGED
|
@@ -417,7 +417,8 @@ for (let i = 0; i < 200; i++) {
|
|
|
417
417
|
|
|
418
418
|
A floating galaxy of 2000 particles with a custom-shader core sphere, navigable in VR. Session data stored in Fireproof.
|
|
419
419
|
|
|
420
|
-
|
|
420
|
+
### `App.jsx`
|
|
421
|
+
```javascript
|
|
421
422
|
import * as BABYLON from "@babylonjs/core";
|
|
422
423
|
import React, { useEffect, useRef } from "react";
|
|
423
424
|
import { useFireproof } from "use-fireproof";
|
package/llms/youtube.md
CHANGED
|
@@ -250,7 +250,8 @@ nothing they can act on, and the four cases above each have a different fix.
|
|
|
250
250
|
|
|
251
251
|
## Complete backend.js
|
|
252
252
|
|
|
253
|
-
|
|
253
|
+
### `backend.js`
|
|
254
|
+
```js app=youtube-dashboard
|
|
254
255
|
export const config = {
|
|
255
256
|
scheduled: { interval: "1h" },
|
|
256
257
|
// The visitor path below reads the snapshot docs on the fetch lane, which
|
|
@@ -507,7 +508,8 @@ export async function scheduled(event, ctx) {
|
|
|
507
508
|
|
|
508
509
|
## App.jsx sketch
|
|
509
510
|
|
|
510
|
-
|
|
511
|
+
### `App.jsx`
|
|
512
|
+
```jsx app=youtube-dashboard
|
|
511
513
|
import React, { useState } from "react";
|
|
512
514
|
import { useFireproof } from "use-fireproof";
|
|
513
515
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibes.diy/prompts",
|
|
3
|
-
"version": "14.3.
|
|
3
|
+
"version": "14.3.21",
|
|
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.
|
|
41
|
-
"@vibes.diy/identity": "14.3.
|
|
42
|
-
"@vibes.diy/use-vibes-types": "14.3.
|
|
40
|
+
"@vibes.diy/call-ai-v2": "14.3.21",
|
|
41
|
+
"@vibes.diy/identity": "14.3.21",
|
|
42
|
+
"@vibes.diy/use-vibes-types": "14.3.21",
|
|
43
43
|
"arktype": "~2.2.3",
|
|
44
44
|
"json-schema-faker": "~0.6.3"
|
|
45
45
|
},
|
|
@@ -9,5 +9,6 @@ good state to base the rewrite on. Trust it as ground truth for what
|
|
|
9
9
|
already works; do not regress features that are present there.
|
|
10
10
|
|
|
11
11
|
Do not split the rewrite across multiple SEARCH/REPLACE blocks. One
|
|
12
|
-
block, full file, fresh contents.
|
|
13
|
-
|
|
12
|
+
block, full file, fresh contents. A heading naming the file,
|
|
13
|
+
with its path in backticks (### `App.jsx`), then a single fenced ```jsx
|
|
14
|
+
block directly below it with the entire file inside.
|
|
@@ -60,13 +60,22 @@ Before writing code, provide a title and brief description of the app. Then list
|
|
|
60
60
|
|
|
61
61
|
## Output format
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
Name each file in a markdown heading directly above its code block, with the path in backticks:
|
|
64
|
+
|
|
65
|
+
### `App.jsx`
|
|
66
|
+
```jsx
|
|
67
|
+
export default function App() {
|
|
68
|
+
return <main>Hello</main>;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The same heading labels every block a turn emits — `App.jsx` for the React component, `seed.json` for launch content, or a relative path like `components/Feed.jsx` for an additional source file.
|
|
64
73
|
|
|
65
74
|
## Multi-file apps — keep `App.jsx` under ~500 lines
|
|
66
75
|
|
|
67
76
|
The sandbox serves raw ES modules, so `App.jsx` can import local `.js`/`.jsx` files with relative imports (`import Feed from "./components/Feed.jsx"`). Use that to keep `App.jsx` under about 500 lines:
|
|
68
77
|
|
|
69
|
-
- When an app would grow past ~500 lines of `App.jsx`, split it: move feature components into their own files (e.g. `components/Feed.jsx`, one feature per file, `export default`) and import them from `App.jsx`. Emit each new file as its own complete fenced code block
|
|
78
|
+
- When an app would grow past ~500 lines of `App.jsx`, split it: move feature components into their own files (e.g. `components/Feed.jsx`, one feature per file, `export default`) and import them from `App.jsx`. Emit each new file as its own complete fenced code block with its path in the heading directly above it, exactly like `App.jsx`.
|
|
70
79
|
- When editing an app whose `App.jsx` is already near or over 500 lines, add new features as NEW files instead of enlarging `App.jsx`: emit the new component file in full, then a small edit to `App.jsx` that adds the import and renders the component. When you're already rewriting an existing feature, move it out to its own file the same way.
|
|
71
80
|
- `App.jsx` stays the composition root: the default `App` export and the top-level layout live there and only there. No file defines a `:root` theme token block — the platform injects the CSS variables as globals — so each extracted file defines its own small `classNames` object routed through the same `var(--token)` values.
|
|
72
81
|
- Values used by more than one file — constants, option lists, small pure helpers, document-shape literals (e.g. a `STAGES` array or a `CATEGORIES` list) — live in their own small leaf module (e.g. `lib/stages.js`) that both `App.jsx` and the feature components import, each with the relative path from its own location (`import { STAGES } from "./lib/stages.js"` from `App.jsx` at the root, `"../lib/stages.js"` from a file in `components/`). Imports flow one direction: `App.jsx` imports the feature components, and `App.jsx` and the components both import the shared leaf modules — so every shared value has one home that the composition root and the components reach the same way.
|
|
@@ -81,7 +90,7 @@ The sandbox serves raw ES modules, so `App.jsx` can import local `.js`/`.jsx` fi
|
|
|
81
90
|
|
|
82
91
|
Every feature you described above should work when this one block lands. Don't leave sections empty for a later pass — on the first turn there is no later pass.
|
|
83
92
|
|
|
84
|
-
**Split into companion files by default.** Whenever the app has more than a couple of distinct features — and always when the finished app would push `App.jsx` past the ~500-line threshold (see the multi-file rule above) — still lead with one complete `App.jsx` block, but as the composition root: imports, the `classNames` object, layout chrome, and the default `App` export composing the features. Then emit each extracted feature component as its own complete file block (path
|
|
93
|
+
**Split into companion files by default.** Whenever the app has more than a couple of distinct features — and always when the finished app would push `App.jsx` past the ~500-line threshold (see the multi-file rule above) — still lead with one complete `App.jsx` block, but as the composition root: imports, the `classNames` object, layout chrome, and the default `App` export composing the features. Then emit each extracted feature component as its own complete file block (its path heading first, e.g. `components/Feed.jsx`) right after the `App.jsx` block. Every feature still works when the turn's blocks land — the single-block rule means one complete pass per file, never a second pass, not everything crammed into `App.jsx`. Only a genuinely small app (one screen, one or two features) stays single-file.
|
|
85
94
|
- When a write surface needs gating, destructure `useVibe` for the database it writes to — `const { can, ready } = useVibe("<dbName>");`. Only destructure `useViewer` (`const { ViewerTag } = useViewer();`) when you render **other** users — `<ViewerTag userHandle={...} />` for authors/rosters. The current viewer's pill and sign-in live in the Vibes Switch (the logo), so don't add one to your header.
|
|
86
95
|
- **Be creative with the layout, but respect mobile idioms.** Thumb-reachable primary actions, generous tap targets (`min-h-11`), scrollable lists, no hover-only interactions.
|
|
87
96
|
- **For chat or log panels, keep autoscroll on the panel itself.** Use a bounded `max-h-64 overflow-y-auto` container with a ref and move it to the end when entries change:
|
|
@@ -133,12 +142,11 @@ When the user's prompt hands you **concrete example data** — an image of items
|
|
|
133
142
|
|
|
134
143
|
**Required starting state belongs to the app's working initialization.** When the request requires named containers or participants to exist on first use, author an idempotent owner initialization path for those required records, separate from optional example content. Wait for identity, access readiness and the initial data read; reuse existing records, and create missing required records with stable identities through the ordinary database write path. Check each complete intended document with `can.create`, await its write, and show an actionable setup error if it fails. Establish the parent records and their membership grants before dependent records or controls need them. Keep existing user edits on later visits. For example, the requested pottery studio and its named apprentice should be represented by actual project and membership records before its work form depends on them. A name present only in `seed.json` describes an offered import, not an existing grant.
|
|
135
144
|
|
|
136
|
-
Emit it
|
|
145
|
+
Emit it like every other file: the heading naming `seed.json`, then a fenced ```json block directly below it, as in the shape below. Emit it **last**, after `App.jsx` and any companion feature files.
|
|
137
146
|
|
|
138
147
|
Shape — a JSON **object keyed by database name** (the same names you pass to `useFireproof`), each value an **array of items**:
|
|
139
148
|
|
|
140
|
-
seed.json
|
|
141
|
-
|
|
149
|
+
### `seed.json`
|
|
142
150
|
```json
|
|
143
151
|
{
|
|
144
152
|
"cardSetMaker": [
|