diff --git a/docs/requirements.md b/docs/requirements.md index 0591c46..2d0d873 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -101,7 +101,7 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro - **Enemy buffer zone** — space between the enemy's defence stations and the enemy spawn boundary (`enemy_buffer_width`). - REQ-GW-SCROLL-LIMIT: The player can scroll the view horizontally from the asteroid's left edge to the current set of enemy defence stations (the enemy buffer zone is not visible). - REQ-GW-PUSH-EXPAND: When the player destroys a set of enemy defence stations, the scrollable area is extended by `world.toml [push].push_expand_columns` tiles. A new enemy buffer zone of `world.toml [regions].enemy_buffer_width` tiles is added beyond the new enemy defence stations. -- REQ-GW-ASTEROID-EXPAND: When the player unlocks an asteroid expansion, `world.toml [expansion].columns_per_expansion` tile columns are added to the left of the asteroid. +- REQ-GW-ASTEROID-EXPAND: When the player unlocks an asteroid expansion, `world.toml [expansion].columns_per_expansion` tile columns are added to the left of the asteroid. Those are the columns drawn as locked ground before the purchase (REQ-UI-LOCKED-ASTEROID) and the ones the expansion button stands on (REQ-UI-EXPAND-BUTTON). ## HQ & Game Over @@ -449,7 +449,7 @@ Several UI elements carry a tooltip: the header bar's artifact count (REQ-UI-ART **An item named on something that already carries a tooltip of its own carries none.** One display shows one tooltip, and the one it was given for its own sake is the one that wins: the building block cost on a build button says nothing about blocks, because the button is there to explain the building (REQ-UI-BUILD-COST, REQ-UI-BUILD-TOOLTIP). The module selection buttons are excluded on the same ground even though a module without a `modules.toml` description leaves its button silent (REQ-MOD-UI-DIALOG, REQ-MOD-UI-MODULE-TOOLTIP): the button is a described control by design, and whether one module happens to carry the text is a gap in the config rather than a decision about the UI — the same material icon must not explain itself on one button and not on the one beside it. - **Everywhere else the item is explained, on a clickable control or not**: the asteroid expansion button's cost (REQ-UI-EXPAND-BUTTON), the blueprint cards' costs (REQ-UI-BLUEPRINT-CARD), the recipe summaries on the selection dialog's option buttons (REQ-UI-SELECT-OPTIONS), and the recipe lines of the unlock-choice dialog's options (REQ-DEF-SCHEMATIC-DROP). These say what they do and nothing about the items they name, and the two answers do not compete: an option button says what a recipe makes, an item tooltip says where an input comes from. + **Everywhere else the item is explained, on a clickable control or not**: the asteroid expansion button's cost line (REQ-UI-EXPAND-BUTTON), the blueprint cards' costs (REQ-UI-BLUEPRINT-CARD), the recipe summaries on the selection dialog's option buttons (REQ-UI-SELECT-OPTIONS), and the recipe lines of the unlock-choice dialog's options (REQ-DEF-SCHEMATIC-DROP). These say what they do and nothing about the items they name, and the two answers do not compete: an option button says what a recipe makes, an item tooltip says where an input comes from. **On a clickable control the tooltip shows on hover only.** The click belongs to the control — it buys the expansion, picks the blueprint, selects the recipe — so it cannot also be the gesture that explains (REQ-UI-TOOLTIP-TRIGGER). A click shows the tooltip at once wherever the item is named on something with no click action of its own: an item chip, a value in a row, the selection panel's recipe summary, and the recipe lines of an unlock-choice option, whose card is chosen through a button of its own rather than by being clicked (REQ-DEF-SCHEMATIC-DROP). @@ -457,7 +457,7 @@ Several UI elements carry a tooltip: the header bar's artifact count (REQ-UI-ART ### Layout -The screen is a single column: a header bar across the top and the game world view filling the whole area below it. There is no side panel. All three permanent UI widgets float over the game world — the build button bar (REQ-UI-BUILD-BAR) at its bottom center, the selection panel (REQ-UI-SELECTION-PANEL) beside whatever is currently selected — or wherever the player has dragged it by its header (REQ-UI-SELECTION-PANEL-DRAG) — shown only while something is selected and holding its place on the screen until the next selection, and the controls panel (REQ-UI-CONTROLS-PANEL) in its bottom-left corner, beside the build button bar and rising above it only when the two would overlap. Blueprints have no permanent screen real estate; they are reached through modal dialogs (REQ-UI-BLUEPRINT-DIALOG): +The screen is a single column: a header bar across the top and the game world view filling the whole area below it. There is no side panel. All three permanent UI widgets float over the game world — the build button bar (REQ-UI-BUILD-BAR) at its bottom center, the selection panel (REQ-UI-SELECTION-PANEL) beside whatever is currently selected — or wherever the player has dragged it by its header (REQ-UI-SELECTION-PANEL-DRAG) — shown only while something is selected and holding its place on the screen until the next selection, and the controls panel (REQ-UI-CONTROLS-PANEL) in its bottom-left corner, beside the build button bar and rising above it only when the two would overlap. Each of the three keeps a place on the screen; the asteroid expansion button (REQ-UI-EXPAND-BUTTON) floats over the world as well but keeps a place in the **world** instead, standing on the ground it would buy and panning away with it, which is why it is not drawn below. Blueprints have no permanent screen real estate; they are reached through modal dialogs (REQ-UI-BLUEPRINT-DIALOG): ``` +-----------------------------------------------------------+ @@ -475,14 +475,18 @@ The screen is a single column: a header bar across the top and the game world vi (full window width) ``` -- REQ-UI-HEADER: The header bar spans the full width of the game window and always shows the elapsed survival time, the current global building blocks stock, and the artifact count (REQ-WIN-ARTIFACT-COUNT) displayed as `Artifacts: x/y` (where `x` is the current artifact count and `y` is `world.toml [world].artifact_win_count`) on the left, the boss wave counter and boss countdown (REQ-UI-BOSS-STATUS) and an asteroid expansion button (REQ-UI-EXPAND-BUTTON) to the left of the speed buttons, and game speed controls on the right. +- REQ-UI-HEADER: The header bar spans the full width of the game window and always shows the elapsed survival time, the current global building blocks stock, and the artifact count (REQ-WIN-ARTIFACT-COUNT) displayed as `Artifacts: x/y` (where `x` is the current artifact count and `y` is `world.toml [world].artifact_win_count`) on the left, the boss wave counter and boss countdown (REQ-UI-BOSS-STATUS) to the left of the speed buttons, and game speed controls on the right. The asteroid expansion button is not among them: it stands in the world on the ground it would buy (REQ-UI-EXPAND-BUTTON). - REQ-UI-BLOCKS-ICON: In the header bar (REQ-UI-HEADER), the global building blocks stock is displayed as `Stock: ` followed by the `building_block` item icon (REQ-UI-ITEM-ICON) — e.g. `Stock: 200` then a small block icon — replacing the `Building Blocks: ` text label. The icon is sized to the header text height. When no icon file exists for `building_block` (a missing icon is not an error, REQ-UI-ITEM-ICON), the display falls back to the `Stock: Blocks` text. The display states an amount of an item, so it shows that item's production tooltip in either form (REQ-UI-ITEM-VALUE-TOOLTIP). - REQ-UI-ARTIFACTS-TOOLTIP: The header bar's artifact count display (REQ-UI-HEADER) shows a tooltip — on hover and, the display having no click action of its own, on click as well (REQ-UI-TOOLTIP-TRIGGER, REQ-UI-TOOLTIP-DISMISS) — with the descriptive text defined in `world.toml [world].artifact_tooltip` — intended to tell the player what artifacts are, how they are obtained (REQ-DEF-SCHEMATIC-DROP), and that collecting `world.toml [world].artifact_win_count` of them wins the game (REQ-WIN-ARTIFACT-COUNT). If the field is unset, the artifact count display shows no tooltip. An artifact count is not an amount of an item, so unlike the block stock beside it (REQ-UI-BLOCKS-ICON, REQ-UI-ITEM-VALUE-TOOLTIP) it has no production path to show and states configured text instead — the one display in the header bar that does. It is distinct as well from the build/module button tooltips (REQ-UI-BUILD-TOOLTIP, REQ-MOD-UI-MODULE-TOOLTIP). - REQ-UI-BOSS-STATUS: The header bar displays, to the left of the speed buttons, the current boss wave counter (REQ-WAV-BOSS-COUNTER) and the time remaining on the boss countdown (REQ-WAV-BOSS-COUNTDOWN). The boss wave counter is shown as `Boss Wave #` and the countdown as `Next boss: `, where `` is the remaining seconds formatted as whole minutes and two-digit seconds. Both values update continuously as the simulation runs. - REQ-UI-SPEED: The game speed controls in the header bar are buttons for 0×, 0.5×, 1×, 2×, and 10× speed. The currently active speed is shown as selected. All game simulation (production, movement, threat accumulation, wave timing) scales with the selected speed. 0× pauses the game. - REQ-UI-PAUSE-BORDER: While the game is paused (speed 0×, whether set via the speed controls (REQ-UI-SPEED), the Space toggle (REQ-UI-HOTKEYS), or an auto-pausing modal), a vignette border is drawn around the edges of the game world view to make the paused state hard to miss. The border is black and fades in the alpha channel from fully transparent at its inner (center-facing) edge to 50% opacity at the viewport edge, over a thickness of 100 pixels (capped at half the smaller viewport dimension on very small views). - REQ-UI-DECONSTRUCT-BORDER: While deconstruct mode is active (REQ-UI-DECONSTRUCT-BUTTON, REQ-UI-HOTKEYS), a vignette border is drawn around the edges of the game world view to signal the mode, matching the geometry of the paused-state vignette (REQ-UI-PAUSE-BORDER): a 100-pixel thickness (capped at half the smaller viewport dimension on very small views) with the four sides meeting along mitred corner diagonals. It fades in the alpha channel from fully transparent at its inner (center-facing) edge to the deconstruct tint color at the viewport edge. The color — including its alpha, which sets the peak opacity at the viewport edge — is read from `visuals.toml [overlays].deconstruct_tint`, the same deconstruct-mode color used for the hover tint. The border is presentation-only and has no effect on the simulation. If the game is both paused and in deconstruct mode, both vignettes are drawn and compose over each other. -- REQ-UI-EXPAND-BUTTON: The header bar shows an asteroid expansion button captioned `Expand: ` followed by the `building_block` item icon (REQ-UI-BLOCKS-ICON, REQ-UI-ITEM-ICON) in place of the trailing `Blocks` word, where `` is the current expansion cost computed from `world.toml [expansion].cost_building_blocks_formula` at the current number of purchased expansions (REQ-EXP-COST). When no icon file exists for `building_block`, the caption falls back to the `Expand: Blocks` text. The button carries no tooltip of its own, so the cost explains the item it names on hover (REQ-UI-ITEM-VALUE-TOOLTIP). Clicking the button unlocks the next asteroid expansion (REQ-EXP-UNLOCK, REQ-GW-ASTEROID-EXPAND), spending that many building blocks from the global stock. The button is disabled when the player cannot currently afford the cost (consistent with REQ-UI-BUILD-DISABLED). The caption updates as the cost changes with each purchased expansion. +- REQ-UI-EXPAND-BUTTON: **The asteroid expansion button stands on the ground it would buy.** It is not a fixed control in the header bar: it floats over the game world view (REQ-UI-WORLD-SIZE) **centered on the columns the next expansion unlocks** — the `world.toml [expansion].columns_per_expansion_tiles` locked columns immediately left of the buildable edge (REQ-UI-LOCKED-ASTEROID, REQ-GW-ASTEROID-EXPAND). That is a position in the world, not on the screen, so the button **pans with the view** (REQ-UI-SCROLL) as the tiles beneath it do, and leaves the view entirely when they do: it is part of that piece of ground rather than a control the screen always carries. Nothing brings it back while the player looks elsewhere, and nothing needs to — the pan limit keeps the columns it stands on within reach at all times, since the leftmost pan centers the buildable edge and those columns lie just left of it (REQ-GW-SCROLL-LIMIT). The middle of those columns is the middle of the view vertically, the asteroid running the world's full height (REQ-GW-HEIGHT, REQ-GW-TILE-SIZE). + + The button keeps its size from its face rather than filling the columns it marks, and that face is **two lines**: `Expand` on the first, and the cost on the second as `` followed by the `building_block` item icon (REQ-UI-BLOCKS-ICON, REQ-UI-ITEM-ICON) in place of a trailing `Blocks` word, where `` is the current expansion cost computed from `world.toml [expansion].cost_building_blocks_formula` at the current number of purchased expansions (REQ-EXP-COST). When no icon file exists for `building_block`, the second line falls back to the ` Blocks` text. Two lines rather than one caption because the cost is then a display of its own: **the cost line is what carries the item production tooltip**, as every other value stating an amount of an item does (REQ-UI-ITEM-VALUE-TOOLTIP), on hover only — the click is the button's. The word `Expand` carries nothing; it names the action, not an item. Clicking it unlocks the next asteroid expansion (REQ-EXP-UNLOCK, REQ-GW-ASTEROID-EXPAND), spending that many building blocks from the global stock. The button is disabled when the player cannot currently afford the cost (consistent with REQ-UI-BUILD-DISABLED). Its caption and position both update with each purchased expansion: the cost rises and the button moves a further `columns_per_expansion_tiles` to the left, onto the next stretch of locked ground. + + - **Input.** Mouse events over the button are consumed by it and never reach the game world, as they are over the floating panels (REQ-UI-BUILD-BAR, REQ-UI-SELECTION-PANEL): hovering it shows no builder-mode ghost on the tile beneath, and clicking it neither places a building nor changes the selection. Unlike those panels it is not part of their placement pass (REQ-UI-SELECTION-PANEL), and they do not step around it: the button marks a place in the world, so a panel may cover it as it covers any other world content. - REQ-UI-WORLD-SIZE: The game world view occupies the full width of the game window and the full height below the header bar. No widget insets it: the build button bar (REQ-UI-BUILD-BAR), the selection panel (REQ-UI-SELECTION-PANEL), and the controls panel (REQ-UI-CONTROLS-PANEL) float over it. - REQ-UI-SELECTION-PANEL: The **selection panel** (the panel described under Selection Panel, REQ-UI-SINGLE-SELECTION and following) is a widget that **floats over the game world view** (REQ-UI-WORLD-SIZE), placed **beside the objects it describes** rather than at a fixed corner of the view, so it appears where the player is already looking. It is **sized to its content in both width and height**, so it grows and shrinks as the content changes. Two distances shape its placement, and they are deliberately different: a small **edge margin** it keeps from the view's edges and from the widgets it steps around, and a larger **selection gap** of half a tile (REQ-GW-TILE-SIZE) it keeps from the selection itself, so the panel stands clear of the objects it describes instead of touching them. The selection gap applies **horizontally only**, on the side facing the selection; vertically the panel stays level with the selection (see **Vertical placement**). - **Anchor rectangle.** The panel is placed against the screen rectangle of the selection **at the moment that selection started**: the footprint of the single object selected (a building or construction site, an actor, or a piece of debris), or, when the selection started as a multi-selection (REQ-UI-MULTI-SELECT), the bounding box of all the objects it started with. @@ -550,6 +554,11 @@ The screen is a single column: a header bar across the top and the game world vi - The Salvage Bay has no recipe and no production cycle (REQ-BLD-SALVAGE-BAY); its status light uses only two states: **green** while its output buffer holds at least one unit of scrap, and **red** while its output buffer is empty. The Salvage Bay's status light is never grey or yellow. - The four fill colors (grey, green, red, yellow) and the outline color are read from `visuals.toml [status_light]`, consistent with the other rendering-only colors. The status light is presentation-only and has no effect on the simulation. - REQ-UI-HP-BARS: All entities with HP — the HQ, player and enemy defence stations, and player and enemy ships — render an HP bar below them. The bar is always visible regardless of current HP. The bar's filled portion represents the fraction of current HP to maximum HP. +- REQ-UI-LOCKED-ASTEROID: **The asteroid the player has not unlocked yet is drawn, tinted — and the part of it one purchase away is tinted apart from the rest.** Every asteroid column left of the buildable edge — the edge that moves left with each expansion (REQ-GW-ASTEROID-EXPAND) — is drawn in the asteroid's own fill under a tint, so the player sees the ground expansion will win them rather than empty space. Two tints, both read from `visuals.toml [overlays]`: + - the `world.toml [expansion].columns_per_expansion_tiles` columns immediately left of the buildable edge — the ones the next purchase unlocks, and the ones the expansion button stands on (REQ-UI-EXPAND-BUTTON) — take **`next_expansion`**; + - everything further left takes **`locked_asteroid`**. + + `next_expansion` is the **more transparent** of the two, so the ground one purchase away reads as nearer to being the player's than the ground behind it, and the boundary between them shows exactly how far the next expansion reaches. Both are tints over the same asteroid fill: the distinction is how much of that fill shows through, not a different color of ground. The tinted area has **no left edge of its own**: expansions are unbounded (REQ-EXP-COST prices them but never stops them), so the tint runs as far left as the view reaches. What bounds it in practice is the pan limit (REQ-GW-SCROLL-LIMIT): the view stops with the buildable edge at its center, so the locked area fills the left half of the view at the leftmost pan and no more of it is ever seen. Locked tiles are ground the player cannot build on until they are unlocked (REQ-BLD-PLACE-VALID). - REQ-UI-NO-ZOOM: The view has a fixed zoom level; the player cannot zoom in or out. - REQ-UI-HOTKEYS: Global keyboard shortcuts: - **Space** — toggles pause. Pressing Space pauses (sets speed to 0×) and stores the previously selected non-zero speed; pressing Space again restores that speed.