@jgengine/rapier 0.39.0 → 0.40.0

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.
Files changed (2) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -26,6 +26,137 @@ At publish, rename this heading to the new version and mirror the entries into
26
26
  `packages/core/src/meta/changelog.ts` (the typed `CHANGELOG` export).
27
27
  -->
28
28
 
29
+ ## 0.40.0
30
+
31
+ ### Migrate
32
+
33
+ - **Bump lockstep SDK packages to `^0.40.0`:** `@jgengine/{core,rapier,react,ws,node,sql,convex,shell,editor,assets,navbake}`. CLI `jgengine` is `0.37.0`; `@jgengine/github` is `0.27.0`.
34
+
35
+ ### Added
36
+
37
+ - Impostors: repeated models with a bounding radius of 2.2 m or more (trees, palms, buildings) placed as scatter or as batched static objects draw as camera-facing cards past a distance that grows with the model's size and the graphics tier (70 m plus 16 m per metre of radius on high). Each model is baked once at load into an albedo and normal atlas seen from 64 directions over the upper hemisphere (36 on low), so far cards keep their lighting and cast shadows. Every far placement of a model shares one instanced card draw, whichever batch cell it sits in. Low tier keeps impostors with a smaller atlas; models that fail to bake keep drawing as meshes.
38
+ - `postProcessing.atmosphere` (`AtmosphereConfig`, `DEFAULT_ATMOSPHERE`): exponential height haze that fades distant ground into the sky and brightens toward the sun, plus screen-space light shafts where the sky shows through gaps. On by default on medium and up, tuned per `mood` (overcast hazes without shafts, golden and dusk have the most of both); skipped when the scene has no shadow-casting sun.
39
+ - World reflection probe: on medium and up the shell captures the scene around the camera into a cube map one face per frame (64/128/256 px by tier, every 8/4/2 s or after the camera travels), and metal, glossy and glass materials without their own environment map reflect it. An authored HDRI or cube map still wins.
40
+ - The sky dome adds a forward-scattering glow around the sun and reddens the horizon on the sun's side when the sun is low, following the day cycle.
41
+ - Wet surfaces: while it rains, every lit opaque surface darkens and turns glossy over about 14 s, and up-facing ground collects puddles that mirror the sky and the world reflection probe; it dries over about 70 s after the rain stops. A world that opens in rain starts soaked. Glass, water and custom shaders stay as they are; `material.userData.noWetness = true` opts a material out.
42
+ - Wind from the weather: plants and cloth bend in the rain field's wind direction and harder as it rises. Models without a `wind` setting now sway when their mesh or material names read as foliage (palm, leaves, bush, tree…) and only their cloth parts flutter when they read as cloth (flag, banner, awning…); `wind: false` keeps a model rigid.
43
+ - `ambientLife` (`AmbientLifeConfig`): a flock of gulls circles over the ground in view under a sky in fair daylight and leaves in rain or at night (on by default, `birds: false` to turn off); `litter` blows paper along the ground when the wind picks up; `steam` vents breathe plumes that thicken in rain and at night. `ambientLife: false` turns all of it off.
44
+ - `postProcessing.contactShadows` (`ContactShadowConfig`, `DEFAULT_CONTACT_SHADOWS`): screen-space shadows toward the sun so feet, wheels and props sit on the ground. On by default on medium and up; `false` turns it off.
45
+ - `aa: "taa"`: jittered temporal antialiasing with neighbourhood clipping and a light sharpen.
46
+ - `createCityLayout`, `cityRoadSource`, `cityLots` and `tuneCityLayout` (`@jgengine/core/world/cityLayout`): one street and lot layout with US-city defaults (3.5 m lanes, 2.5 m sidewalks, 15 cm kerbs, zone setbacks 0-6 m, floor ranges, corner clearance, driveways). Every number is a live devtools slider; streets redraw through `environment({ roadSource })` and lots re-lay on change.
47
+ - `deriveBuildingLots({ crossClearance })` keeps lots further from roads they do not front.
48
+ - `road({ sidewalk: { kerb } })` sets the kerb height; default stays 14 cm.
49
+ - `ModelMaterialOverride.materials` limits an override to named materials.
50
+ - Scale-only `visual.scale` placements now draw the model scaled (and still batch), not only fallback boxes.
51
+ - Facade library materials `facade/brick-red|brick-grey|brick-brown|glass-blue|glass-mirror` (ambientCG Facade018A/019A/020A/001/005).
52
+ - Realistic model library (`@jgengine/assets/catalogs/modelLibrary`): 58 Poly Haven CC0 models by intent across nine genres, `findLibraryModel`, `libraryModel`, `libraryModelCredits`, known gaps, a `generated` origin for game-committed AI models, and `assets pull model:<name>` / `model-library` with md5 checks, 512 px textures, near/far LOD and meshopt compression.
53
+ - Tune-panel sliders and number fields carry their control name as an accessible label, so drives and screen readers can reach them.
54
+ - Rigged characters placed with `instanceId` now plant their feet on the ground (`ik: "auto"`) and turn their head toward the local player when they come within 7 m, from any angle in front of them (`@jgengine/shell/render/characterGlance`). Both skip characters more than 20 m from the camera, dead characters and the low graphics tier. `ik: "none"` turns both off for a model. Debug snapshots show `feet planted N · glancing N` under `render/characters`.
55
+ - Entity models with no `animation` set default to `"auto"`, so a catalog rig picks up its idle, walk and run clips without extra declaration.
56
+ - Positioned sounds are placed around the head by default (`audio.panning`, default `"hrtf"`; `"equalpower"` is a cheaper stereo pan, `"off"` keeps them centred). Distance loudness still follows each sound's `falloff`; a sound's own `spatial` block still wins.
57
+ - World reverb on positioned sounds, on by default (`audio.reverb`): authored zones (sphere or box, preset `room`, `hall`, `cave`, `outdoor` or `none`) win; elsewhere the shell casts six wall rays and one ceiling ray around the player twice a second and picks room, hall or outdoor. Changes of space blend over about a second. Each bus feeds the reverb through its own level, so muting a bus silences its echo. `reverb: false` keeps everything dry.
58
+ - One-shots (gunshots, impacts) that start behind geometry now play quieter and muffled, on their own budget of 6 line tests per 100 ms.
59
+ - Adaptive music (`audio.adaptiveMusic`, off by default): hits the local player deals or takes raise an intensity that decays in quiet, and the tiers crossfade the built-in explore, tension and fight themes (`ADAPTIVE_THEMES`), or the game's own tiers. `audio/adaptiveMusic` probe.
60
+ - `window.__jgengineAudio.spatial()` reports panned voices, reverb sends, muffled one-shots and the current space.
61
+ - Impact layer (`presentationEffects.impacts`, on by default): sparks and dust at every hit sized by weapon class (light, medium, heavy, melee, explosive, vehicle; `impactClassFor` reads weapon words, `classes` overrides), bullet holes and scorch marks where shots miss into a surface (on the drawn road or wall, not the physics floor under it), camera kick and rumble near blasts and crashes with distance falloff, and a short hit-stop on the local player's heavy hits, hits taken and kills. Reduced motion drops the camera kick. `render/impacts` probe.
62
+ - Fallen bodies: a killed rigged character's last pose drops as a physics ragdoll, lies 5 s, then sinks away; up to 6 at once, off on the low tier, `impacts: { ragdolls: false }` turns it off. A game that keeps its dead entity is left alone. `render/ragdolls` probe.
63
+ - `fireProjectile({ impact })` tags how a shot's landing reads (`"explosive"` for a grenade) without changing its flight or damage; `projectile.settled` now carries `item` and `impact`.
64
+ - World model triggers (`triggers`): a rule fires the moment its conditions become true, applying `then`, firing a ripple, logging a note and running a hook; it re-arms when the conditions lapse, or never with `once`. Turf changing hands or a district rioting is now one declaration.
65
+ - Ripple variants: a ripple can be a list, each variant gated by `when`, `whenPlace` (facts of the place it lands on, such as its owner) or `whenTarget`, so one event lands differently by who holds the block.
66
+ - Targeted schedules and ripple targets: a schedule with `on` picks one built instance of a kind or tag (filtered by `whenTarget`, rolled from the world clock so a reload rolls the same), with an optional `chance`; the ripple's `target` changes land on it and `{target}` names it in the note. Slots take a `label` for that name. Action ripples carry their target too.
67
+ - Live facts (`createWorldModel(..., { live })`, `defineGameSpec({ live })`): facts the game computes, such as the hour or the wanted level, that conditions, lines, flows and triggers read and saves never hold.
68
+ - `WorldModel.advance(seconds, { maxFires })` catches up time spent away in one step: flows pay, facts calm, queues finish, triggers fire and each schedule fires a bounded number of times, with the gains and log lines returned for a "while you were away" summary.
69
+ - Police response cover and pay-offs: `PoliceTickContext.hidden` stops sightings and runs the cold trail `hiddenRate` (default 3) times faster for a garage or hideout, and `PoliceResponse.forgive(amount)` takes heat off at once for a bribe or a fine.
70
+ - `@jgengine/core/worldModel/worldModel`: `defineWorldModel` / `createWorldModel` declare one world of factions, places, people, things, jobs, ripples and schedules as flat facts. Missions, dialogue lines, phone contacts, map blips, the next-step tracker and a news log all read from it, and its state lives in one store, so saves and co-op sync come with it. `spend` applies costs all-or-nothing, and `hook` names game code for whatever a declaration can't say (#2412, #2413).
71
+ - Mission `survive` objectives accept `until`: a world-fact condition to hold for, with or without a `duration`.
72
+ - Model library grows to 88 entries: 13 rigged Microsoft Rocketbox humans (MIT; casual, business, police, worker, guard, jogger, nurse, soldier) with Idle/Walk/Run/Talk clips, 10 Rocketbox animals, a Khronos CarConcept sports car (CC-BY 4.0, logos removed), four Poly Haven trees (jacaranda, fir and pine saplings, large quiver tree) and engine-built `scifi/server-rack` and `scifi/robot-arm`.
73
+ - `assets pull` converts Rocketbox FBX to GLB in Bun (`pullRocketboxModel`), pulls Khronos samples with logo scrubbing and builds authored models (`buildAuthoredModel`); every file is checked against its source's hash.
74
+ - `thinIslands` and the Poly Haven origin's `thin` / `error` options make multi-million-triangle tree scans usable (jacaranda: 118k / 53k triangles, 2.7 MB).
75
+ - `imageCodec`: TGA and PNG decode, PNG and JPEG encode, box downscale, Git blob sha.
76
+ - `facade/glass-curtain` (ambientCG Facade006): glass curtain wall with aluminium mullions and spandrels, 28 m tile.
77
+ - `defineGameSpec({ show })` (`@jgengine/core/worldModel/gameSpec`): built instances of the named kinds or tags appear as entities at their cell or slot (on the ground) and leave when removed or sold, with no game code; a loaded save rebuilds them.
78
+ - `defineGameSpec({ autoStart: true })`: the next available story job starts by itself, so a story runs beat after beat without a giver contact.
79
+ - `pursue({ anchor, hunts })` (`@jgengine/core/scene/behaviors`): `anchor` keeps a pursuer beside another entity (a tamed pet heels at about 2.5 m and returns to it after a fight); `hunts` lists the entity names it auto-aggroes on, instead of the player.
80
+ - The dev runner serves a game's own `public/` files (`apps/dev/gamePublicPlugin.ts`), so a game's committed models load under `bun run drive` as they do under the game's own Vite.
81
+ - `registerEntityMuzzle` / `readEntityMuzzle` (`@jgengine/shell` render): say where an entity's shots visibly leave from; rigged characters register their right hand automatically.
82
+ - Hit markers (`presentationEffects.hitMarkers`, default on): when the local player's attack damages something, a tick flashes over the spot hit, larger and red on a kill. It marks the hit itself, so it works with cursor aim and crosshair aim.
83
+ - Muzzle flashes (`presentationEffects.muzzleFlash`, defaults to the `tracers` setting): a 55 ms star where each direct-fire shot leaves the gun hand, barrel or first-person gun. Reduced motion makes it smaller and dimmer.
84
+ - `render/shotFeedback` devtools probe counts hit markers, kills and flashes.
85
+ - Fire commands get `held` (`{ yaw, pitch, aim, held }`): `false` on the click, `true` on `repeatMs` re-fires, so one binding drives a single-shot pistol and an automatic rifle. `ItemUseInput.held` carries it into item-use handlers.
86
+ - `combat.recoil` event (`{ from, pitch, yaw?, recover? }`): the local player's view climbs by the kick in about 65 ms and settles back (default about 85% within 0.3 s), capped at 0.35 rad per burst, in views that aim with the look. `input/recoil` devtools probe.
87
+ - `GameFrame` (`@jgengine/react/gameFrame`): a panel or game button made of a material (`steel`, `brass`, `hull`, `wood`, `stone`, `paper`, `enamel`, `glass`, `carbon`, `leather`) with a cut silhouette (`chamfer`, `notch`, `slant`, `tab`, `banner`, `shield`, `ticket`, `torn`, `hex`, `box`), a rim, tint and glow. Textures are generated SVG noise and lighting, so no art files ship. `as="button"` lifts on hover, sinks on press, glows on keyboard focus and plays the engine UI sounds. `gameFrameVars()` dresses an element the game already owns.
88
+ - `GameCursor` (`@jgengine/react/gameCursor`): a brackets, chevron, bar, diamond or frame cursor that glides to the `useMenuNav` current item, then focus, then hover. Under reduced motion it jumps instead of gliding.
89
+ - `GameSlider` (`@jgengine/react/gameSlider`): a drawn slider (a groove with a knurled knob, or lit pips) with keyboard, drag and screen-reader support. Inside a menu, Up and Down still move between rows.
90
+ - `useGameFonts`, `loadGameFonts` and `gameFontStacks` (`@jgengine/react/gameFonts`): load a game's bundled display and body fonts and get CSS stacks with installed fallbacks.
91
+ - `HudFade` and `useHudAwake` (`@jgengine/react/hudFade`): a HUD group fades after a quiet spell, comes back when a watched value changes or on hover, and holds while urgent.
92
+ - `GameFramesPreview` fixture (`bun run shoot --fixture GameFramesPreview`): every material and cut, game buttons with each cursor, and both slider looks.
93
+ - `UiKitMenuPreview` fixtures for the Continue and Saves panes on every kit (`UiKitMenu-<kit>-continue`, `-saves`).
94
+ - A guard test (`hudNoFilters.test.ts`) fails if a UI kit, a game-UI block or an engine HUD primitive uses `filter` or `backdrop-filter`.
95
+ - World model primitives for every genre:
96
+ - `kinds` are things placed at runtime (towers, rides, racks), with costs, build times, limits and refunds.
97
+ - `slots` and `grids` hold placements with footprints.
98
+ - `actions` (upgrade, repair, train, sell) have costs that can be refused and scale by a target fact.
99
+ - `totals` sum, count or take the max across subjects.
100
+ - `flows` are per-second streams like income and upkeep.
101
+ - `queues` time work on the engine work queue.
102
+ - Refusals say what was short ("Upgrade needs 60 more gold").
103
+ - `@jgengine/core/worldModel/gameSpec`: `defineGameSpec` turns a whole game declaration into an installable system. Its world is one store, so saves and co-op sync come with it. It provides `<id>.place/remove/act/cancel/job.start` commands that refuse with reasons, `onReady`/`onRemoved`/`onLanded` callbacks to put builds on screen, and named code hooks for anything a declaration can't say (#2413).
104
+ - World model kinds take `tags`: an action's `on`, a total's `of` and `instances(tag)` cover every kind carrying the tag (one Upgrade for every tower).
105
+ - Selling refunds a share of everything an instance cost, build plus upgrades (`WorldInstance.paid`); tick `removed` now lists `{ id, kind, label, refund }`.
106
+ - `place(kind, at, { free, built })` seeds a layout without paying or waiting.
107
+ - Kinds and actions take `refuse`, the game's own words when `when`/`whenTarget` doesn't hold.
108
+ - A timed action already queued on a target refuses `busy` instead of queueing twice.
109
+ - Hook calls carry `target`: the instance an action landed on or that just became ready.
110
+ - `defineGameSpec` adds `onRestored` (every built instance on the first frame and after a save loads) and `accepting` (refuse all commands with a message, e.g. "The park is closed"); `<id>.remove` refuses when there is nothing to remove.
111
+ - UI kits (`@jgengine/react/uiKit`, `uiKitRoot`, `uiKits`): `defineGame({ uiKit: "ink" })` picks one of eight complete visual languages — `ink`, `paper`, `parchment`, `terminal`, `holo`, `broadcast`, `arcade`, `signal` — each with its own shapes, type, motion and UI cue sounds. Every kit ships the same seven parts (`KitButton`, `KitPanel`, `KitMeter`, `KitPrompt`, `KitToast`, `KitMenu`, `KitMinimapFrame`), so switching kits never breaks a game. `customizeKit(base, { tokens, components, css, motion, sounds })` reshapes one per game.
112
+ - With a kit, `GameMenu`/`GamePauseMenu` draw their verbs and detail pane in it, the engine settings, saves and credits panes take the kit's colours and type, the shell's notice stack renders kit toasts, and the kit's cue sounds replace the default UI sounds (a game's `audio.uiCues` still wins).
113
+ - `KitActionPrompt`, `useActionGlyph` and `useInputDevice`/`actionGlyph` (`@jgengine/react/inputDevice`) show the bound key, pad button or a tap target for the device the player is using.
114
+ - `KitObjective`, `KitResultScreen` and `KitBanner` (`@jgengine/react/kitFlow`): the next-goal card with distance, a direction arrow, countdown warnings and an idle hint; a run/day result screen; a phase-change banner.
115
+ - `NoticeStack` `maxVisible` (default 3): older notices wait instead of piling up.
116
+ - Preview fixtures `UiKitsPreview` (all eight kits), `UiKit-<name>` and `UiKitMenu-<name>` (a kit's pause menu with the engine settings pane).
117
+
118
+ ### Changed
119
+
120
+ - A game with no `look` now renders `"cinematic"`: ACES tone mapping, restrained bloom (strength 0.22, threshold 0.95), AO, contact shadows and antialiasing, lit by its `mood`. Write `look: "neutral"` for the old unstyled output.
121
+ - Post chains antialias with TAA on high and ultra and SMAA on low and medium when `aa` is unset. The graphics setting "Anti-aliasing (SMAA)" is now "Anti-aliasing" and gates both.
122
+ - The default sky dome shrinks to fit inside a short camera far plane instead of clipping to black.
123
+ - The prototype-look check no longer flags a game for leaving `look` unset.
124
+ - Settings slider rows draw a `GameSlider` instead of the browser's range input.
125
+ - `GameFrame` draws its rim, cast shadow and glow as clipped plates under the face instead of CSS `filter: drop-shadow(…)`. Over a live 3D scene a filtered element is re-rendered every frame: Odd Orbit's 16 HUD frames at 1600x900 ran at 16–17 fps with the old filter rims and 60 fps with plates. The rim looks the same, and the soft cast shadow is now a hard plate 4px below the frame. `gameFrameVars()` now sets `--jg-gf-rim`, `--jg-gf-rim-w`, `--jg-gf-face-cut` and `--jg-gf-glow`, and hand-dressed elements add `data-shadow` or `data-glow` for the shadow or glow plate.
126
+ - Hover, press, focus and disabled on game buttons light or dim the face with an overlay instead of `brightness()` and `grayscale()` filters.
127
+ - The paper and arcade UI kits, `GameCursor`, `GameSlider`, the game menu, the save list, `ActionHud`, `SelectionHud`, notices, `HudFrame`, the interaction prompt, the map, `MenuScreen`'s `blur` scrim, waypoint markers and the modal backdrop no longer use `filter` or `backdrop-filter`. Panels that had a backdrop blur use a denser fill so text stays readable.
128
+ - A free placement (`place(kind, at, { free: true })`) is still worth its price: selling it refunds the kind's share; cancelling it mid-build returns nothing.
129
+ - `GameSpecDecl.onRemoved` receives the removed view instead of an id.
130
+ - `GameMenu` stacks its verbs above the detail pane on a portrait phone instead of squeezing two columns.
131
+
132
+ ### Fixed
133
+
134
+ - A retained loop started without a position is no longer occlusion-tested from where it began, so a world-wide bed is not muffled when the player walks behind a wall.
135
+ - `ctx.game.audio.intensity(amount)` (event `audio.intensity`) lets a game with no avatar of its own (a tower defense, an RTS) raise the adaptive soundtrack: a released wave, raiders on the field.
136
+ - `audio/enclosure` probe shows the ceiling and wall distances behind the automatic reverb choice.
137
+ - World model triggers now also check at the start of a stepped tick, so a value an event or `set` pushed to a threshold between ticks (a grip knocked to exactly 0) fires its trigger before calming nudges it back.
138
+ - `HudCanvas` lane blocks reach the real right and bottom edges on compact displays. The lane frame and block sizes were measured in on-screen pixels and then placed inside the canvas zoom, so with `compactScale={0.86}` blocks stopped about 116 px short of the right edge at 844x390 and 52 px short on a 390x844 phone. They are now measured in the HUD's own pixels.
139
+ - Quantized glTF meshes (meshopt / `KHR_mesh_quantization`) no longer collapse into boxes when merged or baked into crowds: attributes are converted to float before transforms.
140
+ - Crowd bakes no longer render people black: Rocketbox pulls drop the unused vertex colours and the crowd material turns `vertexColors` off.
141
+ - Khronos pulls bake transmission glass into plain alpha glass and zero the emissive factor when the emissive map is removed (no more white-glowing tyres).
142
+ - Road collision follows live road sources: `resolveEnvironmentField` rebuilds the road drape when the roads change, so ground under re-laid streets stays right.
143
+ - `bun run drive <game> --game-dir <path> --flow <name>` reads the flow from the served game's own `proofs/flows/`, not the engine checkout's `Games/<game>`.
144
+ - Shots in chase, orbit, top-down, RTS and side-view games now aim at what is under the cursor (tested against the collision world, 0.5-2 ms per shot instead of a 40 ms full-scene raycast); first-person, shoulder and pointer-locked play keep the crosshair. `pointer.aim` still overrides.
145
+ - Tracers start at the shooter's gun hand (or a `muzzle` node) instead of the body centre, and at the first-person gun in first person. Tracers last 200 ms and are thicker so they read.
146
+ - A cursor (ray) aim now strays inside the gun's catalog spread like a look aim; it was always laser-straight. A ray aim passes `spread: 0` for a precise shot. `Aim.spread` is allowed on ray aims.
147
+ - The shell's settings dialog now draws inside the game's HUD theme and UI kit. It takes the kit's colours and type, or the game's `hudTheme`, and it sits above notices and the result screen. The selected tab, toggles and hairlines read on light kits.
148
+ - Continue and Saves panes on a kit:
149
+ - The save name, eyebrow, saved time and Resume button read on every kit, using the kit's accent ink.
150
+ - On a short pane the picture shrinks first, so Resume stays on screen.
151
+ - Save cards grow instead of clipping their Load button.
152
+ - Long chips trim on phone cards.
153
+ - The pane scrolls inside the kit panel, and its heading stays put.
154
+ - Ink and paper panel heads keep the aside (distance, count) on the title's row. A long eyebrow pushes the title under it, and titles wrap only between words.
155
+ - Settings rows and tabs on a kit pane take the kit's corners and display type: square on ink, arcade and terminal, soft on paper. Every kit gets a `radius` token, and the slider readout never runs off a phone-width row.
156
+ - The `KitObjective` direction arrow has a shaft, so it reads as pointing where it points.
157
+ - `defineGameSpec` reports `onReady` for a build that stood before the first frame when the game has no `onRestored`.
158
+ - Clicking a HUD button with the mouse or a finger no longer leaves it focused, so gameplay keys (pause, movement, hotkeys) keep working after the click. Dialogs, menus and forms keep their focus.
159
+
29
160
  ## 0.39.0
30
161
 
31
162
  ### Migrate
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgengine/rapier",
3
- "version": "0.39.0",
3
+ "version": "0.40.0",
4
4
  "description": "Rapier physics backend for JGengine",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -30,7 +30,7 @@
30
30
  "test": "bun test src"
31
31
  },
32
32
  "dependencies": {
33
- "@jgengine/core": "^0.39.0",
33
+ "@jgengine/core": "^0.40.0",
34
34
  "@dimforge/rapier3d-compat": "0.19.3"
35
35
  },
36
36
  "publishConfig": {