@vibes.diy/prompts 14.3.32 → 14.3.35
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/backend.md +18 -2
- package/llms/three-js.md +7 -1
- package/llms/voxel.md +75 -28
- package/package.json +4 -4
package/llms/backend.md
CHANGED
|
@@ -384,8 +384,24 @@ const gh = await ctx.github.fetch("/repos/acme/site/issues", { method: "POST", b
|
|
|
384
384
|
calling convention (codegen has been observed passing these positionally).
|
|
385
385
|
The message lands in that person's bell, inbox, and push notifications.
|
|
386
386
|
- `toHandle` is one handle, and the platform delivers to people already in
|
|
387
|
-
this app: the owner, an accepted invite or approved
|
|
388
|
-
named in the access function's persisted grant state
|
|
387
|
+
this app: the owner, who always qualifies, an accepted invite or approved
|
|
388
|
+
request, a handle named in the access function's persisted grant state, or
|
|
389
|
+
somebody whose authenticated write reached the app (anonymous writes don't
|
|
390
|
+
count). Invite, request, and writer membership resolve the person through
|
|
391
|
+
their bound handle; the grant-state clause matches the named handle
|
|
392
|
+
itself. Explicit revocations deny anyone but the owner. A passing check
|
|
393
|
+
plus valid fields writes the notification into the inbox history of a
|
|
394
|
+
recipient the platform can resolve — an unresolvable handle fails the call
|
|
395
|
+
after the participation check. Their switches silence the live bell, the
|
|
396
|
+
push, and the email — not the history.
|
|
397
|
+
- When the notification is the opt-in kind — your turn, your order shipped —
|
|
398
|
+
seat the player the way a guest takes their own seat.
|
|
399
|
+
A turn notification goes to a seat its owner took themselves.
|
|
400
|
+
A join write where the added handle must equal `user.userHandle` qualifies
|
|
401
|
+
the writer by their own act. This is an app-side convention for notifiable
|
|
402
|
+
seats, not a rule about read grants: chosen-peer grants that share without
|
|
403
|
+
notifying — inviting a collaborator into a shared list — stay intentional,
|
|
404
|
+
and a grant-named handle stays eligible whether or not its owner seated it.
|
|
389
405
|
- `body` is the whole message — plain text, 500 chars max. The platform
|
|
390
406
|
titles it with the app's name and links it back to the app, so spend the
|
|
391
407
|
body on what happened and who it concerns.
|
package/llms/three-js.md
CHANGED
|
@@ -1000,7 +1000,13 @@ gltf.scene.traverse((child) => {
|
|
|
1000
1000
|
|
|
1001
1001
|
### Minecraft World Generator
|
|
1002
1002
|
|
|
1003
|
-
Procedural voxel terrain
|
|
1003
|
+
Procedural voxel terrain. **For a block world, the voxel skill is the
|
|
1004
|
+
authority**: it draws each chunk as one `InstancedMesh` of the exposed blocks
|
|
1005
|
+
(or Block Craft's per-face `BufferGeometry` batching) and never a `Mesh` per
|
|
1006
|
+
block — follow it rather than the merge sketch below, which is only the noise
|
|
1007
|
+
half. The same rule holds outside voxels: many things of one shape are one
|
|
1008
|
+
`InstancedMesh` or `Points`, never a `Mesh` each, and nothing allocates a
|
|
1009
|
+
geometry or material inside the frame loop.
|
|
1004
1010
|
|
|
1005
1011
|
```javascript
|
|
1006
1012
|
import { ImprovedNoise } from "three/addons/math/ImprovedNoise.js";
|
package/llms/voxel.md
CHANGED
|
@@ -13,9 +13,10 @@ veins, endless chunk streaming, day/night, live multiplayer edits, ambient
|
|
|
13
13
|
wildlife — and its bigger successor **Blockcraft World**, which adds the full
|
|
14
14
|
survival layer: crafting tiers, tool durability, smelting, armor, mob combat,
|
|
15
15
|
hunger, creative mode, nether/end dimensions, per-player inventory, and a
|
|
16
|
-
shared world reset. **Blocktopia** contributes
|
|
17
|
-
compact procedural island settings, and sparse
|
|
18
|
-
contributes exposed-face chunk meshes and
|
|
16
|
+
shared world reset. **Blocktopia** contributes the instanced chunk renderer,
|
|
17
|
+
material-colored controls, compact procedural island settings, and sparse
|
|
18
|
+
per-cell edits; **Block Craft** contributes exposed-face chunk meshes and
|
|
19
|
+
survival feedback. Adapt the useful
|
|
19
20
|
patterns to the persistence contracts below: whole-world autosaves and durable
|
|
20
21
|
movement heartbeats are expensive examples to improve, rather than defaults.
|
|
21
22
|
|
|
@@ -112,7 +113,8 @@ const state = {
|
|
|
112
113
|
blocks: new Map(), // "x|y|z" -> type (the loaded world, terrain + edits)
|
|
113
114
|
chunks: new Map(), // "cx,cz" -> Set(blockKey) currently-resident chunks
|
|
114
115
|
edits: new Map(), // "x|y|z" -> type|null player edits layered over terrain
|
|
115
|
-
|
|
116
|
+
chunkMeshes: new Map(), // "cx,cz" -> THREE.InstancedMesh (EXPOSED blocks only, one per chunk)
|
|
117
|
+
dirty: new Set(), // "cx,cz" chunks whose mesh must be rebuilt after an edit
|
|
116
118
|
pos: new THREE.Vector3(0, 20, 0),
|
|
117
119
|
vel: new THREE.Vector3(),
|
|
118
120
|
yaw: 0, pitch: 0, keys: {}, onGround: false, fly: false,
|
|
@@ -196,12 +198,17 @@ outline: the accent reinforces the selected mode rather than being its only
|
|
|
196
198
|
signal. On touch, keep movement/look separate from Place/Break/Jump controls,
|
|
197
199
|
and clear held input on pointer cancellation or lost capture.
|
|
198
200
|
|
|
199
|
-
## Rendering:
|
|
201
|
+
## Rendering: instance the EXPOSED blocks (this is the whole performance game)
|
|
200
202
|
|
|
201
203
|
The single most important rule: **do not create a `THREE.Mesh` per stored
|
|
202
|
-
block
|
|
203
|
-
|
|
204
|
-
|
|
204
|
+
block, and never allocate a geometry or material inside the block loop.** A
|
|
205
|
+
chunk is thousands of blocks and most are buried. Three.js pays one draw call
|
|
206
|
+
per mesh per material, so a mesh-per-block world with a six-material cube is
|
|
207
|
+
hundreds of thousands of draw calls a frame — CPU-bound, and a faster GPU does
|
|
208
|
+
not help. Keep buried blocks in the `blocks` map (collision and raycasting read
|
|
209
|
+
the map, not the scene) and draw the rest as **one `InstancedMesh` per chunk**.
|
|
210
|
+
|
|
211
|
+
First, the exposure test — a block with six occluding neighbors is never drawn:
|
|
205
212
|
|
|
206
213
|
```js
|
|
207
214
|
const NB = [[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]];
|
|
@@ -209,26 +216,62 @@ function occludes(t) { return t && t !== "water" && t !== "glass" && t !== "leav
|
|
|
209
216
|
function isHidden(x, y, z) {
|
|
210
217
|
for (const [dx, dy, dz] of NB)
|
|
211
218
|
if (!occludes(state.blocks.get(keyOf(x + dx, y + dy, z + dz)))) return false;
|
|
212
|
-
return true; // fully enclosed → no
|
|
219
|
+
return true; // fully enclosed → no instance
|
|
213
220
|
}
|
|
214
221
|
```
|
|
215
222
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
223
|
+
Then the chunk mesh: one shared `BoxGeometry` and one shared material for the
|
|
224
|
+
whole world, built once outside every loop, with the block color carried by
|
|
225
|
+
`instanceColor`. This is Blocktopia's terrain — the whole island is one draw
|
|
226
|
+
call, and the build is a `setMatrixAt` loop rather than vertex arithmetic:
|
|
220
227
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
228
|
+
```js
|
|
229
|
+
const CUBE = new THREE.BoxGeometry(1, 1, 1); // built ONCE
|
|
230
|
+
const TERRAIN_MAT = new THREE.MeshLambertMaterial({ color: 0xffffff }); // built ONCE; white so instanceColor shows
|
|
231
|
+
const tmpM = new THREE.Matrix4(), tmpC = new THREE.Color();
|
|
232
|
+
|
|
233
|
+
function buildChunkMesh(keys) { // keys: the chunk's resident block keys
|
|
234
|
+
const visible = [];
|
|
235
|
+
for (const k of keys) { const [x, y, z] = parseKey(k); if (!isHidden(x, y, z)) visible.push([x, y, z, state.blocks.get(k)]); }
|
|
236
|
+
const mesh = new THREE.InstancedMesh(CUBE, TERRAIN_MAT, visible.length);
|
|
237
|
+
visible.forEach(([x, y, z, type], i) => {
|
|
238
|
+
mesh.setMatrixAt(i, tmpM.makeTranslation(x + 0.5, y + 0.5, z + 0.5));
|
|
239
|
+
mesh.setColorAt(i, tmpC.setHex(BLOCK_TYPES[type].top));
|
|
240
|
+
});
|
|
241
|
+
mesh.instanceMatrix.needsUpdate = true;
|
|
242
|
+
mesh.instanceColor.needsUpdate = true;
|
|
243
|
+
mesh.frustumCulled = false; // a chunk's bounds are its blocks; let the fog bound distance
|
|
244
|
+
return mesh;
|
|
245
|
+
}
|
|
246
|
+
```
|
|
224
247
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
248
|
+
Blocks whose *material* differs in kind — transparent water and glass, an
|
|
249
|
+
emissive lava — get their own `InstancedMesh` per type sharing the same `CUBE`,
|
|
250
|
+
so the count of draw calls per chunk stays "one plus the number of special
|
|
251
|
+
materials present". Never mint a material per block; the material table is a
|
|
252
|
+
module-level `Object` keyed by type, built once.
|
|
253
|
+
|
|
254
|
+
**Edits rebuild the chunk, not the block.** When a block is placed or broken,
|
|
255
|
+
mark its chunk dirty — and the neighboring chunk too when the block sits on a
|
|
256
|
+
chunk boundary, because a face across the border may have just become exposed
|
|
257
|
+
or buried. Each frame, rebuild at most one or two dirty chunks: `scene.remove`
|
|
258
|
+
the old `InstancedMesh`, `dispose()` it, and add the fresh one. Rebuilding a
|
|
259
|
+
16×16 chunk is a few thousand `setMatrixAt` calls, well under a frame. A
|
|
260
|
+
just-placed block can pop in by starting its instance matrix at scale 0 and
|
|
261
|
+
easing it to 1 over a few frames.
|
|
262
|
+
|
|
263
|
+
Raycasting and collision must read `state.blocks` (the full model), never the
|
|
264
|
+
meshes or the instance buffers — otherwise you can't hit or collide with a face
|
|
265
|
+
that isn't currently drawn.
|
|
266
|
+
|
|
267
|
+
For texture-heavy or very large worlds, use Block Craft's **exposed-face chunk
|
|
268
|
+
batching** instead: append only the visible *faces* into a `BufferGeometry` per
|
|
269
|
+
material per chunk (position, normal, uv and an index per quad), sharing
|
|
270
|
+
materials across chunks. It uploads less than instancing — a buried face is
|
|
271
|
+
never sent at all — and allows a different texture per face, at the cost of
|
|
272
|
+
writing the six quad windings by hand. The dirty-chunk rule is identical.
|
|
273
|
+
Either of these two patterns is correct; a `Mesh` per block is not, even with
|
|
274
|
+
the exposure test in front of it.
|
|
232
275
|
|
|
233
276
|
## Procedural terrain: deterministic noise, layered
|
|
234
277
|
|
|
@@ -274,8 +317,9 @@ function loadChunk(cx, cz) {
|
|
|
274
317
|
if (t === null) { state.blocks.delete(k); keys.delete(k); }
|
|
275
318
|
else { state.blocks.set(k, t); keys.add(k); }
|
|
276
319
|
}
|
|
277
|
-
for (const k of keys) { const [x,y,z] = parseKey(k); if (!isHidden(x,y,z)) addMesh(k, state.blocks.get(k)); }
|
|
278
320
|
state.chunks.set(chunkKey(cx, cz), keys);
|
|
321
|
+
const mesh = buildChunkMesh(keys); // one InstancedMesh for the chunk (see Rendering)
|
|
322
|
+
scene.add(mesh); state.chunkMeshes.set(chunkKey(cx, cz), mesh);
|
|
279
323
|
}
|
|
280
324
|
```
|
|
281
325
|
|
|
@@ -298,7 +342,7 @@ Each frame, figure out which chunks should be resident around the player
|
|
|
298
342
|
(`VIEW_RADIUS` chunks in each direction), enqueue the missing ones sorted
|
|
299
343
|
nearest-first, and load **exactly one per frame** so the framerate never
|
|
300
344
|
stalls. Unload chunks that fall outside the radius (delete their blocks and
|
|
301
|
-
meshes). Never load a whole ring in one frame.
|
|
345
|
+
instanced meshes). Never load a whole ring in one frame.
|
|
302
346
|
|
|
303
347
|
## The player controller — where "Minecraft" is won or lost
|
|
304
348
|
|
|
@@ -1037,8 +1081,11 @@ None of this needs persistence — keep it purely visual and client-side:
|
|
|
1037
1081
|
|
|
1038
1082
|
## Performance checklist
|
|
1039
1083
|
|
|
1040
|
-
-
|
|
1041
|
-
|
|
1084
|
+
- One `InstancedMesh` per chunk of exposed blocks (or Block Craft face
|
|
1085
|
+
batching); keep buried ones in the map for collision/raycast.
|
|
1086
|
+
- Share one geometry + one material table across all blocks, built once
|
|
1087
|
+
outside every loop; never a `Mesh`, geometry or material per block.
|
|
1088
|
+
- Edits dirty a chunk; rebuild at most a chunk or two per frame.
|
|
1042
1089
|
- Stream one chunk per frame; unload out-of-range chunks (dispose meshes).
|
|
1043
1090
|
- Raycast and collide against the block map, never the scene meshes.
|
|
1044
1091
|
- Cap mobs and particles; dispose geometries/materials on unmount and on
|
|
@@ -1046,7 +1093,7 @@ None of this needs persistence — keep it purely visual and client-side:
|
|
|
1046
1093
|
- `renderer.setPixelRatio(Math.min(devicePixelRatio, 2))` and a `Fog` to bound
|
|
1047
1094
|
draw distance.
|
|
1048
1095
|
|
|
1049
|
-
That set — exposed-
|
|
1096
|
+
That set — instanced exposed-block chunks, per-axis collision with step-up and un-stick,
|
|
1050
1097
|
a click-to-play pointer-lock overlay, a DDA raycast, per-voxel Fireproof docs
|
|
1051
1098
|
folded forward monotonically, table-driven survival systems, and a flat
|
|
1052
1099
|
multi-file split once it grows — is what turns a voxel tech demo into a game
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibes.diy/prompts",
|
|
3
|
-
"version": "14.3.
|
|
3
|
+
"version": "14.3.35",
|
|
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.35",
|
|
41
|
+
"@vibes.diy/identity": "14.3.35",
|
|
42
|
+
"@vibes.diy/use-vibes-types": "14.3.35",
|
|
43
43
|
"arktype": "~2.2.3",
|
|
44
44
|
"json-schema-faker": "~0.6.3"
|
|
45
45
|
},
|