Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/AUTHORING.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,9 @@ export default (
);
```

The example pack's `window/` sources are a complete JSX project: `index.ts` lists the documents, `art.ts` declares its
art, `handles.ts` declares the shop and search handles, and `shop.tsx`, `search.tsx`, and `status_hud.tsx` use them.
The example pack's `window/` sources are a complete project: `index.ts` lists the documents, `art.ts` declares its art,
`handles.ts` declares the windows' handles, `shop.tsx`, `search.tsx`, `upgrades.tsx`, and `status_hud.tsx` use them in
JSX, and `clock_hud.ts` is a HUD written with the [`raw` API](#raw-api).

### Slot sections

Expand Down
57 changes: 39 additions & 18 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,26 @@ example/
│ ├── src/
│ │ └── window/ # UI sources — stripped from the built pack
│ │ ├── index.ts # defineWindows entry: the sprite catalog, windows, HUDs, and previews
│ │ ├── handles.ts # typed bindings shared by the shop and search windows
│ │ ├── art.ts # inline art: icons, coin, vents, and the search field sprite
│ │ ├── handles.ts # typed bindings shared by the windows
│ │ ├── art.ts # inline art: icons, coin, vents, bars, and the rank sprites
│ │ ├── shop.tsx # paged catalog, selections, toggles, and buttons
│ │ ├── search.tsx # linked native-anvil catalog search
│ │ ├── upgrades.tsx # themed workshop: styles, vars, cards with a face per stage, choices, and a hotspot
│ │ ├── status_hud.tsx # the shader-relocated actionbar HUDs
│ ├── build/previews/ # preview PNGs of the shop and HUDs, rewritten by every build
│ │ └── clock_hud.ts # the clock HUD, written with the function-style raw API
│ ├── build/previews/ # preview PNGs of the windows and HUDs, rewritten by every build
│ └── dist/ # build output: fonts, glyph atlas, shaders, zip
└── (server lives in ../jvm/example)
```

The Minestom server is the Gradle module `jvm/example`, which depends on `window-minestom`. `Main.kt` boots the server,
`Market.kt` is a throwaway domain model, and `MyShop.kt` implements the **generated** `ShopView`. `MyStatusHud.kt`
implements the **generated** HUD views. The pack uses `target: "minestom"`, so the shop view takes the `Player` it is
shown to: `Main.kt` opens it with `MyShop(player, market).open()`. Generated HUD views take no player; the handwritten
ones that need it take it themselves. `Main.kt` joins the status HUDs into one action-bar `HudStack` and resends it with
`player.sendHud(stack)` every second, which re-renders their clocks and stays ahead of the action bar fading out. The
bindings live under `generated/`, produced by the rpp plugin — committed, do not hand-edit.
`Market.kt` and `Workshop.kt` are a throwaway domain model, and `MyShop.kt` and `MyUpgrades.kt` implement the
**generated** `ShopView` and `UpgradesView`. `MyStatusHud.kt` implements the **generated** HUD views. The pack uses
`target: "minestom"`, so a window view takes the `Player` it is shown to: `Main.kt` opens the shop with
`MyShop(player, market).open()`. Generated HUD views take no player; the handwritten ones that need it take it
themselves. `Main.kt` joins the status HUDs into one action-bar `HudStack` and resends it with `player.sendHud(stack)`
every tick, which keeps the wave bar moving smoothly, re-renders the clocks, and stays ahead of the action bar fading
out. The bindings live under `generated/`, produced by the rpp plugin — committed, do not hand-edit.

## Run it

Expand All @@ -39,12 +42,27 @@ just example-run # boot the Minestom server on :25565
```

Then connect a 26.2 client. The catalog opens on spawn with 30 real item entries, category and sort choices,
favorites/affordability toggles, paging, reactive selection and wallet text, plus buy/search/exit actions. Search opens
a static anvil screen with the native rename field and back and search buttons; searching returns to the catalog
filtered by the query, which the catalog's clear button resets and reopening search restores.
favorites/affordability toggles, paging, reactive selection and wallet text, plus buy/search/workshop/exit actions.
Search opens a static anvil screen with the native rename field and back and search buttons; searching returns to the
catalog filtered by the query, which the catalog's clear button resets and reopening search restores.

The workshop, under its own theme, sells three upgrades for the same coins: a click on a card buys the chosen amount of
levels, each card shows its level as text and is marked new, shows a bar, or is marked maxed, and the rank badge takes
the shared tone. A maxed card takes no clicks, so hovering it shows "Fully upgraded" and no outline. Its levels last
until the server stops.

The actionbar-backed HUD demo is disabled by default so the inventory examples stay visually focused. Enable it with
`-Dwindow.hud.enabled=true`; use `-Dwindow.hud.spriteDebug=true` to print each HUD's static art to chat.
`-Dwindow.hud.enabled=true`; use `-Dwindow.hud.spriteDebug=true` to print each HUD's static art to chat. The pack blanks
vanilla's experience bar, and one of the HUDs draws its wave bar there.

| command | does |
| -------------------------------- | ---------------------------------------------------------------------- |
| `/shop` | opens the catalog, like the hotbar emerald |
| `/upgrades` | opens the workshop, like the catalog's Workshop button |
| `/tone <ok\|warn\|danger\|auto>` | pins the tone the HUDs and newly opened windows draw in; `auto` unpins |
| `/bar <fraction\|auto>` | pins how full the wave bar and a newly opened shop's bar are |

`rpp build` prints where the compiler's output bytes go and fails above the `size.budget` in `rpp.config.ts`.

Override the port with `-Dwindow.port=…`. The server also serves `dist/window-example.zip` as a required resource pack
at `http://127.0.0.1:25567/pack.zip`; override with `-Dwindow.pack=…`, `-Dwindow.pack.port=…`, or `-Dwindow.pack.url=…`
Expand All @@ -54,8 +72,11 @@ when testing from another machine.

The rpp plugin emits `internal` pack data (`WindowPackData`, `WindowFonts`, `WindowSpacers`, and friends), the public
`WindowDefinitions` and `WindowHudDefinitions`, and one public abstract class for each window/HUD. Each handle in
`handles.ts` becomes a member of `ShopView`: `text` handles such as `balance` and `status` are functions returning a
`Component`, `flag` handles such as `canBuy` are Boolean functions, `action` handles such as `buy` are `onBuy(click)`
handlers, `products` is a `WindowCollection` that `MyShop` backs with a `WindowList`, and the `category`/`sort`
selections and `favorites`/`affordable` toggles are UI-owned `var`s with `on…Changed` hooks. `MyStatusHud` implements
each HUD's `text` handles. Omit one, rebuild, and the breakage surfaces at compile time.
`handles.ts` becomes a member of the views that use it: `text` handles such as `balance` and `status` are functions
returning a `Component`, `flag` handles such as `canBuy` are Boolean functions, `action` handles such as `buy` are
`onBuy(click)` handlers, `products` is a `WindowCollection` that `MyShop` backs with a `WindowList`, and the
`category`/`sort` selections and `favorites`/`affordable` toggles are UI-owned `var`s with `on…Changed` hooks. In
`UpgradesView` the indexed handles take the card's index (`upgradeLevel(index)`, `onUpgrade(click)` with `click.index`),
the `upgradeStage` value and the `rank` sprite return generated enums, and `upgradeProgress` and `tone` return a bar's
fraction and a tint's palette entry. `MyStatusHud` implements each HUD's handles. Omit one, rebuild, and the breakage
surfaces at compile time.
3 changes: 2 additions & 1 deletion example/pack/rpp.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export default defineConfig({
window({
namespace: "window",
coreShaders: { hud: true, hover: true },
vanilla: { anvil: { field: "search_field" }, slotHighlight: false },
vanilla: { anvil: { field: "search_field" }, hud: { experience: false }, slotHighlight: false },
size: { report: true, budget: 1_000_000 },
previews: { output: "build/previews" },
kotlin: {
package: "com.chunkzero.window.example.generated",
Expand Down
17 changes: 17 additions & 0 deletions example/pack/src/window/art.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,23 @@ export const budgetFill = shape({
inset_depth: 0,
});

/** The plate a maxed upgrade shows in place of its level bar. */
export const maxedPlate = shape({
kind: "panel",
fill: "#ffb20b",
border_color: "#8d3c03",
border_width: 1,
radius: 2,
inset_depth: 0,
});

/** White art for the `rank` sprite slot, which a tint colors. */
export const ranks = {
rank_1: texture("window/icons/rank_1.png"),
rank_2: texture("window/icons/rank_2.png"),
rank_3: texture("window/icons/rank_3.png"),
};

export const icons = {
back: texture("window/icons/back.png"),
clear: texture("window/icons/clear.png"),
Expand Down
20 changes: 20 additions & 0 deletions example/pack/src/window/clock_hud.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { text } from "plugin:window/bind";
import * as raw from "plugin:window/raw";
import { art } from "plugin:window/theme/industrial";

export const runtime = text("runtime");

/** The clock, written with the function-style `raw` API; it builds the same document as a `<Hud>`. */
export default raw.hud({
name: "status_top_center",
frame: art.hud,
shader: { origin: { x: 0.5, y: 0 }, anchor: { x: 0.5, y: 0 }, x: 0, y: 4 },
children: [
raw.box({
style: { direction: "column", padding: 3 },
children: [
raw.text(runtime, { width: 34, align: "center", color: "#ffffff", shadow: true, small_caps: true }),
],
}),
],
});
34 changes: 32 additions & 2 deletions example/pack/src/window/handles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { action, collection, flag, fraction, input, selection, text, tint, toggle } from "plugin:window/bind";
import {
action,
collection,
flag,
fraction,
input,
selection,
sprite,
text,
tint,
toggle,
value,
} from "plugin:window/bind";

// Shared by the shop and the status HUD
// Shared by the shop, the upgrades window, and the status HUD
export const tone = tint("tone", { ok: "#3ddc84", warn: "#ffb020", danger: "#ff4d4d" });

// Shop
Expand Down Expand Up @@ -36,8 +48,26 @@ export const balance = text("balance");
export const buy = action("buy");
export const canBuy = flag("can_buy");
export const buyLabel = text("buy_label");
export const openUpgrades = action("open_upgrades");

// Catalog search
export const query = input("query");
export const back = action("back");
export const confirm = action("confirm");

// Upgrades; `status` and `balance` are the shop's handles
export const UPGRADES = 3;
const cards = { shape: [UPGRADES] } as const;
export const upgrade = action("upgrade", cards);
export const upgradeName = text("upgrade_name", cards);
export const upgradeLevel = text("upgrade_level", cards);
export const upgradeCost = text("upgrade_cost", cards);
/** How far each upgrade is toward its last level. */
export const upgradeProgress = fraction("upgrade_progress", cards);
export const upgradeStage = value("upgrade_stage", ["new", "open", "maxed"], cards);

export const amount = selection("amount", ["one", "five", "max"]);
/** The workshop's rank badge, one of the catalog sprites `index.ts` registers. */
export const rank = sprite("rank", { only: ["rank_1", "rank_2", "rank_3"] });
export const rankName = text("rank_name");
export const openShop = action("open_shop");
Binary file added example/pack/src/window/icons/rank_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pack/src/window/icons/rank_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pack/src/window/icons/rank_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 35 additions & 15 deletions example/pack/src/window/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import { defineWindows, preview } from "plugin:window/ui";
import type { PreviewOptions } from "plugin:window/ui";
import { art } from "plugin:window/theme/industrial";

import { ranks } from "./art.ts";
import clock, { runtime } from "./clock_hud.ts";
import * as handles from "./handles.ts";
import search from "./search.tsx";
import shop from "./shop.tsx";
import statusHuds, { coins, hint, power, rate, waveCharge } from "./status_hud.tsx";
import statusHuds, { bottomCenter, coins, hint, power, rate, topLeft, waveBar, waveCharge } from "./status_hud.tsx";
import upgrades from "./upgrades.tsx";

/** A preview of the workshop with one card in each stage. */
const upgradesPreview = (options: PreviewOptions) =>
preview(
upgrades,
[
[handles.upgradeName, ["Drill", "Furnace", "Conveyor"]],
[handles.upgradeLevel, ["Lv 0/5", "Lv 3/5", "Lv 5/5"]],
[handles.upgradeCost, ["900", "810", ""]],
[handles.upgradeProgress, [0, 0.6, 1]],
[handles.upgradeStage, ["new", "open", "maxed"]],
[handles.amount, "five"],
[handles.balance, "2500"],
[handles.rank, "rank_2"],
[handles.rankName, "Journeyman"],
[handles.status, "8 of 15 levels"],
],
options,
);

export default defineWindows({
sprites: { searchField: art.inputField },
windows: [shop, search],
sprites: { searchField: art.inputField, ...ranks },
windows: [shop, search, upgrades],
huds: statusHuds,
// `rpp build` writes these to build/previews/, one PNG per preview.
previews: [
Expand All @@ -29,32 +52,29 @@ export default defineWindows({
[handles.canBuy, true],
[handles.buyLabel, "Buy 210"],
]),
upgradesPreview({ scale: 3 }),
// The same window with its regions outlined.
upgradesPreview({ name: "upgrades_regions", outlines: true }),
preview(
statusHuds[0],
topLeft,
[
[coins, "2500"],
[rate, "+10"],
[power, "x1"],
],
{ scale: 3 },
),
// The tinted hint and wave bar in the tint's first palette entry, then in another.
preview(
statusHuds[5],
[
[hint, "Next wave in 4s"],
[waveCharge, 0.6],
],
{ scale: 3 },
),
preview(clock, [[runtime, "4:07"]], { scale: 3 }),
// The tinted hint in the tint's first palette entry, then in another.
preview(bottomCenter, [[hint, "Next wave in 4s"]], { scale: 3 }),
preview(
statusHuds[5],
bottomCenter,
[
[hint, "Wave incoming"],
[handles.tone, "danger"],
[waveCharge, 0.97],
],
{ name: "status_bottom_center_danger", scale: 3 },
),
preview(waveBar, [[waveCharge, 0.6]], { scale: 3 }),
],
});
10 changes: 7 additions & 3 deletions example/pack/src/window/shop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
hasQuery,
next,
nextLabel,
openUpgrades,
page,
previous,
previousLabel,
Expand Down Expand Up @@ -122,7 +123,7 @@ export default (
</Container>

<Player>
<Tabs bind={sort} span={3} tooltip={(value) => sortTooltips[value]} hover={false}>
<Tabs bind={sort} span={3} tooltip={(value) => sortTooltips[value]}>
{(_, i) => <Text bind={sortLabel.at(i)} />}
</Tabs>

Expand Down Expand Up @@ -152,14 +153,17 @@ export default (
<Button
onClick={buy}
enabled={canBuy}
span={6}
span={4}
frame={art.buttonAccent}
tooltip="Buy selected item"
disabled={{ tooltip: "Buy selected item unavailable" }}
>
<Text bind={buyLabel} color="#2a1200" shadow={false} />
</Button>
<Button close span={3}>
<Button onClick={openUpgrades} span={3} tooltip="Upgrade the foundry">
Workshop
</Button>
<Button close span={2}>
Exit
</Button>
</Hotbar>
Expand Down
Loading
Loading