@vibes.diy/prompts 14.3.0 → 14.3.2

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/voxel.js CHANGED
@@ -5,7 +5,8 @@ export const voxelConfig = {
5
5
  "procedural terrain (noise heightmaps, biomes, caves, ore veins, trees), place/break with a " +
6
6
  "DDA voxel raycast, an AABB player controller with gravity, jump, sprint, auto step-up and " +
7
7
  "un-stick, pointer-lock look with a click-to-play overlay and touch drag, endless chunk " +
8
- "streaming, a day/night cycle, ambient mobs, and live multiplayer block edits over Fireproof. " +
8
+ "streaming, a shared voxel palette with material-colored controls, a day/night cycle, " +
9
+ "ambient mobs, and live multiplayer block edits with temporary player presence over Fireproof. " +
9
10
  "Covers the survival layer (table-driven crafting tiers, tools with durability, smelting, " +
10
11
  "armor, mob combat, hunger, dimensions, per-player inventory, world reset) and the flat " +
11
12
  "multi-file project split for bigger games. " +
package/llms/voxel.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"voxel.js","sourceRoot":"","sources":["../../jsr/llms/voxel.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAc;IACpC,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,OAAO;IACd,WAAW,EACT,yFAAyF;QACzF,6FAA6F;QAC7F,4FAA4F;QAC5F,yFAAyF;QACzF,+FAA+F;QAC/F,2FAA2F;QAC3F,yFAAyF;QACzF,6CAA6C;QAC7C,2FAA2F;QAC3F,yFAAyF;IAC3F,IAAI,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,CAAC;IAC/E,YAAY,EAAE,OAAO;IACrB,UAAU,EAAE,OAAO;IACnB,UAAU,EAAE,WAAW;CACxB,CAAC"}
1
+ {"version":3,"file":"voxel.js","sourceRoot":"","sources":["../../jsr/llms/voxel.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAc;IACpC,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,OAAO;IACd,WAAW,EACT,yFAAyF;QACzF,6FAA6F;QAC7F,4FAA4F;QAC5F,yFAAyF;QACzF,uFAAuF;QACvF,gGAAgG;QAChG,2FAA2F;QAC3F,yFAAyF;QACzF,6CAA6C;QAC7C,2FAA2F;QAC3F,yFAAyF;IAC3F,IAAI,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,CAAC;IAC/E,YAAY,EAAE,OAAO;IACrB,UAAU,EAAE,OAAO;IACnB,UAAU,EAAE,WAAW;CACxB,CAAC"}
package/llms/voxel.md CHANGED
@@ -13,7 +13,11 @@ 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. Every pattern below is pulled from them.
16
+ shared world reset. **Blocktopia** contributes material-colored controls,
17
+ compact procedural island settings, and sparse per-cell edits; **Block Craft**
18
+ contributes exposed-face chunk meshes and survival feedback. Adapt the useful
19
+ patterns to the persistence contracts below: whole-world autosaves and durable
20
+ movement heartbeats are expensive examples to improve, rather than defaults.
17
21
 
18
22
  ## Project shape: an engine in a React shell, split across a few flat files
19
23
 
@@ -43,9 +47,10 @@ access.js the access function (see multiplayer section)
43
47
  Multi-file rules — each one is load-bearing, breaking any of them breaks the
44
48
  deployed app:
45
49
 
46
- - **All files flat at the root.** The CLI push / codegen path reads top-level
47
- files only — a subdirectory (`components/…`) is silently not uploaded and
48
- every import of it dangles.
50
+ - **All files flat at the root** is a simple default for this example.
51
+ Nested `components/` and `lib/` modules also work in the CLI and codegen.
52
+ **Relative imports resolve to uploaded files** at their exact paths; keep
53
+ the special App, access, backend, and seed entry files at the root.
49
54
  - **Relative imports include the extension**: `./core.js`, `./ui.jsx` — the
50
55
  client serves files by exact path, so an extensionless `./core` 404s in the
51
56
  browser.
@@ -114,17 +119,83 @@ const state = {
114
119
  };
115
120
  ```
116
121
 
117
- Keep block types as a table of face colors so one material set covers the world:
122
+ Keep block types as a table of face colors so one material set covers the world.
123
+ Use the shared palette below for matching materials, with darker side faces:
118
124
 
119
125
  ```js
120
126
  const BLOCK_TYPES = {
121
- grass: { top: 0x5fbf3f, side: 0x7a5230 }, dirt: { top: 0x7a5230, side: 0x6b4626 },
122
- stone: { top: 0x8a8a8a, side: 0x7a7a7a }, sand: { top: 0xe0d29a, side: 0xd6c78a },
123
- water: { top: 0x3f6fbf, side: 0x3f6fbf }, wood: { top: 0x9a6b3f, side: 0x6b4626 },
127
+ grass: { top: 0x6fcf5b, side: 0x8a5a3b }, dirt: { top: 0x8a5a3b, side: 0x6b4626 },
128
+ stone: { top: 0x9b9b9b, side: 0x7a7a7a }, sand: { top: 0xf2dc9b, side: 0xd6c78a },
129
+ water: { top: 0x2f8fe0, side: 0x2f8fe0 }, wood: { top: 0xb5793a, side: 0x6b4626 },
124
130
  leaves:{ top: 0x3f8f2f, side: 0x3f8f2f }, /* ...ores, planks, snow, etc. */
125
131
  };
126
132
  ```
127
133
 
134
+ ## Voxel palette: the block in hand colors the controls
135
+
136
+ Use the Blocktopia voxel palette in every voxel app. Keep the game-specific
137
+ colors in one named table, shared by material swatches and HUD controls. Add
138
+ game-specific materials to that table; preserve these colors for matching
139
+ materials. The surrounding app retains its supplied theme's surfaces and text.
140
+
141
+ ```js
142
+ export const VOXEL_PALETTE = {
143
+ grass: "#6fcf5b", dirt: "#8a5a3b", stone: "#9b9b9b",
144
+ wood: "#b5793a", glass: "#9fe3ff", candy: "#ff6fb1",
145
+ neon: "#39ff9e", water: "#2f8fe0", lava: "#ff5a2f",
146
+ erase: "#ff4d6d", ink: "#1a1325", light: "#ffffff",
147
+ };
148
+
149
+ function luminance(hex) {
150
+ const linear = [1, 3, 5].map((i) => {
151
+ const c = parseInt(hex.slice(i, i + 2), 16) / 255;
152
+ return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
153
+ });
154
+ return linear[0] * 0.2126 + linear[1] * 0.7152 + linear[2] * 0.0722;
155
+ }
156
+ export function readableInk(background) {
157
+ const bg = luminance(background);
158
+ const ratio = (color) => (Math.max(bg, luminance(color)) + 0.05) /
159
+ (Math.min(bg, luminance(color)) + 0.05);
160
+ return ratio(VOXEL_PALETTE.ink) >= ratio(VOXEL_PALETTE.light)
161
+ ? VOXEL_PALETTE.ink : VOXEL_PALETTE.light;
162
+ }
163
+ ```
164
+
165
+ The selected material supplies the active accent; erase mode supplies `erase`.
166
+ Apply it consistently to active view/gravity buttons, action buttons, the
167
+ stage border, selected hotbar ring, and keycap accents. Keep unselected panels
168
+ on theme surfaces (`bg-background/85`, `bg-card`, `text-foreground`) so the
169
+ controls stay readable over sky, water, caves, and bright terrain. Scope the
170
+ variables to the game container, including its HUD and fullscreen subtree:
171
+
172
+ ```jsx
173
+ const accent = eraseMode ? VOXEL_PALETTE.erase : selectedMaterial.color;
174
+ const controlStyle = {
175
+ backgroundColor: "var(--voxel-accent)",
176
+ color: "var(--voxel-accent-fg)",
177
+ };
178
+ return <section style={{
179
+ "--voxel-accent": accent,
180
+ "--voxel-accent-fg": readableInk(accent),
181
+ "--voxel-accent-soft": `${accent}33`, // palette colors are six-digit hex
182
+ }}>
183
+ {/* canvas and HUD share this scope */}
184
+ <button style={controlStyle} onClick={cycleView}>Switch view</button>
185
+ </section>;
186
+ ```
187
+
188
+ Choose the higher-contrast foreground from `ink` and `light` using sRGB relative
189
+ luminance and contrast ratio ([normal text: at least 4.5:1](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html)). For the palette above,
190
+ `dirt` takes white and the other materials and erase take `ink`; recompute for
191
+ additional or customized colors. Apply the same foreground selection to
192
+ hotbar number labels too. A simple brightness threshold can choose white on
193
+ wood, water, or lava even when dark text is more readable. Keep labels/icons,
194
+ `aria-pressed` or `aria-checked`, a visible focus ring, and a two-tone selection
195
+ outline: the accent reinforces the selected mode rather than being its only
196
+ signal. On touch, keep movement/look separate from Place/Break/Jump controls,
197
+ and clear held input on pointer cancellation or lost capture.
198
+
128
199
  ## Rendering: mesh only the EXPOSED blocks (this is the whole performance game)
129
200
 
130
201
  The single most important rule: **do not create a `THREE.Mesh` per stored
@@ -151,6 +222,14 @@ Raycasting and collision must read `state.blocks` (the full model), never the
151
222
  meshes — otherwise you can't hit or collide with a face that isn't currently
152
223
  meshed.
153
224
 
225
+ For larger worlds, use Block Craft's **exposed-face chunk batching**: append
226
+ only visible faces into a `BufferGeometry` per material per chunk, sharing
227
+ materials across chunks. An edit dirties its chunk and any neighboring chunk
228
+ whose boundary face changes; rebuild only those chunks and dispose their old
229
+ geometries. Keep transparent faces in a separate material pass with deliberate
230
+ occlusion rules. The small-world shared-cube example above remains a simpler
231
+ starting point.
232
+
154
233
  ## Procedural terrain: deterministic noise, layered
155
234
 
156
235
  Terrain must be a **pure function of world coordinates** so chunks generate
@@ -200,6 +279,19 @@ function loadChunk(cx, cz) {
200
279
  }
201
280
  ```
202
281
 
282
+ ### Described islands: save the recipe, regenerate the terrain
283
+
284
+ For a world described in a sentence, use Blocktopia's approach: ask `callAI`
285
+ for structured generator settings, normalize them, then persist that compact
286
+ recipe with a fixed seed and generator version. Bound map dimensions, heights,
287
+ densities, array lengths, and supported tree/animal kinds before generating.
288
+ Keep a usable flat-world option and preserve the description if generation
289
+ fails. Generate the voxel field locally from the saved recipe on every client;
290
+ save only player overrides. Keep seeded randomness and traversal deterministic,
291
+ and retain the matching generator for existing worlds when generation changes.
292
+ Ambient animals, flowers, clouds, and particles stay capped and local unless
293
+ their shared gameplay state actually needs persistence.
294
+
203
295
  ## Endless streaming: one chunk per frame
204
296
 
205
297
  Each frame, figure out which chunks should be resident around the player
@@ -258,6 +350,20 @@ toggle** (e.g. `F`) that swaps gravity for direct vertical thrust — great for
258
350
  building. Add **sprint** (hold `Shift` while moving forward → higher speed, and
259
351
  nudge the camera FOV up a few degrees for a sense of speed).
260
352
 
353
+ ### Keyboard: game actions keep the page still
354
+
355
+ During active play, prevent the browser defaults for every key bound to a game action.
356
+ Use `KeyboardEvent.code` for the binding map (`Space`, `ArrowUp`, `KeyW`,
357
+ etc.), and call `event.preventDefault()` in the handled keyboard events so
358
+ Space jumps and arrow keys move without scrolling the page. Apply this only
359
+ while the game has focus or its canvas owns pointer lock, with gameplay active;
360
+ leave typing in chat, inputs, and contenteditable fields, normal button
361
+ activation, and browser shortcuts available outside that input path. CSS
362
+ `touch-action: none` handles touch gestures; keyboard defaults need their own
363
+ handlers. Clear held keys on blur, pointer-lock loss, pause, and tab hiding so
364
+ movement stops even when the matching keyup never arrives. Remove listeners
365
+ when the engine unmounts.
366
+
261
367
  ### Looking: pointer lock with a click-to-play overlay (+ touch drag)
262
368
 
263
369
  Pointer lock is the number-one confusion in browser voxel games: players click
@@ -299,6 +405,32 @@ In the engine, read `movementX/Y` when `document.pointerLockElement === canvas`
299
405
  **drag-to-look on touch** so phones work without pointer lock. Clamp pitch to
300
406
  ±1.5 rad. Provide on-screen move/jump/place/break buttons for touch.
301
407
 
408
+ ### View switcher: see your own character
409
+
410
+ Include a view switcher between first-person and third-person so players can see their own avatar.
411
+ Provide a labeled HUD button that works on touch and a keyboard shortcut
412
+ (e.g. `V`, shown in the control legend); toggle once per press, ignoring key
413
+ repeat. Render a simple blocky local-player avatar in third-person, following
414
+ the player's position and heading, and hide it in first-person so it does not
415
+ cover the camera. Keep the same player physics and position when switching:
416
+ offset the third-person camera behind the player and shorten that offset when
417
+ terrain blocks the view. Preserve aiming and the player's block-interaction
418
+ reach as the camera moves. Keep the button reachable when pointer lock is
419
+ released, and let the shortcut switch views during locked play.
420
+
421
+ ### Optional fullscreen: keep the HUD with the world
422
+
423
+ Offer an optional fullscreen button for a larger play area; the Vibes iframe allows fullscreen.
424
+ When included, call `requestFullscreen()` directly from the button's user
425
+ gesture on the game container that includes both the canvas and HUD. Check
426
+ `document.fullscreenEnabled` and method availability, and handle a rejected
427
+ request by keeping play usable in the embedded view. Derive the Enter/Exit
428
+ fullscreen label from `document.fullscreenElement` on `fullscreenchange`, use
429
+ `document.exitFullscreen()` to exit, and resize the renderer and camera aspect
430
+ to the container on entry and exit. Keep fullscreen and pointer lock as
431
+ separate controls; reacquire pointer lock through the click-to-play overlay
432
+ when needed. Remove the fullscreen listener on unmount.
433
+
302
434
  ### No text selection, and bind touch as well as mouse
303
435
 
304
436
  Two things separate "works on my laptop" from "works", and both are easy to
@@ -368,6 +500,109 @@ when a block breaks — cheap, and it makes mining feel real.
368
500
 
369
501
  ## Multiplayer: live block edits over Fireproof
370
502
 
503
+ ### Keep saved edits separate from temporary movement
504
+
505
+ `useDocument.merge(updates)` updates a local draft and broadcasts its **full
506
+ merged snapshot** to authorized connected peers when it has an `_id`.
507
+ It is a shallow merge, not a durable field-patch API; `save()` persists through
508
+ `database.put()`. The app-facing database has no `database.merge()` method.
509
+
510
+ Use small, separate documents for different lifetimes:
511
+
512
+ - **World recipe and membership:** persist the seed, generator settings,
513
+ version, and world membership once, then only when deliberately changed.
514
+ - **Placed/mined cells:** persist one small override per world and coordinate.
515
+ Include `worldId` in both the ID and indexed fields when an app has several
516
+ worlds. Keep a `removed: true` override for mined procedural terrain so it
517
+ stays gone after reload. Use the consistency model below for concurrent edits.
518
+ - **Inventory, health, and resume checkpoints:** persist per world and player,
519
+ with change detection and an explicit commit/checkpoint cadence. Commit
520
+ important collected items when the action completes; a player-pose heartbeat
521
+ should carry only pose. `save()` still creates a durable write. To commit in
522
+ the same callback as a draft update, pass the complete next snapshot to
523
+ `save(snapshot)`; a bare `save()` can read the previous render's draft.
524
+ A nested object replaces that entire field rather than merging individual
525
+ coordinates.
526
+ - **Live pose/aim:** use a dedicated presence draft and `merge()` without
527
+ `save()`. Keep the movement cadence bounded and heartbeat while stationary.
528
+ Temporary overlays expire after about 12 seconds without updates or when the
529
+ peer disconnects; they are not a durable resume position or offline edit log.
530
+ - **Activity feed:** use a bounded/coalesced recent-action summary unless a
531
+ durable audit trail is required. Showing only eight results does not bound
532
+ storage when every block placement appends a new activity document.
533
+
534
+ Blocktopia's per-coordinate writes already avoid saving an entire world for
535
+ each block. The useful `merge()` substitution is its recurring **presence**
536
+ write. Block Craft's whole-world snapshot every two seconds combines edits,
537
+ inventory, vitals, and pose; split those lifetimes before adopting its survival
538
+ systems. Fewer durable commits and smaller documents reduce persistence work;
539
+ measure wire bytes and delivery latency separately before claiming faster sync.
540
+
541
+ For a world whose membership is already established, mount this component
542
+ with `key={worldId + ":" + handle}`. Its hook stays at component scope and
543
+ starts a new draft when the player changes worlds. `poseRef` is the engine's
544
+ latest `{ x, y, z, theta }` snapshot; animation updates that ref without React
545
+ state or database writes:
546
+
547
+ ```jsx
548
+ function PlayerPresence({ worldId, handle, poseRef, useDocument }) {
549
+ const { merge } = useDocument({
550
+ _id: `presence:${worldId}:${handle}`, type: "presence",
551
+ worldId, userHandle: handle,
552
+ });
553
+ React.useEffect(() => {
554
+ let previous = "";
555
+ let lastSent = 0;
556
+ const timer = setInterval(() => {
557
+ const p = poseRef.current;
558
+ if (!p) return;
559
+ const pose = { x: p.x, y: p.y, z: p.z, theta: p.theta };
560
+ const stamp = JSON.stringify(pose);
561
+ const now = Date.now();
562
+ if (stamp === previous && now - lastSent < 5000) return;
563
+ merge({ ...pose, at: now });
564
+ previous = stamp;
565
+ lastSent = now;
566
+ }, 350);
567
+ return () => clearInterval(timer);
568
+ }, [merge, poseRef]);
569
+ return null;
570
+ }
571
+ ```
572
+
573
+ Peers can receive this never-saved row through a live query on `worldId`;
574
+ the temporary overlay supplies the index fields. The access function must
575
+ validate the sender's identity, bind `_id` to its world/player, validate finite
576
+ pose coordinates, and require world membership before returning the existing
577
+ world channel. Persist the world/invitation that grants that membership first:
578
+ a presence broadcast does not create grants. Use this matching branch in the
579
+ multi-world access function (the single-world example later uses different IDs
580
+ and `authorHandle`):
581
+
582
+ ```js
583
+ if (doc.type === "presence") {
584
+ if (!user || doc.userHandle !== user.userHandle) throw { forbidden: "not you" };
585
+ if (typeof doc.worldId !== "string" || !doc.worldId) throw { forbidden: "world required" };
586
+ if (doc._id !== `presence:${doc.worldId}:${user.userHandle}`) throw { forbidden: "presence ID" };
587
+ if (![doc.x, doc.y, doc.z, doc.theta, doc.at].every(Number.isFinite)) throw { forbidden: "invalid pose" };
588
+ const channel = `world:${doc.worldId}`;
589
+ ctx.requireAccess(channel);
590
+ return { channels: [channel] };
591
+ }
592
+ ```
593
+
594
+ A hidden or disconnected tab may miss its heartbeat, so peers expire it rather
595
+ than treating it as saved state. Use receiver arrival time for update freshness.
596
+ Rely on disconnect/expiry for departure:
597
+ an unmount-time `merge()` can be canceled before broadcast. This example uses
598
+ one presence ID per handle; independent same-handle tabs need a session suffix
599
+ and access rules that validate that ID. During migration from saved presence,
600
+ admit old durable rows only if their timestamps are plausibly fresh; their
601
+ first query arrival or reappearance after overlay expiry is not a heartbeat.
602
+ Alternatively, use a distinct ephemeral namespace with matching access rules.
603
+
604
+ ### Choose the durable edit conflict model
605
+
371
606
  **Know exactly what the substrate gives you before you design for it.** A live
372
607
  query returns the **full, latest-per-document result set**, deliveries are
373
608
  **unordered** (notifications can be delayed; overlapping re-queries can resolve
@@ -406,6 +641,11 @@ so **there is no free lunch here.** Pick a model with eyes open:
406
641
 
407
642
  ### Model A: one doc per coordinate
408
643
 
644
+ The durable examples below use a single shared world. For a world picker,
645
+ carry `worldId` through document IDs, queries, reset watermarks, accumulator
646
+ lifecycles, and access checks together; use one channel per world. Keep a reset
647
+ in one world from invalidating edits or inventories in another.
648
+
409
649
  Give the doc a **deterministic `_id` of `block:<key>`** so every edit at a
410
650
  coordinate updates the same doc — the database stays one-doc-per-cell instead of
411
651
  replaying every historical value. A break writes a `removed: true` tombstone at
@@ -739,7 +979,7 @@ tables once in `core.js` and every system (mining, crafting, combat, UI) reads
739
979
  them — adding content then means adding rows, not code:
740
980
 
741
981
  ```js
742
- export const BLOCKS = [ { id: "grass", name: "Grass", top: 0x5fbf3f, side: 0x7a5230, drops: "dirt" }, /* … */ ]
982
+ export const BLOCKS = [ { id: "grass", name: "Grass", top: 0x6fcf5b, side: 0x8a5a3b, drops: "dirt" }, /* … */ ]
743
983
  export const ITEMS = { plank: { name: "Plank" }, stick: { name: "Stick" }, ironIngot: { name: "Iron Ingot" }, /* … */ }
744
984
  export const RECIPES = [
745
985
  { id: "planks", out: { plank: 4 }, needs: { wood: 1 } },
@@ -772,10 +1012,11 @@ The systems that ride those tables:
772
1012
  - **World depth** — keep a real vertical range (e.g. bedrock at `y = -128`)
773
1013
  so caves and ores have somewhere to live.
774
1014
 
775
- Persist the survival state as typed docs (see access function below): one
776
- `inventory` doc per player (`inv:<handle>`), and a `worldReset` singleton the
777
- owner writes — clients ignore voxel edits older than its timestamp, which
778
- resets the shared world without deleting anything.
1015
+ Persist the survival state as typed docs (see the single-world access function
1016
+ above): one `inventory` doc per player (`inv:<handle>`), and a `worldReset`
1017
+ singleton the owner writes — clients ignore voxel edits older than its
1018
+ timestamp. For several worlds, scope these IDs and queries by world as well
1019
+ (`inv:<worldId>:<handle>`), and update the access checks to enforce that scope.
779
1020
 
780
1021
  ## Ambient life & atmosphere (cheap, high-impact)
781
1022
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/prompts",
3
- "version": "14.3.0",
3
+ "version": "14.3.2",
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.0",
41
- "@vibes.diy/identity": "14.3.0",
42
- "@vibes.diy/use-vibes-types": "14.3.0",
40
+ "@vibes.diy/call-ai-v2": "14.3.2",
41
+ "@vibes.diy/identity": "14.3.2",
42
+ "@vibes.diy/use-vibes-types": "14.3.2",
43
43
  "arktype": "~2.2.3",
44
44
  "json-schema-faker": "~0.6.3"
45
45
  },