·
data · drop-in viewer
asset⌬ datadataprimary: values.yaml·part ofpackage economyKit.package·originates fromworld d48725e2-1…●2problems
What it does
No description provided yet.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
This asset doesn't declare a schema or structured payload.
⌬ Metadata
description
economyKit sample currency: Coins (coins icon style), new wallets start with 100.Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
10items
# currency (economyKit contract)
One currency a game's players can hold: gold, gems, a premium token, anything. Add a `.data` asset bound to `economyKit.currency` anywhere in a world and economyKit finds it by itself; no code changes.
| Field | Meaning |
|---|---|
| `id` | The name code uses (`"coins"`). Letters, digits, `_` and `-`. |
| `nameKey` | Translation key for the name players read (`economy.currency_coins`, or one in the game's own `locales/<lang>/<ns>.json`). |
| `name` | Fallback name when no `nameKey` is given or the key has no translation. |
| `icon` | One of the eight icon styles: `coins`, `gems`, `tokens`, `scrap`, `souls`, `energy`, `tickets`, `banknotes`. |
| `color` | Accent colour for counters and popups. |
| `start` | What a new player's wallet starts with. |
| `max` | The most one wallet can hold; anything above is refused. |
| `persist` | Kept between sessions (true) or reset each session (false, e.g. per-match cash). |
| `order` | Sort order in wallet displays (lower first). |
▲ 0↑ born
# economyKit
economyKit 1.0.13 gives any multiplayer Zero game money, cheat-proof wallets and shops: currencies, prices, income and fees are data, and one authoritative machine decides every buy, sell, grant, spend and trade.
**What you get:** six shop screens (grid store, vendor list, vending machine, between-wave quick buy, upgrade tree, two-player trade window), three shopkeepers to put in your world (a merchant behind his counter, a vending kiosk, a hooded spirit of light), eight currency styles, four wallet displays, income, fees and upkeep, player-to-player trading, menusKit's eight looks, keyboard, gamepad and touch controls, phone layouts, English and Brazilian Portuguese, and 29 automated tests.
**Install:** search ZeroMind for economyKit and install it into your world (from code or the shell, `zeromind.installAsset` with the package id `d113a24e-3a87-40d2-a725-af49b56f629b`). One install brings inventoryKit, saveKit, menusKit and navUiKit with it. Then try the shopkeeper below.
## A shopkeeper selling three items
Install **economyKit** into a new world (one install brings inventoryKit, saveKit, menusKit and navUiKit with it), replace the contents of `scenes/main.scene/entrypoint.luau` with this, and press Play:
```lua
local Economy = require("economyKit.economy")
function onLoad()
Economy.setup({ wallet = "corner" })
Economy.defineShop({
id = "smithy", title = "The Smithy", screen = "vendor",
items = {
{ item = "sword", price = 40 },
{ item = "shield", price = 60 },
{ item = "healthPotion", price = 12 },
},
})
Economy.spawnShopkeeper({ kind = "counter", shop = "smithy", position = { 0, 0, 6 } })
end
```
A merchant stands behind his counter 6 m in front of you, and your coins sit in the top-left corner (every new wallet starts with 100). Walk up to him and press **E** (gamepad **X**, or tap the **Shop** button on a touch screen). Buy the sword and the shield: the bank takes 100 coins, both land in your inventoryKit bag (Tab), and the health potion now shows dimmed with "Need 12 more"; pressing Buy on it is refused with "Not enough Coins: you need 12 more". Escape (gamepad B, or the ✕ button) closes the shop and you walk again. Stop and press Play again: your coins and items are still there.
## Styles, and how to switch them
Every style of a family draws the same data and raises the same events, so a world switches with one setting and nothing else. Every style also carries tags (`style`, `genre`, `setting`, plus `input` for screens and `size` for wallets) so a game can pick by them; see the end of this section.
| Family | Styles | Switch with |
|---|---|---|
| Shop screens | `grid` (store of cards with a detail pane), `vendor` (shopkeeper portrait, greeting and priced list), `vending` (vending machine with slot codes, LCD and DISPENSE), `quickBuy` (strip of big buttons between waves, with the wave timer), `upgradeTree` (tiers that unlock the next), `trade` (two players' offers side by side) | a shop's `screen` field; `Economy.setScreen("vending")` forces every shop into one style; `Economy.open(shop, { screen = "grid" })` for one opening |
| Currency icons | `coins`, `gems`, `tokens`, `scrap`, `souls`, `energy` (energy cells), `tickets`, `banknotes`: each its own painted icon, frame shape and glow, plus a 3D model for coins on the ground | a currency's `icon` field |
| Wallet displays | `corner` (rolling counters, top left), `panel` (full wallet with names, top right, or bottom right with `panelBottom`), `popup` ("+10" / "−25" rising where the eye is), `minimal` (one line of text, bottom left; on a phone held upright that cannot fit the names it shows each currency's icon and number, shortening amounts of 10,000 and more to "12k" or "1.2M" only if they still would not fit, so a full wallet stays on one line) | `Economy.setup({ wallet = "panel" })` or `Economy.setWallet({ "corner", "popup" })` (several at once is fine) |
| Shopkeepers | `counter` (a merchant behind a wooden counter, warm lamp), `machine` (a vending kiosk with a lit screen), `holo` (a hooded spirit of light floating over a rune plinth) | `Economy.spawnShopkeeper({ kind = "holo", shop = ... })`, or the `Shopkeeper` component's `kind` field in a scene. A placed keeper's `screen` field picks the screen it opens; changing it (or `kind`, `shop`, `radius`) while playing takes effect at once |
| Looks | menusKit's eight: `scifi`, `fantasy`, `cartoon`, `pixel`, `minimal`, `military`, `horror`, `cozy` | a shop's `look` field, or `Economy.setLook("pixel")` for every shop without one. Every screen keeps its text readable in every look: secondary text, prices and warnings are held to at least 3.6:1 contrast with the panel they sit on, and the screens that paint their own dark body (vending machine, quick buy, upgrade tree) switch a parchment or paper look to light ink there |
`Economy.catalogue()` returns all of these as data, plus every currency, shop, price list, income, sink and event the game knows. Its `screens`, `icons`, `wallets` and `keepers` are lists of `{ id, name, label, tags }` (`name` in the player's language), for example:
```lua
{ id = "energy", name = "Energy cells", label = "economy.icon_energy",
tags = { style = { "neon", "tech", "battery cell" }, genre = { "shooter", "strategy", "tower defense" }, setting = { "sci-fi", "cyberpunk" } } }
```
`Economy.styles(family, query)` picks from one family (`"screen"`, `"icon"`, `"wallet"` or `"keeper"`) by tag: `Economy.styles("icon", { setting = "sci-fi" })` gives energy cells and scrap, `Economy.styles("keeper", { genre = "rpg" })` the counter merchant, and a bare word matches any tag (`Economy.styles("screen", "gamepad")`).
Things a player cannot afford always look it: dimmed, with the price in red and how much is missing ("Need 12 more"), or "Sold out" / "Needs Boots" for stock limits and upgrade prerequisites. The bank refuses them anyway if a request arrives.
## Add a currency
Add one data asset anywhere in your world, bound to `economyKit.currency`; the kit finds it by itself. `myGame/currencies/stars.data/values.yaml`:
```yaml
contract: economyKit.currency
values:
id: stars
name: "Stars"
nameKey: "economy.currency_stars" # optional: a key in your own locales/<lang>/economy.json
icon: tokens # one of the eight icon styles
color: "#ffd84a"
start: 0 # what a new wallet holds
max: 99999 # the most one wallet can hold
persist: true # false: starts over every session (match cash)
order: 10 # position in wallet displays
```
Or from code: `Economy.defineCurrency({ id = "stars", icon = "tokens", start = 0 })`. Your own currencies are always on; of the kit's eight samples only `coins` is on unless you pass `Economy.setup({ currencies = { "coins", "gems" } })`.
## Add a price list and a shop
A shop points at a price list, so shops can share prices and a game changes a price in one place. `myGame/prices/armory.data/values.yaml`:
```yaml
contract: economyKit.priceList
values:
id: armory
currency: coins # prices are in this unless an entry says otherwise
sellRate: 0.5 # what the shop pays back, as a share of the price
entries:
- { item: sword, price: 40 }
- { item: arrows, price: 8, qty: 10 } # one purchase gives 10
- { item: amulet, price: 6, currency: gems } # priced in another currency
- { item: ironKey, price: 80, stock: 1 } # one per player
- { item: helmet, price: 90, requires: sword } # upgrade trees: buy the sword first
- { item: bread, price: 4, sell: 0 } # the shop will not buy it back
```
`myGame/shops/armory.data/values.yaml`:
```yaml
contract: economyKit.shop
values:
id: armory
title: "The Armory"
titleKey: "" # or a translation key
priceList: armory
screen: grid # grid, vendor, vending, quickBuy, upgradeTree, trade
keeper: counter # counter, machine, holo
look: fantasy # any menusKit look, or "" for the game's
buy: true
sell: true
fees: [marketFee] # economyKit.sink ids charged on purchases and sales here
```
Items are inventoryKit items (`Inventory.catalogue().items` lists them; a game adds its own with inventoryKit's `inventoryKit.inventoryItem` contract). Put the shop in the world with `Economy.spawnShopkeeper({ kind = "counter", shop = "armory", position = { x, y, z }, yaw = 0 })` in `onLoad`, or add the **Shopkeeper** component to an entity in your scene. A keeper faces its own −Z (yaw 0 faces a player standing towards −Z). `Economy.open("armory")` opens a shop from anywhere (a menu, a key, a trigger).
## Income and sinks
```yaml
contract: economyKit.income
values: { id: salary, currency: coins, amount: 5, every: 10, onWave: false, waveGrowth: 0, cap: 1000 }
```
`every` pays every connected player each N seconds; `onWave: true` pays when the host's game code calls `Economy.wave(n)` (amount + waveGrowth × (wave − 1)); `cap` stops paying a player who already holds that much.
```yaml
contract: economyKit.sink
values: { id: marketFee, kind: fee, currency: coins, amount: 0, percent: 10, appliesTo: [buy] }
```
`kind: fee` is added to purchases, sales or trades of the shops that list it (`appliesTo`: `buy`, `sell`, `trade`; trades use `Economy.setup{ tradeFees = { ... } }`). `kind: upkeep` takes `amount` from every player every `every` seconds, never below `floor`. `kind: charge` is a one-off a game takes with `Economy.charge("revive")`. The kit ships `allowance`, `waveBounty`, `soulTrickle` (incomes) and `marketFee`, `tradeFee`, `rent`, `revive` (sinks); switch samples on with `Economy.setup({ income = { "allowance" }, sinks = { "rent" } })`.
## Events
```lua
Economy.on("balanceChanged", function(e) print(e.currency, e.value, e.delta, e.why.kind) end)
Economy.on("purchaseMade", function(e) print("bought", e.item, e.count) end)
Economy.on("purchaseRefused", function(e) print(e.text) end) -- "Not enough Coins: you need 40 more"
Economy.on("saleMade", function(e) end)
Economy.on("tradeCompleted", function(trade) end)
```
All events: `balanceChanged`, `purchaseMade`, `purchaseRefused`, `saleMade`, `saleRefused`, `tradeCompleted`, `tradeUpdated`, `tradeRefused`, `tradeCancelled`, `spendRefused`, `refused` (any refusal), `shopOpened`, `shopClosed`, `bankChanged`, `ready`, and `wave` on the host. Each refusal carries `code`, `values` and `text` (in the player's language). On the machine running the bank, `"bank.<event>"` hears every player's events (`bank.purchaseMade`, `bank.tamper`, ...), for server-side game logic.
## Trading between two players
A shop with `screen = "trade"` (the sample `tradingPost`) opens the trade window: pick a player in the room, they get the invitation as a window of their own (and a navUiKit toast when the game runs a navUiKit HUD), both put items from their bags and money in, and both press Accept. Any change resets both accepts. The bank then checks both sides can still cover their offers, takes the items out of both bags, sees them gone, moves the money and hands the items over. If anything fails along the way (an item moved, a player left, a balance changed) everything is given back and nothing moves. From code: `Economy.tradeWith(peerId)`, `tradeOffer({ items = {...}, money = {...} })`, `tradeReady()`, `tradeCancel()`. `Economy.tradeWith("npc:tobi")` practises with a trader who answers on his own (define your own in `setup{ npcTraders = ... }`).
## How it stays cheat-proof
- **One bank.** Exactly one machine in a room runs the bank: the lowest peer id (the host when the room was made; the next machine takes over if it leaves). Every other machine only sends requests on the `economyKit` channel. The relay names the sender, and the bank maps that machine to its account through the scene's players registry (the avatar the relay says it owns), so nobody can act for someone else.
- **Requests, not balances.** A machine asks to buy, sell, spend or trade; the bank checks the price list, stock, prerequisites, room in the bag and its own copy of the wallet, then applies the change whole or refuses with a reason. Retried requests are answered again, never charged twice.
- **Selling and trading take items first.** The bank asks the player's machine to hand items over and pays only once it sees them gone from that player's synced inventory.
- **Grants.** `Economy.grant(player, currency, n)` called on the bank's machine (host game code: kill rewards, quests) applies at once. From a player's machine it is refused unless the game allowed that reason: `setup{ clientGrants = { quest = { max = 50, perMinute = 100 } } }`.
- **Kept between sessions.** Wallets live in the world's runtime data under `economyKit/<ns>.<world>/w/<account>` (the namespace plus this world's id, so a wallet never follows a player into another world), written only by the bank. A change to those paths the bank did not make (a player writing the shared store by hand) is put back at once and raised as `bank.tamper`. Each player's machine also copies its confirmed wallet into its **saveKit** profile (`Save.get("economyKit")`), so it travels with the player's save; the bank never trusts that copy. Coins on the ground (`Economy.spawnCoin`) pay only a player whose avatar the bank sees standing there.
Checked here: a balance written straight into the shared store (99,999 coins) was put back within a frame and the following purchase was still refused for lack of gems; a balance written into the player's own saveKit profile changed nothing; balances, purchases and stock came back after leaving and re-entering play.
## Controls, phones and the web
Keyboard: **E** opens the shop in front of you, arrows/WASD move, **Enter/Space** buys, **F** or **Q/R** switch Buy/Sell (and accept a trade), **1-6** pick in the quick-buy strip, **Escape** closes. Gamepad: **X** opens, d-pad moves, **A** buys, **Y**/bumpers switch tabs, **B** closes. Touch and mouse: tap the **Shop** button, tap cards and buttons, ✕ closes. A finger's tap on any of the kit's buttons is also read by the kit itself and pressed once, so it works even when the touch controls are up (#21441); a tap the UI presses as well still counts once. While a shop is open the player's walking and camera are stood down (`economyKit.economyBlock`); closing hands them back, whichever way it closes (the quick-buy strip leaves you free to move).
Every label in every screen reads whole in every look, in both languages, on a desktop window and on a phone held either way: a wrapping label is never narrower than its longest word, with 5% to spare for text a browser draws a little wider, a name in a fixed-width tile gets a smaller font before it would break, and a one-line label is never squeezed narrower than its text. The wallet displays read whole too: the minimal line is never wider than the screen, whatever `minimalWidth` a game asks for, and keeps each entry in one piece (on a phone held upright, all eight sample currencies fit on one line as icon and number, whatever the amounts: amounts of 10,000 and more are shortened there, "12k" or "1.2M", only when the full numbers would not fit), the wallet panel is wide enough for its longest currency name beside its longest amount, and on a short screen it takes shorter rows so a full wallet fits its height. On a phone each shop's title has a row of its own beside the close button, with the Buy and Sell tabs and the wallet chips below it, so a long title never shares its room. On a screen held upright every screen and wallet display is laid out for a 430-point phone and scaled to fit (the same way inventoryKit does), clear of the safe area; on a short screen (a phone held sideways) the shop panels, the quick-buy tiles, the vendor's portrait and the grid's detail pane shrink so every button stays on screen. `Economy.setInsets({ left = 180 })` keeps the kit clear of your own HUD. All timers use the engine's wall clock, so the kit runs the same in the browser.
## Translations
Every word comes from `locales/en/economy.json` and `locales/pt-BR/economy.json` in the package (shop titles, greetings, currency and item names, refusals, buttons). A game overrides any word, or adds a language, with its own `/locales/<lang>/economy.json`. Names you add use `nameKey` / `titleKey` / `greetingKey`, or fall back to the plain `name` / `title`.
## Reference
`local Economy = require("economyKit.economy")`
- Setup: `setup(opts)` (currencies, income, sinks, wallet, screen, look, ns, clientGrants, clientWaves, tradeFees, npcTraders, save, labels, toasts, insets, and where the wallet displays sit: `panelTop` or `panelBottom` (points from the top or bottom of the screen), `popupPos` (`{ left | right, top }`), `minimalBottom`, `minimalWidth`), `configure(opts)`, `config()`, `setWallet`, `setScreen`, `setLook`, `setInsets`, `catalogue()`, `styles(family, query)`.
- Data: `define(kind, t)`, `defineCurrency`, `definePriceList`, `defineShop` (with inline `items`), `defineIncome`, `defineSink`, `reload()`, `currencies()`, `currency(id)`, `shops()`, `shop(id)`, `priceList(id)`.
- Wallet: `balance(cur)`, `balances()`, `wallet()`, `isReady()`, `key()`, `canAfford(costs)`, `quote(shop, item, n)`.
- Actions (each returns a request id and takes an optional `cb(info)`): `buy(shop, item, n)`, `sell(shop, item, n)`, `spend(cur, n, reason)` or `spend({ cur = n }, nil, reason)`, `charge(sinkId)`, `grant(player, cur, n, reason)`, `wave(n)`.
- Trading: `tradeWith(peer | "npc:<id>")`, `trade()`, `tradeAnswer(accept)`, `tradeOffer(offer)`, `tradeReady(ready)`, `tradeCancel()`, `tradePartners()`.
- Screens: `open(shop, opts)`, `close()`, `isOpen()`, `current()`.
- World: `spawnShopkeeper(opts)` (kind, shop, position, yaw, label, labelWidth, marker, name), `spawnCoin(pos, opts)`.
- Events: `on(event, fn)` returns a function that stops listening. Text: `text(reason)`, `currencyName`, `itemName`, `shopTitle`.
- Bank: `isBank()`, `bankPeer()`.
- Kits it brings: `inventory()` returns the inventoryKit module economyKit runs on (`inventoryKit.inventory`), so your code and other kits change the same bag economyKit fills without installing inventoryKit themselves.
Components: **Shopkeeper** (kind, shop, screen, label, labelWidth, marker, radius), **CoinPickup** (placed by `spawnCoin`), **EconomyHost** (started by the kit itself; never place it).
## Tests
`economyKitTests` (29 tests) runs the sample data through the contracts, the ledger and the bank against fake players and a fake shared store: buying with fees, refusals with shortfalls, stock and prerequisites, retries, selling, tamper repair, grants, income, waves, upkeep and charges; trades that complete, that fail for money, that are refused for a full bag, and that are cancelled before both accept or fail halfway through the hand-over (nothing moves, and only goods that really left a bag go back); and saving the economy and loading it into a new bank, with wallets, purchases and stock coming back the same. On the screen side: every shop screen and wallet display at desktop and phone sizes, every screen readable in all eight looks (at least 3:1 contrast for every text), no label able to break inside a word or be squeezed narrower than its text on any screen, look, size or language, the minimal wallet line fitting an upright phone with all eight currencies at any amounts, shop titles staying whole on an upright phone, the close button drawn as a cross in every look, every style carrying tags, both languages, and this README's first example's calls. `tools.use("tests", "run", { suite = "economyKitTests" })`.
## Known limits
- The bank runs on a player's machine (the lowest peer), not on a dedicated server: Zero rooms have none. Machines that are not the bank cannot change any balance; a player alone in a world is their own bank, so a modified client playing alone can change its own money.
- Items are as trustworthy as inventoryKit's inventories, which each player's own machine owns: the bank checks that a seller holds what they sell, as their synced inventory shows it.
- #14448: two engines signed in to one account collide as one player, so a real two-player trade on one account cannot be run. The kit gives a second session of the same account its own wallet (`u:<id>#2`); the trade rules are covered by the tests with two fake players.
- #20750: the web build's frame rate drops in busy multiplayer scenes. Market Square (all six stalls and every wallet display at once) in the browser ran at about 14 to 22 fps, and the gallery's own counter read 17 FPS (about 60 ms a frame); this was measured on a machine busy with other work at the time, so treat it as a rough figure.
- #21420: installing a package with several dependencies takes about a minute; economyKit brings four kits with it.
- #11895: a screen-sized panel cannot be positioned smaller than the screen, so every kit screen places its elements inside a full-screen root of its own.
- #7781: a 3D text keeps its previous string until it is respawned, so a shopkeeper's name sign is respawned, not edited, when the player switches language.
- #21441: with touch active, a tap on a content button above the touch controls can be missed. The kit reads taps on its own buttons itself and presses them once, so the Shop button, Buy and close work under a finger; a game's own buttons next to the kit's are not covered.
## Changes
- **1.0.13**: economyKit and inventoryKit's own components run on one inventoryKit again. economyKit's modules were pinned to an older inventoryKit release than the inventoryKit package it ships, so an install loaded two copies of the bag code: `Inventory.setup{ hud = false }` (and `Economy.inventory()`) reached economyKit's copy while the bag strip was drawn by the other, and the strip could not be turned off. inventoryKit is updated to its latest release and every reference repinned to it; 29 tests.
- **1.0.12**: `Economy.inventory()` returns the inventoryKit module economyKit runs on, so a kit built on economyKit (buildPlaceKit, for one) can turn the bag's strip and keys off without requiring inventoryKit itself. A direct require of a kit that came in as economyKit's dependency was published with no version, and ZeroMind then refused to install the kit that made it.
- **1.0.11**: documentation only, no code changes from 1.0.10: the package description and the README's opening now read as a store listing (what you get, how to install, then the shopkeeper example).
- **1.0.10**: shop titles stay whole on a phone held upright in every look: "Adventurer's Outfitters" broke as "Adventurer'" / "s Outfitters" in the pixel look because the title shared a wrapping row with the wallet chips and had only about 1.5% more room than its longest word, so text drawn a little wider in a browser broke at the apostrophe. A phone header now gives the title a row of its own beside the close button (tabs and wallet chips below), and every wrapping label keeps 5% more than its longest word (plus its letter spacing and two points). The minimal wallet line really fits all eight sample currencies on one line on an upright phone: inside the floating wallet box the wrapping row had been laid out narrower than its own entries and dropped the last one (banknotes) onto a second line, so on a phone the row now gets its room as a width; icons count at their true widths (banknotes and tickets are wider than tall), the line is fitted with 6% to spare, its font and gaps tighten slightly when needed, and amounts of 10,000 and more shorten there ("12k", "1.2M") only if the full numbers still would not fit. The wallet panel is now as wide as its longest currency name beside its longest amount ("Células de energia" was squeezed beside a large amount in Portuguese). New test: shop titles stay whole on an upright phone, and the wallet-line test now covers large amounts and true icon widths (29 tests).
- **1.0.9**: the minimal wallet line reads whole on a phone held upright: it is never wider than the screen, whatever `minimalWidth` a game asks for (Market Square asked for 1240 points and "Banknotes" ran off the right edge), every entry stays in one piece, and when the names cannot fit on one line it shows each currency's icon and number, so all eight sample currencies fit one line. On a short screen (a phone held sideways) the wallet panel takes shorter rows and starts at the top, so a full wallet of eight fits its height. Known limits now carry the measured browser frame rate for Market Square. New test: the minimal line fits an upright phone (28 tests).
- **1.0.8**: every label reads whole in every look, language and size: a wrapping label is never narrower than its longest word (names like "Cloth" and "Sword" broke between letters because the UI lays labels out in whole points), names in fixed-width tiles shrink their font instead of breaking, one-line labels are never squeezed by their row, and long titles and hints wrap. Phones held sideways keep every button on screen (shorter panels, smaller quick-buy tiles, a compact vendor portrait and grid detail pane, stacked upgrade tiers when columns get narrow). The kit presses its own buttons when a finger taps them, so touch works with the touch controls up (#21441). Shopkeeper signs are respawned when the language changes (#7781). Wallets are kept per world (`economyKit/<ns>.<world>/...`), so a store an engine carried over from another world never sets a player's balance; existing wallets in a world that ran 1.0.7 start over once. New test: no label can break inside a word (27 tests).
- **1.0.7**: documentation only, no code changes from 1.0.6: the Known limits entry on simulated touches cites its issue (#21441), and the test suite's description counts and lists all 26 tests.
- **1.0.6**: a placed shopkeeper picks up a change to its `screen` (or `kind`, `shop`, `radius`) while playing; every screen reads in every look (the quick-buy strip and upgrade tree used dark fantasy ink on their dark tiles; secondary text, prices and warnings are now held to at least 3.6:1 contrast); the close button is a drawn cross, not a character some looks' fonts lacked; the catalogue lists screens, icons, wallets and keepers with names and `style` / `genre` / `setting` tags, and `Economy.styles` picks by tag; `panelBottom` and `minimalWidth` place the wallet panel and widen the minimal line; review records for the Portuguese catalog. Fixed: a trade that failed halfway through the hand-over could send items back to a player whose own hand-over had failed, copying them; it now returns only goods it saw leave a bag. Six new tests: full-bag and cancelled-halfway trades, a save and load round trip, contrast in every look, the close cross, and style tags.
- **1.0.5**: `Economy.setup` starts inventoryKit for the player, so bought items come back after Stop and Play (or a rejoin) in a game that never calls `Inventory.setup` itself, such as the three-item example above. Before, the bag was saved but not loaded again until something was given.
- **1.0.4**: a shopkeeper's name sign stays on one line and shrinks to fit `labelWidth` (long names used to wrap and draw over themselves); the floating coin over a keeper can be turned off (`marker = false`); `popupPos` places the "+10 / −25" popups and stacks many at once in columns of four; signs are rasterised at scale 1 (above 1 cropped the tops of the letters).
- **1.0.3**: refreshed model previews; no code changes from 1.0.2.
- **1.0.2**: installs cleanly into an empty world: its Model and Light components now resolve to the engine's own, not to older copies another kit had carried into the authoring world, and saveKit is pinned as a full dependency.
- **1.0.1**: first release on the world's main branch. The text module is now `economyKit.lang` (a package-relative `~.text` failed to resolve after a world reload).
- **1.0.0**: a candidate published from a side branch for the fresh-install check; superseded by 1.0.1.
▲ 0↑ born
backing path · economyKit.package/data/currencies/coins.data
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
2problems
From dependencies
2 problems across 1 depeconomyKit.currency→ datatypevia data_contract
●
structure.missing_required_file
required file `README.md` is missing — Describe what gameplay concept this contract models and what it is used for.
●
structure.missing_required_file
required file `.metadata` is missing — Describe the gameplay concept this contract types.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up
agent_score is exposed.usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor
+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
—%no reports yet
Sign in to report whether this part worked for you.
Discussion
Scoped to this part · feeds back into the world's score.
0comments
Sign in to post.sign in
No comments yet. Be the first.