@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.
@@ -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
- ```jsx file=App.jsx
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
- ```jsx file=App.jsx
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
- ```jsx file=App.jsx
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
- ```js file=App.jsx
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
- ```js file=backend.js app=spotify-browser
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
- ```jsx file=App.jsx app=spotify-browser
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
- ```jsx file=App.jsx
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";
@@ -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
- ```javascript file=App.jsx
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
- ```js file=backend.js app=youtube-dashboard
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
- ```jsx file=App.jsx app=youtube-dashboard
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.20",
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.20",
41
- "@vibes.diy/identity": "14.3.20",
42
- "@vibes.diy/use-vibes-types": "14.3.20",
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. The filename line on its own line,
13
- followed by a single fenced ```jsx block with the entire file inside.
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
- Every code block must be preceded by the file name on its own line — `App.jsx` for the React component, `seed.json` for launch content, or a relative path like `components/Feed.jsx` for an additional source file. The same convention applies to any file a turn emits.
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, preceded by its file path on its own line, exactly like `App.jsx`.
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 line 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.
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 with the filename-on-its-own-line convention: the filename `seed.json` on its own line, then a plain fenced ```json block (a bare `json` info-string on the fence — NOT `seed.json` on the fence line; the server keys off the preceding filename line). Emit it **last**, after `App.jsx` and any companion feature files.
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": [