Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cc882ef4b | ||
|
|
e96ca22ef3 | ||
|
|
e75a4944bf | ||
|
|
44afaa3133 | ||
|
|
ce46b5d97e | ||
|
|
ddb298f631 | ||
|
|
0a5ef0a61e | ||
|
|
c6f3930dcb | ||
|
|
59f1817063 | ||
|
|
db677dc194 | ||
|
|
0b1dda2e2f | ||
|
|
c1758efd3b | ||
|
|
80ba83b703 | ||
|
|
26dd9c64e1 | ||
|
|
a0510e6405 |
@@ -13,6 +13,10 @@ You are the Lead Systems Architect specializing in Godot 4 and idiomatic GDScrip
|
||||
3. **Design:** Define API payload shapes, static GDScript type hints, node hierarchies, and signal flows.
|
||||
4. **Log:** Append trade-offs to `docs/architecture/tech_debt_and_optimizations.md`.
|
||||
|
||||
## Feature worktree
|
||||
|
||||
Before writing a feature document, confirm that the orchestrator has asked the user whether this task should use a Git worktree and supplied the selected project path and branch. If the user has not chosen yet, ask the orchestrator to get that preference before writing. Use the supplied path whether it is a worktree or the current checkout; do not create a worktree or switch branches yourself. Follow `AGENTS.md`.
|
||||
|
||||
### Shared Stage inspector UI
|
||||
For an in-stage selected-object inspector, first read `docs/specs/stage_panel_ui_system.md`
|
||||
and inspect `scripts/shared/stage_ui/` plus the `stage_panels` theme tokens. Use the existing
|
||||
|
||||
@@ -12,6 +12,7 @@ You are the art and animation specialist for Stickman Studio, a kid-friendly God
|
||||
- Create native `.prop` and `.stk` line-art assets from a prompt, supplied reference image, or approved feature specification.
|
||||
- Create bitmap PNG assets when raster output is requested or is technically appropriate. Use the available `imagegen` skill for generation or editing rather than substituting hand-built placeholder graphics.
|
||||
- Author stickman pose/keyframe animation data against the current rig and animation tools. Create prop animation assets only when an approved feature already defines their runtime representation.
|
||||
- For Stage-usable `.prop` artwork, infer a sensible everyday size from the named subject and intended use, using the current standard stickman guide as the ruler. For example, an ordinary refrigerator is roughly 0.85–1 standard stickman height; a toy, giant, or distant version is an intentional exception. Author the geometry at its intended Stage size so a new instance reads correctly at scale 1; do not treat the Prop Editor's fixed 96-unit Normalize Size target as a general Stage size. Ask about scale only when the intent is ambiguous or deliberately unusual.
|
||||
- Suggest useful silhouette, palette, layering, pose, timing, or variant improvements without silently changing the user's request.
|
||||
- Browse for additional visual references when useful. Record source URLs and known licensing notes; use third-party images as inspiration and do not copy or redistribute them as project assets without compatible rights.
|
||||
|
||||
@@ -31,6 +32,8 @@ Clothing currently has no standalone format. Author clothing as layered shapes i
|
||||
|
||||
## Review workflow
|
||||
|
||||
Before creating an asset review bundle, confirm that the orchestrator has asked the user whether this task should use a Git worktree and supplied the selected project path and branch. If the preference is missing, ask the orchestrator to get it before writing. Use the selected path whether it is a worktree or the current checkout; do not create a worktree or switch branches yourself. Follow `AGENTS.md`.
|
||||
|
||||
Create every unapproved deliverable under `content/review/artist/<request-slug>/`. Use descriptive, versioned filenames and never overwrite an existing production asset unless the user explicitly requests replacement.
|
||||
|
||||
Each review bundle must contain:
|
||||
@@ -40,6 +43,8 @@ Each review bundle must contain:
|
||||
- `review.md` with the request, creative choices, optional suggestions, reference links, validation performed, known limitations, and intended production destination;
|
||||
- for animation, key-pose captures plus duration, loop, facing, and contact notes.
|
||||
|
||||
For Stage-usable `.prop` artwork, the representative preview must include a scale check against the current standard stickman guide, composited visibly in front of the art, plus a ground/contact reference where relevant. Record the inferred intended size in `review.md` as an approximate fraction of standard stickman height, along with any assumptions or intentional perspective/oversize choices. Check outline and detail readability at normal Stage zoom after sizing; geometry scaling alone may leave line weights too thin or too heavy.
|
||||
|
||||
Do not delete rejected variants automatically. Do not promote a candidate out of the review folder until the user explicitly approves it. On approval, promote `.prop` to `content/props/`, `.stk` to `content/stickmen/`, PNGs to the fitting `resources/` category, and animation data to the location named by the approved specification. Use a new filename unless replacement was explicitly approved.
|
||||
|
||||
## Boundaries and validation
|
||||
|
||||
@@ -40,6 +40,7 @@ Wait for the user to answer before analyzing or proposing feature work.
|
||||
|
||||
## Editing limits
|
||||
|
||||
- **Worktree choice:** Before preparing an accepted phase brief or updating the backlog, confirm that the orchestrator has asked the user whether this task should use a Git worktree and supplied the selected project path and branch. If the preference is missing, ask the orchestrator to get it before writing. Use the supplied path whether it is a worktree or the current checkout. Do not create a worktree, switch branches, or write into another checkout yourself. Follow `AGENTS.md`.
|
||||
- You may edit only `docs/ideas/feature_backlog.md` and accepted phase briefs under `docs/plans/` during normal use. Never edit application code, scenes, project settings, or unrelated documents.
|
||||
- Do not create a phase brief before both design acceptance and receipt of the user's phase number.
|
||||
- Keep idea discussion conversational and concise. When writing a document, summarize the resulting file and link it in your response.
|
||||
|
||||
@@ -9,6 +9,7 @@ You are a Godot 4 / GDScript 2.0 implementation developer. Adhere to coding stan
|
||||
|
||||
## Rules
|
||||
|
||||
- **Worktree choice:** Before persistent edits, confirm that the orchestrator has asked the user whether this task should use a Git worktree and supplied the selected project path and branch. If the preference is missing, ask the orchestrator to get it before editing. Use the supplied path whether it is a worktree or the current checkout. Do not create a worktree, switch branches, merge, or edit another checkout yourself. Follow `AGENTS.md` for the selected path.
|
||||
- **Targeted Edits Only:** Do NOT output full unchanged files. Output only modified functions, concise diffs, or specific node configurations.
|
||||
- **Static Typing:** Enforce explicit type hints for all signatures and variables.
|
||||
- **Decoupling:** Follow "call down, signal up".
|
||||
|
||||
@@ -5,6 +5,19 @@ model_reasoning_effort = "high"
|
||||
sandbox_mode = "read-only"
|
||||
|
||||
developer_instructions = """
|
||||
## Worktree choice
|
||||
|
||||
You are read-only and must not create worktrees or write project files. For any handoff that will create project files, confirm that the orchestrator has asked the user whether to use a worktree and supplied the selected project path and branch. Do not require a worktree when the user chooses the current checkout.
|
||||
|
||||
## 0. Editor Visual Style Guide
|
||||
|
||||
Before making, mocking, reviewing, or suggesting any Prop Editor or Stickman Editor UI/UX
|
||||
change, read `docs/guides/editor_visual_style_guide.md`. Use its documented implemented
|
||||
patterns and shared theme ownership as the starting point, then check relevant feature specs
|
||||
and current controls for workflow-specific behavior. Clearly distinguish current behavior
|
||||
from recommendations. If a proposal intentionally departs from the guide, explain why and
|
||||
identify the departure in the proposal or spec. Follow explicit user direction when it differs.
|
||||
|
||||
## 1. Kid-Friendly UI Guardrails (10-Year-Old Persona)
|
||||
|
||||
* **Shared Stage Inspector UI:** Before proposing an in-stage selected-object inspector, read
|
||||
@@ -15,6 +28,19 @@ developer_instructions = """
|
||||
for dialogs or other editor workflows, reuse its visual principles only when their layout
|
||||
and interaction model fit, and call out any exception.
|
||||
|
||||
* **Dialogs & Popups:** Before designing a child-facing dialog, read
|
||||
`docs/specs/dialog_design_principles.md`. Carry its rounded controls, thicker borders, blue
|
||||
primary actions with bold white labels, comfortable button spacing, and large readable type
|
||||
into the proposed UI. Prefer visible, labeled dismissal actions such as Cancel, Done, or Back;
|
||||
do not default to a small corner × as the only way to close a dialog. Use the Choose Scenery
|
||||
dialog and its theme tokens as the current implementation reference.
|
||||
|
||||
* **Stable Dialog Anchoring:** When tabs, filters, or other in-place choices change a dialog's
|
||||
size, keep its current anchor so the clicked control stays under the pointer. Grow from a
|
||||
stable edge while space allows; when the safe viewport is reached, cap the dialog and scroll
|
||||
its content. Nudge it only as much as needed to keep essential controls visible. Do not
|
||||
recenter after every content change.
|
||||
|
||||
* **Touch & Click Target Rules:**
|
||||
* Minimum pointer hit-target: **44×44 logical pixels** (never build tiny 16px/24px buttons).
|
||||
* Control heights (buttons, dropdowns, rows) must obey `button_min_height` tokens from the theme.
|
||||
@@ -48,15 +74,17 @@ developer_instructions = """
|
||||
|
||||
* **Accessible Inputs:**
|
||||
* Prefer simple explicit buttons (e.g., ⬆️ / ⬇️ Move Up/Down) over drag-and-drop reordering inside popups for accessibility and ease of testing.
|
||||
* Always provide prominent, clickable `[X Cancel]` buttons on active workflows so users don't need to know the `Esc` key.
|
||||
* Provide a prominent, clickable, visibly labeled action such as **Cancel** on active workflows so users do not need to know the `Esc` key. Do not rely on a corner × as the sole dismissal control.
|
||||
|
||||
## 3. Pipeline Output Protocol
|
||||
|
||||
When invoked during Phase 0a (UI/UX Proposal & Alternatives):
|
||||
1. Analyze the initial proposal for usability hurdles, tiny click targets, or hidden menus.
|
||||
2. Pitch 1 to 3 alternate visual/interaction approaches (e.g., compare floating cursor badges vs. top notification bars).
|
||||
3. Mark your recommended choice with [Recommended] and ask up to 3 simple clarification questions.
|
||||
4. STOP and wait for user feedback.
|
||||
2. Present about three distinct UI concepts by default (usually exactly three). Apply the same default when the user directly asks you for UI ideas or mockups outside a formal spec-pipeline run.
|
||||
3. Give each concept a visual mockup, not only a prose description. Use one comparison board when all three remain legible; otherwise create a separate mockup for each. Use supplied screenshots and the established product style as visual references when available. Make the concepts differ in interaction or information hierarchy, not only colors or decoration. If visual mockup generation is unavailable, provide annotated wireframes and say so.
|
||||
4. Pair each mockup with a short title and concise tradeoff. Mark the recommended option with [Recommended] and explain why. Ask up to 3 focused clarification questions after presenting the concepts.
|
||||
5. Do not require alternatives or mockups for implementation-only requests, narrow bug fixes, or critique-only questions unless the user asks. Follow any user-specified number or format.
|
||||
6. STOP and wait for user feedback before writing the UI spec.
|
||||
|
||||
When invoked during Phase 0b (UI Spec Generation):
|
||||
Output a structured spec covering:
|
||||
|
||||
@@ -16,4 +16,5 @@ You are a technical writer for Godot 4 / GDScript projects. You document game ar
|
||||
|
||||
1. **Targeted Edits Only:** Touch only the specific markdown sections affected by recent changes. Never output full unchanged files.
|
||||
2. **Scannable & Technical:** Lead directly with code blocks, tables, and structured lists. Eliminate marketing fluff or generic introductions.
|
||||
"""
|
||||
3. **Worktree Choice:** Before any persistent documentation work, confirm that the orchestrator has asked the user whether this task should use a Git worktree and supplied the selected project path and branch. If the preference is missing, ask the orchestrator to get it first. Use the selected path whether it is a worktree or the current checkout; do not create a worktree yourself.
|
||||
"""
|
||||
|
||||
@@ -7,11 +7,15 @@ description: "Create or revise Stickman Studio props, stickmen, embedded clothin
|
||||
|
||||
Use the `artist` subagent for project graphical-asset and animation work. This skill manages delegation, review, approval, and handoff; it does not replace the Artist's visual judgment.
|
||||
|
||||
## Choose a worktree before creating files
|
||||
|
||||
Before creating an asset review bundle or other project files, ask whether the user wants this task to use a Git worktree unless they have already stated a preference. For small, self-contained asset changes, offer the current checkout as the default. Wait for the answer before creating a worktree. Follow `AGENTS.md`, and pass Artist the absolute path and branch the user selected, whether that is a worktree or the current checkout. Do not require a worktree when the user declines one.
|
||||
|
||||
## Delegate to Artist
|
||||
|
||||
Spawn `artist` with `agent_type: "artist"`. Reuse the same Artist for revisions while it is available. Tell it that other agents may share the workspace and that it must preserve unrelated changes.
|
||||
|
||||
Pass the user's request, intended use, supplied image roles (reference versus edit target), relevant approved specification, requested format, and any style or technical constraints. Do not require the user to repeat information already available in the conversation or repository.
|
||||
Pass the user's request, intended use, supplied image roles (reference versus edit target), relevant approved specification, requested format, and any style or technical constraints. For Stage-usable `.prop` art, include a requested scale when one is specified; otherwise have Artist infer a conventional size from the named subject and intended use against the standard stickman guide, and record that estimate in the review bundle. Do not require the user to repeat ordinary size information or clarify unless the requested scale is ambiguous or intentionally unusual.
|
||||
|
||||
Before delegating, read [references/project-formats.md](references/project-formats.md) for routing and source-of-truth locations. For production or revision work, also read [references/review-workflow.md](references/review-workflow.md).
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ Treat the user's clear statement that they are ready to work on the discussed, s
|
||||
|
||||
## Stage 3: Write and hand off the brief
|
||||
|
||||
Once the user is ready and the phase number is known, have Designer create the accepted product/design brief at `docs/plans/phase_<number>_<feature_slug>.md`, following `docs/plans/README.md`. The brief should cover the goal and audience, desired child outcome, behavior/flow and feedback, story or directing value where relevant, success criteria, included and excluded scope, known risks/dependencies, project references, and remaining questions for the spec-pipeline. Keep architecture/API decisions for the architect's later technical specification in `docs/specs/`.
|
||||
Once the user is ready and the phase number is known, ask whether the brief and later feature work should use a Git worktree unless the user has already stated a preference for this task. Follow the choice and the `Feature branches and worktrees` rules in `AGENTS.md`; do not create a worktree before the user answers. Use the selected checkout consistently for the brief, later specs, implementation, and verification. Pass its absolute path and current branch to Designer. Do not switch branches or write outside the selected checkout.
|
||||
|
||||
Have Designer create the accepted product/design brief at `docs/plans/phase_<number>_<feature_slug>.md`, following `docs/plans/README.md`. The brief should cover the goal and audience, desired child outcome, behavior/flow and feedback, story or directing value where relevant, success criteria, included and excluded scope, known risks/dependencies, project references, and remaining questions for the spec-pipeline. Keep architecture/API decisions for the architect's later technical specification in `docs/specs/`.
|
||||
|
||||
Do not overwrite an existing phase brief without the user's direction. Confirm the resulting file exists, update the matching backlog entry to `Planned` with a link to the brief, then tell the user where the plan is using a clickable local file link. Stop there; this skill creates the design handoff, not the technical spec or implementation.
|
||||
|
||||
@@ -5,17 +5,26 @@ description: "Stickman Studio feature workflow: UI/UX and architecture specs, im
|
||||
|
||||
## Execution Logic
|
||||
|
||||
### Feature branch and worktree setup
|
||||
|
||||
Before creating a worktree for a task, ask the user whether they want one and wait for the answer. For small, self-contained fixes or documentation changes, offer the current checkout as the default; for larger feature phases, explain the benefit of a dedicated worktree. Do not create a worktree before the user chooses. Keep the user's choice for the task from the first persistent artifact through implementation and verification.
|
||||
|
||||
Follow the `Feature branches and worktrees` rules in `AGENTS.md`: inspect `git status --short`, the current branch, and worktree list before the first persistent change. If the user chooses the current checkout, stay on its branch. If they choose a worktree, reuse a matching one or create `.worktrees/<feature-slug>` on `feature/<feature-slug>` from the integration branch, including the phase number when known. Do not switch branches, transfer uncommitted changes without direction, or merge automatically.
|
||||
|
||||
Pass every delegated agent the absolute selected project path and its branch, whether that path is a worktree or the current checkout. Tell each agent to use it for all repository reads, writes, Godot runs, and visual checks. Do not stop file-writing work solely because the user chose not to use a worktree.
|
||||
|
||||
1. **Phase 0a: UI/UX Proposal & Alternative Ideas (User-Facing Features Only)**
|
||||
- `@uiux` analyzes the user's initial idea for cognitive friction, accessibility, and kid-friendliness.
|
||||
- Before proposing, mocking, reviewing, or suggesting UI/UX changes, `@uiux` reads `docs/guides/editor_visual_style_guide.md` and checks the relevant implemented controls/specs. Treat the guide as the current visual baseline; distinguish implemented behavior from recommendations and explain intentional departures. This also applies to direct `@uiux` requests outside the pipeline.
|
||||
- For an in-stage selected-object inspector, `@uiux` first reviews `docs/specs/stage_panel_ui_system.md` and the current shared controls under `scripts/shared/stage_ui/`; proposals should build on that system unless the interaction needs justify a specific exception.
|
||||
- `@uiux` pitches **1–3 alternative interaction approaches** (e.g., comparing floating tooltips vs. top-center banners, custom cursor reticles, or streamlined dialogs).
|
||||
- `@uiux` highlights the most intuitive option with `[Recommended]` and asks up to 3 clarification questions.
|
||||
- Follow the concept-count and visual-mockup protocol in `.codex/agents/uiux.toml`; it also applies when the user asks `@uiux` for ideas outside a formal pipeline run.
|
||||
- `@uiux` **STOP:** Waits for user feedback/selection before writing the UI spec.
|
||||
- _Bypass Rule:_ If the feature is strictly internal engine/backend logic (e.g., physics, serialization, scanning), skip directly to Phase 1a.
|
||||
|
||||
2. **Phase 0b: UI Spec Generation**
|
||||
- User approves an option or provides feedback.
|
||||
- `@uiux` outputs the UI/UX specification (control layouts, widget behaviors, visual feedback states, and cursor logic).
|
||||
- Carry forward the style guide's applicable patterns and token ownership. If the approved direction departs from them, record the reason and the specific difference in the spec.
|
||||
- For Stage inspector work, name which shared components and theme tokens the design uses or proposes to extend. Treat dialogs and other editor panels as separate workflows unless their interaction model fits the inspector kit.
|
||||
|
||||
3. **Phase 1a: Architecture Proposal & Clarification**
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
.worktrees/
|
||||
.images/
|
||||
/android/
|
||||
addons/
|
||||
*.tmp
|
||||
.opencode/skills/playwright-cli
|
||||
*.import
|
||||
# Local scratch captures, logs, and temporary browser profiles
|
||||
/tmp/
|
||||
/work/
|
||||
content/review/artist/
|
||||
content/examples/
|
||||
/tests/godot_test_user_data/
|
||||
/tests/*_runtime.log
|
||||
/tests/phase19_*.log
|
||||
/tests/phase19_visual_*.png
|
||||
/tests/phase19_selected_artwork_depth_inspector.png
|
||||
/.codex-remote-attachments/
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
- Headless tests + command-line scene playback exist (see "Command-line testing & debug playback" below); the GUI editor runs via `run/main_scene`.
|
||||
- **Main scene:** `res://scenes/main.tscn` (set as `run/main_scene` in `project.godot`; hosts the Stickman Editor)
|
||||
|
||||
## Feature branches and worktrees
|
||||
|
||||
- Before creating a Git worktree for a task, ask the user whether they want this task to use one. Do not create a worktree until they answer. For small, self-contained fixes and documentation changes, offer the current checkout as the default; for larger feature phases, explain why a worktree may help and let the user choose.
|
||||
- Read-only discussion and proposals do not need a worktree. Before the first persistent change, inspect `git status --short`, `git branch --show-current`, and `git worktree list`.
|
||||
- If the user chooses the current checkout, keep working on its current branch. Do not switch branches, stash, reset, clean, move, or overwrite unrelated work.
|
||||
- If the user chooses a worktree, reuse a matching one when present. Otherwise, create `.worktrees/<feature-slug>` with branch `feature/<feature-slug>`, based on the integration branch (usually `main`). Include the phase number in the slug when known, such as `phase-20-stage-search`. Example: `git worktree add .worktrees/phase-20-stage-search -b feature/phase-20-stage-search main`. Confirm the path and branch with `git worktree list` and `git branch --show-current`.
|
||||
- If relevant uncommitted changes need to be carried into a chosen worktree, ask how to handle them before proceeding.
|
||||
- Pass every subagent the absolute path and branch the user chose, whether that is a worktree or the current checkout. All project reads, writes, Godot commands, and visual checks must target that path. Do not require a worktree when the user chose the current checkout.
|
||||
- Do not merge feature branches automatically. Keep each feature branch available for review and merge only when the user asks or the active workflow explicitly authorizes it.
|
||||
- `.worktrees/` is a local worktree container and must remain gitignored.
|
||||
|
||||
## Repository layout
|
||||
|
||||
- `scripts/` and `scenes/` stay as separate roots with matching feature groups. Editor controllers live in `scripts/editors/{stickman,prop,stage}`; stage, stickman runtime, props, terrain, and speech systems live in `scripts/{stage,characters/stickman,props,terrain,speech}`.
|
||||
@@ -72,6 +83,29 @@ the configured `run/main_scene`.
|
||||
Keep the prompt and visible Cancel together, leave the mode pill unobstructed, and reuse or
|
||||
generalize `StageUseTargetCaptureBar` instead of copying its styling.
|
||||
|
||||
## Child-facing dialogs and popups
|
||||
|
||||
- When a user prefixes a UI/UX question or request with `uiux:` or `uiux,`, route it to the
|
||||
custom UI/UX agent defined in `.codex/agents/uiux.toml`. Treat that prefix as an explicit
|
||||
delegation request. The UI/UX agent is read-only; carry its design guidance into implementation
|
||||
separately when implementation is requested.
|
||||
- Before making, mocking, reviewing, or suggesting Prop or Stickman UI/UX changes, have `@uiux`
|
||||
read `docs/guides/editor_visual_style_guide.md` and consult the relevant implemented patterns
|
||||
and feature specs. Treat the guide as the current visual baseline; call out intentional
|
||||
departures and distinguish current behavior from recommendations.
|
||||
- For new or revised child-facing dialogs, popups, and short setup flows, follow the
|
||||
[Dialog Design Principles](docs/specs/dialog_design_principles.md). Use rounded containers
|
||||
and controls, clear borders, blue primary actions with bold white labels, comfortable button
|
||||
spacing, and large readable type. Prefer a visible, labeled action such as Cancel, Done, or
|
||||
Back; do not make a small corner × the default or only way to close a dialog.
|
||||
- When a dialog resizes after a tab, filter, or other in-place choice, preserve its current
|
||||
anchor so the clicked control does not jump away from the pointer. Keep the dialog within the
|
||||
safe viewport by limiting its height and scrolling content; nudge it only as much as needed
|
||||
to keep essential controls visible. Avoid recentering after every content change.
|
||||
- Keep reusable values in `SandboxTheme` or `PropTheme`. The Choose Scenery dialog in
|
||||
`scripts/shared/ui/asset_selector.gd` and the `popups.asset_selector` tokens are the current
|
||||
implementation reference. Adapt its layout to each workflow.
|
||||
|
||||
## Required addon
|
||||
|
||||
- **Scalable Vector Shapes 2D** (v2.27.7) at `addons/curved_lines_2d/`
|
||||
|
||||
@@ -0,0 +1,715 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "wood",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T23:11:16",
|
||||
"modified_at": "2026-10-21T23:11:16"
|
||||
},
|
||||
"prop_name": "Bookshelf",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#AB795E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -320.119689941406,
|
||||
"y": -488.025634765625
|
||||
},
|
||||
{
|
||||
"x": 320.119689941406,
|
||||
"y": -488.025634765625
|
||||
},
|
||||
{
|
||||
"x": 320.119689941406,
|
||||
"y": 488.025604248047
|
||||
},
|
||||
{
|
||||
"x": -320.119689941406,
|
||||
"y": 488.025604248047
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F5D9AA",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -273.043273925781,
|
||||
"y": -431.533935546875
|
||||
},
|
||||
{
|
||||
"x": 273.043273925781,
|
||||
"y": -431.533935546875
|
||||
},
|
||||
{
|
||||
"x": 273.043273925781,
|
||||
"y": 412.703308105469
|
||||
},
|
||||
{
|
||||
"x": -273.043273925781,
|
||||
"y": 412.703308105469
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#AB795E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -273.043273925781,
|
||||
"y": -171.044372558594
|
||||
},
|
||||
{
|
||||
"x": 273.043273925781,
|
||||
"y": -171.044372558594
|
||||
},
|
||||
{
|
||||
"x": 273.043273925781,
|
||||
"y": -133.383239746094
|
||||
},
|
||||
{
|
||||
"x": -273.043273925781,
|
||||
"y": -133.383239746094
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#AB795E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -273.043273925781,
|
||||
"y": 108.275756835938
|
||||
},
|
||||
{
|
||||
"x": 273.043273925781,
|
||||
"y": 108.275756835938
|
||||
},
|
||||
{
|
||||
"x": 273.043273925781,
|
||||
"y": 145.936904907227
|
||||
},
|
||||
{
|
||||
"x": -273.043273925781,
|
||||
"y": 145.936904907227
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C87375",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -238.520568847656,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": -182.028854370117,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": -182.028854370117,
|
||||
"y": -183.598083496094
|
||||
},
|
||||
{
|
||||
"x": -238.520568847656,
|
||||
"y": -183.598083496094
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#77A7B2",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -169.475143432617,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": -112.983421325684,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": -112.983421325684,
|
||||
"y": -183.598083496094
|
||||
},
|
||||
{
|
||||
"x": -169.475143432617,
|
||||
"y": -183.598083496094
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E3B765",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -100.429710388184,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": -43.9379997253418,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": -43.9379997253418,
|
||||
"y": -183.598083496094
|
||||
},
|
||||
{
|
||||
"x": -100.429710388184,
|
||||
"y": -183.598083496094
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#82B38D",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -28.2458553314209,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": 28.2458553314209,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": 28.2458553314209,
|
||||
"y": -183.598083496094
|
||||
},
|
||||
{
|
||||
"x": -28.2458553314209,
|
||||
"y": -183.598083496094
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C87375",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": 53.3532829284668,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": 109.844993591309,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": 109.844993591309,
|
||||
"y": -183.598083496094
|
||||
},
|
||||
{
|
||||
"x": 53.3532829284668,
|
||||
"y": -183.598083496094
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#77A7B2",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": 134.952423095703,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": 191.444137573242,
|
||||
"y": -409.56494140625
|
||||
},
|
||||
{
|
||||
"x": 191.444137573242,
|
||||
"y": -183.598083496094
|
||||
},
|
||||
{
|
||||
"x": 134.952423095703,
|
||||
"y": -183.598083496094
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#78A7B2",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -232.243698120117,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": -178.890426635742,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": -178.890426635742,
|
||||
"y": 86.3067626953125
|
||||
},
|
||||
{
|
||||
"x": -232.243698120117,
|
||||
"y": 86.3067626953125
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E5B869",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -166.336700439453,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": -112.983421325684,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": -112.983421325684,
|
||||
"y": 86.3067626953125
|
||||
},
|
||||
{
|
||||
"x": -166.336700439453,
|
||||
"y": 86.3067626953125
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C97375",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -100.429710388184,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": -47.0764274597168,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": -47.0764274597168,
|
||||
"y": 86.3067626953125
|
||||
},
|
||||
{
|
||||
"x": -100.429710388184,
|
||||
"y": 86.3067626953125
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#9BB586",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": 12.5537137985229,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": 65.9069976806641,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": 65.9069976806641,
|
||||
"y": 86.3067626953125
|
||||
},
|
||||
{
|
||||
"x": 12.5537137985229,
|
||||
"y": 86.3067626953125
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#83AABB",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": 84.7375717163086,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": 138.090850830078,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": 138.090850830078,
|
||||
"y": 86.3067626953125
|
||||
},
|
||||
{
|
||||
"x": 84.7375717163086,
|
||||
"y": 86.3067626953125
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DEAA72",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": 150.644561767578,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": 203.997848510742,
|
||||
"y": -114.552658081055
|
||||
},
|
||||
{
|
||||
"x": 203.997848510742,
|
||||
"y": 86.3067626953125
|
||||
},
|
||||
{
|
||||
"x": 150.644561767578,
|
||||
"y": 86.3067626953125
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#8CB98E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -213.413131713867,
|
||||
"y": 199.290191650391
|
||||
},
|
||||
{
|
||||
"x": -37.6611404418945,
|
||||
"y": 199.290191650391
|
||||
},
|
||||
{
|
||||
"x": -37.6611404418945,
|
||||
"y": 371.903747558594
|
||||
},
|
||||
{
|
||||
"x": -213.413131713867,
|
||||
"y": 371.903747558594
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#79AF81",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": -28.2458553314209,
|
||||
"y": 211.843902587891
|
||||
},
|
||||
{
|
||||
"x": -35.6525459289551,
|
||||
"y": 240.654678344727
|
||||
},
|
||||
{
|
||||
"x": -56.7427864074707,
|
||||
"y": 265.10302734375
|
||||
},
|
||||
{
|
||||
"x": -88.3153762817383,
|
||||
"y": 281.4228515625
|
||||
},
|
||||
{
|
||||
"x": -125.537139892578,
|
||||
"y": 287.166198730469
|
||||
},
|
||||
{
|
||||
"x": -162.758895874023,
|
||||
"y": 281.4228515625
|
||||
},
|
||||
{
|
||||
"x": -194.331481933594,
|
||||
"y": 265.10302734375
|
||||
},
|
||||
{
|
||||
"x": -215.421722412109,
|
||||
"y": 240.654678344727
|
||||
},
|
||||
{
|
||||
"x": -222.828414916992,
|
||||
"y": 211.843902587891
|
||||
},
|
||||
{
|
||||
"x": -215.421722412109,
|
||||
"y": 183.033111572266
|
||||
},
|
||||
{
|
||||
"x": -194.331481933594,
|
||||
"y": 158.584777832031
|
||||
},
|
||||
{
|
||||
"x": -162.758895874023,
|
||||
"y": 142.264938354492
|
||||
},
|
||||
{
|
||||
"x": -125.537139892578,
|
||||
"y": 136.521606445313
|
||||
},
|
||||
{
|
||||
"x": -88.3153762817383,
|
||||
"y": 142.264938354492
|
||||
},
|
||||
{
|
||||
"x": -56.7427864074707,
|
||||
"y": 158.584777832031
|
||||
},
|
||||
{
|
||||
"x": -35.6525459289551,
|
||||
"y": 183.033111572266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C17476",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 12.553713506884,
|
||||
"points": [
|
||||
{
|
||||
"x": 31.3842849731445,
|
||||
"y": 252.643463134766
|
||||
},
|
||||
{
|
||||
"x": 207.136276245117,
|
||||
"y": 252.643463134766
|
||||
},
|
||||
{
|
||||
"x": 207.136276245117,
|
||||
"y": 393.872741699219
|
||||
},
|
||||
{
|
||||
"x": 31.3842849731445,
|
||||
"y": 393.872741699219
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#F4CE9E",
|
||||
"outline_width": 9.41528513016301,
|
||||
"points": [
|
||||
{
|
||||
"x": 31.3842849731445,
|
||||
"y": 312.273620605469
|
||||
},
|
||||
{
|
||||
"x": 207.136276245117,
|
||||
"y": 312.273620605469
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"objects",
|
||||
"walls"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "none",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T21:43:32",
|
||||
"modified_at": "2026-10-21T21:43:32"
|
||||
},
|
||||
"prop_name": "City Skyline",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#879DB0",
|
||||
"outline_color": "#687F97",
|
||||
"outline_width": 8.76671850699844,
|
||||
"points": [
|
||||
{
|
||||
"x": -935.116638183594,
|
||||
"y": 284.918365478516
|
||||
},
|
||||
{
|
||||
"x": -935.116638183594,
|
||||
"y": 7.30561065673828
|
||||
},
|
||||
{
|
||||
"x": -812.382568359375,
|
||||
"y": 7.30561065673828
|
||||
},
|
||||
{
|
||||
"x": -812.382568359375,
|
||||
"y": -138.806365966797
|
||||
},
|
||||
{
|
||||
"x": -642.892700195313,
|
||||
"y": -138.806365966797
|
||||
},
|
||||
{
|
||||
"x": -642.892700195313,
|
||||
"y": -7.30558013916016
|
||||
},
|
||||
{
|
||||
"x": -537.692077636719,
|
||||
"y": -7.30558013916016
|
||||
},
|
||||
{
|
||||
"x": -537.692077636719,
|
||||
"y": -246.929229736328
|
||||
},
|
||||
{
|
||||
"x": -397.424591064453,
|
||||
"y": -246.929229736328
|
||||
},
|
||||
{
|
||||
"x": -397.424591064453,
|
||||
"y": -80.361572265625
|
||||
},
|
||||
{
|
||||
"x": -251.312606811523,
|
||||
"y": -80.361572265625
|
||||
},
|
||||
{
|
||||
"x": -251.312606811523,
|
||||
"y": -176.795471191406
|
||||
},
|
||||
{
|
||||
"x": -111.045104980469,
|
||||
"y": -176.795471191406
|
||||
},
|
||||
{
|
||||
"x": -111.045104980469,
|
||||
"y": -21.9167785644531
|
||||
},
|
||||
{
|
||||
"x": 43.8335914611816,
|
||||
"y": -21.9167785644531
|
||||
},
|
||||
{
|
||||
"x": 43.8335914611816,
|
||||
"y": -284.918334960938
|
||||
},
|
||||
{
|
||||
"x": 181.178848266602,
|
||||
"y": -284.918334960938
|
||||
},
|
||||
{
|
||||
"x": 181.178848266602,
|
||||
"y": -71.5948486328125
|
||||
},
|
||||
{
|
||||
"x": 321.446350097656,
|
||||
"y": -71.5948486328125
|
||||
},
|
||||
{
|
||||
"x": 321.446350097656,
|
||||
"y": -188.484436035156
|
||||
},
|
||||
{
|
||||
"x": 467.558319091797,
|
||||
"y": -188.484436035156
|
||||
},
|
||||
{
|
||||
"x": 467.558319091797,
|
||||
"y": -18.9945449829102
|
||||
},
|
||||
{
|
||||
"x": 604.903564453125,
|
||||
"y": -18.9945449829102
|
||||
},
|
||||
{
|
||||
"x": 604.903564453125,
|
||||
"y": -124.195159912109
|
||||
},
|
||||
{
|
||||
"x": 756.860046386719,
|
||||
"y": -124.195159912109
|
||||
},
|
||||
{
|
||||
"x": 756.860046386719,
|
||||
"y": 21.9168128967285
|
||||
},
|
||||
{
|
||||
"x": 935.116638183594,
|
||||
"y": 21.9168128967285
|
||||
},
|
||||
{
|
||||
"x": 935.116638183594,
|
||||
"y": 284.918365478516
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DDE7E8",
|
||||
"outline_color": "#DDE7E8",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -195.827392578125,
|
||||
"y": -154.283813476563
|
||||
},
|
||||
{
|
||||
"x": -160.760498046875,
|
||||
"y": -154.283813476563
|
||||
},
|
||||
{
|
||||
"x": -160.760498046875,
|
||||
"y": -98.7612609863281
|
||||
},
|
||||
{
|
||||
"x": -195.827392578125,
|
||||
"y": -98.7612609863281
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DDE7E8",
|
||||
"outline_color": "#DDE7E8",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -753.937805175781,
|
||||
"y": -71.5948486328125
|
||||
},
|
||||
{
|
||||
"x": -718.870910644531,
|
||||
"y": -71.5948486328125
|
||||
},
|
||||
{
|
||||
"x": -718.870910644531,
|
||||
"y": -18.9945449829102
|
||||
},
|
||||
{
|
||||
"x": -753.937805175781,
|
||||
"y": -18.9945449829102
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DDE7E8",
|
||||
"outline_color": "#DDE7E8",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -470.480560302734,
|
||||
"y": -191.406677246094
|
||||
},
|
||||
{
|
||||
"x": -435.413696289063,
|
||||
"y": -191.406677246094
|
||||
},
|
||||
{
|
||||
"x": -435.413696289063,
|
||||
"y": -138.806365966797
|
||||
},
|
||||
{
|
||||
"x": -470.480560302734,
|
||||
"y": -138.806365966797
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DDE7E8",
|
||||
"outline_color": "#DDE7E8",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 87.6671829223633,
|
||||
"y": -232.318023681641
|
||||
},
|
||||
{
|
||||
"x": 122.734062194824,
|
||||
"y": -232.318023681641
|
||||
},
|
||||
{
|
||||
"x": 122.734062194824,
|
||||
"y": -173.873229980469
|
||||
},
|
||||
{
|
||||
"x": 87.6671829223633,
|
||||
"y": -173.873229980469
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DDE7E8",
|
||||
"outline_color": "#DDE7E8",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 371.124420166016,
|
||||
"y": -135.884124755859
|
||||
},
|
||||
{
|
||||
"x": 406.191284179688,
|
||||
"y": -135.884124755859
|
||||
},
|
||||
{
|
||||
"x": 406.191284179688,
|
||||
"y": -83.2838134765625
|
||||
},
|
||||
{
|
||||
"x": 371.124420166016,
|
||||
"y": -83.2838134765625
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DDE7E8",
|
||||
"outline_color": "#DDE7E8",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 660.426147460938,
|
||||
"y": -77.4393310546875
|
||||
},
|
||||
{
|
||||
"x": 695.492980957031,
|
||||
"y": -77.4393310546875
|
||||
},
|
||||
{
|
||||
"x": 695.492980957031,
|
||||
"y": -27.7612609863281
|
||||
},
|
||||
{
|
||||
"x": 660.426147460938,
|
||||
"y": -27.7612609863281
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"buildings"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "none",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T23:11:48",
|
||||
"modified_at": "2026-10-21T23:11:48"
|
||||
},
|
||||
"prop_name": "Framed Picture",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B68165",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -146.410003662109,
|
||||
"y": -109.141998291016
|
||||
},
|
||||
{
|
||||
"x": 146.410003662109,
|
||||
"y": -109.141998291016
|
||||
},
|
||||
{
|
||||
"x": 146.410003662109,
|
||||
"y": 109.141998291016
|
||||
},
|
||||
{
|
||||
"x": -146.410003662109,
|
||||
"y": 109.141998291016
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F4DEAF",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -121.120994567871,
|
||||
"y": -85.1839981079102
|
||||
},
|
||||
{
|
||||
"x": 121.120994567871,
|
||||
"y": -85.1839981079102
|
||||
},
|
||||
{
|
||||
"x": 121.120994567871,
|
||||
"y": 85.1839981079102
|
||||
},
|
||||
{
|
||||
"x": -121.120994567871,
|
||||
"y": 85.1839981079102
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#A4CFCD",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -106.479995727539,
|
||||
"y": -71.8740005493164
|
||||
},
|
||||
{
|
||||
"x": 106.479995727539,
|
||||
"y": -71.8740005493164
|
||||
},
|
||||
{
|
||||
"x": 106.479995727539,
|
||||
"y": 71.8740005493164
|
||||
},
|
||||
{
|
||||
"x": -106.479995727539,
|
||||
"y": 71.8740005493164
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F3D68C",
|
||||
"outline_color": "#F3D68C",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 77.197998046875,
|
||||
"y": -39.9300003051758
|
||||
},
|
||||
{
|
||||
"x": 75.6806564331055,
|
||||
"y": -32.2900581359863
|
||||
},
|
||||
{
|
||||
"x": 71.3549118041992,
|
||||
"y": -25.8080883026123
|
||||
},
|
||||
{
|
||||
"x": 64.8729400634766,
|
||||
"y": -21.4823379516602
|
||||
},
|
||||
{
|
||||
"x": 57.2329978942871,
|
||||
"y": -19.9650001525879
|
||||
},
|
||||
{
|
||||
"x": 49.5930557250977,
|
||||
"y": -21.4823379516602
|
||||
},
|
||||
{
|
||||
"x": 43.1110877990723,
|
||||
"y": -25.8080883026123
|
||||
},
|
||||
{
|
||||
"x": 38.7853393554688,
|
||||
"y": -32.2900581359863
|
||||
},
|
||||
{
|
||||
"x": 37.2679977416992,
|
||||
"y": -39.9300003051758
|
||||
},
|
||||
{
|
||||
"x": 38.7853393554688,
|
||||
"y": -47.5699424743652
|
||||
},
|
||||
{
|
||||
"x": 43.1110877990723,
|
||||
"y": -54.0519104003906
|
||||
},
|
||||
{
|
||||
"x": 49.5930557250977,
|
||||
"y": -58.3776588439941
|
||||
},
|
||||
{
|
||||
"x": 57.2329978942871,
|
||||
"y": -59.8950004577637
|
||||
},
|
||||
{
|
||||
"x": 64.8729400634766,
|
||||
"y": -58.3776588439941
|
||||
},
|
||||
{
|
||||
"x": 71.3549118041992,
|
||||
"y": -54.0519104003906
|
||||
},
|
||||
{
|
||||
"x": 75.6806564331055,
|
||||
"y": -47.5699424743652
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#88B798",
|
||||
"outline_color": "#88B798",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -106.479995727539,
|
||||
"y": 71.8740005493164
|
||||
},
|
||||
{
|
||||
"x": -26.6199989318848,
|
||||
"y": -14.6409997940063
|
||||
},
|
||||
{
|
||||
"x": 13.3099994659424,
|
||||
"y": 30.6129989624023
|
||||
},
|
||||
{
|
||||
"x": 53.2399978637695,
|
||||
"y": -23.9580001831055
|
||||
},
|
||||
{
|
||||
"x": 106.479995727539,
|
||||
"y": 51.9090003967285
|
||||
},
|
||||
{
|
||||
"x": 106.479995727539,
|
||||
"y": 71.8740005493164
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#F0E1BC",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -85.1839981079102,
|
||||
"y": 55.9020004272461
|
||||
},
|
||||
{
|
||||
"x": -10.6479997634888,
|
||||
"y": 55.9020004272461
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"objects",
|
||||
"walls"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"prop_name": "Potted Plant",
|
||||
"material_preset": "none",
|
||||
"tags": ["nature", "objects"],
|
||||
"shapes": [
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -45,
|
||||
"y": 16
|
||||
},
|
||||
{
|
||||
"x": -55,
|
||||
"y": -6
|
||||
},
|
||||
{
|
||||
"x": -39,
|
||||
"y": -74
|
||||
},
|
||||
{
|
||||
"x": -4,
|
||||
"y": -28
|
||||
},
|
||||
{
|
||||
"x": 8,
|
||||
"y": 11
|
||||
}
|
||||
],
|
||||
"fill_color": "#70B481",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 4,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": 3,
|
||||
"y": 8
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": -31
|
||||
},
|
||||
{
|
||||
"x": 38,
|
||||
"y": -91
|
||||
},
|
||||
{
|
||||
"x": 48,
|
||||
"y": -48
|
||||
},
|
||||
{
|
||||
"x": 36,
|
||||
"y": 4
|
||||
}
|
||||
],
|
||||
"fill_color": "#83C290",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 4,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -18,
|
||||
"y": 14
|
||||
},
|
||||
{
|
||||
"x": -4,
|
||||
"y": -112
|
||||
},
|
||||
{
|
||||
"x": 18,
|
||||
"y": -56
|
||||
},
|
||||
{
|
||||
"x": 16,
|
||||
"y": 15
|
||||
}
|
||||
],
|
||||
"fill_color": "#9CCF90",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 4,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "line",
|
||||
"points": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 30
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": -69
|
||||
}
|
||||
],
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#5C946F",
|
||||
"outline_width": 5,
|
||||
"closed": false,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -55,
|
||||
"y": 17
|
||||
},
|
||||
{
|
||||
"x": 55,
|
||||
"y": 17
|
||||
},
|
||||
{
|
||||
"x": 43,
|
||||
"y": 102
|
||||
},
|
||||
{
|
||||
"x": -43,
|
||||
"y": 102
|
||||
}
|
||||
],
|
||||
"fill_color": "#C47761",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 4,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -60,
|
||||
"y": 14
|
||||
},
|
||||
{
|
||||
"x": 60,
|
||||
"y": 14
|
||||
},
|
||||
{
|
||||
"x": 60,
|
||||
"y": 31
|
||||
},
|
||||
{
|
||||
"x": -60,
|
||||
"y": 31
|
||||
}
|
||||
],
|
||||
"fill_color": "#DC9670",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 4,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "line",
|
||||
"points": [
|
||||
{
|
||||
"x": -21,
|
||||
"y": 59
|
||||
},
|
||||
{
|
||||
"x": 21,
|
||||
"y": 59
|
||||
}
|
||||
],
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#EFC09A",
|
||||
"outline_width": 4,
|
||||
"closed": false,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
}
|
||||
],
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"role": "pivot",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"rotation_deg": 0,
|
||||
"z_index_offset": 0,
|
||||
"allowed_hands": "both"
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"created_at": "2026-10-15T00:00:00",
|
||||
"modified_at": "2026-10-15T00:00:00"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "none",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T23:12:17",
|
||||
"modified_at": "2026-10-21T23:12:17"
|
||||
},
|
||||
"prop_name": "Patterned Rug",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C77377",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -210.297988891602,
|
||||
"y": -89.8424987792969
|
||||
},
|
||||
{
|
||||
"x": 210.297988891602,
|
||||
"y": -89.8424987792969
|
||||
},
|
||||
{
|
||||
"x": 235.586990356445,
|
||||
"y": 71.20849609375
|
||||
},
|
||||
{
|
||||
"x": -235.586990356445,
|
||||
"y": 71.20849609375
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F0D29A",
|
||||
"outline_color": "#F0D29A",
|
||||
"outline_width": 2.662,
|
||||
"points": [
|
||||
{
|
||||
"x": -175.692001342773,
|
||||
"y": -63.2224998474121
|
||||
},
|
||||
{
|
||||
"x": 175.692001342773,
|
||||
"y": -63.2224998474121
|
||||
},
|
||||
{
|
||||
"x": 195.656997680664,
|
||||
"y": 44.5884971618652
|
||||
},
|
||||
{
|
||||
"x": -195.656997680664,
|
||||
"y": 44.5884971618652
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#7E9B9C",
|
||||
"outline_color": "#7E9B9C",
|
||||
"outline_width": 2.662,
|
||||
"points": [
|
||||
{
|
||||
"x": -129.106994628906,
|
||||
"y": -44.5885009765625
|
||||
},
|
||||
{
|
||||
"x": 129.106994628906,
|
||||
"y": -44.5885009765625
|
||||
},
|
||||
{
|
||||
"x": 141.085998535156,
|
||||
"y": 25.9544982910156
|
||||
},
|
||||
{
|
||||
"x": -141.085998535156,
|
||||
"y": 25.9544982910156
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F6D69A",
|
||||
"outline_color": "#F6D69A",
|
||||
"outline_width": 1.331,
|
||||
"points": [
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -37.9335021972656
|
||||
},
|
||||
{
|
||||
"x": 46.5849990844727,
|
||||
"y": -8.6515007019043
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 19.2994995117188
|
||||
},
|
||||
{
|
||||
"x": -46.5849990844727,
|
||||
"y": -8.6515007019043
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#DBA389",
|
||||
"outline_width": 3.993,
|
||||
"points": [
|
||||
{
|
||||
"x": -183.677993774414,
|
||||
"y": 72.5394973754883
|
||||
},
|
||||
{
|
||||
"x": -183.677993774414,
|
||||
"y": 89.8424987792969
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#DBA389",
|
||||
"outline_width": 3.993,
|
||||
"points": [
|
||||
{
|
||||
"x": -122.451995849609,
|
||||
"y": 72.5394973754883
|
||||
},
|
||||
{
|
||||
"x": -122.451995849609,
|
||||
"y": 89.8424987792969
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#DBA389",
|
||||
"outline_width": 3.993,
|
||||
"points": [
|
||||
{
|
||||
"x": -61.2259979248047,
|
||||
"y": 72.5394973754883
|
||||
},
|
||||
{
|
||||
"x": -61.2259979248047,
|
||||
"y": 89.8424987792969
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#DBA389",
|
||||
"outline_width": 3.993,
|
||||
"points": [
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 72.5394973754883
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 89.8424987792969
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#DBA389",
|
||||
"outline_width": 3.993,
|
||||
"points": [
|
||||
{
|
||||
"x": 61.2259979248047,
|
||||
"y": 72.5394973754883
|
||||
},
|
||||
{
|
||||
"x": 61.2259979248047,
|
||||
"y": 89.8424987792969
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#DBA389",
|
||||
"outline_width": 3.993,
|
||||
"points": [
|
||||
{
|
||||
"x": 122.451995849609,
|
||||
"y": 72.5394973754883
|
||||
},
|
||||
{
|
||||
"x": 122.451995849609,
|
||||
"y": 89.8424987792969
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#DBA389",
|
||||
"outline_width": 3.993,
|
||||
"points": [
|
||||
{
|
||||
"x": 183.677993774414,
|
||||
"y": 72.5394973754883
|
||||
},
|
||||
{
|
||||
"x": 183.677993774414,
|
||||
"y": 89.8424987792969
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"objects"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,548 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "none",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T21:40:26",
|
||||
"modified_at": "2026-10-21T21:40:26"
|
||||
},
|
||||
"prop_name": "Sunny Storefront",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E8B571",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -783.44287109375,
|
||||
"y": -596.427490234375
|
||||
},
|
||||
{
|
||||
"x": 783.44287109375,
|
||||
"y": -596.427490234375
|
||||
},
|
||||
{
|
||||
"x": 783.44287109375,
|
||||
"y": 798.606262207031
|
||||
},
|
||||
{
|
||||
"x": -783.44287109375,
|
||||
"y": 798.606262207031
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#6C4E69",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -859.259887695313,
|
||||
"y": -677.299011230469
|
||||
},
|
||||
{
|
||||
"x": 859.259887695313,
|
||||
"y": -677.299011230469
|
||||
},
|
||||
{
|
||||
"x": 859.259887695313,
|
||||
"y": -535.773864746094
|
||||
},
|
||||
{
|
||||
"x": -859.259887695313,
|
||||
"y": -535.773864746094
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FAE6AF",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -581.264038085938,
|
||||
"y": -813.769653320313
|
||||
},
|
||||
{
|
||||
"x": 581.264038085938,
|
||||
"y": -813.769653320313
|
||||
},
|
||||
{
|
||||
"x": 581.264038085938,
|
||||
"y": -682.353454589844
|
||||
},
|
||||
{
|
||||
"x": -581.264038085938,
|
||||
"y": -682.353454589844
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#B97768",
|
||||
"outline_width": 25.2723514249647,
|
||||
"points": [
|
||||
{
|
||||
"x": -252.723510742188,
|
||||
"y": -743.007141113281
|
||||
},
|
||||
{
|
||||
"x": 252.723510742188,
|
||||
"y": -743.007141113281
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F3D77A",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -717.734741210938,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": 717.734741210938,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": 717.734741210938,
|
||||
"y": -313.377197265625
|
||||
},
|
||||
{
|
||||
"x": -717.734741210938,
|
||||
"y": -313.377197265625
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E37C70",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -717.734741210938,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": -480.174652099609,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": -520.610412597656,
|
||||
"y": -318.431640625
|
||||
},
|
||||
{
|
||||
"x": -677.299011230469,
|
||||
"y": -318.431640625
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FFF2D4",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -480.174652099609,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": -242.614562988281,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": -283.050323486328,
|
||||
"y": -318.431640625
|
||||
},
|
||||
{
|
||||
"x": -439.738891601563,
|
||||
"y": -318.431640625
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E37C70",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -242.614562988281,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": -5.05447006225586,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": -45.4902305603027,
|
||||
"y": -318.431640625
|
||||
},
|
||||
{
|
||||
"x": -202.178802490234,
|
||||
"y": -318.431640625
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FFF2D4",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -5.05447006225586,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": 232.505615234375,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": 192.069854736328,
|
||||
"y": -318.431640625
|
||||
},
|
||||
{
|
||||
"x": 35.381290435791,
|
||||
"y": -318.431640625
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E37C70",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": 232.505615234375,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": 470.065704345703,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": 429.629943847656,
|
||||
"y": -318.431640625
|
||||
},
|
||||
{
|
||||
"x": 272.941375732422,
|
||||
"y": -318.431640625
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FFF2D4",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": 470.065704345703,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": 707.625793457031,
|
||||
"y": -520.610412597656
|
||||
},
|
||||
{
|
||||
"x": 667.190063476563,
|
||||
"y": -318.431640625
|
||||
},
|
||||
{
|
||||
"x": 510.50146484375,
|
||||
"y": -318.431640625
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#81B5BD",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -636.863220214844,
|
||||
"y": -247.669067382813
|
||||
},
|
||||
{
|
||||
"x": -101.089401245117,
|
||||
"y": -247.669067382813
|
||||
},
|
||||
{
|
||||
"x": -101.089401245117,
|
||||
"y": 722.789184570313
|
||||
},
|
||||
{
|
||||
"x": -636.863220214844,
|
||||
"y": 722.789184570313
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#D4F1E8",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -566.100646972656,
|
||||
"y": -171.851989746094
|
||||
},
|
||||
{
|
||||
"x": -171.851989746094,
|
||||
"y": -171.851989746094
|
||||
},
|
||||
{
|
||||
"x": -171.851989746094,
|
||||
"y": 591.372985839844
|
||||
},
|
||||
{
|
||||
"x": -566.100646972656,
|
||||
"y": 591.372985839844
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#835B73",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": 111.198341369629,
|
||||
"y": -247.669067382813
|
||||
},
|
||||
{
|
||||
"x": 611.590881347656,
|
||||
"y": -247.669067382813
|
||||
},
|
||||
{
|
||||
"x": 611.590881347656,
|
||||
"y": 722.789184570313
|
||||
},
|
||||
{
|
||||
"x": 111.198341369629,
|
||||
"y": 722.789184570313
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C4DCDD",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": 171.851989746094,
|
||||
"y": -181.9609375
|
||||
},
|
||||
{
|
||||
"x": 545.882751464844,
|
||||
"y": -181.9609375
|
||||
},
|
||||
{
|
||||
"x": 545.882751464844,
|
||||
"y": 596.427429199219
|
||||
},
|
||||
{
|
||||
"x": 171.851989746094,
|
||||
"y": 596.427429199219
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#835B73",
|
||||
"outline_width": 25.2723514249647,
|
||||
"points": [
|
||||
{
|
||||
"x": 358.867370605469,
|
||||
"y": -181.9609375
|
||||
},
|
||||
{
|
||||
"x": 358.867370605469,
|
||||
"y": 596.427429199219
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C99672",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 20.2178811399718,
|
||||
"points": [
|
||||
{
|
||||
"x": -808.715209960938,
|
||||
"y": 722.789184570313
|
||||
},
|
||||
{
|
||||
"x": 808.715209960938,
|
||||
"y": 722.789184570313
|
||||
},
|
||||
{
|
||||
"x": 808.715209960938,
|
||||
"y": 813.769653320313
|
||||
},
|
||||
{
|
||||
"x": -808.715209960938,
|
||||
"y": 813.769653320313
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"buildings"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "none",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T21:40:03",
|
||||
"modified_at": "2026-10-21T21:40:03"
|
||||
},
|
||||
"prop_name": "Town House",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B3C99C",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -807.520385742188,
|
||||
"y": -732.243041992188
|
||||
},
|
||||
{
|
||||
"x": 807.520385742188,
|
||||
"y": -732.243041992188
|
||||
},
|
||||
{
|
||||
"x": 807.520385742188,
|
||||
"y": 1307.08801269531
|
||||
},
|
||||
{
|
||||
"x": -807.520385742188,
|
||||
"y": 1307.08801269531
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#CF735F",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -944.38818359375,
|
||||
"y": -663.80908203125
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -1361.83520507813
|
||||
},
|
||||
{
|
||||
"x": 944.38818359375,
|
||||
"y": -663.80908203125
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F3E3B2",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -164.241424560547,
|
||||
"y": -1197.59375
|
||||
},
|
||||
{
|
||||
"x": 164.241424560547,
|
||||
"y": -1197.59375
|
||||
},
|
||||
{
|
||||
"x": 164.241424560547,
|
||||
"y": -725.399658203125
|
||||
},
|
||||
{
|
||||
"x": -164.241424560547,
|
||||
"y": -725.399658203125
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#85ADBC",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -136.867858886719,
|
||||
"y": -1170.22021484375
|
||||
},
|
||||
{
|
||||
"x": 136.867858886719,
|
||||
"y": -1170.22021484375
|
||||
},
|
||||
{
|
||||
"x": 136.867858886719,
|
||||
"y": -752.773193359375
|
||||
},
|
||||
{
|
||||
"x": -136.867858886719,
|
||||
"y": -752.773193359375
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E9D6A9",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -602.218566894531,
|
||||
"y": -362.699829101563
|
||||
},
|
||||
{
|
||||
"x": -191.615005493164,
|
||||
"y": -362.699829101563
|
||||
},
|
||||
{
|
||||
"x": -191.615005493164,
|
||||
"y": 225.831939697266
|
||||
},
|
||||
{
|
||||
"x": -602.218566894531,
|
||||
"y": 225.831939697266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E9D6A9",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": 191.615005493164,
|
||||
"y": -362.699829101563
|
||||
},
|
||||
{
|
||||
"x": 602.218566894531,
|
||||
"y": -362.699829101563
|
||||
},
|
||||
{
|
||||
"x": 602.218566894531,
|
||||
"y": 225.831939697266
|
||||
},
|
||||
{
|
||||
"x": 191.615005493164,
|
||||
"y": 225.831939697266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B9DFE3",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -533.78466796875,
|
||||
"y": -287.422546386719
|
||||
},
|
||||
{
|
||||
"x": -260.048919677734,
|
||||
"y": -287.422546386719
|
||||
},
|
||||
{
|
||||
"x": -260.048919677734,
|
||||
"y": 150.554595947266
|
||||
},
|
||||
{
|
||||
"x": -533.78466796875,
|
||||
"y": 150.554595947266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B9DFE3",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": 260.048919677734,
|
||||
"y": -287.422546386719
|
||||
},
|
||||
{
|
||||
"x": 533.78466796875,
|
||||
"y": -287.422546386719
|
||||
},
|
||||
{
|
||||
"x": 533.78466796875,
|
||||
"y": 150.554595947266
|
||||
},
|
||||
{
|
||||
"x": 260.048919677734,
|
||||
"y": 150.554595947266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#E9D6A9",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -396.916778564453,
|
||||
"y": -287.422546386719
|
||||
},
|
||||
{
|
||||
"x": -396.916778564453,
|
||||
"y": 150.554595947266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#E9D6A9",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": 396.916778564453,
|
||||
"y": -287.422546386719
|
||||
},
|
||||
{
|
||||
"x": 396.916778564453,
|
||||
"y": 150.554595947266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#8A6273",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -246.36213684082,
|
||||
"y": 417.446929931641
|
||||
},
|
||||
{
|
||||
"x": 246.36213684082,
|
||||
"y": 417.446929931641
|
||||
},
|
||||
{
|
||||
"x": 246.36213684082,
|
||||
"y": 1307.08801269531
|
||||
},
|
||||
{
|
||||
"x": -246.36213684082,
|
||||
"y": 1307.08801269531
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F5D98B",
|
||||
"outline_color": "#F5D98B",
|
||||
"outline_width": 6.84339278606966,
|
||||
"points": [
|
||||
{
|
||||
"x": 184.771606445313,
|
||||
"y": 903.327819824219
|
||||
},
|
||||
{
|
||||
"x": 182.171127319336,
|
||||
"y": 916.398681640625
|
||||
},
|
||||
{
|
||||
"x": 174.780258178711,
|
||||
"y": 927.553466796875
|
||||
},
|
||||
{
|
||||
"x": 163.625518798828,
|
||||
"y": 934.9443359375
|
||||
},
|
||||
{
|
||||
"x": 150.554641723633,
|
||||
"y": 937.544799804688
|
||||
},
|
||||
{
|
||||
"x": 137.483764648438,
|
||||
"y": 934.9443359375
|
||||
},
|
||||
{
|
||||
"x": 126.329025268555,
|
||||
"y": 927.553466796875
|
||||
},
|
||||
{
|
||||
"x": 118.938163757324,
|
||||
"y": 916.398681640625
|
||||
},
|
||||
{
|
||||
"x": 116.337677001953,
|
||||
"y": 903.327819824219
|
||||
},
|
||||
{
|
||||
"x": 118.938163757324,
|
||||
"y": 890.256958007813
|
||||
},
|
||||
{
|
||||
"x": 126.329025268555,
|
||||
"y": 879.102172851563
|
||||
},
|
||||
{
|
||||
"x": 137.483764648438,
|
||||
"y": 871.711364746094
|
||||
},
|
||||
{
|
||||
"x": 150.554641723633,
|
||||
"y": 869.11083984375
|
||||
},
|
||||
{
|
||||
"x": 163.625518798828,
|
||||
"y": 871.711364746094
|
||||
},
|
||||
{
|
||||
"x": 174.780258178711,
|
||||
"y": 879.102172851563
|
||||
},
|
||||
{
|
||||
"x": 182.171127319336,
|
||||
"y": 890.256958007813
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E8B38A",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 27.3735711442786,
|
||||
"points": [
|
||||
{
|
||||
"x": -875.954284667969,
|
||||
"y": 1231.81066894531
|
||||
},
|
||||
{
|
||||
"x": 875.954284667969,
|
||||
"y": 1231.81066894531
|
||||
},
|
||||
{
|
||||
"x": 875.954284667969,
|
||||
"y": 1361.83520507813
|
||||
},
|
||||
{
|
||||
"x": -875.954284667969,
|
||||
"y": 1361.83520507813
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"buildings"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,433 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "none",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T23:12:39",
|
||||
"modified_at": "2026-10-21T23:12:39"
|
||||
},
|
||||
"prop_name": "Wall Clock",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DCA678",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 7.3205,
|
||||
"points": [
|
||||
{
|
||||
"x": 102.486999511719,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": 94.6833419799805,
|
||||
"y": 39.2232398986816
|
||||
},
|
||||
{
|
||||
"x": 72.4729537963867,
|
||||
"y": 72.4729537963867
|
||||
},
|
||||
{
|
||||
"x": 39.2232398986816,
|
||||
"y": 94.6833419799805
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 102.486999511719
|
||||
},
|
||||
{
|
||||
"x": -39.2232398986816,
|
||||
"y": 94.6833419799805
|
||||
},
|
||||
{
|
||||
"x": -72.4729537963867,
|
||||
"y": 72.4729537963867
|
||||
},
|
||||
{
|
||||
"x": -94.6833419799805,
|
||||
"y": 39.2232398986816
|
||||
},
|
||||
{
|
||||
"x": -102.486999511719,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": -94.6833419799805,
|
||||
"y": -39.2232398986816
|
||||
},
|
||||
{
|
||||
"x": -72.4729537963867,
|
||||
"y": -72.4729537963867
|
||||
},
|
||||
{
|
||||
"x": -39.2232398986816,
|
||||
"y": -94.6833419799805
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -102.486999511719
|
||||
},
|
||||
{
|
||||
"x": 39.2232398986816,
|
||||
"y": -94.6833419799805
|
||||
},
|
||||
{
|
||||
"x": 72.4729537963867,
|
||||
"y": -72.4729537963867
|
||||
},
|
||||
{
|
||||
"x": 94.6833419799805,
|
||||
"y": -39.2232398986816
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FCF2D8",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 4.3923,
|
||||
"points": [
|
||||
{
|
||||
"x": 79.0614013671875,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": 73.0439453125,
|
||||
"y": 30.2483062744141
|
||||
},
|
||||
{
|
||||
"x": 55.8993377685547,
|
||||
"y": 55.8993377685547
|
||||
},
|
||||
{
|
||||
"x": 30.2483062744141,
|
||||
"y": 73.0439453125
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 79.0614013671875
|
||||
},
|
||||
{
|
||||
"x": -30.2483062744141,
|
||||
"y": 73.0439453125
|
||||
},
|
||||
{
|
||||
"x": -55.8993377685547,
|
||||
"y": 55.8993377685547
|
||||
},
|
||||
{
|
||||
"x": -73.0439453125,
|
||||
"y": 30.2483062744141
|
||||
},
|
||||
{
|
||||
"x": -79.0614013671875,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": -73.0439453125,
|
||||
"y": -30.2483062744141
|
||||
},
|
||||
{
|
||||
"x": -55.8993377685547,
|
||||
"y": -55.8993377685547
|
||||
},
|
||||
{
|
||||
"x": -30.2483062744141,
|
||||
"y": -73.0439453125
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -79.0614013671875
|
||||
},
|
||||
{
|
||||
"x": 30.2483062744141,
|
||||
"y": -73.0439453125
|
||||
},
|
||||
{
|
||||
"x": 55.8993377685547,
|
||||
"y": -55.8993377685547
|
||||
},
|
||||
{
|
||||
"x": 73.0439453125,
|
||||
"y": -30.2483062744141
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#75586C",
|
||||
"outline_width": 5.8564,
|
||||
"points": [
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -65.8844985961914
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -45.3871002197266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#75586C",
|
||||
"outline_width": 5.8564,
|
||||
"points": [
|
||||
{
|
||||
"x": 64.4204025268555,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": 43.9230003356934,
|
||||
"y": 0.0
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#75586C",
|
||||
"outline_width": 5.8564,
|
||||
"points": [
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 65.8844985961914
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 45.3871002197266
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#75586C",
|
||||
"outline_width": 5.8564,
|
||||
"points": [
|
||||
{
|
||||
"x": -64.4204025268555,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": -43.9230003356934,
|
||||
"y": 0.0
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#75586C",
|
||||
"outline_width": 7.3205,
|
||||
"points": [
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -35.1384010314941
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#75586C",
|
||||
"outline_width": 7.3205,
|
||||
"points": [
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": 35.1384010314941,
|
||||
"y": 21.9615001678467
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#75586C",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 1.4641,
|
||||
"points": [
|
||||
{
|
||||
"x": 7.32049989700317,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": 6.76414203643799,
|
||||
"y": 2.79643106460571
|
||||
},
|
||||
{
|
||||
"x": 5.1829137802124,
|
||||
"y": 5.1829137802124
|
||||
},
|
||||
{
|
||||
"x": 2.79643106460571,
|
||||
"y": 6.76414203643799
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 7.32049989700317
|
||||
},
|
||||
{
|
||||
"x": -2.79643106460571,
|
||||
"y": 6.76414203643799
|
||||
},
|
||||
{
|
||||
"x": -5.1829137802124,
|
||||
"y": 5.1829137802124
|
||||
},
|
||||
{
|
||||
"x": -6.76414203643799,
|
||||
"y": 2.79643106460571
|
||||
},
|
||||
{
|
||||
"x": -7.32049989700317,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": -6.76414203643799,
|
||||
"y": -2.79643106460571
|
||||
},
|
||||
{
|
||||
"x": -5.1829137802124,
|
||||
"y": -5.1829137802124
|
||||
},
|
||||
{
|
||||
"x": -2.79643106460571,
|
||||
"y": -6.76414203643799
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -7.32049989700317
|
||||
},
|
||||
{
|
||||
"x": 2.79643106460571,
|
||||
"y": -6.76414203643799
|
||||
},
|
||||
{
|
||||
"x": 5.1829137802124,
|
||||
"y": -5.1829137802124
|
||||
},
|
||||
{
|
||||
"x": 6.76414203643799,
|
||||
"y": -2.79643106460571
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"walls",
|
||||
"objects"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,687 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"prop_name": "Wall TV",
|
||||
"material_preset": "none",
|
||||
"tags": [
|
||||
"objects",
|
||||
"walls"
|
||||
],
|
||||
"shapes": [
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -335,
|
||||
"y": -195
|
||||
},
|
||||
{
|
||||
"x": 335,
|
||||
"y": -195
|
||||
},
|
||||
{
|
||||
"x": 340,
|
||||
"y": -190
|
||||
},
|
||||
{
|
||||
"x": 340,
|
||||
"y": 190
|
||||
},
|
||||
{
|
||||
"x": 335,
|
||||
"y": 195
|
||||
},
|
||||
{
|
||||
"x": -335,
|
||||
"y": 195
|
||||
},
|
||||
{
|
||||
"x": -340,
|
||||
"y": 190
|
||||
},
|
||||
{
|
||||
"x": -340,
|
||||
"y": -190
|
||||
}
|
||||
],
|
||||
"fill_color": "#1A202A",
|
||||
"outline_color": "#090D13",
|
||||
"outline_width": 3.8,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -333,
|
||||
"y": -188
|
||||
},
|
||||
{
|
||||
"x": 333,
|
||||
"y": -188
|
||||
},
|
||||
{
|
||||
"x": 324,
|
||||
"y": -178
|
||||
},
|
||||
{
|
||||
"x": -324,
|
||||
"y": -178
|
||||
}
|
||||
],
|
||||
"fill_color": "#3C4652",
|
||||
"outline_color": "#3C4652",
|
||||
"outline_width": 0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -333,
|
||||
"y": -187
|
||||
},
|
||||
{
|
||||
"x": -324,
|
||||
"y": -178
|
||||
},
|
||||
{
|
||||
"x": -324,
|
||||
"y": 168
|
||||
},
|
||||
{
|
||||
"x": -333,
|
||||
"y": 185
|
||||
}
|
||||
],
|
||||
"fill_color": "#323C47",
|
||||
"outline_color": "#323C47",
|
||||
"outline_width": 0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": 333,
|
||||
"y": -187
|
||||
},
|
||||
{
|
||||
"x": 333,
|
||||
"y": 185
|
||||
},
|
||||
{
|
||||
"x": 324,
|
||||
"y": 168
|
||||
},
|
||||
{
|
||||
"x": 324,
|
||||
"y": -178
|
||||
}
|
||||
],
|
||||
"fill_color": "#101720",
|
||||
"outline_color": "#101720",
|
||||
"outline_width": 0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -332,
|
||||
"y": 168
|
||||
},
|
||||
{
|
||||
"x": 332,
|
||||
"y": 168
|
||||
},
|
||||
{
|
||||
"x": 332,
|
||||
"y": 188
|
||||
},
|
||||
{
|
||||
"x": -332,
|
||||
"y": 188
|
||||
}
|
||||
],
|
||||
"fill_color": "#232B36",
|
||||
"outline_color": "#232B36",
|
||||
"outline_width": 0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -327,
|
||||
"y": -177
|
||||
},
|
||||
{
|
||||
"x": 327,
|
||||
"y": -177
|
||||
},
|
||||
{
|
||||
"x": 327,
|
||||
"y": 169
|
||||
},
|
||||
{
|
||||
"x": -327,
|
||||
"y": 169
|
||||
}
|
||||
],
|
||||
"fill_color": "#10151D",
|
||||
"outline_color": "#080C12",
|
||||
"outline_width": 2.3,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -318,
|
||||
"y": -167
|
||||
},
|
||||
{
|
||||
"x": 318,
|
||||
"y": -167
|
||||
},
|
||||
{
|
||||
"x": 318,
|
||||
"y": 158
|
||||
},
|
||||
{
|
||||
"x": -318,
|
||||
"y": 158
|
||||
}
|
||||
],
|
||||
"fill_color": "#242932",
|
||||
"outline_color": "#10141B",
|
||||
"outline_width": 2.4,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -309,
|
||||
"y": -158
|
||||
},
|
||||
{
|
||||
"x": -67,
|
||||
"y": -158
|
||||
},
|
||||
{
|
||||
"x": -151,
|
||||
"y": 149
|
||||
},
|
||||
{
|
||||
"x": -309,
|
||||
"y": 149
|
||||
}
|
||||
],
|
||||
"fill_color": "#36404A",
|
||||
"outline_color": "#36404A",
|
||||
"outline_width": 0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -309,
|
||||
"y": -158
|
||||
},
|
||||
{
|
||||
"x": -230,
|
||||
"y": -158
|
||||
},
|
||||
{
|
||||
"x": -299,
|
||||
"y": 149
|
||||
},
|
||||
{
|
||||
"x": -309,
|
||||
"y": 149
|
||||
}
|
||||
],
|
||||
"fill_color": "#3C4651",
|
||||
"outline_color": "#3C4651",
|
||||
"outline_width": 0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "line",
|
||||
"points": [
|
||||
{
|
||||
"x": -296,
|
||||
"y": -154
|
||||
},
|
||||
{
|
||||
"x": -90,
|
||||
"y": -154
|
||||
}
|
||||
],
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#66717B",
|
||||
"outline_width": 1.4,
|
||||
"closed": false,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "line",
|
||||
"points": [
|
||||
{
|
||||
"x": -309,
|
||||
"y": 151
|
||||
},
|
||||
{
|
||||
"x": 309,
|
||||
"y": 151
|
||||
}
|
||||
],
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#1A2029",
|
||||
"outline_width": 4.0,
|
||||
"closed": false,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "line",
|
||||
"points": [
|
||||
{
|
||||
"x": -320,
|
||||
"y": 171
|
||||
},
|
||||
{
|
||||
"x": 320,
|
||||
"y": 171
|
||||
}
|
||||
],
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#4A535F",
|
||||
"outline_width": 1.2,
|
||||
"closed": false,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -7.0,
|
||||
"y": 183.0
|
||||
},
|
||||
{
|
||||
"x": -7.94,
|
||||
"y": 186.5
|
||||
},
|
||||
{
|
||||
"x": -10.5,
|
||||
"y": 189.06
|
||||
},
|
||||
{
|
||||
"x": -14.0,
|
||||
"y": 190.0
|
||||
},
|
||||
{
|
||||
"x": -17.5,
|
||||
"y": 189.06
|
||||
},
|
||||
{
|
||||
"x": -20.06,
|
||||
"y": 186.5
|
||||
},
|
||||
{
|
||||
"x": -21.0,
|
||||
"y": 183.0
|
||||
},
|
||||
{
|
||||
"x": -20.06,
|
||||
"y": 179.5
|
||||
},
|
||||
{
|
||||
"x": -17.5,
|
||||
"y": 176.94
|
||||
},
|
||||
{
|
||||
"x": -14.0,
|
||||
"y": 176.0
|
||||
},
|
||||
{
|
||||
"x": -10.5,
|
||||
"y": 176.94
|
||||
},
|
||||
{
|
||||
"x": -7.94,
|
||||
"y": 179.5
|
||||
}
|
||||
],
|
||||
"fill_color": "#39232A",
|
||||
"outline_color": "#111720",
|
||||
"outline_width": 1.0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": -10.0,
|
||||
"y": 183.0
|
||||
},
|
||||
{
|
||||
"x": -10.54,
|
||||
"y": 185.0
|
||||
},
|
||||
{
|
||||
"x": -12.0,
|
||||
"y": 186.46
|
||||
},
|
||||
{
|
||||
"x": -14.0,
|
||||
"y": 187.0
|
||||
},
|
||||
{
|
||||
"x": -16.0,
|
||||
"y": 186.46
|
||||
},
|
||||
{
|
||||
"x": -17.46,
|
||||
"y": 185.0
|
||||
},
|
||||
{
|
||||
"x": -18.0,
|
||||
"y": 183.0
|
||||
},
|
||||
{
|
||||
"x": -17.46,
|
||||
"y": 181.0
|
||||
},
|
||||
{
|
||||
"x": -16.0,
|
||||
"y": 179.54
|
||||
},
|
||||
{
|
||||
"x": -14.0,
|
||||
"y": 179.0
|
||||
},
|
||||
{
|
||||
"x": -12.0,
|
||||
"y": 179.54
|
||||
},
|
||||
{
|
||||
"x": -10.54,
|
||||
"y": 181.0
|
||||
}
|
||||
],
|
||||
"fill_color": "#E05A60",
|
||||
"outline_color": "#E05A60",
|
||||
"outline_width": 0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": 21.0,
|
||||
"y": 183.0
|
||||
},
|
||||
{
|
||||
"x": 20.06,
|
||||
"y": 186.5
|
||||
},
|
||||
{
|
||||
"x": 17.5,
|
||||
"y": 189.06
|
||||
},
|
||||
{
|
||||
"x": 14.0,
|
||||
"y": 190.0
|
||||
},
|
||||
{
|
||||
"x": 10.5,
|
||||
"y": 189.06
|
||||
},
|
||||
{
|
||||
"x": 7.94,
|
||||
"y": 186.5
|
||||
},
|
||||
{
|
||||
"x": 7.0,
|
||||
"y": 183.0
|
||||
},
|
||||
{
|
||||
"x": 7.94,
|
||||
"y": 179.5
|
||||
},
|
||||
{
|
||||
"x": 10.5,
|
||||
"y": 176.94
|
||||
},
|
||||
{
|
||||
"x": 14.0,
|
||||
"y": 176.0
|
||||
},
|
||||
{
|
||||
"x": 17.5,
|
||||
"y": 176.94
|
||||
},
|
||||
{
|
||||
"x": 20.06,
|
||||
"y": 179.5
|
||||
}
|
||||
],
|
||||
"fill_color": "#243A30",
|
||||
"outline_color": "#111720",
|
||||
"outline_width": 1.0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{
|
||||
"x": 18.0,
|
||||
"y": 183.0
|
||||
},
|
||||
{
|
||||
"x": 17.46,
|
||||
"y": 185.0
|
||||
},
|
||||
{
|
||||
"x": 16.0,
|
||||
"y": 186.46
|
||||
},
|
||||
{
|
||||
"x": 14.0,
|
||||
"y": 187.0
|
||||
},
|
||||
{
|
||||
"x": 12.0,
|
||||
"y": 186.46
|
||||
},
|
||||
{
|
||||
"x": 10.54,
|
||||
"y": 185.0
|
||||
},
|
||||
{
|
||||
"x": 10.0,
|
||||
"y": 183.0
|
||||
},
|
||||
{
|
||||
"x": 10.54,
|
||||
"y": 181.0
|
||||
},
|
||||
{
|
||||
"x": 12.0,
|
||||
"y": 179.54
|
||||
},
|
||||
{
|
||||
"x": 14.0,
|
||||
"y": 179.0
|
||||
},
|
||||
{
|
||||
"x": 16.0,
|
||||
"y": 179.54
|
||||
},
|
||||
{
|
||||
"x": 17.46,
|
||||
"y": 181.0
|
||||
}
|
||||
],
|
||||
"fill_color": "#68CB8D",
|
||||
"outline_color": "#68CB8D",
|
||||
"outline_width": 0,
|
||||
"closed": true,
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"reshaped": false
|
||||
}
|
||||
],
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"role": "pivot",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"rotation_deg": 0,
|
||||
"z_index_offset": 0,
|
||||
"allowed_hands": "both"
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T20:07:34-04:00",
|
||||
"modified_at": "2026-10-21T20:07:34-04:00"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "wood",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T23:13:10",
|
||||
"modified_at": "2026-10-21T23:13:10"
|
||||
},
|
||||
"prop_name": "Open Window Frame",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EBCF9E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -171.698989868164,
|
||||
"y": -186.339996337891
|
||||
},
|
||||
{
|
||||
"x": -145.078994750977,
|
||||
"y": -186.339996337891
|
||||
},
|
||||
{
|
||||
"x": -145.078994750977,
|
||||
"y": 165.043991088867
|
||||
},
|
||||
{
|
||||
"x": -171.698989868164,
|
||||
"y": 165.043991088867
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EBCF9E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": 145.078994750977,
|
||||
"y": -186.339996337891
|
||||
},
|
||||
{
|
||||
"x": 171.698989868164,
|
||||
"y": -186.339996337891
|
||||
},
|
||||
{
|
||||
"x": 171.698989868164,
|
||||
"y": 165.043991088867
|
||||
},
|
||||
{
|
||||
"x": 145.078994750977,
|
||||
"y": 165.043991088867
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EBCF9E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -171.698989868164,
|
||||
"y": -186.339996337891
|
||||
},
|
||||
{
|
||||
"x": 171.698989868164,
|
||||
"y": -186.339996337891
|
||||
},
|
||||
{
|
||||
"x": 171.698989868164,
|
||||
"y": -159.720001220703
|
||||
},
|
||||
{
|
||||
"x": -171.698989868164,
|
||||
"y": -159.720001220703
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EBCF9E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -171.698989868164,
|
||||
"y": 138.42399597168
|
||||
},
|
||||
{
|
||||
"x": 171.698989868164,
|
||||
"y": 138.42399597168
|
||||
},
|
||||
{
|
||||
"x": 171.698989868164,
|
||||
"y": 165.043991088867
|
||||
},
|
||||
{
|
||||
"x": -171.698989868164,
|
||||
"y": 165.043991088867
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EBCF9E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -13.3099994659424,
|
||||
"y": -159.720001220703
|
||||
},
|
||||
{
|
||||
"x": 13.3099994659424,
|
||||
"y": -159.720001220703
|
||||
},
|
||||
{
|
||||
"x": 13.3099994659424,
|
||||
"y": 138.42399597168
|
||||
},
|
||||
{
|
||||
"x": -13.3099994659424,
|
||||
"y": 138.42399597168
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EBCF9E",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -145.078994750977,
|
||||
"y": -23.9580001831055
|
||||
},
|
||||
{
|
||||
"x": 145.078994750977,
|
||||
"y": -23.9580001831055
|
||||
},
|
||||
{
|
||||
"x": 145.078994750977,
|
||||
"y": 2.66199994087219
|
||||
},
|
||||
{
|
||||
"x": -145.078994750977,
|
||||
"y": 2.66199994087219
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C89670",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 5.324,
|
||||
"points": [
|
||||
{
|
||||
"x": -192.994995117188,
|
||||
"y": 165.043991088867
|
||||
},
|
||||
{
|
||||
"x": 192.994995117188,
|
||||
"y": 165.043991088867
|
||||
},
|
||||
{
|
||||
"x": 192.994995117188,
|
||||
"y": 186.339996337891
|
||||
},
|
||||
{
|
||||
"x": -192.994995117188,
|
||||
"y": 186.339996337891
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"walls",
|
||||
"buildings"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "wood",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T23:15:32",
|
||||
"modified_at": "2026-10-21T23:15:32"
|
||||
},
|
||||
"prop_name": "Cozy Armchair",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#80A9AF",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -243.811782836914,
|
||||
"y": 185.452575683594
|
||||
},
|
||||
{
|
||||
"x": -243.811782836914,
|
||||
"y": -208.796264648438
|
||||
},
|
||||
{
|
||||
"x": -184.155700683594,
|
||||
"y": -281.421051025391
|
||||
},
|
||||
{
|
||||
"x": 184.155700683594,
|
||||
"y": -281.421051025391
|
||||
},
|
||||
{
|
||||
"x": 243.811782836914,
|
||||
"y": -208.796264648438
|
||||
},
|
||||
{
|
||||
"x": 243.811782836914,
|
||||
"y": 185.452575683594
|
||||
},
|
||||
{
|
||||
"x": 197.124420166016,
|
||||
"y": 239.921173095703
|
||||
},
|
||||
{
|
||||
"x": -197.124420166016,
|
||||
"y": 239.921173095703
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#A8CED0",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -168.59326171875,
|
||||
"y": -213.983749389648
|
||||
},
|
||||
{
|
||||
"x": 168.59326171875,
|
||||
"y": -213.983749389648
|
||||
},
|
||||
{
|
||||
"x": 168.59326171875,
|
||||
"y": 60.9529457092285
|
||||
},
|
||||
{
|
||||
"x": -168.59326171875,
|
||||
"y": 60.9529457092285
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C3DDCF",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -189.343200683594,
|
||||
"y": 50.5779762268066
|
||||
},
|
||||
{
|
||||
"x": 189.343200683594,
|
||||
"y": 50.5779762268066
|
||||
},
|
||||
{
|
||||
"x": 212.686874389648,
|
||||
"y": 182.858840942383
|
||||
},
|
||||
{
|
||||
"x": -212.686874389648,
|
||||
"y": 182.858840942383
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#80A9AF",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -246.405517578125,
|
||||
"y": -3.8906135559082
|
||||
},
|
||||
{
|
||||
"x": -186.749450683594,
|
||||
"y": -40.2030067443848
|
||||
},
|
||||
{
|
||||
"x": -153.030792236328,
|
||||
"y": 9.07809829711914
|
||||
},
|
||||
{
|
||||
"x": -153.030792236328,
|
||||
"y": 208.796264648438
|
||||
},
|
||||
{
|
||||
"x": -246.405517578125,
|
||||
"y": 208.796264648438
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#80A9AF",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": 246.405517578125,
|
||||
"y": -3.8906135559082
|
||||
},
|
||||
{
|
||||
"x": 186.749450683594,
|
||||
"y": -40.2030067443848
|
||||
},
|
||||
{
|
||||
"x": 153.030792236328,
|
||||
"y": 9.07809829711914
|
||||
},
|
||||
{
|
||||
"x": 153.030792236328,
|
||||
"y": 208.796264648438
|
||||
},
|
||||
{
|
||||
"x": 246.405517578125,
|
||||
"y": 208.796264648438
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#755369",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -184.155700683594,
|
||||
"y": 224.35871887207
|
||||
},
|
||||
{
|
||||
"x": -124.499633789063,
|
||||
"y": 224.35871887207
|
||||
},
|
||||
{
|
||||
"x": -124.499633789063,
|
||||
"y": 281.421051025391
|
||||
},
|
||||
{
|
||||
"x": -184.155700683594,
|
||||
"y": 281.421051025391
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#755369",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": 124.499633789063,
|
||||
"y": 224.35871887207
|
||||
},
|
||||
{
|
||||
"x": 184.155700683594,
|
||||
"y": 224.35871887207
|
||||
},
|
||||
{
|
||||
"x": 184.155700683594,
|
||||
"y": 281.421051025391
|
||||
},
|
||||
{
|
||||
"x": 124.499633789063,
|
||||
"y": 281.421051025391
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"objects"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "wood",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T23:15:55",
|
||||
"modified_at": "2026-10-21T23:15:55"
|
||||
},
|
||||
"prop_name": "Coffee Table",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B9805D",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 6.44204,
|
||||
"points": [
|
||||
{
|
||||
"x": -241.57649230957,
|
||||
"y": -112.735702514648
|
||||
},
|
||||
{
|
||||
"x": 241.57649230957,
|
||||
"y": -112.735702514648
|
||||
},
|
||||
{
|
||||
"x": 241.57649230957,
|
||||
"y": -67.6414184570313
|
||||
},
|
||||
{
|
||||
"x": -241.57649230957,
|
||||
"y": -67.6414184570313
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#D69E70",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 6.44204,
|
||||
"points": [
|
||||
{
|
||||
"x": -206.145278930664,
|
||||
"y": -67.6414184570313
|
||||
},
|
||||
{
|
||||
"x": 206.145278930664,
|
||||
"y": -67.6414184570313
|
||||
},
|
||||
{
|
||||
"x": 206.145278930664,
|
||||
"y": -48.315299987793
|
||||
},
|
||||
{
|
||||
"x": -206.145278930664,
|
||||
"y": -48.315299987793
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#A66F58",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 6.44204,
|
||||
"points": [
|
||||
{
|
||||
"x": -199.703231811523,
|
||||
"y": -49.9258079528809
|
||||
},
|
||||
{
|
||||
"x": -157.829986572266,
|
||||
"y": -49.9258079528809
|
||||
},
|
||||
{
|
||||
"x": -144.945892333984,
|
||||
"y": 112.735702514648
|
||||
},
|
||||
{
|
||||
"x": -186.819152832031,
|
||||
"y": 112.735702514648
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#A66F58",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 6.44204,
|
||||
"points": [
|
||||
{
|
||||
"x": 157.829986572266,
|
||||
"y": -49.9258079528809
|
||||
},
|
||||
{
|
||||
"x": 199.703231811523,
|
||||
"y": -49.9258079528809
|
||||
},
|
||||
{
|
||||
"x": 186.819152832031,
|
||||
"y": 112.735702514648
|
||||
},
|
||||
{
|
||||
"x": 144.945892333984,
|
||||
"y": 112.735702514648
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#C38C68",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 6.44204,
|
||||
"points": [
|
||||
{
|
||||
"x": -162.661514282227,
|
||||
"y": 35.4312210083008
|
||||
},
|
||||
{
|
||||
"x": 162.661514282227,
|
||||
"y": 35.4312210083008
|
||||
},
|
||||
{
|
||||
"x": 162.661514282227,
|
||||
"y": 54.7573394775391
|
||||
},
|
||||
{
|
||||
"x": -162.661514282227,
|
||||
"y": 54.7573394775391
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#E8B98A",
|
||||
"outline_width": 4.83153,
|
||||
"points": [
|
||||
{
|
||||
"x": -185.208648681641,
|
||||
"y": -99.8516159057617
|
||||
},
|
||||
{
|
||||
"x": 185.208648681641,
|
||||
"y": -99.8516159057617
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"objects"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
}
|
||||
},
|
||||
"material_preset": "wood",
|
||||
"metadata": {
|
||||
"created_at": "2026-10-21T23:16:12",
|
||||
"modified_at": "2026-10-21T23:16:12"
|
||||
},
|
||||
"prop_name": "Cozy Couch",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B7767B",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -435.748718261719,
|
||||
"y": 165.99951171875
|
||||
},
|
||||
{
|
||||
"x": -435.748718261719,
|
||||
"y": -171.186996459961
|
||||
},
|
||||
{
|
||||
"x": -376.092651367188,
|
||||
"y": -261.967987060547
|
||||
},
|
||||
{
|
||||
"x": 376.092651367188,
|
||||
"y": -261.967987060547
|
||||
},
|
||||
{
|
||||
"x": 435.748718261719,
|
||||
"y": -171.186996459961
|
||||
},
|
||||
{
|
||||
"x": 435.748718261719,
|
||||
"y": 165.99951171875
|
||||
},
|
||||
{
|
||||
"x": 378.686401367188,
|
||||
"y": 217.874359130859
|
||||
},
|
||||
{
|
||||
"x": -378.686401367188,
|
||||
"y": 217.874359130859
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#D9908A",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -355.342712402344,
|
||||
"y": -186.749450683594
|
||||
},
|
||||
{
|
||||
"x": 355.342712402344,
|
||||
"y": -186.749450683594
|
||||
},
|
||||
{
|
||||
"x": 355.342712402344,
|
||||
"y": 41.4998779296875
|
||||
},
|
||||
{
|
||||
"x": -355.342712402344,
|
||||
"y": 41.4998779296875
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#985C71",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -184.155700683594
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 38.906135559082
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EDB09A",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -368.311401367188,
|
||||
"y": 23.3436813354492
|
||||
},
|
||||
{
|
||||
"x": 368.311401367188,
|
||||
"y": 23.3436813354492
|
||||
},
|
||||
{
|
||||
"x": 391.655090332031,
|
||||
"y": 160.812026977539
|
||||
},
|
||||
{
|
||||
"x": -391.655090332031,
|
||||
"y": 160.812026977539
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B7767B",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -433.154968261719,
|
||||
"y": -59.6560745239258
|
||||
},
|
||||
{
|
||||
"x": -373.498901367188,
|
||||
"y": -88.1872406005859
|
||||
},
|
||||
{
|
||||
"x": -339.780242919922,
|
||||
"y": -51.8748474121094
|
||||
},
|
||||
{
|
||||
"x": -339.780242919922,
|
||||
"y": 186.749450683594
|
||||
},
|
||||
{
|
||||
"x": -435.748718261719,
|
||||
"y": 186.749450683594
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B7767B",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": 433.154968261719,
|
||||
"y": -59.6560745239258
|
||||
},
|
||||
{
|
||||
"x": 373.498901367188,
|
||||
"y": -88.1872406005859
|
||||
},
|
||||
{
|
||||
"x": 339.780242919922,
|
||||
"y": -51.8748474121094
|
||||
},
|
||||
{
|
||||
"x": 339.780242919922,
|
||||
"y": 186.749450683594
|
||||
},
|
||||
{
|
||||
"x": 435.748718261719,
|
||||
"y": 186.749450683594
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#755369",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": -360.530181884766,
|
||||
"y": 202.311904907227
|
||||
},
|
||||
{
|
||||
"x": -293.092895507813,
|
||||
"y": 202.311904907227
|
||||
},
|
||||
{
|
||||
"x": -293.092895507813,
|
||||
"y": 261.967987060547
|
||||
},
|
||||
{
|
||||
"x": -360.530181884766,
|
||||
"y": 261.967987060547
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#755369",
|
||||
"outline_color": "#332B45",
|
||||
"outline_width": 10.3749698404,
|
||||
"points": [
|
||||
{
|
||||
"x": 293.092895507813,
|
||||
"y": 202.311904907227
|
||||
},
|
||||
{
|
||||
"x": 360.530181884766,
|
||||
"y": 202.311904907227
|
||||
},
|
||||
{
|
||||
"x": 360.530181884766,
|
||||
"y": 261.967987060547
|
||||
},
|
||||
{
|
||||
"x": 293.092895507813,
|
||||
"y": 261.967987060547
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"objects"
|
||||
],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
{
|
||||
"version": "1.6",
|
||||
"scene_name": "Blank Scene",
|
||||
"sky_id": "sky_neutral",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 1863.90759277344,
|
||||
"y": -391.476318359375
|
||||
},
|
||||
"zoom": 0.665500044822693
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "wall_panel_1",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 448.0,
|
||||
"y": -320.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 5120.0,
|
||||
"y": 2816.0
|
||||
},
|
||||
"finish_id": "finish_wall_brick",
|
||||
"color": "#b95f3dff"
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -128.0,
|
||||
"y": -129.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 2404.91528320313,
|
||||
"y": 141.710083007813
|
||||
},
|
||||
"style": "walk"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1536.0,
|
||||
"y": 224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1728.0,
|
||||
"y": 224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1920.0,
|
||||
"y": 224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2112.0,
|
||||
"y": 224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2304.0,
|
||||
"y": 224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2496.0,
|
||||
"y": 224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 320.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 320.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_19",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_20",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_asphalt"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_2",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 9984.0,
|
||||
"y": 5504.0
|
||||
},
|
||||
"finish_id": "finish_wall_brick",
|
||||
"color": "#b95f3dff"
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1792022400,
|
||||
"modified_unix": 1792470929.846,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,641 @@
|
||||
{
|
||||
"version": "1.5",
|
||||
"scene_name": "Living Room",
|
||||
"sky_id": "sky_clear_day",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 194.703018188477,
|
||||
"y": -486.092163085938
|
||||
},
|
||||
"zoom": 0.665500044822693
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "wall_panel_1",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -820.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1120.0,
|
||||
"y": 170.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_2",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -360.0,
|
||||
"y": -535.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 440.0,
|
||||
"y": 400.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_3",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 360.0,
|
||||
"y": -535.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 440.0,
|
||||
"y": 400.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_1",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -530.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_window_frame-v1.prop",
|
||||
"display_name": "Window frame",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -147.0,
|
||||
"y": -154.0
|
||||
},
|
||||
"size": {
|
||||
"x": 294.0,
|
||||
"y": 284.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_2",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -430.0,
|
||||
"y": -570.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_wall_clock-v1.prop",
|
||||
"display_name": "Wall clock",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 0.800000011920929,
|
||||
"y": 0.800000011920929
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -72.5,
|
||||
"y": -72.5
|
||||
},
|
||||
"size": {
|
||||
"x": 145.0,
|
||||
"y": 145.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_3",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 365.0,
|
||||
"y": -460.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_fireplace_mantel-v2.prop",
|
||||
"display_name": "Fireplace",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 0.819999992847443,
|
||||
"y": 0.819999992847443
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -153.0,
|
||||
"y": -116.0
|
||||
},
|
||||
"size": {
|
||||
"x": 306.0,
|
||||
"y": 244.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_4",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -475.0,
|
||||
"y": -310.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_bookshelf-v1.prop",
|
||||
"display_name": "Bookshelf",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 0.819999992847443,
|
||||
"y": 0.819999992847443
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -104.0,
|
||||
"y": -190.0
|
||||
},
|
||||
"size": {
|
||||
"x": 208.0,
|
||||
"y": 315.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_5",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 185.0,
|
||||
"y": -575.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_framed_picture-v1.prop",
|
||||
"display_name": "Framed picture",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 0.75,
|
||||
"y": 0.75
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -112.0,
|
||||
"y": -84.0
|
||||
},
|
||||
"size": {
|
||||
"x": 224.0,
|
||||
"y": 168.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -774.0,
|
||||
"y": 832.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -588.0,
|
||||
"y": 840.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -374.0,
|
||||
"y": 832.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -174.0,
|
||||
"y": 832.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 26.0,
|
||||
"y": 832.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 226.0,
|
||||
"y": 832.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 426.0,
|
||||
"y": 832.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_6",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 112.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_rug-v1.prop",
|
||||
"display_name": "Floor rug",
|
||||
"depth": "floor",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -179.0,
|
||||
"y": -60.0
|
||||
},
|
||||
"size": {
|
||||
"x": 358.0,
|
||||
"y": 139.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_7",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 500.0,
|
||||
"y": 84.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_potted_plant-v1.prop",
|
||||
"display_name": "Potted plant",
|
||||
"depth": "floor",
|
||||
"scale": {
|
||||
"x": 0.800000011920929,
|
||||
"y": 0.800000011920929
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -62.5,
|
||||
"y": -114.5
|
||||
},
|
||||
"size": {
|
||||
"x": 125.0,
|
||||
"y": 219.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -364.0,
|
||||
"y": 680.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/prop_couch-v1.prop",
|
||||
"stage_object_id": "starter_couch",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "still",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": false,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"use_spots": [],
|
||||
"next_use_spot_number": 1,
|
||||
"wobble_on_impact": false,
|
||||
"scale": {
|
||||
"x": 0.819999992847443,
|
||||
"y": 0.819999992847443
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "prop_2",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": 36.0,
|
||||
"y": 684.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/prop_armchair-v1.prop",
|
||||
"stage_object_id": "starter_armchair",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "still",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": false,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"use_spots": [],
|
||||
"next_use_spot_number": 1,
|
||||
"wobble_on_impact": false,
|
||||
"scale": {
|
||||
"x": 0.779999971389771,
|
||||
"y": 0.779999971389771
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "prop_3",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -159.0,
|
||||
"y": 748.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/prop_coffee_table-v1.prop",
|
||||
"stage_object_id": "starter_coffee_table",
|
||||
"roles": {
|
||||
"depth": "front",
|
||||
"start_motion": "still",
|
||||
"holds_other_props": true,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": false,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"use_spots": [],
|
||||
"next_use_spot_number": 1,
|
||||
"wobble_on_impact": false,
|
||||
"scale": {
|
||||
"x": 0.75,
|
||||
"y": 0.75
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -690.0,
|
||||
"y": 152.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 588.195678710938,
|
||||
"y": 144.184204101563
|
||||
},
|
||||
"style": "walk"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_4",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 206.112670898438,
|
||||
"y": -758.285827636719
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 634.58154296875,
|
||||
"y": 125.426147460938
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_5",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 16.1107177734375,
|
||||
"y": -777.534423828125
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 281.898193359375,
|
||||
"y": 181.309020996094
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_6",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -37.2885131835938,
|
||||
"y": -739.658203125
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 276.930786132813,
|
||||
"y": 100.589233398438
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_7",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 218.531005859375,
|
||||
"y": -634.1015625
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 180.067138671875,
|
||||
"y": 257.061401367188
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_8",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -193.760681152344,
|
||||
"y": -507.433654785156
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 142.811889648438,
|
||||
"y": 428.435668945313
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_9",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -5.0006103515625,
|
||||
"y": -762.63232421875
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 321.63720703125,
|
||||
"y": 211.113220214844
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_10",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 29.7709350585938,
|
||||
"y": -198.21484375
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 736.412475585938,
|
||||
"y": 403.598876953125
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_11",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 458.206604003906,
|
||||
"y": -332.954742431641
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 661.901977539063,
|
||||
"y": 986.023010253906
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_12",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -522.22802734375,
|
||||
"y": -360.275299072266
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 789.811767578125,
|
||||
"y": 1020.79449462891
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_13",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 44.6731567382813,
|
||||
"y": -16.9058227539063
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1493.93664550781,
|
||||
"y": 430.919311523438
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_14",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -199.348937988281,
|
||||
"y": 81.19970703125
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1577.14001464844,
|
||||
"y": 259.545166015625
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_15",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 61.60986328125,
|
||||
"y": 297.579467773438
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1281.58154296875,
|
||||
"y": 192.485595703125
|
||||
},
|
||||
"finish_id": "finish_wall_wood",
|
||||
"color": "#5a9d70ff"
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1792022400,
|
||||
"modified_unix": 1792163812.927,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,659 @@
|
||||
{
|
||||
"version": "1.5",
|
||||
"scene_name": "Living Room",
|
||||
"sky_id": "sky_clear_day",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": -43.7599487304688,
|
||||
"y": 247.024810791016
|
||||
},
|
||||
"zoom": 0.665500164031982
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "wall_panel_1",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -820.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1120.0,
|
||||
"y": 170.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_2",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -360.0,
|
||||
"y": -535.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 440.0,
|
||||
"y": 400.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_3",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 360.0,
|
||||
"y": -535.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 440.0,
|
||||
"y": 400.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_1",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -530.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_window_frame-v1.prop",
|
||||
"display_name": "Window frame",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -147.0,
|
||||
"y": -154.0
|
||||
},
|
||||
"size": {
|
||||
"x": 294.0,
|
||||
"y": 284.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_2",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -430.0,
|
||||
"y": -570.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_wall_clock-v1.prop",
|
||||
"display_name": "Wall clock",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 0.800000011920929,
|
||||
"y": 0.800000011920929
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -72.5,
|
||||
"y": -72.5
|
||||
},
|
||||
"size": {
|
||||
"x": 145.0,
|
||||
"y": 145.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_3",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 365.0,
|
||||
"y": -460.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_fireplace_mantel-v2.prop",
|
||||
"display_name": "Fireplace",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 0.819999992847443,
|
||||
"y": 0.819999992847443
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -153.0,
|
||||
"y": -116.0
|
||||
},
|
||||
"size": {
|
||||
"x": 306.0,
|
||||
"y": 244.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_4",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -475.0,
|
||||
"y": -310.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_bookshelf-v1.prop",
|
||||
"display_name": "Bookshelf",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 0.819999992847443,
|
||||
"y": 0.819999992847443
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -104.0,
|
||||
"y": -190.0
|
||||
},
|
||||
"size": {
|
||||
"x": 208.0,
|
||||
"y": 315.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_5",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 185.0,
|
||||
"y": -575.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_framed_picture-v1.prop",
|
||||
"display_name": "Framed picture",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 0.75,
|
||||
"y": 0.75
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -112.0,
|
||||
"y": -84.0
|
||||
},
|
||||
"size": {
|
||||
"x": 224.0,
|
||||
"y": 168.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_6",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 112.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_rug-v1.prop",
|
||||
"display_name": "Floor rug",
|
||||
"depth": "floor",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -179.0,
|
||||
"y": -60.0
|
||||
},
|
||||
"size": {
|
||||
"x": 358.0,
|
||||
"y": 139.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_7",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 500.0,
|
||||
"y": 84.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_potted_plant-v1.prop",
|
||||
"display_name": "Potted plant",
|
||||
"depth": "floor",
|
||||
"scale": {
|
||||
"x": 0.800000011920929,
|
||||
"y": 0.800000011920929
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -62.5,
|
||||
"y": -114.5
|
||||
},
|
||||
"size": {
|
||||
"x": 125.0,
|
||||
"y": 219.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -690.0,
|
||||
"y": 152.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 588.195678710938,
|
||||
"y": 144.184204101563
|
||||
},
|
||||
"style": "walk"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_4",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 206.112670898438,
|
||||
"y": -758.285827636719
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 634.58154296875,
|
||||
"y": 125.426147460938
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_5",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 16.1107177734375,
|
||||
"y": -777.534423828125
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 281.898193359375,
|
||||
"y": 181.309020996094
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_6",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -37.2885131835938,
|
||||
"y": -739.658203125
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 276.930786132813,
|
||||
"y": 100.589233398438
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_7",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 218.531005859375,
|
||||
"y": -634.1015625
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 180.067138671875,
|
||||
"y": 257.061401367188
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_8",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -193.760681152344,
|
||||
"y": -507.433654785156
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 142.811889648438,
|
||||
"y": 428.435668945313
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_9",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -5.0006103515625,
|
||||
"y": -762.63232421875
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 321.63720703125,
|
||||
"y": 211.113220214844
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_10",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 29.7709350585938,
|
||||
"y": -198.21484375
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 736.412475585938,
|
||||
"y": 403.598876953125
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_11",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 458.206604003906,
|
||||
"y": -332.954742431641
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 661.901977539063,
|
||||
"y": 986.023010253906
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_12",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -522.22802734375,
|
||||
"y": -360.275299072266
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 789.811767578125,
|
||||
"y": 1020.79449462891
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_13",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 44.6731567382813,
|
||||
"y": -16.9058227539063
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1493.93664550781,
|
||||
"y": 430.919311523438
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_14",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -199.348937988281,
|
||||
"y": 81.19970703125
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1577.14001464844,
|
||||
"y": 259.545166015625
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_15",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 61.60986328125,
|
||||
"y": 297.579467773438
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1281.58154296875,
|
||||
"y": 192.485595703125
|
||||
},
|
||||
"finish_id": "finish_wall_wood",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_16",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -1040.0,
|
||||
"y": -848.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 32.0,
|
||||
"y": 32.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_17",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -64.0,
|
||||
"y": -176.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 2048.0,
|
||||
"y": 1504.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_18",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -64.0,
|
||||
"y": 592.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 2048.0,
|
||||
"y": 32.0
|
||||
},
|
||||
"finish_id": "finish_wall_wood",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 640.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1792022400,
|
||||
"modified_unix": 1792165751.76,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
{
|
||||
"version": "1.5",
|
||||
"scene_name": "Untitled",
|
||||
"sky_id": "sky_neutral",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 143.607360839844,
|
||||
"y": -79.9739379882813
|
||||
},
|
||||
"zoom": 0.732050061225891
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_wood"
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_1",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -93.5323791503906,
|
||||
"y": -461.938385009766
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_fireplace_mantel-v2.prop",
|
||||
"display_name": "Cozy Brick Fireplace Mantel",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -386.467620849609,
|
||||
"y": -306.061584472656
|
||||
},
|
||||
"size": {
|
||||
"x": 772.935241699219,
|
||||
"y": 612.123168945313
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": 600.0,
|
||||
"y": -457.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -711.525268554688,
|
||||
"y": -142.811157226563
|
||||
},
|
||||
"style": "run"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_1",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 36.0,
|
||||
"y": -612.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1560.0,
|
||||
"y": 840.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_2",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -36.0,
|
||||
"y": -528.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1656.0,
|
||||
"y": 960.0
|
||||
},
|
||||
"finish_id": "finish_wall_paint",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_3",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 120.0,
|
||||
"y": -84.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1728.0,
|
||||
"y": 168.0
|
||||
},
|
||||
"finish_id": "finish_wall_wood",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_4",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -684.0,
|
||||
"y": -156.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 360.0,
|
||||
"y": 24.0
|
||||
},
|
||||
"finish_id": "finish_wall_wood",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_5",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -792.0,
|
||||
"y": -84.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 144.0,
|
||||
"y": 168.0
|
||||
},
|
||||
"finish_id": "finish_wall_wood",
|
||||
"color": "#5a9d70ff"
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_2",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -109.0,
|
||||
"y": -108.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_rug-v1.prop",
|
||||
"display_name": "Patterned Rug",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -179.0,
|
||||
"y": -60.0
|
||||
},
|
||||
"size": {
|
||||
"x": 358.0,
|
||||
"y": 139.0
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1792178012.798,
|
||||
"modified_unix": 1792178012.798,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"version": "1.6",
|
||||
"scene_name": "Untitled",
|
||||
"sky_id": "sky_neutral",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -400.0
|
||||
},
|
||||
"zoom": 0.5
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "wall_panel_1",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": -608.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 1152.0,
|
||||
"y": 832.0
|
||||
},
|
||||
"finish_id": "finish_wall_brick",
|
||||
"color": "#b95f3dff"
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_1",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -64.0,
|
||||
"y": -868.5
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_city_skyline-v1.prop",
|
||||
"display_name": "City Skyline",
|
||||
"depth": "far",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -321.5,
|
||||
"y": -126.5
|
||||
},
|
||||
"size": {
|
||||
"x": 643.0,
|
||||
"y": 198.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_2",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 320.0,
|
||||
"y": -804.5
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_city_skyline-v1.prop",
|
||||
"display_name": "City Skyline",
|
||||
"depth": "floor",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -321.5,
|
||||
"y": -126.5
|
||||
},
|
||||
"size": {
|
||||
"x": 643.0,
|
||||
"y": 198.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_3",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": -804.5
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_city_skyline-v1.prop",
|
||||
"display_name": "City Skyline",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -321.5,
|
||||
"y": -126.5
|
||||
},
|
||||
"size": {
|
||||
"x": 643.0,
|
||||
"y": 198.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_4",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -448.0,
|
||||
"y": -1600.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/baseball.prop",
|
||||
"display_name": "Baseball",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -26.1999988555908,
|
||||
"y": -26.1999988555908
|
||||
},
|
||||
"size": {
|
||||
"x": 52.4000015258789,
|
||||
"y": 52.4000015258789
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1792555445.055,
|
||||
"modified_unix": 1792555445.055,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
{
|
||||
"version": "1.7",
|
||||
"scene_name": "Untitled",
|
||||
"sky_id": "sky_sunset",
|
||||
"background_kind": "plain",
|
||||
"plain_color": "#FFFFFF",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 1676.29174804688,
|
||||
"y": -39.946044921875
|
||||
},
|
||||
"zoom": 0.310460686683655
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "wall_panel_1",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 288.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 4160.0,
|
||||
"y": 2368.0
|
||||
},
|
||||
"finish_id": "finish_wall_brick",
|
||||
"color": "#b95f3dff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_2",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 288.0,
|
||||
"y": -352.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 5568.0,
|
||||
"y": 3136.0
|
||||
},
|
||||
"finish_id": "finish_wall_wood",
|
||||
"color": "#c87137ff"
|
||||
},
|
||||
{
|
||||
"file_id": "background_ground_1",
|
||||
"type": "background_ground",
|
||||
"position": {
|
||||
"x": 256.0,
|
||||
"y": -352.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 6144.0,
|
||||
"y": 3392.0
|
||||
},
|
||||
"finish_id": "finish_background_concrete",
|
||||
"color": "#a6aaa3ff"
|
||||
},
|
||||
{
|
||||
"file_id": "wall_panel_3",
|
||||
"type": "wall_panel",
|
||||
"position": {
|
||||
"x": 128.0,
|
||||
"y": -320.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 6016.0,
|
||||
"y": 3456.0
|
||||
},
|
||||
"finish_id": "finish_wall_brick",
|
||||
"color": "#22c6ffff"
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -1088.0,
|
||||
"y": -641.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 1562.8154296875,
|
||||
"y": -145.01513671875
|
||||
},
|
||||
"style": "walk"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -2112.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1920.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1728.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1536.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_19",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_20",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1536.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_21",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1728.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_grass"
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1792467978,
|
||||
"modified_unix": 1792700708.001,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,857 @@
|
||||
{
|
||||
"version": "1.7",
|
||||
"scene_name": "Plain Background",
|
||||
"sky_id": "sky_starry_night",
|
||||
"background_kind": "sky",
|
||||
"plain_color": "#F5EFE0",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": -43.8016738891602,
|
||||
"y": -691.851379394531
|
||||
},
|
||||
"zoom": 0.605000019073486
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "background_ground_1",
|
||||
"type": "background_ground",
|
||||
"position": {
|
||||
"x": 96.0,
|
||||
"y": 672.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 6592.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"finish_id": "finish_background_grass",
|
||||
"color": "#72a84cff"
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_1",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -1472.0,
|
||||
"y": -320.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_storefront-v1.prop",
|
||||
"display_name": "Sunny Storefront",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -871.896057128906,
|
||||
"y": -826.405822753906
|
||||
},
|
||||
"size": {
|
||||
"x": 1743.79211425781,
|
||||
"y": 1652.81164550781
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_2",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -321.925048828125,
|
||||
"y": -864.47802734375
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_town_house-v1.prop",
|
||||
"display_name": "Town House",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -958.074951171875,
|
||||
"y": -1375.52197265625
|
||||
},
|
||||
"size": {
|
||||
"x": 1916.14990234375,
|
||||
"y": 2751.0439453125
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_3",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 1408.0,
|
||||
"y": -320.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_storefront-v1.prop",
|
||||
"display_name": "Sunny Storefront",
|
||||
"depth": "near",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -871.896057128906,
|
||||
"y": -826.405822753906
|
||||
},
|
||||
"size": {
|
||||
"x": 1743.79211425781,
|
||||
"y": 1652.81164550781
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_4",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": -2368.0,
|
||||
"y": -256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_city_skyline-v1.prop",
|
||||
"display_name": "City Skyline",
|
||||
"depth": "far",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -939.5,
|
||||
"y": -289.301696777344
|
||||
},
|
||||
"size": {
|
||||
"x": 1879.0,
|
||||
"y": 578.603393554688
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_5",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 704.0,
|
||||
"y": -256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_city_skyline-v1.prop",
|
||||
"display_name": "City Skyline",
|
||||
"depth": "far",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -939.5,
|
||||
"y": -289.301696777344
|
||||
},
|
||||
"size": {
|
||||
"x": 1879.0,
|
||||
"y": 578.603393554688
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "scenery_artwork_6",
|
||||
"type": "scenery_artwork",
|
||||
"position": {
|
||||
"x": 2304.0,
|
||||
"y": -256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/art_city_skyline-v1.prop",
|
||||
"display_name": "City Skyline",
|
||||
"depth": "far",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"last_known_local_bounds": {
|
||||
"position": {
|
||||
"x": -939.5,
|
||||
"y": -289.301696777344
|
||||
},
|
||||
"size": {
|
||||
"x": 1879.0,
|
||||
"y": 578.603393554688
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "background_ground_2",
|
||||
"type": "background_ground",
|
||||
"position": {
|
||||
"x": 96.0,
|
||||
"y": 352.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 6848.0,
|
||||
"y": 832.0
|
||||
},
|
||||
"finish_id": "finish_background_grass",
|
||||
"color": "#72a84cff"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -3264.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -3072.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -2880.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -2688.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -2496.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -2304.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -2112.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1920.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1728.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1536.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_19",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_20",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_21",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_22",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_23",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_24",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_25",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_26",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1536.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_27",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1728.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_28",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1920.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_29",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2112.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_30",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2304.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_31",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2496.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_32",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2688.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_33",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2880.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_34",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3072.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_35",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3264.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_36",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3456.0,
|
||||
"y": 768.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"finish_id": "finish_ground_sidewalk"
|
||||
},
|
||||
{
|
||||
"file_id": "background_ground_3",
|
||||
"type": "background_ground",
|
||||
"position": {
|
||||
"x": 160.0,
|
||||
"y": 864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 6912.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"finish_id": "finish_background_concrete",
|
||||
"color": "#a6aaa3ff"
|
||||
},
|
||||
{
|
||||
"file_id": "background_ground_4",
|
||||
"type": "background_ground",
|
||||
"position": {
|
||||
"x": -2896.0,
|
||||
"y": 848.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 800.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"finish_id": "finish_background_concrete",
|
||||
"color": "#a6aaa3ff"
|
||||
},
|
||||
{
|
||||
"file_id": "background_ground_5",
|
||||
"type": "background_ground",
|
||||
"position": {
|
||||
"x": -3264.0,
|
||||
"y": 864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"size": {
|
||||
"x": 320.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"finish_id": "finish_background_concrete",
|
||||
"color": "#a6aaa3ff"
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -2784.0,
|
||||
"y": 351.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 2027.27270507813,
|
||||
"y": 683.355224609375
|
||||
},
|
||||
"style": "walk"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_2",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -672.0,
|
||||
"y": 352.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -3161.15698242188,
|
||||
"y": 701.537109375
|
||||
},
|
||||
"style": "walk"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_3",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": 3392.0,
|
||||
"y": 351.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -3333.0576171875,
|
||||
"y": 726.330444335938
|
||||
},
|
||||
"style": "run"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1792022400,
|
||||
"modified_unix": 1792732500.154,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "1.7",
|
||||
"scene_name": "Open Sky",
|
||||
"sky_id": "sky_neutral",
|
||||
"background_kind": "sky",
|
||||
"plain_color": "#F5EFE0",
|
||||
"camera": {"position": {"x": 0.0, "y": -400.0}, "zoom": 0.5},
|
||||
"objects": [],
|
||||
"event_rules": [],
|
||||
"metadata": {"created_unix": 1792022400, "modified_unix": 1792022400, "autosave": false, "source_path": ""}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"version": "1.6",
|
||||
"scene_name": "Living Room",
|
||||
"sky_id": "sky_clear_day",
|
||||
"camera": {"position": {"x": 118.0, "y": -432.0}, "zoom": 0.38},
|
||||
"objects": [
|
||||
{"file_id":"wall_top","type":"wall_panel","position":{"x":0.0,"y":-941.0},"rotation":0.0,"size":{"x":4760.0,"y":518.0},"finish_id":"finish_wall_paint","color":"#5A9D70"},
|
||||
{"file_id":"wall_left","type":"wall_panel","position":{"x":-1262.5,"y":-256.0},"rotation":0.0,"size":{"x":2235.0,"y":852.0},"finish_id":"finish_wall_paint","color":"#5A9D70"},
|
||||
{"file_id":"wall_right","type":"wall_panel","position":{"x":1262.5,"y":-256.0},"rotation":0.0,"size":{"x":2235.0,"y":852.0},"finish_id":"finish_wall_paint","color":"#5A9D70"},
|
||||
{"file_id":"wall_under_window","type":"wall_panel","position":{"x":0.0,"y":-116.0},"rotation":0.0,"size":{"x":290.0,"y":572.0},"finish_id":"finish_wall_paint","color":"#5A9D70"},
|
||||
{"file_id":"wall_baseboard","type":"wall_panel","position":{"x":0.0,"y":177.0},"rotation":0.0,"size":{"x":4760.0,"y":14.0},"finish_id":"finish_wall_paint","color":"#E4C496"},
|
||||
{"file_id":"window_frame","type":"scenery_artwork","asset_id":"res://content/props/art_window_frame-v1.prop","display_name":"Window frame","depth":"near","position":{"x":0.0,"y":-530.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"wall_clock","type":"scenery_artwork","asset_id":"res://content/props/art_wall_clock-v1.prop","display_name":"Wall clock","depth":"near","position":{"x":-450.0,"y":-540.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"fireplace","type":"scenery_artwork","asset_id":"res://content/props/art_fireplace_mantel-v2.prop","display_name":"Fireplace","depth":"near","position":{"x":1280.0,"y":-126.5},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"bookshelf","type":"scenery_artwork","asset_id":"res://content/props/art_bookshelf-v1.prop","display_name":"Bookshelf","depth":"near","position":{"x":-930.0,"y":-311.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"picture","type":"scenery_artwork","asset_id":"res://content/props/art_framed_picture-v1.prop","display_name":"Framed picture","depth":"near","position":{"x":1000.0,"y":-530.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"ground_wood_left_12","type":"terrain","asset_id":"ground","position":{"x":-2304.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_11","type":"terrain","asset_id":"ground","position":{"x":-2112.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_10","type":"terrain","asset_id":"ground","position":{"x":-1920.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_09","type":"terrain","asset_id":"ground","position":{"x":-1728.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_08","type":"terrain","asset_id":"ground","position":{"x":-1536.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_07","type":"terrain","asset_id":"ground","position":{"x":-1344.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_06","type":"terrain","asset_id":"ground","position":{"x":-1152.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_05","type":"terrain","asset_id":"ground","position":{"x":-960.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_04","type":"terrain","asset_id":"ground","position":{"x":-768.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_03","type":"terrain","asset_id":"ground","position":{"x":-576.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_02","type":"terrain","asset_id":"ground","position":{"x":-384.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_left_01","type":"terrain","asset_id":"ground","position":{"x":-192.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood","type":"terrain","asset_id":"ground","position":{"x":0.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_01","type":"terrain","asset_id":"ground","position":{"x":192.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_02","type":"terrain","asset_id":"ground","position":{"x":384.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_03","type":"terrain","asset_id":"ground","position":{"x":576.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_04","type":"terrain","asset_id":"ground","position":{"x":768.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_05","type":"terrain","asset_id":"ground","position":{"x":960.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_06","type":"terrain","asset_id":"ground","position":{"x":1152.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_07","type":"terrain","asset_id":"ground","position":{"x":1344.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_08","type":"terrain","asset_id":"ground","position":{"x":1536.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_09","type":"terrain","asset_id":"ground","position":{"x":1728.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_10","type":"terrain","asset_id":"ground","position":{"x":1920.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_11","type":"terrain","asset_id":"ground","position":{"x":2112.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"ground_wood_right_12","type":"terrain","asset_id":"ground","position":{"x":2304.0,"y":200.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_wood"},
|
||||
{"file_id":"rug","type":"scenery_artwork","asset_id":"res://content/props/art_rug-v1.prop","display_name":"Floor rug","depth":"floor","position":{"x":0.0,"y":87.2},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"plant","type":"scenery_artwork","asset_id":"res://content/props/art_potted_plant-v1.prop","display_name":"Potted plant","depth":"floor","position":{"x":1715.0,"y":75.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"couch","type":"prop","asset_id":"res://content/props/prop_couch-v1.prop","position":{"x":-690.0,"y":-85.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"stage_object_id":"starter_couch","roles":{"depth":"behind","start_motion":"still","holds_other_props":false,"blocks_stickmen":true,"can_pick_up":false,"released_blocks_stickmen":true,"released_bumps_other_props":true,"legacy_draw_order":false},"use_spots":[],"next_use_spot_number":1,"wobble_on_impact":false,"material_preset":"WOOD"},
|
||||
{"file_id":"armchair","type":"prop","asset_id":"res://content/props/prop_armchair-v1.prop","position":{"x":620.0,"y":-104.4},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"stage_object_id":"starter_armchair","roles":{"depth":"behind","start_motion":"still","holds_other_props":false,"blocks_stickmen":true,"can_pick_up":false,"released_blocks_stickmen":true,"released_bumps_other_props":true,"legacy_draw_order":false},"use_spots":[],"next_use_spot_number":1,"wobble_on_impact":false,"material_preset":"WOOD"},
|
||||
{"file_id":"coffee_table","type":"prop","asset_id":"res://content/props/prop_coffee_table-v1.prop","position":{"x":-515.0,"y":64.3},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"stage_object_id":"starter_coffee_table","roles":{"depth":"front","start_motion":"still","holds_other_props":true,"blocks_stickmen":true,"can_pick_up":false,"released_blocks_stickmen":true,"released_bumps_other_props":true,"legacy_draw_order":false},"use_spots":[],"next_use_spot_number":1,"wobble_on_impact":false,"material_preset":"WOOD"}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {"created_unix": 1792022400, "modified_unix": 1792022400, "autosave": false, "source_path": ""}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "1.7",
|
||||
"scene_name": "Plain Background",
|
||||
"sky_id": "sky_neutral",
|
||||
"background_kind": "plain",
|
||||
"plain_color": "#F5EFE0",
|
||||
"camera": {"position": {"x": 0.0, "y": -400.0}, "zoom": 0.5},
|
||||
"objects": [],
|
||||
"event_rules": [],
|
||||
"metadata": {"created_unix": 1792022400, "modified_unix": 1792022400, "autosave": false, "source_path": ""}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"version": "1.6",
|
||||
"scene_name": "Town Street",
|
||||
"sky_id": "sky_cloudy_day",
|
||||
"camera": {"position": {"x": 0.0, "y": -1200.0}, "zoom": 0.16},
|
||||
"objects": [
|
||||
{"file_id":"town_landscape_ground","type":"background_ground","position":{"x":0.0,"y":660.0},"size":{"x":8400.0,"y":2000.0},"finish_id":"finish_background_grass","color":"#72A84C"},
|
||||
{"file_id":"scenery_skyline_left_outer","type":"scenery_artwork","asset_id":"res://content/props/art_city_skyline-v1.prop","display_name":"City skyline","depth":"far","position":{"x":-3700.0,"y":-604.918},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"scenery_skyline_left","type":"scenery_artwork","asset_id":"res://content/props/art_city_skyline-v1.prop","display_name":"City skyline","depth":"far","position":{"x":-1850.0,"y":-604.918},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"scenery_skyline","type":"scenery_artwork","asset_id":"res://content/props/art_city_skyline-v1.prop","display_name":"City skyline","depth":"far","position":{"x":0.0,"y":-604.918},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"scenery_skyline_right","type":"scenery_artwork","asset_id":"res://content/props/art_city_skyline-v1.prop","display_name":"City skyline","depth":"far","position":{"x":1850.0,"y":-604.918},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"scenery_skyline_right_outer","type":"scenery_artwork","asset_id":"res://content/props/art_city_skyline-v1.prop","display_name":"City skyline","depth":"far","position":{"x":3700.0,"y":-604.918},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"scenery_tree_left","type":"scenery_artwork","asset_id":"res://content/props/art_tree-v2.prop","display_name":"Tree","depth":"near","position":{"x":-2600.0,"y":-1271.498},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"scenery_town_house","type":"scenery_artwork","asset_id":"res://content/props/art_town_house-v1.prop","display_name":"Town house","depth":"near","position":{"x":-1400.0,"y":-1361.835},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"scenery_storefront","type":"scenery_artwork","asset_id":"res://content/props/art_storefront-v1.prop","display_name":"Storefront","depth":"near","position":{"x":1400.0,"y":-813.77},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"scenery_tree_right","type":"scenery_artwork","asset_id":"res://content/props/art_tree-v2.prop","display_name":"Tree","depth":"near","position":{"x":2600.0,"y":-1271.498},"rotation":0.0,"scale":{"x":1.0,"y":1.0}},
|
||||
{"file_id":"ground_sidewalk_left_12","type":"terrain","asset_id":"ground","position":{"x":-2304.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_11","type":"terrain","asset_id":"ground","position":{"x":-2112.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_10","type":"terrain","asset_id":"ground","position":{"x":-1920.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_09","type":"terrain","asset_id":"ground","position":{"x":-1728.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_08","type":"terrain","asset_id":"ground","position":{"x":-1536.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_07","type":"terrain","asset_id":"ground","position":{"x":-1344.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_06","type":"terrain","asset_id":"ground","position":{"x":-1152.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_05","type":"terrain","asset_id":"ground","position":{"x":-960.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_04","type":"terrain","asset_id":"ground","position":{"x":-768.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_03","type":"terrain","asset_id":"ground","position":{"x":-576.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_02","type":"terrain","asset_id":"ground","position":{"x":-384.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_01","type":"terrain","asset_id":"ground","position":{"x":-192.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk","type":"terrain","asset_id":"ground","position":{"x":0.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_01","type":"terrain","asset_id":"ground","position":{"x":192.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_02","type":"terrain","asset_id":"ground","position":{"x":384.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_03","type":"terrain","asset_id":"ground","position":{"x":576.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_04","type":"terrain","asset_id":"ground","position":{"x":768.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_05","type":"terrain","asset_id":"ground","position":{"x":960.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_06","type":"terrain","asset_id":"ground","position":{"x":1152.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_07","type":"terrain","asset_id":"ground","position":{"x":1344.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_08","type":"terrain","asset_id":"ground","position":{"x":1536.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_09","type":"terrain","asset_id":"ground","position":{"x":1728.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_10","type":"terrain","asset_id":"ground","position":{"x":1920.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_11","type":"terrain","asset_id":"ground","position":{"x":2112.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_12","type":"terrain","asset_id":"ground","position":{"x":2304.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_13","type":"terrain","asset_id":"ground","position":{"x":-2496.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_14","type":"terrain","asset_id":"ground","position":{"x":-2688.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_15","type":"terrain","asset_id":"ground","position":{"x":-2880.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_16","type":"terrain","asset_id":"ground","position":{"x":-3072.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_17","type":"terrain","asset_id":"ground","position":{"x":-3264.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_18","type":"terrain","asset_id":"ground","position":{"x":-3456.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_19","type":"terrain","asset_id":"ground","position":{"x":-3648.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_left_20","type":"terrain","asset_id":"ground","position":{"x":-3840.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_13","type":"terrain","asset_id":"ground","position":{"x":2496.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_14","type":"terrain","asset_id":"ground","position":{"x":2688.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_15","type":"terrain","asset_id":"ground","position":{"x":2880.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_16","type":"terrain","asset_id":"ground","position":{"x":3072.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_17","type":"terrain","asset_id":"ground","position":{"x":3264.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_18","type":"terrain","asset_id":"ground","position":{"x":3456.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_19","type":"terrain","asset_id":"ground","position":{"x":3648.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_sidewalk_right_20","type":"terrain","asset_id":"ground","position":{"x":3840.0,"y":0.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_sidewalk"},
|
||||
{"file_id":"ground_asphalt_left_12","type":"terrain","asset_id":"ground","position":{"x":-2304.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_11","type":"terrain","asset_id":"ground","position":{"x":-2112.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_10","type":"terrain","asset_id":"ground","position":{"x":-1920.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_09","type":"terrain","asset_id":"ground","position":{"x":-1728.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_08","type":"terrain","asset_id":"ground","position":{"x":-1536.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_07","type":"terrain","asset_id":"ground","position":{"x":-1344.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_06","type":"terrain","asset_id":"ground","position":{"x":-1152.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_05","type":"terrain","asset_id":"ground","position":{"x":-960.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_04","type":"terrain","asset_id":"ground","position":{"x":-768.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_03","type":"terrain","asset_id":"ground","position":{"x":-576.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_02","type":"terrain","asset_id":"ground","position":{"x":-384.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_01","type":"terrain","asset_id":"ground","position":{"x":-192.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt","type":"terrain","asset_id":"ground","position":{"x":0.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_01","type":"terrain","asset_id":"ground","position":{"x":192.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_02","type":"terrain","asset_id":"ground","position":{"x":384.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_03","type":"terrain","asset_id":"ground","position":{"x":576.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_04","type":"terrain","asset_id":"ground","position":{"x":768.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_05","type":"terrain","asset_id":"ground","position":{"x":960.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_06","type":"terrain","asset_id":"ground","position":{"x":1152.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_07","type":"terrain","asset_id":"ground","position":{"x":1344.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_08","type":"terrain","asset_id":"ground","position":{"x":1536.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_09","type":"terrain","asset_id":"ground","position":{"x":1728.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_10","type":"terrain","asset_id":"ground","position":{"x":1920.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_11","type":"terrain","asset_id":"ground","position":{"x":2112.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_12","type":"terrain","asset_id":"ground","position":{"x":2304.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_extension","type":"terrain","asset_id":"ground","position":{"x":-2496.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_extension","type":"terrain","asset_id":"ground","position":{"x":2496.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_14","type":"terrain","asset_id":"ground","position":{"x":-2688.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_15","type":"terrain","asset_id":"ground","position":{"x":-2880.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_16","type":"terrain","asset_id":"ground","position":{"x":-3072.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_17","type":"terrain","asset_id":"ground","position":{"x":-3264.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_18","type":"terrain","asset_id":"ground","position":{"x":-3456.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_19","type":"terrain","asset_id":"ground","position":{"x":-3648.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_left_20","type":"terrain","asset_id":"ground","position":{"x":-3840.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_14","type":"terrain","asset_id":"ground","position":{"x":2688.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_15","type":"terrain","asset_id":"ground","position":{"x":2880.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_16","type":"terrain","asset_id":"ground","position":{"x":3072.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_17","type":"terrain","asset_id":"ground","position":{"x":3264.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_18","type":"terrain","asset_id":"ground","position":{"x":3456.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_19","type":"terrain","asset_id":"ground","position":{"x":3648.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"},
|
||||
{"file_id":"ground_asphalt_right_20","type":"terrain","asset_id":"ground","position":{"x":3840.0,"y":32.0},"rotation":0.0,"scale":{"x":1.0,"y":1.0},"finish_id":"finish_ground_asphalt"}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {"created_unix": 1792022400, "modified_unix": 1792022400, "autosave": false, "source_path": ""}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
# Patterned scenery rendering
|
||||
|
||||
A patterned wall or background uses one small repeating image for each finish and tint. The camera samples that same image wherever the surface appears. A pan or zoom changes the visible rectangle and sampling scale; it does not create a new image for each camera position.
|
||||
|
||||

|
||||
|
||||
## Render pipeline
|
||||
|
||||
1. A visible, committed patterned surface requests its style from the scene's `StageSurfaceBakePool`.
|
||||
2. The cache checks the style key. A ready entry is reused; a missing entry is queued for the shared baker.
|
||||
3. At most one queued style is baked per process frame. The baker draws a four-world-unit overscan around the material period so edge details can be cropped without gaps.
|
||||
4. After the submitted drawing reaches `frame_post_draw`, the pool captures the image, crops the period, generates mipmaps, and publishes an `ImageTexture`.
|
||||
5. The temporary vector commands are cleared. The surface draws one camera-clipped quad using the shared image, repeat sampling, and mipmapped filtering.
|
||||
|
||||
The GPU still renders the textured rectangle every frame. When the view changes, the CPU also updates that rectangle and its texture coordinates. This is a small drawing command; it does not rebuild brick faces, grain, pores, or other vector details. The cache counters distinguish image builds and readbacks from ordinary redraws.
|
||||
|
||||
## Shared style images
|
||||
|
||||
The cache is owned by a scene-scoped pool. Its key includes finish, tint, wall/background kind, material version, repeat period, pixel density, and mipmap configuration. It excludes surface position, camera position, zoom, rectangle size, and erase fragment. Thus same-style surfaces and fragments share one image, while a tint change correctly requests a different image.
|
||||
|
||||

|
||||
|
||||
The current periods are finite, seamless repeat units baked at two bitmap pixels per world unit:
|
||||
|
||||
| Finish | Repeat period in world units | Bitmap size |
|
||||
| --- | ---: | ---: |
|
||||
| Brick | 800 × 304 | 1600 × 608 |
|
||||
| Wood | 960 × 384 | 1920 × 768 |
|
||||
| Grass | 704 × 576 | 1408 × 1152 |
|
||||
| Carpet | 544 × 416 | 1088 × 832 |
|
||||
| Concrete | 1120 × 760 | 2240 × 1520 |
|
||||
|
||||
For example, a 100-world-unit brick remains 100 world units wide. At 0.4× zoom it covers about 40 screen pixels; zoom changes how the GPU samples the image, not the brick geometry. The finite repeat unit makes detail bounded, so landmarks can become noticeable on very large surfaces.
|
||||
|
||||
## Zoom and mipmaps
|
||||
|
||||
The renderer captures the material once at fixed density, then builds smaller mip levels from that image. During zoom-out the GPU samples a smaller level to reduce shimmer; during zoom-in it samples a larger level. This replaces separately drawing the material at several CPU-selected zoom levels. At the Stage's maximum 6× zoom, the source image is magnified three times and can look softer. The current quality/performance tradeoff is fixed in the cache configuration.
|
||||
|
||||

|
||||
|
||||
## Erasing and pattern alignment
|
||||
|
||||
The eraser still cuts a rectangle into up to four rectangular fragments. Each fragment draws only its own bounds, but requests the same style image; it does not bake a fragment-specific copy. Cancel restores the original geometry, and Commit retains the new fragments. Both use the existing material sampling rules.
|
||||
|
||||
The sampling origin is significant: walls use `global_position`; background ground uses `global_position + motif_origin_offset`. Each surface computes its source UV from its local visible position plus that draw origin, wrapped by the material period. This preserves the current alignment convention across cuts. Avoid changing the origin rule as a generic transform correction: unusual transformed fragments need separate verification before making a broader alignment claim.
|
||||
|
||||

|
||||
|
||||
## Memory and rebuild boundaries
|
||||
|
||||
The scene cache has a 64 MiB resident texture budget. Accounting includes mip levels, textures waiting for safe retirement, and reserved space for a capture. Unused entries are evicted by least-recent use when needed. A style held by active surfaces can prevent admission of another style; the pool reports this as budget pressure rather than exceeding the cap. Under ordinary use, returning to a recently used style should reuse its warm image. Many tint variants can force eviction and a later rebuild.
|
||||
|
||||
A style's first capture still costs CPU/GPU work and can briefly affect a frame. Once ready, moving the camera across a large wall does not enqueue position tiles or read back new images. The shared baker also clears its vector command list after capture, preventing the native drawing resources that previously accumulated in many per-tile viewports.
|
||||
|
||||
These images are temporary runtime data. A saved `.scene` keeps surface settings and geometry; the cache recreates its images when needed in a new Stage session. Closing the scene releases its pool.
|
||||
|
||||
## What causes another bake?
|
||||
|
||||
| Action | New image work? |
|
||||
| --- | --- |
|
||||
| Pan left, then return right | No, while the style remains cached. |
|
||||
| Zoom in or out | No. The GPU samples existing mipmaps. |
|
||||
| Resize a wall | No. Change the rectangle and texture coordinates. |
|
||||
| Erase, Cancel, or Commit | No, if the style is ready. Change geometry and clipping. |
|
||||
| Use the same finish and tint on another wall | No, if the style is ready. Share its image. |
|
||||
| Choose a new finish or tint | Bake once if that style is missing. |
|
||||
| Return to an evicted style, or open a fresh session | Recreate the missing image. |
|
||||
|
||||
## Terms used here
|
||||
|
||||
- **Bake:** render the vector artwork once to make an image.
|
||||
- **Texture:** the image the GPU samples when drawing.
|
||||
- **Quad:** one rectangle, represented by two triangles.
|
||||
- **UVs:** coordinates that select which part of a texture to sample.
|
||||
- **Mipmaps:** smaller copies of an image, prepared in advance for zooming out.
|
||||
- **Readback:** copy the rendered image from the GPU so the cache can keep an independent texture.
|
||||
|
||||
## Scope and code map
|
||||
|
||||
The bitmap cache is for committed patterned walls and backgrounds in render-capable runs. Plain paint surfaces, interactive placement previews, and headless runs retain the direct renderer path. Fully opaque scenery can suppress a fully hidden surface's texture request; partial coverage remains conservative.
|
||||
|
||||
- [StageSurfaceCache](../../scripts/stage/scenery/stage_surface_cache.gd) owns style handles, the scene pool, bake queue, image capture, mipmaps, cache keys, and budget statistics.
|
||||
- [StageRectSurface](../../scripts/stage/scenery/stage_rect_surface.gd) requests the style, clips the surface to the visible camera area, and draws the repeated texture.
|
||||
- [StageSurfaceRenderer](../../scripts/stage/scenery/stage_surface_renderer.gd) defines patterned artwork, material periods, and the direct-drawing path.
|
||||
- [Repeating scenery material cache spec](../specs/scenery_bitmap_tile_cache.md) records implementation constraints and acceptance checks.
|
||||
|
||||
In one observed warm run of `fps.scene`, four style entries used 36,399,144 bytes (about 34.71 MiB); 720 warm camera frames recorded zero builds, readbacks, or evictions. This is a run snapshot, not a guarantee for other scenes, tint combinations, or hardware.
|
||||
@@ -0,0 +1,43 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="640" viewBox="0 0 1200 640" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Erasing changes rectangles while sharing the same background texture</title>
|
||||
<desc id="desc">A rectangular cut turns one wall into top, bottom, left and right fragments. All fragments sample the existing image using their pattern coordinates. The image itself is not painted over or copied.</desc>
|
||||
<defs>
|
||||
<pattern id="brick" width="80" height="48" patternUnits="userSpaceOnUse"><rect width="80" height="48" fill="#d2cbaf"/><rect x="2" y="2" width="36" height="19" fill="#25b8df"/><rect x="42" y="2" width="36" height="19" fill="#39c7ee"/><rect x="-18" y="26" width="36" height="19" fill="#32c2e8"/><rect x="22" y="26" width="36" height="19" fill="#21b4da"/><rect x="62" y="26" width="36" height="19" fill="#32c2e8"/></pattern>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto"><path d="M0 0L10 5L0 10Z" fill="#475569"/></marker>
|
||||
<style>text{font-family:Segoe UI,Arial,sans-serif;fill:#172033}.title{font-size:30px;font-weight:700}.heading{font-size:22px;font-weight:700}.body{font-size:18px}.small{font-size:16px}.arrow{fill:none;stroke:#475569;stroke-width:3;marker-end:url(#arrow)}</style>
|
||||
</defs>
|
||||
<rect width="1200" height="640" rx="16" fill="#f8fafc"/>
|
||||
<text x="40" y="53" class="title">Erase the wall geometry. Keep the shared image.</text>
|
||||
<text x="40" y="86" class="body">Fragments crop their own rectangles and use the existing pattern coordinates.</text>
|
||||
<text x="50" y="136" class="heading">Before: one wall rectangle</text>
|
||||
<g transform="translate(50 160)">
|
||||
<rect width="460" height="300" fill="url(#brick)" stroke="#94a3b8" stroke-width="2"/>
|
||||
<rect x="155" y="90" width="150" height="120" fill="#fff" fill-opacity=".3" stroke="#b45309" stroke-width="4" stroke-dasharray="10 6"/>
|
||||
<rect x="174" y="131" width="112" height="36" rx="6" fill="#fff7ed"/>
|
||||
<text x="230" y="155" class="body" text-anchor="middle">Cut here</text>
|
||||
</g>
|
||||
<path d="M532 310H648" class="arrow"/>
|
||||
<text x="590" y="283" class="small" text-anchor="middle">Erase area</text>
|
||||
|
||||
<text x="680" y="136" class="heading">After: up to four fragments</text>
|
||||
<g transform="translate(680 160)">
|
||||
<rect width="460" height="300" fill="#dbeafe"/>
|
||||
<g fill="url(#brick)" stroke="#0f766e" stroke-width="3">
|
||||
<rect width="460" height="90"/>
|
||||
<rect x="0" y="210" width="460" height="90"/>
|
||||
<rect x="0" y="90" width="155" height="120"/>
|
||||
<rect x="305" y="90" width="155" height="120"/>
|
||||
</g>
|
||||
<g fill="#fff"><rect x="195" y="26" width="70" height="36" rx="6"/><rect x="182" y="242" width="96" height="36" rx="6"/><rect x="43" y="131" width="70" height="36" rx="6"/><rect x="342" y="131" width="78" height="36" rx="6"/></g>
|
||||
<text x="230" y="51" class="body" text-anchor="middle">Top</text>
|
||||
<text x="230" y="267" class="body" text-anchor="middle">Bottom</text>
|
||||
<text x="78" y="155" class="body" text-anchor="middle">Left</text>
|
||||
<text x="381" y="155" class="body" text-anchor="middle">Right</text>
|
||||
<text x="230" y="143" class="body" text-anchor="middle">Empty area</text>
|
||||
<text x="230" y="173" class="small" text-anchor="middle">Scene behind</text>
|
||||
</g>
|
||||
|
||||
<rect x="40" y="510" width="1120" height="95" rx="12" fill="#eff6ff" stroke="#2563eb" stroke-width="2"/>
|
||||
<text x="62" y="546" class="heading">All remaining pieces still use the same cached texture.</text>
|
||||
<text x="62" y="580" class="body">Cancel restores the original geometry. Commit keeps the fragments. Neither paints into the image.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,39 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1200" height="630" viewBox="0 0 1200 630" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Zoom uses smaller copies already stored in the material texture</title>
|
||||
<desc id="desc">The brick material starts at 1600 by 608 bitmap pixels. Its mip chain includes 800 by 304, 400 by 152 and 200 by 76, continuing down to one pixel. These copies are prepared once. Brick world dimensions stay fixed.</desc>
|
||||
<defs>
|
||||
<pattern id="brick" width="100" height="38" patternUnits="userSpaceOnUse"><rect width="100" height="38" fill="#d2cbaf"/><rect x="2" y="2" width="46" height="15" fill="#26b8df"/><rect x="52" y="2" width="46" height="15" fill="#39c7ee"/><rect x="-23" y="21" width="46" height="15" fill="#32c2e8"/><rect x="27" y="21" width="46" height="15" fill="#21b4da"/><rect x="77" y="21" width="46" height="15" fill="#32c2e8"/></pattern>
|
||||
<pattern id="half" xlink:href="#brick" patternTransform="scale(.5)"/>
|
||||
<pattern id="quarter" xlink:href="#brick" patternTransform="scale(.25)"/>
|
||||
<pattern id="eighth" xlink:href="#brick" patternTransform="scale(.125)"/>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto"><path d="M0 0L10 5L0 10Z" fill="#7c3aed"/></marker>
|
||||
<style>text{font-family:Segoe UI,Arial,sans-serif;fill:#172033}.title{font-size:30px;font-weight:700}.heading{font-size:22px;font-weight:700}.body{font-size:18px}.small{font-size:16px}.arrow{fill:none;stroke:#7c3aed;stroke-width:3;marker-end:url(#arrow)}</style>
|
||||
</defs>
|
||||
<rect width="1200" height="630" rx="16" fill="#f8fafc"/>
|
||||
<text x="40" y="53" class="title">Zoom samples ready-made sizes of the same image.</text>
|
||||
<text x="40" y="86" class="body">Mipmaps are generated once with the material. The GPU selects and blends them during rendering.</text>
|
||||
|
||||
<rect x="60" y="150" width="400" height="152" fill="url(#brick)" stroke="#94a3b8"/>
|
||||
<path d="M471 228H508" class="arrow"/>
|
||||
<rect x="530" y="188" width="200" height="76" fill="url(#half)" stroke="#94a3b8"/>
|
||||
<path d="M741 228H778" class="arrow"/>
|
||||
<rect x="800" y="207" width="100" height="38" fill="url(#quarter)" stroke="#94a3b8"/>
|
||||
<path d="M911 228H948" class="arrow"/>
|
||||
<rect x="970" y="217" width="50" height="19" fill="url(#eighth)" stroke="#94a3b8"/>
|
||||
<text x="1043" y="234" class="heading">…</text>
|
||||
|
||||
<text x="260" y="342" class="heading" text-anchor="middle">1600 × 608</text>
|
||||
<text x="260" y="373" class="small" text-anchor="middle">Base image: 2 pixels / world unit</text>
|
||||
<text x="630" y="342" class="heading" text-anchor="middle">800 × 304</text>
|
||||
<text x="630" y="373" class="small" text-anchor="middle">Half size</text>
|
||||
<text x="850" y="342" class="heading" text-anchor="middle">400 × 152</text>
|
||||
<text x="850" y="373" class="small" text-anchor="middle">Quarter size</text>
|
||||
<text x="1000" y="342" class="heading" text-anchor="middle">200 × 76</text>
|
||||
<text x="1000" y="373" class="small" text-anchor="middle">Eighth size</text>
|
||||
<text x="60" y="414" class="small">The actual chain continues down to 1 × 1. Diagram sizes are scaled for illustration.</text>
|
||||
|
||||
<rect x="40" y="450" width="1120" height="143" rx="12" fill="#ecfdf5" stroke="#0f766e" stroke-width="2"/>
|
||||
<text x="62" y="486" class="heading">World size, image size and screen size are different things.</text>
|
||||
<text x="62" y="521" class="body">A brick stays 100 world units wide. At 40% zoom, it covers about 40 screen pixels.</text>
|
||||
<text x="62" y="556" class="body">Camera zoom changes sampling detail; it does not bake another image or resize the brick geometry.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,51 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="640" viewBox="0 0 1200 640" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Background rendering: prepare a style once, reuse it while moving the camera</title>
|
||||
<desc id="desc">A visible surface requests its finish and tint from the scene cache. A cache hit goes directly to the GPU repeat sampler. A cache miss uses one temporary baker, captures an image and mipmaps, and releases vector commands.</desc>
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto"><path d="M0 0L10 5L0 10Z" fill="#475569"/></marker>
|
||||
<style>text{font-family:Segoe UI,Arial,sans-serif;fill:#172033}.title{font-size:30px;font-weight:700}.heading{font-size:22px;font-weight:700}.body{font-size:18px}.small{font-size:16px}.arrow{fill:none;stroke:#475569;stroke-width:3;marker-end:url(#arrow)}</style>
|
||||
</defs>
|
||||
<rect width="1200" height="640" rx="16" fill="#f8fafc"/>
|
||||
<text x="40" y="53" class="title">Prepare a material once. Reuse it as the camera moves.</text>
|
||||
<text x="40" y="86" class="body">Only visible, committed patterned scenery requests a cached material.</text>
|
||||
|
||||
<rect x="40" y="140" width="250" height="126" rx="12" fill="#eff6ff" stroke="#2563eb" stroke-width="2"/>
|
||||
<text x="60" y="177" class="heading">Visible surface</text>
|
||||
<text x="60" y="210" class="body">Finish + tint</text>
|
||||
<text x="60" y="239" class="small">Example: blue brick</text>
|
||||
<path d="M292 203H370" class="arrow"/>
|
||||
|
||||
<rect x="390" y="140" width="260" height="126" rx="12" fill="#eff6ff" stroke="#2563eb" stroke-width="2"/>
|
||||
<text x="410" y="177" class="heading">Scene style cache</text>
|
||||
<text x="410" y="210" class="body">Already have this image?</text>
|
||||
<text x="410" y="239" class="small">Shared by all matching surfaces</text>
|
||||
<path d="M652 203H740" class="arrow"/>
|
||||
<text x="674" y="182" class="small">Hit</text>
|
||||
|
||||
<rect x="760" y="140" width="400" height="126" rx="12" fill="#ecfdf5" stroke="#0f766e" stroke-width="2"/>
|
||||
<text x="782" y="177" class="heading">GPU draws the visible rectangle</text>
|
||||
<text x="782" y="210" class="body">Repeat texture + sample its mipmaps</text>
|
||||
<text x="782" y="239" class="small">Pan / zoom updates sampling coordinates</text>
|
||||
|
||||
<path d="M520 268V324" class="arrow"/>
|
||||
<text x="540" y="304" class="small">Miss: prepare this style</text>
|
||||
<rect x="390" y="344" width="260" height="158" rx="12" fill="#f5f3ff" stroke="#7c3aed" stroke-width="2"/>
|
||||
<text x="410" y="379" class="heading">One temporary baker</text>
|
||||
<text x="410" y="412" class="body">Draw one pattern period</text>
|
||||
<text x="410" y="441" class="body">Wait for GPU; capture image</text>
|
||||
<text x="410" y="476" class="small">Then clear vector commands</text>
|
||||
<path d="M652 423H740" class="arrow"/>
|
||||
|
||||
<rect x="760" y="344" width="400" height="158" rx="12" fill="#f5f3ff" stroke="#7c3aed" stroke-width="2"/>
|
||||
<text x="782" y="379" class="heading">Store the reusable texture</text>
|
||||
<text x="782" y="412" class="body">Crop overscan; generate mipmaps</text>
|
||||
<text x="782" y="441" class="body">Keep the image, not the vector artwork</text>
|
||||
<text x="782" y="476" class="small">Ready styles stay warm within the cache budget</text>
|
||||
<path d="M960 342V282" class="arrow"/>
|
||||
<text x="980" y="309" class="small">Ready</text>
|
||||
|
||||
<rect x="40" y="548" width="540" height="56" rx="10" fill="#dbeafe"/>
|
||||
<text x="59" y="582" class="body">Blue route: reuse during ordinary pan and zoom</text>
|
||||
<rect x="604" y="548" width="556" height="56" rx="10" fill="#ede9fe"/>
|
||||
<text x="623" y="582" class="body">Purple route: bake only when a style is missing</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,44 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="650" viewBox="0 0 1200 650" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Many wall rectangles share one material image</title>
|
||||
<desc id="desc">One blue-brick image supplies Wall A, Wall B, and an erased fragment. Different sizes, positions, and camera views do not create more images. A different tint or finish is a different cached style.</desc>
|
||||
<defs>
|
||||
<pattern id="brick" width="64" height="40" patternUnits="userSpaceOnUse">
|
||||
<rect width="64" height="40" fill="#d2cbaf"/>
|
||||
<g><rect x="2" y="2" width="28" height="15" fill="#25b8df"/><rect x="34" y="2" width="28" height="15" fill="#39c7ee"/><rect x="-14" y="22" width="28" height="15" fill="#32c2e8"/><rect x="18" y="22" width="28" height="15" fill="#21b4da"/><rect x="50" y="22" width="28" height="15" fill="#32c2e8"/></g>
|
||||
</pattern>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto"><path d="M0 0L10 5L0 10Z" fill="#2563eb"/></marker>
|
||||
<style>text{font-family:Segoe UI,Arial,sans-serif;fill:#172033}.title{font-size:30px;font-weight:700}.heading{font-size:22px;font-weight:700}.body{font-size:18px}.small{font-size:16px}.arrow{fill:none;stroke:#2563eb;stroke-width:3;marker-end:url(#arrow)}</style>
|
||||
</defs>
|
||||
<rect width="1200" height="650" rx="16" fill="#f8fafc"/>
|
||||
<text x="40" y="53" class="title">Wall area can grow. The number of style images stays the same.</text>
|
||||
<text x="40" y="86" class="body">Position, wall size, camera position and zoom are not part of the style key.</text>
|
||||
|
||||
<rect x="400" y="117" width="400" height="163" rx="12" fill="#eff6ff" stroke="#2563eb" stroke-width="2"/>
|
||||
<rect x="420" y="140" width="160" height="112" fill="url(#brick)" stroke="#94a3b8"/>
|
||||
<text x="602" y="162" class="heading">One shared image</text>
|
||||
<text x="602" y="194" class="body">Blue brick</text>
|
||||
<text x="602" y="224" class="small">Varied brick faces</text>
|
||||
<text x="602" y="250" class="small">Repeats both ways</text>
|
||||
<path d="M600 282V311H210V341" class="arrow"/>
|
||||
<path d="M600 311V341" class="arrow"/>
|
||||
<path d="M600 311H990V341" class="arrow"/>
|
||||
|
||||
<rect x="40" y="360" width="340" height="192" rx="12" fill="#fff" stroke="#cbd5e1" stroke-width="2"/>
|
||||
<text x="62" y="396" class="heading">Wall A</text>
|
||||
<rect x="62" y="416" width="296" height="103" fill="url(#brick)"/>
|
||||
|
||||
<rect x="430" y="360" width="340" height="192" rx="12" fill="#fff" stroke="#cbd5e1" stroke-width="2"/>
|
||||
<text x="452" y="396" class="heading">Wall B</text>
|
||||
<rect x="452" y="416" width="190" height="103" fill="url(#brick)"/>
|
||||
<text x="659" y="455" class="small">Same</text>
|
||||
<text x="659" y="480" class="small">style</text>
|
||||
|
||||
<rect x="820" y="360" width="340" height="192" rx="12" fill="#fff" stroke="#cbd5e1" stroke-width="2"/>
|
||||
<text x="842" y="396" class="heading">Erased fragment</text>
|
||||
<rect x="842" y="416" width="90" height="103" fill="url(#brick)"/>
|
||||
<text x="952" y="455" class="small">Only the visible</text>
|
||||
<text x="952" y="480" class="small">rectangle changes</text>
|
||||
|
||||
<text x="40" y="591" class="body">A different finish or tint is a separate style. A matching warm style reuses the existing image.</text>
|
||||
<text x="40" y="621" class="small" fill="#64748b">Patterns shown here are schematic; the actual brick image contains 8 columns × 8 rows of varied artwork.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,42 @@
|
||||
# Scenery surface caching
|
||||
|
||||
`StageRectSurface` renders committed patterned scenery through reusable texture tiles.
|
||||
Drawing previews use the adaptive lightweight renderer. Paint remains a single rectangle.
|
||||
|
||||
## Camera movement
|
||||
|
||||
Tiles use a fixed grid in the surface's local coordinates. Texture resolution changes in
|
||||
powers of two, so adjacent wheel steps reuse existing tiles. Panning requests only newly
|
||||
exposed tiles. Existing textures stay visible while missing tiles are prepared, with a
|
||||
lightweight surface motif beneath them to prevent blank areas.
|
||||
|
||||
`StageSurfaceCache` keeps queued tiles as metadata. A shared queue creates and renders at
|
||||
most one tile per process frame across all surfaces. It also retires at most two obsolete
|
||||
render targets per frame. This avoids large allocations, vector rebuilds, and batches of
|
||||
GPU resource releases during camera input.
|
||||
|
||||
Each tile has a 256 × 128 pixel core and a four pixel gutter. The gutter is cropped during
|
||||
compositing to prevent seams. Each surface requests at most 192 visible tiles and retains
|
||||
at most 224 tiles, evicting older unused entries. Half-resolution tiles retain full brick
|
||||
texture and wood grain. Only quarter-resolution tiles and below omit fine texture, for
|
||||
distant views. Brick and plank positions remain fixed. Detail can fill in progressively
|
||||
after movement, including when returning from a distant view to a normal zoom level.
|
||||
|
||||
## Invalidation and coverage
|
||||
|
||||
Geometry, finish, tint, and motif-origin changes invalidate that surface's tiles. Camera
|
||||
movement selects tiles without invalidating their artwork. Render targets belong to the
|
||||
surface node; queued references are weak so deleted surfaces cannot keep jobs alive.
|
||||
|
||||
Fully opaque rectangular sibling surfaces can suppress artwork entirely hidden behind
|
||||
them. Coverage checks account for transforms, draw order, and visibility. Transparent
|
||||
surfaces, custom materials, differing relative-Z conventions, and Y-sorted parents disable
|
||||
this optimization conservatively. Revealing a surface resumes its pending tiles.
|
||||
|
||||
## Verification
|
||||
|
||||
`tests/test_scenery_surface_cache.gd` checks rendered appearance against the direct vector
|
||||
renderer, tile reuse and invalidation, the shared build limit, allocation and retention
|
||||
bounds, and covered-surface behavior. Run it with a graphical Godot renderer for pixel
|
||||
comparisons. The adaptive preview regressions remain in
|
||||
`tests/test_scenery_surface_preview.gd` and `tests/test_scenery_brick_preview.gd`.
|
||||
@@ -81,6 +81,16 @@ This document tracks known technical debt, optimization opportunities, and minor
|
||||
| 69 | **Contact entry alone can miss a stickman hitting a fixed prop** — grounded locomotion stops at a shape-sweep safe fraction, sometimes before `body_entered` fires; resting contacts can also chatter after pause or quick separation. | Medium | Implemented; user-verified; automated result undocumented | Phase 17c routes identified blocking-prop sweep hits and actual body contacts through one relative approach-speed scorer and pair gate. Multiple stickman limbs collapse into one rig/prop pair; separation/rearm and cooldown gates suppress repeat hits. The user has verified Phase 17c; no automated behavior verification result is documented. Keep existing collision-rule dispatch independent. See `docs/specs/phase_17c_impact_wobble.md`. (2026-10-14) |
|
||||
| 70 | **Impact strength is initially speed based while prop mass is preset based** — material presets set `RigidBody2D.mass`, but fixed props are frozen and mass is not a child-facing setting. | Low | Implemented; future design | Phase 17c keeps the Wobble boolean and visual-only response independent of mass. Impact scoring is centralized in `StageImpactResolver` so a future editable-mass or impulse design can be evaluated without altering the Stage switch or migrating old scene choices. Do not infer a physical impulse from a frozen prop's preset mass; verify any future mass effect separately. See `docs/specs/phase_17c_impact_wobble.md`. (2026-10-14) |
|
||||
| 71 | **Palette art is supplied at much higher resolution than its display size** — six 1254 × 1254 PNGs appear in 64 × 64 card image areas. | Low | ✅ Resolved | Phase 18 is implemented and user-verified. The original source PNGs remain 1254 × 1254, Godot imports are capped at 256 px, and `StageChrome` maps the six images by placement ID. The focused palette suite passed; the headless Sandbox Stage loaded, and `git diff --check` passed. Keep the map local to the fixed Stage palette; revisit a data-driven icon descriptor only if tools or themed art become extensible. See `docs/specs/phase_18_palette_icons.md`. (2026-10-14) |
|
||||
| 72 | **Stage-wide Undo/Redo needs its own phase** — Phase 19 placement, erase, style, repair, selected-artwork depth, direct single-piece moves/resizes, and group Keep actions change the document without an integrated command history. | Medium | Deferred to separate phase | Design one Stage-level history with coherent commands across Scenery, Ground, Props, terrain, characters, scene naming, and directed content, with safe boundaries around PLAY/paused edits and save/recovery. The Phase 19 sizing amendment keeps single-piece gestures commit-on-release with cancellable active snapshots and retains group Keep/Cancel; neither is an Undo implementation or shortcut. Selected-artwork depth choices also commit immediately. User explicitly deferred Stage Undo/Redo to its own phase. See `docs/specs/phase_19_scenery_backgrounds_surface_finishes.md` and `docs/specs/phase_19_selected_artwork_depth_inspector.md`. (2026-10-17) |
|
||||
| 73 | **Whole-set transform requires cross-system invariants** — Phase 19's temporary group transform covers only inert Scenery pieces: wall panels, artwork, and the planned Background ground. | Medium | Future feature | Moving/scaling walkable Ground, characters, interactive Props, Sky, camera composition, waypoints, and rules together needs separate physics, navigation, event-target, and save contracts. Do not expand the Scenery group tool into a whole-set transform without that design. See `docs/specs/phase_19_scenery_backgrounds_surface_finishes.md` and `docs/specs/phase_19_background_ground_and_wall_color.md`. (2026-10-17) |
|
||||
| 74 | **Background surface motifs need a shared zoom-consistent draw budget** — a pattern detail scale derived from each panel's size can shift seams or texture density where adjacent pieces meet, while uncapped large rectangles can issue excessive draw calls. | Medium | Planned | Phase 19 follow-up uses world-cell coordinates, visible-region culling, and any level-of-detail choice derived from camera zoom for all pieces in the same view. Keep Grass/Concrete/Carpet detail deterministic and bounded; consider a texture cache only if measured scenes remain expensive. See `docs/specs/phase_19_background_ground_and_wall_color.md`. (2026-10-17) |
|
||||
| 75 | **Old Brick/Wood wall colors were saved but not rendered** — v1.5 walls can carry the old default green while their brick and wood palettes were hard-coded. | Low | Planned migration | Scene v1.6 migration replaces only the old green placeholder on pre-v1.6 Brick/Wood entries with natural finish defaults; Paint and non-placeholder colors remain. The exact placeholder could have been intentionally authored in an older file, which cannot be distinguished retrospectively. New v1.6 colors are authoritative, including green Brick/Wood. See `docs/specs/phase_19_background_ground_and_wall_color.md`. (2026-10-17) |
|
||||
| 76 | **Camera-aware Sky redraws vector motifs while framing changes** — the former static Sky drew motifs only when the preset or viewport changed. | Low | Planned | The Phase 19 Sky addition keeps one screen-space `StageSkyView`, redraws only when a bound camera's effective framing changes, and caches reusable cloud/moon curve samples where practical. Measure sustained pan/zoom cost in a rendered Stage before adding a raster or shader path. The fixed reference frame and bounded response can saturate at distant camera positions; that is an accepted composition trade-off, not scene state to persist. See `docs/specs/phase_19_scenery_backgrounds_surface_finishes.md#phase-19-addition-camera-aware-sky-details`. (2026-10-21) |
|
||||
| 77 | **Starter surfaces guarantee a finite pan envelope, not arbitrary camera framing** — the two bundled sets use a fixed authored width to keep their scene data simple. | Low | Implemented; visual review pending | The authored envelope is a 1,280-logical-pixel viewport at zoom 0.5, ±1,000 world units of travel, and 100 units of margin per side. User review prompted an opaque Town Grass Background ground and separate scale-1 tile rows. Twenty-five 192-unit tiles cover the 4,760-unit minimum; Asphalt has 27 tiles (5,184 units) so the road extends one tile beyond the sidewalk at both ends. Navigation merges contiguous tile tops and routes the 32-unit curb step at the exposed ends without merging Ground objects or colliders. The focused suite passes 515 assertions, including the curb step and PLAY landing. The camera remains unrestricted, so wider viewports, farther pans, and zoomed-out shots can reveal finite ends. Rendered seam review remains pending. See docs/specs/phase_19_starter_scene_composition.md. (2026-10-21)
|
||||
| 78 | **Plain Background adds a second backdrop kind while Sky remains a separate renderer** — live Stage, starter previews, and chooser cards must agree on kind and remembered color. | Medium | Spec prepared; implementation pending | Phase 19 composes one shared `StageBackgroundView` from the existing Sky view and an opaque fill. Scene v1.7 stores active kind, last Sky ID, and confirmed plain color; all older scenes migrate as Sky. `SandboxStage` owns the transient custom-picker draft, which must never enter Save or autosave. The existing chooser's four-Sky layout and 42 px compact swatches need targeted extension, and grid/gizmo contrast needs theme-backed treatment for light and dark fills. Rendered pan/zoom/resize, legacy migration, and every draft-cancel exit remain verification gates. See `docs/specs/phase_19_plain_background.md`. (2026-10-22) |
|
||||
| 79 | **Editor chrome has two existing token sources and scene-level literals** — PropTheme owns current Prop UI values while Stickman scenes hardcode bars, labels, and borders. | Medium | Spec prepared; implementation pending | Add one validated `EditorVisualTheme` source for shared semantic chrome and editor-local `Theme` instances. Retain PropTheme for prop material/primitive/canvas values and keep Stickman canvas drawing tokens in a separate namespace. Migrate legacy Prop `ui` accessors deliberately so a chrome role has one final authority; use SandboxTheme values as a visual reference without a runtime dependency or Stage inspector component reuse. See `docs/specs/editor_visual_harmonization.md`. (2026-10-23) |
|
||||
| 80 | **Stickman panel nodes currently own both document shapes and local view state** — rebuilding a panel for a focused layout would reset selection, zoom, and pan and risk save/preview drift. | Medium | Spec prepared; implementation pending | Move the same ten BodyPartPanel instances between Overview and Focus hosts, retain one permanent WholeStickmanPreview sibling, and defer switching while a drag or popup is active. The controller owns session-only view choice and active part; manually chosen views survive resize, and narrow Overview remains scrollable. A future document-model extraction is warranted only if new editor features make live-node ownership limiting. See `docs/specs/editor_visual_harmonization.md`. (2026-10-23) |
|
||||
| 81 | **Stickman authored transforms lack a complete dirty-state boundary** — preview translation emits `part_moved`, while rotation and scale currently have no commit signal; Save/Load/Clear do not track unsaved work. | Medium | Spec prepared; implementation pending | Add a controller-observable transform commit path for position, rotation, and scale, plus `_dirty`/`_current_path` and Save/Discard Changes/Cancel transactions for replacement and close. Keep Overview/Focus, guide, grid, selection, and zoom/pan as session UI state that never marks dirty. Preserve the `.stk` format. See `docs/specs/editor_visual_harmonization.md`. (2026-10-23) |
|
||||
|
||||
---
|
||||
|
||||
@@ -169,5 +179,19 @@ This document tracks known technical debt, optimization opportunities, and minor
|
||||
| 2026-10-14 | Phase 17c Impact wobble implementation is present against the approved UI and architecture contracts. The prop card has a per-placement switch and EDIT sample; PLAY routes contacts and identified blocking sweeps through the approach-speed resolver, including ragdoll and prop pairs, while wobbling artwork only. Scene v1.4 stores the setting and migrates older scenes to Off; STOP/reset clears transient motion. Automated behavior verification and in-editor user verification have not been completed. Updated #69–#70; mass-aware scoring remains a future design seam. |
|
||||
| 2026-10-14 | User verified Phase 17c Impact wobble. Updated #69 and the Phase 17 plan; no automated behavior verification result was supplied. |
|
||||
| 2026-10-14 | Phase 18 palette image icons implemented and user-verified (`docs/specs/phase_18_palette_icons.md`). `StageChrome` maps the six palette placement IDs to preloaded images; the three plural filenames are now singular, original 1254 × 1254 PNGs are preserved, and Godot imports are capped at 256 px for display in the existing 64 × 64 card areas. The focused palette suite passed, the headless Sandbox Stage loaded, and `git diff --check` passed. Godot import exited 0 with Windows certificate-store and global editor-settings warnings. User verified the palette appearance and placement behavior in the Editor; #71 is resolved. |
|
||||
| 2026-10-15 | Phase 19 architecture specification drafted for final user sign-off (`docs/specs/phase_19_scenery_backgrounds_surface_finishes.md`) after approval of live `.prop` references with a repairable missing-art placement, adaptive viewport Sky, and a Stage-hosted Prop Editor route. The design adds inert wall/artwork nodes, vector finishes, scene v1.5 migration, `.prop` v1.1 tags, Scenery-only selection and snapshot group transforms, shared Stage UI generalizations, and ordinary editable starter scenes. Logged #72 for a separate Stage Undo/Redo phase and #73 for a separately designed whole-set transform. No runtime code or assets changed. |
|
||||
| 2026-10-16 | Added the Phase 19 Stage-relative sizing architecture amendment to `docs/specs/phase_19_scenery_backgrounds_surface_finishes.md` for final sign-off. Prop Editor Size for Stage uses a reversible snapshot, longest-edge presets of 0.35/1/2 standing-stickman heights, origin-based uniform geometry/stroke/editable-anchor scaling, and an editor-only foreground figure/floor comparison. A selected Scenery piece uses its own snapshot transaction and commits on release; a group still uses Keep/Cancel. Existing `.scene` v1.5 placement scale and `.prop` v1.1 geometry need no schema change or load-time normalization. Explicit Save at an existing `.prop` path retains live-reference updates for all users of that source; no asset-version enforcement or new save prompt was requested. Updated #72 for the deferred Stage Undo boundary. The amendment needs no new art and Phase 19 user/editor verification remains pending. No runtime code changed by this specification entry. |
|
||||
| 2026-10-17 | Wrote the Phase 19 selected-artwork depth inspector specification (`docs/specs/phase_19_selected_artwork_depth_inspector.md`) for final sign-off. It reuses the existing `StageInspectorPanel` and `StagePanelChoiceGroup`, applies Far/Near/On the floor immediately to one live or missing Scenery placement through `StageSceneryArtwork.set_depth()`, and follows the Stage's existing dirty/save path. The current `.scene` depth field, `StageDrawOrder`, and `stage_panels` tokens need no changes. Updated #72 to include immediate depth edits in a future Stage-wide Undo phase. No runtime code changed by this specification entry. |
|
||||
| 2026-10-17 | Wrote the Phase 19 Background ground and wall color architecture specification (`docs/specs/phase_19_background_ground_and_wall_color.md`) for final sign-off. It defines distinct inert wall/backdrop scene types over a small shared rectangle contract, world-aligned bounded vector materials, selected-piece color preview without mutating saved tint, one eight-color Stage settings list, scene v1.6 migration of old Brick/Wood placeholder green, shared Stage inspector controls, and confirmed single-piece backdrop erasure. Logged #74 for zoom-consistent motif budgets and #75 for the old unused wall-color ambiguity. No runtime code changed. |
|
||||
|
||||
| 2026-10-20 | Approved the scenery bitmap tile cache architecture (`docs/specs/scenery_bitmap_tile_cache.md`). Lightweight `StageSurfaceCache` handles share immutable bitmap tiles through one `StageSurfaceBakePool` under the current scene, with a 64 MiB resident bitmap budget and one reusable offscreen baker. Camera-visible tiles use four fixed zoom levels (0.125, 0.5, 1, 2); the coarsest tile bakes first and refined detail overlays it. At maximum 6× zoom, the 2× bitmap may look softer because it is magnified threefold. Erased fragments clip shared tiles only when their complete pattern sampling phase matches. The previous per-surface viewport cache retained vector commands and had no scene-wide resource limit, a likely contributor to `Element limit reached`; the exact RID pool remains unconfirmed. GPU readback during bitmap capture and regeneration after budget eviction are accepted costs to measure during implementation. |
|
||||
|
||||
| 2026-10-20 | Replaced the positional scenery tile design after the user observed continuous buffering when panning after zoom. The accepted revision in `docs/specs/scenery_bitmap_tile_cache.md` bakes one seamless, 2× bitmap per finish/tint period and uses GPU repeat plus generated mipmaps for all camera positions and zooms. Erased fragments share the style texture and crop it using their existing sample coordinate. The scene-wide 64 MiB limit includes mipmaps; inactive style variants may be evicted, while recently used styles stay warm when space allows. This trades unique random detail across an unlimited wall for finite repeated variation and keeps the existing possible 3× bitmap enlargement at maximum zoom. A style change can bake once; repeated camera movement must not increment build or readback counts after styles are ready. |
|
||||
| 2026-10-21 | Drafted the camera-aware Sky architecture addendum in `docs/specs/phase_19_scenery_backgrounds_surface_finishes.md` for user sign-off. Accepted a fixed built-in camera reference, one bounded response profile per preset, and normalized motif anchors with uniform scaling. The gradient remains a full-screen `CanvasLayer` draw; motifs derive deterministic bounded pan/zoom response from absolute `Camera2D` framing. Chooser and starter previews stay unbound and still; existing Sky/camera scene fields suffice. The trade-offs are response saturation far from the reference and more frequent vector redraws during camera movement; logged #76 for measured performance follow-up. No runtime code or tests changed. |
|
||||
| 2026-10-21 | Wrote the Phase 19 starter-scene composition UI/UX and architecture specifications (`docs/specs/phase_19_starter_scene_composition_ui_ux.md`, `docs/specs/phase_19_starter_scene_composition.md`) after approval of the Everyday Storybook brief and the 1,280-pixel / ±1,000-world-unit pan defaults. The edited starter snapshots use current scene v1.6 and existing Ground, wall, Background ground, Scenery, and Prop types, and keep the camera unrestricted; the starter card derives a central opening preview without new scene metadata. No code or art changed. Added #77 for the finite authored-envelope and broad-selection trade-off; the architecture spec is approved and implementation/agent verification are underway.
|
||||
| 2026-10-21 | Implemented the approved starter-scene composition spec. Town Street and Living Room now use continuous 4,760-unit support surfaces, aligned bases, and camera-derived starter-card framing; both edited scene files use current v1.6. The focused production-load/save-reopen/PLAY composition test passed 177 assertions, with measured visible-contact geometry within 0.225 logical pixels. The broader scenery suite exits 1 on nine other background-card and wall-erasure/capture-bar assertions, while the new surface assertions pass. GUI capture exited 134 and headless capture produced no image, so rendered-pixel checks, pan-endpoint seam inspection, narrow viewport/zoom-in framing, and user/editor verification remain pending. Updated #77 from planned to implemented with the finite-camera limitation accepted. See `docs/specs/phase_19_starter_scene_composition.md`.
|
||||
| 2026-10-21 | Revised the starters after the user's Town Street screenshot exposed Sky clouds below the skyline and the user rejected oversized scaled Ground blocks. Added an opaque Grass Background ground, replaced the sidewalk and both starter floors with scale-1 tile rows, and extended Asphalt by one tile at each end so the road is accessible. The focused production-path test passed 515 assertions, including navigation across tile seams, sidewalk-to-road routing, and a PLAY actor landing grounded on Asphalt. The broader scenery suite still exits 1 on the same nine Sky-preview/gallery and Scenery-edit UI assertions observed before this revision; its new surface assertions pass. A bounded GUI capture exited 134 without an image, so rendered pixels, pan endpoints, card previews, narrow viewport/zoom-in states, and user/editor review remain pending. See `docs/specs/phase_19_starter_scene_composition.md`.
|
||||
|
||||
| 2026-10-22 | Prepared and revised the Phase 19 Plain Background architecture specification (`docs/specs/phase_19_plain_background.md`) for final user sign-off. The accepted composed Stage backdrop view serves live Stage and previews; scene v1.7 persists active kind, last Sky ID, and confirmed plain color while migrating all older scenes as Sky. Color drafts stay out of Save/autosave, and theme-backed grid and two-tone gizmo overlays address light fills without changing art. Per user feedback, the current-color chip is the sole custom-picker entry, the separate More colors button is removed, and the custom picker uses a simple Preview label without a temporary-state helper message. Logged #78 for the chooser extension and rendered verification gates. No runtime code or tests changed. |
|
||||
|
||||
_End of Log_
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
# Editor Visual Style Guide
|
||||
|
||||
**Scope:** Establish a practical visual and interaction direction for the Prop Editor and Stickman Editor, using the Sandbox Stage UI as a product reference.
|
||||
**Status:** Guidance for current and future editor UI. Prop and Stickman share `EditorVisualTheme` for editor chrome and selected reusable controls; Stage-only layouts and components remain Stage-specific unless explicitly generalized.
|
||||
|
||||
## 1. Product direction
|
||||
|
||||
Both editors should feel like approachable creative workspaces in the same Stickman Studio product:
|
||||
|
||||
- Keep the canvas or preview as the main work surface. Put tools and settings around it, not on top of the artwork unless a temporary task requires an overlay.
|
||||
- Make the current task and mode easy to recognize. Use direct labels such as **Arrange**, **Reshape**, **Attach**, **Save**, and **Cancel**.
|
||||
- Prefer visible feedback on the object over abstract state: selection outlines, vertex handles, previews, mode coloring, and status text.
|
||||
- Preserve a stable layout while the child works. Opening an inspector section, showing help, or changing a mode should not make the active control jump away from the pointer.
|
||||
- Make recovery and destructive actions predictable. Show what is about to happen and keep a visible way to cancel.
|
||||
- Share a visual language, not necessarily identical panel layouts. A vector canvas, a modal dialog, an in-stage inspector card, and a stickman-part panel have different jobs.
|
||||
|
||||
The Sandbox Stage establishes a useful baseline for hierarchy, contrast, child-facing language, control states, safe viewport behavior, and theme tokens. Its in-stage inspector and capture bar are Stage patterns; they should be adapted only when an editor workflow has the same interaction needs.
|
||||
|
||||
## 2. Current implementation map
|
||||
|
||||
| Surface | Current implementation | Reuse implication |
|
||||
| --- | --- | --- |
|
||||
| Sandbox Stage | SandboxTheme loads validated tokens from [sandbox_theme.json](../../sandbox_theme.json). Stage inspector controls live under [scripts/shared/stage_ui](../../scripts/shared/stage_ui/). | Use as the product reference for semantic colors, readable type, focus, action roles, and reusable theme access. |
|
||||
| Stage inspector | The approved [Stage panel UI system](../specs/stage_panel_ui_system.md) targets in-stage selected-object cards. | Do not insert StageInspectorPanel into editor inspectors by default. Borrow fitting rules and state behavior; use its components only if the layout and ownership match. |
|
||||
| Stage and editor dialogs | [StageDialogStyler](../../scripts/shared/stage_ui/stage_dialog_styler.gd) draws the shared confirmation card over the active scene while retaining native dialog signals. The style reads `popups.confirmation` from SandboxTheme. | Use this shared card for Prop and Stickman confirmation, recovery, and short action dialogs. Native file picker content remains native. |
|
||||
| Shared editor chrome | [EditorVisualTheme](../../scripts/shared/editor_ui/editor_visual_theme.gd) loads validated tokens from [editor_visual_theme.json](../../editor_visual_theme.json) and builds each editor's local control Theme. `EditorSelectionDropdown` and `EditorContextMenu` supply shared selection and canvas-menu styling. | Use shared semantic tokens and controls for matching editor workflows. Keep editor-specific document behavior in its owner. |
|
||||
| Prop Editor | [PropTheme](../../scripts/editors/prop/prop_theme.gd) reads [prop_theme.json](../../prop_theme.json) for material, geometry, and canvas defaults; editor chrome comes from `EditorVisualTheme`. The main scene uses split containers, a scrollable inspector, modes, and a nested Attach preview. | Keep Prop artwork/material values and canvas contrast in `PropTheme`; use shared editor tokens for chrome, inspector states, and selection dropdown styling. |
|
||||
| Stickman Editor | [stickman_editor.gd](../../scripts/editors/stickman/stickman_editor.gd) uses `EditorVisualTheme` for chrome and coordinates ten BodyPartPanels in a two-column Overview beside the Whole Stickman preview, plus a Focus view for one large panel. | Overview columns and panels expand to the workspace size, retaining a 230 × 160 px minimum and scrolling when space is short. Keep the splitter draggable, preserve panel state, and show the part title inside its panel in both views. |
|
||||
| Child-facing dialogs | [Dialog Design Principles](../specs/dialog_design_principles.md) documents the rounded, labeled-action pattern and stable resizing behavior. | Apply these rules to editor dialogs, adapting ownership and host behavior to each editor. |
|
||||
|
||||
The Prop Editor user guide at [prop_editor_user_guide.md](prop_editor_user_guide.md) describes its current controls and layout. Use it to avoid documenting proposed changes as existing behavior.
|
||||
|
||||
## 3. Shared visual system
|
||||
|
||||
### 3.1 Semantic color roles
|
||||
|
||||
Use color to reinforce meaning consistently. Keep labels, shapes, icons, or state text alongside color so meaning survives grayscale, low contrast, and color-vision differences.
|
||||
|
||||
| Role | Sandbox Stage reference | Editor guidance |
|
||||
| --- | --- | --- |
|
||||
| Main background | global.bg_color #171B24F2 | Use a dark neutral around the work area; avoid competing with authored art. |
|
||||
| Raised surface | global.surface_color #252B38FA | Use for toolbars, inspector shells, and cards. Distinguish adjacent surfaces by value, border, or spacing. |
|
||||
| Primary text | global.text_color #F5F7FA | Use for titles, control names, and important values. |
|
||||
| Secondary text | global.muted_text_color #AAB2C0 | Use for helper text and secondary status; keep readable at the chosen size. |
|
||||
| EDIT accent | mode_colors.edit #22C6FF | Shared editor accent for active modes, selection accents, and editor guidance through `EditorVisualTheme`. |
|
||||
| DIRECT accent | mode_colors.direct #FFB300 | Reserved for the Stage's directing mode. Do not use as a generic warning color in editors. |
|
||||
| PLAY accent | mode_colors.play #33DD77 | Reserved for Stage playback state. |
|
||||
| Primary action | Stage dialog/action blue #087DBA | Use for the single most important forward action in a dialog. |
|
||||
| Destructive action | Stage danger #E66B75 with dark red surfaces | Use only for destructive actions; pair with explicit wording and a cancel path. |
|
||||
| Focus | Stage dialog focus #8BD9FF | Give keyboard focus an outline that remains visible over selected, hovered, and dark states. |
|
||||
| Canvas grid | Stage tokens vary with canvas treatment; Prop canvas currently uses #FFFFFF26. | Keep grid lines subtle. The work, selection, and handles must dominate the grid. |
|
||||
|
||||
These values are current Stage reference values, not a mandate to paste literal hex values into editor controls. Resolve colors through validated theme accessors. If an editor needs a warmer or quieter local accent, define a semantic editor token and document its mapping to Stage meaning.
|
||||
|
||||
### 3.2 Shared chrome and intentional editor differences
|
||||
|
||||
Both standalone editors now use `EditorVisualTheme` for shared chrome roles, sizing, and local control Themes. Keep these domain-specific values in their existing owner:
|
||||
|
||||
- `PropTheme` retains material tints, primitive defaults, outline widths, and the Prop canvas surface/grid. Keep its neutral charcoal canvas distinct from the blue-tinted editor panels. Stickman canvas grid and selection colors remain in `EditorVisualTheme.stickman_canvas` tokens.
|
||||
- `EditorVisualTheme` owns common editor surfaces, text, EDIT accent, focus, action roles, menu sizes, and minimum targets. `SandboxTheme` continues to own Stage-specific panels and dialog tokens.
|
||||
|
||||
Preserve these boundaries when extending the UI: share semantic chrome roles where workflows match, and keep canvas, material, and runtime-domain colors local to their owner.
|
||||
|
||||
### 3.3 Type, spacing, and shape
|
||||
|
||||
Use these Stage examples as starting points, then tune them for the denser editor workspace:
|
||||
|
||||
- Stage inspector hierarchy: title **24 px**, section **20 px**, body **20 px**, helper **16 px**.
|
||||
- Stage inspector shell: **12 px** padding, **8 px** header gap, **12 px** section gap, **10 px** corner radius.
|
||||
- Stage choice row: **56 px** minimum height; Stage toggle row: **64 px** minimum, increasing when helper text is visible.
|
||||
- Large child-facing dialogs: title about **28–30 px**, body about **20 px**, button about **20 px**, **2 px** borders, **12–18 px** corner radii, and generous footer spacing.
|
||||
- Stage generally uses dark surfaces with a restrained border. The dialog guide's stronger borders and rounder controls are for modal emphasis, not a requirement to put every editor widget inside a thick outline.
|
||||
|
||||
For compact inspectors, shorten the hierarchy only after checking it at the intended window size. Prefer a clear label and value over shrinking type until it becomes difficult to read. Use container spacing and alignment rather than per-control position nudges.
|
||||
|
||||
### 3.4 State styling contract
|
||||
|
||||
Every interactive control should have distinct, inspectable states:
|
||||
|
||||
| State | Expected feedback |
|
||||
| --- | --- |
|
||||
| Neutral | Stable surface and legible label; no implied selection. |
|
||||
| Hover | Small surface or border change. Must not resemble selected or focused. |
|
||||
| Selected / active | Persistent fill, border, pressed state, or explicit status. Keep the label unchanged when possible. |
|
||||
| Keyboard focus | High-contrast focus ring or border that is visible even over selected fill. |
|
||||
| Disabled | Control cannot activate, remains readable, and explains why when the reason is not obvious. |
|
||||
| Dragging / live preview | Immediate object feedback; indicate the active handle or preview and make cancellation discoverable. |
|
||||
| Error / invalid | Explain the problem near the affected task and offer a concrete next step. Do not rely on red alone. |
|
||||
| Saved / dirty | Show a concise, persistent status such as **Saved** / **Unsaved changes** where it helps prevent lost work. |
|
||||
|
||||
For drawing handles, keep a contrasting backing/halo where the canvas can contain arbitrary colors. The Prop canvas's two-tone selection halo and the Stage gizmo backing are useful precedents. Selection should be readable at all zoom levels; keep handle sizes in screen space when scaling the canvas.
|
||||
|
||||
## 4. Layout and reuse rules
|
||||
|
||||
### 4.1 Use the right pattern for the job
|
||||
|
||||
- **In-stage selected-object inspector:** follow StageInspectorPanel, choice groups, and toggle rows in the [Stage UI spec](../specs/stage_panel_ui_system.md). Its title/Close header, fixed header with scrolling body, and safe-rect fitting are specific to a floating selection card.
|
||||
- **Editor inspector:** favor a persistent column beside the canvas, with labeled groups and vertical scrolling. The Prop Editor already uses a split container and scrollable inspector. Separate sections with rounded cards, readable headings, colorful section icons, and concise helper copy; keep related values grouped in compact tiles. Reuse Stage's hierarchy and state clarity, but do not force the floating Stage card structure into this column.
|
||||
- **Temporary targeting step:** the Stage capture bar is for a short-lived click-on-stage task. An editor can borrow the prompt-plus-visible-Cancel contract when it has a similar temporary canvas capture step, but should not copy the bar just because it is visible in Stage.
|
||||
- **Modal dialog:** follow [Dialog Design Principles](../specs/dialog_design_principles.md). Keep a labeled **Cancel**, **Done**, or **Back** action; use one visually clear primary action; preserve the clicked control's anchor when content grows; cap height and scroll content on short viewports.
|
||||
- **Canvas tools:** keep mode and document controls outside the draw area where possible. Put contextual handles and temporary prompts near the object only if they do not obscure the task.
|
||||
|
||||
### 4.2 Reuse through tokens and small components
|
||||
|
||||
1. Put repeated colors, font sizes, minimum sizes, spacing, radii, border widths, and state colors in a validated theme source.
|
||||
2. Use typed accessors with sensible fallbacks. Avoid repeating raw values across script-built controls and .tscn files.
|
||||
3. Apply per-control StyleBox overrides. Do not mutate a cached/shared Theme to style one editor or one accent variant.
|
||||
4. Extract a reusable control only after the behavior or presentation appears in at least two appropriate contexts. Keep domain rules and document mutations in the editor controller.
|
||||
5. Prefer native Button, ButtonGroup, CheckBox, OptionButton, and LineEdit semantics. Custom-drawn controls should separate visual drawing from input and expose a clear typed API.
|
||||
6. Keep canvas-specific rendering tokens separate from chrome tokens. Grid, artwork, shape fill, selection halo, vertex handles, and preview ghosts have different contrast jobs.
|
||||
7. Do not serialize UI state unless it is part of the authored document. Tool preference, document content, preview-only state, and persistence should be deliberately separated.
|
||||
|
||||
Both standalone editors build their chrome Theme from `EditorVisualTheme`; Prop also uses `PropTheme` for prop-specific art and material defaults. Stage remains the reference for fitting, dialog hierarchy, and child-facing language, but its in-stage inspector layout is not a default editor-inspector component.
|
||||
|
||||
### 4.3 Responsive workspace behavior
|
||||
|
||||
- Preserve canvas priority. When space is constrained, inspector content scrolls before drawing tools or essential canvas controls are clipped.
|
||||
- Keep splitters draggable and give both sides a useful minimum. Prop Editor has the outer canvas/inspector split and an Attach preview split; these are good workspace patterns to retain.
|
||||
- Use container-driven rows (FlowContainer, HBoxContainer, VBoxContainer) instead of fixed offsets for control groups that can wrap or grow with theme fonts.
|
||||
- Keep top actions and mode controls reachable at smaller window sizes. Wrap or stack controls only when necessary, and preserve their order and mode meaning.
|
||||
- Keep toolbars, status bars, and dialogs inside safe margins. A dynamic dialog should grow from a stable anchor and scroll rather than jump or recenter after each choice.
|
||||
- Stickman Overview uses two equal, flexible columns of five body-part drawing panels beside the Whole Stickman preview. Let both columns fill the Overview pane and share extra width; let the five rows share extra height while preserving a 230 × 160 px minimum panel size. Scroll the Overview when the viewport is shorter than its minimum content size.
|
||||
- Keep the Overview/preview splitter draggable. On narrow windows, use the existing Focus view to give one body-part panel the available space; keep Whole Stickman access available through its dedicated control. Switching views must preserve each panel instance, authored geometry, selection, and view transform. In Focus, use the title inside the active panel as the only canvas heading; do not repeat it above the panel.
|
||||
- Validate the layout at wide and narrow windows, with raised fonts and resized panels, before claiming responsive behavior.
|
||||
|
||||
### 4.4 Shared confirmation dialog style
|
||||
|
||||
Use the Sandbox Stage confirmation card for child-facing confirmation, recovery, and short action dialogs in both standalone editors. The shared implementation is `StageDialogStyler`, with color, sizing, and spacing values from `SandboxTheme.popups.confirmation`.
|
||||
|
||||
- Draw a dim backdrop and a centered, rounded dark card. Use the themed card width (560 px target), 22 px inset, 18 px corners, and 2 px border; fit the card inside the safe viewport.
|
||||
- Put a contextual icon badge and a left-aligned 28 px title in the header. Put the message in a left-aligned 20 px body. Wrap longer copy and scroll the body if the viewport is short.
|
||||
- Order actions as primary, destructive, then **Cancel**. Use Stage blue for Save, Restore, and other forward actions; use the danger treatment for Discard, Start Over, and other destructive choices; use the neutral surface for Cancel. Make action labels at least 52 px high and 112 px wide, with 12 px gaps.
|
||||
- Keep the visible **Cancel** action even when Escape is supported. Do not show a native title-bar **×**. Focus the primary action when present; for a destructive-only prompt, focus Cancel.
|
||||
- Keep the native `AcceptDialog` or `ConfirmationDialog` as the signal source and open its shared overlay through `StageDialogStyler`. This keeps confirmation, custom-action, cancellation, keyboard, and safe-viewport behavior consistent.
|
||||
- Apply this pattern to Prop recovery, unsaved changes before New/Close/Stage return, off-origin save choices, anchor rename, and error acknowledgement; apply it to Stickman Start Over, unsaved changes, grid setup, and error acknowledgement. File pickers keep their native file-selection interface.
|
||||
|
||||
Treat the card as one shared product pattern. Do not create editor-local confirmation palettes or button-role variants.
|
||||
|
||||
## 5. Editor flows and state maps
|
||||
|
||||
The following maps describe the current interaction architecture at a level useful for future visual work. They are not proposed additions to file formats.
|
||||
|
||||
### 5.1 Prop Editor flow
|
||||
|
||||
Current primary flow, based on [prop_editor.gd](../../scripts/editors/prop/prop_editor.gd) and [prop_canvas.gd](../../scripts/editors/prop/prop_canvas.gd):
|
||||
|
||||
~~~mermaid
|
||||
flowchart TD
|
||||
Open[Open Prop Editor] --> Recovery{Recover autosave?}
|
||||
Recovery -->|Restore| Dirty[Restore document as dirty]
|
||||
Recovery -->|Discard / none| New[New or loaded document]
|
||||
Dirty --> Arrange[Arrange shapes]
|
||||
New --> Arrange
|
||||
Arrange --> Reshape[Reshape vertices]
|
||||
Arrange --> Attach[Attach anchors and preview]
|
||||
Reshape --> Arrange
|
||||
Attach --> Arrange
|
||||
Attach --> Reshape
|
||||
Arrange --> Save[Save / Save As]
|
||||
Reshape --> Save
|
||||
Attach --> Save
|
||||
Save --> Clean[Saved status; autosave cleared]
|
||||
Arrange --> Exit{New / close with changes?}
|
||||
Reshape --> Exit
|
||||
Attach --> Exit
|
||||
Exit -->|Save| Save
|
||||
Exit -->|Discard| Close[Close or start new]
|
||||
Exit -->|Cancel| CurrentMode[Return to current mode]
|
||||
~~~
|
||||
|
||||
Presentation rules for this flow:
|
||||
|
||||
- Arrange, Reshape, and Attach are persistent tool modes. Keep the active mode visually selected and keep mode labels stable.
|
||||
- Mode changes may change available controls and inspector sections. Explain missing controls through a short label or helper only when the reason is not obvious from the mode.
|
||||
- Shape/anchor edits change the document and should visibly change dirty status. Preview motion, visibility toggles, and other session-only controls should not imply the document was edited.
|
||||
- Saving should confirm completion in the status area or title state. Errors should identify the failed file action and retain the child's work.
|
||||
- New and close with unsaved changes offer explicit **Save**, **Discard**, and **Cancel** outcomes. For actions that could replace work, name the consequence in the prompt.
|
||||
- In Attach mode, show the selected anchor and its editable handles clearly on the canvas, and keep the private stickman/prop preview visually separate from the authoring surface.
|
||||
|
||||
### 5.2 Stickman Editor flow
|
||||
|
||||
Current primary flow, based on [stickman_editor.gd](../../scripts/editors/stickman/stickman_editor.gd), [body_part_panel.gd](../../scripts/editors/stickman/body_part_panel.gd), and [whole_stickman_preview.gd](../../scripts/editors/stickman/whole_stickman_preview.gd):
|
||||
|
||||
~~~mermaid
|
||||
flowchart LR
|
||||
LoadOrStart[Load or start stickman] --> Parts[Choose a body-part drawing panel]
|
||||
Parts --> Draw[Draw and color one or more shapes]
|
||||
Draw --> Select[Select shape or vertex]
|
||||
Select --> Preview[Inspect whole-stickman assembly]
|
||||
Preview --> Guide[Toggle pose guide / reset views]
|
||||
Guide --> Parts
|
||||
Parts --> Save[Save stickman]
|
||||
Save --> Continue[Continue editing]
|
||||
LoadOrStart --> Clear[Clear with confirmation]
|
||||
Clear --> Parts
|
||||
~~~
|
||||
|
||||
Presentation rules for this flow:
|
||||
|
||||
- Make the active body-part panel and active shape unambiguous. Selecting a shape in one panel clears selection in the others.
|
||||
- Keep local drawing context and the assembled Whole Stickman preview distinct but visually related. A change in one body part should have a prompt, visible effect in the assembly preview.
|
||||
- Use the pose guide as quiet construction help beneath selection gizmos. Guide colors distinguish left/right limbs; the guide must not capture pointer input or obscure active edits.
|
||||
- Keep color editing and recent colors close to the relevant part, and confirm a color only through the explicit dialog action.
|
||||
- Keep grid/snap and guide visibility available as tool preferences, visually separated from authored shape color and geometry.
|
||||
|
||||
### 5.3 Reusable dialog transaction
|
||||
|
||||
For either editor, the expected child-facing sequence is:
|
||||
|
||||
1. State the action in the title and one short sentence.
|
||||
2. Show the effect or consequence when it may be surprising.
|
||||
3. Present one primary action, any needed destructive action, and a visible **Cancel**. If the only forward-looking choice is destructive (such as Start Over), keep it in the danger role and focus Cancel initially.
|
||||
4. Keep focus in the dialog, preserve the current anchor during resize, and return focus to the invoking control after close where practical.
|
||||
5. On success, close the dialog and update the affected editor state once. On cancel, leave the document unchanged.
|
||||
|
||||
This is a target interaction contract for editor dialogs. Existing controls should be checked individually before being treated as compliant.
|
||||
|
||||
## 6. Interaction, feedback, and child-facing language
|
||||
|
||||
### 6.1 Input and feedback
|
||||
|
||||
- Support mouse and touch-size targets; target at least **44 × 44 logical pixels** for child-facing actions. Prefer Stage's **48 px** action target where the layout allows.
|
||||
- Keep keyboard navigation visible and complete: Tab reaches meaningful controls, Enter/Space activates them, Escape cancels temporary tasks, and focus does not disappear behind a selected style.
|
||||
- Keep right-click and keyboard shortcuts as optional accelerators. A visible menu item or button should remain available for important operations.
|
||||
- Keep the top-level File/Edit/View menu titles plain and use familiar emoji beside readable action labels inside their dropdowns. Match the Sandbox Stage menu scale: 22 px menu-bar labels and 26 px popup labels. Group file actions as New/Open/Recent, then Save/Save As, with separators before a distinct Rename or Start Over action where present. Use the restrained charcoal popup surface for menu-bar dropdowns; reserve the raised Studio List surface for canvas right-click menus.
|
||||
- Style single-choice editor pickers as a dark field with the chosen label and chevron. Popup rows keep readable text and may include a meaningful domain icon, as in Prop material and shape choices; do not show radio/check glyphs or an empty indicator lane. The current choice gets a full teal surface and cyan outline. Keep hover and keyboard focus visible, and give the field and rows at least 44 logical pixels of height. Use the shared `EditorSelectionDropdown` control for Prop and Stickman editor pickers.
|
||||
- Standardize Prop and Stickman canvas context menus on the **Studio List** pattern: a compact vertical list on a raised editor surface, with a subtle border, rounded corners, readable 20 px labels, and 48 px rows. Resolve surface, border, text, hover, EDIT accent, focus, and destructive colors through `EditorVisualTheme` tokens rather than local color literals.
|
||||
- Group related actions with spacing and separators, and keep each menu's actions specific to the current mode and hit target. Hover uses a lighter surface with a slim EDIT-cyan cue; keyboard focus has a distinct, high-contrast focus outline. Open with no focused row so mouse users do not mistake an action for a selection; show the focus outline after Up/Down navigation, and clear it when the pointer takes over. Give destructive actions explicit labels, separate them from regular actions, and place them last when practical; do not use color as their only cue.
|
||||
- Keep labels as the source of meaning and use icons sparingly and consistently. Open the menu near the pointer, keep the clicked point or shape edge visible, and clamp the menu within the viewport.
|
||||
- For dragging, preview changes continuously, show which handle is active, commit on release, and provide a clear cancel path when the operation is consequential or multi-step.
|
||||
- Avoid hit-test surprises: decorative labels/icons ignore mouse input; a large row toggle has one activation target; a canvas guide is visual only.
|
||||
- Preserve the world point under the cursor during zoom. Keep selected gizmos and handles visible above artwork and grid.
|
||||
- Use both visual and textual feedback for snap, mode, selected state, disabled reason, save state, and errors.
|
||||
|
||||
The Stage panel's full-row toggle and stable help layout are useful behaviors when a row switch is appropriate. In an editor inspector, apply the same principles without copying the Stage card's floating shell.
|
||||
|
||||
### 6.2 Copy and labels
|
||||
|
||||
Prefer concise, concrete verbs and familiar terms:
|
||||
|
||||
| Prefer | Avoid |
|
||||
| --- | --- |
|
||||
| **Arrange**, **Reshape**, **Attach** | Technical labels such as “Transform mode” or “Edit points mode” as the main child-facing label |
|
||||
| **Add Shape**, **Erase Shape**, **Create Point**, **Remove Point** | Ambiguous labels such as “Apply” when the result can be named |
|
||||
| **Save**, **Save As…**, **Load**, **Cancel** | Icon-only actions with no tooltip or accessible label |
|
||||
| “This shape was reshaped.” | A disabled Radius field with no explanation |
|
||||
| “Choose where this prop attaches.” | Internal terms such as “anchor payload” |
|
||||
| “Unsaved changes. Save before starting a new prop?” | Generic “Are you sure?” without naming the consequence |
|
||||
|
||||
Emoji can help distinguish common actions, as used by both editor menus, but should be an optional cue rather than the only meaning. Keep the text label understandable if an emoji font is unavailable. Use the same wording for the same action in menu, dialog, toolbar, tooltip, and user guide.
|
||||
|
||||
### 6.3 Icons and emoji
|
||||
|
||||
- Use one icon or emoji to help scan a familiar action; do not put emoji on every label by default.
|
||||
- Keep the text label as the source of meaning. Provide a tooltip or accessible name for icon-only canvas tools.
|
||||
- Use icons consistently for the same action across menus, toolbars, empty states, and dialogs. Avoid changing icon meaning between editors.
|
||||
- Avoid using an emoji's color as the only state cue; fonts and platforms may render it differently.
|
||||
- Both editors use icons beside readable menu action labels, with separators between distinct groups. Keep top-level File/Edit/View titles plain; place icons on actions and use the same symbol for the same operation across editors.
|
||||
- In the Prop inspector, use colorful, flat icons for section headings, material choices, 2D shape choices, and artwork tags. Keep text labels authoritative. Show tag selection with the selected surface and border; do not add a separate check badge. Shape icons must depict planar 2D geometry.
|
||||
|
||||
### 6.4 Empty, loading, and error states
|
||||
|
||||
The current editors have different levels of state guidance. The following table separates known behavior from recommended presentation:
|
||||
|
||||
| State | Current reference | Recommended presentation |
|
||||
| --- | --- | --- |
|
||||
| New/empty Prop canvas | Arrange has an add-shape context menu and an Arrange-only empty-canvas hint; Reshape does not offer adding a shape. | Keep the canvas mostly clear. Show a short Arrange hint only when it helps discover the next action; hide it as soon as artwork exists. Do not show a dead-end hint in Reshape or Attach. |
|
||||
| Empty Prop inspector selection | Inspector sections depend on mode and selected shape/anchor. | State what to select or create when the empty inspector would otherwise look broken. Keep the message short and do not add a second competing empty-canvas prompt. |
|
||||
| Prop load/recovery | Load failures use an error dialog; autosave recovery offers Restore or Discard. | Name the file/action in the message, preserve the current artwork on failure, and keep Restore/Discard outcomes distinct. Loading feedback should not imply that the document is already saved. |
|
||||
| Stickman panel before drawing | The ten body-part panels are the main workspace; the panel script owns drawing and selection behavior. | Give each blank panel a concise, low-contrast drawing cue if discovery testing shows it is needed. Remove it on first shape so it does not compete with artwork. |
|
||||
| Stickman load/clear | Load and save use file dialogs; Clear has a confirmation dialog; error dialogs report failures. | Keep the current document intact on a failed load. State the consequence in Clear confirmation and offer a visible cancel path. |
|
||||
| Save / dirty state | Prop Editor has status/title and autosave behavior; Stickman Editor's status bar reports cursor coordinates, snap state, and save state. | Keep save status easy to find in both editors. Do not treat autosave as a user-visible successful save unless the file was actually saved to the chosen destination. |
|
||||
|
||||
Do not add spinners or blocking overlays for synchronous work without evidence that the operation takes long enough to need them. If an operation becomes asynchronous, keep progress near the task and preserve access to cancellation where safe.
|
||||
|
||||
### 6.5 Motion and reduced motion
|
||||
|
||||
- Use motion to show cause and effect: a brief selection flash, a panel entering, or a successful action cue. Keep it short and do not delay the next input.
|
||||
- Do not animate every hover or value change. Motion should help the child understand an edit, not decorate idle controls.
|
||||
- Keep persistent mode and selection state visible after any transition ends.
|
||||
- Respect a reduced-motion preference for nonessential transitions and flashes. Provide an equally clear static state.
|
||||
- The current code has short visual effects such as the Prop canvas's new-point flash and Stage completion effects. A unified reduced-motion preference is not established by the referenced theme/specs; treat it as a future product-level decision.
|
||||
|
||||
## 7. Theme and implementation checklist
|
||||
|
||||
Before adding or revising an editor control:
|
||||
|
||||
### Design
|
||||
|
||||
- [ ] Is the control's job clear and is it in the correct workspace area?
|
||||
- [ ] Does it follow the correct pattern: persistent inspector, modal dialog, canvas tool, or temporary capture?
|
||||
- [ ] Are neutral, hover, selected, focused, disabled, dragging, and error states defined?
|
||||
- [ ] Does selected state remain distinct from hover and focus?
|
||||
- [ ] Are colors backed by labels, icons, position, or shape cues where appropriate?
|
||||
- [ ] Are labels child-readable and consistent with the existing action vocabulary?
|
||||
- [ ] Can the layout handle smaller windows, longer names, and larger font presets?
|
||||
|
||||
### Theme
|
||||
|
||||
- [ ] Are colors, type sizes, spacing, radii, borders, and target sizes tokens rather than repeated literals?
|
||||
- [ ] Does the token use a semantic name rather than a control-specific unexplained hex?
|
||||
- [ ] Does it have a validated accessor, fallback, and range clamp where applicable?
|
||||
- [ ] Are per-control style changes local and isolated from a shared cached Theme?
|
||||
- [ ] Is the difference from Stage tokens intentional and documented?
|
||||
|
||||
### Interaction
|
||||
|
||||
- [ ] Can pointer, touch, and keyboard users reach and activate the control?
|
||||
- [ ] Does a disabled control explain why, if not self-evident?
|
||||
- [ ] Does temporary work have an obvious Cancel/undo path?
|
||||
- [ ] Does a control's position remain stable while help, validation, or mode content changes?
|
||||
- [ ] Does changing a tool preference avoid marking the document dirty unless that is intentional?
|
||||
- [ ] Does success/failure produce visible feedback without hiding the canvas or losing authored work?
|
||||
|
||||
### Architecture
|
||||
|
||||
- [ ] Does the editor controller own document mutation, persistence, and dirty state?
|
||||
- [ ] Does a reusable control emit a typed intent and display a supplied value?
|
||||
- [ ] Is new reuse actually shared by more than one appropriate UI context?
|
||||
- [ ] Are UI preferences, preview-only state, and document data kept separate?
|
||||
- [ ] Are new theme values represented in both default config and committed JSON?
|
||||
- [ ] Are existing user guides/specs updated only after the behavior is verified?
|
||||
|
||||
### Implementation recipe
|
||||
|
||||
For a new editor UI element, use this sequence:
|
||||
|
||||
1. Name its job and state owner. Decide whether the editor controller, canvas, or reusable view owns the value and mutation.
|
||||
2. Identify the closest reference pattern: Stage inspector, Stage dialog, Prop Editor mode control, Prop canvas selection, or Stickman body-part panel. Record what should carry over and what should not.
|
||||
3. Define the semantic tokens and states before styling. Reuse existing token names where their meaning matches; add new names to the theme defaults and JSON with validation/fallback behavior.
|
||||
4. Build with Godot containers and native controls first. Add a custom control only when it provides repeated behavior or custom canvas drawing.
|
||||
5. Wire typed intent signals to the owning controller. Refresh controls from document state without emitting a second mutation.
|
||||
6. Check the smallest supported window, larger type, long labels, all modes, selected/disabled/focused states, and save/error/cancel paths.
|
||||
7. Capture before/after screenshots or a short manual checklist. Update the user guide after the behavior is accepted.
|
||||
|
||||
This is recommended implementation order, not a claim that every current editor control follows it.
|
||||
|
||||
### Recommended harmonization order
|
||||
|
||||
1. **Maintain token ownership.** `EditorVisualTheme` owns shared standalone-editor chrome; `PropTheme` owns prop-domain and canvas defaults; `SandboxTheme` owns Stage-specific UI. Document any intentional override at the token or component that owns it.
|
||||
2. **Audit remaining overrides.** Check for editor chrome values that still bypass `EditorVisualTheme`; preserve the Prop canvas surface/material palette and Stickman canvas drawing tokens where they serve artwork contrast.
|
||||
3. **Document responsive limits.** Record minimum usable widths, toolbar wrapping, how the two Stickman Overview columns share space beside the preview, and when Focus or scrolling takes over.
|
||||
4. **Audit remaining state gaps.** Verify focus, disabled reasons, save/error status, destructive confirmation, and cancel behavior. Both editors use the shared `StageDialogStyler` card for confirmation, recovery, and short action dialogs.
|
||||
5. **Validate visually at agreed sizes.** Compare the editor screenshots with the Stage reference and adjust intentional differences explicitly.
|
||||
|
||||
This order is a maintenance checklist for the current shared chrome and editor-specific drawing patterns; it does not propose replacing the established theme architecture.
|
||||
|
||||
### Visual QA checklist
|
||||
|
||||
- [ ] Compare Prop and Stickman editor startup screens side by side with the Stage's dark surface and EDIT accent references.
|
||||
- [ ] Check every mode with no selection, with a selected object, during drag, and after release/cancel.
|
||||
- [ ] Check primary action, destructive action, disabled control, hover, keyboard focus, and persistent selected states.
|
||||
- [ ] Check prop autosave recovery, load failure, unsaved New/Close, and successful save feedback.
|
||||
- [ ] Check Stickman Clear confirmation, load failure, snap status, pose guide, and cross-panel selection.
|
||||
- [ ] Resize to the smallest supported viewport and increase font size. Confirm canvas access, scroll access, and nonoverlapping controls.
|
||||
- [ ] Verify visible keyboard order and Return/Space/Escape behavior; confirm focus returns to the invoking control where appropriate.
|
||||
- [ ] Check grid, artwork, selection halo, vertex handles, pose guide, anchor markers, and preview ghosts against light and dark artwork.
|
||||
- [ ] Check text contrast and state distinction with a contrast measurement and color-vision simulation; the current specs do not provide measured results.
|
||||
- [ ] Repeat the checks with emoji rendering unavailable or replaced; action meaning must remain clear from text.
|
||||
|
||||
## 8. Recommended additional coverage
|
||||
|
||||
To make this guide a stronger long-term design reference, add these pieces as the editor UI evolves:
|
||||
|
||||
1. **Annotated screenshots at canonical window sizes.** Include each editor's initial screen, every mode, selection/reshape states, Attach preview, and one modal. Mark which visuals are current and which are target.
|
||||
2. **A theme ownership map.** Document how `SandboxTheme`, `EditorVisualTheme`, and `PropTheme` divide Stage UI, shared editor chrome, and Prop domain/canvas values. Note intentional overrides and identify any remaining editor chrome that bypasses its shared token.
|
||||
3. **Responsive breakpoints and minimum workspace sizes.** Record minimum usable canvas/inspector widths, when controls wrap, how the Attach preview stacks, and how the two Stickman body-panel columns share space with the Whole Stickman preview.
|
||||
4. **Accessibility and contrast acceptance checks.** Specify contrast targets, keyboard tab order, focus visibility, touch target checks, color-vision-safe cues, and high-font-size behavior. The current references provide useful states and target sizes but do not establish a measured accessibility audit.
|
||||
5. **Motion and sound rules.** Define when transitions, selection flashes, save feedback, and error feedback animate or use sound; keep them brief, informative, and respectful of reduced-motion preferences.
|
||||
6. **Content and localization rules.** Include label length budgets, wrapping/truncation behavior, tooltip standards, pluralization, and translation expansion checks.
|
||||
7. **Editor-specific control patterns.** Document mode bars, drawing canvases, color pickers, anchor lists, selection gizmos, empty states, and destructive file flows as reusable examples with their owning state and signals.
|
||||
8. **Verification matrix.** Link each visual contract to a scene/test/manual check so future changes can distinguish an implemented pattern from a recommendation.
|
||||
|
||||
## 9. Reference files
|
||||
|
||||
- [AGENTS.md](../../AGENTS.md) — repository layout, editor architecture, shared Stage UI, and child-facing dialog guardrails.
|
||||
- [Stage panel UI system](../specs/stage_panel_ui_system.md) — Stage inspector card, transient capture bar, component contracts, fitting, and acceptance criteria.
|
||||
- [Dialog Design Principles](../specs/dialog_design_principles.md) — child-facing modal shell, action hierarchy, and stable resize behavior.
|
||||
- [SandboxTheme implementation](../../scripts/stage/sandbox_theme.gd) and [SandboxTheme config](../../sandbox_theme.json).
|
||||
- [PropTheme implementation](../../scripts/editors/prop/prop_theme.gd) and [PropTheme config](../../prop_theme.json).
|
||||
- [Prop Editor controller](../../scripts/editors/prop/prop_editor.gd), [Prop Editor scene](../../scenes/editors/prop/prop_editor.tscn), and [Prop Editor guide](prop_editor_user_guide.md).
|
||||
- [Prop canvas](../../scripts/editors/prop/prop_canvas.gd) — mode behavior, canvas gestures, selection handles, and context menus.
|
||||
- [Stickman Editor controller](../../scripts/editors/stickman/stickman_editor.gd), [Stickman Editor scene](../../scenes/editors/stickman/stickman_editor.tscn), [BodyPartPanel](../../scripts/editors/stickman/body_part_panel.gd), and [Whole Stickman preview](../../scripts/editors/stickman/whole_stickman_preview.gd).
|
||||
- [Stage dialog style helper](../../scripts/shared/stage_ui/stage_dialog_styler.gd) and [Stage capture bar](../../scripts/editors/stage/stage_use_target_capture_bar.gd).
|
||||
- [Prop Editor UX specification](../specs/phase_9c_prop_editor_ux.md) — current approved Prop Editor mode, Attach preview, marker, and layout behavior.
|
||||
|
||||
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
@@ -0,0 +1,191 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1800" height="1260" viewBox="0 0 1800 1260" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Editor visual harmonization: three design directions</title>
|
||||
<desc id="desc">A comparison board showing Familiar Studio, Adaptive Studio, and Focused Maker concepts for the Prop and Stickman Editors.</desc>
|
||||
<defs>
|
||||
<style>
|
||||
.bg { fill: #171b24; }
|
||||
.card { fill: #202633; stroke: #465064; stroke-width: 2; }
|
||||
.card-rec { fill: #202b39; stroke: #22c6ff; stroke-width: 3; }
|
||||
.surface { fill: #252b38; stroke: #596477; stroke-width: 1.5; }
|
||||
.work { fill: #171d28; stroke: #657184; stroke-width: 1.5; }
|
||||
.canvas { fill: #20232b; stroke: #7f8ca0; stroke-width: 1.5; }
|
||||
.cyan { fill: #22c6ff; }
|
||||
.cyan-stroke { stroke: #22c6ff; }
|
||||
.blue { fill: #087dba; }
|
||||
.muted { fill: #aab2c0; }
|
||||
.text { fill: #f5f7fa; font-family: Arial, sans-serif; }
|
||||
.small { font-size: 17px; }
|
||||
.body { font-size: 20px; }
|
||||
.label { font-size: 18px; font-weight: 700; }
|
||||
.h2 { font-size: 30px; font-weight: 700; }
|
||||
.title { font-size: 40px; font-weight: 700; }
|
||||
.chip { fill: #2d3748; stroke: #596477; stroke-width: 1; }
|
||||
.active-chip { fill: #103b4c; stroke: #22c6ff; stroke-width: 2; }
|
||||
.line { stroke: #667286; stroke-width: 1.5; }
|
||||
.accent-line { stroke: #22c6ff; stroke-width: 3; }
|
||||
.selected { fill: none; stroke: #22c6ff; stroke-width: 3; }
|
||||
.outline { fill: none; stroke: #f5f7fa; stroke-width: 2; }
|
||||
.figure { fill: none; stroke: #aab2c0; stroke-width: 4; stroke-linecap: round; }
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="bg" width="1800" height="1260"/>
|
||||
<text class="text title" x="48" y="62">Two editors, one visual language</text>
|
||||
<text class="text body muted" x="48" y="98">Phase 0a · Three layout directions · Shared tokens and accessible states in every option</text>
|
||||
|
||||
<!-- Concept A -->
|
||||
<g transform="translate(42,132)">
|
||||
<rect class="card" width="556" height="1080" rx="20"/>
|
||||
<text class="text h2" x="26" y="46">A. Familiar Studio</text>
|
||||
<text class="text small muted" x="26" y="76">Keep today’s workspace arrangement</text>
|
||||
<rect class="chip" x="26" y="94" width="176" height="34" rx="17"/>
|
||||
<text class="text label small" x="42" y="117">LOWEST CHANGE</text>
|
||||
|
||||
<text class="text label" x="26" y="166">PROP EDITOR · WIDE</text>
|
||||
<rect class="surface" x="26" y="180" width="504" height="260" rx="12"/>
|
||||
<rect class="surface" x="36" y="190" width="484" height="38" rx="8"/>
|
||||
<text class="text small" x="48" y="215">File Save <tspan fill="#aab2c0">Unsaved changes</tspan></text>
|
||||
<rect class="active-chip" x="319" y="197" width="82" height="26" rx="13"/>
|
||||
<text class="text small" x="330" y="216">Arrange</text>
|
||||
<rect class="chip" x="405" y="197" width="68" height="26" rx="13"/>
|
||||
<text class="text small" x="415" y="216">Reshape</text>
|
||||
<rect class="chip" x="477" y="197" width="36" height="26" rx="13"/>
|
||||
<text class="text small" x="484" y="216">…</text>
|
||||
<rect class="canvas" x="36" y="237" width="322" height="192" rx="8"/>
|
||||
<path class="figure" d="M196 278 L196 363 M196 297 L151 337 M196 297 L242 337 M196 363 L163 406 M196 363 L230 406"/>
|
||||
<circle class="selected" cx="196" cy="278" r="16"/>
|
||||
<rect class="surface" x="368" y="237" width="152" height="192" rx="8"/>
|
||||
<text class="text small" x="381" y="263">Inspector</text>
|
||||
<rect class="chip" x="380" y="275" width="128" height="34" rx="7"/>
|
||||
<text class="text small" x="393" y="298">Fill color</text>
|
||||
<rect class="chip" x="380" y="317" width="128" height="34" rx="7"/>
|
||||
<text class="text small" x="393" y="340">Outline</text>
|
||||
<rect class="blue" x="380" y="365" width="128" height="42" rx="9"/>
|
||||
<text class="text small" x="403" y="392">Add Shape</text>
|
||||
|
||||
<text class="text label" x="26" y="484">STICKMAN EDITOR · WIDE</text>
|
||||
<rect class="surface" x="26" y="498" width="504" height="330" rx="12"/>
|
||||
<rect class="surface" x="36" y="508" width="484" height="35" rx="8"/>
|
||||
<text class="text small" x="48" y="532">File Save View <tspan fill="#aab2c0">Saved</tspan></text>
|
||||
<rect class="work" x="36" y="552" width="148" height="264" rx="8"/>
|
||||
<rect class="work" x="194" y="552" width="148" height="264" rx="8"/>
|
||||
<rect class="work" x="352" y="552" width="158" height="264" rx="8"/>
|
||||
<text class="text small" x="48" y="577">Head · Torso</text>
|
||||
<text class="text small" x="206" y="577">Arms · Legs</text>
|
||||
<text class="text small" x="364" y="577">Whole Stickman</text>
|
||||
<g fill="#252b38" stroke="#586477">
|
||||
<rect x="46" y="591" width="58" height="62" rx="6"/><rect x="113" y="591" width="58" height="62" rx="6"/>
|
||||
<rect x="46" y="662" width="58" height="62" rx="6"/><rect x="113" y="662" width="58" height="62" rx="6"/>
|
||||
<rect x="46" y="733" width="58" height="62" rx="6"/><rect x="113" y="733" width="58" height="62" rx="6"/>
|
||||
<rect x="204" y="591" width="58" height="62" rx="6"/><rect x="271" y="591" width="58" height="62" rx="6"/>
|
||||
<rect x="204" y="662" width="58" height="62" rx="6"/><rect x="271" y="662" width="58" height="62" rx="6"/>
|
||||
</g>
|
||||
<rect class="selected" x="45" y="590" width="60" height="64" rx="7"/>
|
||||
<path class="figure" d="M431 603 L431 708 M431 623 L405 651 M431 623 L457 651 M431 708 L411 760 M431 708 L451 760"/>
|
||||
<text class="text small muted" x="26" y="858">Update styling, targets, focus, and dialogs;</text>
|
||||
<text class="text small muted" x="26" y="882">keep all ten drawing panels visible.</text>
|
||||
|
||||
<line class="line" x1="26" y1="918" x2="530" y2="918"/>
|
||||
<text class="text label" x="26" y="955">Tradeoff</text>
|
||||
<text class="text body" x="26" y="986">Least workflow change. The ten small canvases</text>
|
||||
<text class="text body" x="26" y="1014">stay dense; narrow windows may hide the preview.</text>
|
||||
</g>
|
||||
|
||||
<!-- Concept B -->
|
||||
<g transform="translate(622,132)">
|
||||
<rect class="card-rec" width="556" height="1080" rx="20"/>
|
||||
<text class="text h2" x="26" y="46">B. Adaptive Studio</text>
|
||||
<text class="text small muted" x="26" y="76">Keep overview; add a workspace that can grow</text>
|
||||
<rect class="active-chip" x="26" y="94" width="198" height="34" rx="17"/>
|
||||
<text class="text label small" x="42" y="117">RECOMMENDED</text>
|
||||
|
||||
<text class="text label" x="26" y="166">PROP EDITOR · WIDE</text>
|
||||
<rect class="surface" x="26" y="180" width="504" height="220" rx="12"/>
|
||||
<rect class="surface" x="36" y="190" width="484" height="38" rx="8"/>
|
||||
<text class="text small" x="48" y="215">File Save <tspan fill="#aab2c0">Saved</tspan></text>
|
||||
<rect class="active-chip" x="312" y="197" width="82" height="26" rx="13"/>
|
||||
<text class="text small" x="323" y="216">Arrange</text>
|
||||
<rect class="chip" x="398" y="197" width="68" height="26" rx="13"/>
|
||||
<text class="text small" x="408" y="216">Reshape</text>
|
||||
<rect class="chip" x="470" y="197" width="42" height="26" rx="13"/>
|
||||
<text class="text small" x="478" y="216">Attach</text>
|
||||
<rect class="canvas" x="36" y="237" width="318" height="152" rx="8"/>
|
||||
<path class="figure" d="M192 265 L192 337 M192 281 L154 312 M192 281 L230 312 M192 337 L164 375 M192 337 L221 375"/>
|
||||
<circle class="selected" cx="192" cy="265" r="14"/>
|
||||
<rect class="surface" x="364" y="237" width="156" height="152" rx="8"/>
|
||||
<text class="text small" x="376" y="263">Scroll settings</text>
|
||||
<rect class="chip" x="376" y="276" width="132" height="30" rx="7"/>
|
||||
<rect class="chip" x="376" y="314" width="132" height="30" rx="7"/>
|
||||
<rect class="blue" x="376" y="352" width="132" height="28" rx="7"/>
|
||||
<text class="text small" x="399" y="372">Add Shape</text>
|
||||
|
||||
<text class="text label" x="26" y="446">STICKMAN · FOCUS ON PART</text>
|
||||
<rect class="surface" x="26" y="460" width="504" height="354" rx="12"/>
|
||||
<rect class="surface" x="36" y="470" width="484" height="36" rx="8"/>
|
||||
<text class="text small" x="48" y="495">File Save <tspan fill="#aab2c0">Unsaved changes</tspan></text>
|
||||
<rect class="chip" x="36" y="514" width="224" height="34" rx="8"/>
|
||||
<text class="text small" x="95" y="537">Overview · 10 parts</text>
|
||||
<rect class="active-chip" x="268" y="514" width="252" height="34" rx="8"/>
|
||||
<text class="text small" x="330" y="537">Focus on Part</text>
|
||||
<rect class="active-chip" x="36" y="556" width="484" height="38" rx="8"/>
|
||||
<text class="text label" x="51" y="581">Body part: Head ▾</text>
|
||||
<rect class="canvas" x="36" y="602" width="294" height="170" rx="8"/>
|
||||
<text class="text small muted" x="50" y="625">Head drawing canvas</text>
|
||||
<circle class="outline" cx="181" cy="688" r="43"/>
|
||||
<circle class="selected" cx="181" cy="688" r="48"/>
|
||||
<rect class="surface" x="340" y="602" width="180" height="170" rx="8"/>
|
||||
<text class="text small" x="354" y="627">Whole Stickman</text>
|
||||
<path class="figure" d="M430 643 L430 707 M430 656 L410 674 M430 656 L450 674 M430 707 L414 750 M430 707 L446 750"/>
|
||||
<rect class="surface" x="36" y="780" width="484" height="26" rx="8"/>
|
||||
<text class="text small" x="48" y="800">Add Shape Arrange Reshape Color + Future tools</text>
|
||||
|
||||
<text class="text small muted" x="26" y="848">Overview keeps all ten panels available; Focus makes</text>
|
||||
<text class="text small muted" x="26" y="874">room for new tools and is useful at any window size.</text>
|
||||
<line class="line" x1="26" y1="918" x2="530" y2="918"/>
|
||||
<text class="text label" x="26" y="955">Tradeoff</text>
|
||||
<text class="text body" x="26" y="986">More workspace and state work; switching views</text>
|
||||
<text class="text body" x="26" y="1014">must preserve selection and drawing context.</text>
|
||||
</g>
|
||||
|
||||
<!-- Concept C -->
|
||||
<g transform="translate(1202,132)">
|
||||
<rect class="card" width="556" height="1080" rx="20"/>
|
||||
<text class="text h2" x="26" y="46">C. Focused Maker</text>
|
||||
<text class="text small muted" x="26" y="76">Make one task and canvas the center of both editors</text>
|
||||
<rect class="chip" x="26" y="94" width="205" height="34" rx="17"/>
|
||||
<text class="text label small" x="42" y="117">LARGEST REDESIGN</text>
|
||||
|
||||
<text class="text label" x="26" y="166">ONE SHARED WORKSPACE PATTERN</text>
|
||||
<rect class="surface" x="26" y="180" width="504" height="552" rx="12"/>
|
||||
<rect class="surface" x="36" y="190" width="484" height="38" rx="8"/>
|
||||
<text class="text small" x="48" y="215">File Save <tspan fill="#aab2c0">Saved</tspan></text>
|
||||
<rect class="surface" x="36" y="238" width="484" height="50" rx="8"/>
|
||||
<text class="text label" x="52" y="270">Choose task or body part ▾</text>
|
||||
<rect class="canvas" x="36" y="298" width="318" height="338" rx="8"/>
|
||||
<text class="text small muted" x="51" y="324">Large active canvas</text>
|
||||
<path class="figure" d="M195 382 L195 500 M195 405 L151 444 M195 405 L239 444 M195 500 L160 570 M195 500 L230 570"/>
|
||||
<circle class="selected" cx="195" cy="382" r="26"/>
|
||||
<rect class="surface" x="364" y="298" width="156" height="338" rx="8"/>
|
||||
<text class="text small" x="377" y="325">For this task</text>
|
||||
<rect class="chip" x="376" y="340" width="132" height="39" rx="7"/>
|
||||
<text class="text small" x="389" y="366">Color</text>
|
||||
<rect class="chip" x="376" y="388" width="132" height="39" rx="7"/>
|
||||
<text class="text small" x="389" y="414">Shape</text>
|
||||
<rect class="blue" x="376" y="440" width="132" height="42" rx="8"/>
|
||||
<text class="text small" x="392" y="467">Add Shape</text>
|
||||
<rect class="chip" x="376" y="492" width="132" height="39" rx="7"/>
|
||||
<text class="text small" x="389" y="518">Erase Shape</text>
|
||||
<rect class="active-chip" x="36" y="646" width="484" height="72" rx="9"/>
|
||||
<text class="text label" x="53" y="675">Preview drawer</text>
|
||||
<text class="text small" x="53" y="702">Whole Stickman · Attach preview · Open</text>
|
||||
|
||||
<text class="text small muted" x="26" y="770">The same task-first frame in Prop and Stickman.</text>
|
||||
<text class="text small muted" x="26" y="796">The preview opens only when needed.</text>
|
||||
<line class="line" x1="26" y1="918" x2="530" y2="918"/>
|
||||
<text class="text label" x="26" y="955">Tradeoff</text>
|
||||
<text class="text body" x="26" y="986">Strongest focus and consistency, but most users</text>
|
||||
<text class="text body" x="26" y="1014">must relearn navigation; all ten parts are no</text>
|
||||
<text class="text body" x="26" y="1042">longer visible at once.</text>
|
||||
</g>
|
||||
|
||||
<text class="text small muted" x="48" y="1240">For discussion only · Palette and labels follow the Editor Visual Style Guide; this is not final UI styling.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,78 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="1000" viewBox="0 0 1600 1000">
|
||||
<defs>
|
||||
<pattern id="grid" width="64" height="64" patternUnits="userSpaceOnUse">
|
||||
<path d="M64 0H0V64" fill="none" stroke="#FFFFFF" stroke-opacity=".055" stroke-width="1"/>
|
||||
</pattern>
|
||||
<linearGradient id="sky" x2="0" y2="1"><stop stop-color="#626E7E"/><stop offset="1" stop-color="#D3DEE5"/></linearGradient>
|
||||
<linearGradient id="day" x2="0" y2="1"><stop stop-color="#52ADE8"/><stop offset="1" stop-color="#DFF5FF"/></linearGradient>
|
||||
<linearGradient id="room" x2="0" y2="1"><stop stop-color="#DAD0B7"/><stop offset="1" stop-color="#F4E8CF"/></linearGradient>
|
||||
</defs>
|
||||
<rect width="1600" height="1000" fill="#2A313B"/>
|
||||
<rect width="1600" height="1000" fill="url(#grid)"/>
|
||||
<rect x="84" y="54" width="1432" height="892" rx="30" fill="#202735" stroke="#566173" stroke-width="2"/>
|
||||
<text x="136" y="123" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="42" font-weight="700">Choose a starter scene</text>
|
||||
<text x="137" y="160" fill="#AEB8C8" font-family="Arial, sans-serif" font-size="21">Pick a place to begin. You can change the background later.</text>
|
||||
|
||||
<!-- Plain Background card -->
|
||||
<g>
|
||||
<rect x="134" y="190" width="638" height="302" rx="16" fill="#171C25" stroke="#22C6FF" stroke-width="4"/>
|
||||
<rect x="146" y="202" width="614" height="170" rx="10" fill="#F5EFE0"/>
|
||||
<rect x="146" y="202" width="614" height="170" rx="10" fill="none" stroke="#FFFFFF" stroke-opacity=".35" stroke-width="2"/>
|
||||
<text x="453" y="416" text-anchor="middle" fill="#F8FAFC" font-family="Arial, sans-serif" font-size="28" font-weight="700">Plain Background</text>
|
||||
<text x="453" y="449" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="20">An empty stage with one color.</text>
|
||||
<text x="453" y="476" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="20">Choose a new color whenever you like.</text>
|
||||
</g>
|
||||
|
||||
<!-- Open Sky card -->
|
||||
<g>
|
||||
<rect x="798" y="190" width="638" height="302" rx="16" fill="#171C25" stroke="#465061" stroke-width="2"/>
|
||||
<rect x="810" y="202" width="614" height="170" rx="10" fill="url(#sky)"/>
|
||||
<circle cx="1286" cy="250" r="22" fill="#FFF0A2" stroke="#FFE27A" stroke-width="6"/>
|
||||
<g fill="#F7FBFF" stroke="#DCE7F0" stroke-width="3">
|
||||
<ellipse cx="921" cy="275" rx="37" ry="15"/><circle cx="902" cy="268" r="15"/><circle cx="925" cy="261" r="19"/><circle cx="946" cy="271" r="14"/>
|
||||
<ellipse cx="1115" cy="316" rx="39" ry="14"/><circle cx="1094" cy="309" r="14"/><circle cx="1117" cy="302" r="18"/><circle cx="1140" cy="313" r="13"/>
|
||||
</g>
|
||||
<text x="1117" y="416" text-anchor="middle" fill="#F8FAFC" font-family="Arial, sans-serif" font-size="28" font-weight="700">Open Sky</text>
|
||||
<text x="1117" y="449" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="20">An empty stage with a soft sky.</text>
|
||||
<text x="1117" y="476" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="20">Sun and clouds, ready for your story.</text>
|
||||
</g>
|
||||
|
||||
<!-- Town Street card -->
|
||||
<g>
|
||||
<rect x="134" y="522" width="638" height="302" rx="16" fill="#171C25" stroke="#465061" stroke-width="2"/>
|
||||
<rect x="146" y="534" width="614" height="170" rx="10" fill="url(#day)"/>
|
||||
<circle cx="695" cy="566" r="17" fill="#FFE99A"/>
|
||||
<g fill="#FFFFFF" stroke="#DCE7F0" stroke-width="2">
|
||||
<ellipse cx="228" cy="574" rx="29" ry="11"/><circle cx="215" cy="568" r="11"/><circle cx="231" cy="563" r="14"/><circle cx="247" cy="572" r="10"/>
|
||||
<ellipse cx="430" cy="600" rx="32" ry="11"/><circle cx="414" cy="594" r="11"/><circle cx="432" cy="588" r="14"/><circle cx="450" cy="598" r="10"/>
|
||||
</g>
|
||||
<rect x="146" y="643" width="614" height="39" fill="#58996B"/>
|
||||
<rect x="146" y="682" width="614" height="22" fill="#5C626A"/>
|
||||
<path d="M322 642L393 586L466 642Z" fill="#D86F58" stroke="#282D35" stroke-width="4"/>
|
||||
<rect x="338" y="642" width="108" height="40" fill="#EAD6AE" stroke="#282D35" stroke-width="4"/>
|
||||
<rect x="373" y="650" width="28" height="32" fill="#55A6D0" stroke="#282D35" stroke-width="3"/>
|
||||
<rect x="394" y="612" width="24" height="27" fill="#68B9E2" stroke="#282D35" stroke-width="3"/>
|
||||
<text x="453" y="752" text-anchor="middle" fill="#F8FAFC" font-family="Arial, sans-serif" font-size="28" font-weight="700">Town Street</text>
|
||||
<text x="453" y="785" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="20">Cloudy sky, shops, trees,</text>
|
||||
<text x="453" y="812" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="20">sidewalk, and road.</text>
|
||||
</g>
|
||||
|
||||
<!-- Living Room card -->
|
||||
<g>
|
||||
<rect x="798" y="522" width="638" height="302" rx="16" fill="#171C25" stroke="#465061" stroke-width="2"/>
|
||||
<rect x="810" y="534" width="614" height="170" rx="10" fill="url(#room)"/>
|
||||
<rect x="810" y="534" width="614" height="67" fill="url(#day)"/>
|
||||
<circle cx="1306" cy="567" r="17" fill="#FFE99A"/>
|
||||
<rect x="1038" y="570" width="103" height="98" fill="#91C5E3" stroke="#704E3D" stroke-width="8"/>
|
||||
<path d="M1089 574V664M1042 620H1137" stroke="#FFF8E9" stroke-width="7"/>
|
||||
<rect x="810" y="676" width="614" height="28" fill="#926545"/>
|
||||
<rect x="876" y="630" width="135" height="54" rx="14" fill="#6D8E67" stroke="#4E5E49" stroke-width="4"/>
|
||||
<rect x="890" y="614" width="107" height="36" rx="12" fill="#7FA17A" stroke="#4E5E49" stroke-width="4"/>
|
||||
<text x="1117" y="752" text-anchor="middle" fill="#F8FAFC" font-family="Arial, sans-serif" font-size="28" font-weight="700">Living Room</text>
|
||||
<text x="1117" y="785" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="20">A cozy room with a window,</text>
|
||||
<text x="1117" y="812" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="20">rug, and furniture.</text>
|
||||
</g>
|
||||
|
||||
<rect x="692" y="864" width="216" height="58" rx="18" fill="#171C25" stroke="#586273" stroke-width="2"/>
|
||||
<text x="800" y="902" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="24" font-weight="700">Close</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 72 KiB |
@@ -0,0 +1,74 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="1000" viewBox="0 0 1600 1000">
|
||||
<defs>
|
||||
<pattern id="grid" width="64" height="64" patternUnits="userSpaceOnUse"><path d="M64 0H0V64" fill="none" stroke="#FFFFFF" stroke-opacity=".055" stroke-width="1"/></pattern>
|
||||
<linearGradient id="clear" x2="0" y2="1"><stop stop-color="#52ADE8"/><stop offset="1" stop-color="#DFF5FF"/></linearGradient>
|
||||
<linearGradient id="cloudy" x2="0" y2="1"><stop stop-color="#72839A"/><stop offset="1" stop-color="#D4E0E4"/></linearGradient>
|
||||
<linearGradient id="sunset" x2="0" y2="1"><stop stop-color="#765A91"/><stop offset=".55" stop-color="#DF8E9A"/><stop offset="1" stop-color="#FFC980"/></linearGradient>
|
||||
<linearGradient id="night" x2="0" y2="1"><stop stop-color="#101A3B"/><stop offset="1" stop-color="#536F97"/></linearGradient>
|
||||
</defs>
|
||||
<rect width="1600" height="1000" fill="#2A313B"/><rect width="1600" height="1000" fill="url(#grid)"/>
|
||||
<rect x="72" y="38" width="1456" height="924" rx="30" fill="#202735" stroke="#566173" stroke-width="2"/>
|
||||
<text x="120" y="102" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="38" font-weight="700">Scenery</text>
|
||||
<rect x="120" y="124" width="230" height="54" rx="16" fill="#12394A" stroke="#22C6FF" stroke-width="3"/>
|
||||
<text x="235" y="160" text-anchor="middle" fill="#F6FAFF" font-family="Arial, sans-serif" font-size="22" font-weight="700">Backgrounds</text>
|
||||
<rect x="365" y="124" width="190" height="54" rx="16" fill="#171C25" stroke="#566173" stroke-width="2"/>
|
||||
<text x="460" y="160" text-anchor="middle" fill="#DCE3EC" font-family="Arial, sans-serif" font-size="22">Artwork</text>
|
||||
<text x="120" y="224" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="25" font-weight="700">Choose the scene background</text>
|
||||
|
||||
<!-- Plain Background -->
|
||||
<g>
|
||||
<rect x="120" y="250" width="420" height="246" rx="16" fill="#171C25" stroke="#22C6FF" stroke-width="4"/>
|
||||
<rect x="132" y="262" width="396" height="157" rx="10" fill="#F5EFE0"/>
|
||||
<rect x="145" y="274" width="165" height="32" rx="12" fill="#12394A" stroke="#22C6FF" stroke-width="2"/>
|
||||
<text x="227" y="297" text-anchor="middle" fill="#F7FBFF" font-family="Arial, sans-serif" font-size="16" font-weight="700">Current background</text>
|
||||
<text x="330" y="458" text-anchor="middle" fill="#F6F8FC" font-family="Arial, sans-serif" font-size="23" font-weight="700">Plain Background</text>
|
||||
</g>
|
||||
|
||||
<!-- Clear Day -->
|
||||
<g>
|
||||
<rect x="590" y="250" width="420" height="246" rx="16" fill="#171C25" stroke="#465061" stroke-width="2"/>
|
||||
<rect x="602" y="262" width="396" height="157" rx="10" fill="url(#clear)"/>
|
||||
<circle cx="910" cy="304" r="23" fill="#FFE99A" stroke="#FFF3BD" stroke-width="5"/>
|
||||
<g fill="#FFFFFF" stroke="#DFEAF1" stroke-width="2"><ellipse cx="714" cy="354" rx="43" ry="14"/><circle cx="694" cy="348" r="13"/><circle cx="717" cy="341" r="18"/><circle cx="741" cy="352" r="12"/></g>
|
||||
<text x="800" y="458" text-anchor="middle" fill="#F6F8FC" font-family="Arial, sans-serif" font-size="23" font-weight="700">Clear Day</text>
|
||||
</g>
|
||||
|
||||
<!-- Cloudy Day -->
|
||||
<g>
|
||||
<rect x="1060" y="250" width="420" height="246" rx="16" fill="#171C25" stroke="#465061" stroke-width="2"/>
|
||||
<rect x="1072" y="262" width="396" height="157" rx="10" fill="url(#cloudy)"/>
|
||||
<g fill="#F8FBFE" stroke="#E2EBF1" stroke-width="2"><ellipse cx="1190" cy="326" rx="42" ry="14"/><circle cx="1170" cy="320" r="14"/><circle cx="1194" cy="312" r="18"/><circle cx="1216" cy="324" r="12"/><ellipse cx="1360" cy="372" rx="42" ry="13"/><circle cx="1342" cy="366" r="12"/><circle cx="1362" cy="358" r="17"/><circle cx="1384" cy="369" r="12"/></g>
|
||||
<text x="1270" y="458" text-anchor="middle" fill="#F6F8FC" font-family="Arial, sans-serif" font-size="23" font-weight="700">Cloudy Day</text>
|
||||
</g>
|
||||
|
||||
<!-- Sunset -->
|
||||
<g>
|
||||
<rect x="120" y="520" width="420" height="220" rx="16" fill="#171C25" stroke="#465061" stroke-width="2"/>
|
||||
<rect x="132" y="532" width="396" height="135" rx="10" fill="url(#sunset)"/>
|
||||
<circle cx="330" cy="623" r="23" fill="#FFE09B"/><path d="M132 640Q330 600 528 640V667H132Z" fill="#5C6D76" opacity=".7"/>
|
||||
<text x="330" y="713" text-anchor="middle" fill="#F6F8FC" font-family="Arial, sans-serif" font-size="23" font-weight="700">Sunset</text>
|
||||
</g>
|
||||
|
||||
<!-- Starry Night -->
|
||||
<g>
|
||||
<rect x="590" y="520" width="420" height="220" rx="16" fill="#171C25" stroke="#465061" stroke-width="2"/>
|
||||
<rect x="602" y="532" width="396" height="135" rx="10" fill="url(#night)"/>
|
||||
<g fill="#FFE8A5"><circle cx="664" cy="563" r="3"/><circle cx="740" cy="604" r="3"/><circle cx="806" cy="555" r="4"/><circle cx="927" cy="580" r="3"/><circle cx="889" cy="635" r="3"/></g>
|
||||
<path d="M875 560a28 28 0 1 0 26 46a22 22 0 1 1-26-46" fill="#FFF0BE"/>
|
||||
<text x="800" y="713" text-anchor="middle" fill="#F6F8FC" font-family="Arial, sans-serif" font-size="23" font-weight="700">Starry Night</text>
|
||||
</g>
|
||||
|
||||
<text x="1060" y="558" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="22" font-weight="700">More backgrounds</text>
|
||||
<rect x="1060" y="578" width="195" height="100" rx="15" fill="#171C25" stroke="#566173" stroke-width="2"/>
|
||||
<rect x="1077" y="596" width="52" height="56" rx="8" fill="#C6A36C" stroke="#E7D0A6" stroke-width="2"/>
|
||||
<path d="M1083 606h40M1083 618h40M1083 630h40M1083 642h40" stroke="#896644" stroke-width="3"/>
|
||||
<text x="1183" y="635" text-anchor="middle" fill="#F6F8FC" font-family="Arial, sans-serif" font-size="19" font-weight="700">Wall panel</text>
|
||||
<rect x="1274" y="578" width="206" height="100" rx="15" fill="#171C25" stroke="#566173" stroke-width="2"/>
|
||||
<rect x="1290" y="596" width="52" height="56" rx="8" fill="#7AA474" stroke="#A5C39C" stroke-width="2"/>
|
||||
<path d="M1297 609h38M1297 622h38M1297 635h38" stroke="#D7E6C5" stroke-width="2" opacity=".7"/>
|
||||
<text x="1402" y="622" text-anchor="middle" fill="#F6F8FC" font-family="Arial, sans-serif" font-size="16" font-weight="700">Background</text>
|
||||
<text x="1402" y="644" text-anchor="middle" fill="#F6F8FC" font-family="Arial, sans-serif" font-size="16" font-weight="700">ground</text>
|
||||
|
||||
<rect x="692" y="874" width="216" height="58" rx="18" fill="#171C25" stroke="#586273" stroke-width="2"/>
|
||||
<text x="800" y="912" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="24" font-weight="700">Close</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 50 KiB |
@@ -0,0 +1,45 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="1000" viewBox="0 0 1600 1000">
|
||||
<defs>
|
||||
<pattern id="grid" width="64" height="64" patternUnits="userSpaceOnUse"><path d="M64 0H0V64" fill="none" stroke="#FFFFFF" stroke-opacity=".055" stroke-width="1"/></pattern>
|
||||
</defs>
|
||||
<rect width="1600" height="1000" fill="#2A313B"/><rect width="1600" height="1000" fill="url(#grid)"/>
|
||||
<rect x="76" y="46" width="1448" height="908" rx="30" fill="#202735" stroke="#566173" stroke-width="2"/>
|
||||
<rect x="116" y="82" width="250" height="54" rx="16" fill="#171C25" stroke="#566173" stroke-width="2"/>
|
||||
<text x="241" y="117" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="21" font-weight="700">‹ Backgrounds</text>
|
||||
<text x="116" y="194" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="38" font-weight="700">Plain Background</text>
|
||||
<text x="118" y="231" fill="#B8C2D0" font-family="Arial, sans-serif" font-size="21">Tap a color to use it on the Stage.</text>
|
||||
|
||||
<text x="120" y="279" fill="#EAF0F8" font-family="Arial, sans-serif" font-size="22" font-weight="700">Preview</text>
|
||||
<rect x="120" y="296" width="1360" height="190" rx="22" fill="#F5EFE0" stroke="#F4F7FB" stroke-width="4"/>
|
||||
|
||||
<rect x="120" y="520" width="310" height="280" rx="18" fill="#171C25" stroke="#3C4656" stroke-width="2"/>
|
||||
<text x="150" y="564" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="22" font-weight="700">Color</text>
|
||||
<rect x="150" y="584" width="68" height="68" rx="12" fill="#F5EFE0" stroke="#22C6FF" stroke-width="4"/>
|
||||
<circle cx="212" cy="646" r="16" fill="#087DBA" stroke="#44CCFF" stroke-width="2"/>
|
||||
<path d="M205 652 L207 646 L215 638 L220 643 L212 651 Z M213 640 L218 645 M205 652 L211 650" fill="none" stroke="#FFFFFF" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<text x="234" y="625" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="23" font-weight="700">#F5EFE0</text>
|
||||
<text x="150" y="696" fill="#AEB8C8" font-family="Arial, sans-serif" font-size="18">Tap swatch to pick a custom color</text>
|
||||
|
||||
<rect x="454" y="520" width="470" height="280" rx="18" fill="#171C25" stroke="#3C4656" stroke-width="2"/>
|
||||
<text x="484" y="564" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="22" font-weight="700">Recently used</text>
|
||||
<g stroke="#DCE3EC" stroke-width="3">
|
||||
<rect x="484" y="590" width="64" height="64" rx="12" fill="#FFB703"/><rect x="560" y="590" width="64" height="64" rx="12" fill="#24B9E8"/>
|
||||
<rect x="636" y="590" width="64" height="64" rx="12" fill="#00A542"/><rect x="712" y="590" width="64" height="64" rx="12" fill="#0798EA"/>
|
||||
<rect x="788" y="590" width="64" height="64" rx="12" fill="#F5EFE0" stroke="#22C6FF" stroke-width="5"/>
|
||||
</g>
|
||||
<g stroke="#DCE3EC" stroke-width="3">
|
||||
<rect x="484" y="682" width="64" height="64" rx="12" fill="#F04C53"/>
|
||||
<rect x="560" y="682" width="64" height="64" rx="12" fill="#A855F7"/>
|
||||
<rect x="636" y="682" width="64" height="64" rx="12" fill="#FFFFFF"/>
|
||||
</g>
|
||||
|
||||
<rect x="948" y="520" width="532" height="280" rx="18" fill="#171C25" stroke="#3C4656" stroke-width="2"/>
|
||||
<text x="978" y="564" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="22" font-weight="700">Colors</text>
|
||||
<g stroke="#DCE3EC" stroke-width="3">
|
||||
<rect x="978" y="590" width="64" height="64" rx="12" fill="#FFFFFF"/><rect x="1054" y="590" width="64" height="64" rx="12" fill="#171717"/>
|
||||
<rect x="1130" y="590" width="64" height="64" rx="12" fill="#22B8E6"/><rect x="1206" y="590" width="64" height="64" rx="12" fill="#FFB703"/>
|
||||
<rect x="1282" y="590" width="64" height="64" rx="12" fill="#2AD67B"/><rect x="1358" y="590" width="64" height="64" rx="12" fill="#F04C53"/>
|
||||
</g>
|
||||
<rect x="670" y="858" width="260" height="62" rx="18" fill="#171C25" stroke="#586273" stroke-width="2"/>
|
||||
<text x="800" y="898" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="22" font-weight="700">Back to Backgrounds</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 72 KiB |
@@ -0,0 +1,49 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="1000" viewBox="0 0 1600 1000">
|
||||
<defs>
|
||||
<pattern id="grid" width="64" height="64" patternUnits="userSpaceOnUse"><path d="M64 0H0V64" fill="none" stroke="#FFFFFF" stroke-opacity=".055" stroke-width="1"/></pattern>
|
||||
<linearGradient id="fieldBase" x1="0" x2="1"><stop stop-color="#F2BF48"/><stop offset="1" stop-color="#F2BF48"/></linearGradient>
|
||||
<linearGradient id="whiteFade" x1="0" x2="1"><stop stop-color="#FFFFFF"/><stop offset="1" stop-color="#FFFFFF" stop-opacity="0"/></linearGradient>
|
||||
<linearGradient id="blackFade" x1="0" y1="0" x2="0" y2="1"><stop stop-color="#000000" stop-opacity="0"/><stop offset="1" stop-color="#000000"/></linearGradient>
|
||||
<linearGradient id="hues" x1="0" y1="0" x2="0" y2="1"><stop stop-color="#FF0000"/><stop offset=".17" stop-color="#FFFF00"/><stop offset=".34" stop-color="#00FF00"/><stop offset=".51" stop-color="#00FFFF"/><stop offset=".68" stop-color="#0000FF"/><stop offset=".84" stop-color="#FF00FF"/><stop offset="1" stop-color="#FF0000"/></linearGradient>
|
||||
</defs>
|
||||
<rect width="1600" height="1000" fill="#2A313B"/><rect width="1600" height="1000" fill="url(#grid)"/>
|
||||
<rect x="175" y="56" width="1250" height="888" rx="30" fill="#202735" stroke="#566173" stroke-width="2"/>
|
||||
<text x="800" y="119" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="40" font-weight="700">Choose background color</text>
|
||||
<text x="230" y="165" fill="#EAF0F8" font-family="Arial, sans-serif" font-size="22" font-weight="700">Preview</text>
|
||||
<rect x="230" y="184" width="1140" height="145" rx="22" fill="#F5EFE0" stroke="#F4F7FB" stroke-width="4"/>
|
||||
|
||||
<!-- saturation and value field -->
|
||||
<rect x="230" y="356" width="890" height="365" rx="10" fill="url(#fieldBase)"/>
|
||||
<rect x="230" y="356" width="890" height="365" rx="10" fill="url(#whiteFade)"/>
|
||||
<rect x="230" y="356" width="890" height="365" rx="10" fill="url(#blackFade)"/>
|
||||
<rect x="230" y="356" width="890" height="365" rx="10" fill="none" stroke="#AEB8C8" stroke-width="2"/>
|
||||
<circle cx="328" cy="412" r="12" fill="none" stroke="#111827" stroke-width="5"/><circle cx="328" cy="412" r="8" fill="none" stroke="#FFFFFF" stroke-width="3"/>
|
||||
|
||||
<!-- hue bar -->
|
||||
<rect x="1144" y="356" width="76" height="365" rx="12" fill="url(#hues)" stroke="#AEB8C8" stroke-width="2"/>
|
||||
<path d="M1136 397H1228" stroke="#10151E" stroke-width="8"/><path d="M1136 397H1228" stroke="#FFFFFF" stroke-width="4"/>
|
||||
|
||||
<!-- mode tabs -->
|
||||
<rect x="230" y="744" width="990" height="56" rx="14" fill="#171C25" stroke="#566173" stroke-width="2"/>
|
||||
<rect x="232" y="746" width="326" height="52" rx="12" fill="#2D3543" stroke="#22C6FF" stroke-width="2"/>
|
||||
<text x="395" y="781" text-anchor="middle" fill="#FFFFFF" font-family="Arial, sans-serif" font-size="21" font-weight="700">RGB</text>
|
||||
<path d="M560 750V795M890 750V795" stroke="#566173" stroke-width="2"/>
|
||||
<text x="725" y="781" text-anchor="middle" fill="#DAE1EA" font-family="Arial, sans-serif" font-size="21">HSV</text>
|
||||
<text x="1055" y="781" text-anchor="middle" fill="#DAE1EA" font-family="Arial, sans-serif" font-size="21">Linear</text>
|
||||
|
||||
<!-- selected value -->
|
||||
<rect x="1245" y="356" width="125" height="365" rx="16" fill="#171C25" stroke="#3C4656" stroke-width="2"/>
|
||||
<text x="1307" y="391" text-anchor="middle" fill="#AEB8C8" font-family="Arial, sans-serif" font-size="16">COLOR</text>
|
||||
<rect x="1268" y="416" width="79" height="79" rx="14" fill="#F5EFE0" stroke="#22C6FF" stroke-width="3"/>
|
||||
<text x="1307" y="531" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="16">Hex</text>
|
||||
<rect x="1260" y="546" width="94" height="44" rx="9" fill="#252D3A" stroke="#657184" stroke-width="2"/>
|
||||
<text x="1307" y="575" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="18">F5EFE0</text>
|
||||
<text x="1307" y="634" text-anchor="middle" fill="#AEB8C8" font-family="Arial, sans-serif" font-size="15">R 245</text>
|
||||
<text x="1307" y="662" text-anchor="middle" fill="#AEB8C8" font-family="Arial, sans-serif" font-size="15">G 239</text>
|
||||
<text x="1307" y="690" text-anchor="middle" fill="#AEB8C8" font-family="Arial, sans-serif" font-size="15">B 224</text>
|
||||
|
||||
<rect x="835" y="850" width="230" height="62" rx="18" fill="#171C25" stroke="#586273" stroke-width="2"/>
|
||||
<text x="950" y="890" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="22" font-weight="700">Back</text>
|
||||
<rect x="1085" y="850" width="285" height="62" rx="18" fill="#087DBA" stroke="#44CCFF" stroke-width="3"/>
|
||||
<text x="1227" y="890" text-anchor="middle" fill="#FFFFFF" font-family="Arial, sans-serif" font-size="22" font-weight="700">Use color</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 137 KiB |
@@ -0,0 +1,92 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1800" height="1200" viewBox="0 0 1800 1200">
|
||||
<defs>
|
||||
<pattern id="grid" width="64" height="64" patternUnits="userSpaceOnUse">
|
||||
<path d="M64 0H0V64" fill="none" stroke="#FFFFFF" stroke-opacity=".055" stroke-width="1"/>
|
||||
</pattern>
|
||||
<linearGradient id="open-sky" x2="0" y2="1"><stop stop-color="#626E7E"/><stop offset="1" stop-color="#D3DEE5"/></linearGradient>
|
||||
<linearGradient id="town-sky" x2="0" y2="1"><stop stop-color="#52ADE8"/><stop offset="1" stop-color="#DFF5FF"/></linearGradient>
|
||||
<linearGradient id="room-wall" x2="0" y2="1"><stop stop-color="#E6DABD"/><stop offset="1" stop-color="#F4E8CF"/></linearGradient>
|
||||
<clipPath id="plain-clip"><rect x="134" y="198" width="742" height="276" rx="12"/></clipPath>
|
||||
<clipPath id="sky-clip"><rect x="924" y="198" width="742" height="276" rx="12"/></clipPath>
|
||||
<clipPath id="town-clip"><rect x="134" y="638" width="742" height="276" rx="12"/></clipPath>
|
||||
<clipPath id="room-clip"><rect x="924" y="638" width="742" height="276" rx="12"/></clipPath>
|
||||
</defs>
|
||||
|
||||
<rect width="1800" height="1200" fill="#2A313B"/>
|
||||
<rect width="1800" height="1200" fill="url(#grid)"/>
|
||||
<rect x="65" y="35" width="1670" height="1130" rx="30" fill="#202735" stroke="#566173" stroke-width="2"/>
|
||||
<text x="122" y="111" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="46" font-weight="700">Choose a starter scene</text>
|
||||
<text x="124" y="151" fill="#AEB8C8" font-family="Arial, sans-serif" font-size="23">Pick a place to begin. You can change the background later.</text>
|
||||
|
||||
<!-- The larger cards devote almost twice the original area to the scene preview. -->
|
||||
<rect x="120" y="184" width="770" height="418" rx="20" fill="#171C25" stroke="#22C6FF" stroke-width="4"/>
|
||||
<rect x="910" y="184" width="770" height="418" rx="20" fill="#171C25" stroke="#596474" stroke-width="2"/>
|
||||
<rect x="120" y="624" width="770" height="418" rx="20" fill="#171C25" stroke="#596474" stroke-width="2"/>
|
||||
<rect x="910" y="624" width="770" height="418" rx="20" fill="#171C25" stroke="#596474" stroke-width="2"/>
|
||||
|
||||
<g clip-path="url(#plain-clip)">
|
||||
<rect x="134" y="198" width="742" height="276" fill="#F5EFE0"/>
|
||||
</g>
|
||||
<rect x="134" y="198" width="742" height="276" rx="12" fill="none" stroke="#FFFFFF" stroke-opacity=".38" stroke-width="2"/>
|
||||
|
||||
<g clip-path="url(#sky-clip)">
|
||||
<rect x="924" y="198" width="742" height="276" fill="url(#open-sky)"/>
|
||||
<circle cx="1525" cy="267" r="26" fill="#FFF1A8" stroke="#FFE27A" stroke-width="7"/>
|
||||
<g fill="#F7FBFF" stroke="#DBE6EF" stroke-width="3">
|
||||
<ellipse cx="1042" cy="297" rx="49" ry="19"/><circle cx="1014" cy="287" r="20"/><circle cx="1043" cy="278" r="25"/><circle cx="1077" cy="291" r="20"/>
|
||||
<ellipse cx="1342" cy="365" rx="53" ry="18"/><circle cx="1312" cy="355" r="20"/><circle cx="1343" cy="345" r="25"/><circle cx="1378" cy="358" r="19"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<g clip-path="url(#town-clip)">
|
||||
<rect x="134" y="638" width="742" height="276" fill="url(#town-sky)"/>
|
||||
<circle cx="781" cy="699" r="24" fill="#FFE99A"/>
|
||||
<g fill="#FFFFFF" stroke="#DCE7F0" stroke-width="3">
|
||||
<ellipse cx="245" cy="707" rx="43" ry="16"/><circle cx="222" cy="699" r="17"/><circle cx="249" cy="690" r="21"/><circle cx="277" cy="704" r="15"/>
|
||||
<ellipse cx="532" cy="737" rx="39" ry="14"/><circle cx="511" cy="730" r="15"/><circle cx="534" cy="721" r="19"/><circle cx="558" cy="733" r="14"/>
|
||||
</g>
|
||||
<rect x="134" y="823" width="742" height="47" fill="#5D9D70"/>
|
||||
<rect x="134" y="870" width="742" height="44" fill="#575F68"/>
|
||||
<path d="M329 820L432 728L534 820Z" fill="#D8705A" stroke="#28313A" stroke-width="5"/>
|
||||
<rect x="349" y="820" width="166" height="51" fill="#E8D4AC" stroke="#28313A" stroke-width="5"/>
|
||||
<rect x="415" y="834" width="39" height="37" fill="#58A7D4" stroke="#28313A" stroke-width="4"/>
|
||||
<rect x="461" y="769" width="33" height="40" fill="#71BBDC" stroke="#28313A" stroke-width="4"/>
|
||||
<path d="M647 821V746" stroke="#594D3B" stroke-width="12"/>
|
||||
<circle cx="647" cy="738" r="48" fill="#4F9B67" stroke="#336D4C" stroke-width="5"/>
|
||||
</g>
|
||||
|
||||
<g clip-path="url(#room-clip)">
|
||||
<rect x="924" y="638" width="742" height="276" fill="url(#room-wall)"/>
|
||||
<rect x="924" y="638" width="742" height="74" fill="url(#town-sky)"/>
|
||||
<circle cx="1576" cy="680" r="23" fill="#FFE99A"/>
|
||||
<rect x="1232" y="677" width="150" height="141" fill="#91C5E3" stroke="#704E3D" stroke-width="10"/>
|
||||
<path d="M1307 683V812M1238 747H1376" stroke="#FFF8E9" stroke-width="8"/>
|
||||
<rect x="924" y="866" width="742" height="48" fill="#926545"/>
|
||||
<ellipse cx="1149" cy="865" rx="143" ry="26" fill="#BA7F5B"/>
|
||||
<rect x="1041" y="792" width="226" height="81" rx="18" fill="#6D8E67" stroke="#4E5E49" stroke-width="6"/>
|
||||
<rect x="1061" y="769" width="186" height="57" rx="18" fill="#80A17A" stroke="#4E5E49" stroke-width="6"/>
|
||||
<rect x="1481" y="826" width="88" height="43" rx="6" fill="#C49371" stroke="#654C3E" stroke-width="5"/>
|
||||
<path d="M1524 826V779" stroke="#755A43" stroke-width="6"/>
|
||||
<circle cx="1524" cy="764" r="25" fill="#FFF5DF" stroke="#755A43" stroke-width="5"/>
|
||||
</g>
|
||||
|
||||
<g fill="#F8FAFC" font-family="Arial, sans-serif" text-anchor="middle" font-weight="700" font-size="32">
|
||||
<text x="505" y="521">Plain Background</text>
|
||||
<text x="1295" y="521">Open Sky</text>
|
||||
<text x="505" y="961">Town Street</text>
|
||||
<text x="1295" y="961">Living Room</text>
|
||||
</g>
|
||||
<g fill="#F5F7FA" font-family="Arial, sans-serif" text-anchor="middle" font-size="22">
|
||||
<text x="505" y="558">An empty stage with one color.</text>
|
||||
<text x="505" y="589">Choose a new color whenever you like.</text>
|
||||
<text x="1295" y="558">An empty stage with a soft sky.</text>
|
||||
<text x="1295" y="589">Sun and clouds, ready for your story.</text>
|
||||
<text x="505" y="998">Cloudy sky, shops, trees,</text>
|
||||
<text x="505" y="1029">sidewalk, and road.</text>
|
||||
<text x="1295" y="998">A cozy room with a window,</text>
|
||||
<text x="1295" y="1029">rug, and furniture.</text>
|
||||
</g>
|
||||
|
||||
<rect x="790" y="1077" width="220" height="64" rx="18" fill="#171C25" stroke="#667386" stroke-width="2"/>
|
||||
<text x="900" y="1118" text-anchor="middle" fill="#F5F7FA" font-family="Arial, sans-serif" font-size="26" font-weight="700">Close</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 83 KiB |
@@ -0,0 +1,74 @@
|
||||
# Phase 19 — Background Ground and Wall Color
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified as part of Phase 19. The scenery suite passes **706 checks with 0 failures**. This brief remains the product-level record; runtime contracts are in the linked architecture specification.
|
||||
|
||||
## Goal and audience
|
||||
|
||||
Help a child make a Stage feel like a coherent place. Wall panels need a working color choice, and broad ground visible behind buildings or furniture needs its own decorative surface. A child should be able to make the grassy town backdrop in the reference scene, or an indoor carpeted backdrop, without changing where stickmen can walk.
|
||||
|
||||
The audience is a child arranging scenes in the Sandbox Stage's EDIT mode and then directing or playing them. The distinction remains simple: **Background ground looks like ground; walkable Ground is where stickmen walk.**
|
||||
|
||||
## Desired outcome and story value
|
||||
|
||||
- Make a town green behind its buildings and trees while the ordinary Ground tiles still define the walking route.
|
||||
- Give a room a carpeted background area in a chosen color, or give an outdoor set a concrete backdrop.
|
||||
- Change a painted wall's color and choose a brick or wood color that still looks textured.
|
||||
- Reuse favorite colors across walls and carpet without reconstructing a color in every scene.
|
||||
- Save, reopen, resize, and rearrange these pieces without losing their look or making decorative areas solid.
|
||||
|
||||
## Child flow and behavior
|
||||
|
||||
### Choose and edit wall color
|
||||
|
||||
In **Scenery → Backgrounds → Wall panel**, the child chooses **Paint**, **Brick**, or **Wood**, then chooses a color. Eight recently used colors appear first, newest first, followed by useful preset colors. **More colors…** opens a color dialog with **Use color** and **Cancel**. A confirmed color updates the small finish preview and the Stage placement ghost before the child draws the panel. Cancel restores the prior choice.
|
||||
|
||||
Dragging a rectangle places one wall panel with the chosen finish and color. In **Edit Scenery**, selecting a wall panel exposes **Look** and **Color** in its inspector. A change affects only that panel. The existing move, resize, wall-area erase, and erase-piece behaviors continue to apply.
|
||||
|
||||
Paint uses the chosen color as its main surface. Brick and Wood use it to shift their material palettes while retaining recognizable mortar, grain, shading, and variation. Their default choices should look like believable brick and wood; custom colors remain available for imaginative sets. Preview and placed panel must agree about the result.
|
||||
|
||||
### Draw Background ground
|
||||
|
||||
The **Scenery → Backgrounds** chooser gains **Background ground** immediately after **Wall panel**, with large **Grass**, **Concrete**, and **Carpet** cards. The cards and placement prompt say **“Decorative only · Stickmen don’t walk here.”** The choice is separate from the existing **Ground** palette tool. Carpet has the same recent and preset color choices and **More colors…** flow; confirmed color changes the carpet hue while its fabric detail remains visible.
|
||||
|
||||
The child chooses a look, sees a patterned ghost, drags a rectangle, and releases to place a finite decorative surface. In **Edit Scenery**, that piece can be selected, moved, resized, restyled, recolored where applicable, or erased using the same child-facing model as a wall panel. Broad surfaces must remain easy to select in Edit Scenery without taking ordinary EDIT clicks intended for Ground, Props, or characters.
|
||||
|
||||
Background ground sits above the Sky and behind wall panels, Far and Near scenery artwork, buildings, trees, and walkable Ground. It is fixed scenery in EDIT, DIRECT, and PLAY. It provides no collision, support, navigation, pickup, Use action, or event target. Walkable Ground keeps its existing physics and terrain tools.
|
||||
|
||||
Grass has restrained detail throughout the filled area, so a large green panel reads as grass at normal Stage zoom. Concrete has a distinct surface treatment, and Carpet retains a fabric-like look at chosen colors. Motifs use a stable world scale: resizing reveals or hides more pattern rather than stretching it, and adjoining panels of one look align visibly. Their previews should show the same character as the Stage rendering.
|
||||
|
||||
### Reuse colors
|
||||
|
||||
Wall Paint, Brick, Wood, and Background ground Carpet share one list of **eight recently used colors**, newest first. Choosing a preset or confirming **Use color** puts that color first and removes any duplicate; the list persists in user settings across scenes. Canceling a custom color dialog or its tentative preview does not add a color. The color history is a convenience for choosing future looks; changing it does not recolor existing pieces.
|
||||
|
||||
## Success criteria
|
||||
|
||||
- A child can color a new Paint wall and recolor one selected wall without changing another wall. Brick and Wood respond visibly to color while their material details remain legible.
|
||||
- A child can place a broad Grass backdrop behind a town's buildings, then place ordinary Ground in front. A stickman follows only the walkable Ground during PLAY.
|
||||
- Grass texture remains visible inside a large backdrop at common camera views; Concrete and Carpet are distinguishable in chooser cards and on Stage. A colored Carpet still looks like fabric.
|
||||
- Background ground remains finite and editable. Moving or resizing a piece preserves its motif scale; adjoining matching pieces have aligned motifs.
|
||||
- The eight-color history is shared across the four colorable looks, persists across scenes and restarts, and ignores canceled choices.
|
||||
- Chooser and inspector controls remain reachable on smaller displays, and the visual-only role is clear in words as well as appearance. Save and reopen preserve the pieces, finishes, colors, positions, and visual order.
|
||||
|
||||
## Scope and exclusions
|
||||
|
||||
Included: the missing wall color controls and textured tint behavior; one decorative rectangular Background ground type with Grass, Concrete, and Carpet; Carpet color; shared eight-color history; responsive chooser and selected-piece editing; visual previews; scene persistence and compatibility with existing scenes.
|
||||
|
||||
Excluded: new walkable Ground, Ramp, or Step behavior; changes to navigation or collision; parallax or animated scenery; freehand terrain shapes; user-authored repeatable patterns; automatic horizon blending or edge generation; a general color library beyond the recent list; and a new Scenery file/editor format. The separate [backdrop horizon and edge treatment idea](../ideas/feature_backlog.md) can address deliberate transitions later.
|
||||
|
||||
## Current project fit and references
|
||||
|
||||
The accepted [Phase 19 product plan](phase_19_scenery_backgrounds_surface_finishes.md) and [UI/UX specification](../specs/phase_19_scenery_backgrounds_ui_ux.md) already call for a wall Color choice and for recoloring a selected panel. The present wall data stores a color, but Brick and Wood rendering uses fixed palettes, and the current chooser and selected-wall card do not expose color. This brief closes that visible Phase 19 gap.
|
||||
|
||||
Existing walkable Ground is a `TerrainBlock` with collision and finish drawing. Its Grass motif emphasizes the top edge of the block; it is not the broad interior treatment needed for a distant field. The current semantic draw order places Sky, walls, Far and Near scenery, walkable Ground, floor scenery, and action elements in separate bands. Background ground adds a visual band behind those scene pieces while keeping the Stage's established Scenery selection model.
|
||||
|
||||
Relevant implementation locations for the spec-pipeline to inspect are `scripts/stage/scenery/stage_wall_panel.gd`, `scripts/stage/scenery/stage_surface_renderer.gd`, `scripts/stage/stage_draw_order.gd`, `scripts/terrain/terrain_block.gd`, `scripts/stage/stage_scene_io.gd`, `scripts/editors/stage/stage_scenery_controller.gd`, `scripts/editors/stage/sandbox_stage.gd`, `scripts/editors/stage/stage_asset_browser.gd`, `scripts/shared/ui/asset_selector.gd`, and the shared Stage panel system in `docs/specs/stage_panel_ui_system.md`.
|
||||
|
||||
## Dependencies, risks, and specification questions
|
||||
|
||||
- **Material color:** UI/UX and architecture should define a predictable relationship between the selected hue and each finish's multiple tones. Brick mortar and wood grain must keep enough contrast across very light, dark, or saturated custom colors.
|
||||
- **Layering and overlap:** The recommended order is Sky → Background ground → wall panels → Far art → Near art → walkable Ground → floor art → action. The spec should confirm how a large decorative surface is selected when other scenery covers it and how it behaves in existing multi-piece scenery edits.
|
||||
- **Large areas and zoom:** Repeatable vector detail needs to stay crisp and coherent without becoming visually noisy or costly across a large rectangle. The spec should settle how it previews at card size and at normal and zoomed Stage views.
|
||||
- **Persistence:** Architecture should settle saved identifiers, old-scene defaults, and user-setting storage for the recent colors. The visible history is per user, while each placed piece saves its own color.
|
||||
- **Copy and terminology:** UI/UX should settle the final short label for **Background ground**, the helper wording in chooser and capture bar, and the selected-piece inspector wording. The role distinction from walkable **Ground** must survive narrow screens and keyboard/touch use.
|
||||
|
||||
These are specification questions; the approved child behavior above should remain intact.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Phase 19 handoff
|
||||
|
||||
**Status (2026-10-22): Complete and user/editor verified.** The user verified the integrated Phase 19 behaviors in the editor, including camera-aware Sky details, starter compositions, surface finishes, Plain Background, scenery artwork/depth, furniture behavior, and Plain Background save/reopen. The final `tests/test_phase19_scenery.gd` run passed **706 checks with 0 failures** (Godot exit code 0).
|
||||
|
||||
The implementation provides Sky and Plain Background choices, editable Plain color, wall panels and background ground, inert Scenery artwork with depth and resize controls, Ground finishes, and four editable New Scene starters. Stage-wide Undo/Redo remains deliberately deferred and is tracked as technical debt. No further Phase 19 implementation or user verification is outstanding.
|
||||
|
||||
## Verification record
|
||||
|
||||
- **Automated:** `tests/test_phase19_scenery.gd` — 706 PASS checks, 0 failures, exit code 0, Godot 4.7.1. The run used a temporary Windows Roaming AppData location after the default profile path failed during Godot log initialization. Godot also logged a root-certificate-store warning; it did not affect the suite result.
|
||||
- **User/editor:** The user reports completion of all planned visual and interactive checks across camera-aware Sky, both starter compositions, surface finish resizing/tiling, Plain Background, scenery/artwork, and furniture behavior. The user separately confirmed Plain Background save/reopen. Do not interpret that as a manual save/reopen check for every manifest asset; persistence is additionally covered by automated paths.
|
||||
- **Test command:**
|
||||
|
||||
```powershell
|
||||
& "C:\Godot4\Godot_v4.7.1-stable_win64_console.exe" --headless --path . --script res://tests/test_phase19_scenery.gd
|
||||
```
|
||||
|
||||
## Start here
|
||||
|
||||
- [Phase 19 product plan](phase_19_scenery_backgrounds_surface_finishes.md) — approved scope, starter behavior, asset manifest, and success criteria.
|
||||
- [Phase 19 architecture specification](../specs/phase_19_scenery_backgrounds_surface_finishes.md) — Stage/file contracts, camera-aware Sky, scenery editing, and acceptance routes.
|
||||
- [Phase 19 UI/UX specification](../specs/phase_19_scenery_backgrounds_ui_ux.md) — Stage chooser and interaction behavior.
|
||||
- [Plain Background plan](phase_19_plain_background.md) and [architecture specification](../specs/phase_19_plain_background.md) — solid backdrop, chooser flow, and persistence.
|
||||
- [Starter composition brief](phase_19_starter_scene_composition.md) and [architecture specification](../specs/phase_19_starter_scene_composition.md) — Town Street and Living Room layouts.
|
||||
- [Background Ground and Wall Color brief](phase_19_background_ground_and_wall_color.md) — decorative surfaces and shared color behavior.
|
||||
- [Selected artwork depth specification](../specs/phase_19_selected_artwork_depth_inspector.md) — Far/Near/On the floor inspector behavior.
|
||||
- [Technical debt log](../architecture/tech_debt_and_optimizations.md) — deferred Stage Undo/Redo.
|
||||
|
||||
Phase 19 is complete. Later work should use the linked specifications and keep Stage-wide Undo/Redo in its separate scope.
|
||||
@@ -0,0 +1,130 @@
|
||||
# Phase 19 — Plain Background
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified as part of Phase 19. The user explicitly verified Plain Background save/reopen; the Phase 19 scenery suite passes **706 checks with 0 failures**. Detailed presentation and file behavior are specified in the linked Plain Background UI/UX and architecture documents.
|
||||
> **Relationship to Phase 19:** This brief updates only the earlier three-card **File → New** choice and the four-Sky-only **Backgrounds** choice. Other accepted Scenery, starter composition, Sky, Ground, and artwork behavior remains as described in the existing Phase 19 plans and specifications.
|
||||
|
||||
## Goal and audience
|
||||
|
||||
Give a child a genuinely empty Stage and an easy way to choose its background color. The audience is a child starting a scene through **File → New** or changing a scene's look in **EDIT**. A plain color can set a mood for an abstract story, title-like shot, or set built entirely from the child's own Ground, characters, Props, and Scenery.
|
||||
|
||||
The background is a scene-wide visual choice. It fills the camera view in **EDIT**, **DIRECT**, and **PLAY**, without adding a selectable Stage object or changing the colors or behavior of placed pieces.
|
||||
|
||||
## PNG mockups
|
||||
|
||||
**Review status:** The starter and Backgrounds PNGs are user-approved. The color-choices and custom-picker PNGs were revised per user feedback: tapping the current-color chip opens the picker without a separate **More colors** button, and the custom picker shows a simple **Preview** label with no temporary-state helper message. The final mockups were approved and implemented. The production initial color is warm off-white `#F5EFE0`; Plain Background previews use a uniform solid fill. Editable SVG source files sit beside each PNG.
|
||||
|
||||
- [New Scene starter chooser](assets/phase_19_plain_background/01_new_scene.png)
|
||||
- [Larger New Scene chooser proposal](assets/phase_19_plain_background/05_large_starter_chooser.png) — expands the same four cards and gives each preview more room; retain the bounded, scrollable layout on smaller screens.
|
||||
- [Scenery Backgrounds chooser](assets/phase_19_plain_background/02_background_picker.png)
|
||||
- [Plain Background color choices](assets/phase_19_plain_background/03_color_choices.png)
|
||||
- [Custom color picker](assets/phase_19_plain_background/04_custom_color_picker.png)
|
||||
|
||||
## Desired child outcome
|
||||
|
||||
- Start **Plain Background** and see one uninterrupted solid color, with no Sky imagery, Ground, characters, Props, or other placed objects.
|
||||
- Recognize the existing empty starter as **Open Sky**: its current neutral gradient, sun, and clouds remain available.
|
||||
- Find the background color in **EDIT → Scenery → Backgrounds**, beside the Sky choices, and use a familiar color preview, swatches, and picker.
|
||||
- Change between a plain color and a Sky without losing the chosen plain color. Save, reopen, and see the same chosen background.
|
||||
|
||||
## Child flow and feedback
|
||||
|
||||
### File → New
|
||||
|
||||
The existing unsaved-work Save/Discard/Cancel gate runs before the starter chooser. Canceling the chooser leaves the open scene intact. The chooser presents four large illustrated cards; a chosen starter opens as a new, unsaved, editable scene.
|
||||
|
||||
```text
|
||||
┌ Choose a starter scene ───────────────────────────────┐
|
||||
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
||||
│ │ [solid color preview]│ │ [soft sky preview] │ │
|
||||
│ │ Plain Background │ │ Open Sky │ │
|
||||
│ │ An empty stage with │ │ An empty stage with │ │
|
||||
│ │ a color you can pick.│ │ a soft sky. │ │
|
||||
│ └──────────────────────┘ └──────────────────────┘ │
|
||||
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
||||
│ │ [street preview] │ │ [room preview] │ │
|
||||
│ │ Town Street │ │ Living Room │ │
|
||||
│ └──────────────────────┘ └──────────────────────┘ │
|
||||
│ [Close] │
|
||||
└───────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
The **Plain Background** card shows its actual initial solid fill. **Open Sky** is the existing sky-backed empty starter, renamed so its preview and label agree. Town Street and Living Room retain their current compositions and editability. On a narrow screen, cards wrap into one column within a bounded, scrollable chooser; the title and visible Close action remain reachable.
|
||||
|
||||
The initial Plain Background color is **warm off-white `#F5EFE0`**, approved as the starting look. It should read like paper and let typical character and artwork outlines remain visible. The Stage grid and selection outlines need contrast treatment so they remain legible over both light and dark child-selected colors.
|
||||
|
||||
### Change the background in EDIT
|
||||
|
||||
The child opens **Scenery → Backgrounds**. A **Plain Background** choice sits with the four existing Sky presets. The chooser shows which background is current with a clear border and words as well as color; keyboard focus remains visually separate from selection.
|
||||
|
||||
```text
|
||||
┌ Choose Scenery ────────────────────────────────────────┐
|
||||
│ [Backgrounds] [Artwork] │
|
||||
│ Choose the scene background │
|
||||
│ ┌───────────────────┐ ┌────────────┐ ┌────────────┐ │
|
||||
│ │ [saved plain color]│ │ Clear Day │ │ Cloudy Day │ │
|
||||
│ │ Plain Background │ └────────────┘ └────────────┘ │
|
||||
│ │ Current background│ ┌────────────┐ ┌────────────┐ │
|
||||
│ └───────────────────┘ │ Sunset │ │ Starry Night│ │
|
||||
│ └────────────┘ └────────────┘ │
|
||||
│ [Wall panel] [Background ground] │
|
||||
│ [Close] │
|
||||
└───────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Choosing the **Plain Background** card immediately switches the Stage to its remembered plain fill and opens its color choices. This background choice is confirmed at the card tap, just as a Sky card is. The child can close or go Back from the color choices while keeping that fill. Preset and recently used swatches are quick, **confirmed** color choices: tapping one immediately updates the entire Stage, the current-color preview, and recent colors. The current-color chip is a button; tapping it opens the fuller picker. There is no separate **More colors** button.
|
||||
|
||||
The full picker starts from the latest confirmed plain color. Moving its controls gives a tentative preview of the Stage background and the large color sample. **Use color** confirms that custom color, records it in recent colors, and returns to the plain color choices. **Back** or Cancel discards the custom draft, restores the confirmed plain fill from before the picker opened, and returns to the color choices. Back from the color choices returns to Backgrounds without undoing the card or swatch choices. This matches the established distinction between direct swatch selection and a custom-color draft.
|
||||
|
||||
```text
|
||||
┌ Choose background color ──────────────────────────────┐
|
||||
│ Preview: [wide uninterrupted solid color] │
|
||||
│ Current color [■] #F5EFE0 (tap swatch to pick custom)│
|
||||
│ Recently used [■] [■] [■] ... (tap to use now) │
|
||||
│ Colors [■] [■] [■] ... (tap to use now) │
|
||||
│ [‹ Backgrounds] [Close] │
|
||||
└───────────────────────────────────────────────────────┘
|
||||
|
||||
┌ Custom picker · opened from current-color swatch ────┐
|
||||
│ Preview: [wide solid color; Stage previews draft] │
|
||||
│ [color field / sliders] [RGB] [HSV] [Linear] │
|
||||
│ [Back] [Use color] │
|
||||
└───────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Keep the Stage visually undimmed while either Plain Background color view is open, while retaining the transparent, input-blocking modal layer. In the color-choices view, Back and Close stay in the fixed footer; stack them as full-width targets on narrow windows.
|
||||
|
||||
The color views follow the existing rounded Scenery chooser and surface color picker visual language: large preview, readable labels, spacious swatches, visible Back, and a blue **Use color** action for the custom draft. They stay within the safe viewport and scroll their body when needed; changing views preserves the chooser's anchor so the clicked control does not jump. Swatches, cards, and actions have at least 44 × 44 logical-pixel targets and usable keyboard focus. The current choice is identified by text and outline, not color alone. The RGB/HSV/Linear controls are the existing advanced color picker behavior, not a new child-facing color model to teach.
|
||||
|
||||
The four Sky cards retain their current one-tap behavior. Choosing any Sky changes the scene background immediately. The scene remembers its last chosen plain color, so reopening Plain Background starts with that color and allows the child to use it again. Sky and plain color remain visual backdrops: neither appears in Stage object selection, blocks movement, or recolors Ground, walls, scenery artwork, Props, characters, or speech.
|
||||
|
||||
## Story and mechanics considerations
|
||||
|
||||
A child can use a plain color as an open visual canvas or as a deliberate mood. They can place walkable Ground and a cast later, then move the camera without revealing a backdrop edge. Sky remains the choice for a designed outdoor look with clouds, sun, moon, or stars. Switching backgrounds changes appearance alone; it does not alter actions, events, camera controls, physics, or the ordinary editability of starter pieces.
|
||||
|
||||
## Success criteria
|
||||
|
||||
1. **File → New** shows four distinguishable previews and labels: Plain Background, Open Sky, Town Street, and Living Room. Cancel preserves the existing scene; choosing Plain Background opens an unsaved scene with no Ground or placed objects and no Sky imagery.
|
||||
2. A child in EDIT can choose Plain Background under Scenery → Backgrounds and immediately see the remembered fill. Preset/recent swatches apply immediately. In the custom picker, **Use color** confirms the draft, while **Back** or Cancel restores the last confirmed fill.
|
||||
3. The committed color fills every camera view without an edge, gradient, sun, cloud, moon, or star. It remains visually consistent through camera pan/zoom, viewport resize, EDIT/DIRECT/PLAY, and PLAY/stop.
|
||||
4. Switching to any Sky and back restores the scene's chosen plain color. Save/reopen preserves both the active background choice and that remembered color. Previously saved scenes using the neutral Sky keep their established appearance.
|
||||
5. Background changes do not recolor or change the behavior of placed scenery, Ground, Props, characters, or speech. The background never intercepts Stage selection.
|
||||
6. At narrow viewport sizes and with keyboard navigation, the starter cards, Backgrounds choices, color controls, and visible Back/Use/Close actions remain readable and reachable.
|
||||
|
||||
## Scope and exclusions
|
||||
|
||||
**Included:** A new Plain Background starter; the **Open Sky** label for the existing empty sky-backed starter; a scene-wide solid color background choice in EDIT; existing preset/recent swatches and full color picker presentation; clear preview and commit/cancel behavior; remembered plain color across Sky switches; save/reopen support; accurate starter and chooser previews; preservation of existing neutral-Sky scenes.
|
||||
|
||||
**Excluded:** New Sky motifs or customization, gradients or patterns for Plain Background, transparency, animation or directed background transitions, background colors tied to time of day, automatic contrast changes to placed objects, wall/Ground recoloring, new story mechanics, and Stage Undo/Redo. The existing Background ground and wall panels remain finite Scenery surfaces with their own separate color behavior.
|
||||
|
||||
## Current behavior and references
|
||||
|
||||
The current [Phase 19 Scenery brief](phase_19_scenery_backgrounds_surface_finishes.md) and [Scenery UI/UX specification](../specs/phase_19_scenery_backgrounds_ui_ux.md) describe three New Scene cards and four Sky choices; this addition updates those two choice sets only. The [Starter Scene Composition brief](phase_19_starter_scene_composition.md) defines the Town Street and Living Room compositions, which this addition does not revise. Follow the [Dialog Design Principles](../specs/dialog_design_principles.md) for the starter chooser and color flow.
|
||||
|
||||
Today, the [blank starter](../../content/stages/starters/blank.scene) contains no objects and selects `sky_neutral`. The [Sky view](../../scripts/stage/scenery/stage_sky_view.gd) draws that neutral choice as a gray gradient with sun and clouds. The [Stage asset browser](../../scripts/editors/stage/stage_asset_browser.gd) supplies the three starter entries and the four Sky cards; the [Scenery chooser](../../scripts/shared/ui/asset_selector.gd) displays them. Existing [surface color controls](../../scripts/shared/stage_ui/stage_surface_color_controls.gd) and [picker view](../../scripts/shared/stage_ui/stage_surface_color_picker_view.gd) provide a familiar color interaction. The [scene file handler](../../scripts/stage/stage_scene_io.gd) currently validates a saved Sky ID, and the [starter preview](../../scripts/stage/scenery/stage_starter_card_preview.gd) renders it. UI/UX and architecture should account for active background choice, remembered plain color, previews, and older files without changing the appearance of existing `sky_neutral` scenes.
|
||||
|
||||
## Dependencies, risks, and open choices
|
||||
|
||||
- **Grid and selection contrast:** On `#F5EFE0`, current white grid and selection lines have low contrast. The UI/UX specification calls for theme-backed contrasting treatments across light, dark, and saturated backgrounds without recoloring placed artwork.
|
||||
- **Picker navigation:** The current-color chip is the sole entry to the custom picker; its focus/return behavior and the bounded layout are specified in the UI/UX document. The direct swatch, tentative custom preview, **Use color**, and Back/Cancel outcomes above are settled product behavior.
|
||||
- **Previews and persistence:** The starter and Backgrounds cards must reflect the selected plain color, and save/reopen must retain the active choice plus the plain color remembered behind a Sky. Architecture should resolve the file representation and legacy migration without changing older neutral Sky scenes.
|
||||
- **Visual contrast:** A light or dark child-selected background may make some artwork or EDIT overlays harder to see. UI/UX should review selection, grid, mode cues, and speech readability without silently changing the child's chosen artwork colors.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Phase 19 — Scenery, Backgrounds, and Vector Surface Finishes
|
||||
|
||||
> **Status:** Accepted product/design brief. Technical specifications and implementation remain to be developed through the spec-pipeline.
|
||||
> **Status (2026-10-22):** Phase 19 implementation and user/editor verification are complete. The user verified the integrated Sky, starter compositions, surface finishes, Plain Background, Scenery artwork, and furniture behavior in the editor, including Plain Background save/reopen. The Phase 19 scenery suite passes **706 checks with 0 failures**. Stage-wide Undo/Redo remains deferred. The later [Plain Background addendum](phase_19_plain_background.md) adds Plain Background and renames the original neutral-Sky Blank Scene choice **Open Sky**; see the [Phase 19 handoff](phase_19_handoff.md) for the verification record.
|
||||
> **Audience:** UI/UX, architecture, implementation, and art contributors.
|
||||
> **Purpose:** Define the child experience and the content required for indoor and outdoor sets. Rendering, file contracts, and GDScript APIs belong in later specifications.
|
||||
|
||||
@@ -53,10 +53,24 @@ The existing vector Prop Editor and `.prop` assets supply user-created artwork.
|
||||
|
||||
### Choose a Sky
|
||||
|
||||
**Backgrounds → Sky** shows four designed thumbnail cards: **Clear Day**, **Cloudy Day**, **Sunset**, and **Starry Night**. One tap changes the scene's Sky, and choosing another card changes it again. A Sky fills every camera view without an exposed edge; its clouds, sun, moon, and stars remain visually stable and crisp during pan and zoom. Each preset should be a considered composition rather than a flat color with an obvious repeated icon. The Sky remains fixed throughout PLAY.
|
||||
**Backgrounds → Sky** shows four designed thumbnail cards: **Clear Day**, **Cloudy Day**, **Sunset**, and **Starry Night**. One tap changes the scene's Sky, and choosing another card changes it again. A Sky fills every camera view without an exposed edge. Its gradient stays fixed to the screen while its clouds, sun, moon, and stars respond gently to camera pan and zoom as described in the [camera-aware Sky details addendum](#camera-aware-sky-details-addendum). Each preset should be a considered composition rather than a flat color with an obvious repeated icon.
|
||||
|
||||
Changing Sky changes **only the sky**. It never tints or recolors Ground, wall panels, scenery artwork, characters, or Props. Sky is selected through its chooser, not by clicking a giant rectangle on the Stage.
|
||||
|
||||
### Camera-aware Sky details addendum
|
||||
|
||||
**Goal and audience.** A child making an outdoor scene should see a Sky that feels distant without making their Ground and stickman appear to float among oversized clouds. This applies when a child chooses any of the four Phase 19 Sky presets, frames a shot in EDIT or DIRECT, and watches it in PLAY.
|
||||
|
||||
**Child flow.** The child chooses a Sky as before, places walkable Ground and a stickman, then pans or zooms the Stage camera. The Sky gradient continues to fill the entire view. Clouds and celestial details shift gently with camera movement and change size modestly with camera zoom, so the composition feels connected to the shot while staying distant. The child does not set a motion mode, slider, or per-scene option. Switching presets applies that preset's tuned response automatically. The same view is reproduced after saving and reopening the scene at its saved camera framing.
|
||||
|
||||
**Visual behavior.** Each preset keeps its distinctive color and motifs, with detail size and placement tuned to leave clear space around characters and Ground at ordinary framing. Camera response is bounded and smooth: no visible Sky edge, abrupt jump, distracting sweep, or cloud that grows to dominate the action during normal pan and zoom. The gradient remains screen-filling and fixed; only Sky details respond. EDIT, DIRECT, and PLAY use the same camera-relative composition. The chosen Sky remains decorative and never changes the color, collision, or movement of any world object.
|
||||
|
||||
**Horizon and Ground.** The Sky does not draw a horizon or a ground line. A child who wants land behind the playable area uses the existing world-anchored **Background ground** scenery surface, placed behind walkable Ground. This keeps a visible landscape edge aligned with the scene as the camera moves. Softer contours, automatic edge blending, and easier horizon construction remain the separate [backdrop horizon and edge treatment idea](../ideas/feature_backlog.md); this addendum does not define or ship those tools.
|
||||
|
||||
**Success criteria.** At ordinary and representative close/wide camera views, a character on Ground reads as being in front of the Sky rather than inside a cloud. Panning and zooming each preset gives a perceptible but subtle response without revealing an edge or obscuring the action. The same camera framing reproduces the same Sky composition after a mode change, PLAY/stop cycle, or save/reopen, and the composition adapts coherently to a resized viewport. A Background ground surface and walkable Ground stay aligned with each other while Sky details respond behind them. Sky chooser previews still identify the four looks and do not imply that the child must configure camera behavior.
|
||||
|
||||
**Scope and handoff.** This is a Phase 19 visual-behavior addition for the four existing Sky presets. It preserves the existing Sky choice and screen-filling gradient. It excludes autonomous cloud/weather animation, a child-facing motion control, a Sky-ground horizon, multi-layer parallax scenery, and changes to terrain physics or Background ground placement. UI/UX and architecture should resolve how much pan/zoom response is comfortable for each preset and how the view stays composed at viewport extremes. Relevant current references are `scripts/stage/scenery/stage_sky_view.gd`, `scripts/editors/stage/sandbox_stage.gd`, `scripts/stage/scenery/stage_background_ground.gd`, the [Phase 19 Sky UI/UX specification](../specs/phase_19_scenery_backgrounds_ui_ux.md), and the [Background Ground and Wall Color plan](phase_19_background_ground_and_wall_color.md). Those earlier specifications describe the original static behavior and need a focused follow-up before implementation.
|
||||
|
||||
### Draw a wall panel
|
||||
|
||||
**Backgrounds → Wall panel** offers **Paint**, **Brick**, and **Wood** finishes with a color choice. The child chooses a finish, drags from one corner to the other, sees a translucent preview of the intended size and pattern, and releases to place a finite rectangular panel. Snap may help edges meet. A selected panel can later be moved, resized, recolored, restyled, or erased; changing one panel does not silently alter others.
|
||||
@@ -81,7 +95,7 @@ Sky
|
||||
|
||||
Every Scenery tier is visual only. Its depth never grants collision, support, pickup, Use spots, or event participation. An On the floor rug is visible above a wood Ground finish without covering furniture or the character's feet.
|
||||
|
||||
**Edit Scenery** exposes the scenery pieces for selection. A clear outline and large handles let the child move and resize art, change its depth, or erase it; a wall panel also exposes Finish and Color. Broad panels must not steal clicks or box selections from characters, Ground, and Props in ordinary EDIT. Within Edit Scenery, a cutout in front of a panel should be easy to choose, and the panel must still be reachable through its exposed area, edge, or an overlapping-items choice. Sky remains in its own chooser. A visible Cancel closes a placement or sizing gesture before commit, and leaving Edit Scenery returns to ordinary selection. Selection and focus cannot rely on color alone.
|
||||
**Edit Scenery** exposes the scenery pieces for selection. A clear outline and large handles let the child move and resize art, change its depth, or erase it; a wall panel also exposes Finish and Color. Broad panels must not steal clicks or box selections from characters, Ground, and Props in ordinary EDIT. Within Edit Scenery, a cutout in front of a panel should be easy to choose, and the panel must still be reachable through its exposed area, edge, or an overlapping-items choice. A selected wall panel also offers **Erase wall area**: drag a rectangle to remove that area from one or more wall panels while keeping the surrounding pieces and their finish. This is a manual visual cutout; it does not create glass, collision, or doorway behavior. Each released cut is immediate; Cancel/Escape/right-click discard only the current drag, and Stage Undo remains deferred to its own future phase. Sky remains in its own chooser. Placement and group-resize previews have visible Cancel actions. A single-piece move or resize previews during its direct-manipulation gesture and commits on release; while the gesture is active it can be canceled through the capture bar (touch), Escape, or right-click. There is no second Keep confirmation. Leaving Edit Scenery returns to ordinary selection. Selection and focus cannot rely on color alone.
|
||||
|
||||
### Finish Ground and play
|
||||
|
||||
@@ -89,28 +103,30 @@ The existing **Ground** palette entry gains a visual finish chooser. Picture swa
|
||||
|
||||
Ground remains solid and walkable. This phase gives finishes only to **Ground**; it does not redesign or restyle Ramp and Step. Children can use Sidewalk and Asphalt Ground in Town Street and Wood Ground in Living Room. A Scenery wall panel or road marking never becomes a movement surface.
|
||||
|
||||
In **PLAY**, edit handles and placement ghosts disappear. Sky and Scenery stay still; characters move on Ground; Props follow their own saved behavior settings. Stopping PLAY restores the authored arrangement for another take. Story playback and camera movement should preserve the intended visual layer order and the child's view of the action.
|
||||
In **PLAY**, edit handles and placement ghosts disappear. Scenery stays put; Sky details respond gently to camera pan and zoom under the same rules as EDIT and DIRECT. Characters move on Ground; Props follow their own saved behavior settings. Stopping PLAY restores the authored arrangement for another take. Story playback and camera movement should preserve the intended visual layer order and the child's view of the action.
|
||||
|
||||
## Included scope and exclusions
|
||||
|
||||
Included in Phase 19: one fixed scene-wide Sky preset; four initial Sky designs; finite editable wall panels; inert `.prop` Scenery placements with Far, Near, and On the floor depth; built-in multi-select browse tags; Ground-only visual finishes; editable Blank/Town Street/Living Room New Scene choices; Scenery-safe selection; scene save/reopen and legacy defaults; and the built-in vector content listed below.
|
||||
Included in Phase 19: one chosen scene-wide Sky with a screen-filling fixed gradient and gentle automatic camera-aware details; four initial Sky designs; finite editable wall panels with manually erasable rectangular openings; inert `.prop` Scenery placements with Far, Near, and On the floor depth; built-in multi-select browse tags; Ground-only visual finishes; editable Blank/Town Street/Living Room New Scene choices; Scenery-safe selection; scene save/reopen and legacy defaults; built-in vector content listed below; and a stage-relative size-authoring guide/workflow shared by Props and Scenery artwork, with single Scenery artwork placements resizable independently in Edit Scenery. The new authoring convention does not silently rescale existing assets or saved placements.
|
||||
|
||||
Excluded from Phase 19: a new Scenery Editor or `.scenery` file; child-authored repeatable finish patterns or reusable whole-Sky themes; animated weather, parallax, or directed Sky transitions; whole-scene filters such as sepia or black-and-white; functional doors or scene travel; automatic window cutouts or glass; Ramp/Step finishes or terrain redesign; inserting a starter into an existing scene; user-authored reusable set templates; and functional stairs or multi-level travel. [Multi-level walkable scenes](../ideas/feature_backlog.md) and [whole-scene visual filters](../ideas/feature_backlog.md) are separate future ideas, not Phase 19 work.
|
||||
Excluded from Phase 19: a new Scenery Editor or `.scenery` file; child-authored repeatable finish patterns or reusable whole-Sky themes; autonomous weather animation, multi-layer parallax scenery, or directed Sky transitions; whole-scene filters such as sepia or black-and-white; functional doors or scene travel; automatic window cutouts or glass; Ramp/Step finishes or terrain redesign; inserting a starter into an existing scene; user-authored reusable set templates; and functional stairs or multi-level travel. [Multi-level walkable scenes](../ideas/feature_backlog.md) and [whole-scene visual filters](../ideas/feature_backlog.md) are separate future ideas, not Phase 19 work.
|
||||
|
||||
## Asset production manifest
|
||||
|
||||
This is the authoritative content checklist for the two starters and the shared pickers. The initial status of **every** row is **Needed**. Progress through **Needed → Concept ready → Art approved → Final vector ready → Integrated → Verified**. A raster sketch may reach **Concept ready**; it is not a final `.prop`, Sky theme, or repeatable vector finish. Final cutouts must be repo-native vector/`.prop` artwork, and Sky/finish visuals must remain crisp through Stage zoom. Art contributors may use raster concept images as reference, then produce final assets in coordination with implementation.
|
||||
This is the authoritative content checklist for the two starters and the shared pickers. The initial status of every row was **Needed**. Progress through **Needed → Concept ready → Art approved → Final vector ready → Integrated → Verified**. Following user approval on 2026-10-15, the approved `.prop` vectors, Sky themes, and finishes are integrated into the production Stage, shared picker, and starter scenes. The complete manifest now records production integration, automated verification, and user/editor visual verification completed on 2026-10-22. The user also verified Plain Background save/reopen; this does not claim a manual save/reopen check for every manifest item. A raster sketch may reach **Concept ready**; it is not a final `.prop`, Sky theme, or repeatable vector finish. Final cutouts must be repo-native vector/`.prop` artwork, and Sky/finish visuals must remain crisp through Stage zoom. Art contributors may use raster concept images as reference, then produce final assets in coordination with implementation.
|
||||
|
||||
In the tables, **TBD** in Source/rights means the creator, reference provenance, and license or permission still need recording. **TBD** in Final location and Evidence means those fields must be filled as content is produced. For each row, validation evidence should include a thumbnail or Sky/finish preview, the asset in the Stage at normal and zoomed views, and save/reopen of its starter use where applicable. Stable IDs identify deliverables; they are not prescribed file names or runtime contracts.
|
||||
|
||||
### Adaptive Sky themes
|
||||
|
||||
The **Verified** statuses below describe the production Sky artwork and picker, including the camera-aware detail behavior. The user completed editor visual verification on 2026-10-22.
|
||||
|
||||
| Stable ID | Class / final format | Tags / default layer | Starter use | Behavior / collision | Status | Source / rights | Visual acceptance | Final location / definition | Validation evidence |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| `sky_clear_day` | Adaptive vector Sky theme; not `.prop` | N/A; Sky | Living Room; picker | Scene-wide, static; none | Needed | TBD | Appealing blue depth and varied light cloud/sun detail; window gap reads clearly; no edge on pan. | TBD | TBD |
|
||||
| `sky_cloudy_day` | Adaptive vector Sky theme; not `.prop` | N/A; Sky | Town Street; picker | Scene-wide, static; none | Needed | TBD | Layered, varied clouds leave town silhouettes readable; no obvious tile or edge. | TBD | TBD |
|
||||
| `sky_sunset` | Adaptive vector Sky theme; not `.prop` | N/A; Sky | Picker | Scene-wide, static; none | Needed | TBD | Warm atmospheric color and sun/cloud composition remain distinct from Clear Day without tinting scene objects. | TBD | TBD |
|
||||
| `sky_starry_night` | Adaptive vector Sky theme; not `.prop` | N/A; Sky | Picker | Scene-wide, static; none | Needed | TBD | Dark graduated sky, varied stars, and moon remain legible while foreground contrast survives. | TBD | TBD |
|
||||
| `sky_clear_day` | Adaptive vector Sky theme; not `.prop` | N/A; Sky | Living Room; picker | Scene-wide; camera-aware details; none | Verified | Original vector concept | Appealing blue depth and varied light cloud/sun detail; window gap reads clearly; no edge on pan. | `scripts/stage/scenery/stage_sky_view.gd` | Production card and Living Room Stage render inspected: `tests/phase19_visual_background_gallery.png`, `tests/phase19_visual_living_room.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `sky_cloudy_day` | Adaptive vector Sky theme; not `.prop` | N/A; Sky | Town Street; picker | Scene-wide; camera-aware details; none | Verified | Original vector concept | Layered, varied clouds leave town silhouettes readable; no obvious tile or edge. | `scripts/stage/scenery/stage_sky_view.gd` | Production card and Town Street Stage render inspected: `tests/phase19_visual_background_gallery.png`, `tests/phase19_visual_town_street.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `sky_sunset` | Adaptive vector Sky theme; not `.prop` | N/A; Sky | Picker | Scene-wide; camera-aware details; none | Verified | Original vector concept | Warm atmospheric color and sun/cloud composition remain distinct from Clear Day without tinting scene objects. | `scripts/stage/scenery/stage_sky_view.gd` | Production card and Stage render inspected: `tests/phase19_visual_background_gallery.png`, `tests/phase19_visual_finishes_and_repair.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `sky_starry_night` | Adaptive vector Sky theme; not `.prop` | N/A; Sky | Picker | Scene-wide; camera-aware details; none | Verified | Original vector concept | Dark graduated sky, varied stars, and moon remain legible while foreground contrast survives. | `scripts/stage/scenery/stage_sky_view.gd` | Distinct production gallery preview inspected: `tests/phase19_visual_background_gallery.png`; full Stage/editor visual verification completed 2026-10-22. |
|
||||
|
||||
### Repeatable vector surface finishes
|
||||
|
||||
@@ -118,16 +134,16 @@ These are finish definitions and previews, not ordinary Props. Ground finishes c
|
||||
|
||||
| Stable ID | Class / final format | Tags / default layer | Starter use | Behavior / collision | Status | Source / rights | Visual acceptance | Final location / definition | Validation evidence |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| `finish_wall_paint` | Vector wall finish | N/A; wall panel | Living Room; picker | Inert panel; none | Needed | TBD | Smooth green room wall and other chosen colors without seams at panel edges. | TBD | TBD |
|
||||
| `finish_wall_brick` | Repeatable vector wall finish | N/A; wall panel | Picker | Inert panel; none | Needed | TBD | Bricks keep coherent size and joins as panel is resized. | TBD | TBD |
|
||||
| `finish_wall_wood` | Repeatable vector wall finish | N/A; wall panel | Picker | Inert panel; none | Needed | TBD | Boards read as wood at common Stage zoom and do not stretch with the panel. | TBD | TBD |
|
||||
| `finish_ground_paint` | Vector Ground finish | N/A; Ground | Picker | Solid, walkable Ground | Needed | TBD | Plain color is clean and visually distinct from wall-only backdrop. | TBD | TBD |
|
||||
| `finish_ground_brick` | Repeatable vector Ground finish | N/A; Ground | Picker | Solid, walkable Ground | Needed | TBD | Neighboring pieces form a continuous brick surface. | TBD | TBD |
|
||||
| `finish_ground_wood` | Repeatable vector Ground finish | N/A; Ground | Living Room; picker | Solid, walkable Ground | Needed | TBD | Wood plank floor reads continuously beneath rug and furniture. | TBD | TBD |
|
||||
| `finish_ground_grass` | Repeatable vector Ground finish | N/A; Ground | Picker | Solid, walkable Ground | Needed | TBD | Grassy surface is readable and not noisy behind feet. | TBD | TBD |
|
||||
| `finish_ground_dirt` | Repeatable vector Ground finish | N/A; Ground | Picker | Solid, walkable Ground | Needed | TBD | Earthy surface remains distinct from Grass at thumbnail and Stage size. | TBD | TBD |
|
||||
| `finish_ground_sidewalk` | Repeatable vector Ground finish | N/A; Ground | Town Street; picker | Solid, walkable Ground | Needed | TBD | Light concrete sidewalk forms a broad, aligned run beneath shops. | TBD | TBD |
|
||||
| `finish_ground_asphalt` | Repeatable vector Ground finish | N/A; Ground | Town Street; picker | Solid, walkable Ground | Needed | TBD | Darker road contrasts with sidewalk while preserving visible character edges. | TBD | TBD |
|
||||
| `finish_wall_paint` | Vector wall finish | N/A; wall panel | Living Room; picker | Inert panel; none | Verified | Original vector concept | Smooth green room wall and other chosen colors without seams at panel edges. | `scripts/stage/scenery/stage_surface_renderer.gd` | Production gallery preview and Living Room render inspected: `tests/phase19_visual_background_gallery.png`, `tests/phase19_visual_living_room.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_wall_brick` | Repeatable vector wall finish | N/A; wall panel | Picker | Inert panel; none | Verified | Original vector concept; user image used as inspiration for v2 | Bricks keep coherent size and joins as panel is resized. | `scripts/stage/scenery/stage_surface_renderer.gd` | Production gallery preview and Stage wall render inspected: `tests/phase19_visual_background_gallery.png`, `tests/phase19_visual_finishes_and_repair.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_wall_wood` | Repeatable vector wall finish | N/A; wall panel | Picker | Inert panel; none | Verified | Original vector concept | Boards read as wood at common Stage zoom and do not stretch with the panel. | `scripts/stage/scenery/stage_surface_renderer.gd` | Production gallery preview inspected: `tests/phase19_visual_background_gallery.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_ground_paint` | Vector Ground finish | N/A; Ground | Picker | Solid, walkable Ground | Verified | Original vector concept | Plain color is clean and visually distinct from wall-only backdrop. | `scripts/stage/scenery/stage_surface_renderer.gd` | Production Ground renderer is integrated with Stage; Phase 19 runtime suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_ground_brick` | Repeatable vector Ground finish | N/A; Ground | Picker | Solid, walkable Ground | Verified | Original vector concept | Neighboring pieces form a continuous brick surface. | `scripts/stage/scenery/stage_surface_renderer.gd` | Production Ground renderer is integrated with Stage; Phase 19 runtime suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_ground_wood` | Repeatable vector Ground finish | N/A; Ground | Living Room; picker | Solid, walkable Ground | Verified | Original vector concept | Wood plank floor reads continuously beneath rug and furniture. | `scripts/stage/scenery/stage_surface_renderer.gd` | Production Living Room scene and Ground renderer integrated; Phase 19 runtime suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_ground_grass` | Repeatable vector Ground finish | N/A; Ground | Picker | Solid, walkable Ground | Verified | Original vector concept | Grassy surface is readable and not noisy behind feet. | `scripts/stage/scenery/stage_surface_renderer.gd` | Production Ground render inspected: `tests/phase19_visual_finishes_and_repair.png`; runtime suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_ground_dirt` | Repeatable vector Ground finish | N/A; Ground | Picker | Solid, walkable Ground | Verified | Original vector concept | Earthy surface remains distinct from Grass at thumbnail and Stage size. | `scripts/stage/scenery/stage_surface_renderer.gd` | Production Ground renderer is integrated with Stage; Phase 19 runtime suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_ground_sidewalk` | Repeatable vector Ground finish | N/A; Ground | Town Street; picker | Solid, walkable Ground | Verified | Original vector concept | Light concrete sidewalk forms a broad, aligned run beneath shops. | `scripts/stage/scenery/stage_surface_renderer.gd` | Town Street starter load and runtime suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `finish_ground_asphalt` | Repeatable vector Ground finish | N/A; Ground | Town Street; picker | Solid, walkable Ground | Verified | Original vector concept | Darker road contrasts with sidewalk while preserving visible character edges. | `scripts/stage/scenery/stage_surface_renderer.gd` | Town Street starter load and runtime suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
|
||||
### Reusable Scenery artwork
|
||||
|
||||
@@ -135,17 +151,17 @@ Each item below is a `.prop` vector artwork asset offered through Scenery. Its S
|
||||
|
||||
| Stable ID | Class / final format | Tags / default layer | Starter use | Behavior / collision | Status | Source / rights | Visual acceptance | Final location / definition | Validation evidence |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| `art_city_skyline` | Vector `.prop` cutout | Buildings; Far | Town Street ×1 | Inert; none | Needed | TBD | Long, muted overlapping building silhouette reads as distant and leaves cloud sky visible. | TBD | TBD |
|
||||
| `art_storefront` | Vector `.prop` cutout | Buildings; Near | Town Street ×1 or more | Inert; none | Needed | TBD | Colorful, readable shop front contrasts with skyline; repeat use does not look like one flat strip. | TBD | TBD |
|
||||
| `art_town_house` | Vector `.prop` cutout | Buildings; Near | Town Street ×1 or more | Inert; none | Needed | TBD | House silhouette and palette differ clearly from storefront at normal zoom. | TBD | TBD |
|
||||
| `art_tree` | Vector `.prop` cutout | Nature; Near | Town Street ×2 or more | Inert; none | Needed | TBD | Friendly, readable crown/trunk; repeated copies tolerate size and position variation. | TBD | TBD |
|
||||
| `art_window_frame` | Vector `.prop` cutout | Walls, Buildings; Near | Living Room ×1 | Inert; none | Needed | TBD | Frame is transparent at its center and aligns over the wall-panel gap to reveal actual Sky. | TBD | TBD |
|
||||
| `art_fireplace_mantel` | Vector `.prop` cutout | Walls, Objects; Near | Living Room ×1 | Inert; none | Needed | TBD | Fireplace and mantel read clearly as decoration without suggesting this asset itself blocks movement. | TBD | TBD |
|
||||
| `art_wall_clock` | Vector `.prop` cutout | Walls, Objects; Near | Living Room ×1 | Inert; none | Needed | TBD | Clock reads at room scale without tiny illegible markings. | TBD | TBD |
|
||||
| `art_bookshelf` | Vector `.prop` cutout | Objects, Walls; Near | Living Room ×1 | Inert; none | Needed | TBD | Shelf, books, and plant details remain legible without dense tracing. | TBD | TBD |
|
||||
| `art_framed_picture` | Vector `.prop` cutout | Objects, Walls; Near | Living Room ×1 or more | Inert; none | Needed | TBD | Clear frame and image contrast on green paint; reuse can vary size/position. | TBD | TBD |
|
||||
| `art_potted_plant` | Vector `.prop` cutout | Nature, Objects; Near | Living Room ×1 | Inert; none | Needed | TBD | Leaf and pot shapes remain distinct from wall and furniture. | TBD | TBD |
|
||||
| `art_rug` | Vector `.prop` cutout | Objects; On the floor | Living Room ×1 | Inert; none | Needed | TBD | Visible over Wood Ground and below furniture/feet; border survives zoom. | TBD | TBD |
|
||||
| `art_city_skyline` | Vector `.prop` cutout | Buildings; Far | Town Street ×1 | Inert; none | Verified | Original vector art | Long, muted overlapping building silhouette reads as distant and leaves cloud sky visible. | `content/props/art_city_skyline-v1.prop` | Town Street production Stage render inspected: `tests/phase19_visual_town_street.png`; save/reopen suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_storefront` | Vector `.prop` cutout | Buildings; Near | Town Street ×1 or more | Inert; none | Verified | Original vector art | Colorful, readable shop front contrasts with skyline; repeat use does not look like one flat strip. | `content/props/art_storefront-v1.prop` | Town Street production Stage render inspected: `tests/phase19_visual_town_street.png`; save/reopen suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_town_house` | Vector `.prop` cutout | Buildings; Near | Town Street ×1 or more | Inert; none | Verified | Original vector art | House silhouette and palette differ clearly from storefront at normal zoom. | `content/props/art_town_house-v1.prop` | Town Street production Stage render inspected: `tests/phase19_visual_town_street.png`; save/reopen suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_tree` | Vector `.prop` cutout | Nature; Near | Town Street ×2 or more | Inert; none | Verified | Original vector art; user image used as inspiration for v2 | Friendly, readable crown/trunk; repeated copies tolerate size and position variation. | `content/props/art_tree-v2.prop` | Revised v2 tree inspected in Town Street and repair view: `tests/phase19_visual_town_street.png`, `tests/phase19_visual_finishes_and_repair.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_window_frame` | Vector `.prop` cutout | Walls, Buildings; Near | Living Room ×1 | Inert; none | Verified | Original vector art | Frame is transparent at its center and aligns over the wall-panel gap to reveal actual Sky. | `content/props/art_window_frame-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; save/reopen suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_fireplace_mantel` | Vector `.prop` cutout | Walls, Objects; Near | Living Room ×1 | Inert; none | Verified | Original vector art | Fireplace and mantel read clearly as decoration without suggesting this asset itself blocks movement. | `content/props/art_fireplace_mantel-v2.prop` | Revised v2 fireplace inspected in Living Room: `tests/phase19_visual_living_room.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_wall_clock` | Vector `.prop` cutout | Walls, Objects; Near | Living Room ×1 | Inert; none | Verified | Original vector art | Clock reads at room scale without tiny illegible markings. | `content/props/art_wall_clock-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_bookshelf` | Vector `.prop` cutout | Objects, Walls; Near | Living Room ×1 | Inert; none | Verified | Original vector art | Shelf, books, and plant details remain legible without dense tracing. | `content/props/art_bookshelf-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_framed_picture` | Vector `.prop` cutout | Objects, Walls; Near | Living Room ×1 or more | Inert; none | Verified | Original vector art | Clear frame and image contrast on green paint; reuse can vary size/position. | `content/props/art_framed_picture-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_potted_plant` | Vector `.prop` cutout | Nature, Objects; Near | Living Room ×1 | Inert; none | Verified | Original vector art | Leaf and pot shapes remain distinct from wall and furniture. | `content/props/art_potted_plant-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; user/editor visual verification completed 2026-10-22. |
|
||||
| `art_rug` | Vector `.prop` cutout | Objects; On the floor | Living Room ×1 | Inert; none | Verified | Original vector art | Visible over Wood Ground and below furniture/feet; border survives zoom. | `content/props/art_rug-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; starter runtime suite passed; user/editor visual verification completed 2026-10-22. |
|
||||
|
||||
### Interactive furniture Props
|
||||
|
||||
@@ -153,11 +169,11 @@ These are `.prop` assets placed through Props in Living Room. Their authored sha
|
||||
|
||||
| Stable ID | Class / final format | Tags / default layer | Starter use | Behavior / collision | Status | Source / rights | Visual acceptance | Final location / definition | Validation evidence |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| `prop_couch` | Vector `.prop` furniture | Objects; Prop depth per placement | Living Room ×1 | Still, appropriately character-blocking; valid collision | Needed | TBD | Comfortable couch silhouette sized for stickman and room; no implied Sit action. | TBD | TBD |
|
||||
| `prop_armchair` | Vector `.prop` furniture | Objects; Prop depth per placement | Living Room ×1 | Still, appropriately character-blocking; valid collision | Needed | TBD | Distinct chair silhouette, matching couch style and character scale. | TBD | TBD |
|
||||
| `prop_coffee_table` | Vector `.prop` furniture | Objects; Prop depth per placement | Living Room ×1 | Still, can support small props; valid collision | Needed | TBD | Tabletop/support reads clearly and leaves rug visible. | TBD | TBD |
|
||||
| `prop_couch` | Vector `.prop` furniture | Objects; Prop depth per placement | Living Room ×1 | Still, appropriately character-blocking; valid collision | Verified | Original vector art | Comfortable couch silhouette sized for stickman and room; no implied Sit action. | `content/props/prop_couch-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; prop integration regression available; user/editor visual verification completed 2026-10-22. |
|
||||
| `prop_armchair` | Vector `.prop` furniture | Objects; Prop depth per placement | Living Room ×1 | Still, appropriately character-blocking; valid collision | Verified | Original vector art | Distinct chair silhouette, matching couch style and character scale. | `content/props/prop_armchair-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; prop integration regression available; user/editor visual verification completed 2026-10-22. |
|
||||
| `prop_coffee_table` | Vector `.prop` furniture | Objects; Prop depth per placement | Living Room ×1 | Still, can support small props; valid collision | Verified | Original vector art | Tabletop/support reads clearly and leaves rug visible. | `content/props/prop_coffee_table-v1.prop` | Living Room production render inspected: `tests/phase19_visual_living_room.png`; prop integration regression available; user/editor visual verification completed 2026-10-22. |
|
||||
|
||||
Existing built-in crate and ball artwork may be used in Town Street if an interactive object benefits that starter; no new interactive town asset is required to achieve its visual reference. The artist should establish a coherent cartoon style and scale against the live stickman. Far art is quieter than Near art; outlines and silhouettes must remain clear at selector-thumbnail size and normal Stage zoom. Avoid excessive vector point counts, hard-to-read microdetail, and busy contrast behind character faces or speech bubbles. The source/rights field must distinguish original art, licensed sources, and generated raster concepts. Reference art is not automatically licensed final content.
|
||||
Existing built-in crate and ball artwork may be used in Town Street if an interactive object benefits that starter; no new interactive town asset is required to achieve its visual reference. The artist should establish a coherent cartoon style and author each asset at its intended Stage size relative to the standard approximately 940-world-unit standing stickman. Infer ordinary dimensions from a recognizable object's name and use, and record approximate intended bounds in stickman units (height, plus width when useful) with a scale-check preview; ask only when the intended use makes size genuinely ambiguous. Far art is quieter than Near art; outlines and silhouettes must remain clear at selector-thumbnail size and normal Stage zoom. Avoid excessive vector point counts, hard-to-read microdetail, and busy contrast behind character faces or speech bubbles. The source/rights field must distinguish original art, licensed sources, and generated raster concepts. Reference art is not automatically licensed final content.
|
||||
|
||||
## Success criteria
|
||||
|
||||
@@ -165,10 +181,12 @@ Existing built-in crate and ball artwork may be used in Town Street if an intera
|
||||
2. A child can create Living Room from New Scene, see the actual selected Sky through its window gap, change the Sky without tinting the room, restyle the wall or Wood Ground, move the rug and furniture independently, and save/reopen the revised set.
|
||||
3. A child can place one `.prop` drawing through Scenery and through Props and understand that the two copies behave differently. The Scenery copy never blocks, supports, moves, is picked up or used, or triggers an event in PLAY.
|
||||
4. Far skyline, Near buildings/trees, Ground, On the floor rug, and Props preserve their intended order through pan, zoom, PLAY, stop, and reload. Character and speech readability survives the four Sky styles and common finishes.
|
||||
5. Ordinary EDIT selection still reaches foreground characters, Props, and Ground over broad panels. Edit Scenery makes every cutout and panel discoverable and correctable; placement and resize can be canceled before commit. Labels, icons, outlines, and focus reveal state without depending on color alone.
|
||||
5. Ordinary EDIT selection still reaches foreground characters, Props, and Ground over broad panels. Edit Scenery makes every cutout and panel discoverable and correctable; placement and an active resize gesture can be canceled before commit, while a single-piece resize commits on release and group resize retains Keep/Cancel. Labels, icons, outlines, and focus reveal state without depending on color alone.
|
||||
6. Wall panel and Ground finish choices preview correctly; wall patterns do not stretch as panels resize, and adjacent Ground pieces do not show distracting pattern restarts. Changing a palette finish does not repaint existing pieces; a selected piece can be changed deliberately.
|
||||
7. Older `.scene` documents retain their prior neutral background and Ground appearance when opened. Older untagged `.prop` assets remain visible in All artwork, and a missing referenced Scenery asset yields a visible recovery cue rather than silently removing the child's placement.
|
||||
8. Every required manifest item reaches **Verified**, with source/rights and final location recorded. A raster concept alone cannot satisfy a final vector content requirement.
|
||||
8. Each chosen Sky keeps its gradient screen-filling while its details respond gently and predictably to camera pan and zoom in EDIT, DIRECT, and PLAY, as specified in the [camera-aware Sky details addendum](#camera-aware-sky-details-addendum). The action remains readable, no edge appears, and the same framing survives save/reopen.
|
||||
9. Every required manifest item reaches **Verified**, with source/rights and final location recorded. A raster concept alone cannot satisfy a final vector content requirement.
|
||||
10. New and revised `.prop` artwork is authored at its intended Stage size relative to the standard approximately 940-world-unit standing stickman, avoiding a mandatory resize on ordinary placement. The Prop Editor's Size for Stage guide is visible over artwork and above a floor/contact cue. Loading performs no automatic normalization; deliberate asset overwrites retain the usual live-reference behavior and existing Save workflow, without new copy/version prompts. Individual Scenery pieces resize independently, preserve proportions, and save/reopen at the committed scale.
|
||||
|
||||
## Current project context, risks, and dependencies
|
||||
|
||||
@@ -178,13 +196,14 @@ Existing built-in crate and ball artwork may be used in Town Street if an intera
|
||||
- Stage selection currently uses World-object bounds and an overlapping-object chooser. Large wall panels and floor art can otherwise catch almost every click or box selection. A dedicated, forgiving Scenery edit flow and predictable hit order are product requirements. The approved [Stage panel UI system](../specs/stage_panel_ui_system.md) supplies the in-stage inspector visual contract; adapt it for selected Scenery/Ground controls where it fits.
|
||||
- Finite panels, tiled vector finishes, and detailed Sky motifs must stay crisp and performant across Stage zoom and camera pan. Ground pieces need aligned world-scale patterns. The Town Street and Living Room references should guide composition and mood, not be treated as final licensed assets.
|
||||
- The two starters require the manifest content as real deliverables. Missing art, inconsistent scale, or raster-only placeholders would leave a child with a visually incomplete feature even if the controls work.
|
||||
- Stage-relative authoring scale must account for both tall and wide props/artwork without forcing every asset to one generic height. The stickman comparison guides intent; the artist records an approximate scale, and the Prop Editor provides reversible correction. Loading does not normalize existing assets. Deliberately saving revised geometry over a live reference updates that drawing in referencing scenes; the user chose to retain the existing Save workflow because scenes are not yet in production.
|
||||
|
||||
## Remaining questions for the spec-pipeline
|
||||
## Specification decisions recorded
|
||||
|
||||
These are design and architecture tasks for the specification stage, not unresolved user choices about Phase 19's product goal:
|
||||
The following design questions were resolved in the linked UI/UX and architecture specifications and verified with the integrated Phase 19 behavior:
|
||||
|
||||
1. What exact UI presents Backgrounds, Artwork tags, placement layer, Ground finish, and Edit Scenery without crowding the existing Stage palette? Define keyboard, touch, narrow-viewport, dismissal, and undo/cancel behavior using the established Stage panel patterns.
|
||||
2. How will an adaptive Sky fill unbounded camera views while keeping motifs stable and detailed, and how will wall and Ground finishes keep repeatable pattern scale and alignment through resizing, drag painting, and zoom?
|
||||
1. What exact UI presents Backgrounds, Artwork tags, placement layer, Ground finish, and Edit Scenery without crowding the existing Stage palette? Define keyboard, touch, narrow-viewport, dismissal, and cancellation behavior using the established Stage panel patterns; Stage Undo remains out of scope for Phase 19 and is tracked separately.
|
||||
2. How will an adaptive Sky fill unbounded camera views while keeping its gradient fixed and its details gently camera-aware as described in the addendum, and how will wall and Ground finishes keep repeatable pattern scale and alignment through resizing, drag painting, and zoom?
|
||||
3. What saved scene and optional `.prop` tag fields, validation, migration defaults, missing-art recovery, and starter creation flow preserve existing documents and the same artwork's independent Scenery/Prop placements?
|
||||
4. How will selected panels, cutouts, rugs, Ground, and ordinary objects remain reachable where bounds overlap, including the window gap and a room-sized wall?
|
||||
5. Which asset production workflow turns concepts into final vector content, records provenance, checks collision only for interactive Props, and advances each manifest row through integration and verification?
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# Phase 19 — Starter Scene Composition
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified as part of Phase 19. The user verified both starter compositions in the editor; the Phase 19 scenery suite passes **706 checks with 0 failures**. The detailed composition decisions below remain the historical product and implementation brief.
|
||||
|
||||
## Goal and audience
|
||||
|
||||
Make **Town Street** and **Living Room** look like complete, usable story sets when a child opens them, moves the camera, places a stickman, and presses PLAY. The audience is a child starting from **File → New** who should see a clear place to stage action and be able to change its individual pieces.
|
||||
|
||||
The selected visual direction is the upper-left **Everyday Storybook** composition from the outdoor and indoor concept boards. It favors friendly shapes, a calm backdrop, a clear floor line, and open space for characters and speech.
|
||||
|
||||
## Desired child outcome
|
||||
|
||||
- **Town Street:** A child immediately recognizes a neighborhood street. Shops, houses, and trees stand on the same sidewalk line; a subdued skyline gives distance; the center has room for a character to walk or speak. The sidewalk, curb, and road remain visible as a continuous set as the child pans through the intended starter area.
|
||||
- **Living Room:** A child immediately recognizes a room with a complete wall and wood floor. The window is the only opening to the Sky. Furniture rests on the floor, and a centered rug gives the room warmth while leaving a clear action lane.
|
||||
- In either starter, the child can select, move, resize, restyle, or remove ordinary pieces with the existing Stage tools, then save and reopen the revised scene.
|
||||
|
||||
## Core behavior and composition
|
||||
|
||||
**Opening and editing.** Keep the existing Blank Scene, Town Street, and Living Room choices and the current unsaved-scene flow. The two revised starters should open at a useful camera frame with no setup step. They remain editable scenes assembled from the existing Sky, Scenery, wall/background surfaces, walkable Ground, and Props. Do not flatten a starter into a single picture or merge independently useful objects merely to hide seams.
|
||||
|
||||
**Outdoor set.** Use the current Cloudy Day Sky and a quiet Far skyline. Arrange the existing house, storefront, and tree artwork so their visible bases meet one consistent street datum. Preserve a generous, readable opening near the initial center for a stickman and speech. Carry Sidewalk and Asphalt as left-to-right rows of ordinary-size Ground tiles across the visible frame and agreed pan range. Add an opaque, non-walkable Background ground layer below the skyline datum to cover clouds showing through the lower scene. Buildings and trees may repeat or vary in size and spacing to support a longer street, while remaining individual editable placements.
|
||||
|
||||
**Indoor set.** Carry the painted wall and a left-to-right row of ordinary-size Wood Ground tiles across the initial frame and agreed pan range. Make the wall and floor meet cleanly with a visible baseboard or equivalent visual edge. Keep the intentional opening beneath the window frame as the only place the selected Sky shows through; no Sky should leak at outer wall edges, below the floor, or through unintended seams. Position the couch, armchair, and coffee table so they visually rest on the floor. Center the existing rug in the room, show it above the wood finish and below action, and leave enough uncluttered floor for a character to move and be seen. Wall decoration remains secondary to the window and action area.
|
||||
|
||||
**Camera envelope.** The approved implementation target is a **4,760-world-unit** minimum for each walkable span: a 1,280-logical-pixel viewport at saved zoom 0.5, ±1,000 world units of pan from the saved camera, and 100 world units of margin at each end. Twenty-five standard 192-unit tiles span 4,800 units and satisfy the target without oversized scaled blocks. Town Asphalt adds one normal-size tile at each end (27 total) so the lower road is physically reachable beyond the sidewalk ends. Outside the defined starter envelope, finite set edges may appear naturally because the camera remains unrestricted. The architecture spec records the exact formula and accepted trade-offs.
|
||||
|
||||
## Story and kid-facing feedback
|
||||
|
||||
The default shot should communicate where action can happen without explanatory text. A child placing a stickman should see feet on a walkable surface, room in the center for a short walk or conversation, and enough contrast to read the character and a speech bubble. Panning should reveal more of the same coherent set, with no sudden floating building, missing floor, or stray Sky gap. Existing Scenery and Ground editing affordances provide recovery if a child moves a piece; this polish adds no new child-facing controls.
|
||||
|
||||
## Success criteria
|
||||
|
||||
1. At the saved starting camera, both starters read as complete places at normal Stage size, with a clear central action area and understandable walkable surfaces.
|
||||
2. In Town Street, every near building and tree appears grounded on the sidewalk/curb datum. Sidewalk and road continue across the initial view and the defined horizontal pan envelope without an exposed end or distracting join. A character can step from the sidewalk onto the road at either exposed end. The Far skyline remains subdued behind the action.
|
||||
3. In Living Room, the wall, baseboard, and wood floor continue across the initial view and pan envelope. The selected Sky appears through the window opening only. Couch, chair, and table visibly contact the floor; the rug remains centered and does not consume the character's main movement lane.
|
||||
4. At normal framing, a placed stickman and speech remain easy to see in both starters. PLAY preserves the intended walking/support behavior, visual order, and composition; saving and reopening preserves the revised set and camera frame.
|
||||
5. The important pieces remain separately editable through their established tools. Moving or removing one house, tree, wall panel, Ground piece, rug, or furniture Prop does not require replacing a baked image.
|
||||
|
||||
The pre-implementation design review found the outdoor artwork bases roughly **128 screen pixels above Ground**, the **700-world-unit Ground run** ending inside a roughly **917-pixel viewport**, and the indoor couch/chair roughly **24 screen pixels above the floor**. Those measurements motivated the composition work; they are not final placement coordinates.
|
||||
|
||||
## Scope and exclusions
|
||||
|
||||
**Included:** Composition and placement polish for the existing Town Street and Living Room starter scenes; continuity of existing surfaces and backdrops over a defined pan range; alignment of visible artwork and furniture with their shared ground/floor datum; initial camera framing; preservation of scene editability and existing Prop/Scenery roles.
|
||||
|
||||
**Excluded:** New story mechanics, sit behavior, new controls or authoring tools, Stage-wide Undo/Redo, camera restrictions, endless scenery generation, and changes to terrain collision or a general navigation system. The existing navigation bake receives only the tile-seam and exposed 32-unit curb connectors required by these authored surfaces. New art is outside this pass unless the existing library cannot make the selected composition legible; identify any specific missing visual element before proposing an asset request.
|
||||
|
||||
## Current project behavior and references
|
||||
|
||||
The Phase 19 [scenery product plan](phase_19_scenery_backgrounds_surface_finishes.md) defines the starter choices, editable scenery layers, and the distinction between visual Scenery and walkable Ground. The [Background Ground and Wall Color brief](phase_19_background_ground_and_wall_color.md) defines decorative Background ground and editable wall finishes. The user/editor verification recorded in the [Phase 19 handoff](phase_19_handoff.md) is complete. The later [Plain Background brief](phase_19_plain_background.md) adds Plain Background and renames the former neutral-Sky Blank Scene choice **Open Sky**.
|
||||
|
||||
The accepted visual direction is detailed in the [starter-scene UI/UX specification](../specs/phase_19_starter_scene_composition_ui_ux.md). The implementation contract is in the [approved starter-scene architecture specification](../specs/phase_19_starter_scene_composition.md).
|
||||
|
||||
Before this composition pass, the [Town Street scene](../../content/stages/starters/town_street.scene) used one Far skyline, separate Near trees/buildings, and short Sidewalk/Asphalt Ground runs. The [Living Room scene](../../content/stages/starters/living_room.scene) used three wall panels, seven Wood Ground pieces, separate decorations, and three Props. Both saved zoom 0.5. The implementation now promotes these starters to current scene format v1.6, extends required surfaces to the approved envelope, and frames starter previews from the saved camera. See the focused [architecture specification](../specs/phase_19_starter_scene_composition.md) for exact placements and verification results. The existing artwork and furniture remain in [content/props](../../content/props/), with each placement independently editable.
|
||||
|
||||
## Verification status
|
||||
|
||||
- The focused composition suite passed 515 assertions, including tile bounds, seam navigation, a physical PLAY step from sidewalk to road, and Living Room floor support.
|
||||
- The earlier broad-suite run recorded nine failures; that result was superseded by the 2026-10-22 retest, which passed the Phase 19 scenery suite with 706 checks and 0 failures.
|
||||
- The user completed editor visual verification of Town Street and Living Room, including the composition behaviors and surfaces covered here.
|
||||
|
||||
## Implementation status
|
||||
|
||||
The initial focused composition test passed 177 assertions, but user visual review found clouds visible through the Town Street below the skyline and rejected the oversized scaled walkable blocks. The revision adds opaque Grass Background ground, ordinary-size tile rows, and an Asphalt extension so characters can reach the road. The focused composition suite passed 515 assertions, including routing across tile seams and a grounded PLAY drop onto Asphalt. The user has since completed the editor visual review; current Phase 19 test and verification results are summarized above and in the [handoff](phase_19_handoff.md).
|
||||
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 114 KiB |
@@ -0,0 +1,34 @@
|
||||
# Child-Facing Dialog Design Principles
|
||||
|
||||
Use this guide when creating or revising child-facing dialogs, popups, and short setup flows. It captures the shared visual language established in the Choose Scenery dialog. In-stage selected-object inspectors continue to follow the [Stage panel UI system](stage_panel_ui_system.md).
|
||||
|
||||
## Visual style
|
||||
|
||||
- Use rounded dialog shells, buttons, choice tiles, and preview containers. A corner radius around 16–22 logical pixels is a useful starting point for large controls; use smaller radii for compact swatches.
|
||||
- Give controls a clear outline. Use about a 2 px border at rest and 3 px for selected, hovered, or focused states. Keep focus visually distinct from selection.
|
||||
- Style the main action with a saturated blue fill, bold white text, and a visible border. Use the theme’s action color or edit-mode blue token rather than adding a one-off color.
|
||||
- Use dark neutral fills and light text for secondary actions. Leave about 12–16 logical pixels between separate footer buttons so they read as individual choices.
|
||||
- Use large, readable type: roughly 30 px for a dialog title, 22–26 px for section headings, and 20–22 px for main control labels and body copy. Helper text can be smaller when it remains easy to read.
|
||||
- Keep pointer targets at least 44 × 44 logical pixels. Provide generous padding around labels and icons.
|
||||
|
||||
## Dismissal and action labels
|
||||
|
||||
- Give the child a visible, labeled action that describes what happens, such as **Cancel**, **Done**, **Back**, or **Close**.
|
||||
- Avoid making a small corner **×** the default or only way to dismiss a dialog. Use it only when it adds a useful secondary shortcut; the labeled action remains available.
|
||||
- Make the primary action’s wording describe the result, such as **Draw wall panel** or **Use color**. Keep Cancel separate from the primary action and visually secondary.
|
||||
- Escape can remain a keyboard shortcut, but it does not replace a visible action.
|
||||
|
||||
## Theme and implementation
|
||||
|
||||
- Put reusable colors, sizes, spacing, radii, and border widths in `SandboxTheme` or `PropTheme` tokens. Apply local stylebox overrides instead of mutating a shared theme resource.
|
||||
- Use `StageDialogStyler` in `scripts/shared/stage_ui/stage_dialog_styler.gd` for Sandbox Stage and standalone Prop/Stickman confirmation, recovery, and short action dialogs. It owns the shared shell, typography, and primary, secondary, or destructive button roles through `SandboxTheme.popups.confirmation`. Custom Control-based dialogs can reuse its `panel_style()` and `style_button()` helpers.
|
||||
- Render the shared modal surface as a Control in the active scene's UI CanvasLayer. Keep the native `AcceptDialog` or `ConfirmationDialog` hidden as the signal source; a full-screen native Window can replace the active scene with a blank surface on some render paths. Native `FileDialog` contents remain native.
|
||||
- Keep larger text from clipping: use containers that can expand or wrap, and size the dialog after its visible content has been laid out.
|
||||
- Preserve clear hover, pressed, selected, focused, and disabled states. Do not use color as the only indication of a state.
|
||||
- Adapt the arrangement to each workflow while keeping this shared visual language. The Choose Scenery dialog in `scripts/shared/ui/asset_selector.gd` and its `popups.asset_selector` theme tokens are the current implementation reference.
|
||||
|
||||
## Stable position during dynamic resizing
|
||||
|
||||
- When a dialog changes size after a tab, filter, or other in-place choice, preserve its current anchor so the clicked control stays under the pointer.
|
||||
- Let the dialog grow from its stable edge while there is room. Before expanding, account for the usable viewport; if the full content will not fit, cap the dialog and let its content area scroll.
|
||||
- Move the dialog only as much as needed to keep essential controls visible. Avoid recentering after every content change, which makes controls jump away from the pointer.
|
||||
@@ -0,0 +1,224 @@
|
||||
# Editor visual harmonization — architecture and UI specification
|
||||
|
||||
> **Status:** Proposed for final user sign-off (2026-10-23). **Branch:** `feature/editor-visual-harmonization`. **Scope:** Prop Editor and Stickman Editor presentation, responsive workspaces, control feedback, dialogs, and save status. This specification does not change `.prop` or `.stk` formats or Stage inspector behavior.
|
||||
|
||||
## 1. Outcome and approved direction
|
||||
|
||||
The two editors should read as parts of one Stickman Studio product while keeping their distinct authoring tasks. The canvas remains the main work surface. The Prop Editor retains its Arrange, Reshape, and Attach modes, split canvas, Attach preview, and scrolling inspector. The Stickman Editor gains **Overview**, with all ten body-part panels available, and **Focus on Part**, with one larger live panel, a body-part picker, and the Whole Stickman preview. Focus can be chosen at any window size. It is the automatic default only when the minimum widths needed by Overview do not fit. Once a child chooses a view, that choice remains in effect for the session through window resizing.
|
||||
|
||||
The [Editor Visual Style Guide](../guides/editor_visual_style_guide.md) supplies the visual direction, and [Dialog Design Principles](dialog_design_principles.md) supplies modal behavior. [Stage panel UI system](stage_panel_ui_system.md) remains scoped to in-stage selected-object cards. Neither `StageInspectorPanel` nor its choice/toggle controls are transplanted into the persistent editor workspaces.
|
||||
|
||||
The implementation proceeds in staged slices under this one contract. Each slice should be reviewable without changing the saved document schema. Final handoff waits for the behavior and rendered visual checks in §10.
|
||||
|
||||
## 2. Current architecture and constraints
|
||||
|
||||
| Area | Current fact | Consequence |
|
||||
| --- | --- | --- |
|
||||
| Prop theme | `PropTheme` reads `prop_theme.json` with defaults, clamping, and typed accessors. `PropEditor` builds a local `Theme`; it also hardcodes some stylebox colors and gives mode buttons `FOCUS_NONE`. | Share chrome roles through one editor token source and restore a distinct keyboard focus state. Keep prop material, primitive, and canvas values under `PropTheme`. |
|
||||
| Prop layout | `prop_editor.tscn` has fixed top-row offsets, outer `HSplitContainer`, scrolling inspector, and an inner Attach split. | Replace brittle top-row positioning with container sizing; keep both splitters and the inspector scroll. |
|
||||
| Stickman state | `StickmanEditor` instantiates ten `BodyPartPanel` scenes, stores them by part name, and reads their live shapes for preview and save. Each panel also owns shape selection, zoom, pan, and popup state. | A view switch must move the same nodes. Calling `set_shape_data()` would reset selection, zoom, and pan. |
|
||||
| Stickman layout | The scene has two five-panel `VBoxContainer` columns and one `WholeStickmanPreview` in a fixed three-column `HBoxContainer`. Each body panel has a 230 × 160 minimum. | Overview needs scroll access; Focus needs a separate host and width-based initial choice. |
|
||||
| Stickman document feedback | Save and load serialize directly; no current path or dirty status is tracked. `WholeStickmanPreview.part_moved` reports translation, while rotation and scale have no commit signal. | Dirty tracking and unsaved-work flows need an explicit controller boundary covering every authored transform. |
|
||||
| Attach drawing order | Anchor `z_index_offset` is an integer clamped to −5…5. `PropAttachPreview` assigns it to the preview prop's `z_index`; held runtime props apply it relative to the rig's index. | Keep the signed value and preview result. Zero means normal ordering, not a universal “front” preset. |
|
||||
|
||||
## 3. Theme ownership and visual contract
|
||||
|
||||
### 3.1 One shared editor chrome source
|
||||
|
||||
Add `scripts/shared/editor_ui/editor_visual_theme.gd` as `class_name EditorVisualTheme extends RefCounted` and `res://editor_visual_theme.json`. It owns **shared editor chrome**: background and raised surfaces, primary and muted text, EDIT accent, keyboard focus, primary/destructive actions, borders, typography, spacing, radii, and minimum control targets. Its loader follows the validated `PropTheme`/`SandboxTheme` pattern: immutable defaults, deep merge of the committed JSON, type validation, clamping, a warning once per invalid key, and a safe default when a file or value is missing. Do not read `SandboxTheme` at runtime to style either editor; its values are a product reference and its popup/inspector semantics belong to the Stage.
|
||||
|
||||
Both editor controllers hold an `EditorVisualTheme` instance and build/apply their own local Godot `Theme` or per-control style overrides. They never mutate `ThemeDB`, the project-wide GUI theme, or a cached shared `Theme` for one selected control. `PropEditor` retains `PropTheme` for material tints, primitive defaults, outline widths, and **prop canvas** colors. Stickman canvas grid, silhouette guide, and selection colors live in a separate `stickman_canvas` namespace with typed accessors; artwork colors are never overridden by chrome styling. Existing `PropTheme.ui` getters may forward during the staged migration, but the final chrome value has one authoritative source in `EditorVisualTheme`. Remove duplicate configuration values when callers have migrated.
|
||||
|
||||
Suggested typed contract (precise names may change in implementation while preserving ownership):
|
||||
|
||||
```gdscript
|
||||
class_name EditorVisualTheme
|
||||
extends RefCounted
|
||||
|
||||
const DEFAULT_PATH: String = "res://editor_visual_theme.json"
|
||||
|
||||
func load_from(path: String = DEFAULT_PATH) -> bool: ...
|
||||
func chrome_color(role: StringName, editor: StringName = &"") -> Color: ...
|
||||
func chrome_px(role: StringName, editor: StringName = &"") -> int: ...
|
||||
func stickman_canvas_color(role: StringName) -> Color: ...
|
||||
func control_theme(editor: StringName) -> Theme: ... # return an editor-local instance
|
||||
```
|
||||
|
||||
The JSON payload is organized by semantic chrome and drawing purpose, for example:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"chrome": {
|
||||
"colors": {"background": "#171B24F2", "surface": "#252B38FA", "focus": "#8BD9FF"},
|
||||
"targets": {"button_min_height": 44, "mode_button_min_height": 56}
|
||||
},
|
||||
"editors": {"prop": {}, "stickman": {}},
|
||||
"stickman_canvas": {"grid_color": "#FFFFFF26", "selection_core": "#FFFFFF", "selection_halo": "#000000D9"}
|
||||
}
|
||||
```
|
||||
|
||||
The complete committed config and script defaults must contain all roles in §3.2, not only these example keys. Resolution order is script defaults, committed shared JSON, then an explicit editor override for the requested editor. Known roles use named accessors or validated role IDs, never arbitrary dotted strings at call sites. An optional `editors.prop` / `editors.stickman` override is allowed only where density or composition has a documented need; shared meanings stay the same. Document any legacy `PropTheme.ui` accessor forwarding and removal in the implementation slice.
|
||||
|
||||
### 3.2 Baseline tokens and states
|
||||
|
||||
| Role | Starting value or rule | Use |
|
||||
| --- | --- | --- |
|
||||
| Main background / raised surface | Stage references `#171B24F2` / `#252B38FA` | Editor chrome; keep drawing canvases visually distinct. |
|
||||
| Primary / muted text | `#F5F7FA` / `#AAB2C0` | Titles, labels, helper copy, disabled reasons. |
|
||||
| EDIT accent | `#22C6FF` | Active editor mode, part/view choice, and selection accent. |
|
||||
| Keyboard focus | `#8BD9FF`, at least a distinct 2 px outline | Visible over normal, hover, and pressed styles; native Tab/Space/Enter remain usable. |
|
||||
| Primary / destructive action | `#087DBA` / `#E66B75` | One forward dialog action and explicit erase/discard actions. Destructive controls retain words and a cancel path. |
|
||||
| Targets | At least 44 × 44 logical pixels for child-facing interactive controls; mode buttons may stay 56 px high | Increase Prop's current 36 px button/row minima; enlarge click areas without enlarging canvas handles visually. |
|
||||
| Density | Body text about 18–20 px, section headers about 20–24 px; compact Overview part title may be about 16–18 px | Confirm fit at minimum supported viewport and larger type. Focus may use a larger part title. |
|
||||
| Canvas selection | Bright core plus dark backing; handle size and hit area are screen-space | Preserve Prop's existing two-tone halo. Extend the same contrast principle to Stickman panel and preview gizmos. |
|
||||
|
||||
The final theme must distinguish neutral, hover, pressed/selected, keyboard focus, disabled, dragging/preview, error, saved, and dirty states. Focus and selection may coexist; focus must not paint over or hide the active mode, as the current Prop button style does. Icons or emoji may add cues but each action remains understandable from text alone. The grid, pose guide, authored shape colors, and material colors remain canvas/domain tokens.
|
||||
|
||||
## 4. Stickman adaptive workspace
|
||||
|
||||
### 4.1 Node hierarchy and state owners
|
||||
|
||||
```text
|
||||
StickmanEditor : Control (document, save/load, dirty, active part, view choice)
|
||||
└─ ChromeRoot : VBoxContainer
|
||||
├─ MenuBar / name and view controls
|
||||
├─ WorkspaceRow : HSplitContainer
|
||||
│ ├─ BodyPartWorkspace : Control
|
||||
│ │ ├─ OverviewScroll : ScrollContainer
|
||||
│ │ │ └─ OverviewColumns : HBoxContainer
|
||||
│ │ │ ├─ LeftColumn : VBoxContainer (five original panels)
|
||||
│ │ │ └─ CenterColumn : VBoxContainer (five original panels)
|
||||
│ │ └─ FocusHost : VBoxContainer
|
||||
│ │ ├─ PartPicker : native choices, scroll/wrap as needed
|
||||
│ │ └─ FocusPanelHost : Control (one original BodyPartPanel)
|
||||
│ └─ WholeStickmanPreview : PanelContainer (script: WholeStickmanPreview; permanent sibling)
|
||||
└─ StatusBar
|
||||
```
|
||||
|
||||
There is exactly one `BodyPartPanel` instance per part and one `WholeStickmanPreview` instance. The preview remains a permanent sibling of the body-part workspace in `WorkspaceRow`; it is not duplicated or serialized for a view switch. The controller records each panel's original Overview parent and index. Entering Focus reparents the active panel into `FocusPanelHost`; leaving Focus restores it at the original index. Changing focused part restores the outgoing panel before moving the incoming panel. The controller's existing panel dictionary and signal connections remain stable.
|
||||
|
||||
`StickmanEditor` owns `enum WorkspaceView { OVERVIEW, FOCUS }`, `_active_part_name: String`, `_view_choice_was_manual: bool`, and the pending view/part request. `BodyPartPanel` owns its shapes, selected shape, zoom, and pan; the preview owns its assembly transform and zoom/pan. The part picker changes `_active_part_name` without calling `BodyPartPanel.select()`, which currently selects the topmost shape and would overwrite the child's shape selection. Clicking a panel updates the active part through the existing selection signal. The active part gets its title inside the panel and a visible border cue in Overview and Focus; Focus does not add a duplicate heading above the canvas.
|
||||
|
||||
Suggested typed additions:
|
||||
|
||||
```gdscript
|
||||
# BodyPartPanel
|
||||
signal presentation_safe
|
||||
func can_switch_presentation() -> bool: ... # false during drag, pan, or popup
|
||||
func add_shape(kind: StringName, at_world: Vector2) -> bool: ...
|
||||
func open_selected_color_picker() -> void: ...
|
||||
|
||||
# StickmanEditor
|
||||
func request_workspace_view(view: WorkspaceView, user_chosen: bool = true) -> void: ...
|
||||
func request_active_part(part_name: String) -> void: ...
|
||||
func _apply_pending_presentation() -> void: ...
|
||||
```
|
||||
|
||||
The picker and view buttons emit typed intent (`view_requested(view: int)`, `part_requested(part_name: String)` if extracted as a small reusable control). The controller validates the part ID against `BODY_PART_NAMES`. No signal bus or saved UI resource is needed for these synchronous presentation decisions.
|
||||
|
||||
Keep one visible action row tied to the active part in either view. **Add Shape** opens the existing Line/Rectangle/Circle choices and places the new shape at the center of that panel's visible drawing area; **Color** opens the selected shape's existing picker and is disabled with a clear reason until a shape is selected. `BodyPartPanel` exposes small typed methods for those actions and remains the owner of shape mutation. The right-click menu stays available for point editing, ordering, copy/paste, mirroring, and erase; use readable wording and a short on-canvas hint so children can discover those secondary tools. This shared row avoids repeating full 44 px toolbars inside all ten Overview panels and shrinking their drawing areas.
|
||||
|
||||
### 4.2 Responsive rules and safe switching
|
||||
|
||||
The automatic initial view is calculated after the first layout pass from available workspace width and the **Overview** content minimum: both panel columns at their useful minimum widths, container gaps, and the preview's useful minimum width. Use the same stable reference widths when the window resizes; a hidden/expanded view must not alter the threshold. If Overview fits, the default is Overview; otherwise Focus. Automatic reevaluation applies only until a child chooses either view. A manual choice remains for the session, including across later resizing and document load/clear. Do not put it in `.stk` or `user://settings.json` in this phase.
|
||||
|
||||
Overview keeps all ten panels reachable, with vertical and, when needed, horizontal scrolling rather than shrinking drawing areas below their usable minimums. A manual Overview choice remains available at a narrow width. Focus is available at any width. Wide Focus shows a persistent, resizable Whole Stickman preview in the split beside the enlarged selected panel. Narrow Focus starts with the preview collapsed so the drawing panel keeps its minimum width; a visible **Whole Stickman** button opens and closes it. If both pane minima cannot fit at once, opening the preview gives it the available workspace and offers a visible **Back to Part** action; no control or panel may be clipped. Keep the preview node alive so its zoom, pan, guide, selection, and part transforms survive collapse and return.
|
||||
|
||||
Do not reparent a panel during vertex/shape drag, pan, context menu, or color popup. Store the requested view/part and apply it when the panel reports a safe point after the gesture or popup closes. This avoids a partial geometry commit and avoids discarding a color choice. A view switch must not call `set_shape_data()`, `clear_shape()`, `reset_view()`, or `select()`; those methods change selection or view context. In particular, `set_shape_data()` currently resets zoom/pan/selection. A presentation change changes no document data, emits no shape-changed signal, and does not mark the document dirty.
|
||||
|
||||
### 4.3 Data and event flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
View[Overview / Focus request] --> Guard{Panel gesture or popup active?}
|
||||
Guard -->|yes| Pending[Keep request pending]
|
||||
Guard -->|no| Move[Reparent one live panel]
|
||||
Pending -->|presentation_safe| Move
|
||||
Move --> Refresh[Update picker, active cue, preview visibility]
|
||||
Refresh --> Status[Document dirty state unchanged]
|
||||
Edit[Draw or transform a part] --> Owner[Live BodyPartPanel / WholeStickmanPreview]
|
||||
Owner --> Controller[StickmanEditor observes commit]
|
||||
Controller --> Assembly[Refresh assembled preview]
|
||||
Controller --> Dirty[Mark Unsaved changes]
|
||||
```
|
||||
|
||||
For example, when the child focuses the left lower arm, its original panel moves from `LeftColumn` to `FocusPanelHost`. Its current `shapes`, selected shape index, `_zoom`, and `_pan_offset` remain in that node. Editing still triggers the controller's existing shape-changed handler; the preview reads from the same ten-node dictionary. Returning to Overview restores that panel to its original slot with the same drawing context.
|
||||
|
||||
## 5. Prop Editor workspace and controls
|
||||
|
||||
Keep the existing `PropCanvas`, scrolling inspector, outer canvas/inspector `HSplitContainer`, and inner Attach preview split. Convert fixed `TopRow`/`TopBar` offsets into container-driven chrome so Grid/Snap, the name field, and mode controls remain visible at larger fonts and narrow sizes. Tool rows may wrap through `FlowContainer`; keep action order stable. Maintain a useful canvas minimum and allow the inspector to scroll rather than clip. Preserve the clicked control's position when a mode reveals a section or Attach preview.
|
||||
|
||||
Restore keyboard focus on Arrange, Reshape, and Attach mode buttons. Give the local Button theme a focus outline that composes with the pressed/selected appearance; keep selected state persistent and text stable. Programmatic refresh uses `set_pressed_no_signal()` as today. Disabled controls explain nonobvious reasons near the control or via a clear tooltip. Arrange-only and Attach-only controls retain their existing mode gating, document mutation, and preview-only behavior.
|
||||
|
||||
Use visible labels and 44 px targets for the primary shape/anchor operations currently hidden in context menus where layout permits. Context menus remain useful shortcuts; the common child path for adding a shape, reshaping a point, and choosing a body part should have an obvious on-screen entry. Preserve Prop's existing two-tone halo and keep its screen-space handles and hit areas distinct. Anchor and preview markers need equivalent contrast against light and dark props. Canvas artwork and material tint values remain unchanged by chrome token migration.
|
||||
|
||||
## 6. Copy, dialogs, and save feedback
|
||||
|
||||
### 6.1 Child-facing wording
|
||||
|
||||
| Current wording | Target copy / rule | Behavioral reason |
|
||||
| --- | --- | --- |
|
||||
| Prop `Friction: 0.xx` | **Surface grip: 0.xx**, with optional helper “Higher values make sliding harder.” | Keep the exact `PhysicsMaterial.friction` value and its surface-contact meaning; do not imply hand gripping or change physics presets. |
|
||||
| Attach `Z Offset` | **Held prop layer** with nearby “Negative: behind · 0: normal order · Positive: farther in front.” Keep the −5…5 integer control and show its visual effect in the preview. | `z_index_offset` is a signed render-layer offset in both preview and held runtime behavior. Zero may draw in front in the preview due tree order, so do not relabel zero as a fixed front/behind category. |
|
||||
| Destructive commands | Prefer **Erase Shape**, **Start Over**, and explicit **Discard Changes** in dialogs. For Start Over, state “Start over with a blank stickman?” and keep a separate visible **Cancel** action. | Say which authored work is affected; pair with a visible Cancel path. |
|
||||
| Technical axis labels | Keep X/Y when they are editable coordinates; use plain helper text where the operation is unclear. | Avoid silently changing geometry or transform semantics while updating words. |
|
||||
|
||||
The Prop Editor's existing dirty title/status and autosave/recovery flow remain authoritative. Improve status wording to clear **Saved** / **Unsaved changes** states; a failed save/load keeps the current document and shows an actionable reason. Preview-only choices, Show Stickman Preview, marker visibility, and mode/view changes do not mark dirty.
|
||||
|
||||
The Stickman Editor adds controller-owned `_current_path: String` and `_dirty: bool`. Name changes, shape edits, shape order, color edits, and committed Whole Stickman position/rotation/scale changes mark dirty; grid/snap, guide, zoom/pan, selection, part picker, and Overview/Focus do not. Add one transform-commit signal or equivalent controller-observable path to `WholeStickmanPreview` that covers translation, rotation, and scale, because its current `part_moved` signal covers only translation. Only a successful save clears dirty; a failed save preserves it. Successful load/clear initializes the expected clean state, and save/load continue to use the existing `.stk` schema and `ContentPaths.canonicalize()` behavior.
|
||||
|
||||
Before Stickman **Load**, **Clear**, or window close replaces unsaved work, show the child-facing **Save / Discard Changes / Cancel** choice. Save with no usable path opens the existing Save dialog and resumes the pending action only after successful save. Cancel or a failed save leaves the document and active view untouched. Clear continues to name that it removes the current stickman. Keep Prop's current New/Close/recovery transactions intact while restyling them. Both editors' dialogs follow the dialog guide: rounded shell, readable type, blue primary action, distinct danger action, 44 px targets, visible labeled dismissal, safe viewport fit, and stable anchor when contents change. Adapt `StageDialogStyler` visual rules; its Stage overlay host is not part of either editor.
|
||||
|
||||
## 7. Static contracts and document boundaries
|
||||
|
||||
| Target | Contract | Owner / boundary |
|
||||
| --- | --- | --- |
|
||||
| `EditorVisualTheme : RefCounted` | `load_from(path: String) -> bool`; typed semantic color/size accessors; local `Theme` construction or copies | Validated shared chrome only; no Stage runtime dependency. |
|
||||
| `PropTheme : RefCounted` | Existing material, primitive, outline, and canvas accessors; temporary UI forwards only while callers migrate | Prop-specific presentation and authoring defaults; never physics material mass/friction/bounce values. |
|
||||
| `PropEditor : Control` | Existing mode, file, autosave, inspector signals and handlers; consume shared chrome tokens | Prop document mutation, Save/Load, dirty, mode control, local Theme. |
|
||||
| `PropCanvas : Control` | Existing typed mode and shape/anchor signals; selection drawing uses canvas tokens | Authoring input and visual feedback. |
|
||||
| `StickmanEditor : Control` | Add `class_name StickmanEditor`; `WorkspaceView`, `request_workspace_view`, `request_active_part`; `_dirty`/pending document action | One live panel dictionary, responsive presentation, `.stk` save/load, dirty state. |
|
||||
| `BodyPartPanel : PanelContainer` | Existing `shape_changed(Array)` and `shape_selected()`; `can_switch_presentation() -> bool`, `presentation_safe`, `add_shape(kind: StringName, at_world: Vector2) -> bool`, `open_selected_color_picker() -> void` | One part's shapes, selection, zoom/pan, gesture/popup safety, and shape operations. |
|
||||
| `WholeStickmanPreview : PanelContainer` | Existing `part_moved(String, Vector2)`; add typed `part_transform_committed(part_name: String, position: Vector2, rotation_deg: float, scale: Vector2)` or equivalent | One assembled preview and document transform commit boundary. |
|
||||
|
||||
No new global bus, serialized `Resource`, duplicate canvas instance, or `.prop`/`.stk` version bump is needed. UI preferences remain session state unless a later feature specifically approves persistence. Saving gathers from the ten live panels and the one live preview, independent of which view is visible.
|
||||
|
||||
## 8. Staged implementation slices
|
||||
|
||||
1. **Shared foundation.** Add the shared editor chrome theme/config and typed accessors. Set semantic roles, focus/selection/disabled states, minimum targets, and scoped theme application. Keep Prop-specific canvas/material tokens. Confirm both config and defaults match.
|
||||
2. **Prop Editor pass.** Migrate Prop chrome to shared roles, fix mode-button keyboard focus, raise touch targets, make top controls and inspector fit, refine labels/help, and style existing dialogs. Preserve its file and autosave behavior.
|
||||
3. **Stickman workspace pass.** Apply the theme to Stickman chrome, introduce Overview/Focus and the body-part picker, move live panel instances safely, add scrolling and narrow preview collapse, preserve drawing context, and expose active-part feedback.
|
||||
4. **Shared state and recovery pass.** Align canvas contrast and action discovery, add complete Stickman dirty/unsaved transactions, and finish dialog and status consistency. Resolve remaining measured layout and contrast issues from rendered review.
|
||||
|
||||
Keep one spec so theme roles, view state, and save behavior are reviewed together. Each slice should leave its editor usable and should report which acceptance outcomes below it satisfies. User-guide changes follow the spec-pipeline documentation phase after the user verifies the feature in the editor.
|
||||
|
||||
## 9. Architectural trade-offs and risks
|
||||
|
||||
| Decision | Benefit | Cost / mitigation |
|
||||
| --- | --- | --- |
|
||||
| Shared semantic editor source with local editor Themes | Consistent chrome and focus states without coupling to Stage internals | Migrate Prop's old `ui` values deliberately; prevent two active authorities for one chrome role. |
|
||||
| Reparent one existing BodyPartPanel into Focus | Preserves shapes, selection, zoom/pan, signals, and current save architecture | Node movement during a gesture/popup is unsafe; defer until `presentation_safe`. Keep original parent/index map. |
|
||||
| Permanent WholeStickmanPreview sibling | One source of assembly transform and preview view state | Narrow layout needs collapse/return controls and a minimum-width fallback. |
|
||||
| Session-only manual view choice | A child's chosen workspace does not jump on resize | Automatic layout helps only until the first manual choice; narrow Overview requires scroll access. |
|
||||
| One umbrella specification, staged slices | Prevents token, mode, and state contracts from drifting across separate documents | Each slice needs explicit acceptance accounting and user review. |
|
||||
| Stickman dirty state added with transform commit | Protects edits during Load/Clear/Close | All authored mutation paths must be audited; translation-only signal is insufficient. |
|
||||
|
||||
Known dependencies: the untracked style guide and design-direction board are source references in this checkout; unrelated dirty Stage work must remain untouched. Theme and layout work can be implemented independently of that Stage work. Prop's in-Stage authoring mode also instantiates `PropEditor`, so chrome changes must preserve its host and hide/disable behavior. Long labels, emoji fallback, larger fonts, and small viewports may expose new minimum-size pressure; resolve by wrapping/scrolling and measured fitting, not by silently shrinking controls.
|
||||
|
||||
## 10. Observable acceptance and verification routes
|
||||
|
||||
| User path | Observable outcome | Verification route |
|
||||
| --- | --- | --- |
|
||||
| Open each editor at a wide window; Tab through menu, primary controls, mode/view buttons, inspector, and dialogs; activate with Space/Enter. | All focusable controls show a distinct focus ring, active mode/view remains visible under focus, and controls meet the agreed target size. | Rendered GUI capture plus real keyboard navigation at ordinary and larger font settings. |
|
||||
| Open Stickman wide, select a part, use Add Shape and Color, draw in a second part, choose Focus on Part, change the focused part, then return to Overview. | The visible actions affect only the active part; Overview has all ten panels; Focus works at wide width; each part retains shapes, selected shape, zoom, and pan; preview updates from edits; no view switch marks dirty. | Interact through production controls; compare panel and preview state before/after switches and inspect rendered captures. |
|
||||
| Open Stickman where Overview's measured minimum does not fit; choose Overview manually, resize wider and narrower, then choose Focus. | Focus is the initial automatic view; Overview remains reachable through scrolling; manual choice remains through resize; Focus preview collapses with visible Whole Stickman access and returns without resetting preview view state. | Rendered narrow/wide GUI session with actual resize and control input. Record viewport dimensions and pane sizes. |
|
||||
| Begin a panel drag or open its color popup, request another view/part, then finish or dismiss that interaction. | The switch waits until the interaction is safe; geometry/color is neither partially committed nor lost; selected shape and pan/zoom remain. | Real input path through the panel and popup; inspect shapes and resulting selection after release/dismissal. |
|
||||
| In Prop, switch Arrange/Reshape/Attach, resize, edit a shape and anchor, and open its preview. | Mode state, inspector sections, top Grid/Snap, canvas, and Attach preview remain reachable without clipped labels or jumping controls; existing document and preview-only dirty rules hold. | Rendered GUI captures of all modes at wide/narrow sizes; check actual edits and status. |
|
||||
| In Prop Attach, set Held prop layer to −1, 0, and +1 and view the preview; save and reopen. | Negative places the held prop behind the rig, zero follows normal ordering, positive places it farther in front; numeric −5…5 values round-trip unchanged. | Preview capture for each value plus a small repeatable save/reopen scenario using an anchor and visible overlapping prop. Confirm runtime held ordering in a Stage scenario where a rig holds the same prop. |
|
||||
| In Prop, choose a material preset and read Surface grip, then switch presets. | The displayed value equals `PhysicsMaterial.friction`; wording describes sliding resistance without changing physics values. | Inspector readback against preset values and rendered text check. |
|
||||
| Edit a Stickman shape, move/rotate/scale a preview part, then Save; edit again and choose Load, Clear, or close. | Every authored mutation sets Unsaved changes; successful Save clears it; Save/Discard Changes/Cancel protects the current document and resumes only the chosen action. | Small repeatable `.stk` scenario: draw and transform two parts, save, reload, compare shape/transform data, then exercise each unsaved branch. Measure status and file content before/after. |
|
||||
| Open save/load/recovery/clear/error dialogs; enlarge type or shorten the viewport. | Primary/destructive actions, visible Cancel/Back/Close, message, and focused control remain accessible; content scrolls or fits without abrupt recentering after a choice. | Rendered dialog states and real pointer/keyboard interactions; capture normal, error, and destructive branches. |
|
||||
| Select artwork with light and dark fills in each editor, drag handles, and use the pose guide/Attach markers. | Selection, active handle, guide, and markers remain legible over both fills and at working zoom; grid stays quieter than the artwork. | Rendered pixel inspection at named scenes/states, with a contrast/color-vision check for text and UI state. |
|
||||
|
||||
Headless parsing or a successful scene launch alone does not establish these visual or interaction outcomes. During implementation, run targeted Godot import/parse and relevant existing regressions, then use a render-capable editor session and real controls for the visual paths. Record scene/state, viewport size, capture location, observed result, and any outcome that could not be verified. Stop for user verification after agent evidence is complete; update user guides only after the user confirms the feature works.
|
||||
@@ -0,0 +1,150 @@
|
||||
# Phase 19 follow-up — Background ground and wall color: architecture specification
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified as part of Phase 19; the scenery suite passes **706 checks with 0 failures**. Implements the [product brief](../plans/phase_19_background_ground_and_wall_color.md) and [UI/UX specification](phase_19_background_ground_and_wall_color_ui_ux.md). This Stage follow-up preserves existing walkable Ground, Prop physics, and artwork contracts.
|
||||
|
||||
## Architectural decision
|
||||
|
||||
Use one small rectangular-surface contract for two distinct inert scenery nodes: `StageWallPanel` and `StageBackgroundGround`. Keep separate scene object types, finish allowlists, draw bands, and erase commands. A shared renderer draws the same material in the chooser, placement ghost, selected-piece preview, and finished scene. `SandboxStage` owns selection, mutations, dirty state, and dialogs; visual controls emit intent only.
|
||||
|
||||
The chosen order is **Sky → Background ground → wall panels → Far artwork → Near artwork → walkable Ground → On the floor artwork → action elements**. Add `StageDrawOrder.BACKGROUND_GROUND = -50` below the existing `WALL = -40`; the Sky stays in its existing background layer. Background ground remains a direct `World` child and has no `CollisionObject2D`, navigation region, support, pickup, Use target, or event identity. Its only Stage behavior outside drawing is Scenery editing.
|
||||
|
||||
```text
|
||||
SandboxStage (scene and input owner)
|
||||
├─ Sky CanvasLayer / StageSkyView
|
||||
├─ World : Node2D
|
||||
│ ├─ StageBackgroundGround : StageRectSurface : Node2D z = -50
|
||||
│ ├─ StageWallPanel : StageRectSurface : Node2D z = -40
|
||||
│ ├─ StageSceneryArtwork (Far / Near / Floor)
|
||||
│ └─ TerrainBlock (walkable Ground; existing collision/navigation)
|
||||
├─ StageSceneryController (placement and transform snapshots)
|
||||
├─ StageSelection / StageGizmos (Scenery scope)
|
||||
└─ UI CanvasLayer
|
||||
├─ AssetSelector (bounded gallery and setup view)
|
||||
├─ StageInspectorPanel (selected Scenery)
|
||||
├─ Stage capture bar
|
||||
└─ themed color and erase dialogs
|
||||
```
|
||||
|
||||
## Typed nodes and API contracts
|
||||
|
||||
| Target | Contract and responsibility |
|
||||
| --- | --- |
|
||||
| New `scripts/stage/scenery/stage_rect_surface.gd`, `class_name StageRectSurface extends Node2D` | Holds `panel_size: Vector2`, `finish_id: StringName`, `tint: Color`, and a transient preview-color flag/value. `func get_local_bounds() -> Rect2` returns a centered positive rectangle. `func set_preview_tint(color: Color) -> void`, `func clear_preview_tint() -> void`, and `func get_render_tint() -> Color` affect drawing only; `tint` remains the saved value. Do not add collision or asset-path state. |
|
||||
| Existing `scripts/stage/scenery/stage_wall_panel.gd`, `class_name StageWallPanel extends StageRectSurface` | Preserve `func configure(new_size: Vector2, finish: StringName, color: Color) -> void` and `motif_origin_offset: Vector2` for erased fragments. Validate only `finish_wall_paint`, `finish_wall_brick`, `finish_wall_wood`; set wall draw order. `_draw()` calls `StageSurfaceRenderer.draw_wall(...)` with `get_render_tint()`. Wall-area subtraction still tests the concrete wall type. |
|
||||
| New `scripts/stage/scenery/stage_background_ground.gd`, `class_name StageBackgroundGround extends StageRectSurface` | `func configure(new_size: Vector2, finish: StringName, color: Color) -> void`; allow only `finish_background_grass`, `finish_background_concrete`, `finish_background_carpet`, set the backdrop draw order, and draw a bounded world-anchored motif. Grass/Concrete ignore Color controls but retain `tint` while the child switches looks; Carpet uses it. Its `get_local_bounds()` supports Stage selection and gizmos. |
|
||||
| Existing `scripts/stage/scenery/stage_surface_renderer.gd`, `class_name StageSurfaceRenderer extends RefCounted` | Add `BACKGROUND_FINISHES: Array[StringName]`, `is_background_finish(id: StringName) -> bool`, `default_tint(finish: StringName) -> Color`, and `draw_background(canvas: CanvasItem, rect: Rect2, finish: StringName, tint: Color, world_origin: Vector2, drawing_scale: Vector2 = Vector2.ONE, cull_to_viewport: bool = true) -> void`. Keep `draw_wall` and `draw_ground`; route preview and Stage through the same finish functions. The default tint is finish-specific, never the old universal green wall value. |
|
||||
| Existing `scripts/stage/stage_draw_order.gd`, `class_name StageDrawOrder extends RefCounted` | Add `BACKGROUND_GROUND: int = -50`. Existing semantic bands and terrain ordering remain stable. |
|
||||
| Existing `scripts/editors/stage/stage_scenery_controller.gd`, `class_name StageSceneryController extends Node` | Add `begin_background_ground(finish: StringName, initial_world_position: Vector2, tint: Color) -> void`. Reuse the existing wall rectangle drag/two-corner, snap, minimum-size, ghost, repeated-placement, and cancel lifecycle through a shared rectangular placement helper. Accept both concrete rectangle types for single and group move/resize; preserve root scale at 1 and change `panel_size`. Keep wall-area eraser restricted to `StageWallPanel`. Existing `placement_committed(node: Node2D)` and `document_change_requested()` signal contracts remain. |
|
||||
| Existing `scripts/stage/stage_selection.gd`, `class_name StageSelection extends RefCounted`, and `scripts/stage/stage_gizmos.gd` | Include `StageBackgroundGround` only in `SelectionScope.SCENERY`, use its transformed `get_local_bounds()` for hit tests and handles, and include it in box selection. `hit_test_all()` and **Pieces here** list overlapping wall, artwork, and backdrop pieces, frontmost first. Ordinary ACTION selection still excludes all scenery surfaces. |
|
||||
| Existing `scripts/editors/stage/stage_scene_adapter.gd`, `class_name StageSceneAdapter extends RefCounted`, and `scripts/stage/stage_scene_io.gd`, `class_name StageSceneIO extends RefCounted` | Add explicit `background_ground` encode/decode/validation and an old-scene color migration (below). Do not route decorative ground through `TerrainBlock` or Ground finish serialization. |
|
||||
| Existing `scripts/editors/stage/sandbox_stage.gd`, `class_name SandboxStage extends Node2D` | Owns selected-piece Look/Color/Erase handlers, color-dialog session, shared recent colors, confirmation target, dirty-state transition, and chooser-to-controller handoff. Refresh widgets with no-signal setters. It must include Background ground in all Scenery-only membership, selection, deletion, save, and mode gates. |
|
||||
|
||||
Keep exact concrete-type checks wherever behavior truly differs, especially wall-area erase. For common rectangle handling, use `node is StageRectSurface` or a small typed helper instead of another list of exact-script comparisons. Do not broaden physics or action selection by using a generic `Node2D` group.
|
||||
|
||||
### Style and color rules
|
||||
|
||||
The selected `Color` is a material base tone. Paint fills directly. Brick uses that tone for brick faces and derives bounded light/dark face variants; mortar remains a legible neutral with contrast against the chosen face. Wood derives plank, grain, highlight, and seam tones from the chosen base while preserving the plank pattern. Carpet derives restrained lighter/darker fibers from its chosen tone. Very light, dark, and saturated colors must still show texture; use a deterministic luminance-aware palette transform with bounded contrast, rather than `CanvasItem.modulate` or a flat overlay. Grass and Concrete have designed palettes and no Color control in this follow-up. All four colorable looks can use imaginative hues.
|
||||
|
||||
New choices use opaque colors. Preserve any valid eight-digit color already stored in an older scene until the user edits it. `StageSurfaceRenderer.default_tint()` supplies visually natural Brick and Wood defaults plus usable Paint and Carpet defaults. Switching Look retains the piece's saved `tint`; switching from Carpet to Grass and back reveals the same Carpet color. In the chooser, each new look starts at its own default until the child explicitly chooses a color; after that, a chosen color follows the child between colorable looks. Merely opening the chooser or drawing with an untouched default does not add history.
|
||||
|
||||
### World-anchored pattern and drawing cost
|
||||
|
||||
Map every motif sample to an integer world-grid cell, seeded only from cell coordinates and finish ID. Clip motif geometry to the panel rectangle and to the visible local viewport rectangle. Moving or resizing a piece changes which world cells are visible; it never scales or restarts a texture from that piece's top-left corner. Adjacent same-finish pieces therefore share pitch and phase. Keep a stable world-space pitch at normal zoom. If a distant zoom needs a coarser level of detail, derive the level from **camera zoom/viewport transform**, not individual panel size; every piece at the same zoom must choose the same level. At small projected size, draw the material base and a restrained subset of motifs. Cap visible-cell work per draw and avoid a full-panel loop for broad backgrounds.
|
||||
|
||||
The existing `StageSurfaceRenderer` brick/wood detail functions currently adapt to the visible rectangle; the follow-up must make any detail-level decision common across adjacent pieces. Existing walkable Ground's grass is concentrated at its top edge; Background ground Grass needs deterministic interior tufts/color variation distributed over its whole rectangle. Concrete needs restrained joints/speckle rather than reusing Sidewalk unchanged. Carpet uses low-contrast short fibers or weave marks at world scale. The setup preview renders a representative world-sized sample with the same renderer, fitted into its card/preview `Control`; it does not stretch an image of the final rectangle. Decorative preview controls ignore pointer input. The Stage ghost can use the same node with alpha modulation and the existing EDIT outline/corner overlay.
|
||||
|
||||
## Scene schema and compatibility
|
||||
|
||||
Advance `StageSceneIO.FILE_VERSION` from `"1.5"` to `"1.6"`; retain reads of v1.0–v1.5. New pieces use a distinct type:
|
||||
|
||||
```json
|
||||
{
|
||||
"file_id": "background_ground_1",
|
||||
"type": "background_ground",
|
||||
"position": {"x": 420.0, "y": 180.0},
|
||||
"rotation": 0.0,
|
||||
"size": {"x": 800.0, "y": 360.0},
|
||||
"finish_id": "finish_background_carpet",
|
||||
"color": "#8B537BFF"
|
||||
}
|
||||
```
|
||||
|
||||
`size` must be finite and positive, `finish_id` must be one of the three background IDs, and `color` must pass the existing `StageSceneIO` hex parser. Store Color for every piece, including Grass/Concrete, so changing Look preserves it. Serialize the live `tint`, never the transient preview tint. Preserve `World` child order when collecting/restoring so overlaps of pieces in the same draw band stay visually stable; the distinct draw bands determine inter-category order. Background pieces need no `scale` field: a resize edits `size`, retaining world pattern pitch. Old `wall_panel` entries keep their existing fields, including optional `motif_origin_offset`; Paint colors remain intact.
|
||||
|
||||
For v1.5 and earlier documents, migrate a Brick or Wood wall's color **only when its saved value is the old default `#5A9D70` or the color is absent** (case-insensitive, optional `#`, with opaque `FF` accepted). Replace that placeholder with the corresponding natural `default_tint()` before validating/loading, because old Brick/Wood drawing ignored the saved tint. Preserve Paint and every non-placeholder Brick/Wood color exactly, including alpha. Never run this rule on v1.6: a child may deliberately choose the same green for Brick or Wood. Missing Paint color keeps its old default. Migration changes the in-memory document; the new version and color are written on its next normal save. Do not alter source files merely on open. Invalid enum/color/size must remain a load error under existing validation rules, and a failed load must not replace the current scene.
|
||||
|
||||
The Stage's `user://sandbox_settings.json` gains `recent_surface_colors: Array[String]`, independent of `.scene` files. Canonicalize to uppercase opaque `#RRGGBB` for new history entries; validate on load, discard malformed/duplicate entries, keep at most eight newest first, and tolerate the key being absent. A valid preset/recent press or confirmed custom color moves it to the front. A canceled dialog, opening a picker, switching Look, and placing an untouched default do not change history. Extend the existing settings load/save methods so saving grid/snap/recent scenes also retains this list. A history write never marks the scene dirty or recolors placed pieces; a placed-piece confirmed color change marks that scene dirty once.
|
||||
|
||||
## UI composition and signal flow
|
||||
|
||||
`AssetSelector` keeps the existing bounded `PopupPanel`, fixed title/Close, tab shell, and scroll body. For Scenery Backgrounds, its first view shows Sky, Wall panel, and Background ground cards; the latter two navigate to an internal setup view. `StageAssetBrowser` supplies IDs/labels, while the chooser owns transient finish/color choice and emits a typed-intent payload through its existing `item_selected(entry: Dictionary)` signal only when **Draw** is pressed. Suggested payload:
|
||||
|
||||
```gdscript
|
||||
{
|
||||
"background_kind": "background_ground", # or "wall"
|
||||
"finish_id": "finish_background_carpet", # String
|
||||
"color": Color("#8B537B"), # in-memory Color, never a saved Variant
|
||||
}
|
||||
```
|
||||
|
||||
Sky continues its immediate-selection route. Choosing a look or color in setup updates only setup state; no Stage tool starts and no existing piece changes. `SandboxStage` closes the chooser, calls the correct `StageSceneryController.begin_*` function with the exact chosen finish/color, and displays the patterned ghost. The chooser's setup view uses native focusable look buttons, one shared wrapping Color control, a representative renderer preview, Back, and Draw inside the bounded scrolling area. It does not inherit `StageInspectorPanel`, whose layout and dismissal rules serve selected Stage objects.
|
||||
|
||||
For selected pieces, extend the **existing** Scenery `StageInspectorPanel` body. Use its fixed header, safe rectangle, scroll position, `style_action_button`, and compact Settings reopen behavior. `StagePanelChoiceGroup` owns **Look** choices and emits `choice_selected(id: StringName)`; its cue controls are render-only. Add one shared `scripts/shared/stage_ui/stage_surface_color_controls.gd`, `class_name StageSurfaceColorControls extends VBoxContainer`, for current color, up to eight recent swatches, presets, and **More colors…**. Its typed contract is `signal color_selected(color: Color)`, `signal custom_color_requested()`, `func configure(selected: Color, recents: Array[Color], presets: Array[Color], stage_theme: SandboxTheme) -> void`, and `func set_selected_no_signal(color: Color) -> void`. Extend the existing `ColorSwatchSelector` from a single row to a wrapping `FlowContainer`, preserving `configure(colors: Array[Color], selected: Color, theme: Variant)`, `set_selected`, and `color_selected(color: Color)`. Refresh both recent and preset groups without emission. `StagePanelToggleRow` is not used because no surface option is boolean. No second inspector shell or choice styling is introduced.
|
||||
|
||||
The custom color dialog uses a native `ColorPicker` in a themed, screen-bounded dialog with its own representative material preview, **Use color**, and **✕ Cancel**. It adopts `SandboxTheme.control_theme()` and popup/dialog tokens, not the Stage inspector hierarchy. For a selected piece, `SandboxStage` holds a provisional session `{target: WeakRef, original_color: Color, tentative_color: Color}`. `ColorPicker.color_changed(color: Color)` calls `target.set_preview_tint(color)` and redraws the dialog preview; it does **not** change `target.tint`, recent history, scene dirty state, or serialized snapshots. **Use color** validates the target and commits `tint = tentative_color`, clears the preview override, records history, and marks the scene dirty once if the color actually changed. **Cancel**, dialog close, Esc, target deletion, scene replacement, and mode switch clear the preview override without a document edit. Because `StageSceneAdapter.collect()` reads `tint`, ordinary Save/autosave cannot serialize a tentative color. For chooser use, the session targets only setup state and its dialog preview; Cancel restores the prior chooser color. A preset/recent press is already confirmed: update the one selected piece immediately, record history, mark dirty once if changed, and refresh the card without sending another choice signal.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Chooser[Scenery setup: Look + Color] -->|Draw payload| Stage[SandboxStage]
|
||||
Stage -->|begin_wall / begin_background_ground| Draft[StageSceneryController ghost]
|
||||
Draft -->|valid release| Piece[World surface node]
|
||||
Piece -->|document_change_requested| Dirty[Scene dirty + save]
|
||||
Piece -->|Edit Scenery select| Card[StageInspectorPanel]
|
||||
Card -->|Look or confirmed swatch| Stage
|
||||
Card -->|More colors| Dialog[Provisional ColorPicker]
|
||||
Dialog -->|color_changed| Render[Transient render tint]
|
||||
Dialog -->|Use color| Stage
|
||||
Dialog -->|Cancel| Restore[Clear render tint]
|
||||
```
|
||||
|
||||
### Erase and selection rules
|
||||
|
||||
Background ground is erasable. In **Edit Scenery**, select one Background ground piece and press **Erase background ground**. The shared confirmation asks **“Erase this piece?”** with **Keep it** and **Erase**. The Delete/Backspace path for a selected Scenery surface calls the same confirmation; it must not fall through to `SandboxStage.delete_selected()`'s immediate generic deletion. Confirmation captures the intended node as a weak reference, checks it is still a live `World` child in Edit Scenery, erases only that node, clears selection/hover, and marks the scene dirty once. Keep it, Cancel, Esc, or closing the confirmation leaves the piece and dirty state unchanged. Wall panels use the corresponding **Erase wall panel** action; **Erase wall area** remains a separate wall-only rectangle subtraction and never cuts Background ground. A group delete, if exposed, must present its member count and follow the existing Phase 19 group confirmation boundary.
|
||||
|
||||
The backdrop's broad area must not capture normal EDIT clicks. In Scenery scope, a higher draw band wins a click; a smaller visible item at equal depth wins, and **Pieces here** lists all hits so a covered background remains reachable. Scenery box selection and group move/resize include Background ground; group preview restores exact size/position on Cancel and commits once on Keep. Selection outlines and corner hit regions follow the existing minimum 44 × 44 logical-pixel Stage gizmo contract. Mode/tool switches cancel an unfinished placement or provisional edit before changing scope. The capture bar reuses the Stage's existing EDIT capture pattern, puts prompt and visible **Done / ✕ Cancel** together below the mode pill, and names the non-walkable role.
|
||||
|
||||
## Theme, focus, and responsive layout
|
||||
|
||||
The selected-piece card adopts `stage_panels.shell`, `.type`, `.choice`, and `.action` from `SandboxTheme.DEFAULT_CONFIG` and `sandbox_theme.json`; add narrowly scoped swatch/preview tokens only for values those groups cannot express. The chooser and color dialog use `popups.asset_selector` / `popups.dialog` and `SandboxTheme.control_theme()`. Create local StyleBox copies for selected/hover/focus states; do not mutate the cached shared `Theme`. Every swatch/button target is at least 44 × 44 logical pixels, with text or a color value as well as its fill. Keep native focus and Space/Enter activation, separate focus ring and selection border, and restore focus to the dialog opener on close.
|
||||
|
||||
Fit both popup windows to the usable display rectangle, accounting for the current root window and OS usable screen area. Keep chooser title/Close and inspector header/Close fixed while their contents scroll. `FlowContainer` wraps colors and look cards before horizontal clipping; Draw and dialog actions remain reachable when fonts grow or the display is short. The inspector uses `set_safe_rect()` and preserves scroll position during a Look/Color change. The Stage capture bar stays below the mode pill and does not cover it.
|
||||
|
||||
## Implementation sequence and repeatable behavior review
|
||||
|
||||
1. Add the scene v1.6 migration/validation and `background_ground` adapter path; preserve old-scene visuals and verify malformed entries are rejected before replacing the live scene.
|
||||
2. Add the common rectangle contract, draw band, and deterministic material rendering. Connect renderer samples to chooser cards, setup preview, ghost, and live nodes.
|
||||
3. Extend Scenery placement, selection, gizmos, group transforms, inspector, erase confirmation, and dirty/save boundaries. Keep wall-area erase concrete-wall-only.
|
||||
4. Extend the shared swatch control and user-settings history, then wire the bounded chooser and provisional custom-color dialog.
|
||||
|
||||
| Child path / runtime scenario | Required observation |
|
||||
| --- | --- |
|
||||
| Scenery → Backgrounds → Wall panel → Brick → default Draw; repeat with chosen color | Both ghosts and placed walls show brick mortar/detail and the chosen hue. The default looks like natural brick. Drawing with an untouched default adds no recent color. |
|
||||
| Scenery → Backgrounds → Background ground → Grass → draw broad rectangle; place a walkable Ground strip in front; PLAY | Grass detail appears across the backdrop, buildings/trees appear in front, and the stickman walks only on the separate Ground strip. Backdrop adds no collision/navigation/event target. |
|
||||
| Draw adjacent Grass or Carpet pieces; move/resize one; zoom in/out | Motif pitch does not stretch and matching neighbors align at the same zoom. A large partly off-screen piece draws only bounded visible detail. |
|
||||
| Edit Scenery → select one wall → Look/Color; select one Carpet → Color | Only the selected piece changes. Changing Carpet to Grass and back restores its saved carpet color. Inspector scroll and selection remain stable; chooser/ghost/Stage material character agrees. |
|
||||
| More colors… on selected Brick/Carpet → change picker several times → Cancel; repeat → Use color | Stage and dialog preview each tentative color. Cancel restores original and adds no recent or scene edit, even if autosave occurs. Use color commits once and moves that color to the front of recents. |
|
||||
| Select eight colors across Paint, Brick, Wood, Carpet; reopen scene and restart Stage | One shared newest-first, deduplicated eight-color list survives restart. Each saved piece keeps its own color; history changes do not recolor another piece. |
|
||||
| Load a v1.5 scene with old green Brick/Wood and Paint; load another with a non-placeholder Brick color; save/reopen | Placeholder Brick/Wood take natural defaults, Paint and the non-placeholder color are preserved, and v1.6 save/reopen preserves the result. An intentionally green v1.6 Brick remains green. |
|
||||
| Edit Scenery → select Background ground through its exposed area or Pieces here → resize/group preview/Cancel/Keep | It is selectable only in Scenery scope, handles remain reachable, Cancel restores exact geometry, Keep commits one change, and normal EDIT clicks still reach interactive objects. |
|
||||
| Select Background ground → Erase background ground → Keep it; then Delete → Erase | Keep it leaves the scene unchanged. Erase removes exactly the captured piece after confirmation and leaves walkable Ground intact. Wall-area eraser cannot cut Background ground. |
|
||||
| Narrow/short display with larger fonts; chooser setup and custom color dialog | Close, Back, Draw, More colors, Use color/Cancel, inspector Close, and capture-bar Cancel remain visible or scroll-reachable by touch and keyboard; no UI spills below the usable screen or covers the mode pill. |
|
||||
|
||||
These scenarios are product behavior checks. They do not require a new test suite by themselves; implementers should use the project’s existing verification routes where needed to establish the behavior, especially scene loading, renderer output, and live selection.
|
||||
|
||||
## Trade-offs and limits
|
||||
|
||||
- A shared rectangle base avoids repeated size, bounds, and transient-preview behavior. Distinct concrete nodes and scene types keep semantic draw order, finish validation, and wall-only erasure explicit. A single `TerrainBlock` or one material-kind enum would blur physics and editing boundaries.
|
||||
- World-grid procedural motifs keep resizing and adjoining pieces coherent without texture assets. Visible-region culling and zoom-consistent detail control limit draw work; if many giant overlapping surfaces later become costly, cache only measured hot paths rather than introducing a render-texture cache now.
|
||||
- Scene v1.6 migration is necessary because v1.5 stored unused Brick/Wood green. It changes only the known placeholder on older documents; ambiguous intentional uses of that exact placeholder cannot be distinguished retrospectively. All v1.6 colors are authoritative.
|
||||
- A transient render tint keeps custom-color preview visible while the saved model and autosave remain stable. It avoids copying live Stage nodes into a modal overlay or treating tentative input as an undoable document edit.
|
||||
- Recent colors are per-user settings; placed colors are document data. Keeping these sources separate makes scene sharing and restart behavior predictable.
|
||||
@@ -0,0 +1,111 @@
|
||||
# Phase 19 follow-up — Background ground and wall color: UI/UX specification
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified as part of Phase 19; the scenery suite passes **706 checks with 0 failures**. This extends the [Phase 19 Scenery UI specification](phase_19_scenery_backgrounds_ui_ux.md); its Sky, artwork, Edit Scenery, and placement behavior remain applicable.
|
||||
|
||||
## Child promise
|
||||
|
||||
A child can choose what a wall or distant ground area looks like, see that look before drawing, and change one placed piece later. **Background ground is scenery:** it looks like ground, stays behind the set, and does not make a walking path. The separate **Ground** palette tool remains the way to make a path that stickmen can walk on.
|
||||
|
||||
The Scenery chooser supplies the same material and color choices for new pieces that the selected-piece card supplies for placed pieces. The color shown in the chooser, its preview, the placement ghost, and the finished piece must agree. Paint, Brick, Wood, and Carpet share eight recently used colors. Grass and Concrete have designed looks and no Color control in this follow-up.
|
||||
|
||||
## Flow and navigation
|
||||
|
||||
```text
|
||||
Scenery → Backgrounds
|
||||
Sky → existing immediate Sky cards
|
||||
Wall panel → Paint / Brick / Wood → choose color → Draw wall panel
|
||||
Background ground → Grass / Concrete / Carpet → choose color for Carpet → Draw background ground
|
||||
|
||||
Edit Scenery → select one piece → Look / Color where available / Erase
|
||||
```
|
||||
|
||||
- **Backgrounds** first shows three large, illustrated choices in this order: **Sky**, **Wall panel**, **Background ground**. Wall panel and Background ground open a setup view *inside the existing bounded Scenery chooser*. An explicit **‹ Back** returns to the three choices; the fixed **✕ Close** dismisses the chooser. Sky keeps its approved immediate-selection behavior.
|
||||
- The setup view shows one clearly selected look, a large representative preview, the Color control when that look supports color, a short role helper, and a large **Draw wall panel** or **Draw background ground** action. Entering the view selects the natural default look and its default color. **Draw** is available immediately: a child can use the default without opening Color.
|
||||
- Choosing a look updates the preview in place; it does not start placement or close the chooser. Wall look choices are **Paint**, **Brick**, **Wood**. Background ground choices are **Grass**, **Concrete**, **Carpet**. Before a child chooses a color, each new look uses its believable finish-specific default; after the child chooses a color, switching looks keeps that chosen color. Grass and Concrete show their designed appearance; Carpet begins with a usable default fabric color.
|
||||
- The chooser closes only after **Draw**. The Stage then arms the corresponding rectangle tool with exactly the chosen look and color. Returning to Scenery later may show the last choice for convenience, but opening the chooser must not modify an existing piece or silently start a tool.
|
||||
- Artwork keeps the existing **Artwork** tab. **Edit placed scenery** remains reachable from the chooser. The chooser retains a fixed title/Close row, a scrollable content area, and its existing bounded screen layout. The setup view does not become an in-stage inspector.
|
||||
|
||||
## Setup view layout and controls
|
||||
|
||||
Use the existing Scenery chooser shell, card treatment, and theme. The contents of its scroll area should follow this structure:
|
||||
|
||||
```text
|
||||
ScrollContainer
|
||||
└─ VBoxContainer
|
||||
├─ Back + category heading
|
||||
├─ Look heading
|
||||
├─ adaptive look cards (one native Button per look)
|
||||
├─ large live material preview
|
||||
├─ Color section (Paint / Brick / Wood / Carpet only)
|
||||
│ ├─ selected-color swatch/button
|
||||
│ ├─ Recently used + wrapping swatches (up to eight)
|
||||
│ ├─ Colors + wrapping preset swatches
|
||||
│ └─ More colors… button
|
||||
├─ role helper
|
||||
└─ Draw action
|
||||
```
|
||||
|
||||
Look cards show material detail at card size, a stable name, a clear selected border and fill, and a separate keyboard focus ring. The large preview uses the same drawing rules as the placed surface at an appropriate scale; Brick mortar, Wood grain, Grass interior detail, Concrete treatment, and Carpet fabric remain visible. Preview decorations ignore pointer input. A selected color swatch shows the actual color as well as a text label or readable color value, so selection never depends on color alone.
|
||||
|
||||
The color row uses two wrapping groups: **Recently used** first, then **Colors** for common presets. Eight recents fit across multiple rows on narrow displays; the group never expands the popup horizontally. An empty history shows **“Colors you use will appear here”** rather than eight blank targets. Duplicate colors appear only once in the history. Each swatch is a single focusable button with a visible selected state, focus ring, and a readable name or color value in its accessible/tooltip text. Touch and click targets are at least 44 × 44 logical pixels. Extend the existing shared `ColorSwatchSelector` or extract a common swatch control instead of building a second swatch style for the chooser and inspector.
|
||||
|
||||
Choosing a recent or preset swatch changes the chosen color and preview immediately. That confirmed choice moves to the front of the shared recent list. The history is shared by Wall Paint, Brick, Wood, and Background ground Carpet, persists across scenes and restarts, and changes no already placed pieces. Merely opening the chooser or drawing with an untouched default color does not create a recent entry.
|
||||
|
||||
**More colors…** opens a bounded, themed color dialog. It shows the color picker and a live preview of the *current look* with the tentative color. The actions are **Use color** and **✕ Cancel**. **Use color** confirms the new color, closes the dialog, updates the setup preview, and adds that color to Recently used. **Cancel**, the dialog Close control, or Esc restores the color held before the dialog opened and leaves history unchanged. The dialog receives `SandboxTheme.control_theme()`, uses popup/dialog tokens, and clamps to the usable display area; its controls scroll if necessary while both actions stay reachable. Returning from the dialog restores focus to **More colors…** or the color control.
|
||||
|
||||
## Drawing on the Stage
|
||||
|
||||
- Drawing a wall keeps the existing **Draw wall panel** rectangle behavior. Drawing Background ground uses the same drag or two-tap corner interaction, snap feedback, minimum valid size cue, and repeated-placement tool lifecycle. The background surface is finite; releasing a valid rectangle places one piece, with **Done** and **✕ Cancel** remaining available for another placement.
|
||||
- The Stage shows a translucent, **patterned** ghost under the cursor before the first corner and a continuously updating patterned rectangle while dragging. The ghost uses the selected material and color. The motif stays at a stable Stage scale as the rectangle changes size; resizing reveals more of it instead of stretching it. A bright EDIT outline and corner reticle make the intended area visible over any Sky. Invalid drafts use the existing red outline and a plain instruction: **“Make this area bigger.”**
|
||||
- Keep the existing screen-space capture-bar position below the toolbar and EDIT mode pill, using the shared Stage capture-bar pattern and `mode_colors.edit` accent. The bar names the current action and keeps **Done** and **✕ Cancel** together. A short pointer pill follows the cursor: **“Drag to draw wall”** or **“Drag to draw background ground.”** The prompt stays near the working point; the header and status bar do not carry essential instructions.
|
||||
- The chooser and capture bar both explain the role in words. The Background ground card and setup helper say **“Decorative only · Stickmen don’t walk here.”** Its capture bar can shorten this to **“Draw background ground · Stickmen don’t walk here.”** The Wall panel helper says **“Looks like a wall · Stickmen can pass through.”** These messages remain visible without hover and do not rely on color or icons.
|
||||
- Cancel during a draft discards the draft. A completed piece stays when placement ends, matching existing Scenery behavior; after one placement, the capture bar includes **“Placed pieces stay.”** Esc and right-click remain shortcuts, while the visible buttons serve touch and keyboard users. Switching mode or tool removes the unfinished ghost.
|
||||
|
||||
## Editing a placed piece
|
||||
|
||||
**Edit Scenery** is the only ordinary selection mode for broad wall and Background ground pieces. A regular EDIT click still favors characters, Props, and walkable Ground. In Edit Scenery, clicking an exposed part or edge of a background piece selects it; a smaller visible item under the pointer wins over a broad background. The existing **Pieces here** chooser lists all matching pieces with large labeled rows when they overlap, so a covered Background ground or wall remains selectable. Background ground joins Scenery box selection and multi-piece movement/resizing under the existing group preview rules.
|
||||
|
||||
One selected piece uses the existing `StageInspectorPanel` shell: fixed name/icon/Close header, scrollable body, safe-screen fitting, and the compact **Settings** button to reopen a dismissed card. The body uses `StagePanelChoiceGroup` for **Look**, stable choice labels, and preview cues. It uses the same wrapping Color control as the chooser, with the selected piece's saved color as the starting value. Theme and minimum heights come from `stage_panels` and `SandboxTheme`; the card is not a separate visual system.
|
||||
|
||||
| Selected piece | Header and controls |
|
||||
| --- | --- |
|
||||
| Wall panel | **Wall panel**; **Look:** Paint / Brick / Wood; **Color**; **Erase wall area**; **Erase wall panel**. |
|
||||
| Background ground | **Background ground**; **Look:** Grass / Concrete / Carpet; **Color** only for Carpet; **Erase background ground**. A short helper repeats **“Decorative only · Stickmen don’t walk here.”** |
|
||||
|
||||
Changing Look or choosing a recent/preset color updates **only the selected piece** immediately. A Look change preserves that piece's stored color, including when changing away from and back to Carpet; this keeps Look and Color independent. A custom color dialog previews its tentative result on that selected piece while open; **Use color** commits it and adds it to history, while **✕ Cancel** restores the piece's prior color and leaves history unchanged. The color dialog's preview and the Stage use the same material drawing rules. The card remains open, keeps its scroll position, and refreshes choices without emitting a second edit.
|
||||
|
||||
The existing large move/resize handles, dark-backed selection outline, button size steps where applicable, and single-piece release-to-commit behavior apply to Background ground as they do to wall panels. Moving or resizing preserves motif scale and alignment with adjacent matching pieces. **Erase** asks **“Erase this piece?”** with **Keep it** and **Erase** before removing one piece; the Delete key follows the same safeguard. **Erase wall area** affects wall panels only and retains the approved cutout behavior. Group edits and their **Keep changes / ✕ Cancel** boundary remain as specified for Phase 19.
|
||||
|
||||
## Theme, responsiveness, and input
|
||||
|
||||
- The Scenery chooser and color dialog use `SandboxTheme.control_theme()` and existing `popups.asset_selector` / `popups.dialog` presentation rules. The inspector uses `stage_panels.shell`, `.type`, `.choice`, and `.action`; EDIT accents come from `mode_colors.edit`. Introduce focused token entries for swatch spacing/selection, look preview sizing, and dialog actions only where existing tokens do not cover them. Add matching entries to `SandboxTheme.DEFAULT_CONFIG` and `sandbox_theme.json`; avoid fixed UI colors or font sizes in the new controls.
|
||||
- Layout uses `VBoxContainer`/`HBoxContainer` for sections and `FlowContainer` for swatches and any wrapping look choices. The title and Close stay fixed while content scrolls. Card columns and swatches wrap before they clip; labels wrap; the Draw button stays in the scroll order and reachable on short screens. The chooser and color dialog fit inside the unobstructed display, including raised font sizes. No selected-piece card or capture bar covers the mode pill.
|
||||
- Every action, swatch, card, and handle has a pointer hit region of at least 44 × 44 logical pixels; button and row heights respect theme `button_min_height` or `stage_panels` minimum target tokens. Text, outline, and focus signal choices in addition to color. Tab order follows Back → Look → Color → Draw → Close in the setup view, with Close always reachable. Space/Enter activates focused choices. The dialog traps focus while open, and closing it returns focus to its opener; closing the chooser returns focus to Scenery. Touch can use two taps for rectangle corners and can always reach Cancel without Esc.
|
||||
- Opening a selected-piece card from the keyboard places focus at its first useful control. Closing it keeps the piece selected, shows the compact Settings reopen action, and returns focus to the Stage or the opener. Scrolling the card must not drag the piece underneath.
|
||||
|
||||
## Copy map
|
||||
|
||||
| Where | Exact child-facing text |
|
||||
| --- | --- |
|
||||
| Backgrounds category | **Wall panel**; **Background ground** |
|
||||
| Background ground role | **Decorative only · Stickmen don’t walk here.** |
|
||||
| Wall role | **Looks like a wall · Stickmen can pass through.** |
|
||||
| Setup sections | **Look**; **Color**; **Recently used**; **Colors**; **More colors…** |
|
||||
| Setup primary action | **Draw wall panel** / **Draw background ground** |
|
||||
| Stage pointer pill | **Drag to draw wall** / **Drag to draw background ground** |
|
||||
| Too-small draft | **Make this area bigger.** |
|
||||
| Selected-piece actions | **Erase wall area**; **Erase wall panel**; **Erase background ground** |
|
||||
| Color dialog | **Use color**; **✕ Cancel** |
|
||||
|
||||
## Observable acceptance outcomes
|
||||
|
||||
1. From Scenery → Backgrounds, a child can choose Wall panel or Background ground, inspect the natural default, and press Draw without visiting Color. The placed preview and final piece show the same material and color.
|
||||
2. Color is available for Paint, Brick, Wood, and Carpet in both setup and selected-piece editing. Brick mortar, Wood grain, and Carpet texture stay recognizable after choosing a light, dark, or saturated color. Grass detail reads inside a large rectangle at normal Stage zoom.
|
||||
3. After choosing eight distinct colors, the history shows newest first in both flows, wraps on a narrow screen, survives a scene change and restart, and has no duplicate. Canceling a tentative custom color changes neither saved color nor history.
|
||||
4. A child can change one selected wall or Background ground piece without changing its neighbors. Changing Look preserves its stored color; selecting Carpet again restores its prior Carpet color. A canceled custom-color preview restores the selected piece.
|
||||
5. A broad Background ground is selectable in Edit Scenery, including through **Pieces here** when covered, and stays out of ordinary EDIT selection. Move, resize, erase, and multi-piece edit controls remain accessible. The separate Ground palette remains clearly marked as walkable.
|
||||
6. On a short or narrow display with larger fonts, chooser title/Close, color dialog actions, inspector header/Close, capture-bar Cancel, and every swatch remain reachable by touch and keyboard. No control spills below the visible screen or covers the mode pill.
|
||||
|
||||
## Remaining UI decisions
|
||||
|
||||
The accepted flow leaves no blocking user-facing choice. During architecture, settle the exact shared swatch-control API and token names, the setup view's retained-choice lifetime, and how the color dialog provides a provisional Stage preview without committing until **Use color**. These choices must preserve the observable behavior above.
|
||||
@@ -0,0 +1,118 @@
|
||||
# Phase 19 — Plain Background: architecture specification
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified. The user explicitly verified Plain Background save/reopen; the Phase 19 scenery suite passes 706 checks with 0 failures. This specification implements the [Plain Background brief](../plans/phase_19_plain_background.md) and [UI/UX specification](phase_19_plain_background_ui_ux.md). The color-choices and custom-picker PNGs reflect the current-color chip as the sole custom-picker entry and the simple **Preview** label; the solid fill and exact labels in the UI/UX specification govern implementation.
|
||||
|
||||
## Scope and decisions
|
||||
|
||||
Plain Background is a scene-wide, opaque backdrop. It is not a Stage object, a wall panel, or Background ground. The initial color is `#F5EFE0`. File → New adds a truly empty Plain Background starter and relabels the existing neutral-Sky starter **Open Sky**. EDIT → Scenery → Backgrounds offers Plain Background beside the four existing Sky cards. A scene remembers its confirmed plain color while a Sky is active.
|
||||
|
||||
The approved design uses a small shared view composed of the existing `StageSkyView` and a full-rect solid `ColorRect`. `SandboxStage` owns the confirmed scene values and the short-lived picker draft. No `Resource`, global signal bus, or extra selectable node is needed for three scalar document values. The Stage inspector kit (`StageInspectorPanel`, `StagePanelChoiceGroup`, `StagePanelToggleRow`) remains for selected objects; this is a modal chooser and uses `AssetSelector`, `AssetCard`, the existing color controls, and their theme tokens.
|
||||
|
||||
When Sandbox Stage launches as the active scene without a requested scene, `SandboxStage` opens the starter chooser once after startup recovery handling. A restored autosave remains the active scene without a chooser; discarding recovery opens the chooser. CLI scene requests and load errors keep their existing flows. Closing the startup chooser leaves the empty EDIT Stage open and does not reopen the chooser for that session.
|
||||
|
||||
## Node hierarchy and rendering
|
||||
|
||||
```text
|
||||
SandboxStage : Node2D
|
||||
├─ StageBackgroundLayer : CanvasLayer (layer -1)
|
||||
│ └─ StageBackgroundView : Control (full viewport; ignores mouse)
|
||||
│ ├─ StageSkyView : Control (camera-bound only on the live Stage)
|
||||
│ └─ PlainFill : ColorRect (full rect, opaque, ignores mouse)
|
||||
├─ StageGrid : Node2D (EDIT overlay)
|
||||
└─ World : Node2D (existing placed objects)
|
||||
|
||||
StageStarterCardPreview : SubViewportContainer
|
||||
└─ PreviewViewport : SubViewport
|
||||
├─ PreviewBackgroundLayer : CanvasLayer (layer -1)
|
||||
│ └─ StageBackgroundView (unbound still)
|
||||
└─ PreviewWorld : Node2D
|
||||
|
||||
AssetSelector scene-wide card
|
||||
└─ StageBackgroundCardPreview : Control
|
||||
└─ StageBackgroundView (unbound still, clipped to card)
|
||||
```
|
||||
|
||||
`StageBackgroundView` toggles its Sky and Plain children exclusively. A Plain view is a single opaque viewport-sized rect, with no gradient, horizon, motif, parallax, or world transform. Its anchors respond to viewport resize. `StageSkyView` continues to own all five existing Sky IDs and camera response; when hidden for Plain it should not spend frames updating Sky motifs. The view and both children ignore mouse input and never enter Stage selection or draw-order lists. The starter preview must use the same background-kind and color interpretation as the live Stage. The gallery card receives the **remembered** plain color even when the active kind is Sky. Card frames and labels are UI overlays outside the fill, not part of its sample.
|
||||
|
||||
## Typed contracts and ownership
|
||||
|
||||
| Target | Contract and change | Owner responsibility |
|
||||
| --- | --- | --- |
|
||||
| `scripts/stage/scenery/stage_background_view.gd`, `class_name StageBackgroundView extends Control` | `func set_background(kind: StringName, sky_id: StringName, plain_color: Color) -> void`; `func bind_camera(camera: Camera2D) -> void`; `func apply_theme(stage_theme: SandboxTheme) -> void` | Only renders a validated Sky or opaque Plain fill. Reuses `StageSkyView`; has no document, history, or picker state. `bind_camera(null)` yields still previews. |
|
||||
| `scripts/editors/stage/sandbox_stage.gd`, `class_name SandboxStage extends Node2D` | Confirmed `_background_kind: StringName`, `_sky_id: StringName`, `_plain_color: Color`; transient `_plain_color_draft_active: bool`, `_plain_color_draft: Color`. Private typed helpers such as `_commit_background_kind(kind: StringName, sky_id: StringName = &"") -> void`, `_commit_plain_color(color: Color) -> void`, `_preview_plain_color(color: Color) -> void`, `_cancel_plain_color_preview() -> void`, `_refresh_background_view() -> void`. | Sole authority for current scene state, dirty state, save snapshot, recent color history, and draft rollback. Switching to Plain changes the kind immediately and opens choices; switching Sky retains `_plain_color`. |
|
||||
| `scripts/stage/stage_scene_io.gd`, `class_name StageSceneIO extends RefCounted` | `FILE_VERSION := "1.7"`; typed validation/migration of `background_kind`, `sky_id`, and `plain_color`. | Reject malformed new backdrop fields before applying a document; migrate older versions without changing their visible Sky. |
|
||||
| `scripts/editors/stage/stage_scene_adapter.gd`, `class_name StageSceneAdapter extends RefCounted` | Pass all three fields through `collect(...) -> Dictionary` and `apply(...) -> Dictionary`. | Keep background data at the top level; no object entry is created. |
|
||||
| `scripts/editors/stage/stage_asset_browser.gd` and `scripts/shared/ui/asset_selector.gd`, `class_name AssetSelector extends PopupPanel` | Supply four starter cards and five scene-wide background cards; pass `{background_kind, sky_id, plain_color}` for active state and previews. Add typed `signal plain_color_preview_requested(color: Color)`, `signal plain_color_commit_requested(color: Color)`, and `signal plain_color_preview_cancel_requested` through the browser facade. | The chooser owns view navigation, focus, current/selected card display, and picker controls; it emits intents. It never marks the scene dirty or writes scene data. Keep existing `surface_color_confirmed` for wall/Ground setup history; do not route Plain through it and double-record a color. |
|
||||
| `scripts/shared/stage_ui/stage_surface_color_controls.gd`, `class_name StageSurfaceColorControls extends VBoxContainer`; `scripts/shared/ui/color_swatch_selector.gd`, `class_name ColorSwatchSelector extends FlowContainer` | Retain `color_selected(color: Color)` and `custom_color_requested`; activating the current-color chip is the sole entry to the full picker. Ensure compact swatches are at least 44 × 44 and stack sections when a horizontal row will clip. | Show current, recent, and preset colors with separate selected and focus treatment. The Stage's existing eight-color recent list is shared. |
|
||||
| `scripts/shared/stage_ui/stage_surface_color_picker_view.gd`, `class_name StageSurfaceColorPickerView extends VBoxContainer` | Extend `configure(...)`, or add a typed background-specific configuration method, so `preview_color_changed(color: Color)` uses an opaque flat sample for Plain. | Native `ColorPicker` supplies controls. The view displays a draft but does not commit it. Surface motif previews keep their current path. |
|
||||
| `scripts/stage/scenery/stage_starter_card_preview.gd` and `scripts/stage/scenery/stage_background_card_preview.gd` | Use `StageBackgroundView` for starter and background card imagery. | Show a true solid fill for Plain and preserve existing Sky rendering in still previews. |
|
||||
| `scripts/stage/stage_grid.gd`, `class_name StageGrid extends Node2D`; `scripts/stage/stage_gizmos.gd`, `class_name StageGizmos extends Node2D`; `scripts/stage/sandbox_theme.gd`, `class_name SandboxTheme extends RefCounted`; `sandbox_theme.json` | Add theme-backed light/dark grid colors and two-tone editor outline colors. Add typed setters on drawing nodes if needed to pass the current backdrop treatment. | Adapt editor overlays to the background while leaving authored art, speech, and physics unchanged. |
|
||||
|
||||
The signal names above are the desired public interface between chooser, browser, and Stage. Keep the existing `item_selected(entry: Dictionary)` path for Sky and Plain card taps. A Plain card tap commits the active kind before the chooser opens its color-choices view. A Sky card tap commits the new Sky immediately and keeps the chooser open. The current-card indicator uses a stable **Current background** badge and selected border; keyboard focus is separate. The Plain color choices and its custom picker keep the Stage at full brightness while the modal input blocker remains active and transparent. Other chooser views retain the usual visual dimming.
|
||||
|
||||
## Saved scene format and migration
|
||||
|
||||
Save top-level fields in `.scene` v1.7:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.7",
|
||||
"background_kind": "plain",
|
||||
"sky_id": "sky_neutral",
|
||||
"plain_color": "#F5EFE0",
|
||||
"camera": {"position": {"x": 0.0, "y": -400.0}, "zoom": 0.5},
|
||||
"objects": [],
|
||||
"event_rules": []
|
||||
}
|
||||
```
|
||||
|
||||
`background_kind` is exactly `"sky"` or `"plain"`. `sky_id` remains one of the existing five IDs even while Plain is active, preserving the last selected Sky for a later switch. `plain_color` is an opaque canonical six-digit `#RRGGBB` string. Runtime color values are clamped to opacity before commit; invalid file values are rejected at the JSON boundary. The plain starter is a separate `.scene` file under `content/stages/starters/` with these values and empty `objects`/`event_rules`; the existing `blank.scene` can remain the Open Sky starter, with its UI label changed. Town Street and Living Room remain authored compositions and acquire migrated Sky-kind fields on their next save if their source version is older.
|
||||
|
||||
`StageSceneIO._migrate_to_current()` must explicitly handle **1.6** as well as 1.0–1.5. Every pre-1.7 file migrates to `background_kind: "sky"` and `plain_color: "#F5EFE0"`; it preserves its migrated `sky_id` (including `sky_neutral`). In particular, adding 1.6 to the old `version != "1.5"` branch would incorrectly overwrite its Sky choice: keep that earlier version-specific rule intact. Current-version normalization still runs for migrated data. Read and validate the complete document before replacing the live scene. Save and autosave both serialize confirmed fields only; a picker draft is never consulted. `ContentPaths.canonicalize()` continues to handle starter paths.
|
||||
|
||||
## Color transaction and navigation
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Backgrounds
|
||||
Backgrounds --> ColorChoices: tap Plain / commit kind
|
||||
Backgrounds --> Backgrounds: tap Sky / commit sky
|
||||
ColorChoices --> ColorChoices: tap swatch / commit color
|
||||
ColorChoices --> CustomPicker: activate current-color chip / snapshot confirmed color
|
||||
CustomPicker --> ColorChoices: Use color / commit once
|
||||
CustomPicker --> ColorChoices: Back or Esc / discard draft
|
||||
ColorChoices --> Backgrounds: Back / keep commits
|
||||
CustomPicker --> [*]: popup hide, mode switch, scene replacement / discard draft
|
||||
```
|
||||
|
||||
`_plain_color` is the confirmed remembered value; `_plain_color_draft` exists only while the custom picker is open. Every native picker movement calls `_preview_plain_color()` to update the live `StageBackgroundView` and its flat chooser sample, without assigning `_plain_color`, changing recent history, or marking dirty. **Use color** clamps to opaque, commits the chosen color once, clears draft state, calls the existing `_record_recent_surface_color()` once, and returns to color choices. A preset/recent swatch uses the same commit method directly. An intentional selection can reorder recent history; mark the scene dirty only if the confirmed scene value actually changes. Opening choices at the untouched default does not add the default to recents.
|
||||
|
||||
Back, Cancel, Esc, popup hide, mode switch, and scene replacement must all clear the draft and restore the confirmed render. A replacement cancels the draft **before** resetting or loading scene state; popup-hide cleanup must be idempotent because a normal close can trigger it after a button callback. Back from color choices returns to Backgrounds without reverting confirmed card/swatches; Close retains confirmed choices. If Save/autosave occurs during a draft, the snapshot reads `_plain_color`, never the displayed draft. Focus returns to the Plain card from color choices and to the custom-picker opener from the picker; the popup keeps its screen anchor while switching views.
|
||||
|
||||
## Chooser layout and contrast
|
||||
|
||||
Use the existing `AssetSelector` responsive grid and `AssetCard` controls. File → New presents Plain Background, Open Sky, Town Street, Living Room in that order, two columns on a normal desktop and one scrollable column when narrow. Keep fixed heading and reachable Close. Backgrounds presents the five scene-wide cards under **Choose the scene background**; Wall panel and Background ground stay in a separate **More backgrounds** row. The color-choices view has a fixed **Choose background color** heading, flat confirmed preview, a focusable current-color chip with readable hex, up to eight shared recents, and presets. Place **‹ Backgrounds** at the left of the fixed footer and **Close** at the right; stack them as full-width actions on narrow layouts. Activating the current-color chip opens the custom picker; do not add a separate **More colors** button. The custom view has a flat draft preview and fixed Back/Use footer. Reuse `popups.asset_selector`, `popups.dialog`, `stage_surface_colors`, `stage_panels.action`, and `mode_colors.edit` tokens; add only narrowly needed flat-preview/backdrop-overlay tokens. Increase `popups.asset_selector.compact_swatch_size` from 42 to at least 44 in both theme sources, and clamp the actual `ColorSwatchSelector` target size to at least 44 even if a custom theme supplies a smaller number. Card, swatch, and action targets also meet 44 × 44. Scroll the content within viewport-safe bounds; do not horizontally clip compact color sections.
|
||||
|
||||
`StageGrid` currently uses translucent white lines. For Plain, choose theme-backed dark minor/major lines on a light fill and light minor/major lines on a dark fill using the displayed color's luminance, including a temporary draft. Minor lines stay subdued; major lines remain legible. On Sky, retain the established grid treatment. `StageGizmos` currently draws white selection and yellow hover outlines, which can disappear against light fills; add a dark backing stroke beneath a bright core for selection, hover, box selection, rotate ring, and scale handles. Keep screen-space widths and hit testing unchanged. This overlay treatment may be applied consistently for Sky and Plain. No authored object, speech bubble, placement material, or pixel color is rewritten. EDIT still owns grid/gizmos, DIRECT keeps its framing cues, and PLAY hides edit-only overlays. Review cursor pills and placement ghosts on light, dark, and saturated fills during rendered verification.
|
||||
|
||||
## Observable acceptance and verification route
|
||||
|
||||
| User path / repeatable scenario | Observable outcome |
|
||||
| --- | --- |
|
||||
| Fresh Sandbox Stage startup without a scene; close the chooser; compare with a CLI scene load and autosave restore/discard | The chooser opens once over an empty EDIT Stage. Close leaves the blank Stage open without reopening the chooser. A CLI-loaded or restored scene suppresses it; discarding autosave recovery opens it only after the recovery dialog closes. |
|
||||
| Dirty scene → File → New → cancel unsaved gate or cancel starter chooser; then choose Plain and Open Sky in separate runs | Gates preserve the prior scene on cancel. Plain opens an unsaved empty scene with a uniform `#F5EFE0` fill and zero placed objects; Open Sky keeps the former neutral gradient, sun, and clouds. Both card previews match. |
|
||||
| EDIT → Scenery → Backgrounds → Plain → swatch → Sky → Plain | Plain taps switch immediately, swatches update Stage and recent ordering, Sky remains selectable, and returning to Plain restores its confirmed color. Selected badge and focus are distinct. Wall/Ground remain separate. |
|
||||
| Plain custom picker → drag RGB/HSV controls → Back; repeat with Esc, Close, mode change, popup dismissal, and scene replacement | Draft appears in Stage/sample while editing; each cancel path restores the prior confirmed fill. Dirty state, recent list, saved file, and autosave content do not change from the draft. Replacement does not carry draft into the next scene. |
|
||||
| Plain color choices → activate current-color chip → change custom picker controls → Use color → Save → reopen; compare color and recent list before/after | The current-color chip opens the picker without a separate button. One confirmation stores an opaque color, records it once in shared history, and marks the scene dirty once. Reopen restores active kind and remembered color. A Sky-active save/reopen also retains the hidden remembered plain color. |
|
||||
| Load representative v1.0–v1.6 files, especially a v1.6 `sky_neutral` scene and a v1.6 non-neutral Sky; save/reopen | They remain visually Sky scenes with the same Sky ID and composition; migration adds default remembered Plain color and writes v1.7 without changing objects, camera, or Sky choice. Invalid v1.7 background data fails before live-scene replacement. |
|
||||
| Plain Stage with no world objects → pan, zoom, viewport resize, EDIT → DIRECT → PLAY → stop; repeat after save/reopen | Every frame stays an opaque edge-free flat fill. No gradient or motifs appear; backdrop never intercepts clicks. Mode transitions retain color; PLAY has no edit-only grid/gizmos. |
|
||||
| Light `#F5EFE0`, dark, and saturated Plain colors with Ground, artwork, Props, character, speech, selection, and placement ghost | Grid major/minor lines, selection/hover/gizmos, cursor pills, and ghosts remain usable. Foreground pixel colors and object behavior remain unchanged. |
|
||||
| Narrow viewport → pointer/touch/keyboard through starters, cards, swatches, picker, Back/Use/Close | Content scrolls without horizontal clipping; actions stay reachable; all targets meet 44 × 44; returning from subviews restores opener focus and popup anchor. |
|
||||
|
||||
Use the real Stage chooser, stage scene load/save path, and render-capable Stage for the scenarios above. Inspect captured frames at the named colors, camera positions, zoom levels, modes, and viewport sizes; a headless parse or a screenshot command alone does not establish visual correctness. Focused automated checks should cover the v1.7 migration/validation boundary and the commit/cancel state transitions where they meaningfully protect behavior. No new graphical or animation asset is required: thumbnails and previews are rendered from existing Sky drawing and the new solid fill.
|
||||
|
||||
## Trade-offs and implementation constraint
|
||||
|
||||
Composing a backdrop view adds one small node and typed facade but keeps Sky drawing focused and lets live Stage and previews share the same kind switch. Three scalar file fields are easier to validate and migrate than a custom `Resource`; the saved `sky_id` is deliberate remembered state while Plain is active. Color history remains a user setting shared with surface colors, while the confirmed plain color belongs to each scene. Theme-backed grid color can account for the flat background, but it cannot account for every placed object beneath a particular grid segment; the two-tone gizmo outline protects selection visibility across mixed art.
|
||||
|
||||
The existing chooser was designed around four Sky cards and a separate surface row. Its grid-row counting, active-card group, footer placement, and compact swatch width need targeted extension for five scene-wide choices and the new color views. Preserve its popup anchor and focus behavior while changing those branches; do not fork a second gallery or color picker.
|
||||
@@ -0,0 +1,99 @@
|
||||
# Phase 19 — Plain Background: UI/UX specification
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified as part of Phase 19. The current-color chip is the sole entry to the custom picker; there is no separate **More colors** button. The default color is warm off-white `#F5EFE0`; the color swatches and sample views show a flat fill.
|
||||
>
|
||||
> **Design references:** [Phase 19 Plain Background brief](../plans/phase_19_plain_background.md), [approved PNG mockups](../plans/assets/phase_19_plain_background/), [Phase 19 Scenery UI/UX specification](phase_19_scenery_backgrounds_ui_ux.md), and [Child-Facing Dialog Design Principles](dialog_design_principles.md).
|
||||
|
||||
## Child promise
|
||||
|
||||
A child can start with an empty stage filled by one color, choose another color in EDIT, and return to that color after trying a Sky. The color fills the whole camera view. It does not create a selectable object or change the colors and behavior of placed pieces.
|
||||
|
||||
## File → New
|
||||
|
||||
- Keep the existing unsaved-work Save/Discard/Cancel gate. Do not replace the current scene until a starter card is chosen.
|
||||
- Use the existing themed `AssetSelector` shell and `AssetCard` presentation with a fixed **Choose a starter scene** heading, a scrollable responsive card body, and a reachable visible **Close** action. The card order and tab order are **Plain Background**, **Open Sky**, **Town Street**, **Living Room**.
|
||||
- At desktop widths, show an equal-sized 2 × 2 card grid. At narrow widths, wrap to one column and scroll the body while keeping the title and Close action available. Preserve the popup's screen anchor when its layout changes.
|
||||
- Make this chooser materially larger than the current roughly 660 × 560 logical-pixel asset selector: target about 1160 logical pixels wide on a roomy desktop, with a natural height that shows both card rows and the Close action. Cap both dimensions to the usable viewport with safe margins; a short display scrolls the card body while the title and Close stay reachable. At the preferred width, each card's preview should be about 500 pixels wide and at least 240 pixels tall, occupying roughly two-thirds of the card height. Scale the preview with its card instead of leaving a small fixed thumbnail inside a large tile. The [larger starter chooser mockup](../plans/assets/phase_19_plain_background/05_large_starter_chooser.png) shows the intended balance; its pixel dimensions are illustrative, not a fixed window size.
|
||||
- Plain Background's thumbnail is a uniform opaque `#F5EFE0` fill with no horizon, gradient, Sky motif, checkerboard, or object. Its copy is: **“An empty stage with one color. Choose a new color whenever you like.”** Starting it creates a new unsaved scene with no Ground or placed objects and no additional setup step.
|
||||
- Open Sky previews the existing neutral gradient, sun, and clouds. Its copy is: **“An empty stage with a soft sky. Sun and clouds, ready for your story.”** This is the existing empty neutral-Sky starter under a clearer name.
|
||||
- Town Street and Living Room retain their authored compositions and existing descriptions.
|
||||
- Activating a card by pointer, touch, Enter, or Space opens that starter. Close or Escape leaves the current scene intact.
|
||||
|
||||
## Fresh Sandbox startup
|
||||
|
||||
- When the Sandbox Stage launches as the active scene without a requested scene, show **Choose a starter scene** once for that Stage session. This gives children the same clear starting point as File → New.
|
||||
- If an autosave is available, resolve its recovery prompt first. Restoring it opens the recovered scene without the starter chooser; discarding it opens the chooser afterward.
|
||||
- A command-line scene load or load error does not open the starter chooser. The chooser must not cover recovery or another modal dialog.
|
||||
- Close or Escape leaves the empty EDIT Stage available. Do not automatically reopen the chooser during that session; File → New remains available when the child wants another starter.
|
||||
|
||||
## EDIT → Scenery → Backgrounds
|
||||
|
||||
- Extend the current `AssetSelector` Backgrounds tab with a **Plain Background** card alongside **Clear Day**, **Cloudy Day**, **Sunset**, and **Starry Night**. Keep **Wall panel** and **Background ground** visually separated under a **More backgrounds** row.
|
||||
- Show the heading **Choose the scene background** above the five scene-wide choices. The Plain Background card preview uses the remembered plain color even while a Sky is active.
|
||||
- Mark the active choice with the existing cyan selected fill/border and a stable **Current background** badge. Keep the keyboard focus outline visually distinct from selection. Do not identify the current choice by color alone.
|
||||
- Sky cards retain their immediate selection behavior and leave the chooser open. Activating Plain Background immediately restores/applies its remembered color and opens the Plain Background color choices. Back or Close from those choices keeps Plain Background active.
|
||||
- Neither a Sky nor Plain Background is Stage-selectable or included in Pieces here. Switching background never starts placement or changes the current cursor mode.
|
||||
|
||||
## Plain Background color choices
|
||||
|
||||
- Reuse the bounded chooser shell, `StageSurfaceColorControls` and shared `ColorSwatchSelector` visual language; the full-stage preview and scene-specific copy are the only feature-specific presentation.
|
||||
- Keep the **Choose background color** heading. Put **‹ Backgrounds** in the fixed footer, left of **Close**, instead of in the title row. Both are large, outlined secondary actions with 12–16 px separation; at narrow widths, stack them vertically as full-width targets. The scrollable body contains:
|
||||
1. Helper text: **“Tap a color to use it on the Stage.”**
|
||||
2. A large, flat, opaque preview of the confirmed color with no text over the color sample.
|
||||
3. The current color swatch and readable hex value.
|
||||
4. **Recently used** colors, using the shared recent color list (up to eight).
|
||||
5. **Colors** preset swatches.
|
||||
- If recents are empty, show **“Colors you use will appear here.”** Opening Plain Background at the untouched default does not add that default to recents.
|
||||
- Tapping a recent or preset swatch immediately confirms it. The full Stage, preview, current swatch, selected outline/check, dirty state, and recent ordering update together. Leaving and reopening the view preserves that confirmed choice.
|
||||
- Give the selected swatch an outline/check that is distinct from keyboard focus. Make all swatches at least 44 × 44 logical pixels, including compact layouts; the current 42-pixel compact swatch default is too small here.
|
||||
- The current-color chip is the sole entry point to the full custom picker. It is a focusable button with clear hover, pressed, and focus states and the tooltip **“Choose a custom color.”** Activating the chip opens the picker; there is no separate **More colors** button.
|
||||
- Keep the Stage at full brightness while Plain Background color choices or its custom picker are open so live color changes can be judged accurately. Keep the modal input-blocking layer active but visually transparent; clicks outside the dialog must not reach the Stage. The dialog keeps its opaque shell, outline, and footer for modal clarity. Other chooser views retain the normal dim backdrop.
|
||||
|
||||
## Full custom picker
|
||||
|
||||
- Reuse/extend `StageSurfaceColorPickerView`, its native `ColorPicker`, large preview, theme, and compact-height behavior. Use a flat, opaque preview matching the Stage with no text overlay.
|
||||
- Use the heading **Choose background color** and a simple **Preview** label above the large color sample. The tentative behavior is communicated by the Stage updating during picker movement and the visible **Use color** / **Back** actions; no explanatory preview message is needed.
|
||||
- On open, snapshot the last confirmed plain color. Moving native color controls updates only the temporary Stage preview and large sample. It does not change history, scene dirty state, or serialized data.
|
||||
- Use a fixed, visible footer with a dark secondary **Back** (or **Cancel**) button and a blue, bold, white **Use color** primary button, separated by 12–16 logical pixels. All actions remain at least 44 × 44 logical pixels.
|
||||
- **Use color** confirms once, updates the remembered color and recent history once, marks the scene dirty once, and returns to the color choices.
|
||||
- Back, Cancel, Escape, or closing the picker restores the confirmed snapshot and returns to color choices with Plain Background still active.
|
||||
- Mode changes, scene replacement, or unexpected popup dismissal also clear a temporary preview and restore the confirmed color. A temporary color must never enter Save or autosave.
|
||||
|
||||
## Focus, layout, and theme
|
||||
|
||||
- Use `SandboxTheme` values from `popups.asset_selector`, `popups.dialog`, `stage_surface_colors`, `stage_panels.action`, and `mode_colors.edit`. Add a small Plain-preview token group only if the existing theme has no suitable values; avoid a parallel swatch or picker system.
|
||||
- Keep cards, swatches, and actions at least 44 × 44 logical pixels. Preserve the existing dialog style: rounded surfaces, visible outlines, readable type, blue primary action, and labeled Close/Back/Use actions.
|
||||
- Tab order: starter cards → Close; Scenery tabs → scene-background cards → surface cards → Close; color choices: Back → current-color chip → recent swatches → preset swatches → footer; custom picker → Back → Use color.
|
||||
- Opening a subview moves focus to its heading or first useful action. Returning from the color choices restores focus to Plain Background; returning from the custom picker restores focus to the current-color chip.
|
||||
- Keep the title and footer actions reachable while the body scrolls. Cap the popup to the safe viewport; do not force clipping or horizontal scrolling to retain compact horizontal swatch columns. Stack the Back/Close footer actions and current/recent/preset sections at narrow widths. Preserve the popup anchor when switching gallery, color, and custom-picker views.
|
||||
- Pointer, touch, and keyboard users get the same selected, hover, focus, and confirmation feedback. Clicking outside must not silently confirm a tentative custom color.
|
||||
|
||||
## Canvas contrast and feedback
|
||||
|
||||
- Review white, black, and saturated Plain Background colors. On light fills such as `#F5EFE0`, the current white EDIT grid and white selection outlines have about 1.15:1 contrast and nearly disappear. Provide a theme-backed contrasting grid treatment for light and dark fills, keeping minor lines subdued and major lines legible.
|
||||
- Give Stage selection, hover, and gizmo outlines a dark backing plus bright core on Plain Backgrounds of any brightness, following the existing two-tone selection-halo practice. Do not recolor authored artwork.
|
||||
- Keep EDIT chrome and mode pill dark-backed with cyan accents, DIRECT framing amber, and PLAY free of edit-only grid and gizmos. Preserve speech styles and their authored colors. Check cursor pills and placement ghosts at light, dark, and saturated backgrounds.
|
||||
- A Plain Background color is a scene-wide visual setting only: it never intercepts Stage selection or changes object ordering, placement, action behavior, or camera movement.
|
||||
|
||||
## Acceptance scenarios
|
||||
|
||||
1. Open Sandbox Stage without a scene and verify the starter chooser appears. Close it and verify the empty EDIT Stage remains available without another automatic prompt in that session. Open a scene through the CLI and verify the chooser does not appear.
|
||||
2. If an autosave is available at startup, restore it and verify the chooser stays closed; discard it and verify the chooser appears afterward without overlapping the recovery prompt.
|
||||
3. In a dirty scene, use File → New and verify the existing unsaved gate appears first. Cancel the starter chooser and confirm the previous scene remains. Choose Plain Background and verify the new unsaved Stage is a single flat `#F5EFE0` with no Sky, Ground, or placed objects. Verify Open Sky reproduces the existing neutral Sky appearance.
|
||||
4. In EDIT, open Scenery → Backgrounds. Verify all five scene-wide choices are visible, the current choice is identified with text and a border, and Wall panel/Background ground remain separate. Choose Plain Background and verify it opens with the remembered color.
|
||||
5. Tap one preset and one recent swatch. For each, verify the Stage and preview update immediately, the color becomes selected, and recent ordering updates. Close and reopen the choices and verify the confirmed value remains.
|
||||
6. Activate the current-color chip to open the custom picker. Move a color control, then choose Back. Verify the Stage and preview return to the last confirmed color and the scene/recent history remain unchanged. Repeat and choose Use color; verify the choice and history update once and remain after Save/reopen.
|
||||
7. Repeat custom-picker cancellation through Escape, visible Cancel/Back, close, mode change, and scene replacement. No temporary preview may leak into the next Stage or saved scene.
|
||||
8. With each of Sky and Plain active, pan, zoom, resize the viewport, enter/stop PLAY, and reopen a saved scene. Verify the solid fill covers the camera view with no edge and that the remembered plain color returns after switching back from Sky.
|
||||
9. On light, dark, and saturated fills, inspect grid, selection, hover, gizmos, cursor pills, placement ghosts, speech, and mode chrome. Confirm the Stage remains readable and placed artwork colors remain unchanged.
|
||||
10. At narrow viewport sizes, navigate each card, swatch, and action by pointer, touch, and keyboard. Verify the content scrolls without clipping; focus and selection remain distinct; Back/Use/Close remain visible; returning from subviews restores the opener focus and popup anchor.
|
||||
|
||||
## Reuse boundary
|
||||
|
||||
| Surface | Reuse direction |
|
||||
| --- | --- |
|
||||
| Starter and Scenery cards | Extend `AssetSelector` and `AssetCard`; use `StageBackgroundCardPreview` for a real solid-color thumbnail and add the Plain-specific label/selection state. Do not create another card gallery. |
|
||||
| Color choices and recents | Reuse `StageSurfaceColorControls` and `ColorSwatchSelector`/shared history. Extend layout for 44-pixel minimum targets and narrow layouts instead of introducing a parallel swatch system. |
|
||||
| Custom picker | Reuse `StageSurfaceColorPickerView` and the native `ColorPicker`; give the scene-wide background its own flat preview and explicit temporary/confirm/cancel lifecycle. |
|
||||
| Stage contrast | Use `SandboxTheme` tokens and the existing two-tone selection halo pattern; do not mutate user-authored object colors or make a second editor theme. |
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
# Phase 19 — Scenery, backgrounds, and surface finishes: architecture and implementation specification
|
||||
|
||||
> **Status (2026-10-22):** Phase 19 architecture is implemented and user/editor verified. The user completed the integrated visual and interaction checks; `tests/test_phase19_scenery.gd` passes **706 checks with 0 failures**. This specification follows the [verified product plan](../plans/phase_19_scenery_backgrounds_surface_finishes.md), the [UI/UX specification](phase_19_scenery_backgrounds_ui_ux.md), and the [Stage panel UI system](stage_panel_ui_system.md). The camera-aware Sky addendum supersedes the original static-detail statements below.
|
||||
|
||||
## Decisions and scope
|
||||
|
||||
1. Use independent, inert `Node2D` placements for wall panels and `.prop` Scenery artwork. The source `.prop` is a **live reference**: its current vector art is used on reopen. Missing art remains a saved, visible, repairable placement. A given `.prop` may be used as inert Scenery and, when it has valid collision geometry, as a functional Prop.
|
||||
2. Sky is one adaptive, viewport-filling, screen-space vector drawing behind the world. Its gradient stays fixed while its details respond gently to camera pan and zoom under the [camera-aware Sky addendum](#phase-19-addition-camera-aware-sky-details); it does not tint other objects. Existing scenes and Blank Scene use an internal neutral Sky. The four child-facing Sky presets are Clear Day, Cloudy Day, Sunset, and Starry Night.
|
||||
3. The existing Prop Editor opens **inside the live Stage session** for Make artwork. The Stage and its unsaved document remain in memory, with Stage input suspended until the editor returns. The standalone F6 route remains valid.
|
||||
4. Select several creates a temporary Scenery selection and snapshot-based transform preview. It does not create a persistent group or a parent that changes the saved hierarchy. Sky, Ground, characters, and functional Props are outside this transform.
|
||||
5. Phase 19 adds neither Stage Undo/Redo nor a whole-set transform. Group preview has its own exact Cancel/Keep boundary. Stage-wide Undo/Redo is a separately planned phase and is logged in [technical debt](../architecture/tech_debt_and_optimizations.md).
|
||||
|
||||
## Existing constraints and ownership
|
||||
|
||||
`scenes/stage/sandbox_stage.tscn` contains a `SandboxStage` root, `Camera2D`, and `World`. The scene adapter serializes direct `World` children; `StageSceneIO` currently writes v1.4. `StageSelection` currently considers every direct world child selectable by world AABB. `StageSpatialIndex` indexes AABBs into 16 px cells and `StageTerrainPainter` treats any indexed overlap as an occupancy conflict. `PropBlock` currently draws at `z_index` -1, 0 (legacy), or 1, while terrain is 0. These are explicit integration points, not implicit behavior to rely on.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Chrome[StageChrome / shared gallery] --> Intent[SandboxStage input arbitration]
|
||||
Intent --> Decor[StageSceneryController]
|
||||
Intent --> Terrain[StageTerrainPainter]
|
||||
Decor --> World[World: WallPanel + SceneryArtwork]
|
||||
Terrain --> World
|
||||
World --> Adapter[StageSceneAdapter]
|
||||
Sky[StageSkyView] --> Adapter
|
||||
Adapter --> IO[StageSceneIO v1.5]
|
||||
Art[PropFile + PropLibrary visual scan] --> Decor
|
||||
Art --> Editor[Stage-hosted PropEditor]
|
||||
```
|
||||
|
||||
| Owner / location | Typed contract or change | Boundary |
|
||||
| --- | --- | --- |
|
||||
| `scripts/stage/stage_draw_order.gd`, `class_name StageDrawOrder extends RefCounted` | Constants `WALL := -40`, `FAR := -30`, `NEAR := -20`, `TERRAIN := -10`, `FLOOR := -5`; `static func scenery_z(depth: StringName) -> int`; `static func apply_terrain(node: TerrainBlock) -> void` | One drawing policy. Leave the existing Prop `-1/0/1` and character relative order intact; rebase terrain drawing only. Never serialize raw `z_index` in place of a semantic depth/finish. |
|
||||
| `scripts/stage/scenery/stage_sky_view.gd`, `class_name StageSkyView extends Control` | `func set_sky(id: StringName) -> void`; `func get_sky() -> StringName`; `func apply_theme(theme: SandboxTheme) -> void`; camera binding specified in the [Sky addendum](#phase-19-addition-camera-aware-sky-details) | Full-rect child of a dedicated `CanvasLayer` with `layer = -1`, mouse ignored. Deterministic vector drawing on preset, viewport, or effective camera-framing changes. No world hit test or physics. |
|
||||
| `scripts/stage/scenery/stage_wall_panel.gd`, `class_name StageWallPanel extends Node2D` | `var finish_id: StringName`; `var tint: Color`; `var panel_size: Vector2`; optional `var motif_origin_offset: Vector2`; `func configure(size: Vector2, finish: StringName, color: Color) -> void`; `func get_local_bounds() -> Rect2` | Finite world rectangle centered at `position`. No `CollisionObject2D`, navigation, support, or interaction registration. Resize changes `panel_size`, never root scale, so motifs retain their world pitch. The renderer lays the pattern out from each panel's current world transform, so eraser-created fragments keep continuous brick courses; the optional offset preserves source-wall lineage in saved data. |
|
||||
| `scripts/stage/scenery/stage_scenery_artwork.gd`, `class_name StageSceneryArtwork extends Node2D` | `var asset_path: String`; `var display_name: String`; `var depth: StringName`; `var last_known_local_bounds: Rect2`; `var missing: bool`; `func load_visual(path: String) -> bool`; `func set_depth(value: StringName) -> void`; `func get_visual_world_bounds() -> Rect2`; `func get_saved_footprint() -> Rect2` | Build a `Visuals` child via `PropVisuals.build()` from the complete shape stack. No `PropBlock`, collision hull, physics, Use spots, anchors, or event identity. If loading fails, render a neutral marker/known footprint from saved data and preserve path/name/transform. |
|
||||
| `scripts/stage/scenery/stage_surface_renderer.gd`, `class_name StageSurfaceRenderer extends RefCounted` | `static func is_wall_finish(id: StringName) -> bool`; `static func is_ground_finish(id: StringName) -> bool`; `static func draw_wall(canvas: CanvasItem, rect: Rect2, finish: StringName, tint: Color, world_origin: Vector2) -> void`; `static func draw_ground(canvas: CanvasItem, rect: Rect2, finish: StringName, tint: Color, world_origin: Vector2) -> void` | Shared vector definitions for Paint/Brick/Wood, with Grass/Dirt/Sidewalk/Asphalt for Ground. One motif vocabulary and world-coordinate phase; no raster scale blur. Drawing helpers clip motifs to finite panel/block bounds and bound work to visible tiles. |
|
||||
| `scripts/terrain/terrain_block.gd`, `class_name TerrainBlock extends StaticBody2D` | Add `var finish_id: StringName` and `func set_finish(id: StringName) -> void` for `spawn_id == "ground"`; preserve `polygon_points`, fill, outline, and `CollisionPolygon2D` | Ground appearance changes without altering collision geometry, navigation, or terrain occupancy. Ramp/Step retain the old look. |
|
||||
| `scripts/editors/stage/stage_scenery_controller.gd`, `class_name StageSceneryController extends Node` | `signal placement_committed(node: Node2D)`; `signal document_change_requested`; `signal preview_state_changed(active: bool)`; `func begin_artwork(path: String, depth: StringName) -> bool`; `func begin_wall(finish: StringName, initial_world_position: Vector2, tint: Color) -> void`; `func begin_wall_eraser(initial_world_position: Vector2) -> bool`; `func cancel_active_gesture() -> void`; `func exit_tool() -> void`; `func begin_group_transform(kind: StringName, members: Array[Node2D]) -> bool`; `func preview_group(delta: Vector2, factor: float) -> bool`; `func commit_group() -> void`; `func cancel_group() -> void` | Owns Scenery-only tool/substate and snapshots. A wall-eraser release subtracts its snapped rectangle from every intersected wall panel and emits one document change when anything changed. `SandboxStage` retains top-level mode, Save, dirty, and input priority. Typed intent signals do not pass UI controls into persistence. |
|
||||
| `scripts/editors/stage/sandbox_stage.gd`, `class_name SandboxStage extends Node2D` | Route Scenery tools before ordinary selection/placement; gate save/PLAY while a group preview needs resolution; apply controller commits through existing `_mark_scene_dirty()` and `_save_object_state()` as appropriate | Do not append all Phase 19 interaction state to the root controller. Cancel pending drafts on tool/mode changes before existing direct/play transitions. |
|
||||
| `scripts/stage/stage_selection.gd`, `class_name StageSelection extends RefCounted` | Add a typed selection context, for example `enum SelectionScope { ACTION, SCENERY }` plus `func set_scope(scope: SelectionScope) -> void`; make hit/hover/box use the same predicate | Ordinary EDIT excludes wall/artwork, including missing broad bounds. Edit Scenery includes only those; smaller cutouts outrank panels, with the overlap chooser for remaining ambiguity. Sky is never selectable. |
|
||||
| `scripts/stage/stage_scene_io.gd`, `class_name StageSceneIO extends RefCounted`; `scripts/editors/stage/stage_scene_adapter.gd`, `class_name StageSceneAdapter extends RefCounted` | v1.5 migration/validation, sky and new object encode/decode, known footprint, Ground finish | Validate document before `_reset_scene_content()`. Invalid new fields cannot silently erase the current scene. Preserve missing Scenery entries across save cycles. |
|
||||
|
||||
`StageSpawner` remains the factory for physical terrain, Props, stickmen, and Areas. A small Scenery factory may live in `StageSceneryController` or `scripts/stage/scenery/` to create inert nodes; it must not route visual artwork through `spawn_prop_asset()`. `StageRunSession` and the event/rule engine must treat Scenery nodes as nonparticipants even in PLAY and paused EDIT. Keep Scenery outside the physical spatial index and terrain-paint candidate set, but include it in `World` serialization and Scenery-only selection.
|
||||
|
||||
## Scene v1.5 contract
|
||||
|
||||
All scene objects remain independent entries in the existing `objects` array. `file_id` is unique within a file, allocated by the adapter; it is not a durable group ID. Scenery object transforms use world coordinates. The Sky ID is a root property. The examples omit unrelated current fields.
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.5",
|
||||
"scene_name": "Living Room",
|
||||
"sky_id": "sky_clear_day",
|
||||
"camera": {"position": {"x": 0, "y": -400}, "zoom": 0.5},
|
||||
"objects": [
|
||||
{"file_id": "wall_panel_1", "type": "wall_panel", "position": {"x": -280, "y": -420}, "size": {"x": 320, "y": 400}, "finish_id": "finish_wall_paint", "color": "#5A9D70"},
|
||||
{"file_id": "scenery_artwork_1", "type": "scenery_artwork", "asset_id": "res://content/props/window_frame.prop", "display_name": "Window frame", "depth": "near", "position": {"x": 0, "y": -450}, "rotation": 0, "scale": {"x": 1, "y": 1}, "last_known_local_bounds": {"position": {"x": -80, "y": -70}, "size": {"x": 160, "y": 140}}},
|
||||
{"file_id": "terrain_1", "type": "terrain", "asset_id": "ground", "position": {"x": 0, "y": 0}, "rotation": 0, "scale": {"x": 1, "y": 1}, "finish_id": "finish_ground_wood"}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {}
|
||||
}
|
||||
```
|
||||
|
||||
The document may contain internal `sky_neutral` and `finish_ground_legacy` IDs to reproduce the prior blank/background and green Ground. They are valid for loading/migration but are not extra child-facing picker cards. For wall panels, `position` is the rectangle center, `size` has strictly positive finite x/y, and rotation is fixed at zero. Group resize writes the new size and center while leaving wall root scale at `(1, 1)`. For artwork, `scale` is finite, positive, and uniform for Phase 19 editing; `rotation` is finite and preserved for existing/scripted entries and repair previews, though the Phase 19 UI offers no rotation control. Depth IDs are exactly `far`, `near`, `floor`; Near is the placement default.
|
||||
|
||||
The manual **Erase wall area** tool adds one optional wall field, `motif_origin_offset: {x, y}`, recording the vector from a fragment's saved `position` to its source wall's origin; absent means `(0, 0)`, so existing v1.5 scenes remain valid and no version bump or migration is needed. When a rectangle intersects a wall panel, transform its four corners into that panel's local space, intersect with the finite local bounds, and replace the original with up to four non-overlapping rectangular fragments outside the intersection. Copy the finish, tint, placement ordering, and source-wall lineage to every fragment. Render each fragment's surface pattern using its current world origin, not the inherited source origin, so brick courses remain on the same world-space lattice across the new fragment boundaries. Remove the source panel when the intersection covers it fully; do not touch artwork or non-wall objects. This is visual editing only: no glass, collision, doorway, Ground, or physics behavior is inferred. Each valid release commits immediately through the existing document-dirty signal; Done/Cancel/RMB/Esc exits the tool, and canceling a held drag discards only that uncommitted drag. There is no Stage Undo in Phase 19.
|
||||
|
||||
`last_known_local_bounds` is cached geometry metadata, updated when a live asset loads and retained unchanged if it later goes missing. Include stroke width when deriving it, so horizontal/vertical line-only artwork still has a positive visible footprint without inventing collision geometry. It supports a repair footprint and safe group movement; it is not embedded artwork. Missing or malformed optional bounds fall back to a compact world marker and disable group resize until repaired. `display_name` is a short saved fallback label. A repaired placement changes only its selected `asset_id`, name, and known bounds after explicit confirmation; its position, scale, rotation, depth, and unrelated placements remain. The default repair is one placement. A future or optional explicit “Use for all matching places” path must show a count and ask separately before changing other references.
|
||||
|
||||
`StageSceneIO._migrate_to_current()` accepts v1.0 through v1.4 and adds `sky_neutral` plus `finish_ground_legacy` to old Ground entries, without changing old Prop role and draw-order migrations. v1.5 validation checks top-level Sky ID, object type payloads, finite vectors and numbers, positive wall sizes and artwork scales, allowed finish/depth IDs, type-safe color strings, unique `file_id`, and canonicalized asset paths. Malformed optional cached art bounds produce a warning and the no-footprint repair marker, rather than rejecting otherwise valid scene content. The adapter creates a missing Scenery node when the source cannot load; missing source is a warning and repair state, not document rejection. Unknown object types follow the existing warning/skip convention only after structural validation. The existing safe write and autosave paths write the same v1.5 snapshot. Manual Save asks to Keep or Cancel a pending group preview; background autosave waits until the preview is resolved. On mode switch, cancel the preview before the current PLAY-entry autosave. Draft values are never serialized.
|
||||
|
||||
## Visual layers, Sky, and finishes
|
||||
|
||||
The semantic draw order is Sky → wall panels → Far art → Near art → terrain → floor art → characters and Props. `StageDrawOrder` applies bands to direct `World` children. Set all existing terrain varieties to the terrain band for consistent physical-surface drawing; their collision and input remain unchanged. Prop `-1/0/1` choices and World child order among legacy depth-zero Props and stickmen are preserved. Reapply the policy on spawn, load, depth change, and reset. Selection must use the same semantic tier order plus smaller actual art footprint preference, rather than assuming child insertion order expresses depth.
|
||||
|
||||
`StageSkyView` lives in its own `CanvasLayer` behind `World`, not under the camera or a wall. Its draw rectangle follows viewport size, so panning/zooming cannot reveal an edge. Use deterministic vector gradient bands, stars, clouds, sun/moon and shapes with bounded point counts. The preset controls only this view. The gradient stays screen-fixed; the [camera-aware Sky addendum](#phase-19-addition-camera-aware-sky-details) defines bounded, camera-responsive details and redraw invalidation. There is no per-frame random placement, autonomous animation, or tint propagation. Sky thumbnails use the same drawing definitions at card size in their unbound default composition.
|
||||
|
||||
`StageSurfaceRenderer` defines finite vector motifs with a world-aligned origin and fixed world-unit pitch. Wall and Ground may share Brick/Wood definitions but use context-aware fill/outline colors and scale. `StageWallPanel._draw()` uses its current finite rectangle as a clip and asks the renderer for only intersecting motif cells. For brick walls, cull to the camera-visible local rectangle; if that visible area exceeds 12,000 cells, increase the brick pitch uniformly for all visible courses instead of truncating rows or columns. This keeps large walls fully patterned and fragments continuous without unbounded draw work. Ground renders within its existing rectangle geometry; existing `CollisionPolygon2D` and navigation surfaces are never rebuilt merely for a finish change. The selected **New Ground look** is passed into both `StageTerrainPainter` ghost creation and each committed Ground block; it never repaints earlier blocks. During group resize, wall motif lines retain their pitch and phase. Ground blocks adjacent on a shared edge use the same world phase; shared same-finish interior borders are suppressed or visually joined so a painted run reads as one surface. The neighbor check refreshes on place, delete, move, load, and per-piece finish change, and considers only nearby Ground rectangles; it does not change occupancy/collision. Other motif types remain bounded by the camera-visible region or a maximum cell count per finite panel so `_draw()` work stays limited.
|
||||
|
||||
## Selection, input, and transform state
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> OrdinaryEdit
|
||||
OrdinaryEdit --> Chooser: Scenery palette
|
||||
Chooser --> PlaceArt: artwork chosen
|
||||
Chooser --> DrawWall: wall look chosen
|
||||
Chooser --> EditScenery: Edit placed scenery
|
||||
PlaceArt --> OrdinaryEdit: Done / Cancel / RMB / Esc
|
||||
DrawWall --> OrdinaryEdit: Done / Cancel / RMB / Esc
|
||||
EditScenery --> GroupPreview: Move together / Resize together
|
||||
GroupPreview --> EditScenery: Keep changes / Cancel / RMB / Esc
|
||||
EditScenery --> OrdinaryEdit: Done editing / Esc
|
||||
```
|
||||
|
||||
The controller tracks one active Scenery tool at a time, the number of committed copies this session, and whether a wall/touch draft is active. A passive artwork ghost is never a committed edit. Right-click/Done/Cancel follow the approved [exit matrix](phase_19_scenery_backgrounds_ui_ux.md#placement-exit-cancel-and-mode-changes): committed pieces stay; an active draft is discarded; a late release cannot commit it. Existing terrain and Prop placement are canceled when a Scenery tool takes input. DIRECT/PLAY clears Scenery ghosts and Edit Scenery selection.
|
||||
|
||||
`StageSelection` filters both click and box paths. Ordinary EDIT includes existing actionable objects and excludes Scenery broad bounds. In Edit Scenery, candidate geometry comes from a wall rectangle or the full transformed vector art: filled polygons use point-in-polygon, open strokes use a screen-scaled segment tolerance, and missing art uses its marker or known footprint. A small cutout wins over a broad wall even if both are candidates; unresolved overlaps use the shared “Pieces here” popup. The small explicit missing-art **Find artwork** badge is a separate 44 px screen-space hit target that can open Edit Scenery without making the entire missing footprint selectable in ordinary EDIT. Sky never enters either selection scope.
|
||||
|
||||
For one selected artwork, a uniform scale changes root `scale` within finite positive bounds. For a wall, resizing changes `panel_size`, with a minimum visible world size and no mirrored/negative rectangle. Pointer/touch handle hit areas are at least 44 logical pixels after camera zoom compensation. `StageGizmos` can share outline/handle drawing helpers; a Scenery-specific adapter is justified for rectangle sizing, no rotation control, and the pending group preview. It must still use `SandboxTheme.overlays` selection colors and the Stage halo style, rather than duplicating visual tokens.
|
||||
|
||||
Group preview snapshots `global_position`, `rotation`, artwork `scale` or wall `panel_size`, and the initial world bounds of each selected member. For move, derive one delta from the selected union anchor, apply Snap once to that anchor, then add the same delta to every snapshot position. For resize, compute one positive factor around the opposite union corner `P`; for each artwork center `x`, set `x' = P + factor * (x - P)` and `scale' = factor * scale`; for each wall center/size, use the same center formula and `size' = factor * size`. Derive every preview frame from the snapshots, never the previous preview frame. Reject factor `<= 0`, any collapsed member, or any out-of-range art scale. Buttons use the same formula with top-left fixed. Missing members with no known footprint may move but block group resize with the approved explanation. Mouse release leaves the candidate preview pending. `Keep changes` saves each authored transform, marks dirty once, and returns to Edit Scenery. `Cancel`, RMB, or Esc restores all snapshots exactly and leaves the same selection. A Save request opens a Keep/Cancel decision for the preview and resumes Save only after explicit resolution; tool/mode changes cancel the preview. A temporary group selection and preview are never written to `.scene`.
|
||||
|
||||
## Phase 19 addition: authoring size and single-placement transforms
|
||||
|
||||
This addition implements the approved [Stage-relative sizing flow](phase_19_scenery_backgrounds_ui_ux.md#stage-relative-authoring-size-in-prop-editor) inside Phase 19. The standard standing guide spans **939.5 world units** from head-circle top to ankle line; write `H := 939.5` as one Prop Editor reference constant derived from `WholeStickmanPreview.GUIDE_JOINTS` and `GUIDE_HEAD_RADIUS`, so the UI never assumes the old 96-unit Normalize Size target. The presets are starting points based on the artwork's **longest visible dimension**, including stroke: Small = `0.35 H`, Room = `1.0 H`, Big = `2.0 H`. This covers both tall and wide drawings without forcing a wide rug or skyline to be one stickman tall. Each **Make bigger** step multiplies by `1.1`; **Make smaller** multiplies by `1 / 1.1`, so opposite steps return to the same size within floating-point tolerance. The labels are approximate comparison choices, not an inferred real-world category or a maximum size. Artist size inference is part of authoring/review instructions; no runtime name parsing, asset size tag, or automatic normalization is added.
|
||||
|
||||
### Prop Editor authoring transaction
|
||||
|
||||
`PropEditor` (`class_name PropEditor extends Control`) replaces the Arrange toolbar's immediate `_on_normalize_size_pressed()` action and `NORMALIZED_MAX_EXTENT` with **Size for Stage**. The action is disabled when the document has no drawable geometry or its longest visible extent is not finite and positive; its tooltip says **“Add visible artwork to use Size for Stage.”** It owns the toolbar controls, Keep/Cancel routing, and the existing `_dirty`/autosave boundary. `PropCanvas` (`class_name PropCanvas extends Control`) owns a temporary deep copy of its complete shape stack and the supplied editable-anchor dictionary; its normal `shapes` and the editor's `_anchors` remain the committed document while previewing. A small typed API is sufficient:
|
||||
|
||||
```gdscript
|
||||
func begin_stage_size_preview(anchors: Dictionary) -> bool
|
||||
func preview_stage_size(factor: float) -> bool
|
||||
func commit_stage_size_preview() -> Dictionary # {"changed": bool, "anchors": Dictionary}
|
||||
func cancel_stage_size_preview() -> void
|
||||
func is_stage_size_preview_active() -> bool
|
||||
func get_visible_shapes_bounds() -> Rect2 # Includes outline/stroke width.
|
||||
func fit_stage_size_view(bounds: Rect2, padding_px: float) -> void
|
||||
```
|
||||
|
||||
The preview records original internal shape dictionaries, anchors, canvas pan/zoom, and the entry bounds once. Preset factor is `target_longest_edge / entry_longest_edge`; fine buttons adjust the current absolute factor, but **every rendered candidate is derived from the entry snapshot**, never scaled from the previous candidate. The shared `origin` anchor remains at `(0, 0)`. Scale all polygon/line points, circle points and radius, each shape's `outline_width` (including line-only art), and every editable anchor position by the same factor about the document origin. Preserve colors, shape order, vertex flags, `reshaped`, anchor roles, and anchor angles. This is the established whole-document pivot, so Size for Stage does not silently recenter the saved origin or detach grips from their art. Reject a candidate atomically if factor, coordinate, radius, stroke width, anchor position, or visible extent is nonfinite or outside the existing representable coordinate/size limits; leave the last valid preview visible and the committed document untouched. Do not clamp one shape or anchor independently. Zero-width strokes remain zero. A no-op factor of 1 leaves the document clean when it was clean on entry.
|
||||
|
||||
Draw the size candidate in `PropCanvas._on_canvas_draw()` and then draw the guide **after all artwork**, with dark halo and light core for the bones, head, and floor line. Derive the comparison floor from the **candidate's current visual bottom**; align both guide ankles to that y and place the figure just to the artwork's left (or over its left portion when width is tight), so offset and centered authoring coordinates compare correctly without translating the artwork. With an empty canvas, draw the guide at its normal origin and ankle line; Size for Stage remains disabled until artwork exists. The floor cue can follow a changed candidate bottom. On entry, compute a union of candidate artwork plus the guide/floor and frame it with a bounded margin. Refit that union after a preset choice and when a fine step would clip it; do not reframe on every draw or override a child's deliberate pan/zoom while the union remains visible. The sizing view may temporarily fit below the canvas's normal manual `MIN_ZOOM` on narrow viewports and restores the prior pan/zoom on exit. Outside the sizing view, show the same foreground guide and floor whenever **Show Stickman Guide** is enabled. During sizing, force guide drawing on without changing or persisting that checkbox; restore its user preference on exit. The guide is canvas drawing only, never a saved shape, anchor, or Stage object.
|
||||
|
||||
**Keep size** validates the full candidate, swaps the complete shapes/anchors once, emits one document change, refreshes inspector/thumbnail state, and starts the existing dirty/autosave timer once if the result differs from the snapshot. **Cancel**, Esc, mode switch, New/Load, return to Stage, or closing the editor discards the candidate before another document action; no preview geometry enters Save/autosave. A Save request while the sizing view is open asks the child in the existing sizing controls to **Keep size** or **✕ Cancel** first, then the child can use ordinary Save/Save As; no new save dialog or asset-copy policy is introduced. `Transform Whole Prop`, Attach, Reshape, and canvas editing cannot run concurrently with this sizing transaction. The present whole-prop Transform action remains available in Arrange after sizing.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
Arrange --> SizePreview: Size for Stage / snapshot
|
||||
SizePreview --> SizePreview: Small, Room, Big, smaller, bigger / derive from snapshot
|
||||
SizePreview --> Arrange: Keep size / validate, commit once, dirty once
|
||||
SizePreview --> Arrange: Cancel or Esc / discard, no dirty
|
||||
SizePreview --> Arrange: leave editor or switch mode / discard, no dirty
|
||||
```
|
||||
|
||||
### Direct Stage move and resize of one Scenery piece
|
||||
|
||||
`StageSceneryController` (`class_name StageSceneryController extends Node`) takes ownership of the currently selected Scenery drag, replacing `SandboxStage`'s local `_scenery_drag_snapshots`/`_scenery_dragging` move path. It reuses its existing group snapshot math and `document_change_requested` signal but keeps the single gesture's commit boundary separate: release commits immediately; group release still leaves a candidate requiring **Keep changes**. Suggested typed controller contract:
|
||||
|
||||
```gdscript
|
||||
signal single_gesture_changed(active: bool)
|
||||
func begin_single_transform(node: Node2D, kind: StringName, pointer: Vector2, dragged_corner: Vector2 = Vector2.INF) -> bool
|
||||
func preview_single_transform(pointer: Vector2) -> bool
|
||||
func commit_single_transform() -> bool
|
||||
func cancel_single_transform() -> void
|
||||
func is_single_transform_active() -> bool
|
||||
func step_single_size(node: Node2D, factor: float) -> bool
|
||||
```
|
||||
|
||||
`kind` is exactly `&"move"` or `&"resize"`; the controller accepts only one selected `StageWallPanel` or `StageSceneryArtwork`. Snapshot `{node: Node2D, position: Vector2, rotation: float, scale: Vector2, panel_size: Vector2 when wall, bounds: Rect2, pointer: Vector2, dragged_corner: Vector2}`. This is transient in-memory state, never a `.scene` payload. A missing artwork without known bounds can move but cannot resize. Before applying any candidate, validate the whole result: finite position and scale, positive artwork scale components within the current Stage range, positive wall dimensions above `MIN_PANEL_SIZE`, valid node still in Edit Scenery, and a nondegenerate starting AABB **for resize**. A move preserves any existing positive nonuniform scale. A resize multiplies both scale components by one uniform factor, preserving the ratio of an imported/scripted placement without normalizing it. Rejecting a frame retains the last valid preview. An unchanged release emits no document change.
|
||||
|
||||
For move, derive `raw_delta = pointer - pointer0` from the snapshot. With Snap on, align the **visible world AABB's top-left corner** rather than the node's often offset origin: `delta = snap(bounds0.position + raw_delta) - bounds0.position`; apply `position0 + delta`. This preserves the existing top-left grid-alignment promise for placed wall panels and artwork. For uniform resize, take the world AABB corner opposite the dragged corner as the fixed point `P`. With `D = dragged_corner - P`, use `factor = 1 + (pointer - pointer0).dot(D) / D.length_squared()`; reject nonpositive/invalid factors. For artwork with saved local geometry, `position' = P + factor * (position0 - P)` and `scale' = scale0 * factor`, preserving rotation and depth. For walls, use the same position formula and `panel_size' = panel_size0 * factor`, leaving root scale at 1 so Brick/Wood motif pitch does not stretch. The fixed world corner stays fixed even when artwork's authored origin is offset. **Smaller**/**Bigger** in the selected-piece card call `step_single_size()` with reciprocal factors `1/1.1` and `1.1`, top-left pinned; each valid press is an immediate independent commit for that placement only. Other artwork instances, walls, Ground, Props, characters, and their interaction state are untouched.
|
||||
|
||||
`StageGizmos` supplies selection outline and corner drawing/hit geometry, using existing `SandboxTheme.overlays` colors and dark-halo/light-core selection language. Extend its Scenery adapter with at least **44 × 44 logical-pixel** hit regions converted through camera zoom, prioritizing a corner hit over the body; do not reuse its current `PropBlock`-only SCALE gesture or origin-pivot formula. The Stage root arbitrates input once: selected corner starts resize, selected body starts move, and group preview has priority while active. `StageSceneryController` previews directly on the selected node, then emits `document_change_requested` exactly once on changed release; `SandboxStage` updates its authored-state/save path and card. Esc, right-click, visible capture-bar **✕ Cancel**, mode/tool switch, selection removal, or node deletion restores the snapshot and clears the gesture. An input-generation token or equivalent active-state guard must consume a mouse/touch release after cancellation so it cannot commit an old draft. Manual Save first cancels an active single gesture and saves only prior commits; background autosave waits for it to end. Group preview retains its existing separate Keep/Cancel save gate.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Pointer[Corner/body press] --> Hit[StageGizmos hit: corner first]
|
||||
Hit --> Begin[SceneryController snapshot]
|
||||
Begin --> Preview[Pointer motion from snapshot]
|
||||
Preview --> Release[Release: commit once]
|
||||
Preview --> Cancel[Esc/RMB/capture Cancel: restore]
|
||||
Release --> Dirty[Stage dirty + scene v1.5 placement transform]
|
||||
Cancel --> Idle[No dirty; stale release ignored]
|
||||
```
|
||||
|
||||
The selected artwork card adopts `StageInspectorPanel` for fixed header/scrolling body, `StagePanelChoiceGroup` for Far/Near/On the floor, and `StageInspectorPanel.style_action_button()` for Smaller/Bigger and Erase. The selected wall card uses the same shell and action styling. Both call `set_safe_rect()` and preserve the compact Settings reopen behavior. `StagePanelToggleRow` is reserved for actual booleans; no new panel control is needed for size. The already shared `StageUseTargetCaptureBar.set_capture_actions()` shows **✕ Cancel** only while a single drag is held; group Keep/Cancel remains unchanged. New sizing controls in Prop Editor use its existing Arrange toolbar and `PropTheme`, because that editor is a distinct workflow from an in-stage selected-object card. No duplicate dialog, capture-bar, choice, or button styling is introduced.
|
||||
|
||||
The existing `.scene` v1.5 `position`, `scale`, `rotation`, and wall `size` fields already persist these per-placement changes; `.prop` v1.1 already stores points, circle radius, outline width, and anchors. This addition requires no schema bump and performs **no load-time resizing or migration of asset geometry or placement scale**. Saving an explicitly revised `.prop` at its existing path intentionally updates all live-reference Scenery and Props that use that path when reloaded; ordinary Save and Save As remain the only asset save actions. A scene's saved placement scale continues to multiply its current referenced art. There is no new asset-version enforcement, copy/update prompt, automatic compensation factor, or runtime name-based size inference.
|
||||
|
||||
## Asset catalog, tags, thumbnails, and missing-art repair
|
||||
|
||||
`PropFile` advances to v1.1 with optional top-level `tags: Array[String]`. It accepts v1.0 files with `tags = []`, normalizes a fixed set `nature`, `buildings`, `walls`, `roads`, `objects`, deduplicates, and writes only known IDs. Tags describe appearance, never physics. The same file remains the only vector authoring format; no `.scenery` file or new asset library root appears. Keep cutouts as immediate children of `content/props/` for existing scans; unapproved art stays under ignored `content/review/artist/<slug>/` and must not enter browser results. `ContentPaths.canonicalize()` handles saved paths, including old `props/` paths, while preserving external paths.
|
||||
|
||||
Split library eligibility by role without duplicating parsing: a shared parse/cache step returns `{id: String, path: String, name: String, shapes: Array[Dictionary], tags: Array[String], visual_bounds: Rect2, material_preset: int, collision_hull: PackedVector2Array}`. Scenery accepts nonempty visible vector geometry, including open lines and transparent-window frames, via `PropVisuals.build()`/shape bounds. A closed filled shape needs three noncollinear points; an open stroke needs two distinct points, positive width, and visible color. These rules accept line art without accepting a blank `.prop`. Props retain the existing valid closed-hull requirement. The existing `StageAssetBrowser` scan, asynchronous thumbnail queue, `ThumbnailCache`, and `PropThumbnail.render_shapes()` are reused for either role; a line-only artwork thumbnail must not go through `flatten_to_payload()` as a fake collision shape. Scenery keeps authored per-shape colors rather than applying a Prop material tint. All artwork includes untagged assets; Unsorted appears when appropriate. The same tag filters are available in Props, but its entries remain physically eligible only. Do not scan review directories or recursively change the existing immediate-child library behavior.
|
||||
|
||||
On scene open, load every live artwork reference. A missing/invalid source leaves a `StageSceneryArtwork` node with `missing = true`, saved transform/depth, remembered name, and last known footprint. Render a neutral translucent footprint with dashed light/dark edge when bounds exist, otherwise a compact world marker, with a constant-screen-size picture/question icon and “Artwork not found” label. It stays subdued in DIRECT/PLAY and is never solid. Show one themed missing-assets summary for the load with the UI spec’s **Show scenery** / **Later** actions, while retaining separate Prop/stickman warning semantics. The Scenery piece list has a **Needs artwork** section.
|
||||
|
||||
**Find artwork…** uses the established `.prop` chooser; **Choose another artwork** uses the common Artwork gallery. The candidate must pass Scenery visual validation before a ghost appears at the saved position/size/orientation/depth. The explicit **Use this artwork here?** confirmation commits only the selected placement. Cancel/failure leaves the original path, marker, and scene dirty state untouched. Replacing art marks dirty once and refreshes the known bounds, name, and visual tree; the original position, scale, rotation, and depth remain. A changed source file is picked up on reopen for every live reference; there is no embedded snapshot. The optional File details disclosure may show the path for an adult. The simple one-placement repair is required; an all-matching bulk repair is optional and must be explicitly confirmed with its count.
|
||||
|
||||
## Starter scenes and document lifecycle
|
||||
|
||||
Keep versioned starter documents under `content/stages/starters/` with stable IDs for Blank, Town Street, and Living Room. They are ordinary `.scene` snapshots, not locked nested instances. Blank may be assembled from the current neutral empty-scene defaults; Town Street and Living Room data use the same wall, artwork, terrain, Prop, Sky, and camera schema as a saved child scene. The bundled files reference only explicitly approved production art. A window is a genuine gap between wall rectangles with a transparent frame and Sky behind it; no cutting or glass behavior is inferred. Furniture Props receive deliberate still/block/support roles from the normal Prop contract, without promising Sit.
|
||||
|
||||
The focused [Phase 19 starter-scene composition specification](phase_19_starter_scene_composition.md) defines the approved pan-safe Town Street and Living Room surfaces and the opening-shot bounds used by starter-card previews. It keeps the ordinary v1.5 scene records and camera free of limits.
|
||||
|
||||
The current `PendingFileAction.NEW_SCENE` unsaved Save/Discard/Cancel gate remains authoritative. After it resolves, show the shared starter gallery **before** replacing the current document. Canceling the gallery leaves the existing scene and post-gate dirty state. Selecting a starter preflights its scene data, loads ordinary editable objects, resets `current_path` to empty, stamps a fresh creation time, proposes its editable name, and marks the new document unsaved. Failed starter validation leaves the prior scene intact and shows one themed error. No starter is inserted into another scene. A first-save path follows the existing Save As flow. CLI scene playback continues to load `.scene` directly, with no starter-specific runtime branch.
|
||||
|
||||
## UI component and theme reuse
|
||||
|
||||
| Surface | Reuse or shared extension | Feature-local work / justified exception |
|
||||
| --- | --- | --- |
|
||||
| File → New gate | `StageChrome` File menu; `StageModalViews` unsaved dialog; `StageDocumentController` pending action | Starter-choice result and fresh-document handoff only. |
|
||||
| Starter, Scenery, Sky, finish and replacement galleries | Extract a responsive shared card-gallery body from `AssetSelector`/`scenes/stage/asset_selector.tscn`; retain `AssetCard`, `StageAssetBrowser`, thumbnail pipeline | Tabs, descriptive text, and filter meaning are feature-specific. Replace the current fixed four-column/12-per-page and `FOCUS_NONE` card limitation in the shared path: adaptive columns, scroll, native focus, visible focus ring, and keyboard activation. Non-placeable cards disable card drag. |
|
||||
| Browse tags and authoring tags | One shared wrapping chip/choice treatment using native Buttons and `FlowContainer`/`HFlowContainer`, `SandboxTheme` popup tokens | Single-select browser filter versus multi-select authoring tags have distinct state rules. Do not use vertical `StagePanelChoiceGroup` as a chip row. |
|
||||
| Wall color | Extend `ColorSwatchSelector` for wrap/selected/focus; native color picker in a `StageModalViews` themed window | Chosen wall color remains local to the placement/selected panel. |
|
||||
| Selected artwork, missing art, wall, Ground, multi-selection | Direct use of `StageInspectorPanel`, `StagePanelChoiceGroup`, `stage_panels` tokens and `StagePropSettingsView` dismissal/compact Settings precedent | Domain rows and commands stay in a Stage Scenery/Ground view adapter. `StagePanelToggleRow` is used only for a real boolean, not depth or finish. |
|
||||
| Member list / overlap popup / wall-area eraser | `StageInspectorPanel` action styling; generalize `StageModalViews.show_objects_here()` labels and candidate filter; reuse `StageUseTargetCaptureBar` for the eraser prompt and Done/Cancel | Membership, piece labels, the red rectangle preview, and wall subtraction are Scenery-specific. The selected wall card starts the tool; no new dialog, overlap popup, or capture-bar styling. |
|
||||
| Placement/group capture | Extract themed responsive shell from `StageUseTargetCaptureBar`, preserving mode-pill-safe position, prompt/Cancel grouping, action stacking | Use-target and Scenery wording/actions stay in callers. No copied capture-bar CSS/StyleBox code. |
|
||||
| Cursor and ghosts | `StageChrome` tooltip safe placement, `StagePlacementOverlay`, terrain ghost presentation, `SandboxTheme.overlays` | The draft geometry, validity, and missing marker are feature-specific. |
|
||||
| Make artwork | Existing `PropEditor`, `PropCanvas`, `.prop` Save/recovery and `PropThumbnail` | Add a typed `AuthoringContext { PROP, SCENERY }`, `signal artwork_saved(path: String)`, and `signal return_requested`. In Scenery context hide material/mass/bounce, attachment, and other action settings; keep shape/color/name/tags/Save. |
|
||||
|
||||
The shared UI contracts should remain small and typed. Extract `scripts/shared/ui/asset_gallery_popup.gd`, `class_name AssetGalleryPopup extends PopupPanel`, as the fixed header/Close and scrollable responsive `AssetCard` grid used by the current `AssetSelector` and Phase 19 choosers. It emits `item_selected(entry: Dictionary)` and `cancelled`, and exposes `open_gallery(title: String, entries: Array[Dictionary]) -> void`, `set_thumbnail(entry_id: String, texture: Texture2D) -> void`, and `focus_entry(entry_id: String) -> void`. A card entry has `{id: String, label: String, thumbnail: Texture2D|null, helper: String, draggable: bool}`; the caller maps `id` to its domain item. `AssetSelector` retains its public `open(kind, entries)` facade and uses the shared gallery, so existing Prop/Stickman callers are not broken. `StageAssetBrowser` retains scanning/caching and adds a role-safe filtered query such as `scan_entries(kind: String, tag: StringName = &"") -> Array[Dictionary]`; no gallery owns asset parsing.
|
||||
|
||||
Extract `scripts/shared/stage_ui/stage_capture_bar.gd`, `class_name StageCaptureBar extends PanelContainer`, from the `StageUseTargetCaptureBar` shell. Its intended interface is `signal action_pressed(id: StringName)`, `func configure(stage_theme: SandboxTheme, mode: int, top_bar_height: float) -> void`, `func set_prompt(text: String) -> void`, `func set_actions(actions: Array[Dictionary]) -> void`, and `func hide_capture() -> void`; each action dictionary has `{id: StringName, label: String, prominent: bool}`. Keep `StageUseTargetCaptureBar` as a thin Use-specific wrapper or composition client preserving `cancel_requested` and `change_prop_requested`. Generalize `StageModalViews.show_objects_here()` with a typed title/label provider while retaining its existing facade and `object_selected(node: Node2D)` signal. Existing `StageInspectorPanel`/`StagePanelChoiceGroup` APIs need no new domain knowledge: caller-owned cards call `set_header`, `body`, `set_safe_rect`, `request_fit`, and `add_choice`/`select_no_signal` directly. `ColorSwatchSelector` may change its layout container to `FlowContainer` while preserving `configure(colors: Array[Color], selected: Color, theme: Variant)`, `set_selected`, and `color_selected(color: Color)`.
|
||||
|
||||
All new popup/native-window instances receive `SandboxTheme.control_theme()` explicitly, then `StageModalViews.apply_dialog_theme()` for child font overrides. The latter does not assign a window theme. Extend `SandboxTheme.DEFAULT_CONFIG` and `sandbox_theme.json` only for shared popup/gallery/chip/capture/selection measurements and colors. Use local StyleBox copies; do not mutate the cached shared `Theme`. Selected, hover, focus, and disabled remain distinguishable. All actionable controls and handle hit regions meet the approved minimum 44 × 44 logical pixels. Viewport-safe rectangles keep the mode pill and Close reachable; long content scrolls under a fixed header. The existing queue/rule/speech popups are distinct workflows and are not recast as gallery or inspector shells.
|
||||
|
||||
## Stage-hosted Prop Editor lifecycle
|
||||
|
||||
Instantiate the existing `scenes/editors/prop/prop_editor.tscn` in a full-viewport Stage-hosted UI layer, set Scenery context before its first user interaction, then focus its first drawing/name control. While active, `SandboxStage` routes no world selection, placement, camera mode, or shortcuts to the hidden Stage; dialogs and editor input remain usable. The underlying Stage document, dirty flag, selection, and current scene path remain in memory. The editor keeps its own `.prop` autosave and unsaved-work gate. Its F6 standalone exit still quits its own run; in hosted context Close/Cancel emits `return_requested` to remove the editor view and restore Stage input/focus without quitting the Stage. A successful Save emits `artwork_saved(path)` after the file write; **Place it as Scenery** returns to the Artwork chooser with a fresh scan/thumbnail generation and the saved asset focused. Merely opening/canceling the editor never changes the Stage document. A saved new `.prop` outside the Stage is a separate asset write, so returning without placement leaves the Stage unchanged.
|
||||
|
||||
## Implementation and art gates
|
||||
|
||||
1. Extend data boundaries first: `.prop` tags and role-safe visual scanning; scene v1.5 migration/validation; semantic draw order; inert visual nodes and shared finish/Sky definitions. Validate old scene/Prop compatibility before UI wiring.
|
||||
2. Generalize the existing card gallery, tag treatment, capture bar, overlap popup, color treatment, confirmation style, and theme tokens. Build the Phase 19 chooser and inspectors from those shared controls. Avoid a parallel popup/card system.
|
||||
3. Connect placement, selection scopes, missing repair, Ground finish, and group snapshot previews through `StageSceneryController` and the existing Stage save/mode gates. Add the starter gallery and Stage-hosted Prop Editor return path.
|
||||
4. The original Phase 19 art manifest used `$asset-creation` and approved production assets. **This sizing amendment requires no new vector/raster deliverables**: it draws the existing stickman guide and floor cue in Prop Editor and extends existing Stage handles. An artist may deliberately revise a particular `.prop` through the ordinary asset-review workflow, but implementation does not batch resize built-ins or reopen the original art approval gate merely because this amendment is signed off.
|
||||
5. Run syntax/import checks and focused existing suites after each integration slice. Add focused behavior checks where actual world state is at issue. Perform render-capable Stage/editor captures and real input-path checks before reporting visual/interactive outcomes as agent-verified.
|
||||
|
||||
Relevant existing regression starting points are `tests/test_phase19_scenery.gd`, `tests/test_phase10_prop_integration.gd`, `tests/test_prop_editor_file.gd`, `tests/test_prop_editor_canvas.gd`, `tests/test_prop_editor_round3.gd`, `tests/test_content_paths.gd`, and `tests/test_phase17a_prop_roles.gd`; run focused affected suites rather than the full historical matrix for each sizing edit. The original Phase 19 fixture covers scenery persistence and group behavior; extend focused coverage for Size for Stage's atomic Keep/Cancel and a real one-piece Stage resize, including late release after cancellation. Exercise production input and save/reopen paths, not only helper calculations.
|
||||
|
||||
## Observable acceptance and verification routes
|
||||
|
||||
Each row names a child path and a repeatable observation. Automated checks may create in-memory fixtures, but should use actual Stage spawning, document, input, and PLAY paths where practical; node/signal existence alone does not establish behavior.
|
||||
|
||||
| Child path / scenario | Observable outcome and measurement |
|
||||
| --- | --- |
|
||||
| File → New → cancel starter, then Town Street; save/reopen; repeat Living Room | Existing scene survives chooser Cancel. Each chosen starter is unsaved, individually editable, and preserves Sky, separate panels/art/Props/Ground and positions after save/reopen. Living Room Sky is visible through an actual wall gap. |
|
||||
| Scenery → Artwork → Nature → Tree; place twice, change depth, RMB; reopen | Two distinct inert copies persist at saved transforms/depths. RMB removes ghost, preserves committed copies, returns to ordinary EDIT. Check `PhysicsDirectSpaceState2D` contacts, navigation candidates, and event participation remain absent for scenery while a normal Prop remains functional. |
|
||||
| Make line-only artwork in Stage-hosted editor; Save → Place it as Scenery | `.prop` with open strokes appears in Scenery and has a valid thumbnail; it does not enter Props without valid closed collision geometry. Stage unsaved state and focus survive authoring return. Tags filter it without changing its behavior. |
|
||||
| Draw Brick wall, resize it; paint a Wood Ground run, restyle one block | Wall is finite/inert; brick pitch stays constant. Ground collision and walking path remain valid; wood motifs line up across neighbors, shared seams do not interrupt the run, and only the selected block changes to the new finish. Measure character feet/contact over several physics ticks before and after restyling. |
|
||||
| Ordinary EDIT click/box in front of broad wall; enter Edit Scenery; select art and wall through Pieces here | Gameplay objects remain reachable in ordinary EDIT. Scenery-only selection finds art ahead of broad panels, includes missing art in Edit Scenery, and never selects Sky. Real pointer/touch/keyboard activation produces the expected selection and popup dismissal. |
|
||||
| Living Room: select two walls, window frame, rug; move preview then RMB; resize preview then Keep; Save/reopen | RMB restores each exact snapshot transform. Keep applies one positive factor around the opposite fixed corner, preserves artwork proportions/depth and wall motif pitch, leaves Ground/furniture untouched, and persists member transforms without a saved group. Save while pending asks Keep/Cancel and never writes draft values. |
|
||||
| Prop Editor → Arrange → Size for Stage on a tall refrigerator, wide rug, and small item; try each preset/fine buttons, Cancel once and Keep once | The artwork and standard guide remain fully visible at ordinary and narrow viewport sizes. Longest visible edge reaches approximately `0.35H`, `1H`, or `2H` while proportions, circle radii, line widths, and editable anchor positions share the same factor; the foreground halo guide's ankles meet the floor cue at the candidate bottom. Cancel restores byte-equivalent authored geometry/anchors and the prior dirty state; Keep commits once. A Big preset cannot clip the guide merely because opening began on small artwork. Save/reopen the `.prop` through the normal path and compare geometry/anchors. |
|
||||
| Edit Scenery → select two copies of one artwork; drag a corner on one, release; then cancel another drag with Esc/RMB/touch Cancel and release the pointer | The opposite visible corner stays at the same world position; only the edited placement changes, and it commits on release without Keep. A canceled drag restores its snapshot and the late release makes no change. With Snap on, a moved artwork or wall's visible top-left lands on a grid intersection. Smaller then Bigger returns near the initial bounds. Save/reopen and check the two copies retain distinct scales, while Props/Ground/PLAY behavior remains unchanged. A missing artwork without known bounds shows no resize handle. |
|
||||
| Open a pre-amendment `.prop` and `.scene`, then explicitly overwrite one referenced `.prop` through ordinary Save | Opening alone does not rescale artwork or placement values. The explicit source overwrite changes every live reference to that source on reopen, while each scene placement retains its saved scale; there is no hidden compensation, copy prompt, or version migration. |
|
||||
| Move a referenced `.prop` aside, reopen, repair selected missing artwork; cancel once then confirm | One neutral marker remains at saved position/depth, summary appears once, ordinary EDIT targets are not stolen, cancel keeps path/dirty state, and confirmed repair changes only that placement. Missing footprint/no-footprint group resize rules and PLAY marker presentation hold. Restore source and reopen to confirm live-reference visual update. |
|
||||
| Select each Sky, pan/zoom, PLAY/stop, reopen | The fixed gradient fills the screen without an edge or flicker; details follow the bounded response in the [Sky addendum](#phase-19-addition-camera-aware-sky-details). Foreground pixel colors are unchanged by Sky choice. Layer order remains Sky/wall/Far/Near/Ground/floor/actors through camera movement, simulation, and reload; ghosts/handles/capture bars disappear in PLAY. |
|
||||
|
||||
Visual acceptance requires opening the affected scene in a render-capable Godot GUI, capturing the named chooser, normal/zoomed Stage, missing-art, group-preview, **Prop Editor sizing guide at Small/Big and narrow width, active single-piece handles/capture bar**, and PLAY states, and inspecting the pixels. Record capture location, scene/state, and observation. Interactive acceptance requires exercising the actual controls and input events, including RMB/Esc/touch cancellation, button sizing, grid-aligned move, commit on release, and a late release after cancellation. If GUI or input automation is unavailable after an attempted route, name the unverified outcomes and hand the user a focused reproducible check; a headless parse or screenshot file alone is insufficient. **Closeout:** the user reports completing the Phase 19 editor verification on 2026-10-22; the automated scenery suite passes 706 checks. Plain Background save/reopen was also explicitly verified by the user.
|
||||
|
||||
## Trade-offs and future work
|
||||
|
||||
- Independent nodes preserve the current editable direct-child document model and avoid using `PropBlock` as a fake inert body. The cost is a separate artwork visual node and explicit scene-object decoding.
|
||||
- Live `.prop` references keep scenes compact and make art edits visible on reopen. They can change a scene's appearance after the source file changes; the saved name/footprint and repair flow cover missing files, not version pinning. A future immutable asset-version policy would need a separate decision.
|
||||
- Stage-relative authoring size is geometry stored in `.prop`, while a Stage Scenery resize is an instance transform stored in `.scene`. This keeps legacy loads stable and lets two placements of one source have different sizes. It also means an intentional overwrite of a live `.prop` updates all references; the user chose to retain ordinary Save/Save As without a new copy/update decision. The authoring preview scales outline width and editable anchors with geometry and uses origin as its pivot; its floor guide follows visual bounds solely for comparison.
|
||||
- A one-piece Stage drag commits on release for speed; a multi-piece group retains Keep/Cancel because its wider effect is harder to judge during a gesture. Both use exact snapshots before commit, while Stage-wide Undo remains deferred to the separate phase logged in technical debt.
|
||||
- Rebased terrain drawing enables the required floor-art tier without changing Prop-to-character depth semantics. It changes terrain's relative visual position beneath Props; physics and navigation stay unchanged and must be regression checked.
|
||||
- Vector motifs retain clarity and world alignment without repeated raster textures, at the cost of careful clipping/culling and seam management. Keep motif definitions centralized so wall/Ground previews match runtime drawing.
|
||||
- Stage-wide Undo/Redo deserves one command history across placement, deletion, style, repair, and group commits. The Phase 19 Keep/Cancel preview is a local transaction only. Whole-set transform needs its own design because Ground physics, character/Prop placement, rules, and camera all have different transform invariants.
|
||||
|
||||
## Phase 19 addition: camera-aware Sky details
|
||||
|
||||
This focused addition implements the accepted [product addendum](../plans/phase_19_scenery_backgrounds_surface_finishes.md#camera-aware-sky-details-addendum) and [UI/UX contract](phase_19_scenery_backgrounds_ui_ux.md#camera-aware-sky-details). The original clauses above that describe Sky details as static are superseded here. **Only the four existing child-facing Sky presets gain automatic camera response.** The internal neutral Sky may use a zero-response profile. There is no motion setting, additional Sky card, theme token, scene field, or change to Background ground behavior.
|
||||
|
||||
### Ownership, nodes, and typed contract
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Camera[SandboxStage/Camera2D\nworld position + zoom] -->|bind once; sample framing| Sky[StageSkyLayer: CanvasLayer -1\nStageSkyView: Control]
|
||||
Sky --> Gradient[full-rect gradient\nscreen fixed]
|
||||
Sky --> Motifs[clouds / sun / moon / stars\nbounded camera response]
|
||||
World[World: Background ground + walkable Ground + actors] --> Camera
|
||||
Cards[Sky chooser and starter card previews] -->|SkyView without camera binding| Still[default still composition]
|
||||
```
|
||||
|
||||
`SandboxStage` (`class_name SandboxStage extends Node2D`) owns the one live `Camera2D` and passes it to the already-built `StageSkyView`; it does not dispatch a separate Sky update from every mouse, touchpad, scene-load, mode, or PLAY path. `StageSkyView` (`class_name StageSkyView extends Control`) owns all Sky drawing and the response calculation. Its narrow typed API is:
|
||||
|
||||
```gdscript
|
||||
func bind_camera(camera: Camera2D) -> void # A null camera restores the default still composition.
|
||||
func set_sky(id: StringName) -> void
|
||||
func get_sky() -> StringName
|
||||
func apply_theme(theme: SandboxTheme) -> void
|
||||
```
|
||||
|
||||
`StageSkyView` samples the bound camera's finite `global_position` and positive uniform `zoom.x` in its own `_process(delta: float) -> void`, compares the **effective** framing against the last drawn values, and calls `queue_redraw()` only when the visible composition changes. Its `NOTIFICATION_RESIZED` path also invalidates layout. Invalid or unavailable camera data falls back to the fixed default composition rather than propagating NaN into drawing. The first binding, preset change, and scene load invalidate immediately so a newly shown view does not display a previous frame's motifs. No signal or runtime state is serialized; the last sampled values exist only to avoid redundant redraws. The chooser's `StageBackgroundCardPreview` and starter's `StageStarterCardPreview` create unbound `StageSkyView` instances and remain representative still images. No new UI component, Stage inspector control, or `SandboxTheme.stage_panels` token is needed.
|
||||
|
||||
### Deterministic response and layout
|
||||
|
||||
Use the built-in Stage camera framing, `REF_POSITION := Vector2(0.0, -400.0)` and `REF_ZOOM := 0.5`, as the fixed reference for **every** scene. These values match `SandboxStage`'s current defaults and `sandbox_stage.tscn`. Evaluate each frame from absolute camera position and zoom; never accumulate input deltas, seed from elapsed time, or capture a per-session origin. Thus identical `{sky_id, camera.position, camera.zoom, viewport.size}` yields identical drawing after mode changes, PLAY/stop, and save/reopen. The existing `.scene` camera position/zoom and `sky_id` fields are sufficient; scene version and migration stay unchanged.
|
||||
|
||||
Each preset has one internal response profile, shared by all its motifs. A profile contains bounded horizontal/vertical pan limits in viewport fractions, a pan response span, and a bounded logarithmic zoom strength/span. These are renderer constants, not saved data or child-facing controls. A suitable starting envelope is at most about **5% of viewport width and 3% of height** for motif displacement and about **0.85–1.15×** for uniform motif size over the Stage's supported zoom range; tune each preset by rendered comparison at ordinary, close, and wide shots. Derive pan from the camera-position difference expressed in reference-frame screen pixels and pass it through a smooth odd saturating function (for example `tanh`). Derive zoom from `log(camera_zoom / REF_ZOOM)` through a smooth bounded function, then exponentiate to keep the size positive and reciprocal around the reference zoom. Avoid hard clamps in the visible response range, which can create a conspicuous change in motion at the limit. Camera movement of world objects must visibly exceed Sky-detail movement at ordinary framing. At the reference camera framing, displacement is zero and scale is one.
|
||||
|
||||
For clarity, one possible pure calculation is `shift.x = -W * limit_x * tanh(((camera_x - REF_POSITION.x) * REF_ZOOM / W) / span_x)` (and likewise for y), with `size_factor = exp(gain * tanh(log(camera_zoom / REF_ZOOM) / zoom_span))`; choose `limit/span` and `gain` so the detail response remains gentle. The final spec requirement is bounded, continuous, deterministic behavior, not these exact coefficients. Apply the same profile to all motifs of a preset as one visual group; individual stars may retain different authored sizes and positions, but do not acquire independent motion layers. Keep `sky_neutral` deterministic; a zero-response profile is acceptable for that internal default.
|
||||
|
||||
The gradient remains a full `Rect2(Vector2.ZERO, size)` draw in the screen-space `CanvasLayer`; **do not apply the motif transform to the gradient**. Place motif centers using normalized viewport anchors and scale their authored vector shapes **uniformly** with a single viewport-derived scalar, rather than separate x/y stretch. Apply the camera-induced size factor about the motif's own anchor, then add the bounded shift. Let the viewport clip any motif portion outside the visible rectangle; the gradient still fills those pixels, so no Sky edge appears. On resize, recompute anchors and the scalar from the new dimensions and reevaluate the same absolute camera frame. Retune the current low and oversized clouds, especially Cloudy Day and Sunset, so the ordinary lower action area remains comparatively open. This is art composition within the renderer, not a hard mask that hides clouds over arbitrary character positions.
|
||||
|
||||
The current star loop uses `fposmod(..., size.x/y)`, so changing viewport size can wrap a star abruptly to a distant position. Replace that layout with a fixed, deterministic set of normalized star anchors (or a fixed seeded list mapped to normalized coordinates); never seed it from the frame clock or call `randf()` while drawing. Existing cloud/moon curves should be sampled or cached once per shape/preset where practical, because camera movement now invalidates the drawing more often. Keep motif count and vector point count bounded; retain the gradient texture until the preset actually changes. There is no autonomous cloud drift, weather animation, horizon line, selection geometry, collision, or world tint.
|
||||
|
||||
`StageBackgroundGround` remains a world-anchored `Node2D` surface behind walkable Ground. Its landscape edge and the walkable Ground therefore move and scale together through the normal `Camera2D` transform. The Sky makes no ground-line claim and does not inspect terrain or character positions.
|
||||
|
||||
### Data flow and observable acceptance
|
||||
|
||||
1. The child chooses Clear Day, Cloudy Day, Sunset, or Starry Night. `SandboxStage` calls the existing `set_sky(id)` path; the Sky draws its fixed gradient and reference-frame motif composition. The chooser card remains a still preview.
|
||||
2. A pan or zoom changes `Camera2D` through any existing input route. The bound `StageSkyView` samples the resulting absolute framing, derives its bounded motif transform, and redraws only when that framing changes. No mode or PLAY-specific Sky branch runs.
|
||||
3. Save writes the existing `sky_id` and camera fields. Reopen loads those values; the next Sky draw derives the same composition from them and the current viewport size. A resize derives a coherent composition at the new size without changing saved state.
|
||||
|
||||
Repeat this in a rendered Stage: choose each preset; place a stickman on walkable Ground with a broad Background ground panel behind it; frame an ordinary shot, a close shot, and a wide shot; pan in EDIT and DIRECT, switch to PLAY and pan/zoom again, then stop. At an unchanged camera framing, motif anchors and apparent size must match across those mode and PLAY transitions. Resize the viewport twice and verify the gradient remains full-screen, motif shapes keep their proportions, and stars do not jump across the screen. Save at a nondefault camera framing, reopen at the same viewport size, and compare the motif composition; it must match without a separate Sky setting. Throughout, Sky displacement and scaling are perceptible but restrained, no edge or flicker is exposed, the lower ordinary action area remains usable, Ground and Background ground stay aligned, and foreground colors/physics remain unchanged. A screenshot or headless parse alone cannot establish the camera-response and composition outcomes; inspect rendered frames at the named camera states.
|
||||
|
||||
### Architectural trade-offs
|
||||
|
||||
- Keeping one `CanvasLayer` and one `StageSkyView` reuses current drawing and preview paths. The renderer must now redraw vector motifs while the camera moves; bounded geometry, geometry caching, and change-only invalidation keep that cost proportional to visible camera changes.
|
||||
- Fixed reference framing avoids a new `.scene` field and makes save/reopen exact. Very distant camera positions can sit near the response limit, so additional panning there may change the Sky little; that is the accepted cost of a bounded composition.
|
||||
- One profile per preset is simple to tune and preserves visual unity. It does not simulate separate cloud distances. True multilayer parallax and autonomous Sky animation remain outside this Phase 19 addition.
|
||||
- Normalized anchors and uniform motif size preserve proportions across viewport shapes. Wide or narrow aspect ratios change the available spacing between details, requiring visual checks on both shapes; exact pixel placement across resizes is not promised.
|
||||
@@ -0,0 +1,289 @@
|
||||
# Phase 19 — Scenery, backgrounds, and surface finishes: UI/UX specification
|
||||
|
||||
> **Status (2026-10-22):** Phase 19 UI/UX is implemented and user/editor verified. The user completed the integrated visual and interaction checks; the scenery suite passes **706 checks with 0 failures**. Camera-aware Sky and Plain Background are later Phase 19 additions; see the [Plain Background plan](../plans/phase_19_plain_background.md) and [UI/UX specification](phase_19_plain_background_ui_ux.md). Based on the [Phase 19 product plan](../plans/phase_19_scenery_backgrounds_surface_finishes.md).
|
||||
>
|
||||
> **Decision:** Use a responsive Scenery chooser followed by canvas tools. Placement stays active for repeated copies. Right-click exits placement. Scenery artwork keeps live `.prop` references, with a visible, repairable placeholder if a referenced file cannot be found. The Phase 19 addition standardizes new artwork around a standing-stickman size guide and adds single-placement Scenery resizing; direct single-piece transforms commit on release, while the existing group preview keeps its Keep/Cancel boundary. Phase 19 does not add Undo; Stage Undo is deferred to its own future phase and should be recorded in tech debt during architecture planning.
|
||||
|
||||
> **Reuse gate for every new dialog or control:** Before building it, inspect the existing shared UI, Stage panel kit, Stage modal/capture controls, and `SandboxTheme` tokens. Use a matching component directly; extend or extract shared behavior when Phase 19 uses it in more than one place. Keep only content and interaction that are genuinely unique to this feature local. Do not add a parallel card grid, overlap popup, capture bar, dialog skin, swatch style, or selected-object inspector. The later architecture specification must name any justified exception before implementation.
|
||||
|
||||
## Child promise and visual language
|
||||
|
||||
The Stage teaches three roles through entry points and short, visible words: **Scenery stays put**, **Props can be part of the action**, and **Ground is where stickmen walk**. An identical drawing can be placed through Scenery or Props without implying the copies behave alike. Sky is chosen through its card, never by selecting an enormous rectangle in the Stage.
|
||||
|
||||
Keep the existing mode language: EDIT uses cyan/blue and a visible grid, DIRECT uses amber/gold and its camera frame, and PLAY uses green with clean artwork. Each active tool also has an icon and words; color alone never identifies it. All buttons, cards, chips, handles' pointer hit regions, and dialog actions have at least a 44 × 44 logical-pixel target. Control heights come from `SandboxTheme` tokens rather than local constants.
|
||||
|
||||
## Flow at a glance
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
New[File → New] --> Gate[Protect unsaved scene]
|
||||
Gate --> Starter[Choose Blank, Town Street, or Living Room]
|
||||
Starter --> Edit[EDIT Stage]
|
||||
Edit --> Scenery[Scenery chooser]
|
||||
Scenery --> Sky[Choose Sky: changes immediately]
|
||||
Scenery --> Wall[Choose wall look → draw panels]
|
||||
Scenery --> Art[Filter artwork → choose drawing → place copies]
|
||||
Scenery --> Dress[Edit Scenery → select and change pieces]
|
||||
Dress --> Several[Select several → move or resize scenery together]
|
||||
Several --> Review[Keep changes or Cancel preview]
|
||||
Review --> Dress
|
||||
Edit --> Ground[Ground → choose look → paint walkable pieces]
|
||||
Wall --> Edit
|
||||
Art --> Edit
|
||||
Dress --> Edit
|
||||
Ground --> Edit
|
||||
```
|
||||
|
||||
The chooser is for discovery and choice. Once an artwork or wall tool is chosen, it closes so the Stage is visible. A small capture bar below the top toolbar and mode pill carries the current task, **Done**, and **✕ Cancel**. The cursor pill and ghost carry the immediate instruction at the pointer.
|
||||
|
||||
## Concrete screen examples
|
||||
|
||||
Desktop, while placing a Tree:
|
||||
|
||||
```text
|
||||
┌ File ─────────────── ✏️ Edit | 🎬 Direct | ▶️ Play ─── Grid Snap ┐
|
||||
│ [Ground] │
|
||||
│ [Ramp] ✏️ EDIT │
|
||||
│ [Step] ┌──────────────────────────────────────────────┐ │
|
||||
│ [Props] │ 🌳 Tree stays put [Far] [● Near] [Floor] │ │
|
||||
│ [People] │ Place another tree [Done] [✕ Cancel] │ │
|
||||
│ [Scenery] └──────────────────────────────────────────────┘ │
|
||||
│ [Areas] │
|
||||
│ (translucent Tree ghost) │
|
||||
│ 🌳 Tree · Near │
|
||||
│ ─── ground / existing set ─── │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
The Scenery chooser, opened from the left palette:
|
||||
|
||||
```text
|
||||
┌ Scenery: stays put ─────────────────────────────── [✕ Close] ┐
|
||||
│ [Backgrounds] [● Artwork] [Edit placed scenery] │
|
||||
│ [All artwork] [Nature] [Buildings] [Walls] │
|
||||
│ [Roads & paths] [Objects] [Unsorted, when needed] │
|
||||
│ │
|
||||
│ [ Tree preview ] [ Storefront preview ] │
|
||||
│ [ Tree ] [ Storefront ] │
|
||||
│ [ Skyline preview ] [ Rug preview ] │
|
||||
│ [ Skyline ] [ Rug ] │
|
||||
│ │
|
||||
│ [Make artwork…] │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Edit Scenery, with several pieces selected and a group resize preview:
|
||||
|
||||
```text
|
||||
┌ File ─────────────── ✏️ Edit | 🎬 Direct | ▶️ Play ─── Grid Snap ┐
|
||||
│ [Scenery] ✏️ EDIT [Edit Scenery · 4 pieces] [Done editing] │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ ◇ fixed corner old dashed bounds │ │
|
||||
│ │ [wall] [window] [clock] [rug] │ │
|
||||
│ │ new bright group outline ◉ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
│ ┌────────────────────────────────────────────────────┐ │
|
||||
│ │ Resize 4 scenery pieces · Ground and Props stay put │ │
|
||||
│ │ [Smaller] [Bigger] [Keep changes] [✕ Cancel] │ │
|
||||
│ └────────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
These are relationship examples, not fixed pixel geometry. On a narrow viewport the chooser becomes a bounded, scrollable sheet with one card column if needed; filter chips wrap. It never opens wider or taller than the unobstructed screen. The top mode pill remains visible, and the chooser always has a reachable Close button. The capture bar wraps its text and stacks actions only when needed; it never hides the mode pill or the Stage point being placed.
|
||||
|
||||
## Control layout and navigation
|
||||
|
||||
### Stage palette and Scenery chooser
|
||||
|
||||
- Add one illustrated **Scenery** card to the existing vertically scrollable left palette. Keep **Props** and **Ground** as separate cards, with a short helper line in their chooser/tool: “Stays put”, “Can be part of the action”, or “Stickmen walk here.” The palette card opens the Scenery chooser rather than directly arming a tool.
|
||||
- Keep the Scenery card pressed while its chooser and nested views are open. Back navigation keeps it pressed; closing or canceling the full chooser clears it. If a choice starts drawing, show that active state with the existing on-Stage capture bar instead of leaving the chooser card pressed.
|
||||
- The chooser has a fixed title/Close row; **Backgrounds** and **Artwork** tabs; a scrollable body; and a fixed lower **Make artwork…** action when relevant. It is a chooser workflow, not a selected-object inspector. It receives `SandboxTheme.control_theme()` and its own popup tokens, while borrowing the Stage panel system's font, surface, selected, hover, focus, and target-size rules.
|
||||
- **Backgrounds** shows two large category choices, **Sky** and **Wall panel**. **Artwork** shows a single-select filter row with **All artwork**, **Nature**, **Buildings**, **Walls**, **Roads & paths**, **Objects**, and conditional **Unsorted**. One drawing may carry several tags, so it appears under every matching filter. All artwork includes old, untagged drawings. Filters describe appearance, not behavior. Apply the same filters in the Props browser while keeping its title and placement role distinct.
|
||||
- Use a `FlowContainer` for wrapping filter buttons and an adaptive card grid for previews. Each card has a large illustration, a readable name, and a visible keyboard focus ring. No card depends on hover to reveal its action. Changing tabs or tags preserves the chooser and moves focus to the first relevant control; closing returns focus to the Scenery palette card.
|
||||
- A chooser Close or Esc dismisses only the chooser. Clicking outside may dismiss it when safe, but never chooses an asset or changes a Sky. A blank result shows **“No artwork here yet”** and offers **All artwork** and **Make artwork…** rather than an empty panel.
|
||||
|
||||
### File → New starter chooser
|
||||
|
||||
- Run the existing unsaved-work Save/Discard/Cancel gate before offering a starter. Do not replace the open scene until a starter card is chosen. If the starter chooser is canceled, the current scene remains open; its dirty state reflects whether the child saved it at the gate.
|
||||
- The themed modal uses three large illustrated cards: **Blank Scene**, **Town Street**, and **Living Room**, plus **✕ Cancel**. Each card pairs a preview with one plain sentence: “Start from scratch”, “Shops, trees, sidewalk, and road”, or “A room with a window, rug, and furniture.” The cards wrap to fewer columns on narrower screens and remain scrollable. No tiny menu inside a card.
|
||||
- Choosing a card creates a new unsaved scene with its suggested name in an editable name field. The name may be changed there or through the existing Rename Scene command. A small, dismissible on-Stage cue can say **“Try Scenery to change this place”** after Town Street or Living Room opens. It must not cover the Stage or block input.
|
||||
- Blank starts with the existing neutral view and no Ground; the other two show editable ordinary pieces described in the accepted brief. Their cards must not promise a functional door, sitting, or automatic window cutting.
|
||||
|
||||
## Backgrounds and placement
|
||||
|
||||
### Sky
|
||||
|
||||
- **Backgrounds → Sky** opens four designed thumbnail cards: **Clear Day**, **Cloudy Day**, **Sunset**, **Starry Night**. The currently selected card has a strong border, filled selected state, and the text **“Current Sky”**; keyboard focus remains a separate outline.
|
||||
- One tap or Enter/Space changes the Sky immediately; the chooser stays open so another card can be tried. Close means “stop choosing”, not “revert”. With no Undo in Phase 19, the child can restore the previous look by choosing its card again. Changing Sky never recolors or tints other pieces. Sky has no Stage selection handles or overlap entry.
|
||||
- The thumbnail shows enough clouds, sun/moon, and color variation to predict the Stage result. It remains a representative still image; the Stage applies its automatic camera response without asking the child to configure motion.
|
||||
|
||||
### Camera-aware Sky details
|
||||
|
||||
- The four existing Sky cards and their immediate selection flow stay unchanged. The selected card still says **Current Sky**. Do not add a motion toggle, slider, new label, tutorial cue, cursor, or theme token.
|
||||
- Keep the vertical gradient fixed to and filling the full viewport. Clouds, sun, moon, and stars respond automatically and subtly to Stage camera pan and zoom in **EDIT**, **DIRECT**, and **PLAY**. They move less and change size less than the stickman and Ground, so they read as distant details while connecting to a dramatic shot.
|
||||
- Preset-specific composition keeps the main action area clear at ordinary framing. During close and wide views, details remain recognizable and do not grow across the character or walkable Ground. Camera response stays continuous and bounded; it does not expose an edge, pop, sweep distractingly, or reverse abruptly.
|
||||
- At unchanged camera framing, switching modes, starting/stopping PLAY, and reopening a saved scene reproduce the same Sky composition. On viewport resize, the gradient continues to cover the view and the details recompose coherently.
|
||||
- Keep landscape edges on world-anchored **Background ground** and scenery. Sky details do not draw a horizon, gain selection handles, enter selection, or alter the colors or behavior of world pieces.
|
||||
- The visible feedback is the Sky details' restrained response to the same pan/zoom gesture already used on the Stage. No additional status message or control feedback is needed.
|
||||
- Acceptance path: choose each Sky, then pan and zoom through ordinary, close, and wide framing in EDIT/DIRECT/PLAY; resize the viewport; start/stop PLAY; save/reopen with a saved camera view; and place Background ground behind walkable Ground. Confirm a subtle but perceptible Sky response, clear action area, no edge/flicker, consistent mode transitions, and Ground alignment.
|
||||
|
||||
### Wall panel
|
||||
|
||||
- **Backgrounds → Wall panel** offers picture choices **Paint**, **Brick**, and **Wood**, plus a large preview of only the selected finish (Paint is a flat color; Brick and Wood show their texture). The selected-color tile replaces the chooser content and footer with the themed custom color view; **Back to wall panel** discards its draft and returns to setup, while **Use color** applies it and returns. The chooser's **Recently used** row is the only recent-color list. In the expanded setup chooser, **Cancel** exits and **Draw wall panel** starts placement; there is no separate Back or close-X action in that state.
|
||||
- Choosing a look updates its preview. Pressing **Draw wall panel** closes the chooser and arms placement. The capture bar says **“Drag across the space for a wall panel”**, with **Done** and **✕ Cancel**. The pointer has a corner reticle and a nearby pill **“Drag to draw wall”**. A press sets the first corner; dragging draws a world-anchored translucent patterned rectangle; release commits one finite panel. The pattern preview remains at sensible scale rather than stretching with the draft.
|
||||
- Snap, when enabled, visibly aligns the draft to nearby grid lines. An unusably small draft shows a red outline and **“Make the wall bigger”**; release leaves no panel. A valid draft uses the EDIT accent plus a neutral outline and dimension cue. This is appearance only: a helper in the chooser says **“Looks like a wall. Stickmen can pass through.”**
|
||||
- Touch can drag or tap the first and second corners. The first tap leaves a visible anchored corner and continuous rectangle preview; the second tap commits. The same visible Cancel and Done remain available. Right-click cancels a draft and exits the wall tool under the exit rules below.
|
||||
|
||||
### Artwork and depth
|
||||
|
||||
- Choosing an artwork card closes the chooser, starts a translucent ghost under the pointer, and shows a capture bar with the drawing's name, **Far**, **Near**, **On the floor**, **Done**, and **✕ Cancel**. **Near** is the default for a newly chosen drawing. Each depth choice has a simple layer illustration plus text; selected, hover, and focus states differ without relying on color. Changing depth updates the ghost's visible placement layer before commit.
|
||||
- The cursor pill says **“Click to place [name]”**; on touch it becomes a small anchored Stage hint after the asset is chosen. Tap/click commits one copy. The ghost remains ready for another; after a commit the bar says **“Place another [name]”** and shows the count of copies placed in this tool session. Copies already committed remain when the tool closes. A repeat placement starts as another distinct piece.
|
||||
- The selected artwork's source card may carry tag badges in the chooser, but tag words never suggest collision or interaction. The Stage preview says **“Stays put”**. Its depth affects appearance only; it does not grant blocking, pickup, support, Use, or event behavior.
|
||||
|
||||
### Opening a wall panel for a window or doorway
|
||||
|
||||
- Wall-area erasing is easy to discover from either entry point: a selected wall panel's shared Scenery inspector includes a touch-sized **Erase wall area** action, and the Edit Scenery capture bar shows **Erase wall area** whenever nothing is selected. Either starts a dedicated tool with a translucent red, crossed rectangle preview and a visible capture bar: **“Drag over the wall · release to erase”**, **Done**, and **✕ Cancel**. Snap-to-grid, when enabled, applies to both drag corners.
|
||||
- Dragging a rectangle through one or more wall panels removes only the covered area. Each intersected panel is split into up to four remaining rectangles that retain its look and color. Brick/wood motifs keep a shared anchor, so the surrounding pattern does not restart at every cut edge. Existing artwork and other scenery are untouched; this is a visual opening, not a collision or doorway mechanic.
|
||||
- Each valid release applies that opening immediately. **Done**, **✕ Cancel**, right-click, or Esc exits the tool; canceling an in-progress drag discards only that draft, while previously completed openings remain. Phase 19 has no Undo, so keep the capture copy clear about this commit-on-release behavior.
|
||||
|
||||
### Placement exit, cancel, and mode changes
|
||||
|
||||
| State | **Done** | **✕ Cancel** | Right-click / Esc |
|
||||
| --- | --- | --- | --- |
|
||||
| Chooser open, no tool | Close chooser | Close chooser | Close chooser |
|
||||
| Tool armed, only passive artwork ghost or wall corner cursor, no placement yet | Exit without placing | Exit without placing | Exit without placing |
|
||||
| Active uncommitted wall draw or resize | Discard the draft, then exit the tool | Discard the draft, then exit the tool | Discard the draft, then exit the tool |
|
||||
| One or more pieces committed, no active gesture | Keep pieces and exit | Keep pieces; discard only the next passive ghost and exit | **Done**: keep pieces and exit |
|
||||
| One or more pieces committed, another gesture active | Keep prior pieces; discard current draft and exit | Keep prior pieces; discard current draft and exit | **Cancel current draft**, keep prior pieces, then exit |
|
||||
|
||||
A passive artwork ghost does not count as an active gesture; a pressed wall corner, two-tap first corner, or resize drag does. Releasing a mouse button after cancellation cannot commit the old draft. The capture bar keeps a short line **“Placed pieces stay”** once any copy has committed, so Cancel does not falsely imply that all prior placements are erased. Right-click is an optional pointer shortcut; Done and Cancel stay visible for touch and keyboard users. Switching to DIRECT/PLAY or opening another Stage tool discards an active draft, preserves completed pieces, and removes all ghosts, handles, and capture prompts. No new Undo control or shortcut is introduced here.
|
||||
|
||||
## Edit Scenery and selected-object cards
|
||||
|
||||
- The Scenery chooser has a large **Edit placed scenery** action. It closes the chooser and enters a clearly labeled **“Edit Scenery”** state inside EDIT, with an on-Stage pill and prominent **Done editing** button. The global mode remains EDIT and its mode pill remains visible. Done editing, Esc when no edit gesture is active, or switching modes returns to ordinary selection. Esc during a resize or move first cancels that draft and leaves Edit Scenery active. The child can reopen Scenery to place more pieces.
|
||||
- Ordinary EDIT click/box selection favors characters, Props, Ground, and existing interactive objects; broad wall panels, Far/Near artwork, and floor art do not enter those results. In Edit Scenery, only wall panels and Scenery artwork enter click/box selection. The selected piece gets a bright outline backed by a dark halo, a text name/depth label, and large move/resize handles with at least 44 × 44 logical-pixel hit regions at common zoom. A single-piece drag previews live and commits immediately on release; uniform resize keeps the opposite corner visibly pinned, and the transform affects only that placement. It has no extra Keep confirmation. While the pointer/finger is held, a compact capture bar offers **✕ Cancel** for touch users; Escape, right-click, or leaving Edit Scenery also cancels the active gesture and restores the pre-drag position/size. Releasing the gesture commits without waiting for another choice. A later Stage Undo action is deferred to its own phase and tracked in technical debt. The selected-artwork card also offers large **Smaller** and **Bigger** actions for users who prefer buttons; each applies one immediate, proportion-preserving size step to that placement only. Existing placement sizes are not automatically changed when this feature is added.
|
||||
- When pieces overlap, a small cutout under the pointer takes priority over a broad panel. Clicking a panel's exposed area or edge selects it. If several pieces still match, show a themed **“Pieces here”** chooser with one large labeled row per candidate and a visible Close. A selected panel also remains reachable through that chooser when its visible area is covered. Box selection in Edit Scenery includes only Scenery pieces; ordinary box selection does not gather broad scenery.
|
||||
- A selected Scenery artwork card uses `StageInspectorPanel` and `StagePanelChoiceGroup`. The header has the drawing name, icon, and Close. The body offers an illustrated **Where it appears** group with **Far**, **Near**, and **On the floor**, large **Smaller** / **Bigger** size steps, and **Erase scenery**. A selected wall card uses the same shell, with **Wall panel** header, **Look**, **Color**, and **Erase wall panel**. Each change applies only to that selected piece. These cards have a fixed Close, scrollable body, and the established compact **Settings** reopen button while the same piece remains selected. Closing the card does not exit Edit Scenery.
|
||||
- An Erase action for a wall or artwork asks **“Erase this piece?”** with **Keep it** and **Erase** buttons before removing it, because Phase 19 has no Undo. The Delete key follows the same safeguard for selected Scenery.
|
||||
- Sky is never listed in **Pieces here**, never box selected, and never shown in the selected-piece card. Its only edit path is **Backgrounds → Sky**.
|
||||
|
||||
### Artwork file missing after reopen
|
||||
|
||||
- A missing live `.prop` reference leaves a **real, saved Scenery placement** at its authored position and Far/Near/On the floor depth. On the Stage, draw a soft neutral translucent footprint with a dashed light-and-dark outline when the saved extent is known; otherwise draw a compact world-anchored marker at the saved point. A constant-screen-size picture/question icon and label say **“Artwork not found”**, followed by a short remembered drawing name or file name when available. Do not use a large red error block, expose a full file path on the canvas, or show an empty gap that looks like the child erased the art. Keep the marker legible on all four Skies and on common Ground/wall looks. In DIRECT and PLAY, the placement remains a subdued neutral marker at the same layer, without edit handles or repair controls, so the missing set piece is still evident without covering the action.
|
||||
- On scene open, reuse the existing missing-assets summary dialog with calmer copy: **“Some artwork could not be found. Your scenery spots are still here.”** List the friendly names and offer **“Show scenery”** and **“Later”**. Show scenery enters Edit Scenery and focuses the first missing placement; Later closes the dialog and leaves every marker visible. This summary appears once for the load, not on every frame or selection. It does not replace the existing stickman/Prop warning semantics; the missing-Scenery wording is scoped to Scenery.
|
||||
- In ordinary EDIT, the footprint and label are visible but the missing placement's broad bounds do **not** enter normal click or box selection. Its small, explicit **Find artwork** badge has at least a 44 × 44 hit target and can switch to Edit Scenery with that placement selected; the badge alone takes input, so a child can still select a character, Ground, or Prop in front of the marker. The Stage palette's **Edit placed scenery** path and a **Needs artwork** section in the Scenery piece list provide alternatives when the badge is covered or offscreen.
|
||||
- In Edit Scenery, the missing placement participates in Scenery selection and **Pieces here** with a distinct picture/question icon and **“Artwork not found · [name]”** row. Selecting it shows the normal `StageInspectorPanel` shell headed **“Artwork not found”**, with the remembered name, its saved depth, and large actions **Find artwork…**, **Choose another artwork**, **Keep for now**, and **Erase scenery**. An optional **File details** disclosure may show the saved path for a helping adult; the path is not the primary instruction. The neutral marker remains visible when the card is closed, and the compact Settings reopen control works as for other Scenery. If the original size is unavailable, do not show misleading resize handles; explain **“Find artwork to change its size.”** Moving the marker and changing its depth remain possible without making it solid or interactive. It can join Select several for group moves; if any selected member lacks a known footprint, disable Resize together with the same plain-language reason until that artwork is repaired.
|
||||
- **Find artwork…** opens the established themed `.prop` file chooser so the child can point to a moved file. **Choose another artwork** opens the same responsive Artwork gallery used for placement, explicitly labeled as a replacement choice. After either choice, show a ghost of the candidate at the saved position, size/scale, orientation, and depth where those saved values exist, and ask **“Use this artwork here?”** with **Use artwork** and **✕ Cancel**. The replacement can be adjusted afterward; do not silently alter Ground, Props, or other Scenery. Canceling the chooser, file dialog, or preview leaves the missing marker and saved reference untouched. An unsuccessful file load returns to the same marker/card with a plain **“Could not open that artwork. Try another file.”** message. Erase uses the shared **“Erase this piece?”** confirmation; only confirmed Erase removes the placement. If several places reference the same missing file, default to repairing the selected place only; an explicit **Use for all matching places** choice may be offered, with the affected count shown before confirmation.
|
||||
- The placeholder, badge, piece-list row, preview actions, and dialog work by touch and keyboard: focus is visible and distinct from the missing state; Tab reaches the badge/list, actions are at least 44 × 44, Enter/Space activates them, Esc closes a chooser or cancels an uncommitted preview, and focus returns to the selected placeholder/card. On a narrow viewport, the label truncates gracefully to the remembered name, the inspector body scrolls below a fixed header/Close, and its actions wrap or stack without hiding the mode pill. A missing marker is identified by icon and words as well as outline, never by color alone.
|
||||
|
||||
### Move or resize several Scenery pieces
|
||||
|
||||
- **Select several** is a large, explicit action within Edit Scenery. While it is active, tapping pieces adds/removes them without beginning a move. A touch-friendly, scrollable piece list offers each piece's thumbnail/name/depth and a large selection row; it provides **Select all scenery** and **Clear selection**. Box selection may add Scenery pieces under the same filter. **Select all scenery** means every wall panel plus every Far, Near, and On the floor Scenery artwork placement in the open scene. Sky, Ground, characters, and interactive Props are never included. There is no automatic starter-wide group or persistent lock between pieces.
|
||||
- With two or more pieces selected, show a halo-backed union outline, a separate outline on each member, and the text **“N scenery pieces selected”**. The selected-object card uses the shared `StageInspectorPanel` shell with **Move together**, **Resize together**, **Clear selection**, and a short explanation **“Ground and Props stay put.”** It does not show a single shared depth, finish, or color control, because mixed members may have different settings. The group outline and count appear on the canvas, not only in the card. Closing the card follows the normal compact Settings reopen behavior and leaves the selection visible.
|
||||
- **Move together** starts a live preview. Dragging the group or using large on-screen arrow buttons applies the same world-space offset to every selected Scenery piece, preserving their relative spacing and Far/Near/On the floor choices. The original outlines remain faint/dashed while the candidate positions have bright outlines. Snap, if enabled, moves the selection as a unit from its anchor without rounding members independently. A cursor pill says **“Move N scenery pieces”**.
|
||||
- **Resize together** starts a live uniform-size preview. Drag a group corner inward/outward; the opposite corner shows a fixed pin and does not move. Every selected artwork piece changes size and position by the same positive scale around that anchor, retaining its proportions and relative layout. Wall panel rectangles change size and position with the group, while Brick/Wood motifs retain their world-scale size and alignment instead of stretching. Far/Near/On the floor choices remain unchanged. Clamp or reject a preview that would collapse or flip any piece; show **“Too small”** with a blocked outline. The cursor pill says **“Resize N scenery pieces”** and identifies the fixed corner with a visible pin.
|
||||
- During either group preview, the on-canvas capture bar shows **Keep changes** and **✕ Cancel**, the selection count, and **“Ground and Props stay put.”** Releasing a pointer leaves the preview pending; it does not save a change or newly mark the scene dirty. Keep changes commits the whole preview as one edit and marks the scene dirty once. Cancel, right-click, or Esc restores the exact pre-preview positions and sizes and returns to the same multi-selection in Edit Scenery. A later mouse/touch release cannot commit a canceled preview. **Done editing** or switching modes while a preview is pending first cancels it, then exits Edit Scenery. A Save request while a preview is pending asks the child to Keep changes or Cancel before saving; it never silently saves the draft.
|
||||
- The group tools are operable without precise dragging: touch targets and corner hit areas are at least 44 × 44 logical pixels; large move arrows and **Smaller/Bigger** buttons give touch and keyboard users repeatable steps. Pointer users may drag any corner and see its opposite fixed pin; the button path starts with the top-left corner fixed and labels that choice. Every control is focusable, has a visible focus ring and text label, and responds to Enter/Space. On a narrow viewport, the multi-selection card scrolls beneath its fixed Close, the capture bar stacks its actions, and arrow/size buttons remain reachable even when a group corner lies offscreen. The mode pill and Stage preview remain unobstructed.
|
||||
- A committed group transform saves each member's new position and size through the normal scene save; depth, finish, physics, and interaction roles do not change. The temporary multi-selection, preview, and group outline do not persist on reopen. A whole-set transform that also moves/scales Sky, Ground, characters, or interactive Props is outside Phase 19 and belongs to a separately designed future feature.
|
||||
|
||||
Single-artwork direct resizing and multi-piece group resizing intentionally have different commit gestures: one artwork placement commits on handle release, while a group retains the existing snapshot preview with **Keep changes** / **✕ Cancel**. Do not add a single-piece confirmation bar as a substitute for deferred Stage Undo.
|
||||
|
||||
### Stage-relative authoring size in Prop Editor
|
||||
|
||||
- In Arrange, replace the fixed-target **Normalize Size** action with **Size for Stage**. It opens a reversible sizing view with **Small**, **Room**, and **Big** starting sizes and fine **Make smaller** / **Make bigger** adjustments. The presets are rough visual starting points relative to the standard standing stickman, not rigid limits; preserve the asset's proportions and let the child inspect the actual comparison before keeping it. Exact preset ratios are an architecture/implementation detail, not new UI copy.
|
||||
- Frame the complete artwork and guide together when the sizing view opens. Show a standing stickman at the standard 1:1 reference scale **in front of the artwork**, plus a clear floor/contact line near ankle level. Use a dark halo with a light core so the guide remains visible over any fill. The guide is editor-only and never becomes part of the saved artwork. The guide is visible whenever **Show Stickman Guide** is on and is forced on while **Size for Stage** is active.
|
||||
- **Keep size** applies the preview to the authored shapes and returns to Arrange; **✕ Cancel** restores the exact pre-preview shape geometry. Existing whole-prop Transform behavior remains the way to move/rotate/resize all shapes and editable anchors together. Keep this sizing action within the established Prop Editor Arrange toolbar and `PropTheme`; do not reuse the Stage inspector card for a distinct editor workflow.
|
||||
- Artist-created and newly authored vector artwork should already be drawn at its intended Stage size, so first placement is normally scale 1 relative to the authored artwork. The standard figure is about 940 world units tall. Prop names should guide an ordinary-object size estimate; the asset review records approximate intended bounds relative to the stickman (height, and width when useful) and includes a scale-check preview. The sizing view is a correction/authoring aid, not a required step for every asset.
|
||||
- Loading existing `.prop` files and scenes performs no automatic normalization and retains saved placement transforms. **Keep size** deliberately changes the authored geometry; saving over the same `.prop` uses the existing live-reference behavior, so scenes using that drawing show its revised artwork on reopen. Keep the current Save and Save As workflow; this addition introduces no extra copy/version prompt or overwrite confirmation.
|
||||
|
||||
## Ground finish workflow
|
||||
|
||||
- The existing **Ground** palette entry gains a **New Ground look** chooser with large picture swatches: **Paint**, **Brick**, **Wood**, **Grass**, **Dirt**, **Sidewalk**, **Asphalt**. Paint, Brick, and Wood use the same names and comparable preview motif as wall finishes. A chosen swatch becomes the active look for future Ground only. The chooser states **“New Ground will look like this”** and never silently repaints existing pieces.
|
||||
- Returning to the Stage shows a patterned Ground ghost for one tap or the existing drag-paint run. A small cursor pill says **“Click or drag to add Ground”** and the capture bar provides Done and Cancel under the exit rules above. Valid/blocked stroke previews use outline, symbols, and short words as well as color. Adjacent ghost pieces show a continuous-looking pattern. Ramp and Step keep their existing appearance and palette behavior.
|
||||
- Selecting an existing Ground piece in ordinary EDIT opens a Ground `StageInspectorPanel` card with **This Ground's look**, the same finish swatches in a `StagePanelChoiceGroup`, and any existing Ground controls. Selecting a finish here changes only the selected piece. The different headings **New Ground look** and **This Ground's look** make scope visible before a tap.
|
||||
- In PLAY, Ground keeps its walkable behavior and chosen look. Wall panels, road markings, and rugs never look like a selectable walking surface in the UI.
|
||||
|
||||
## Prop Editor route for Scenery artwork
|
||||
|
||||
- **Make artwork…** in the Scenery chooser uses the existing vector `.prop` authoring tool; there is no separate Scenery Editor or file type. When entered from Scenery, its first screen is framed as **“Make artwork for your scene”** and foregrounds vector drawing, color, shape arrangement, naming, and Save. Hide prop-only material, mass, bounce, collision, Use/attachment, and other action controls from this entry route. Do not require a pretend solid shape to save visual-only artwork.
|
||||
- The Props entry route retains prop-relevant controls and its distinct **“Make a Prop”** framing. If a drawing is valid for both roles, the child may find it in both browsers; the Stage placement entry point decides what the copy does. After a successful artwork save, offer **“Place it as Scenery”** and return to the Artwork chooser focused on the saved drawing. Cancel/exit returns without changing the open Stage.
|
||||
- Tag editing uses the same large multi-select choices **Nature**, **Buildings**, **Walls**, **Roads & paths**, and **Objects** in artwork authoring. The words are descriptive, optional, and never gate the All artwork view. An untagged saved asset remains discoverable under All artwork and conditional Unsorted.
|
||||
|
||||
The **Size for Stage** workflow above applies to both Scenery artwork and Props because they share the same `.prop` authoring canvas. It does not change the Stage role distinction: a Scenery placement remains inert and non-colliding, while a Prop retains its existing interaction and physics settings.
|
||||
|
||||
## Theme, components, and accessibility contract
|
||||
|
||||
- For selected wall, artwork, and Ground cards, reuse `StageInspectorPanel` for the fixed header, safe rect, body scroll, Close, focus, and reopened Settings button pattern. Reuse `StagePanelChoiceGroup` for exclusive depth/finish choices with stable labels and decorative preview cues. `StagePanelToggleRow` and `StagePanelSwitchVisual` remain available for true on/off settings but are not forced into this feature's depth or finish choices.
|
||||
- The multi-selection card also reuses `StageInspectorPanel` and `stage_panels.action` for its large Move/Resize/Clear actions; its member list and preview controls add tokens under `stage_panels` rather than hardcoded colors or sizes. The group capture bar extends the same transient Stage capture pattern used for placement, keeping its instruction and Cancel together below the mode pill.
|
||||
- Extend the `stage_panels` `SandboxTheme` tokens only where these cards need new preview-cue size, card spacing, or scenery-specific accent/selection outlines. Continue using `stage_panels.shell`, `.type`, `.choice`, and `.action` for geometry and typography, and `mode_colors.edit` for the EDIT accent. The Scenery chooser, starter modal, color dialog, and Ground chooser use popup/theme tokens and `SandboxTheme.control_theme()`; their layout is distinct from an in-stage inspector. Generalize the existing Stage capture-bar look for wall/artwork/Ground placement instead of copying fixed styling.
|
||||
- On narrow or short viewports, chooser contents scroll, filter chips wrap, card columns collapse, the inspector header/Close remain fixed, and the capture bar wraps/stacks within safe margins. Never let a panel cover the EDIT/DIRECT/PLAY mode pill. Decorative thumbnails and cue drawings ignore pointer input; each actual choice is one native focusable Button with Space/Enter activation. Focus moves into an opened chooser/card and returns to the opener on Close when possible.
|
||||
- Pointer, touch, and keyboard all reveal the selected state, hover where applicable, focus, disabled reasons, and confirmation. No instructional step exists only in a top header, bottom status bar, hover tooltip, or shortcut. Cursor pills remain near the pointer without covering it; they flip to stay in view. Touch users get the same instruction anchored near the draft plus always-visible Done/Cancel.
|
||||
|
||||
### Reuse and standardization audit
|
||||
|
||||
This matrix identifies current UI that already exists. “Extend/share” is a design requirement to converge repeated controls; it does not prescribe a class, signal, or file contract for the architect.
|
||||
|
||||
| Phase 19 surface | Existing source to use | Reuse decision and boundary |
|
||||
| --- | --- | --- |
|
||||
| **File → New** and unsaved-work gate | `StageChrome` File menu; `StageModalViews` unsaved `ConfirmationDialog`; Stage document flow | **Direct reuse.** Preserve Save/Discard/Cancel, focus, and the current scene until a starter is chosen. Do not make a second unsaved-work dialog. |
|
||||
| Illustrated starter chooser | `AssetCard`, `AssetSelector` scene/shell, `StageModalViews` dialog theming and Rename Scene name entry | **Extend/share the card-gallery presentation.** The three starter cards need a responsive grid, scroll, Close/Cancel, and selected focus behavior also needed by Scenery/Sky/finishes. The editable suggested name follows existing name-entry styling/validation; starter composition remains feature-local. This is a modal choice, not `StageInspectorPanel`. |
|
||||
| Scenery chooser and Artwork cards | `AssetSelector`, `AssetCard`, `StageAssetBrowser`, thumbnail cache/renderers, `scenes/stage/asset_selector.tscn` | **Extend/share the gallery shell and card behavior, reuse browsing/thumbnail work.** The current selector is a fixed four-column paged popup and sets card focus to `FOCUS_NONE`; these must be corrected for responsive layout and keyboard use in the common path rather than copied into a Scenery-only popup. Backgrounds/Artwork tabs use native button choice states and shared popup styling; placement-role text stays feature-local. |
|
||||
| Sky and wall/Ground finish cards | `AssetCard` and the responsive gallery behavior above; `SandboxTheme` popup/card tokens | **Share the same preview-card and focus/selected-state rules.** Sky and finishes supply their own preview imagery and one-tap selection meaning; card dragging is disabled for these choices. They do not pretend to be `.prop` assets or reuse `StageAssetBrowser` asset scanning. Wall and Ground share names/preview motifs for Paint, Brick, and Wood. |
|
||||
| Artwork tags, Props filters, authoring tags | No existing reusable tag-chip control; `StagePanelChoiceGroup` is a vertical exclusive inspector control; Stage speech UI demonstrates `HFlowContainer` wrapping | **Extract one shared wrapping filter/choice treatment.** Use native focusable buttons and one theme contract across Scenery browsing, Props browsing, and optional multi-tag authoring. Single-choice browser filters and multi-choice authoring use the same visual states but different selection rules. Do not clone local chip styling or force the vertical inspector group into a wrapping browser row. |
|
||||
| Wall Color and custom color view | `ColorSwatchSelector`; native `ColorPicker` in the themed Stage view | **Extend/share the color-swatch treatment** so it wraps on narrow screens, has visible chosen/focus states, and uses Stage tokens. Open custom color selection from the selected-color tile, keep one recent-color row in the chooser, and provide **Back to wall panel** / **Use color** actions. The Prop Editor's `PropTheme` styling is not a Stage style source; wall/color values remain feature-local. |
|
||||
| Scenery overlap **Pieces here** | `StageModalViews.show_objects_here()` and its themed, viewport-clamped, scrollable `PopupPanel` | **Generalize the existing overlap chooser.** Supply Scenery-only candidates and child-facing piece names/depth, while retaining the same placement, 44 px rows, dismiss, and focus behavior. Do not create a second overlapping-items popup. |
|
||||
| Missing Scenery artwork | Existing `MissingPropPlaceholder`/`MissingStickmanPlaceholder` preserve missing placements; `StageModalViews` missing-assets dialog; `StageInspectorPanel`; `StageAssetBrowser` gallery/file chooser | **Reuse and generalize the recovery path.** Keep saved placement continuity and one themed load summary, but give Scenery its neutral labeled marker, selection-card repair actions, and the existing artwork/file choosers. Do not copy the older red marker styling or create a second asset gallery or dialog skin. |
|
||||
| **Erase this piece?** | `StageModalViews` confirmation/dialog theming; existing Erase Use spot `ConfirmationDialog` and safe/danger treatment in `SandboxStage` | **Reuse the confirmation pattern.** Share the button sizing, themed window, and danger/safe styles instead of copying the spot-erase styling into another private function. The affected piece and wording are local. |
|
||||
| Placement and group-preview bar | `StageUseTargetCaptureBar` and the transient capture-bar contract in `stage_panel_ui_system.md` | **Generalize/extract the capture-bar shell** for EDIT prompts, mode accent, Done/Keep changes/Cancel, responsive stacking, and a safe position below the mode pill. Keep Use-target-specific wording/actions in its caller; do not build a second bar with copied colors/geometry. |
|
||||
| Cursor pill and Stage ghosts | `StageChrome` action tooltip/cursor, current placement ghost/terrain overlay, `SandboxTheme.overlays` | **Extend/share presentation and safe cursor positioning** while the wall/artwork/Ground draft visuals remain feature-local. Keep one visual language for valid/blocked, mouse/touch feedback, and cancellation; do not copy the current tooltip's hardcoded colors into Phase 19. |
|
||||
| Selected artwork, wall, Ground, and multi-selection card | `StageInspectorPanel`, `StagePanelChoiceGroup`, `StagePropSettingsView` dismissal/reopen behavior, `stage_panels` tokens | **Direct reuse of inspector shell and exclusive choice group; extend shared action styling only as needed.** These are in-stage selected-object cards. Their data, headings, member list, and commands stay feature-local. `StagePanelToggleRow`/switch are reserved for real on/off values and are not substitutes for depth or finish choices. |
|
||||
| **Erase wall area** tool | Selected wall's `StageInspectorPanel` or the no-selection Edit Scenery `StageUseTargetCaptureBar`; wall ghost/placement logic in `StageSceneryController` | **Reuse the selected-object action styling and existing transient capture bar.** Only the cutout rectangle preview and rectangle subtraction are feature-specific; do not add another toolbar or dialog. |
|
||||
| Select-several member list | `StageInspectorPanel` body/action styling; `StageModalViews` large selectable-row precedent | **Reuse row sizing, focus, selected, and scroll rules.** Membership logic and piece labels remain local to Edit Scenery; do not invent another inspector shell or tiny checkbox list. |
|
||||
| **Make artwork…** and return | Existing Prop Editor scene/controller and `.prop` authoring; `StageAssetBrowser` refresh/thumbnail path | **Reuse the existing editor and asset browser.** The Scenery entry changes the visible authoring framing and hides prop-only controls; it does not create another editor, file picker, art card system, or `.scenery` format. The return-to-Stage handoff is feature-local. |
|
||||
| Stage-relative size in Prop Editor | Existing Prop Editor Arrange toolbar, whole-prop transform, Normalize Size path, stickman guide, and `PropTheme` | **Extend the existing authoring workflow.** Replace the fixed 96-unit normalization target with the reversible Size for Stage preview and front-drawn guide; keep the authoring figure/editor chrome local to Prop Editor. Do not adopt `StageInspectorPanel` for this editor-only interaction or change existing saved assets automatically. |
|
||||
|
||||
For every row, new dialogs/popups explicitly receive `SandboxTheme.control_theme()` and the established Stage dialog style, with their visual values read from `SandboxTheme`/`sandbox_theme.json` (`popups`, `palette`, `stage_panels`, `chrome.dialogs`, `mode_colors`, and `overlays` as appropriate). The existing `StageModalViews.apply_dialog_theme()` handles font/child overrides but is not, by itself, a substitute for assigning the control theme to a new window. Reuse local stylebox instances rather than mutating the cached shared `Theme`. Keep popup gallery behavior separate from the in-stage inspector layout while making their type, spacing, focus, and selected states consistent.
|
||||
|
||||
The existing `QueuePanel`, `RulePanel`, `ActionEditor`, and speech popups in `scenes/editors/stage/` solve different editing tasks. They can inform theme and responsive-container choices, but are not replacement shells for a starter or art gallery. Any new Stage popup should pass the same theme, sizing, focus, and dismissal checks as those existing workflows.
|
||||
|
||||
## Exact child-facing copy map
|
||||
|
||||
| Context | Text |
|
||||
| --- | --- |
|
||||
| Palette entry | **Scenery**; helper **Stays put** |
|
||||
| Props distinction | **Props**; helper **Can be part of the action** |
|
||||
| Ground distinction | **Ground**; helper **Stickmen walk here** |
|
||||
| Scenery tabs | **Backgrounds**, **Artwork** |
|
||||
| Edit action/state | **Edit placed scenery**, **Edit Scenery**, **Done editing** |
|
||||
| Multi-selection | **Select several**, **Select all scenery**, **Clear selection**, **N scenery pieces selected** |
|
||||
| Group action/preview | **Move together**, **Resize together**, **Ground and Props stay put**, **Keep changes**, **✕ Cancel** |
|
||||
| Group adjustment | **Smaller**, **Bigger**, **Too small** |
|
||||
| Wall category/helper | **Wall panel**; **Looks like a wall. Stickmen can pass through.** |
|
||||
| Wall cursor/draft | **Drag to draw wall**; **Make the wall bigger** |
|
||||
| Artwork cursor | **Click to place [name]**; after first copy **Place another [name]**; during direct resize **Resize [name]** |
|
||||
| Placement actions | **Done**, **✕ Cancel**; after a commit **Placed pieces stay** |
|
||||
| Ground palette/inspector | **New Ground look**, **This Ground's look** |
|
||||
| Overlap chooser | **Pieces here** |
|
||||
| Missing artwork | **Artwork not found**, **Find artwork**, **Needs artwork**, **Show scenery**, **Later** |
|
||||
| Missing artwork repair | **Find artwork…**, **Choose another artwork**, **Keep for now**, **Use this artwork here?**, **Use artwork**, **File details** |
|
||||
| Repair failure | **Could not open that artwork. Try another file.** |
|
||||
| Erase safeguard | **Erase this piece?**, **Keep it**, **Erase** |
|
||||
| Starter cards | **Blank Scene**, **Town Street**, **Living Room** |
|
||||
| Stage-relative size | **Size for Stage**, **Small**, **Room**, **Big**, **Make smaller**, **Make bigger**, **Keep size**, **✕ Cancel**, **Show Stickman Guide** |
|
||||
| Single Scenery resize | **Smaller**, **Bigger**; a handle drag commits on release |
|
||||
| Wall opening tool | **Erase wall area**, **Drag over the wall · release to erase**; **Erase another area · earlier openings stay** |
|
||||
|
||||
Do not expose “entity”, “collision hull”, “z-index”, “physics layer”, “finish ID”, or “depth tier” as child-facing copy.
|
||||
|
||||
## Observable UI review scenarios
|
||||
|
||||
1. Create Town Street from File → New, cancel at the starter chooser once, then choose it. The old scene persists on cancel; the starter appears as an editable unsaved scene with its sky, Ground, and separate set pieces.
|
||||
2. Choose Tree under Scenery → Artwork → Nature, change Far/Near/On the floor, place two copies, and right-click. Both copies remain, the passive ghost disappears, and ordinary EDIT selection returns. Repeat with an unfinished wall drag: right-click discards only that draft.
|
||||
3. In ordinary EDIT, click and box-select a character and Prop in front of a room wall without selecting the wall. Enter Edit Scenery, select a window cutout, then choose the broad wall through its exposed area or Pieces here. Start a direct resize and cancel the still-active gesture before release; its old bounds return. Release a second resize and verify it commits immediately, with no Keep prompt.
|
||||
4. Change Sky through all four cards while the Living Room window remains visible. The room colors stay unchanged; Close leaves the last chosen Sky, and keyboard focus returns to Scenery.
|
||||
5. Select Wood for New Ground, paint a run, then select one existing Ground piece and change only that piece to Brick through **This Ground's look**. A selected wall panel's own Finish/Color changes only that panel.
|
||||
6. At a narrow viewport and with touch/keyboard input, reach every chooser card, depth choice, Cancel, Done, inspector Close, and overlapping-piece choice without clipping or relying on hover. Enter PLAY and confirm all ghosts, handles, and edit-only bars disappear.
|
||||
7. In Living Room, use Select several to choose two wall panels, the window frame, and rug. Preview a shared move, cancel with right-click, and verify all four return exactly to their original locations while Wood Ground and furniture remain still. Preview a uniform corner resize, check the opposite anchor stays fixed and wall motifs do not stretch, then Keep changes; save and reopen. The four pieces retain their new positions/sizes and original depth/finish, while the temporary group selection is gone. Repeat the preview with touch or keyboard controls in a narrow viewport, using Esc to cancel.
|
||||
8. Save a scene with two copies of one live `.prop` Scenery drawing, then make the file unavailable and reopen the scene. The friendly missing-art summary appears once; both labeled markers remain at their saved positions/depths through EDIT and PLAY. In ordinary EDIT, select a character in front of a marker without selecting Scenery. Use a marker's Find artwork badge or the Edit Scenery **Needs artwork** list to open its card. Cancel a file choice and verify both markers remain. Choose a replacement for one copy, preview then cancel once, then confirm it; only that copy changes. Confirm the second still has a marker after save/reopen until it too is repaired or deliberately erased. Repeat the repair path with keyboard and on a narrow touch viewport.
|
||||
9. In Prop Editor, open **Size for Stage** on representative tall, wide, and small artwork. Confirm the standard stickman is drawn in front, the floor/contact guide is visible over every fill, the preview frames both together, presets and fine adjustments preserve proportions, **Keep size** applies, and **✕ Cancel** restores the exact prior geometry. Confirm new placement uses the authored size and loading an existing file performs no automatic normalization. Deliberately save revised geometry over a referenced asset and confirm the usual Save flow and live-reference update on reopen, with scene placement transforms retained. In Edit Scenery, resize one placement and confirm it commits on release and saves/reopens; cancel a still-active drag with Escape/right-click and with the touch capture bar; verify other scenery and Props stay unchanged. Compare this with the separate group Keep/Cancel flow. Repeat sizing-guide visibility and Stage handle/button access with keyboard/touch and at a narrow viewport.
|
||||
10. Open Scenery and navigate between Backgrounds, Plain Background color choices, and its custom picker. Back keeps the Scenery card pressed; Close or Escape from the full chooser clears it. Choose an artwork or surface tool and confirm the chooser card is unpressed while the on-Stage capture bar shows the active tool.
|
||||
@@ -0,0 +1,82 @@
|
||||
# Phase 19 addition — selected Scenery artwork depth
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified as part of Phase 19; the full scenery suite passes 706 checks with 0 failures. **Scope:** Edit Scenery's in-stage card for exactly one selected `StageSceneryArtwork`, including a missing-artwork marker. This is an addition to Phase 19. It does not change placement, wall panels, physical Props, or the scene schema.
|
||||
|
||||
## Child-facing behavior
|
||||
|
||||
After placing artwork, a child enters **Edit Scenery** and selects one drawing. The existing card keeps its artwork icon, name, fixed **Close** button, and **Smaller** / **Bigger** controls. Above the size controls, it shows **Where it appears** with three large, full-width choices:
|
||||
|
||||
1. **Far**
|
||||
2. **Near**
|
||||
3. **On the floor**
|
||||
|
||||
The selected choice matches that particular drawing's current layer. A short note below the choices says: **“Far is behind Near. On the floor is in front of the ground.”** Pressing another choice updates the Stage immediately and keeps the same card open. It changes only that selected placement; other copies of the same artwork keep their own layers. Repeatedly pressing the current choice has no effect on the document. The child's placement cursor and its Far/Near/On the floor capture-bar choices keep their current behavior.
|
||||
|
||||
A missing-artwork marker has the same depth section, using its saved depth. Changing it moves the marker's draw layer and is retained if the picture is repaired. A wall panel has no depth section. No selection or several selected scenery pieces has no single-artwork depth section or active depth command. Existing repair actions and the missing-artwork explanation remain visible where applicable.
|
||||
|
||||
The three buttons use the shared Stage inspector's selected, hover, focus, and disabled visual states; their words never gain checkmarks. Each native button meets the shared 44-pixel minimum hit height and responds to click, touch, Enter, and Space. On a short viewport, the body scrolls while the header and Close remain visible. A depth change preserves the body's scroll position. The card stays within the Stage's safe rectangle and does not cover the mode pill.
|
||||
|
||||
## Existing contracts and target changes
|
||||
|
||||
| Class / file | Typed contract | Change |
|
||||
| --- | --- | --- |
|
||||
| `StageInspectorPanel extends PanelContainer`, `scripts/shared/stage_ui/stage_inspector_panel.gd` | `func body() -> VBoxContainer`; `func set_header(title: String, icon_text: String = "") -> void`; `func set_safe_rect(rect: Rect2) -> void`; `func request_fit() -> void`; `func reset_scroll() -> void` | Reuse the present scenery card shell, its fixed header/Close, fit, and scroll. No new component API. |
|
||||
| `StagePanelChoiceGroup extends VBoxContainer`, `scripts/shared/stage_ui/stage_panel_choice_group.gd` | `signal choice_selected(id: StringName)`; `func add_choice(id: StringName, caption: String, cue: Control = null) -> Button`; `func select_no_signal(id: StringName) -> void`; `func apply_theme(stage_theme: SandboxTheme) -> void` | Instantiate one artwork depth group with IDs `&"far"`, `&"near"`, `&"floor"`. The caller owns the mapping to child-facing captions and the domain mutation. No new component API. |
|
||||
| `SandboxStage extends Node2D`, `scripts/editors/stage/sandbox_stage.gd` | Existing `_build_scenery_inspector()`, `_refresh_scenery_inspector()`, `_mark_scene_dirty()`; add a feature-local handler such as `func _on_selected_scenery_depth_choice(id: StringName) -> void` | Own the section, selection guard, refresh, and dirty call. Keep it in the existing scenery inspector body before `_scenery_size_row`. |
|
||||
| `StageSceneryArtwork extends Node2D`, `scripts/stage/scenery/stage_scenery_artwork.gd` | `var depth: StringName`; `func set_depth(value: StringName) -> void` | Existing setter remains authoritative. It applies `StageDrawOrder.scenery_z(depth)` immediately to live art and missing markers. No new API. |
|
||||
| `StageSceneAdapter extends RefCounted`, `scripts/editors/stage/stage_scene_adapter.gd` | Existing Scenery artwork entry's `depth: String` | Existing snapshot/load round trip persists the changed layer. No version, migration, or payload change. |
|
||||
|
||||
The section is feature-local composition inside the shared shell:
|
||||
|
||||
```text
|
||||
StageInspectorPanel (existing scenery card)
|
||||
├─ fixed header: artwork name or “Artwork not found” + Close
|
||||
└─ scrolling body
|
||||
├─ missing-artwork explanation (only when missing)
|
||||
├─ Where it appears (only for one selected artwork)
|
||||
│ ├─ StagePanelChoiceGroup
|
||||
│ │ ├─ Far [id: far]
|
||||
│ │ ├─ Near [id: near]
|
||||
│ │ └─ On the floor [id: floor]
|
||||
│ └─ helper: Far is behind Near. On the floor is in front of the ground.
|
||||
├─ Smaller / Bigger (existing availability rules)
|
||||
└─ existing wall-erase or missing-artwork actions, as applicable
|
||||
```
|
||||
|
||||
Style the heading and helper with the existing `SandboxTheme` `stage_panels.type.section_size`, `stage_panels.type.helper_size`, and text/muted colors. Apply the theme to the choice group so it uses `stage_panels.choice` sizing and states and `mode_colors.edit` accent. `StagePanelToggleRow` is for booleans and does not represent this three-way choice. No parallel button styling, theme token, popup, or dialog is required. This follows the approved [Stage panel UI system](stage_panel_ui_system.md) and [Phase 19 UI/UX specification](phase_19_scenery_backgrounds_ui_ux.md).
|
||||
|
||||
## Signal and document flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Press[Far / Near / On the floor pressed] --> Choice[StagePanelChoiceGroup.choice_selected: StringName]
|
||||
Choice --> Guard[SandboxStage validates Edit Scenery and exactly one selected artwork]
|
||||
Guard --> Same{New depth?}
|
||||
Same -- No --> Sync[Refresh selected button without signal]
|
||||
Same -- Yes --> Setter[StageSceneryArtwork.set_depth]
|
||||
Setter --> Draw[StageDrawOrder z-index changes now]
|
||||
Setter --> Dirty[SandboxStage._mark_scene_dirty]
|
||||
Dirty --> Sync
|
||||
Dirty --> Save[Normal .scene save snapshot stores depth]
|
||||
```
|
||||
|
||||
The handler re-reads the current selection when the signal arrives; it must not retain a previously selected artwork reference in a button callback. It returns without mutation unless Stage is in Edit Scenery, the selection has exactly one valid `StageSceneryArtwork`, and the ID belongs to `far/near/floor`. It also returns without marking dirty when the requested ID already equals `artwork.depth`. For a real change, it calls `artwork.set_depth(id)` once, calls `_mark_scene_dirty()` once, and refreshes the card. Refresh uses `select_no_signal(artwork.depth)`, avoiding a second handler call. It does not call `reset_scroll()` for this value change or close/recreate the card; normal fitting can be requested without moving the child's reading position.
|
||||
|
||||
For example, a selected tree with `depth == &"near"` receives `&"far"` from the button. Its `z_index` changes from `StageDrawOrder.NEAR` (`-20`) to `StageDrawOrder.FAR` (`-30`), its position and scale stay the same, and the Stage becomes dirty. Saving writes `"depth": "far"` in that tree's scenery artwork entry. Reopening selects Far for that tree; another tree placement can still be Near. A missing-art marker follows the same layer path and keeps its saved `asset_id`, footprint, and repair state.
|
||||
|
||||
## Acceptance and verification
|
||||
|
||||
1. Place two overlapping copies of a drawing, enter Edit Scenery, select one, and change Near to Far and then On the floor. The selected button and visible overlap order change immediately; the other copy keeps its former layer and neither copy moves or resizes.
|
||||
2. With one drawing selected, press its already selected layer. The document's dirty state does not change and no redundant depth mutation is applied. Change to another layer; the document becomes dirty, the card stays open, and its scroll position remains stable.
|
||||
3. Save the changed scene and reopen it. The same placement retains the new layer and its selected-artwork card highlights the saved choice. No scene-version migration or new field is needed.
|
||||
4. Select a missing-art marker with known or unknown bounds. Its saved layer is highlighted and can be changed before repair; the marker visibly follows the chosen layer, and a later successful repair keeps that latest layer. Existing Find/Choose/Keep actions and size availability remain intact.
|
||||
5. Select a wall panel, clear selection, and select multiple Scenery pieces. None offers a single-artwork depth choice. The wall's existing controls and group selection behavior remain available.
|
||||
6. On a short or narrow viewport and by keyboard or touch, reach all three depth choices and Close. The fixed header remains accessible; selected/focus styles are distinct, and the Stage mode pill remains clear.
|
||||
|
||||
## Architectural decisions and limits
|
||||
|
||||
- **Reuse the existing inspector and choice group.** The UI is one exclusive three-way setting inside a card that already exists, so an additional panel class, signal bus, generic inspector schema, or `Resource` model adds indirection without simplifying this change.
|
||||
- **Keep the Stage controller responsible for mutations.** The shared UI emits a `StringName` intent. `SandboxStage` verifies the live selection, changes one `StageSceneryArtwork`, and uses its existing dirty path; the UI control knows nothing about scene persistence.
|
||||
- **Keep per-placement depth as the source of truth.** The `.scene` adapter already saves this field and `set_depth()` already maps it to Godot draw order. Missing-art recovery preserves the placement's depth. The placement tool's default and capture-bar setting remain separate from editing an existing piece.
|
||||
- **Keep Undo in its own phase.** Each depth press is an immediate committed Stage edit. A future Stage-wide Undo command can capture old/new depth alongside other scenery actions under the existing Phase 19 debt item.
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
# Phase 19 — Starter Scene Composition: Architecture and Implementation Specification
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified. The user verified the Town Street and Living Room compositions in the editor. The Phase 19 scenery suite passes **706 checks with 0 failures**; see the [Phase 19 handoff](../plans/phase_19_handoff.md). The user-requested opaque Town Street Background ground layer and ordinary-size walkable Ground tiles are included.
|
||||
>
|
||||
> **Approvals:** Everyday Storybook direction approved; architecture defaults approved: **1,280×720 logical-pixel reference viewport (16:9)**, saved zoom **0.5**, horizontal pan guarantee **±1,000 world units**, and **100 world units** of end margin.
|
||||
>
|
||||
> **Related documents:** [Accepted composition brief](../plans/phase_19_starter_scene_composition.md), [UI/UX specification](phase_19_starter_scene_composition_ui_ux.md), [Phase 19 scenery specification](phase_19_scenery_backgrounds_surface_finishes.md), and [Background Ground and Wall Color brief](../plans/phase_19_background_ground_and_wall_color.md).
|
||||
|
||||
## Decisions and scope
|
||||
|
||||
1. Revise the existing Town Street and Living Room `.scene` snapshots using the existing editable node types. Promote the edited starter snapshots to the existing current scene format v1.6; their bundled source snapshots are v1.5. Preserve current starter IDs, File → New flow, and ordinary save/reopen behavior. The existing 1.5→1.6 migration and `background_ground` object type are already supported; this feature adds no schema field and does not bump beyond v1.6.
|
||||
2. At saved zoom 0.5, author a horizontal surface span of at least **4,760 world units** for each surface that must remain present during pan. Use adjacent ordinary-size terrain tiles rather than scaling one walkable block across the whole span. The current Ground template snaps to a 192×32-world-unit polygon at scale 1; 25 adjacent tiles produce a 4,800-unit run from x=−2,400 to +2,400, covering a **1,280-logical-pixel rendered viewport**, camera center travel from the saved x-position by **±1,000 world units**, and at least **100 world units** of margin at either end:
|
||||
|
||||
`required_width = viewport_width / saved_zoom + 2 * pan_travel + 2 * margin`
|
||||
|
||||
`= 1,280 / 0.5 + 2 * 1,000 + 2 * 100 = 4,760 world units`
|
||||
|
||||
Each tile remains a normal-size, independently selectable Ground object. Adjacent edges must meet exactly: preserve one level collision top, avoid gaps/overlaps, and let the repeated tile edges read as intentional joints.
|
||||
|
||||
With the current saved camera center x=0, 25 tiles span x=−2,400 to +2,400. At camera x=±1,000, the viewport reaches ±2,280, leaving a 120-unit margin. Town Asphalt uses two additional normal-size tiles, one at each end, so a character can step down from the sidewalk onto the road at an exposed curb; its 27 tiles span 5,184 units.
|
||||
3. Keep camera panning unrestricted. The authored guarantee is finite and applies at the saved zoom over the stated envelope; scene edges can appear beyond that envelope or in a wider zoomed-out shot. Zooming in continues to show the same continuous surface across the viewport.
|
||||
4. Keep camera and placement state as ordinary saved `.scene` fields. Adjust the saved camera y only as needed to meet the approved opening composition; do not add camera limits or runtime surface extension.
|
||||
5. Reframe `StageStarterCardPreview` around the saved opening composition. Its image must not become panoramic merely because pan-only Ground or wall extents are longer. Derive the preview focus from the saved camera and visible central composition; do not add preview metadata to `.scene`.
|
||||
6. Reuse existing production artwork, surface finishes, Sky presets, and child-facing choices. This pass introduces no new controls, theme tokens, scene object types, signals, or graphical assets.
|
||||
|
||||
**In scope:** `content/stages/starters/town_street.scene`, `content/stages/starters/living_room.scene`, `scripts/stage/scenery/stage_starter_card_preview.gd`, and targeted navigation-ribbon coalescing plus the exposed Town curb connector in `scripts/editors/stage/sandbox_stage.gd` needed for tile seams and the 32-unit sidewalk-to-road step.
|
||||
|
||||
**Out of scope:** camera restrictions; runtime-generated or auto-extending scenery; a new starter or template system; new art; changes to Ground physics/collision, navigation behavior beyond adjacent tile seams and the exposed 32-unit Town curb step, wall collision, Prop roles, Sky response, chooser controls, or scene serialization; zoom-out edge guarantees beyond the stated envelope.
|
||||
|
||||
## Current state and architecture fit
|
||||
|
||||
Both bundled starter files currently use scene v1.5 with `sky_id`, saved camera `{position, zoom}`, and independently editable object records. `StageSceneIO` migrates them to the current v1.6 format on read. Both currently save zoom 0.5 and camera x=0. Town Street saves a Cloudy Day Sky, one Far skyline, four Near artworks, and 1,400-world-unit Sidewalk and Asphalt runs. The buildings and trees do not share one visible base line, and their current Ground ends inside the opening view. Living Room saves a Clear Day Sky, three painted wall panels around a real window gap, seven 200-unit Wood Ground pieces, separate wall art and rug, and three functional Props. The floor run is short; the couch and armchair are visibly above its support line.
|
||||
|
||||
`StageSceneIO` and `StageSceneAdapter` already persist and reload these records. `StageSpawner` creates ordinary terrain and Props. `TerrainBlock` remains the walkable surface; `StageBackgroundGround`, `StageWallPanel`, and `StageSceneryArtwork` remain inert Scenery. `StageSurfaceRenderer` already draws world-aligned surface motifs with viewport culling, and `StageRectSurface` caches wall patterns. These are existing contracts to reuse, not new abstractions.
|
||||
|
||||
The source art's measured visual bottoms are useful placement references: Town house about 128 local units below its origin, storefront 119, tree 113; couch 111, armchair 107, coffee table 94. These bounds are starting measurements only. Final alignment uses rendered visible contact at Stage scale, not saved origins or selection AABBs alone.
|
||||
|
||||
## Scene and rendering flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
FileNew[File → New → Town Street or Living Room] --> Read[StageSceneIO migrates v1.5 input to current v1.6]
|
||||
Read --> Apply[StageSceneAdapter + StageSpawner create ordinary World children]
|
||||
Apply --> Camera[Saved Camera2D position and zoom]
|
||||
Camera --> Sky[Screen-space StageSkyView]
|
||||
Camera --> World[World surfaces, scenery, Props, actors]
|
||||
World --> Opening[Everyday Storybook opening composition]
|
||||
Pan[Unrestricted camera pan] --> Camera
|
||||
Extent[Authored 4,760-unit surfaces] --> World
|
||||
Read --> Preview[StageStarterCardPreview]
|
||||
Camera --> Preview
|
||||
Preview --> Card[Opening-shot preview; ignores pan-only bounds]
|
||||
Opening --> Save[Existing scene save/reopen path]
|
||||
Save --> Read
|
||||
```
|
||||
|
||||
The live Sky remains the screen-space background. World surfaces and objects keep their existing semantic draw order: Sky, Background ground, wall/Far scenery, Near scenery, walkable Ground and floor scenery, then action objects and actors. Preserve the existing Sky response and keep the chooser card's Sky unbound to the live camera.
|
||||
|
||||
## Starter composition contracts
|
||||
|
||||
### Town Street
|
||||
|
||||
- Keep the Cloudy Day Sky, muted Far skyline, existing house/storefront/tree artwork, and normal Ground palette. Use the Far skyline and the placement/scale of existing Near art to imply more street while preserving a clear center.
|
||||
- Align the visible bottoms of each building and tree to one sidewalk top line. Use source-art visible bounds to seed placement, then adjust by rendered inspection. At saved zoom 0.5, the final visible gap from an asset base to the sidewalk must be no more than 3 logical screen pixels.
|
||||
- Give the initial camera frame a calm center lane at walking height: at least its middle third remains clear of Near artwork, leaving room for a standard standing stickman and a short speech bubble.
|
||||
- Add an opaque `StageBackgroundGround` behind the skyline, near artwork, and walkable tiles. It begins at the skyline's lower visible datum and extends below the opening viewport, covering the clouds that otherwise show through the gap between the skyline and street. Use the existing Grass finish. It is visual only and does not create another walking line.
|
||||
- Build Sidewalk as a horizontal row of 25 default-size Ground tiles, with centers from x=−2,304 to +2,304 and bounds x=−2,400…+2,400. Build Asphalt as a separate row of 27 default-size tiles, with one extra tile at either end and bounds x=−2,592…+2,592. Place Sidewalk at y=0 and Asphalt at y=32 so their edges meet and the Asphalt begins below the Sidewalk. The exposed 192-unit road ends provide a physically reachable 32-unit curb step; route navigation at those endpoints without merging the Ground blocks or colliders. Keep both rows flat and continuous; no single oversized block or deep scaled Asphalt piece.
|
||||
- Keep skyline and Near artwork as separate editable placements. The Far skyline should not reveal a distracting cut edge within the pan envelope; reuse/reposition or duplicate existing skyline art only if its actual bounds require it.
|
||||
|
||||
### Living Room
|
||||
|
||||
- Keep the Clear Day Sky and the existing window frame and room artwork. Extend the painted wall from side to side across x=−2,380…+2,380, with a clean floor boundary and editable baseboard or equivalent edge.
|
||||
- Build the wall as opaque editable panels around one deliberate window aperture. The opening is the only visible route to Sky. Extend the top and side panel bounds far enough to cover the full rendered viewport at pan endpoints; use slight opaque overlap at non-window joins to prevent subpixel Sky leaks. Do not overlap the aperture.
|
||||
- Preserve the window as a real gap between wall panels with the existing transparent frame in front of the Sky. Do not add fake glass, collision, or a new wall-cutout behavior.
|
||||
- Build `finish_ground_wood` as one horizontal row of 25 default-size Ground tiles. Centers are spaced 192 world units apart from x=−2,304 to +2,304 at y=200; at scale 1 the row's top is y=184 and its combined bounds are x=−2,400…+2,400. Keep one level collision top and the existing wood pattern scale; do not stretch one block across the room.
|
||||
- Place the couch, armchair, coffee table, and floor art so visible supports/base edges sit at the wood floor line within 3 logical screen pixels at saved zoom. Preserve Prop roles and their normal collision/support. Keep the rug centered, visually above the wood, below actors, and outside the central movement lane.
|
||||
- Keep the wall decorations separate and secondary to the window and action. No individual decoration or furniture piece may be merged into a backdrop image.
|
||||
|
||||
### Shared camera and child readability
|
||||
|
||||
- Retain saved zoom 0.5 unless rendered comparison shows the approved composition cannot fit. Save the chosen camera y/center in each scene so normal File → New opens directly to the intended shot.
|
||||
- At the supported 1,280×720-logical-pixel reference viewport, test the saved center and camera x at −1,000 and +1,000, at zoom 0.5. At all three positions, the applicable sidewalk/road, wall/baseboard, and floor cover the full rendered viewport width with no panel or terrain end, accidental Sky seam, or distracting join.
|
||||
- Tune vertical framing against the safe Stage area in a render-capable run: put the walking line about 70–80% down from the top of the usable Stage area. A standing stickman must fit from feet to head; a two-line speech bubble must remain readable with about 24 logical pixels of clearance from visible Stage chrome.
|
||||
- A narrower viewport is covered by the same surfaces and must retain actor/bubble legibility. Do not assert the 1,280-pixel guarantee for a wider logical viewport without recalculating the extent formula.
|
||||
|
||||
## Persistence and typed contracts
|
||||
|
||||
No new API, signal, or serialized field is introduced.
|
||||
|
||||
| Target | Existing contract and required update |
|
||||
| --- | --- |
|
||||
| `content/stages/starters/town_street.scene` | Write current v1.6 with the existing `sky_id`, camera, and ordinary object dictionaries. Add the Grass Background ground object, and use unique `file_id`s for each default-size Sidewalk (25) and Asphalt (27) terrain tile. Keep stable IDs for retained artwork and preserve the camera. |
|
||||
| `content/stages/starters/living_room.scene` | Write current v1.6. Update wall panel `position`/`size`, use unique `file_id`s for each default-size Wood Ground tile, and preserve artwork/Prop transforms and camera. Keep the window aperture represented by the spatial gap between wall panels. |
|
||||
| `StageSceneIO` (`class_name StageSceneIO`) | Read v1.5 legacy snapshots and write current v1.6 documents. Do not bump beyond v1.6 or add camera-envelope/preview fields. |
|
||||
| `StageSceneAdapter` (`class_name StageSceneAdapter`) | Continue mapping `terrain`, `background_ground`, `wall_panel`, `scenery_artwork`, and `prop` dictionaries into their existing node classes. No starter-specific loader branch. |
|
||||
| `SandboxStage` (`class_name SandboxStage extends Node2D`) and `Camera2D` | Load the saved camera normally. Do not clamp position to starter bounds. Coalesce adjacent collinear terrain top edges into continuous navigation ribbons so pathfinding crosses tile joints; connect Town's 32-unit curb step only where the lower Asphalt extends past the upper Sidewalk. Keep the terrain objects/colliders separate. Existing zoom limits and user input remain authoritative. |
|
||||
| `StageStarterCardPreview` (`class_name StageStarterCardPreview extends SubViewportContainer`) | Replace the all-object-bounds fit as the preview focus rule. Keep its private preview setup and local `_world.scale`/`_world.position`; derive an opening-shot focus from scene `camera.position`/`camera.zoom` and a stable reference aspect. Ignore bounds added solely to cover the pan envelope. Do not mutate the loaded document or live camera. No public signal or caller change. |
|
||||
| `TerrainBlock`, `StageBackgroundGround`, `StageWallPanel`, `StageSceneryArtwork`, `PropBlock`, `StageSurfaceRenderer`, `StageRectSurface` | Reuse existing typed configure/save/render/collision contracts. Modify one only if visual validation finds a concrete rendering, scaling, or hit-selection defect in the required bounds. |
|
||||
|
||||
Representative existing object shapes (not new schema):
|
||||
|
||||
```json
|
||||
{"file_id":"ground_sidewalk_13","type":"terrain","asset_id":"ground","position":{"x":0,"y":0},"rotation":0,"scale":{"x":1,"y":1},"finish_id":"finish_ground_sidewalk"}
|
||||
{"file_id":"ground_asphalt_13","type":"terrain","asset_id":"ground","position":{"x":0,"y":32},"rotation":0,"scale":{"x":1,"y":1},"finish_id":"finish_ground_asphalt"}
|
||||
{"file_id":"town_backdrop","type":"background_ground","position":{"x":0,"y":Y},"size":{"x":4800,"y":H},"finish_id":"finish_background_grass","color":"#72A84C"}
|
||||
{"file_id":"wall_left","type":"wall_panel","position":{"x":X,"y":Y},"rotation":0,"size":{"x":W,"y":H},"finish_id":"finish_wall_paint","color":"#5A9D70"}
|
||||
```
|
||||
|
||||
`N`, `X`, `Y`, `W`, and `H` are scene composition values to tune from rendered visible bounds and camera framing. They do not denote new runtime fields. Prefer scene objects whose visible geometry meets at common edges rather than hiding incorrect positions with z-order.
|
||||
|
||||
## Starter-card framing
|
||||
|
||||
Today `_fit_scene_to_preview()` unions every loaded object's world AABB and fits that union into 256×256. The 4,800-unit rows of tiles or wall would dominate that union. The replacement should:
|
||||
|
||||
1. Read the saved camera center and zoom from the already-loaded scene data.
|
||||
2. Build a square preview-only focus centered on the saved camera position. Use the 16:9 reference viewport height and saved zoom for the square world extent: at 1,280×720 and zoom 0.5, the crop is 1,440×1,440 world units. This keeps the town's central buildings/trees or the room's window/furniture in the chooser card while ignoring long pan-only bounds. Fit the square crop into the existing 220×220 usable area of the 256×256 preview.
|
||||
3. Fit that focus region inside the preview's usable bounds. Do not include pan-only surface tails when computing the frame; the live scene still renders those full surfaces.
|
||||
4. Leave the Sky preview still and full-rect. Apply preview pan/scale only to the preview `_world` node; never modify saved camera data.
|
||||
5. Inspect both cards at their actual chooser size. Each should show its identity and central composition without shrinking the actor/set to a tiny strip or clipping the window/road datum.
|
||||
|
||||
Do not add per-starter preview bounds to `.scene` unless a shared, camera-derived crop demonstrably cannot keep both cards recognizable. That would require a separately approved data/authoring need.
|
||||
|
||||
## User paths and observable acceptance
|
||||
|
||||
| Child path / repeatable scenario | Required observation |
|
||||
| --- | --- |
|
||||
| File → New → Town Street | At the saved shot, the child sees a readable neighborhood, opaque land behind the skyline, continuous tiled sidewalk/road, a clear center lane, and the existing cloudy Sky above the skyline. Near artwork bases rest on the same walkable line within 3 screen pixels. |
|
||||
| Town Street at saved zoom; pan to camera x=−1,000, 0, +1,000 | The full rendered width remains covered by sidewalk and Asphalt tile rows. Tile joints are intentional and edges have no collision or navigation gaps; no exposed row end or Sky/clouds show through below the skyline. A PLAY actor can walk off the sidewalk end and land on the exposed road, and navigation connects both walk lines there. The decorative backdrop does not support a stickman. |
|
||||
| File → New → Living Room | The child sees a complete painted room with visible baseboard and wood floor. Sky appears through the window opening only. Furniture supports meet the floor within 3 screen pixels; rug is centered below actors, with an open action lane. |
|
||||
| Living Room at saved zoom; pan to camera x=−1,000, 0, +1,000 | Wall, baseboard, and floor cover the full rendered width. No Sky leak appears at panel edges, under the floor, or outside the window. Furniture stays separate and the ground remains one support level. |
|
||||
| Place a standard standing stickman and a two-line speech bubble in the central lane; inspect EDIT and PLAY | Feet contact the intended surface. Head, body, and bubble are legible with the specified chrome clearance. PLAY preserves Ground support and existing Prop behavior; no decorative Background ground or wall panel gains collision. |
|
||||
| Open New Scene chooser; inspect Town Street and Living Room cards | Each card remains a recognizable opening-shot preview after the live-world pan surfaces are lengthened. The camera framing of the preview does not move the saved/live scene. |
|
||||
| Save each revised starter as an ordinary scene, close/reopen it | Existing object types, finish IDs, individual placements, roles, Sky ID, and saved camera framing round-trip through the current scene v1.6 format. The loaded scene remains editable and has no starter-only runtime behavior. |
|
||||
| Resize to a narrower Stage viewport; zoom in for a close shot | Continuous surfaces still cover the visible width. The action lane and window remain legible. This pass does not promise full-width coverage for zoom-out views wider than the reference envelope. |
|
||||
|
||||
Phase 2 must inspect rendered captures from a render-capable Godot Stage at opening frame, both pan endpoints, PLAY, both starter cards, and a narrower viewport; record the capture paths and observed pixel gaps/seams. Exercise actual camera pan, save/reopen, Ground support and navigation across tile joints, and normal selection/edit routes. Bake adjacent collinear tile tops into continuous navigation ribbons and connect the exposed Town curb step without merging separate terrain objects or colliders. A successful import or headless parse alone does not verify composition. If an interactive rendering/input route is unavailable after trying it, list each unverified outcome and provide a focused user check.
|
||||
|
||||
### Implementation and verification record (2026-10-21)
|
||||
|
||||
- The initial pass promoted both snapshots to v1.6 and aligned visible bases, but used oversized scaled walkable blocks and omitted Town Background ground. The user identified those issues; that surface implementation was superseded by the tile/backdrop revision below.
|
||||
- `StageStarterCardPreview` now derives a square crop from the saved camera position and zoom. At zoom 0.5, it frames a 1,440 × 1,440 world-unit opening crop in the existing 220 × 220 usable preview area.
|
||||
- `/Applications/Godot.app/Contents/MacOS/Godot --path /Users/ryan/Projects/stickman --headless --rendering-method gl_compatibility --script res://tests/test_phase19_starter_scene_composition.gd` passed **515 assertions** on Godot 4.7.1. It covers production scene loading, save/reopen, surface bounds, window opening, preview transforms, base contacts, PLAY support, navigation across each tile row, and sidewalk-to-road access. Town Asphalt has 27 scale-1 tiles spanning 5,184 units; a PLAY actor moved from x=2,280 to x=2,500 and landed grounded on the road at feet y=15.31. The navigation query from center to the opposite walk line follows the exposed right curb through `(2400, -4)` and `(2400, 12)`. Measured contact gaps at the saved zoom were 0.0 logical px for Town artwork; 0.0–0.123 px for Living Room floor artwork; and 0.025–0.225 px for the three Props. These are production-loaded geometry measurements, not pixel samples from rendered captures.
|
||||
- An earlier Phase 19 scenery-suite run exited 1 with nine failures in Sky/surface previews and Edit Scenery eraser/capture-bar behavior. This historical result was superseded by the 2026-10-22 retest: **706 checks passed, 0 failed**.
|
||||
- Rendered-pixel inspection could not be completed here: a bounded GUI capture attempt exited 134 without output or an image, and an earlier headless compatibility capture produced no image before it was stopped after 30 seconds. The default headless Vulkan test path also crashed in shader translation. The focused compatibility test exited successfully; the environment printed a macOS CA-certificate lookup warning.
|
||||
- User/editor checks listed here are complete as of 2026-10-22. The user verified the starter compositions and the remaining Phase 19 visual/interaction scenarios; see the [Phase 19 handoff](../plans/phase_19_handoff.md) for the consolidated record.
|
||||
|
||||
### User visual follow-up (2026-10-21)
|
||||
|
||||
The user's Town Street capture showed Sky clouds visible below the skyline because the initial implementation omitted Background ground. The user also rejected the oversized scaled TerrainBlocks used for walkable surfaces and requested left-to-right rows of ordinary Ground tiles in both templates. The current revision adds opaque non-walkable Grass Background ground behind Town Street and uses adjacent scale-1 tiles for Sidewalk, Asphalt, and Living Room Wood. Sidewalk uses 25 tiles; Asphalt uses 27, extending one tile beyond each sidewalk end so the road is physically reachable. The focused production-path test passed 515 assertions, including seam routing and a grounded PLAY drop onto Asphalt. The final user/editor verification and 706-check Phase 19 suite result supersede this earlier pending status.
|
||||
|
||||
## Trade-offs and deferred work
|
||||
|
||||
- Ordinary-scale tile rows avoid oversized Ground selection bounds and keep each walkable piece independently editable. Their joints should remain intentional, with adjacent collision and visible edges meeting without gaps. The navigation bake merges contiguous coplanar tile tops for routing while the Ground pieces remain separate, and connects the Town curb step only at exposed road ends.
|
||||
- The 4,800-unit sidewalk/floor rows of ordinary-size Ground tiles cover the specified 4,760-unit minimum envelope and remain individually editable. Town Asphalt extends to 5,184 units for curb access. These finite surfaces do not track arbitrary viewport resizing, very wide zoom-out shots, or unbounded camera travel. The camera remains free; no edge clamp or auto-extension obscures that finite set boundary.
|
||||
- Preview framing is derived from the saved opening camera instead of saved preview metadata. This avoids schema/round-trip work but gives every card the same generic crop policy; if that cannot show a particular starter clearly, document the concrete limitation before proposing metadata.
|
||||
- No new art is required based on current library bounds. A curb/baseboard visual gap that cannot be composed from existing terrain finishes and wall panels should be described as one specific missing asset and sent through the existing asset-approval workflow.
|
||||
- Stage-wide Undo/Redo remains deferred. Starter polishing edits saved object data through existing flows and adds no new transaction system.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Phase 19 — Starter Scene Composition UI/UX Specification
|
||||
|
||||
> **Status (2026-10-22):** Implemented and user/editor verified as part of Phase 19; the scenery suite passes **706 checks with 0 failures**. This specification records scene presentation and reuses the existing controls.
|
||||
>
|
||||
> **Source:** [Phase 19 — Starter Scene Composition brief](../plans/phase_19_starter_scene_composition.md).
|
||||
|
||||
## User path
|
||||
|
||||
From **File → New**, the child chooses **Town Street** or **Living Room** and immediately sees a coherent set with a clear walkable area. At the saved camera frame, a standing stickman and a short speech bubble fit comfortably in the action area. The same visual relationships remain legible in EDIT, DIRECT, PLAY, and after save/reopen. A deliberate horizontal pan reveals more of the same set.
|
||||
|
||||
## Composition rules
|
||||
|
||||
### Town Street
|
||||
|
||||
- Keep the Cloudy Day Sky and a subdued Far skyline behind individual Near buildings and trees.
|
||||
- Add an opaque, non-walkable Background ground layer below the skyline datum. It must cover the lower opening view behind the street and prevent Sky clouds from showing through the gap between the skyline and the walkable surface.
|
||||
- Align all visible house, storefront, and tree bases to one sidewalk datum. Keep seams at or below 3 logical screen pixels at saved zoom.
|
||||
- Carry the Sidewalk and Asphalt across the usable stage frame as horizontal rows of ordinary-size, walkable Ground tiles. Keep their tops level and their edges adjacent so the tile joints are intentional, with no collision or visual gaps.
|
||||
- Leave at least the middle third of the initial frame visually calm at walking height. Near artwork may frame the action, but should not cover a character or speech placed in this area.
|
||||
- Keep Background ground behind the skyline, artwork, and terrain; distinguish it from the walkable sidewalk/road. It does not create another walking line.
|
||||
|
||||
### Living Room
|
||||
|
||||
- Continue the painted wall and a horizontal row of ordinary-size, walkable Wood Ground tiles across the initial frame and agreed pan envelope. Keep adjacent tile edges level, with intentional joints and no collision gaps. A visible baseboard or equivalent edge marks where wall meets floor.
|
||||
- Construct the window as a deliberate opening between editable wall pieces. The selected Sky is visible through that opening only; no Sky gaps appear at the room edges, below the floor, or along panel seams.
|
||||
- Place the couch, armchair, and coffee table so their visible supports meet the floor within 3 logical screen pixels at saved zoom. Keep the rug centered, above the floor finish, below actors, and outside the main movement lane.
|
||||
- Keep the middle third of the frame at walking height visually calm enough for a stickman and short speech bubble. Wall decoration stays secondary to the window and action.
|
||||
|
||||
## Camera framing and pan continuity
|
||||
|
||||
- Preserve the existing starter-choice flow and use a saved camera framing that shows the complete scene identity, walking datum, and clear action area at the actual safe Stage viewport size.
|
||||
- Place the walking line around 70–80% of usable viewport height measured from the top. Show a default standing stickman from feet to head and leave about 24 logical pixels between a two-line speech bubble and visible Stage chrome.
|
||||
- Define a horizontal pan envelope for each starter. At the saved zoom, the appropriate continuous surfaces must cover the full rendered viewport width at the envelope's left and right limits, with a small safety margin. Camera panning remains unrestricted beyond this authored envelope; finite set edges may appear there.
|
||||
- Compute surface width from the reference viewport: `rendered_viewport_width / saved_zoom + 2 * pan_travel + 2 * safety_margin`. For a 1,280-pixel reference width, zoom 0.5, ±1,000-world-unit travel, and 100 world units of margin per side, surfaces need at least 4,760 world units. Use 25 standard 192-unit Ground tiles for the Town sidewalk and Living Room floor. Town Asphalt uses 27 standard tiles, extending one tile beyond each sidewalk end so the road is physically reachable. Do not scale one walkable block across the scene.
|
||||
- Keep set parts independently editable. Tile rows use ordinary-scale pieces with adjacent edges, no collision gaps, and visible joints that read as regular surface tiles.
|
||||
- Do not stretch one walkable Ground block across the full pan envelope. Use a left-to-right line of default-size terrain tiles so each surface remains an ordinary, individually editable piece.
|
||||
|
||||
## Starter chooser preview
|
||||
|
||||
The starter card should show a representative opening composition, not fit the full pan-only extent. The current preview fits the combined bounds of every object; extending the ground and walls could make the important scene too small. Bound preview framing around the saved opening shot (or an explicit authored preview frame) while still showing the Sky, walking datum, and recognizable key artwork. This is a preview-only framing decision: it must not crop or constrain the loaded scene.
|
||||
|
||||
## Controls, copy, and theme
|
||||
|
||||
- Add no controls, filters, dialogs, inspectors, cursor modes, placement overlays, or status messages.
|
||||
- Keep the existing **Blank Scene**, **Town Street**, and **Living Room** choice labels.
|
||||
- Add no `SandboxTheme` colors or `stage_panels` tokens. Use the existing Sky, wall, Ground, Scenery, and Prop visual styles; tune scene-art contrast so a character and speech remain easy to read.
|
||||
- Reuse the existing EDIT, DIRECT, and PLAY mode treatments without adding mode-specific starter behavior.
|
||||
|
||||
## Observable UI/UX acceptance outcomes
|
||||
|
||||
1. Opening either starter at its saved frame reveals the intended place, a single readable walking datum, a calm central action area, and room for a default stickman plus short speech.
|
||||
2. At saved zoom, there is no visible (>3 logical screen-pixel) gap between Near artwork and the street datum or between furniture supports and the room floor.
|
||||
3. At the center and both ends of the specified pan envelope, the sidewalk/road or wall/baseboard/floor fills the usable Stage width without exposed ends, distracting seams, or stray Sky. In Living Room, Sky appears through the window opening only.
|
||||
4. The chooser card remains a recognizable view of the opening composition after the world surfaces are extended for panning.
|
||||
5. The same composition and visual ordering remain in EDIT, DIRECT, PLAY, and after save/reopen. Normal child edits can still move or remove individual pieces.
|
||||
|
||||
## Not applicable
|
||||
|
||||
There is no new interaction flow, so UI node/layout additions, focus behavior, cursor feedback, child-facing copy changes, dialogs, and inspector-token changes do not apply. Architecture will identify only the scene data, preview framing, or rendering changes needed to meet the observable outcomes.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Repeating scenery material cache
|
||||
|
||||
Status: accepted architecture for the 2026-10-20 scenery cache follow-up.
|
||||
|
||||
## Problem and result
|
||||
|
||||
`content/stages/fps.scene` exposed two related costs. The old vector tile cache could accumulate enough native drawing resources to report `Element limit reached`. Its replacement bounds those resources, but panning after zoom still reveals new world-position tiles and continuously starts more bitmap captures. Brick, wood, grass, carpet, and concrete are repeated finishes. Bake **one finite, seamless material texture per finish and tint** and repeat it across every visible rectangle. Once that style is ready, camera pan and zoom update only the draw quad and sampling coordinates; they do not build or read back more imagery.
|
||||
|
||||
Keep the scene-scoped `StageSurfaceCache.BakePool` under `SceneTree.current_scene` as a sibling of `World`. `StageRectSurface` owns a lightweight `StageSurfaceCache` handle for its style. A single reusable `SubViewport` baker is enough. Paint and interactive placement keep their existing direct drawing paths. No `.scene` schema or child-facing control changes are needed.
|
||||
|
||||
```text
|
||||
current_scene
|
||||
├── World
|
||||
│ ├── StageRectSurface ──┐
|
||||
│ └── erased fragment ──┼── handles for the same finish + tint
|
||||
└── StageSurfaceBakePool ─┴── one repeating ImageTexture
|
||||
└── SurfaceBitmapBaker (temporary vector commands)
|
||||
```
|
||||
|
||||
## Material periods and appearance
|
||||
|
||||
Bake every period at **2 bitmap pixels per world unit**. The material repeats in both directions. These dimensions are multiples of the current renderer's natural cells:
|
||||
|
||||
| Finish | Repeated cells | World period | Bitmap size at 2× |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Brick wall | 8 columns × 8 rows | 800 × 304 | 1600 × 608 |
|
||||
| Wood wall | 3 columns × 6 rows | 960 × 384 | 1920 × 768 |
|
||||
| Grass background | 16 × 16 | 704 × 576 | 1408 × 1152 |
|
||||
| Carpet background | 16 × 16 | 544 × 416 | 1088 × 832 |
|
||||
| Concrete background | 4 × 4 slabs | 1120 × 760 | 2240 × 1520 |
|
||||
|
||||
The 8-row brick and 6-row wood periods preserve stagger parity; the wood period also preserves its three-tone cycle. Keep brick size, plank size, color relationships, rough outlines, grain, pores, and other material features at their current world scale. Remove view-size-driven changes to brick or plank dimensions from the material bake: zoom must sample the same pattern. The resulting bitmap keeps full artwork at 40% zoom through GPU minification. At the Stage's maximum 6× zoom, the 2× bitmap is magnified threefold and may appear softer; this is an accepted quality trade-off.
|
||||
|
||||
The renderer uses absolute pattern cell coordinates for geometry and `posmod(cell_index, period_cell_count)` for **every decorative seed and tone choice**, including negative world coordinates. Wrap row and column before computing brick jitter, palette, marks, pores, wood tone, grain, knots, grass tufts, carpet fibers, and concrete speckles. Features crossing a period edge must be drawn from the matching wrapped neighbor, then clipped to the exact period bitmap. Check the first and last rows and columns together; a matching cell seed alone does not repair geometry or filtering at the seam. A finite period makes the former never-ending random variation visibly repeat; the chosen periods balance variety with bounded bitmap size.
|
||||
|
||||
## Rendering and erase coordinates
|
||||
|
||||
Generate mipmaps on the captured `Image` before creating its `ImageTexture`. On each patterned `StageRectSurface`, enable `CanvasItem.TEXTURE_REPEAT_ENABLED`. Draw the intersection of surface bounds and camera view as a single clipped quad with `draw_texture_rect_region(..., clip_uv = false)`; its source rectangle can span many repetitions. Compute the source position from the same renderer sample coordinate used today: **surface-local position plus `get_surface_draw_origin_world()`**, reduced with `fposmod` by the period before converting to bitmap pixels. Reducing the offset avoids large UV coordinates during long camera pans. Source width and height come from the visible local rectangle at two bitmap pixels per world unit. Godot's repeat sampler and mipmaps handle zoom without a cached zoom level.
|
||||
|
||||
The eraser continues splitting one rectangular surface into up to four fragments. Each fragment clips its own quad to its bounds and the camera. It requests the same style texture; the bitmap key is independent of fragment position, size, camera position, and zoom. Preserve the existing sampling convention: wall draw origin is `global_position`; background ground draw origin is `global_position + motif_origin_offset`. Moving, rotating, saving, reloading, erasing, Cancel, and Commit must keep each material's pattern aligned under those existing rules. A fragment's differing sample offset changes only its source UV, never the style bitmap.
|
||||
|
||||
Only request a style when some of that surface is camera-visible and not proven fully covered by later opaque scenery. Keep conservative coverage checks; partial union of multiple cover surfaces is optional. A surface with no texture yet draws its base color while its one style capture is queued. An already ready style remains warm through camera movement, including when the surface temporarily leaves the viewport.
|
||||
|
||||
## Cache and baker contracts
|
||||
|
||||
`StageSurfaceCache` remains a `RefCounted` handle with `signal updated`, `attach_to(owner_node: Node)`, `get_texture() -> Texture2D`, `dispose()`, and `static get_stats(owner_node: Node = null) -> Dictionary`. Its build request changes from a positional tile to a style request. The payload is finish (`StringName`), tint (`Color`), wall/background kind (`bool`), renderer/material revision, and the fixed period and density derived from finish. `StageRectSurface` no longer retains a dictionary of camera-position tiles. One handle may be replaced when tint or finish changes; other surfaces with the same key keep their texture.
|
||||
|
||||
`StageSurfaceCache.BakePool` has one entry per requested style. Entry identity includes all values that alter baked pixels, especially finish, tint, wall/background kind, and renderer revision. It excludes camera transform, surface bounds, eraser fragment, and sample phase. A queued entry with no live visible interested owner can be canceled. The pool serializes captures through one `SubViewport`, waits until the GPU has consumed its vector commands, reads the completed image, generates mipmaps, publishes an immutable `ImageTexture`, and clears baker vector commands. A failed capture leaves the base color visible and permits retry; it must not publish an empty ready texture.
|
||||
|
||||
Keep a **64 MiB global resident texture budget per scene**, including all mip levels, retired textures awaiting a safe frame, and reserved bytes for a build. One copy each of the five listed periods is about 32 MiB before mipmaps and 43 MiB with mipmaps at RGBA8; additional tint variants can require eviction. Evict styles without visible interested owners before styles in active use, and release canvas references safely before freeing a texture. Keep recently used styles warm so panning away and back does not trigger a new capture under normal budget. If active styles collectively exceed the budget, retain the hard cap and show base color for a style that cannot be admitted; expose this through stats rather than silently exceeding the budget. Revisit period size or density if this occurs in ordinary scenes.
|
||||
|
||||
`get_stats()` must expose at least resident texture bytes, entries, queued styles, active baker count, builds, readbacks, cache hits, and budget refusals. These counters make the reuse behavior observable without adding UI.
|
||||
|
||||
## Data flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Visible[Visible patterned surface] -->|finish + tint| Cache[Scene style cache]
|
||||
Cache -->|ready texture| UV[Sample repeated texture at existing pattern offset]
|
||||
Cache -->|first style request| Baker[One temporary bitmap baker]
|
||||
Baker -->|capture + mipmaps| Cache
|
||||
UV --> Clip[Clip quad to surface and camera]
|
||||
Clip --> Stage[Stage canvas]
|
||||
Camera[Pan or zoom] --> UV
|
||||
```
|
||||
|
||||
## Observable acceptance and verification
|
||||
|
||||
1. Open `content/stages/fps.scene` in EDIT, DIRECT, and PLAY. Allow visible brick, wood, and concrete styles to become ready. Pan left and right repeatedly and zoom in and out through the same region. `builds` and `readbacks` stay unchanged after those styles are ready; only a new finish or tint may add a style capture. Frame movement does not pause for repeated tile buffering, and `Element limit reached` does not recur.
|
||||
2. Inspect the left/right and top/bottom period boundaries for every finish at distant, 40%, normal, and close zoom. There are no lines, shifted brick courses, broken planks, or mismatched decorative marks. Zoom changes sampling detail without changing motif geometry.
|
||||
3. Erase through a brick wall and background ground, Cancel, then erase and Commit. Inspect both sides of each fragment edge, then save and reload. The cut stays clear, surrounding patterns stay aligned, and the cache still has one entry per shared style.
|
||||
4. Change a wall's tint and finish. The changed style may bake once; unchanged surfaces keep their ready texture. Return to the earlier style and pan again to check that recently used styles stay warm within the 64 MiB budget. Observe total bytes, pending styles, and baker lifetime during a long Stage session.
|
||||
|
||||
Use a render-capable run of the actual Stage for appearance and frame-time observations. This architecture update does not require a new test file.
|
||||
|
||||
## Trade-offs
|
||||
|
||||
A periodic material replaces unique random detail across an arbitrarily large wall with a bounded, repeating pattern. The chosen periods and seeded variation should make repetition unobtrusive at ordinary framing, but repeated landmarks can become noticeable on very large surfaces. GPU mipmaps replace four separately baked zoom levels and keep pan/zoom free of new builds. A one-time GPU readback remains when a finish/tint style first appears. Multiple color variants can evict warm styles under the 64 MiB cap, so those cases need measurement on representative scenes.
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"chrome": {
|
||||
"colors": {
|
||||
"background": "#171B24F2",
|
||||
"surface": "#252B38FA",
|
||||
"surface_hover": "#30394A",
|
||||
"selected_surface": "#103B4D",
|
||||
"text": "#F5F7FA",
|
||||
"text_muted": "#AAB2C0",
|
||||
"edit": "#22C6FF",
|
||||
"preview": "#22C6FF66",
|
||||
"focus": "#8BD9FF",
|
||||
"action_primary": "#087DBA",
|
||||
"destructive": "#E66B75",
|
||||
"border": "#FFFFFF33",
|
||||
"disabled": "#77808F",
|
||||
"saved": "#8FD6A4",
|
||||
"dirty": "#FFD166",
|
||||
"error": "#FF8A8A"
|
||||
},
|
||||
"fonts": {
|
||||
"body": 18,
|
||||
"helper": 16,
|
||||
"section": 22,
|
||||
"title": 26,
|
||||
"menu": 20,
|
||||
"menu_bar": 22,
|
||||
"menu_popup": 26,
|
||||
"status": 16,
|
||||
"mode": 24,
|
||||
"prop_name": 20,
|
||||
"context_menu": 20
|
||||
},
|
||||
"spacing": { "small": 8, "medium": 12, "large": 16 },
|
||||
"radii": { "control": 8, "panel": 10 },
|
||||
"borders": { "normal": 1, "focus": 2 },
|
||||
"targets": {
|
||||
"button_min_height": 44,
|
||||
"row_min_height": 44,
|
||||
"mode_button_min_height": 56,
|
||||
"context_menu_row_height": 48,
|
||||
"context_menu_min_width": 208
|
||||
}
|
||||
},
|
||||
"editors": { "prop": {}, "stickman": {} },
|
||||
"stickman_canvas": {
|
||||
"grid_color": "#FFFFFF26",
|
||||
"selection_core": "#FFFFFF",
|
||||
"selection_halo": "#000000D9"
|
||||
}
|
||||
}
|
||||
@@ -23,3 +23,4 @@ config/icon="res://icon.svg"
|
||||
|
||||
window/size/initial_position_type=0
|
||||
window/size/initial_position=Vector2i(4000, 200)
|
||||
window/size/initial_screen=1
|
||||
|
||||
@@ -20,29 +20,5 @@
|
||||
"grid_size": 15,
|
||||
"background_color": "#1F1F1F",
|
||||
"grid_color": "#FFFFFF26"
|
||||
},
|
||||
"ui": {
|
||||
"fonts": {
|
||||
"body": 18,
|
||||
"header": 24,
|
||||
"menu": 22,
|
||||
"menu_bar": 22,
|
||||
"mode": 26,
|
||||
"status": 18,
|
||||
"prop_name": 20,
|
||||
"context_menu": 22
|
||||
},
|
||||
"hit_targets": {
|
||||
"button_min_height": 36,
|
||||
"row_min_height": 36,
|
||||
"mode_button_min_height": 56
|
||||
},
|
||||
"colors": {
|
||||
"text": "#F2F2F2",
|
||||
"text_muted": "#9A9A9A",
|
||||
"border": "#FFFFFF33",
|
||||
"accent": "#4FA3FF",
|
||||
"inspector_background": "#262C39"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||