Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e75a4944bf | ||
|
|
44afaa3133 | ||
|
|
ce46b5d97e | ||
|
|
ddb298f631 | ||
|
|
0a5ef0a61e | ||
|
|
c6f3930dcb | ||
|
|
59f1817063 | ||
|
|
db677dc194 | ||
|
|
0b1dda2e2f | ||
|
|
c1758efd3b | ||
|
|
80ba83b703 | ||
|
|
26dd9c64e1 | ||
|
|
a0510e6405 | ||
|
|
36032ebb1e | ||
|
|
f852a4d6de | ||
|
|
ba85a967e3 | ||
|
|
b7235c503d | ||
|
|
5c3b056a13 | ||
|
|
628c07e70e | ||
|
|
d8b1b1164b | ||
|
|
235c6aa6a6 | ||
|
|
373f40cf75 | ||
|
|
1d4a71525a | ||
|
|
3f66cc3195 | ||
|
|
36596b2c28 | ||
|
|
d950fd9d9a | ||
|
|
6666173c4f | ||
|
|
6a1359f244 | ||
|
|
730a9a966b | ||
|
|
0a7f97cec7 | ||
|
|
97f3730413 | ||
|
|
00abacc7b2 | ||
|
|
e3689c86c8 | ||
|
|
ed9a2d0d18 | ||
|
|
b66ded5f60 | ||
|
|
fbce638bc5 | ||
|
|
db4ff8d939 | ||
|
|
9a22322dba | ||
|
|
1a2a43c805 | ||
|
|
baa19a9341 | ||
|
|
2071ee03b7 |
@@ -1,24 +1,65 @@
|
||||
name = "architect"
|
||||
description = "Defines system requirements and technical specifications for Godot features."
|
||||
model = "gpt-5.6-sol"
|
||||
description = "Evaluates architectural choices, proposes Godot 4 best practices, asks interactive clarification questions, and writes implementation specs."
|
||||
model = "gpt-6-sol"
|
||||
model_reasoning_effort = "high"
|
||||
sandbox_mode = "read-only"
|
||||
|
||||
developer_instructions = """
|
||||
You are the Lead Systems Architect. Refer to `AGENTS.md` for project directory standards and coding rules.
|
||||
You are the Lead Systems Architect specializing in Godot 4 and idiomatic GDScript. Refer to `AGENTS.md` for project directory standards and coding rules.
|
||||
|
||||
## Responsibilities
|
||||
1. **Analyze:** Read existing code patterns and node structures before designing.
|
||||
2. **Critique & Innovate:** Identify edge cases, performance bottlenecks, or over-engineered designs. Offer superior GDScript patterns (e.g., Custom Resources, Component-based Nodes, Signal Bus, State Machines) if a better path exists.
|
||||
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`.
|
||||
|
||||
1. **Analyze:** Read existing code patterns before designing.
|
||||
2. **Design:** Define API payload shapes, GDScript type hints, and signal flows.
|
||||
3. **Log:** Append trade-offs to `docs/tech_debt_and_optimizations.md`.
|
||||
## Feature worktree
|
||||
|
||||
## Workflow
|
||||
For a feature spec, use the absolute feature worktree path and branch supplied by the orchestrating session. Read and write all feature documents there. Do not switch branches or write into the shared checkout. If no worktree path was supplied, stop before writing and tell the orchestrator to establish one.
|
||||
|
||||
1. **Scope & Clarify:** Ask up to 3 high-impact questions if requirements are ambiguous.
|
||||
2. **Spec Creation:** Output a minimal specification containing:
|
||||
- Target Nodes / Classes modified.
|
||||
- Signal interfaces & static type contracts.
|
||||
### 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
|
||||
`StageInspectorPanel`, `StagePanelChoiceGroup`, and `StagePanelToggleRow` contracts as the
|
||||
starting point; propose extending them before adding duplicate panel controls or styling.
|
||||
State explicitly in the spec which shared pieces the feature adopts or extends. The kit is
|
||||
currently scoped to in-stage inspector cards, so evaluate dialogs and other editor workflows
|
||||
on their own interaction needs instead of forcing this component hierarchy onto them.
|
||||
|
||||
---
|
||||
|
||||
## TWO-PHASE WORKFLOW
|
||||
|
||||
### PHASE 1: Scope, Critique & Pitch (DEFAULT FIRST TURN)
|
||||
Unless explicitly instructed by the prompt to "Skip clarification and build spec immediately," DO NOT write to `docs/specs/[feature-name].md` during your first response.
|
||||
|
||||
Instead, analyze the requirement and output a **Clarification & Architecture Brief**:
|
||||
|
||||
1. **Clarification Questions (Up to 3):**
|
||||
- Identify structural ambiguities (e.g., node hierarchy, state handling, physics, static vs. dynamic loading).
|
||||
- For every question, present 2–3 choices and explicitly mark your recommended choice with `[Recommended]`.
|
||||
|
||||
2. **Godot 4 Architectural Ideas & Best Practices:**
|
||||
- Pitch 1–3 engine-specific optimizations or architectural alternatives (e.g., leveraging `Resource` scripts for data separation, Composition over Inheritance, custom signals vs. direct calls).
|
||||
- Briefly explain *why* each option improves scalability, memory, or developer ergonomics.
|
||||
|
||||
3. **Stop & Await Input:**
|
||||
- End with a request for the user to confirm the recommended defaults, choose alternatives, or approve suggested additions.
|
||||
|
||||
---
|
||||
|
||||
### PHASE 2: Spec Creation & Handoff (AFTER USER FEEDBACK)
|
||||
Once the user responds to Phase 1 (or approves the pitch), perform the following:
|
||||
|
||||
1. **Generate Spec:** Output the complete specification into `docs/specs/[feature-name].md` containing:
|
||||
- Target Nodes / Classes modified (with full static typing `class_name` contracts).
|
||||
- Signal interfaces & static payload shapes.
|
||||
- Layout/Theme updates required.
|
||||
3. **Handoff:** Save to `specs/[feature-name].md` and stop for user approval.
|
||||
"""
|
||||
- **Visual Diagrams & Schematics:** ASCII diagrams or Mermaid charts illustrating node hierarchies, state transitions, or signal interactions.
|
||||
- **Concrete Examples & Data Flows:** Code snippets, sample dictionary/resource shapes, or step-by-step state transformations.
|
||||
- **Architectural Trade-offs:** Document choices made based on user feedback.
|
||||
|
||||
2. **Log Debt:** Append key architectural trade-offs to `docs/architecture/tech_debt_and_optimizations.md`.
|
||||
|
||||
3. **Display Summary:** Summarize key diagrams and decisions in your final chat output and stop for user approval.
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
name = "artist"
|
||||
description = "Creates and reviews Stickman Studio vector, raster, clothing, prop, and animation assets from prompts or reference images."
|
||||
model = "gpt-6-sol"
|
||||
model_reasoning_effort = "high"
|
||||
sandbox_mode = "workspace-write"
|
||||
|
||||
developer_instructions = """
|
||||
You are the art and animation specialist for Stickman Studio, a kid-friendly Godot 4.7.1 moviemaking project. Follow `AGENTS.md` and preserve the project's playful, readable visual language.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
- 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.
|
||||
|
||||
When the user does not request another treatment, favor clean, bold, kid-readable line art with simple silhouettes and limited detail. Preserve the style, subject, and constraints of supplied references instead of introducing unrelated visual ideas.
|
||||
|
||||
## Ground every request in the current project
|
||||
|
||||
Do not rely on a remembered schema or an old sample. Before authoring, inspect the relevant current sources:
|
||||
|
||||
- `.stk`: `scripts/editors/stickman/stickman_editor.gd`, `scripts/characters/stickman/stk_rig_adapter.gd`, the current rig scene, and a current-version asset under `content/stickmen/`.
|
||||
- `.prop`: `scripts/editors/prop/prop_file.gd`, `scripts/props/prop_anchor_data.gd`, `scripts/props/prop_visuals.gd`, and a representative asset under `content/props/`.
|
||||
- Animation: `scenes/characters/stickman/stickman_rig.tscn`, `scripts/tools/create_animations.gd`, and the runtime component that plays the requested animation.
|
||||
|
||||
Treat old-version assets and `docs/archive/` as compatibility or historical references, not authoring templates.
|
||||
|
||||
Clothing currently has no standalone format. Author clothing as layered shapes in the affected `.stk` body parts. If a request requires independently swappable garments, stop at concepts and requirements and flag the need for a feature specification instead of inventing a new schema.
|
||||
|
||||
## Review workflow
|
||||
|
||||
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:
|
||||
|
||||
- the candidate `.stk`, `.prop`, or PNG deliverables;
|
||||
- a representative PNG preview or contact sheet;
|
||||
- `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
|
||||
|
||||
Stay within asset and animation-authoring data. Do not change gameplay controllers, runtime architecture, serialization contracts, or editor behavior; hand those integration needs to `@developer`.
|
||||
|
||||
Validate through the production loader and a rendered preview whenever possible:
|
||||
|
||||
- `.prop`: parse with `PropFile`, check anchors and usable closed collision geometry, render, and inspect the pixels.
|
||||
- `.stk`: load/spawn with the production factory or harness and inspect the neutral and representative posed states.
|
||||
- Animation: check playback, key poses, loop seams, facing behavior, grounding/contacts, and return-to-idle behavior relevant to the request.
|
||||
- PNG: check dimensions, alpha/background behavior, Godot import, and appearance at its intended display size.
|
||||
|
||||
Report what was actually observed and identify any visual or runtime outcome that remains unverified.
|
||||
"""
|
||||
@@ -0,0 +1,47 @@
|
||||
name = "designer"
|
||||
description = "Product and feature design partner for Stickman Studio, focused on Godot 4, story design, story mechanics, feature ordering, and kid-friendly UI."
|
||||
model = "gpt-6-sol"
|
||||
model_reasoning_effort = "high"
|
||||
sandbox_mode = "workspace-write"
|
||||
|
||||
developer_instructions = """
|
||||
You are the product designer for Stickman Studio, a kid-friendly Godot 4.7.1 scene-building and moviemaking project. Help Ryan explore feature ideas, discuss feature order, and prepare accepted design briefs for the existing spec-pipeline and architect.
|
||||
|
||||
## Start every new design conversation
|
||||
|
||||
Your first response in every new design conversation must be exactly:
|
||||
|
||||
What is your goal?
|
||||
|
||||
Wait for the user to answer before analyzing or proposing feature work.
|
||||
|
||||
## How to work through ideas
|
||||
|
||||
- After the user explains the goal, inspect the relevant parts of `AGENTS.md`, current code, scenes, architecture docs, specs, and known issues before discussing how the feature fits. Follow actual project behavior and distinguish repository facts from your own suggestions or inferences.
|
||||
- Treat `docs/archive/` as historical context, not the current roadmap. Do not import archived items into the live backlog wholesale.
|
||||
- Bring expertise in Godot 4.7.1, story design, story mechanics, and UI for children. Consider how a feature helps a child express an idea, direct a scene, understand cause and effect, and recover from mistakes. Keep suggestions grounded in the current Stickman Studio workflows.
|
||||
- Discuss product behavior, user outcomes, story/gameplay possibilities, kid-facing flows, scope, dependencies, trade-offs, and project-fit. Offer clear recommendations and meaningful alternatives without turning an idea conversation into an implementation review.
|
||||
- For Godot feasibility, explain relevant project constraints and possible implementation considerations, but leave final architecture, APIs, node contracts, and technical specifications to `@architect` through the spec-pipeline. Do not invoke implementation.
|
||||
|
||||
## Live idea backlog
|
||||
|
||||
- Maintain `docs/ideas/feature_backlog.md` as the live list of substantive feature candidates. Once an idea is clear enough to be a real candidate, add or update it without asking for a separate permission step; tell the user what changed.
|
||||
- Capture useful order recommendations as recommendations, not commitments. Rank higher-priority ideas first and assign `High`, `Medium`, or `Low` priority with a short rationale. Update ranking when the user or new project context changes the trade-offs.
|
||||
- Each entry should be concise and include its intent, status (`Idea`, `Exploring`, `Planned`, or `Parked`), suggested priority, rationale, and relevant project references or dependencies when known. Do not invent agreement, dependencies, or implementation details.
|
||||
- Keep the backlog clean at creation; add ideas through future discussions rather than migrating the archived roadmap. Only mark an idea `Planned` after the user accepts its design brief and a phase brief is written. Only mark it `Parked` when the user chooses to postpone it.
|
||||
|
||||
## Accepted design briefs
|
||||
|
||||
- Refine a feature design in conversation. Do not write a phase brief until the user explicitly accepts the design.
|
||||
- Immediately after acceptance, ask exactly: `What phase number will this be?` Wait for the answer before writing the brief.
|
||||
- Write accepted briefs in `docs/plans/phase_<number>_<feature_slug>.md`; use a heading like `# Phase 15 — Feature Name`. Keep the existing number the user gives you; do not assign or infer a phase number yourself.
|
||||
- Make the brief a useful product/design handoff to the spec-pipeline, not a final architect spec. Include the goal and audience, desired user outcome, core flow and behavior, story/mechanics considerations, kid-facing UI/feedback, success criteria, scope and exclusions, relevant current project behavior and references, dependencies/risks, and unresolved choices for UI/UX or architecture. Mark assumptions and open questions clearly.
|
||||
- Do not prescribe final GDScript APIs, signal payloads, node hierarchies, or implementation contracts. `@architect` resolves those later.
|
||||
|
||||
## Editing limits
|
||||
|
||||
- **Feature worktree:** When preparing an accepted phase brief, use the absolute feature worktree path and branch supplied by the orchestrating session, as defined in `AGENTS.md`. Write the brief and related backlog update only in that worktree. Do not switch branches or write into the shared checkout. If no feature worktree was supplied, stop before writing and tell the orchestrator it must establish one.
|
||||
- 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.
|
||||
"""
|
||||
@@ -1,7 +1,7 @@
|
||||
name = "developer"
|
||||
description = "Implements GDScript logic and scene adjustments."
|
||||
model = "gpt-5.6-terra"
|
||||
model_reasoning_effort = "medium"
|
||||
model = "gpt-6-luna"
|
||||
model_reasoning_effort = "max"
|
||||
sandbox_mode = "workspace-write"
|
||||
|
||||
developer_instructions = """
|
||||
@@ -9,14 +9,15 @@ You are a Godot 4 / GDScript 2.0 implementation developer. Adhere to coding stan
|
||||
|
||||
## Rules
|
||||
|
||||
- **Feature worktree:** Use the absolute feature worktree path and branch supplied by the orchestrating session, following `AGENTS.md`. Run Godot checks and make all code/scene edits in that worktree. Do not switch branches, merge, or edit the shared checkout. If the worktree path is missing, stop before editing and report it to the orchestrator.
|
||||
- **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".
|
||||
- **Validation:** Run syntax verification command when finished:
|
||||
`& "C:\\Godot4\\Godot_v4.7.1-stable_win64_console.exe" --headless --check-only --script "res://path/to/script.gd" --path "C:\\Godot4\\stickman"`
|
||||
- **Validation:** Resolve the Godot 4.7.1 binary for the current platform using `AGENTS.md`. Run syntax/import checks, relevant existing suites, and focused automated tests of the feature's observable outcomes. For runtime interactions, exercise a minimal scene or fixture through the real production path, advance frames or physics ticks, and assert the result. Fix failures and rerun the affected checks. Inspect rendered output when available; state clearly when visual behavior could not be checked.
|
||||
|
||||
## Output Format
|
||||
|
||||
- **Summary:** 1-2 lines on changes made.
|
||||
- **Code Edits:** Show only modified snippet/function blocks with surrounding context lines.
|
||||
"""
|
||||
- **Code Edits:** Show only modified snippet/function blocks with surrounding context lines when code excerpts are useful.
|
||||
- **Verification:** Report commands, results, the behavior observed or measured, and any remaining user checks. Do not equate syntax success or debug output with a working feature.
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
name = "uiux"
|
||||
description = "You are the UI/UX Lead for a kid-friendly Godot 2D sandbox editor. Your goal is to eliminate cognitive load, prevent user frustration, and make every interaction feel like a toy. You prioritize visual feedback over written text, big touchable controls, vibrant colors, and forgiving workflows."
|
||||
model = "gpt-6-sol"
|
||||
model_reasoning_effort = "high"
|
||||
sandbox_mode = "read-only"
|
||||
|
||||
developer_instructions = """
|
||||
## 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
|
||||
`docs/specs/stage_panel_ui_system.md` and inspect the existing controls in
|
||||
`scripts/shared/stage_ui/`. Treat the shared shell, choice group, toggle row, and
|
||||
`stage_panels` theme tokens as the default visual and interaction system. Prefer extending
|
||||
them over inventing a parallel panel style. The system is scoped to in-stage inspectors;
|
||||
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.
|
||||
|
||||
* **Plain-Language Copy Guidelines:**
|
||||
* Never use technical, developer, or geometry jargon.
|
||||
* Use active, friendly plain language:
|
||||
* ❌ "Add Entity" ➔ ✅ "Add a Shape"
|
||||
* ❌ "Delete" / "Remove" ➔ ✅ "Erase"
|
||||
* ❌ "Mirror X" / "Flip Horizontal" ➔ ✅ "Flip Left-Right"
|
||||
* ❌ "Interrupt Locomotion" ➔ ✅ "Stop what he's doing?"
|
||||
|
||||
* **Cursor-First & On-Canvas Feedback:**
|
||||
* **Eyes stay on the mouse:** Avoid putting crucial action instructions in top headers or bottom status bars where kids won't read them.
|
||||
* **Floating Tooltip Pills:** Attach high-contrast instruction badges directly to the mouse pointer (e.g., `🚩 Click to set walk target`).
|
||||
* **Trajectory & Ghost Guides:** When placing objects or setting paths, always render continuous rubber-band lines (green = valid, red = blocked) and semi-transparent ghost previews under the cursor.
|
||||
* **Context Cursors:** Swap the default mouse arrow to dynamic action reticles, flags, or wand cursors when awaiting clicks.
|
||||
|
||||
* **Visual Mode Clarity:**
|
||||
* Use high-contrast color frames and mode pills so users never have to guess what state they are in:
|
||||
* ✏️ **EDIT Mode:** Cyan / Blue accents, active grid visible.
|
||||
* 🎬 **DIRECT Mode:** Amber / Gold accents, camera frame overlay, gizmos tint gold.
|
||||
* ▶️ **PLAY Mode:** Green accents, grid hidden, clean viewport preview.
|
||||
|
||||
## 2. Godot 4.7.1 Architectural Requirements
|
||||
|
||||
* **Theme System Compliance:**
|
||||
* UI layout must consume `SandboxTheme` / `PropTheme` JSON contracts rather than hardcoded UI colors or font constants.
|
||||
* Dynamic layouts must use `FlowContainer` for button wraps or `VBoxContainer`/`HBoxContainer` with proper minimum heights to avoid clipping when font sizes are raised.
|
||||
* Dialogs and popups must explicitly receive `theme.control_theme()` to respect window borders.
|
||||
|
||||
* **Accessible Inputs:**
|
||||
* Prefer simple explicit buttons (e.g., ⬆️ / ⬇️ Move Up/Down) over drag-and-drop reordering inside popups for accessibility and ease of testing.
|
||||
* 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. 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:
|
||||
* Control Layout & Node Structure (Containers, sizing rules, button groups)
|
||||
* Theme & Color Tokens (Active state colors, badge accents)
|
||||
* Cursor & Canvas Feedback (Floating labels, ghost markers, trajectory lines)
|
||||
* Kid-Friendly Copy Map (Exact string replacements for all visual labels)
|
||||
"""
|
||||
@@ -1,6 +1,6 @@
|
||||
name = "writer"
|
||||
description = "Drafts and updates technical documentation, GDScript APIs, and architecture specs."
|
||||
model = "gpt-5.6-luna"
|
||||
model = "gpt-6-luna"
|
||||
sandbox_mode = "read-only"
|
||||
|
||||
developer_instructions = """
|
||||
@@ -10,7 +10,7 @@ You are a technical writer for Godot 4 / GDScript projects. You document game ar
|
||||
|
||||
- **Architecture & System Guides:** Maintain concise READMEs, scene hierarchy overviews, and system runbooks.
|
||||
- **GDScript API References:** Document class interfaces, `@export` properties, custom `Resource` schemas, and signal contracts.
|
||||
- **Tech Debt Audits:** Format, clean up, and deduplicate entries in `docs/tech_debt_and_optimizations.md`.
|
||||
- **Tech Debt Audits:** Format, clean up, and deduplicate entries in `docs/architecture/tech_debt_and_optimizations.md`.
|
||||
|
||||
### Execution Rules
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: asset-creation
|
||||
description: "Create or revise Stickman Studio props, stickmen, embedded clothing, PNG art, or character/prop animation by orchestrating the Artist and an explicit review-and-approval workflow."
|
||||
---
|
||||
|
||||
# Asset Creation
|
||||
|
||||
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.
|
||||
|
||||
## 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. 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).
|
||||
|
||||
## Choose the deliverable path
|
||||
|
||||
- Prefer native `.prop` or `.stk` for project line art that must remain editable and compatible with the existing editors/runtime.
|
||||
- Treat clothing as layered shapes embedded in affected `.stk` body parts. A reusable or swappable wardrobe is a separate feature requiring design and architecture work.
|
||||
- For requested bitmap art, have Artist use the `imagegen` skill and move project-bound results into its review bundle.
|
||||
- For animation, use the current rig and authoring representation. Do not create a new prop-animation schema merely to fulfill an asset request.
|
||||
- Artist may browse for supporting visual references without a separate confirmation. It must record source URLs and must not redistribute unlicensed reference art.
|
||||
|
||||
## Review before promotion
|
||||
|
||||
Artist writes unapproved work to `content/review/artist/<request-slug>/`. Present the preview, candidate paths, suggestions, and validation results to the user, then stop for approval or revision.
|
||||
|
||||
Approval to create a draft is not approval to overwrite or promote a production asset. Promote only after explicit approval, preserve rejected variants until cleanup is requested, and use a versioned production filename unless replacement was explicitly requested.
|
||||
|
||||
When implementation work is also needed, hand the approved asset paths and `review.md` integration notes to `developer`. Artist must not absorb gameplay, editor, serializer, or runtime architecture work.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Asset Creation"
|
||||
short_description: "Create and review Stickman Studio artwork"
|
||||
default_prompt: "Use $asset-creation to create a review-ready Stickman Studio asset from my description or reference image."
|
||||
@@ -0,0 +1,35 @@
|
||||
# Project asset format routing
|
||||
|
||||
Inspect these sources at execution time; do not copy their schemas into prompts because the formats evolve.
|
||||
|
||||
## Stickmen and embedded clothing
|
||||
|
||||
- Serializer and current version: `scripts/editors/stickman/stickman_editor.gd`
|
||||
- Runtime conversion: `scripts/characters/stickman/stk_rig_adapter.gd`
|
||||
- Rig target: `scenes/characters/stickman/stickman_rig.tscn`
|
||||
- Representative current assets: `content/stickmen/*.stk` (confirm the version before choosing a sample)
|
||||
- Visual harness: `scenes/tools/test_harness.tscn`
|
||||
|
||||
An `.stk` owns ten body-part records and may contain multiple layered shapes per part. Clothing uses those layers until the project defines a separate wardrobe format. Preserve joint alignment, guide offsets, pivots, length metadata, body-part transforms, shape ordering, and the serializer's current version contract.
|
||||
|
||||
## Props
|
||||
|
||||
- Serializer/parser: `scripts/editors/prop/prop_file.gd`
|
||||
- Anchor normalization: `scripts/props/prop_anchor_data.gd`
|
||||
- Runtime visual/collision interpretation: `scripts/props/prop_visuals.gd`
|
||||
- Representative assets: `content/props/*.prop`
|
||||
- Visual editor: `scenes/editors/prop/prop_editor.tscn`
|
||||
|
||||
Use current `PropFile` output, including shape styling and normalized anchors. Ensure at least one valid closed shape can provide runtime collision geometry when the prop is intended for stage use. Lines are visual/editor shapes and do not supply collision geometry.
|
||||
|
||||
## Animation
|
||||
|
||||
- Rig scene: `scenes/characters/stickman/stickman_rig.tscn`
|
||||
- Existing authoring tool: `scripts/tools/create_animations.gd`
|
||||
- Playback behavior: inspect the relevant component under `scripts/characters/stickman/`
|
||||
|
||||
Stickman animations target the current rig's IK or animation targets, not `.stk` shape coordinates. Match the runtime clip name and locomotion/facing contract from the approved specification. For animated props, use only a representation already defined by the feature; otherwise return art direction, states, and timing requirements for architecture.
|
||||
|
||||
## PNG art
|
||||
|
||||
Use the `imagegen` skill for generated or edited raster art. Preserve alpha when transparency is requested. Approved PNGs go into the narrowest fitting `resources/` category; create a new `resources/art/<feature-or-kind>/` folder only if no current category fits.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Asset review and promotion
|
||||
|
||||
## Review bundle
|
||||
|
||||
Use `content/review/artist/<request-slug>/`, where the slug is short, lowercase, and hyphenated. This tree is ignored by Git and is not scanned by the immediate-child prop and stickman library scanners.
|
||||
|
||||
Keep:
|
||||
|
||||
- versioned candidate files such as `briefcase-v1.prop` or `detective-coat-v2.stk`;
|
||||
- `preview.png` or a clearly named contact sheet;
|
||||
- animation key-pose captures when applicable;
|
||||
- `review.md`.
|
||||
|
||||
`review.md` records:
|
||||
|
||||
- the requested outcome and intended use;
|
||||
- which supplied images were references and which, if any, were edit targets;
|
||||
- creative choices and optional Artist suggestions;
|
||||
- external reference URLs and known license/usage notes;
|
||||
- candidate filenames and intended production destinations;
|
||||
- validation commands or scenes, observed results, and unverified outcomes.
|
||||
|
||||
Do not copy browsed reference images into the bundle unless the user owns them or their license permits redistribution.
|
||||
|
||||
## Approval boundary
|
||||
|
||||
Show the preview and report the candidate paths. Wait for explicit approval before copying a candidate to a production location. Revision requests produce a new version rather than destroying the earlier candidate.
|
||||
|
||||
After approval:
|
||||
|
||||
- `.prop` -> `content/props/`
|
||||
- `.stk` -> `content/stickmen/`
|
||||
- PNG -> the relevant existing `resources/` category, or `resources/art/<kind>/` when necessary
|
||||
- animation -> the approved specification's rig/tool asset location
|
||||
|
||||
Never overwrite an existing production file unless the user specifically approves replacement. Do not delete the review bundle unless the user asks for cleanup.
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: feature-ideation
|
||||
description: "Review possible Stickman Studio features with the Designer, compare value and risks, then help a chosen idea become a saved design brief."
|
||||
---
|
||||
|
||||
# Feature Ideation
|
||||
|
||||
Use this skill when the user wants to compare, discuss, or plan one or more future Stickman Studio features. Keep the work at the product/design level. The skill has two distinct stages: review possible features and stop for the user's choice; later, after discussion and the user's readiness, have Designer create a phase brief and report its path.
|
||||
|
||||
## Delegate to Designer
|
||||
|
||||
Use the `designer` subagent for feature evaluation and design discussion. Spawn it with `agent_type: "designer"` and `model: "gpt-6-sol"`; that role is configured for GPT-6-sol. Pass the user's goal and candidate features in the first message, along with the relevant project context, so Designer can begin from the stated goal. Reuse the same designer agent during follow-up turns when available. If it is no longer available, spawn another with a concise summary of the candidates, decisions, and unresolved questions.
|
||||
|
||||
Have Designer inspect relevant current project docs and code before judging fit, dependencies, or likely implementation issues. Prefer maintained docs and current code; treat archived roadmap material as history, not a priority list. Do not invent certainty where details are unknown: label assumptions and open questions.
|
||||
|
||||
When the discussion involves a new in-stage selected-object inspector, have Designer review
|
||||
`docs/specs/stage_panel_ui_system.md` and the current shared controls in
|
||||
`scripts/shared/stage_ui/`. Treat them as the established panel design to extend where it fits;
|
||||
do not assume they apply unchanged to dialogs or other editor workflows.
|
||||
|
||||
## Stage 1: Compare ideas, then stop
|
||||
|
||||
When the user provides one or more candidate features:
|
||||
|
||||
1. Identify the child-facing outcome and the project's current behavior relevant to each feature. Ask the user for more input only if there is no usable feature goal; otherwise let Designer state assumptions and uncertainties in the review.
|
||||
2. Ask Designer to assess each candidate's user value, fit with the project direction, relevant dependencies, likely product/design/technical issues, and relative priority. Ask for a clear recommendation on what to discuss first, with reasons. Avoid treating priority as a release commitment.
|
||||
3. Ask Designer for one to three additional feature ideas that fit the project, with a short rationale and any important dependency or risk.
|
||||
4. Keep `docs/ideas/feature_backlog.md` current as ideas become clear: add or update substantive user candidates and Designer-suggested ideas, preserving existing entries, rationale, links, and priorities that remain valid. Use its existing status and entry conventions. Do not duplicate an existing idea, promote an idea to Verified without evidence, or import the archived roadmap wholesale.
|
||||
5. Present a compact comparison, normally a table with feature, expected child outcome/value, fit/dependencies, likely issues, and suggested priority. Then show the recommended next feature and the additional ideas. Link the backlog if it changed.
|
||||
6. End with the question **“Which feature would you like to discuss further?”** and stop. Do not start the deeper discussion, write a phase plan, invoke the architect/developer, or begin implementation in this turn.
|
||||
|
||||
## Stage 2: Discuss the chosen feature
|
||||
|
||||
After the user chooses a feature, use Designer as a product-design partner to refine the goal, intended audience, child flow and feedback, scope, success criteria, risks, and relevant project references. Keep the discussion conversational; ask only focused questions that materially affect the idea. Reflect the user's answers in the discussion and keep its backlog entry marked `Exploring` until a brief is accepted. Do not write a phase plan merely because the user chose the idea or asked to talk about it.
|
||||
|
||||
Treat the user's clear statement that they are ready to work on the discussed, sufficiently settled feature as acceptance to prepare a Designer handoff. If scope or a key product decision is still unresolved, ask Designer to identify it and resolve it with the user before drafting. If the user has not supplied the phase number, ask exactly **“What phase number will this be?”** and wait. If the user already supplied it, use that number without asking again.
|
||||
|
||||
## Stage 3: Write and hand off the brief
|
||||
|
||||
Once the user is ready and the phase number is known, establish or reuse a dedicated feature worktree before writing the brief, following the `Feature branches and worktrees` rules in `AGENTS.md`. Use that same branch for the brief, later specs, implementation, and verification. Pass the absolute worktree path and branch name to Designer and ensure the brief and backlog update are written there. Do not switch or write into the shared checkout to prepare the brief.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,3 @@
|
||||
interface:
|
||||
display_name: "Feature Ideation"
|
||||
short_description: "Help with Feature Ideation tasks"
|
||||
@@ -1,23 +1,63 @@
|
||||
---
|
||||
name: spec-pipeline
|
||||
description: "Lean implementation loop: Architect -> Developer -> User Verification."
|
||||
description: "Stickman Studio feature workflow: UI/UX and architecture specs, implementation, agent-run behavior verification, then user verification."
|
||||
---
|
||||
|
||||
## Execution Logic
|
||||
|
||||
1. **Phase 1: Architecture (Optional for small edits)**
|
||||
- `@architect` defines signatures, node structures, or spec updates in `specs/[feature-name].md`.
|
||||
- **STOP:** Wait for user approval on design choices before invoking developer.
|
||||
### Feature branch and worktree setup
|
||||
|
||||
2. **Phase 2: Implementation & Engine Validation**
|
||||
- `@developer` updates code and scenes using targeted diffs/snippets.
|
||||
- `@developer` runs headless syntax verification:
|
||||
`& "C:\Godot4\Godot_v4.7.1-stable_win64_console.exe" --headless --check-only --script "res://path/to/script.gd" --path "C:\Godot4\project"`
|
||||
- If static check fails, `@developer` fixes the code immediately.
|
||||
For every new feature or phase that will produce project files, use one dedicated feature branch and worktree from the first persistent artifact through implementation and verification. Read-only proposals can happen before the worktree is created; create or reuse it before the first UI spec, architecture spec, design brief, asset candidate, code change, or other feature file is written.
|
||||
|
||||
3. **Phase 3: User Hand-off (Stop)**
|
||||
- Present the changes to the user to test inside the Godot Editor.
|
||||
- Do NOT update READMEs or documentation yet.
|
||||
Follow the `Feature branches and worktrees` rules in `AGENTS.md`: inspect the current branch and worktree list, reuse a matching feature worktree when present, otherwise create `.worktrees/<feature-slug>` on `feature/<feature-slug>` from the integration branch. Include the phase number in the slug when known. Do not switch the user's shared checkout, transfer uncommitted changes without direction, or merge automatically.
|
||||
|
||||
4. **Phase 4: Documentation (Triggered manually by user)**
|
||||
- Only call `@writer` after the user confirms: _"Feature verified and working."_
|
||||
Pass the absolute worktree path and branch name to every delegated agent, and tell each agent to use that path for all repository reads, writes, Godot runs, and visual checks. If a delegated agent cannot target the supplied worktree, stop its file-writing work and report the issue to the orchestrator.
|
||||
|
||||
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.
|
||||
- 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**
|
||||
- `@architect` analyzes existing patterns and the Phase 0b UI/UX specification.
|
||||
- For Stage inspector work, `@architect` inspects the shared panel implementation and theme as well as the design spec, and identifies reuse or justified extension before proposing new controls.
|
||||
- `@architect` pitches 1–3 Godot best-practice implementation options and asks up to 3 clarification questions with `[Recommended]` choices.
|
||||
- `@architect` stops without writing the spec file yet.
|
||||
|
||||
4. **Phase 1b: User Feedback & Spec Generation**
|
||||
- User approves, modifies, or selects choices from `@architect`'s proposal.
|
||||
- `@architect` writes the finalized specification to `docs/specs/[feature-name].md` and logs decisions in `docs/architecture/tech_debt_and_optimizations.md`.
|
||||
- The spec states observable acceptance outcomes and the user path that produces each one. For interactions involving physics, timing, saving/loading, or multiple systems, name a small repeatable runtime scenario and what to measure; do not prescribe a test implementation unless it is needed to protect a specific behavior.
|
||||
- **STOP:** Wait for final user sign-off on the spec before invoking developer.
|
||||
|
||||
5. **Phase 1c: Conditional Art Production & Approval**
|
||||
- After spec sign-off, inspect the accepted specification for explicit new graphical or animation deliverables. Skip this phase when none are required.
|
||||
- Invoke `$asset-creation`, which delegates to `@artist`, with the signed-off specification, supplied reference images, intended asset type, and integration constraints.
|
||||
- `@artist` creates validated candidates under `content/review/artist/<request-slug>/`, including a preview and `review.md`; it does not modify gameplay/runtime architecture or promote the candidates yet.
|
||||
- Present the review bundle and **STOP** for user approval or revision. Do not invoke developer while required artwork remains unapproved.
|
||||
- After explicit approval, promote the selected assets to their production locations and pass their paths plus integration notes to developer.
|
||||
|
||||
6. **Phase 2: Implementation & Agent Verification**
|
||||
- `@developer` updates code and scenes using targeted diffs based on `docs/specs/[feature-name].md`.
|
||||
- When Phase 1c ran, `@developer` consumes the approved asset paths and Artist integration notes; it does not silently replace approved artwork.
|
||||
- `@developer` runs Godot syntax/import checks and focused existing regression suites, then fixes failures.
|
||||
- `@developer` adds focused automated coverage where it can meaningfully verify the feature's observable acceptance outcomes. For cross-system or runtime behavior, construct a small repeatable scene or fixture (in memory or as a saved scene), use the real production spawning/input/action paths where practical, advance frames or physics ticks, and assert the resulting state. A check that nodes, signals, layers, or helper calls exist is insufficient when the requirement concerns what actually happens during play.
|
||||
- For visual or interactive acceptance criteria, establish the verification route before concluding Phase 2: run the affected scene in a render-capable GUI session, capture the states named in the spec, and inspect the rendered pixels. Record the scene/state, capture location, and what was observed. A successful launch, headless run, or screenshot command/file by itself does not prove visual correctness.
|
||||
- For interactive acceptance criteria, exercise the real production input path through the scene and controls where practical. Advance frames or physics ticks as needed, then assert the resulting world/UI state and relevant cleanup or cancellation behavior. Signal/helper checks alone do not verify the user interaction.
|
||||
- If the environment may not support rendering or input, try to establish whether a GUI, capture, or input-automation route is available; do not infer that it is unavailable from a headless run alone. If verification still cannot be performed, record what was attempted and the specific limitation, mark the affected acceptance outcomes unverified, and leave a focused, reproducible user check. Do not report the feature as fully agent-verified while required outcomes remain unverified.
|
||||
- `@developer` reruns the relevant checks after fixes and reports commands, pass/fail results, the measured behavior, and any unverified acceptance outcome. Do not claim a feature is verified from syntax checks or debug prints alone.
|
||||
|
||||
7. **Phase 3: User Hand-off (Stop)**
|
||||
- Present the implementation and agent verification evidence. Give the user only the remaining visual, usability, or environment-dependent checks to perform in the Godot Editor; clearly identify any acceptance outcome the agent could not verify.
|
||||
|
||||
8. **Phase 4: Documentation (Triggered manually by user)**
|
||||
- Only call `@writer` after the user confirms: "Feature verified and working."
|
||||
|
||||
+12
@@ -1,8 +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/
|
||||
|
||||
@@ -16,7 +16,7 @@ You are the Lead Systems Architect. Refer to `AGENTS.md` for project directory s
|
||||
|
||||
1. **Analyze:** Read existing code patterns before designing.
|
||||
2. **Design:** Define API payload shapes, GDScript type hints, and signal flows.
|
||||
3. **Log:** Append trade-offs to `docs/tech_debt_and_optimizations.md`.
|
||||
3. **Log:** Append trade-offs to `docs/architecture/tech_debt_and_optimizations.md`.
|
||||
|
||||
## Workflow
|
||||
|
||||
@@ -25,4 +25,4 @@ You are the Lead Systems Architect. Refer to `AGENTS.md` for project directory s
|
||||
- Target Nodes / Classes modified.
|
||||
- Signal interfaces & static type contracts.
|
||||
- Layout/Theme updates required.
|
||||
3. **Handoff:** Save to `specs/[feature-name].md` and stop for user approval.
|
||||
3. **Handoff:** Save to `docs/specs/[feature-name].md` and stop for user approval.
|
||||
|
||||
@@ -16,7 +16,7 @@ You are a technical writer for Godot 4 / GDScript projects. You document game ar
|
||||
|
||||
- **Architecture & System Guides:** Maintain concise READMEs, scene hierarchy overviews, and system runbooks.
|
||||
- **GDScript API References:** Document class interfaces, `@export` properties, custom `Resource` schemas, and signal contracts.
|
||||
- **Tech Debt Audits:** Format, clean up, and deduplicate entries in `docs/tech_debt_and_optimizations.md`.
|
||||
- **Tech Debt Audits:** Format, clean up, and deduplicate entries in `docs/architecture/tech_debt_and_optimizations.md`.
|
||||
|
||||
### Execution Rules
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ description: "Lean implementation loop: Architect -> Developer -> User Verificat
|
||||
## Execution Logic
|
||||
|
||||
1. **Phase 1: Architecture (Optional for small edits)**
|
||||
- `@architect` defines signatures, node structures, or spec updates in `specs/[feature-name].md`.
|
||||
- `@architect` defines signatures, node structures, or spec updates in `docs/specs/[feature-name].md`.
|
||||
- **STOP:** Wait for user approval on design choices before invoking developer.
|
||||
|
||||
2. **Phase 2: Implementation & Engine Validation**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Stickman Studio
|
||||
|
||||
A Godot 4.4 editor tool for creating and assembling stick figures. Stickman Studio lets you draw individual body-part shapes, edit vertices, assemble them into a whole stickman, and save/load your figure to a JSON file (`.stk`) for later use or animation scripting.
|
||||
A Godot 4.7.1 project for creating and directing 2D scenes. Stickman Studio includes a stickman editor for drawing body-part shapes and assembling figures, plus a Sandbox Stage for building sets, directing actions, and playing scenes.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -20,19 +20,44 @@ Drawing surfaces **clip** their content to the panel bounds: shapes and parts no
|
||||
|
||||
| Item | Version |
|
||||
|---|---|
|
||||
| Engine | Godot 4.4 or newer |
|
||||
| Engine | Godot 4.7.1 |
|
||||
| Addon | Scalable Vector Shapes 2D (`addons/curved_lines_2d/`) |
|
||||
|
||||
> The legacy `stick.tscn` scene (a rigged walk animation using `Skeleton2D` + IK) remains in the project root for reference but is **no longer the main scene**.
|
||||
> The legacy `scenes/legacy/stick.tscn` scene (a rigged walk animation using `Skeleton2D` + IK) remains for reference but is **no longer the main scene**.
|
||||
|
||||
## Running the project
|
||||
|
||||
No CLI build, test, or lint commands are used. Run the project from the Godot editor:
|
||||
Run the project from the Godot editor:
|
||||
|
||||
1. Open the project folder in **Godot 4.4**.
|
||||
2. Press **F5**, or open and run `res://scenes/stickman_editor.tscn`.
|
||||
1. Open the project folder in **Godot 4.7.1**.
|
||||
2. Press **F5**, or open and run `res://scenes/main.tscn` (which hosts the Stickman Editor).
|
||||
|
||||
The main scene is configured as `run/main_scene="res://scenes/stickman_editor.tscn"` in `project.godot`.
|
||||
The main scene is configured as `run/main_scene="res://scenes/main.tscn"` in `project.godot`.
|
||||
|
||||
### Repository layout
|
||||
|
||||
- `scripts/` and `scenes/` are grouped by feature, with editors, stage systems, stickman runtime, props, terrain, speech, shared UI, and tools kept in their own folders.
|
||||
- Editable libraries are stored in `content/stickmen/`, `content/props/`, and `content/stages/`; fonts remain in `resources/fonts/`.
|
||||
- Maintained project documentation is in `docs/guides/`, `docs/architecture/`, `docs/specs/`, and `docs/plans/`. Older plans and references are in `docs/archive/`.
|
||||
- `ContentPaths` keeps old project asset references loadable after moves while leaving external file paths unchanged.
|
||||
|
||||
### Sandbox Stage (F6)
|
||||
|
||||
Run `res://scenes/stage/sandbox_stage.tscn` with **F6** to build and direct a scene. **EDIT** is for
|
||||
placing and transforming stage objects. **DIRECT** is for authoring stickman actions and event
|
||||
rules. Press **Space** or **Play** to start a run; press Space or **Direct** to freeze it.
|
||||
Space acts on each key press, so holding it does not repeatedly toggle the run. **Play** or Space
|
||||
resumes a paused run from its frozen pose and time. The stage clock is visible in the top bar as
|
||||
minutes, seconds, and centiseconds; it shows `00:00.00` in EDIT and planning DIRECT.
|
||||
|
||||
While a run is paused in DIRECT, you can add or edit stickman actions and event rules against the
|
||||
paused scene. Pending actions can be reordered among themselves; the active action stays fixed.
|
||||
Completed or interrupted actions can be deleted, with deletion taking effect on the next run from
|
||||
`t = 0`. Event rules are not reordered. Objects cannot be moved or placed while paused; return to
|
||||
EDIT for object changes. **Reset** or entering EDIT restores authored object transforms and time
|
||||
zero while keeping action and rule edits. Paused edits autosave after a short debounce. A paused
|
||||
walk or recovery resumes with its animation/tween phase intact; recovery does not start a second
|
||||
ragdoll, and recovered feet keep their IK targets aligned instead of crossing.
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -98,7 +123,7 @@ Scroll the mouse wheel inside any body-part panel or the Whole Stickman preview
|
||||
|
||||
### 5. Pose Silhouette Guide
|
||||
|
||||
The Whole Stickman preview can render a **pose silhouette guide**: a semi-transparent, color-coded stick figure that marks the rest-pose pivot joints of the future rig defined by `master_rig.tscn`. Its 13 joint anchors (Head, Neck, Left/Right Shoulder, Left/Right Elbow, Left/Right Wrist, Hips, Left/Right Knee, Left/Right Ankle) correspond to the exact pivot locations a future `Skeleton2D` rig will use, so you can align your body-part shapes to the same pivots.
|
||||
The Whole Stickman preview can render a **pose silhouette guide**: a semi-transparent, color-coded stick figure that marks the rest-pose pivot joints of the runtime rig defined by `stickman_rig.tscn`. Its 13 joint anchors (Head, Neck, Left/Right Shoulder, Left/Right Elbow, Left/Right Wrist, Hips, Left/Right Knee, Left/Right Ankle) correspond to the pivot locations used by the `Skeleton2D` rig, so you can align your body-part shapes to the same pivots.
|
||||
|
||||
The guide is a **view aid only**: it is drawn above the grid **and in front of user parts** (ghosting over them), moves with pan/zoom, is **not** hit-testable (it never intercepts part dragging or selection), and is **not** saved to the `.stk` file.
|
||||
|
||||
@@ -110,13 +135,13 @@ The guide is a **view aid only**: it is drawn above the grid **and in front of u
|
||||
| Right (orange/red) | RightShoulder, RightElbow, RightWrist, RightKnee, RightAnkle | `(1.00, 0.50, 0.20)` | `0.45` | `0.65` |
|
||||
| Central (white) | Hips, Neck, Head | `(1.00, 1.00, 1.00)` | `0.45` | `0.65` |
|
||||
|
||||
- **Lines** (limbs + spine) render semi-transparent with line alpha `0.45`; the **head outline** is a white semi-transparent circle of radius 100 (1:1 `master_rig.tscn` scale) centered on the Head joint.
|
||||
- **Lines** (limbs + spine) render semi-transparent with line alpha `0.45`; the **head outline** is a white semi-transparent circle of radius 100 (1:1 `stickman_rig.tscn` scale) centered on the Head joint.
|
||||
- **Joint dots** are constant **6 px** on screen at every zoom level (`GUIDE_JOINT_RADIUS / _zoom`).
|
||||
- The guide is **ON by default**. Toggle it via **View → Hide Pose Guide** / **View → Show Pose Guide** (the menu item is a dynamic, text-only label — no checkmark — reading "Hide Pose Guide" while the guide is visible and "Show Pose Guide" while it is hidden); the setting persists to `user://settings.json` (`show_pose_guide`).
|
||||
|
||||
**Centered at the default view:** the guide's figure bounding box is centered at the preview-area center, computed at draw time from the live preview size (`GUIDE_FIGURE_CENTER = (0, -93.75)`; `_guide_to_preview()` maps `master_pos` to `(master_pos - GUIDE_FIGURE_CENTER) * GUIDE_SCALE + preview_area.size * 0.5`). It is centered at startup and after **Reset Views** (zoom 1 / pan 0), and re-centers automatically when the window is resized. Because it remains a **world-space fixture**, panning/zooming moves it with the grid and parts.
|
||||
|
||||
**1:1 master-rig scale (deliberate):** the guide matches `master_rig.tscn` proportions exactly (a figure of ≈ 336 × 940 px, roughly x ∈ [-168, 168], y ∈ [-563.5, 376]). Because the default starter parts are small, the guide intentionally **dwarfs** them. At 1:1 zoom the ~940 px figure is taller than a typical panel, so the head and feet clip equally above/below the fold when centered — accepted. `GUIDE_SCALE`/`GUIDE_FIGURE_CENTER` are the tunables if a different size or placement is wanted later.
|
||||
**1:1 master-rig scale (deliberate):** the guide matches `stickman_rig.tscn` proportions exactly (a figure of ≈ 336 × 940 px, roughly x ∈ [-168, 168], y ∈ [-563.5, 376]). Because the default starter parts are small, the guide intentionally **dwarfs** them. At 1:1 zoom the ~940 px figure is taller than a typical panel, so the head and feet clip equally above/below the fold when centered — accepted. `GUIDE_SCALE`/`GUIDE_FIGURE_CENTER` are the tunables if a different size or placement is wanted later.
|
||||
|
||||
### 6. Grid & Panning
|
||||
|
||||
@@ -241,21 +266,21 @@ The Whole Stickman preview treats all shapes in a body-part panel as **one combi
|
||||
|
||||
### 14. Test Harness & Stickman Factory (Phase 9)
|
||||
|
||||
Phase 9 adds the **runtime pipeline** that turns a saved `.stk` file into a live, rigged `master_rig.tscn` instance — plus a standalone staging scene for debugging it in isolation. **Neither is wired into the editor.**
|
||||
Phase 9 adds the **runtime pipeline** that turns a saved `.stk` file into a live, rigged `stickman_rig.tscn` instance — plus a standalone staging scene for debugging it in isolation. **Neither is wired into the editor.**
|
||||
|
||||
**Stickman Factory (`res://scripts/stickman_factory.gd`)** — the runtime entry point:
|
||||
**Stickman Factory (`res://scripts/characters/stickman/stickman_factory.gd`)** — the runtime entry point:
|
||||
|
||||
| Method | Signature | Behavior |
|
||||
|---|---|---|
|
||||
| `load_stk` | `static func load_stk(path: String) -> Dictionary` | Reads a `.stk` file via `FileAccess` + `JSON.parse_string`. Returns `{}` and `push_warning` on failure. |
|
||||
| `spawn_from_data` | `static func spawn_from_data(stk_data: Dictionary) -> Node2D` | Instantiates `res://master_rig.tscn`, calls `StkRigAdapter.apply(stk_data, rig)`, returns the rig root. |
|
||||
| `spawn_from_data` | `static func spawn_from_data(stk_data: Dictionary) -> Node2D` | Instantiates `res://scenes/characters/stickman/stickman_rig.tscn`, calls `StkRigAdapter.apply(stk_data, rig)`, returns the rig root. |
|
||||
| `spawn` | `static func spawn(path: String) -> Node2D` | Chains `load_stk()` → `spawn_from_data()`. Returns `null` on empty data. |
|
||||
|
||||
The factory is the intended runtime API: `StickmanFactory.spawn("res://stickmen/basic.stk")` yields a rigged `StickmanRig` (the root of `master_rig.tscn`) ready to add to the scene tree. `StkRigAdapter` (Phase 8, extended by Phase 9) now also fits the head bone (`Head.position.y = -proportions.torso_length`) and mounts the head as **full geometry** like every other part (clearing its inline `@tool` circle script); the mounted head is dropped `HEAD_CHIN_DROP` (28 px) below the neck so its chin aligns with the pose-guide circle's bottom and overlaps the torso (Phase 9 Round 4).
|
||||
The factory is the intended runtime API: `StickmanFactory.spawn("res://content/stickmen/basic.stk")` yields a rigged `StickmanRig` (the root of `stickman_rig.tscn`) ready to add to the scene tree. `StkRigAdapter` (Phase 8, extended by Phase 9) now also fits the head bone (`Head.position.y = -proportions.torso_length`) and mounts the head as **full geometry** like every other part (clearing its inline `@tool` circle script); the mounted head is dropped `HEAD_CHIN_DROP` (28 px) below the neck so its chin aligns with the pose-guide circle's bottom and overlaps the torso (Phase 9 Round 4).
|
||||
|
||||
**Test Harness (`res://scenes/test_harness.tscn`)** — run via **F6** on the scene (NOT via the main editor scene). Controls:
|
||||
**Test Harness (`res://scenes/tools/test_harness.tscn`)** — run via **F6** on the scene (NOT via the main editor scene). Controls:
|
||||
|
||||
- **Open .stk…** — `FileDialog` filtered to `*.stk`; quick-select buttons for `res://stickmen/break.stk`, `res://stickmen/basic.stk`, `res://stickmen/test.stk`.
|
||||
- **Open .stk…** — `FileDialog` filtered to `*.stk`; quick-select buttons for `res://content/stickmen/break.stk`, `res://content/stickmen/basic.stk`, `res://content/stickmen/test.stk`.
|
||||
- **Show Bones / Show IK Handles** — checkboxes toggling the debug overlay.
|
||||
- **Loaded filename** — status label showing the currently loaded file.
|
||||
- **Pan / zoom** — middle-mouse drag to pan, mouse-wheel to zoom the `Camera2D`; the camera recenters on each spawn.
|
||||
@@ -271,7 +296,7 @@ Debug overlay (a world-space `Node2D` `_draw()`): true bone **segments** drawn b
|
||||
|
||||
The **Vector Terrain System** is a standalone, reusable component for building **crisp, resolution-independent vector terrain** (flat ground, angled ramps, stepped platforms) — with matching 2D collision. It is **not wired into the editor**; it is exercised through a dedicated staging scene run via **F6**.
|
||||
|
||||
**`TerrainBlock` (`res://scripts/terrain_block.gd`)** — `@tool` `class_name TerrainBlock`, `extends StaticBody2D`. A single terrain segment that builds its three children in code:
|
||||
**`TerrainBlock` (`res://scripts/terrain/terrain_block.gd`)** — `@tool` `class_name TerrainBlock`, `extends StaticBody2D`. A single terrain segment that builds its three children in code:
|
||||
|
||||
| Child | Node type | Purpose |
|
||||
|---|---|---|
|
||||
@@ -281,7 +306,7 @@ The **Vector Terrain System** is a standalone, reusable component for building *
|
||||
|
||||
**Exported properties** (`polygon_points: PackedVector2Array`, `fill_color`, `outline_color`, `outline_width`) are driven by a single unified setter that pushes vertex changes to all three children live — no manual rebuilds.
|
||||
|
||||
**`TerrainUtils` (`res://scripts/terrain_utils.gd`)** — `class_name TerrainUtils`, `extends RefCounted`, static utility.
|
||||
**`TerrainUtils` (`res://scripts/terrain/terrain_utils.gd`)** — `class_name TerrainUtils`, `extends RefCounted`, static utility.
|
||||
|
||||
- `sanitize_points(points: PackedVector2Array, grid_size: float = 16.0) -> PackedVector2Array` — sanitizes a raw vertex list through a fixed pipeline, in order:
|
||||
1. **Grid snap** — rounds each vertex to the `grid_size` grid (default **16.0**).
|
||||
@@ -289,13 +314,13 @@ The **Vector Terrain System** is a standalone, reusable component for building *
|
||||
3. **Clockwise enforcement** — `Geometry2D.is_polygon_clockwise()` reverses the winding if it is not already clockwise, **guaranteeing clockwise output**.
|
||||
- `spawn_block(...)` — factory that sanitizes the raw input vectors (`sanitize_points`), creates a `TerrainBlock`, applies the cleaned points, and adds it to the target container.
|
||||
|
||||
**`physics_test_harness.tscn` / `scripts/physics_test_harness.gd`** — `class_name PhysicsTestHarness`, `extends Node2D`; a **standalone staging scene** (run via **F6**; not wired into the editor). It builds flat ground, angled ramps, and stepped `TerrainBlock` instances via `TerrainUtils`, then instantiates `res://master_rig.tscn` standing on the flat ground. The scene root is a `Node2D` + script with a `Camera2D` at position `(0, -400)` zoom `0.5` and an empty `Environment` container. The camera wheel-zoom scales between **0.25x and 3.0x** (to test resolution independence / vector outline thickness); middle-drag pans. It also hosts the **Dynamic Vector Props** spawner (see below): press **1/2/3** to drop physics props above the angled ramp, plus a best-effort `StaticBody2D` collision proxy for the rig (which has no physics bodies of its own). A toggle-mode **Button** (label "Stickman" ↔ "Ragdoll") flips the rig's **kinematic-to-ragdoll** mode (see §17); a **Rest** `SpinBox` (0.1–10 s) writes `_rig.rest_timeout` (runtime-only) and a **"Recover Now"** button calls `_rig.request_recovery()`. The harness connects the rig's `state_changed` signal, which removes the `RigCollisionProxy` on `RAGDOLL` and re-adds it (idempotently) on `ANIMATED`/`RECOVERING`.
|
||||
**`physics_test_harness.tscn` / `scripts/tools/physics_test_harness.gd`** — `class_name PhysicsTestHarness`, `extends Node2D`; a **standalone staging scene** (run via **F6**; not wired into the editor). It builds flat ground, angled ramps, and stepped `TerrainBlock` instances via `TerrainUtils`, then instantiates `res://scenes/characters/stickman/stickman_rig.tscn` standing on the flat ground. The scene root is a `Node2D` + script with a `Camera2D` at position `(0, -400)` zoom `0.5` and an empty `Environment` container. The camera wheel-zoom scales between **0.25x and 3.0x** (to test resolution independence / vector outline thickness); middle-drag pans. It also hosts the **Dynamic Vector Props** spawner (see below): press **1/2/3** to drop physics props above the angled ramp, plus a best-effort `StaticBody2D` collision proxy for the rig (which has no physics bodies of its own). A toggle-mode **Button** (label "Stickman" ↔ "Ragdoll") flips the rig's **kinematic-to-ragdoll** mode (see §17); a **Rest** `SpinBox` (0.1–10 s) writes `_rig.rest_timeout` (runtime-only) and a **"Recover Now"** button calls `_rig.request_recovery()`. The harness connects the rig's `state_changed` signal, which removes the `RigCollisionProxy` on `RAGDOLL` and re-adds it (idempotently) on `ANIMATED`/`RECOVERING`.
|
||||
|
||||
### 16. Dynamic Vector Props
|
||||
|
||||
The **Dynamic Vector Props** system is a standalone, reusable component for building **physical, dynamic props** (crates, balls, planks) as `RigidBody2D` bodies with crisp vector rendering and matching collision. It is **not wired into the editor**; it is exercised through the physics test harness staging scene via **F6**.
|
||||
|
||||
**`PropBlock` (`res://scripts/prop_block.gd`)** — `@tool` `class_name PropBlock`, `extends RigidBody2D`. A single physical prop whose children are built in code, `@tool`-safe (null-guarded for editor safety):
|
||||
**`PropBlock` (`res://scripts/props/prop_block.gd`)** — `@tool` `class_name PropBlock`, `extends RigidBody2D`. A single physical prop whose children are built in code, `@tool`-safe (null-guarded for editor safety):
|
||||
|
||||
| Child | Node type | Purpose |
|
||||
|---|---|---|
|
||||
@@ -328,7 +353,7 @@ The **Dynamic Vector Props** system is a standalone, reusable component for buil
|
||||
|
||||
A **unified live-update setter** drives geometry to all children live — a change to `polygon_points` / `radius` / `shape_type` pushes to the `Polygon2D`, `Line2D`, and the active collision node with no manual rebuilds. Non-`NONE` presets also recolor `fill_color` and `outline_color` (outline = `tint_for(preset).darkened(0.55)`).
|
||||
|
||||
**`PropUtils` (`res://scripts/prop_utils.gd`)** — `class_name PropUtils`, `extends RefCounted`, static factory.
|
||||
**`PropUtils` (`res://scripts/props/prop_utils.gd`)** — `class_name PropUtils`, `extends RefCounted`, static factory.
|
||||
|
||||
- **Primitive generators** return shape-payload dictionaries with default dimensions + color themes:
|
||||
- `create_box(size := Vector2(48,48), ...)` — a 4-point `POLYGON` (wood theme).
|
||||
@@ -349,7 +374,7 @@ A **unified live-update setter** drives geometry to all children live — a chan
|
||||
|
||||
### 17. Kinematic-to-Ragdoll State System
|
||||
|
||||
`StickmanRig` (the runtime root of `master_rig.tscn`) can switch between physics modes via a reversible state machine with three states:
|
||||
`StickmanRig` (the runtime root of `stickman_rig.tscn`) can switch between physics modes via a reversible state machine with three states:
|
||||
|
||||
- **`ANIMATED`** (default) — the kinematic `Skeleton2D` + IK puppet is visible and driven by the `AnimationPlayer` / `SkeletonModificationStack2D`. The rig root's momentum is cached each physics frame (`_physics_process` → `_track_momentum()`) so it can be handed off on transition.
|
||||
- **`RAGDOLL`** — the kinematic rig is frozen (`AnimationPlayer` stopped with `keep_state`) and the `Body/*` visuals hidden **immediately**; a procedural network of `RigidBody2D` + `PinJoint2D` nodes spawned in code takes over, letting the figure fall/tumble against the terrain and props. The ragdoll is built from the **current solved bone positions** (the IK stack is disabled only after the build), so the handoff is instant and seamless — the ragdoll appears in exactly the pose the figure was in, no crossfade.
|
||||
@@ -383,7 +408,7 @@ Ragdoll bodies spawn fully visible — the entry handoff is instant (the ragdoll
|
||||
|
||||
**Angular limits** (`_apply_ragdoll_joint_limits()`): elbows/knees get their band from the editable per-profile, per-joint `RAGDOLL_JOINT_BAND_LIMITS` table — a `{ "lower": deg, "upper": deg }` range for the joint's allowed relative angle (0 = straight; a small side ~5 resists hyperextension, a large side ~150 is the fold, and a narrow/locked band such as `{60, 100}` forces a permanently-bent limb). FORWARD arms `{-150°, +5°}`, legs `{-5°, +150°}`; LEFT/RIGHT override both sides. Joints missing from the table fall back to the `RAGDOLL_JOINTS` `limit` string (`elbow_knee` `-5°..+150°`, `elbow_knee_ccw` `-150°..+5°`). Shoulders/hips allow ±160°; the neck is free (`angular_limit_enabled = false`).
|
||||
|
||||
**Joint bend configuration (EDIT ME):** every per-joint bend *decision* in the ragdoll cycle lives in three `const` tables at the top of `scripts/stickman_rig.gd`, keyed by facing profile, so joints can be tuned without touching pipeline code:
|
||||
**Joint bend configuration (EDIT ME):** every per-joint bend *decision* in the ragdoll cycle lives in three `const` tables at the top of `scripts/characters/stickman/stickman_rig.gd`, keyed by facing profile, so joints can be tuned without touching pipeline code:
|
||||
|
||||
| Const | Shape | Purpose |
|
||||
|---|---|---|
|
||||
@@ -399,30 +424,30 @@ Ragdoll bodies spawn fully visible — the entry handoff is instant (the ragdoll
|
||||
|
||||
`_play_stand_up()` then starts a **2.0 s** sine-in-out tween (`STAND_UP_DURATION`) of the 6 markers → their **pre-ragdoll** captured values and of the arm + head bones to the `_recovery_bones` targets computed by the snap — upper arm bones take the shortest path, lower arm bones use `_natural_joint_target(current, target, offset)` (offset = `bone_angle_lower − bone_angle_upper`; the through-straight rule is evaluated in the joint's rendered space and a `"shortest"` entry in `RECOVERY_JOINT_PATH` bypasses it). The **legs are IK-driven** toward their tweening, ground-clamped ankle markers (the 2 leg mods stay enabled). The arm mods + head LookAt stay disabled during the tween. The baked `stand_up` animation is **not** played — a fixed first keyframe can never match an arbitrary ragdoll rest pose. On tween finish, `_on_stand_up_finished()` restores the pre-ragdoll facing profile + per-joint bend flags + head LookAt state, re-enables the arm mods, re-shows `Body/*`, sets `state = ANIMATED`, and emits — the resumed IK solve reproduces the pre-ragdoll pose exactly (the end pose matches the pre-ragdoll frame, including mid-walk poses).
|
||||
|
||||
**Interruptibility:** `set_ragdoll(true)` during `RECOVERING` kills the stand-up tween and rebuilds the ragdoll; `set_ragdoll(false)` during `RAGDOLL` routes through `_start_recovery()`; repeated `set_ragdoll` calls are idempotent. All ragdoll nodes are spawned procedurally — `master_rig.tscn` is **not** modified (the `stand_up` / `walk_left` / `walk_right` animations are baked into the scene's `AnimationLibrary` by the `create_animations.gd` editor script, which runs manually in the editor; the baked `stand_up` is an authored reference and the recovery path does not play it). The ragdoll bodies spawn under a **world sibling** (not the rig root), so the whole-rig Y-axis mirror does not affect them; `walk_left` remains in the library but is **not used at runtime** — `walk_to()` plays the canonical `walk_right` clip for every direction (root-mirrored for LEFT).
|
||||
**Interruptibility:** `set_ragdoll(true)` during `RECOVERING` kills the stand-up tween and rebuilds the ragdoll; `set_ragdoll(false)` during `RAGDOLL` routes through `_start_recovery()`; repeated `set_ragdoll` calls are idempotent. All ragdoll nodes are spawned procedurally — `stickman_rig.tscn` is **not** modified (the `stand_up` / `walk_left` / `walk_right` animations are baked into the scene's `AnimationLibrary` by the `create_animations.gd` editor script, which runs manually in the editor; the baked `stand_up` is an authored reference and the recovery path does not play it). The ragdoll bodies spawn under a **world sibling** (not the rig root), so the whole-rig Y-axis mirror does not affect them; `walk_left` remains in the library but is **not used at runtime** — `walk_to()` plays the canonical `walk_right` clip for every direction (root-mirrored for LEFT).
|
||||
|
||||
### 18. Sandbox Stage Builder
|
||||
|
||||
The **Sandbox Stage Builder** (Phase 2) is a standalone, kid-friendly director sandbox: a visual stage where you place terrain, props, and stickmen from a palette, then switch between **Edit** (build), **Direct** (director/rule authoring), and **Play** (physics simulation). It is **not wired into the editor** — run via **F6** on `res://scenes/sandbox_stage.tscn`.
|
||||
The **Sandbox Stage Builder** (Phase 2) is a standalone, kid-friendly director sandbox: a visual stage where you place terrain, props, and stickmen from a palette, then switch between **Edit** (build), **Direct** (director/rule authoring), and **Play** (physics simulation). It is **not wired into the editor** — run via **F6** on `res://scenes/stage/sandbox_stage.tscn`.
|
||||
|
||||
The stage is intentionally **extendable**: the spawn palette is registry-driven (adding an object type = appending one dictionary entry), selection hit-tests arbitrary `Node2D`s geometrically, gizmos drive `global_position`/`global_rotation`, and core events are exposed as signals for future phases (Action Queue, Triggers, Save/Load). Styling defaults (fonts/sizes/colors/grid) live in a hand-editable `res://sandbox_theme.json` (Phase 4b, §21).
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `res://scenes/sandbox_stage.tscn` | The stage scene: root `Node2D` + `Camera2D` + empty `World` container. |
|
||||
| `res://scripts/sandbox_stage.gd` | `class_name SandboxStage`, `extends Node2D` — root controller (3-mode state machine, placement + drag-painting, camera, deletion, bottom status bar, mode badge/frame/cursors, signals); **Phase 3b** instantiates the `AssetSelector` grid popup + the two thumbnail renderers, owns the selector open/close flow and the lazy per-frame thumbnail drain, and wires the Stickman/Prop palette buttons to the selector (§22). **Phase 3c** adds the editor-tool wiring: the `QueuePanel` / `RulePanel` / `ActionEditor` / `RuleEditor` / `WaypointContext` instantiation, the unified `CaptureKind` target-capture system, "Edit Queue…"/"Edit Rules…" entry points + right-click stickman/waypoint context menus, the shared confirmation dialog, and consequence-only rule editing (§23). |
|
||||
| `res://scripts/stage_spawner.gd` | `class_name StageSpawner`, `extends RefCounted` — registry-driven factory reusing `TerrainUtils` / `PropUtils` / `StickmanFactory`; exposes `is_terrain_id()` / `get_template_aabb()` / `spawn_id` tagging. `get_template_aabb()` returns the **sanitized** template AABB (mirrors `_spawn_terrain()`'s 16-px grid pass), so it doubles as the block-unit paint stride. **Phase 3b:** registry ids `ground/ramp/step/prop/stickman/area` (separate `crate`/`ball` entries removed); holds the session state `selected_stickman_path` / `selected_prop_id` and a per-path `_stickman_cache`; `prop` and `stickman` spawn the **selected** asset. |
|
||||
| `res://scripts/stickman_library.gd` | **Phase 3b** `class_name StickmanLibrary`, `extends RefCounted` — scans `res://stickmen/*.stk` into `{path, name, data}` entry models (corrupt/missing-`body_parts` files skipped, empty `stickman_name` → filename basename), with `make_entry(path)` for arbitrary Browse-chosen paths (§22). |
|
||||
| `res://scripts/prop_library.gd` | **Phase 3b** `class_name PropLibrary`, `extends RefCounted` — static registry of the 4 prop templates (Crate/Wood, Ball/Rubber, Plank/Metal, Triangle/Cardboard) with their `PropUtils.create_*()` payloads + material presets; `get_default_id()` = `"crate"` (§22). |
|
||||
| `res://scripts/asset_selector.gd` | **Phase 3b** `class_name AssetSelector`, `extends PopupPanel` — grid UI controller (root of `scenes/asset_selector.tscn`): pagination 12/page (4×3), Prev/Next/page label, empty-state label, per-cell thumbnail + name + (prop) material badge, hover styling (no pre-highlight on open), window-resize re-centering, Browse/Refresh/Close wiring, Esc handling; signals `item_selected` / `cancelled` / `browse_requested` / `refresh_requested` (§22). |
|
||||
| `res://scripts/stage_selection.gd` | `class_name StageSelection`, `extends RefCounted` — hover/click/box selection via geometric AABB hit-testing. |
|
||||
| `res://scripts/stage_gizmos.gd` | `class_name StageGizmos`, `extends Node2D` — hover highlight, selection outline, rotate ring handle. |
|
||||
| `res://scripts/stage_grid.gd` | `class_name StageGrid`, `extends Node2D` — optional world-space grid overlay (major line every 5 cells). |
|
||||
| `res://scripts/stage_placement_overlay.gd` | **Phase 4b** `class_name StagePlacementOverlay`, `extends Node2D` — world-space overlay drawing the terrain drag-painting guide line + the director action trajectory / ghost marker. |
|
||||
| `res://scripts/thumbnails/stickman_thumbnail.gd` | **Phase 3b** `class_name StickmanThumbnail`, `extends Node` — renders a parsed `.stk` into a 200×200 `Texture2D` by spawning the **real rig** (`StickmanFactory.spawn_from_data`) inside an offscreen `SubViewport`, framing it and capturing after a double `frame_post_draw` (§22). |
|
||||
| `res://scripts/thumbnails/prop_thumbnail.gd` | **Phase 3b** `class_name PropThumbnail`, `extends Node` — renders a prop template into a 200×200 `Texture2D` via a lightweight `Polygon2D` + `Line2D` visual (no `RigidBody2D`, so no gravity), tinted by the material preset (§22). |
|
||||
| `res://scripts/thumbnails/thumbnail_cache.gd` | **Phase 3b** `class_name ThumbnailCache`, `extends RefCounted` — disk PNG cache under `user://thumbnails/`: stickman key = `basename_mtime`, prop key = `id_v<PROP_VERSION>`; `load_png`/`save_png`/`clean_stale_stickmen` (§22). |
|
||||
| `res://scenes/asset_selector.tscn` | **Phase 3b** `PopupPanel` root + `asset_selector.gd` — minimal shell/layout skeleton (title bar, empty `GridContainer`, footer Prev/Next/Browse/Refresh/Close); all dynamic per-cell content is built in code at runtime (§22). |
|
||||
| `res://scenes/stage/sandbox_stage.tscn` | The stage scene: root `Node2D` + `Camera2D` + empty `World` container. |
|
||||
| `res://scripts/editors/stage/sandbox_stage.gd` | `class_name SandboxStage`, `extends Node2D` — root controller (3-mode state machine, placement + drag-painting, camera, deletion, bottom status bar, mode badge/frame/cursors, signals); **Phase 3b** instantiates the `AssetSelector` grid popup + the two thumbnail renderers, owns the selector open/close flow and the lazy per-frame thumbnail drain, and wires the Stickman/Prop palette buttons to the selector (§22). **Phase 3c** adds the editor-tool wiring: the `QueuePanel` / `RulePanel` / `ActionEditor` / `RuleEditor` / `WaypointContext` instantiation, the unified `CaptureKind` target-capture system, "Edit Queue…"/"Edit Rules…" entry points + right-click stickman/waypoint context menus, the shared confirmation dialog, and consequence-only rule editing (§23). |
|
||||
| `res://scripts/stage/stage_spawner.gd` | `class_name StageSpawner`, `extends RefCounted` — registry-driven factory reusing `TerrainUtils` / `PropUtils` / `StickmanFactory`; exposes `is_terrain_id()` / `get_template_aabb()` / `spawn_id` tagging. `get_template_aabb()` returns the **sanitized** template AABB (mirrors `_spawn_terrain()`'s 16-px grid pass), so it doubles as the block-unit paint stride. **Phase 3b:** registry ids `ground/ramp/step/prop/stickman/area` (separate `crate`/`ball` entries removed); holds the session state `selected_stickman_path` / `selected_prop_id` and a per-path `_stickman_cache`; `prop` and `stickman` spawn the **selected** asset. |
|
||||
| `res://scripts/characters/stickman/stickman_library.gd` | **Phase 3b** `class_name StickmanLibrary`, `extends RefCounted` — scans `res://content/stickmen/*.stk` into `{path, name, data}` entry models (corrupt/missing-`body_parts` files skipped, empty `stickman_name` → filename basename), with `make_entry(path)` for arbitrary Browse-chosen paths (§22). |
|
||||
| `res://scripts/props/prop_library.gd` | **Phase 3b** `class_name PropLibrary`, `extends RefCounted` — static registry of the 4 prop templates (Crate/Wood, Ball/Rubber, Plank/Metal, Triangle/Cardboard) with their `PropUtils.create_*()` payloads + material presets; `get_default_id()` = `"crate"` (§22). |
|
||||
| `res://scripts/shared/ui/asset_selector.gd` | **Phase 3b** `class_name AssetSelector`, `extends PopupPanel` — grid UI controller (root of `scenes/stage/asset_selector.tscn`): pagination 12/page (4×3), Prev/Next/page label, empty-state label, per-cell thumbnail + name + (prop) material badge, hover styling (no pre-highlight on open), window-resize re-centering, Browse/Refresh/Close wiring, Esc handling; signals `item_selected` / `cancelled` / `browse_requested` / `refresh_requested` (§22). |
|
||||
| `res://scripts/stage/stage_selection.gd` | `class_name StageSelection`, `extends RefCounted` — hover/click/box selection via geometric AABB hit-testing. |
|
||||
| `res://scripts/stage/stage_gizmos.gd` | `class_name StageGizmos`, `extends Node2D` — hover highlight, selection outline, rotate ring handle. |
|
||||
| `res://scripts/stage/stage_grid.gd` | `class_name StageGrid`, `extends Node2D` — optional world-space grid overlay (major line every 5 cells). |
|
||||
| `res://scripts/stage/stage_placement_overlay.gd` | **Phase 4b** `class_name StagePlacementOverlay`, `extends Node2D` — world-space overlay drawing the terrain drag-painting guide line + the director action trajectory / ghost marker. |
|
||||
| `res://scripts/shared/thumbnails/stickman_thumbnail.gd` | **Phase 3b** `class_name StickmanThumbnail`, `extends Node` — renders a parsed `.stk` into a 200×200 `Texture2D` by spawning the **real rig** (`StickmanFactory.spawn_from_data`) inside an offscreen `SubViewport`, framing it and capturing after a double `frame_post_draw` (§22). |
|
||||
| `res://scripts/shared/thumbnails/prop_thumbnail.gd` | **Phase 3b** `class_name PropThumbnail`, `extends Node` — renders a prop template into a 200×200 `Texture2D` via a lightweight `Polygon2D` + `Line2D` visual (no `RigidBody2D`, so no gravity), tinted by the material preset (§22). |
|
||||
| `res://scripts/shared/thumbnails/thumbnail_cache.gd` | **Phase 3b** `class_name ThumbnailCache`, `extends RefCounted` — disk PNG cache under `user://thumbnails/`: stickman key = `basename_mtime`, prop key = `id_v<PROP_VERSION>`; `load_png`/`save_png`/`clean_stale_stickmen` (§22). |
|
||||
| `res://scenes/stage/asset_selector.tscn` | **Phase 3b** `PopupPanel` root + `asset_selector.gd` — minimal shell/layout skeleton (title bar, empty `GridContainer`, footer Prev/Next/Browse/Refresh/Close); all dynamic per-cell content is built in code at runtime (§22). |
|
||||
| `res://sandbox_theme.json` | **Phase 4b** hand-editable styling defaults (font paths/sizes, grid snap default, mode accent colors). **Phase 3c** extends the `fonts` block with style variants (`ui_font_bold`/`ui_font_italic`), per-widget size/style flags, and an optional per-widget `{size, bold, italic}` object form (§21.3 / spec §14). Loaded at `_ready()`; missing/malformed falls back to built-in constants. |
|
||||
|
||||
**Mode management** — a single **3-segment switcher** `[ ✏️ Edit | 🎬 Direct | ▶️ Play ]` sits at the far left of the top bar (`enum StageMode { EDIT, DIRECT, PLAY }`). Each mode shows a **contextual toolbar** and a **mode badge pill** in the viewport's top-left corner (`✏️ EDIT` cyan, `🎬 DIRECTING` amber, `▶️ SIMULATING` green), sourced from `sandbox_theme.json` `mode_colors`:
|
||||
@@ -438,7 +463,7 @@ The stage is intentionally **extendable**: the spawn palette is registry-driven
|
||||
|
||||
- **Ground / Ramp / Step** — `TerrainBlock` terrain. Single **terrain** palette items are **drag-painted** (§21): left-click-and-drag paints a staircase run of blocks; a terrain drag commits on release. Non-terrain (props/stickman/area) palette items keep the Phase 2 **single-click repeated placement**.
|
||||
- **Prop** (Phase 3b) — opens a **selector grid** (§22) of the 4 prop templates; selecting one sets the `selected_prop_id` and enters placement mode spawning that `PropBlock` (`PropUtils.create_*()` + the matching material preset). Replaces the earlier separate **Crate** / **Ball** buttons.
|
||||
- **Stickman** (Phase 3b) — opens a **selector grid** (§22) of every `.stk` in `res://stickmen/`; selecting one sets the `selected_stickman_path` and enters placement mode spawning a `StickmanRig` from that file (offset `(0, -385)` so the feet land on the cursor). Replaces the previous hard-coded single-`test.stk` placement.
|
||||
- **Stickman** (Phase 3b) — opens a **selector grid** (§22) of every `.stk` in `res://content/stickmen/`; selecting one sets the `selected_stickman_path` and enters placement mode spawning a `StickmanRig` from that file (offset `(0, -385)` so the feet land on the cursor). Replaces the previous hard-coded single-`test.stk` placement.
|
||||
- **Area** (Phase 4) — a `TriggerArea` sensor.
|
||||
|
||||
Clicking a palette button enters **placement mode**, which shows a translucent **ghost** of the object under the cursor (snapped to the grid when Snap is on); the stickman ghost is a static standing figure. **Left-click** keeps the Phase 2 repeated-placement behavior (each click/drag commits one placement and the tool stays active); **right-click** (or **Esc**) is the explicit **"put the tool down"** gesture — it cancels any in-progress drag, leaves already-placed cells if a drag had committed, and un-toggles the palette button. Each placement emits `object_placed(node)`. The **Stickman** and **Prop** buttons open a selector grid first (a modal `PopupPanel`, §22) and only enter placement mode once an asset is chosen.
|
||||
@@ -470,14 +495,14 @@ Clicking a palette button enters **placement mode**, which shows a translucent *
|
||||
|
||||
### 19. Director Tool (Phase 3a)
|
||||
|
||||
The **Director Tool** (Phase 3a) turns the Sandbox Stage into a mini director's workspace: click a stickman, choose actions from a popup, see the script as waypoints/badges in Edit mode, then press **Play** to run every stickman's action queue. It is **not wired into the editor** — run via **F6** on `res://scenes/sandbox_stage.tscn`.
|
||||
The **Director Tool** (Phase 3a) turns the Sandbox Stage into a mini director's workspace: click a stickman, choose actions from a popup, see the script as waypoints/badges in Edit mode, then press **Play** to run every stickman's action queue. It is **not wired into the editor** — run via **F6** on `res://scenes/stage/sandbox_stage.tscn`.
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `res://scripts/stickman_rig.gd` | Extended with navigation/walking, speech, an action queue, and the queue runner state machine (see API below). |
|
||||
| `res://scripts/stickman_speech_bubble.gd` | `class_name SpeechBubble`, `extends Node2D` — a world-space speech bubble drawn via `_draw()` (`ThemeDB.fallback_font`), a child of the rig above the head. |
|
||||
| `res://scripts/stage_director_visuals.gd` | `class_name StageDirectorVisuals`, `extends Node2D` — Edit-mode director overlay (waypoint dots, dashed connectors, action badges, order numbers); hidden in Play. **Phase 3c** adds `hit_test_waypoint_action()` (rig/index/pos), `set_edit_waypoint()`/`clear_edit_waypoint()` with the pulsing edit highlight for visual walk re-placement, and rule-label → editor routing (§23). |
|
||||
| `res://scripts/sandbox_stage.gd` | Extended with the **Direct** palette button, the action popup + speak/wait dialogs, a code-built `NavigationRegion2D` re-baked on terrain edits, and Play mode now starting each stickman's queue. |
|
||||
| `res://scripts/characters/stickman/stickman_rig.gd` | Extended with navigation/walking, speech, an action queue, and the queue runner state machine (see API below). |
|
||||
| `res://scripts/speech/stickman_speech_bubble.gd` | `class_name SpeechBubble`, `extends Node2D` — a world-space speech bubble drawn via `_draw()` (`ThemeDB.fallback_font`), a child of the rig above the head. |
|
||||
| `res://scripts/stage/stage_director_visuals.gd` | `class_name StageDirectorVisuals`, `extends Node2D` — Edit-mode director overlay (waypoint dots, dashed connectors, action badges, order numbers); hidden in Play. **Phase 3c** adds `hit_test_waypoint_action()` (rig/index/pos), `set_edit_waypoint()`/`clear_edit_waypoint()` with the pulsing edit highlight for visual walk re-placement, and rule-label → editor routing (§23). |
|
||||
| `res://scripts/editors/stage/sandbox_stage.gd` | Extended with the **Direct** palette button, the action popup + speak/wait dialogs, a code-built `NavigationRegion2D` re-baked on terrain edits, and Play mode now starting each stickman's queue. |
|
||||
|
||||
**Direct tool workflow (Edit):**
|
||||
|
||||
@@ -517,7 +542,7 @@ The **Director Tool** (Phase 3a) turns the Sandbox Stage into a mini director's
|
||||
|
||||
- Terrain adaptation is enabled only in **Play**. `_enter_play_mode()` calls `begin_terrain_fall()` before `start_queue()`. An unsupported animated rig free-falls kinematically with bounded gravity; walking animation pauses while airborne and resumes on landing. EDIT and DIRECT disable the controller and restore the authored transform/standing pose.
|
||||
- The center support sample uses three downward rays at horizontal offsets `[-24, 0, +24]`; each lower-leg endpoint uses an independent three-ray fan at `[-4, 0, +4]`. A hit must be a `TerrainBlock` with an upward-facing normal, and the rig's own collision-proxy RIDs are excluded. The highest valid surface wins, preventing a lower floor under a ramp from pulling a leg through the ramp.
|
||||
- `master_rig.tscn` separates animated `AnimationTargets/Left_Leg_Base` and `Right_Leg_Base` markers from live `IK_Targets/Left_Leg` and `Right_Leg` targets. The rig blends complementary continuous stance/swing weights, holds stance contacts in world space, and applies a predictive 24 px foot guard for smooth contact transitions. Root elevation accumulates across ramps and steps, with centerline pelvis compensation; no foot/ankle bones are added.
|
||||
- `stickman_rig.tscn` separates animated `AnimationTargets/Left_Leg_Base` and `Right_Leg_Base` markers from live `IK_Targets/Left_Leg` and `Right_Leg` targets. The rig blends complementary continuous stance/swing weights, holds stance contacts in world space, and applies a predictive 24 px foot guard for smooth contact transitions. Root elevation accumulates across ramps and steps, with centerline pelvis compensation; no foot/ankle bones are added.
|
||||
- Navigation uses shallow ribbons over exposed upward-facing TerrainBlock edges, plus bridges between surface endpoints within 64 px horizontally and 96 px vertically for valid steps. The `NavigationAgent2D` remains at local `(0, +385)` and uses the selected walk speed; navigation supplies horizontal progress while terrain following owns vertical root motion and arrival avoids Y-correction jitter.
|
||||
|
||||
**Nav-mesh behavior:**
|
||||
@@ -526,7 +551,7 @@ The **Director Tool** (Phase 3a) turns the Sandbox Stage into a mini director's
|
||||
- **Auto re-bake** on any terrain edit: the nav mesh is marked dirty on terrain place / move / rotate (`transform_committed`) / delete and re-baked once per frame (coalescing bursts) in `_process`.
|
||||
- Each stickman's `NavigationAgent2D` is a child of the rig **at the feet** (local `(0, +385)` = `-FOOT_OFFSET`), so it sits on the ground-level mesh; agent and region share the default navigation map, layer 1.
|
||||
- `walk_to(target)` treats `target` as a **feet/ground destination**; the rig converts ground-level path points back to root positions with `FOOT_OFFSET := (0, -385)`. Walking is **hybrid**: an **on-mesh target** follows the nav path (`_walk_mode = "nav"`), while an **off-mesh / unreachable target** (empty path **or** `is_target_reachable() == false`) switches to **direct straight-line steering** toward the clicked waypoint (`_walk_mode = "direct"`, root target = waypoint + `FOOT_OFFSET`) — it is **not** rejected with a warning and the rig does **not** stand still. Nav reads are deferred until the map has synced (`map_get_iteration_id(...) != 0`) and the path query is forced via `get_next_path_position()` before any reachability/finished check, so a fresh target is never misjudged as finished/unreachable after a single step.
|
||||
- Pathing is kinematic (`global_position.move_toward`); `avoidance_enabled = false` in 3a, so stickmen path through props and each other (deferred — see `docs/tech_debt_and_optimizations.md` #13).
|
||||
- Pathing is kinematic (`global_position.move_toward`); `avoidance_enabled = false` in 3a, so stickmen path through props and each other (deferred — see `docs/architecture/tech_debt_and_optimizations.md` #13).
|
||||
- **Walk/nav debugging (off by default):** `const DEBUG_WALK` in `stickman_rig.gd` (per-frame walk trace with `mode=nav|direct`, plus one-shot `walk_to`/finish/cancel prints) and `const DEBUG_STAGE` in `sandbox_stage.gd` (`[stage]` target capture, `[nav]` baked verts/polys, `[stage] PLAY rigs`).
|
||||
|
||||
**StickmanRig director API surface:**
|
||||
@@ -553,19 +578,19 @@ The **Director Tool** (Phase 3a) turns the Sandbox Stage into a mini director's
|
||||
|
||||
### 20. Triggers & Event System (Phase 4)
|
||||
|
||||
**Phase 4** adds **reactive storytelling** to the Sandbox Stage. While Phase 3a gave directors *sequential* control (actions in a fixed order per stickman), Phase 4 adds *reactive* control — **"When X happens, do Y"** — via event rules that span objects. It is **not wired into the editor** — run via **F6** on `res://scenes/sandbox_stage.tscn`.
|
||||
**Phase 4** adds **reactive storytelling** to the Sandbox Stage. While Phase 3a gave directors *sequential* control (actions in a fixed order per stickman), Phase 4 adds *reactive* control — **"When X happens, do Y"** — via event rules that span objects. It is **not wired into the editor** — run via **F6** on `res://scenes/stage/sandbox_stage.tscn`.
|
||||
|
||||
The rule concept is **When → Then**: a *trigger* (an event on some object) fires a list of *actions* on a target object. Rules are stored as `_event_rules: Array[Dictionary]` of `{id, trigger, actions}` in `sandbox_stage.gd`, where `trigger` carries `{type, source, target, ...}` instance references and `actions` is an array of Phase 3a action dicts (`{"type":"walk_to","target":...}`, etc.).
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `res://scripts/trigger_area.gd` | NEW `class_name TriggerArea`, `extends Node2D` — a placeable sensor (`@export size: Vector2`, default 96×96) with a centered **local-space** `get_area_rect() -> Rect2` and a translucent green `_draw()` fill + dashed border. **No physics, no signals** — it is a pure geometric region evaluated by the stage. |
|
||||
| `res://scripts/sandbox_stage.gd` | Extended with the rule system: `_event_rules`, the geometric area-entry engine, physics contact routing for stickman/prop collisions (Phase 4.5), the rule-builder UI state machine, and rule auto-cleanup. |
|
||||
| `res://scripts/stickman_rig.gd` | `arrived` gained a `target: Vector2` payload; new `enqueue_reactive(actions)` appends reactive actions without replaying the queue. |
|
||||
| `res://scripts/prop_block.gd` | NEW physics contact signals `collided(other, contact_normal, contact_position)` and `separated(other)`; prop-vs-prop and Phase 4.5 stickman contacts share the contact-monitoring path. |
|
||||
| `res://scripts/stage_director_visuals.gd` | Extended with rule visualization + `set_rules()` / `hit_test_rule()` / `hit_test_waypoint()`. |
|
||||
| `res://scripts/stage_spawner.gd` | New `"area"` palette registry entry (label **"Area"**); duck-typed `get_area_rect` AABB branch in `get_world_aabb`. |
|
||||
| `res://scripts/stage_selection.gd` | Same duck-typed `get_area_rect` AABB branch for selecting/clicking trigger areas. |
|
||||
| `res://scripts/stage/trigger_area.gd` | NEW `class_name TriggerArea`, `extends Node2D` — a placeable sensor (`@export size: Vector2`, default 96×96) with a centered **local-space** `get_area_rect() -> Rect2` and a translucent green `_draw()` fill + dashed border. **No physics, no signals** — it is a pure geometric region evaluated by the stage. |
|
||||
| `res://scripts/editors/stage/sandbox_stage.gd` | Extended with the rule system: `_event_rules`, the geometric area-entry engine, physics contact routing for stickman/prop collisions (Phase 4.5), the rule-builder UI state machine, and rule auto-cleanup. |
|
||||
| `res://scripts/characters/stickman/stickman_rig.gd` | `arrived` gained a `target: Vector2` payload; new `enqueue_reactive(actions)` appends reactive actions without replaying the queue. |
|
||||
| `res://scripts/props/prop_block.gd` | NEW physics contact signals `collided(other, contact_normal, contact_position)` and `separated(other)`; prop-vs-prop and Phase 4.5 stickman contacts share the contact-monitoring path. |
|
||||
| `res://scripts/stage/stage_director_visuals.gd` | Extended with rule visualization + `set_rules()` / `hit_test_rule()` / `hit_test_waypoint()`. |
|
||||
| `res://scripts/stage/stage_spawner.gd` | New `"area"` palette registry entry (label **"Area"**); duck-typed `get_area_rect` AABB branch in `get_world_aabb`. |
|
||||
| `res://scripts/stage/stage_selection.gd` | Same duck-typed `get_area_rect` AABB branch for selecting/clicking trigger areas. |
|
||||
|
||||
**Trigger types:**
|
||||
|
||||
@@ -618,7 +643,7 @@ Edge-triggered dictionaries (which events already fired) are reset on Play/Edit
|
||||
|
||||
### 20.2 Phase 4.5 — Per-Part Collision Bodies and Hit Reactions
|
||||
|
||||
Phase 4.5 gives an ANIMATED `StickmanRig` a physical collision surface in the Sandbox Stage. It is runtime-only and does not change `master_rig.tscn`, the `.stk` format, or the editor layout.
|
||||
Phase 4.5 gives an ANIMATED `StickmanRig` a physical collision surface in the Sandbox Stage. It is runtime-only and does not change `stickman_rig.tscn`, the `.stk` format, or the editor layout.
|
||||
|
||||
- `StickmanRig` builds ten metadata-tagged `CollisionBody` `AnimatableBody2D` proxies (head, torso, and eight limbs). They are top-level relative to their `Body/*` visual containers, use layer/mask `1`, set `sync_to_physics = false`, and copy each rendered visual's global transform in `_sync_collision_bodies()` every physics frame. This explicit synchronization keeps proxies aligned with `RemoteTransform2D`-driven geometry during poses and WALK-left mirroring.
|
||||
- Limb and torso proxies use fitted `CapsuleShape2D`s in the adapter's hanging frame. The head uses a `CircleShape2D` centered from the mounted head geometry's local bounds, with a minimum radius of `90 px` and growth when the mounted geometry is larger. These are intentionally approximate collision shapes, not per-shape polygons.
|
||||
@@ -631,7 +656,7 @@ Focused verification: `tests/test_phase45_collision_bodies.gd` (223 assertions),
|
||||
|
||||
### 21. Phase 4b Polish — Mode Switcher, Theme, Terrain Painting, Director UX, Walk Jitter Fix
|
||||
|
||||
**Phase 4b** is a **polish + bugfix** pass over the Sandbox Stage Builder. It does **not** add new gameplay systems; it restructures the top bar into a **3-segment mode switcher** with contextual toolbars, adds a **bottom status bar** with live mouse coordinates, a **mode badge/frame** and per-mode cursors, upgrades **terrain placement** from single-click into **drag-to-paint** with a grid spatial dictionary, makes the **director's "pick a target" flows** kid-friendly (cursor-attached tooltip, rubber-band trajectory, reticle cursor), introduces a hand-editable **`res://sandbox_theme.json`**, and fixes the **walk-waypoint arrival jitter**. Run via **F6** on `res://scenes/sandbox_stage.tscn`; not wired into the editor. See §18 for the mode-switcher / status-bar / badge / cursor surface; this section details the placement, styling, director-UX, and bugfix internals.
|
||||
**Phase 4b** is a **polish + bugfix** pass over the Sandbox Stage Builder. It does **not** add new gameplay systems; it restructures the top bar into a **3-segment mode switcher** with contextual toolbars, adds a **bottom status bar** with live mouse coordinates, a **mode badge/frame** and per-mode cursors, upgrades **terrain placement** from single-click into **drag-to-paint** with a grid spatial dictionary, makes the **director's "pick a target" flows** kid-friendly (cursor-attached tooltip, rubber-band trajectory, reticle cursor), introduces a hand-editable **`res://sandbox_theme.json`**, and fixes the **walk-waypoint arrival jitter**. Run via **F6** on `res://scenes/stage/sandbox_stage.tscn`; not wired into the editor. See §18 for the mode-switcher / status-bar / badge / cursor surface; this section details the placement, styling, director-UX, and bugfix internals.
|
||||
|
||||
#### 21.1 Terrain drag-painting (Edit mode)
|
||||
|
||||
@@ -655,7 +680,7 @@ Block centers are `block_cell * stride`, and Bresenham runs over block units. A
|
||||
5. **Release** commits the batch **atomically**: only the "empty" block units spawn (all in one frame), the nav mesh is marked dirty **once** (`_nav_dirty = true`, not per node), the grid dictionary is rebuilt, and `object_placed(node)` fires per node. LMB keeps repeated placement active for the next drag (the placement ghost re-arms).
|
||||
6. **RMB** (or **Esc**) ends draw/placement mode — it cancels an in-progress drag (nothing is placed until release), clears the guide line, and un-toggles the palette button and restores the cursor.
|
||||
|
||||
**Grid spatial dictionary** (`_grid_cells`): a runtime `Dictionary` on `SandboxStage` keyed by 16-px grid-cell `Vector2i` (`StageSpawner.TERRAIN_GRID_SIZE`) → `Array[Node2D]`. It is **advisory only** — it drives the 3-state occupancy query (green/neutral/red tint + skip) but is **never authoritative for physics** or for the block-unit paint stride; the `World` tree is the source of truth. Occupancy marks **all 16-px cells covered by the node's world AABB** via `_rasterize_aabb_to_cells()` (for props/stickmen/areas it rasterizes `StageSelection.get_world_aabb()`), so one Ground block (192×32) spans ≈ 12×2 dictionary cells even though it paints as a single block unit. It is populated on place, updated on move/rotate/delete, and rebuilt on grid-size change. Terrain nodes carry a `spawn_id` string (`TerrainBlock.spawn_id`, set by `StageSpawner.spawn_id`) so same-template overlaps are detectable; `StageSpawner.is_terrain_id()` distinguishes terrain registry entries and `get_template_aabb(id)` exposes a terrain template's **sanitized** local AABB for ghost sizing / block-unit stride / cell rasterization.
|
||||
**Grid spatial dictionary** (`_grid_cells`): a runtime `Dictionary` on `SandboxStage` keyed by 16-px grid-cell `Vector2i` (`StageSpawner.TERRAIN_GRID_SIZE`) → `Array[Node2D]`. It is **advisory only** — it drives the 3-state occupancy query (green/neutral/red tint + skip) but is **never authoritative for physics** or for the block-unit paint stride; the `World` tree is the source of truth. Occupancy marks **all 16-px cells covered by the node's world AABB** via `_rasterize_aabb_to_cells()` (for content/props/stickmen/areas it rasterizes `StageSelection.get_world_aabb()`), so one Ground block (192×32) spans ≈ 12×2 dictionary cells even though it paints as a single block unit. It is populated on place, updated on move/rotate/delete, and rebuilt on grid-size change. Terrain nodes carry a `spawn_id` string (`TerrainBlock.spawn_id`, set by `StageSpawner.spawn_id`) so same-template overlaps are detectable; `StageSpawner.is_terrain_id()` distinguishes terrain registry entries and `get_template_aabb(id)` exposes a terrain template's **sanitized** local AABB for ghost sizing / block-unit stride / cell rasterization.
|
||||
|
||||
#### 21.2 Director targeting UX (Direct / rule-building)
|
||||
|
||||
@@ -667,65 +692,18 @@ While a click-awaiting director step is active — a pending **Walk To** target,
|
||||
|
||||
#### 21.3 `res://sandbox_theme.json` (styling defaults)
|
||||
|
||||
A single committed, hand-editable JSON config drives sandbox font/size/color/grid defaults. It loads in `_ready()` before `_build_ui()`; a missing or malformed file logs one `push_warning` and uses all built-in constants (never crashes); unknown extra keys are ignored; a referenced font that does not exist falls back to `ThemeDB.fallback_font` with a warning. The **live** grid size/snap/grid-visibility remain persisted in `user://sandbox_settings.json` (runtime source of truth); the theme supplies the **initial default** grid size on first run. Schema:
|
||||
The Sandbox theme is schema `2.0` and now covers the code-built chrome,
|
||||
palette, selectors, dialogs, overlays, reusable widget data, fonts, colors,
|
||||
and grid defaults. See the complete current key reference, examples, legacy
|
||||
compatibility notes, and troubleshooting guide in
|
||||
[docs/architecture/SANDBOX_THEME.md](docs/architecture/SANDBOX_THEME.md).
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"fonts": {
|
||||
"ui_font": "",
|
||||
"emoji_font": "",
|
||||
"ui_font_bold": "",
|
||||
"ui_font_italic": "",
|
||||
"action_popup_font_size": 24,
|
||||
"action_popup_emoji_size": 22,
|
||||
"assignment_badge_font_size": 20,
|
||||
"assignment_badge_radius": 9,
|
||||
"rule_label_font_size": 16,
|
||||
"status_pill_font_size": 16,
|
||||
"tooltip_font_size": 18,
|
||||
"queue_panel_font_size": 18,
|
||||
"rule_panel_font_size": 18,
|
||||
"action_editor_font_size": 18,
|
||||
"rule_editor_font_size": 18,
|
||||
"panel_row_font_size": 16,
|
||||
"panel_title_font_size": 18,
|
||||
"panel_title_bold": true,
|
||||
"rule_label_bold": false,
|
||||
"badge_bold": true,
|
||||
"action_popup": { "size": 24, "bold": false, "italic": false }
|
||||
},
|
||||
"grid": {
|
||||
"snap_size": 15.0
|
||||
},
|
||||
"mode_colors": {
|
||||
"edit_accent": "#22c6ff",
|
||||
"direct_accent": "#ffb300",
|
||||
"play_accent": "#33dd77",
|
||||
"guide_line": "#22c6ff"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Key | Default | Consumed by |
|
||||
|---|---|---|
|
||||
| `fonts.ui_font` / `fonts.emoji_font` | `""` (fallback font) | `res://` font paths; empty/missing → `ThemeDB.fallback_font`. `emoji_font` is also pushed to `StageDirectorVisuals.emoji_font` and the director popups. |
|
||||
| `fonts.ui_font_bold` / `fonts.ui_font_italic` | `""` (fallback to `ui_font`) | **Phase 3c** style-variant font paths for bold/italic; empty → `ui_font`. Bold/italic are realised via a dedicated `FontVariation` (e.g. `variation_embolden`, OpenType slant) when no separate file is configured. |
|
||||
| `fonts.action_popup_font_size` / `action_popup_emoji_size` | 24 / 22 | Font size override on the director action/trigger/rule popups. **Phase 3c:** `action_popup_emoji_size` is now **consumed** — applied as the popup menu's emoji-glyph font size when a popup font is configured (`_apply_popup_theme()`). |
|
||||
| `fonts.action_popup` (optional object) | `{ "size": 24, "bold": false, "italic": false }` | **Phase 3c** per-widget object form for the popups; when present, overrides the flat `action_popup_font_size` / bold keys for that widget. |
|
||||
| `fonts.assignment_badge_font_size` / `assignment_badge_radius` | 20 / 9 | Replaces `StageDirectorVisuals` `ICON_SIZE_PX` / `RULE_BADGE_RADIUS_PX` (and order-number size) via `set_style(cfg)`. |
|
||||
| `fonts.rule_label_font_size` | 16 | Replaces `StageDirectorVisuals.RULE_LABEL_FONT_SIZE_PX`. **Phase 3c** `fonts.rule_label_bold` (default `false`) adds the bold flag; `fonts.badge_bold` (default `true`) bolds the action/trigger badges. |
|
||||
| `fonts.status_pill_font_size` / `tooltip_font_size` | 16 / 18 | The mode badge pill and the cursor-attached action tooltip. |
|
||||
| `fonts.queue_panel_font_size` / `rule_panel_font_size` | 18 / 18 | **Phase 3c** font sizes for the Queue / Rule panel bodies; fall back to `action_popup_font_size`. |
|
||||
| `fonts.action_editor_font_size` / `rule_editor_font_size` | 18 / 18 | **Phase 3c** font sizes for the Action / Rule editors; fall back to `action_popup_font_size`. |
|
||||
| `fonts.panel_row_font_size` / `panel_title_font_size` | 16 / 18 | **Phase 3c** per-row summary/number label and panel title label sizes; `fonts.panel_title_bold` (default `true`) bolds panel titles. |
|
||||
| `grid.snap_size` | 15.0 | Initial default grid size for the Size spinbox (first run). |
|
||||
| `mode_colors.edit_accent` / `direct_accent` / `play_accent` | `#22c6ff` / `#ffb300` / `#33dd77` | Mode badge pill bg, the Direct viewfinder frame, the active mode-segment text, and tooltip border. |
|
||||
| `mode_colors.guide_line` | `#22c6ff` | The terrain drag-painting dashed guide line (`StagePlacementOverlay.guide_line_color`). |
|
||||
|
||||
`StageDirectorVisuals.set_style(cfg)` applies the `fonts` keys onto instance vars (`badge_icon_size`, `badge_number_size`, `badge_radius`, `rule_label_font_size`) whose defaults equal the old constants, so behavior is unchanged when no theme is present.
|
||||
|
||||
**Phase 3c theming (font styles/sizes):** the Phase 3c widgets now accept an `apply_font(ui_font, emoji_font, sizes)` call — `QueuePanel`, `RulePanel`, `ActionEditor`, and `RuleEditor` (see §23) each expose it (mirroring `AssetSelector.apply_font`), and `SandboxStage._build_ui()` invokes it **after** `add_child(...)`. Per-widget sizes come from the `*_panel_font_size` / `*_editor_font_size` / `panel_row_font_size` / `panel_title_font_size` keys; bold/italic style flags (`panel_title_bold`, `rule_label_bold`, `badge_bold`) and a widget's optional `{size, bold, italic}` object form are applied via the `ui_font_bold` / `ui_font_italic` `FontVariation`-derived font. The `PopupMenu`s (rig/waypoint context) keep `_apply_popup_theme()`, extended to honour `action_popup_emoji_size` and the `action_popup` object form. Authoritative schema: `docs/phase_3c_editor_spec.md` §14.
|
||||
The short version: edit `res://sandbox_theme.json`, restart the Sandbox scene
|
||||
to reload it, and remember that the live grid size/snap/grid-visibility remain
|
||||
in `user://sandbox_settings.json`. Missing or malformed theme data falls back
|
||||
to built-in defaults; missing fonts fall back to `ThemeDB.fallback_font` with a
|
||||
warning. Speech font/size/emoji lists are reusable-widget data reserved for a
|
||||
future speech-customization UI and do not yet alter saved speech actions.
|
||||
|
||||
**Director-context rule-connector refresh (bugfix):** `SandboxStage._on_transform_committed()` now calls `StageDirectorVisuals.mark_dirty()` after a move/rotate, so **translating a `TriggerArea` (or any rule-anchoring object) moves its dashed connector and ⚡/→ badges** to the new position on drag end. (Rule anchors were already computed live each `_draw()`; the missing `mark_dirty()` was leaving them stale because a `_draw()` never ran.) Deleting a referenced area already triggers `_cleanup_rules_for_nodes → set_rules → mark_dirty`.
|
||||
|
||||
@@ -740,13 +718,13 @@ The Phase 3a walk could **jitter up/down at a waypoint** instead of stopping. Ro
|
||||
|
||||
The result: `mode` stays constant for the whole walk, exactly one `arrived` fires, the rig's `global_position` is unchanged after arrival, and the walk/body-bob animation stops cleanly. `DEBUG_WALK` / `DEBUG_STAGE` (off by default) can be enabled to capture the `mode`/`dist`/`next`/`final` trace at arrival.
|
||||
|
||||
#### 21.5 Head LookAt solver fix (`master_rig.tscn`)
|
||||
#### 21.5 Head LookAt solver fix (`stickman_rig.tscn`)
|
||||
|
||||
`master_rig.tscn`'s Head `SkeletonModification2DLookAt` now uses a **full-range, non-inverted band solved in global space** (`constraint_angle_min = -180`, `constraint_angle_max = 180`, `constraint_invert = false`, `constraint_in_localspace = false`). Under the previous ~55°-clamped, inverted, local-space band, the aim solver could oscillate frame-to-frame as the look direction crossed the band boundary, causing a per-frame **mirror** of the head rather than smooth convergence. With the full-range global band there is no boundary to cross, so dragging the Head IK handle converges cleanly onto the aim point (see §14 Phase 9 Round 7).
|
||||
`stickman_rig.tscn`'s Head `SkeletonModification2DLookAt` now uses a **full-range, non-inverted band solved in global space** (`constraint_angle_min = -180`, `constraint_angle_max = 180`, `constraint_invert = false`, `constraint_in_localspace = false`). Under the previous ~55°-clamped, inverted, local-space band, the aim solver could oscillate frame-to-frame as the look direction crossed the band boundary, causing a per-frame **mirror** of the head rather than smooth convergence. With the full-range global band there is no boundary to cross, so dragging the Head IK handle converges cleanly onto the aim point (see §14 Phase 9 Round 7).
|
||||
|
||||
### 22. Asset Library — Stickman & Prop Selector Grids (Phase 3b)
|
||||
|
||||
**Phase 3b** replaces the Sandbox Stage Builder's hard-coded single-stickman and single-prop palette buttons (**Crate** / **Ball** / always-`test.stk` **Stickman**) with **visual selector grids**: clicking **Stickman** or **Prop** opens a modal grid popup (`PopupPanel`) of selectable assets; picking one sets the spawner's session selection and enters placement mode with that asset's ghost. It is **not wired into the editor** — run via **F6** on `res://scenes/sandbox_stage.tscn`. **No `.stk` format change** (the `.stk` schema below is untouched this phase). Pixel rendering (thumbnails) is **manual/F6 verification only**; headless tests never assert on pixels.
|
||||
**Phase 3b** replaces the Sandbox Stage Builder's hard-coded single-stickman and single-prop palette buttons (**Crate** / **Ball** / always-`test.stk` **Stickman**) with **visual selector grids**: clicking **Stickman** or **Prop** opens a modal grid popup (`PopupPanel`) of selectable assets; picking one sets the spawner's session selection and enters placement mode with that asset's ghost. It is **not wired into the editor** — run via **F6** on `res://scenes/stage/sandbox_stage.tscn`. **No `.stk` format change** (the `.stk` schema below is untouched this phase). Pixel rendering (thumbnails) is **manual/F6 verification only**; headless tests never assert on pixels.
|
||||
|
||||
**Workflow:** press the **Stickman** or **Prop** palette button → the grid opens (modal `PopupPanel`, ESC-closeable) → click a cell → the selection is cached session-only, the grid closes, and placement mode begins (ghost of the selected asset appears). Placing repeats the **selected** asset; switching selection re-opens the grid. `Ground`/`Ramp`/`Step` and `Area` remain direct placement buttons, unchanged.
|
||||
|
||||
@@ -754,12 +732,12 @@ The result: `mode` stays constant for the whole walk, exactly one `arrived` fire
|
||||
|
||||
| Grid | Backing | Cells | Details |
|
||||
|---|---|---|---|
|
||||
| **Stickman** | `StickmanLibrary.scan()` of `res://stickmen/*.stk` | one per `.stk` (name = `stickman_name` else filename basename) | Rig-rendered thumbnail per cell; **Browse…** (`*.stk` `FileDialog`) selects an arbitrary path; **Refresh** rescans; **empty-state** label when no files; **single-item skip** — exactly one file bypasses the grid and places directly |
|
||||
| **Stickman** | `StickmanLibrary.scan()` of `res://content/stickmen/*.stk` | one per `.stk` (name = `stickman_name` else filename basename) | Rig-rendered thumbnail per cell; **Browse…** (`*.stk` `FileDialog`) selects an arbitrary path; **Refresh** rescans; **empty-state** label when no files; **single-item skip** — exactly one file bypasses the grid and places directly |
|
||||
| **Prop** | `PropLibrary` (4 static templates) | Crate/Wood, Ball/Rubber, Plank/Metal, Triangle/Cardboard | Thumbnail + name + **material badge**; always a single page |
|
||||
|
||||
**Selection is session-only:** the chosen `selected_stickman_path` / `selected_prop_id` live in memory on `StageSpawner`, persist across `EDIT ⇄ DIRECT ⇄ PLAY` toggles, and reset on scene reload. **No disk save** (`user://sandbox_settings.json` is not extended). If the currently selected stickman path is no longer in the scan, the first entry is selected instead on open/refresh.
|
||||
|
||||
**Selector grid (`AssetSelector` / `scenes/asset_selector.tscn`):** a `PopupPanel` root (`exclusive = true`) built as a minimal shell — authored title bar, empty `GridContainer`, footer (`Prev` / page label / `Next` / `Browse…` / `Refresh` / `Close`) — with **all dynamic per-cell content** (texture + name + material badge) built in code at runtime. `open(kind, entries)` titles the popup ("Choose Your Stickman" / "Choose a Prop"), hides Browse/Refresh for props, and `popup_centered()`. Pagination slices **12/page (4×3)** with Prev/Next hidden when a single page; a static pure `page_bounds(total, page, page_size)` helper backs the slicing. Empty state shows a "no stickmen found" label instead of an empty grid. No cell is pre-highlighted on open (the previous selection-highlight border was removed). The popup re-centers on window resize (`size_changed` → `popup_centered()` while visible). Signals: `item_selected(entry)`, `cancelled()`, `browse_requested()`, `refresh_requested()`.
|
||||
**Selector grid (`AssetSelector` / `scenes/stage/asset_selector.tscn`):** a `PopupPanel` root (`exclusive = true`) built as a minimal shell — authored title bar, empty `GridContainer`, footer (`Prev` / page label / `Next` / `Browse…` / `Refresh` / `Close`) — with **all dynamic per-cell content** (texture + name + material badge) built in code at runtime. `open(kind, entries)` titles the popup ("Choose Your Stickman" / "Choose a Prop"), hides Browse/Refresh for props, and `popup_centered()`. Pagination slices **12/page (4×3)** with Prev/Next hidden when a single page; a static pure `page_bounds(total, page, page_size)` helper backs the slicing. Empty state shows a "no stickmen found" label instead of an empty grid. No cell is pre-highlighted on open (the previous selection-highlight border was removed). The popup re-centers on window resize (`size_changed` → `popup_centered()` while visible). Signals: `item_selected(entry)`, `cancelled()`, `browse_requested()`, `refresh_requested()`.
|
||||
|
||||
**Thumbnails (rig-accurate, cached):** each 200×200 thumbnail is rendered **lazily, one per frame**, by a `Node` renderer owning a persistent offscreen `SubViewport` (`transparent_bg`, `UPDATE_ALWAYS`) with an enabled in-viewport `Camera2D`:
|
||||
|
||||
@@ -778,30 +756,30 @@ The result: `mode` stays constant for the whole walk, exactly one `arrived` fire
|
||||
|
||||
**Palette integration & Esc priority:** `_on_palette_toggled` routes `stickman`/`prop` presses to `_open_selector(id)` (not straight to `set_placement_mode`); un-pressing while the matching selector is open closes it. While the grid is open a **dim backdrop** (`_selector_dim`, a black `ColorRect` at `SELECTOR_DIM_ALPHA` = 0.5, mouse-ignoring, on the UI `CanvasLayer` behind the selector) is shown. `_open_selector` forces the palette button pressed, performs the single-item skip, and (for stickman) reselects the first entry when the selected path is absent. On `item_selected` the spawner's `selected_stickman_path`/`selected_prop_id` are set, the selector closes, and placement begins. `Browse…` builds a one-off entry via `StickmanLibrary.make_entry(path)` (toast on failure). Esc is handled in the `AssetSelector` (`_unhandled_input` → `cancelled`) and by the stage in its existing **Esc priority chain** — rule step → pending walk target → terrain drag → **selector** → DIRECT → placement → selection. An outside-click that closes the modal popup fires its `popup_hide` signal, which is routed to `_on_selector_cancelled()` (idempotency-guarded) so it likewise un-presses the palette button. While the selector is open, `_handle_world_click` / `_handle_mouse_motion` early-return (belt-and-suspenders on top of the modal `PopupPanel`).
|
||||
|
||||
**New scripts:** `stickman_library.gd` / `prop_library.gd` / `thumbnails/thumbnail_cache.gd` / `thumbnails/stickman_thumbnail.gd` / `thumbnails/prop_thumbnail.gd` / `asset_selector.gd` (+ `scenes/asset_selector.tscn`). **Modified:** `stage_spawner.gd` (registry `crate`/`ball` → `prop`; `selected_stickman_path`/`selected_prop_id` session state; per-path `_stickman_cache`; new `get_selected_stickman_path()`/`get_selected_prop_id()` getters), `sandbox_stage.gd` (selector integration), and `tests/test_phase4b1_fixes.gd` (`spawn("crate")` → `spawn("prop")`).
|
||||
**New scripts:** `stickman_library.gd` / `prop_library.gd` / `thumbnails/thumbnail_cache.gd` / `thumbnails/stickman_thumbnail.gd` / `thumbnails/prop_thumbnail.gd` / `asset_selector.gd` (+ `scenes/stage/asset_selector.tscn`). **Modified:** `stage_spawner.gd` (registry `crate`/`ball` → `prop`; `selected_stickman_path`/`selected_prop_id` session state; per-path `_stickman_cache`; new `get_selected_stickman_path()`/`get_selected_prop_id()` getters), `sandbox_stage.gd` (selector integration), and `tests/test_phase4b1_fixes.gd` (`spawn("crate")` → `spawn("prop")`).
|
||||
|
||||
**Verification:** new headless suite `tests/test_phase3b_library.gd` (`extends SceneTree`, no pixel assertions) covering `StickmanLibrary.scan()`/corrupt-skip/`make_entry`, `PropLibrary.get_entries()`/`get_default_id()`, the `StageSpawner` registry ids (`ground/ramp/step/prop/stickman/area`), `_spawn_prop`/`_spawn_stickman` honoring `selected_prop_id`/`selected_stickman_path`, `ThumbnailCache` key/path formatting, `AssetSelector` pagination math (`PAGE_SIZE == 12`), and scene-load checks. Spec: `docs/phase_3b_asset_grid_spec.md`.
|
||||
**Verification:** new headless suite `tests/test_phase3b_library.gd` (`extends SceneTree`, no pixel assertions) covering `StickmanLibrary.scan()`/corrupt-skip/`make_entry`, `PropLibrary.get_entries()`/`get_default_id()`, the `StageSpawner` registry ids (`ground/ramp/step/prop/stickman/area`), `_spawn_prop`/`_spawn_stickman` honoring `selected_prop_id`/`selected_stickman_path`, `ThumbnailCache` key/path formatting, `AssetSelector` pagination math (`PAGE_SIZE == 12`), and scene-load checks. Spec: `docs/specs/phase_3b_asset_grid_spec.md`.
|
||||
|
||||
### 23. Editor Tools — Action & Rule Editing (Phase 3c)
|
||||
|
||||
**Phase 3c** makes the Sandbox Stage's **action queues and event rules fully editable**. Where Phase 3a let directors only *append* actions and Phase 4 only *create/delete* rules, Phase 3c adds edit / delete / drag-reorder for both, a **waypoint right-click context menu** with visual walk re-placement and insert-before/after, and both a **full** and a **consequence-only** rule editor. The entire system is **registry-driven** — the action and trigger templates live in two const registries, and the panels/editors generate their UI from them, so a future action/trigger type is a one-entry append. It is **not wired into the editor** — run via **F6** on `res://scenes/sandbox_stage.tscn`. **No `.stk` format change.**
|
||||
**Phase 3c** makes the Sandbox Stage's **action queues and event rules fully editable**. Where Phase 3a let directors only *append* actions and Phase 4 only *create/delete* rules, Phase 3c adds edit / delete / drag-reorder for both, a **waypoint right-click context menu** with visual walk re-placement and insert-before/after, and both a **full** and a **consequence-only** rule editor. The entire system is **registry-driven** — the action and trigger templates live in two const registries, and the panels/editors generate their UI from them, so a future action/trigger type is a one-entry append. It is **not wired into the editor** — run via **F6** on `res://scenes/stage/sandbox_stage.tscn`. **No `.stk` format change.**
|
||||
|
||||
**New scripts:**
|
||||
|
||||
| File | `class_name` / extends | Responsibility |
|
||||
|---|---|---|
|
||||
| `res://scripts/action_registry.gd` | `ActionRegistry` / `RefCounted` | Registry of the 5 action templates (`walk_to`/`speak`/`wait`/`ragdoll`/`recover`: label, icon, param spec). Static accessors `types()` / `has_type` / `label` / `icon`, plus `to_rule_action()` / `from_rule_action()` (flat queue-action ⇄ rule-action shape conversions) and `summarize()`. |
|
||||
| `res://scripts/trigger_registry.gd` | `TriggerRegistry` / `RefCounted` | Registry of the 5 trigger templates (label, icon, `target_type`: `waypoint`/`action_type`/`none`/`area`/`prop`). Static `types()` / `has_type` / `label` / `icon` / `target_type` / `summarize()`. |
|
||||
| `res://scripts/queue_panel.gd` | `QueuePanel` / `PopupPanel` | Action Queue panel (scrollable list of one stickman's actions, each with ✎ / ✕ / drag-to-reorder ≡). Mutations delegate to the stage via signals; reorders call the rig's `remove_action`/`insert_action`. Root of `scenes/queue_panel.tscn`. |
|
||||
| `res://scripts/rule_panel.gd` | `RulePanel` / `PopupPanel` | Rule list panel filtered by the stage (source stickman **or** a waypoint), with ✎ / ✕ / drag-to-reorder and **Add Rule** / **Clear All**. Reordering emits the new order of the *displayed* rule ids; the stage maps them back onto its full `_event_rules`, preserving un-filtered rules' positions. Root of `scenes/rule_panel.tscn`. |
|
||||
| `res://scripts/action_editor.gd` | `ActionEditor` / `PopupPanel` | Single-action property editor (add & edit). Type dropdown + param fields are generated from `ActionRegistry`. A `walk_to` target is captured on the stage (`target_requested()` → the stage hides the editor, captures a click, calls `set_walk_target()`). |
|
||||
| `res://scripts/rule_editor.gd` | `RuleEditor` / `PopupPanel` | Rule editor in two modes — **`full`** (trigger type + target + actions all editable) and **`consequence`** (trigger read-only; only the actions editable). Trigger targets and action actors are captured on the stage via signals. |
|
||||
| `res://scripts/waypoint_context.gd` | `WaypointContext` / `PopupMenu` | Right-click menu for a `walk_to` waypoint: **✎ Edit this Walk**, **✕ Delete this Walk**, **⬆ Insert action before**, **⬇ Insert action after**, and **⚡ Edit Trigger Rules** (enabled + shows a count when rules target this waypoint). Item ids: `EDIT_WALK`/`DELETE_WALK`/`INSERT_BEFORE`/`INSERT_AFTER`/`EDIT_TRIGGER_RULES`. |
|
||||
| `res://scenes/queue_panel.tscn`, `rule_panel.tscn`, `action_editor.tscn`, `rule_editor.tscn` | minimal shells | Each `.tscn` is a bare `PopupPanel` + root script; **all UI is built in code** at `_ready()` (consistent with the `asset_selector.tscn` pattern). |
|
||||
| `res://scripts/stage/action_registry.gd` | `ActionRegistry` / `RefCounted` | Registry of the 5 action templates (`walk_to`/`speak`/`wait`/`ragdoll`/`recover`: label, icon, param spec). Static accessors `types()` / `has_type` / `label` / `icon`, plus `to_rule_action()` / `from_rule_action()` (flat queue-action ⇄ rule-action shape conversions) and `summarize()`. |
|
||||
| `res://scripts/stage/trigger_registry.gd` | `TriggerRegistry` / `RefCounted` | Registry of the 5 trigger templates (label, icon, `target_type`: `waypoint`/`action_type`/`none`/`area`/`prop`). Static `types()` / `has_type` / `label` / `icon` / `target_type` / `summarize()`. |
|
||||
| `res://scripts/editors/stage/queue_panel.gd` | `QueuePanel` / `PopupPanel` | Action Queue panel (scrollable list of one stickman's actions, each with ✎ / ✕ / drag-to-reorder ≡). Mutations delegate to the stage via signals; reorders call the rig's `remove_action`/`insert_action`. Root of `scenes/editors/stage/queue_panel.tscn`. |
|
||||
| `res://scripts/editors/stage/rule_panel.gd` | `RulePanel` / `PopupPanel` | Rule list panel filtered by the stage (source stickman **or** a waypoint), with ✎ / ✕ / drag-to-reorder and **Add Rule** / **Clear All**. Reordering emits the new order of the *displayed* rule ids; the stage maps them back onto its full `_event_rules`, preserving un-filtered rules' positions. Root of `scenes/editors/stage/rule_panel.tscn`. |
|
||||
| `res://scripts/editors/stage/action_editor.gd` | `ActionEditor` / `PopupPanel` | Single-action property editor (add & edit). Type dropdown + param fields are generated from `ActionRegistry`. A `walk_to` target is captured on the stage (`target_requested()` → the stage hides the editor, captures a click, calls `set_walk_target()`). |
|
||||
| `res://scripts/editors/stage/rule_editor.gd` | `RuleEditor` / `PopupPanel` | Rule editor in two modes — **`full`** (trigger type + target + actions all editable) and **`consequence`** (trigger read-only; only the actions editable). Trigger targets and action actors are captured on the stage via signals. |
|
||||
| `res://scripts/stage/waypoint_context.gd` | `WaypointContext` / `PopupMenu` | Right-click menu for a `walk_to` waypoint: **✎ Edit this Walk**, **✕ Delete this Walk**, **⬆ Insert action before**, **⬇ Insert action after**, and **⚡ Edit Trigger Rules** (enabled + shows a count when rules target this waypoint). Item ids: `EDIT_WALK`/`DELETE_WALK`/`INSERT_BEFORE`/`INSERT_AFTER`/`EDIT_TRIGGER_RULES`. |
|
||||
| `res://scenes/editors/stage/queue_panel.tscn`, `rule_panel.tscn`, `action_editor.tscn`, `rule_editor.tscn` | minimal shells | Each `.tscn` is a bare `PopupPanel` + root script; **all UI is built in code** at `_ready()` (consistent with the `asset_selector.tscn` pattern). |
|
||||
|
||||
**Modified scripts:** `sandbox_stage.gd` (Phase 3c wiring) and `stage_director_visuals.gd` (waypoint action hit-testing + pulsing edit highlight + rule-label click → editor).
|
||||
|
||||
**Theming:** the four Phase 3c widgets above are themeable — each accepts an `apply_font(ui_font, emoji_font, sizes)` call driven by the extended `sandbox_theme.json` `fonts` block (style variants `ui_font_bold`/`ui_font_italic`, per-widget `queue/rule_panel_font_size`, `action/rule_editor_font_size`, `panel_row_font_size`/`panel_title_font_size`, style flags `panel_title_bold`/`rule_label_bold`/`badge_bold`, and the optional `action_popup` `{size, bold, italic}` object form; `action_popup_emoji_size` is now consumed). See §21.3 and `docs/phase_3c_editor_spec.md` §14.
|
||||
**Theming:** the four Phase 3c widgets above are themeable — each accepts an `apply_font(ui_font, emoji_font, sizes)` call driven by the extended `sandbox_theme.json` `fonts` block (style variants `ui_font_bold`/`ui_font_italic`, per-widget `queue/rule_panel_font_size`, `action/rule_editor_font_size`, `panel_row_font_size`/`panel_title_font_size`, style flags `panel_title_bold`/`rule_label_bold`/`badge_bold`, and the optional `action_popup` `{size, bold, italic}` object form; `action_popup_emoji_size` is now consumed). See §21.3 and `docs/specs/phase_3c_editor_spec.md` §14.
|
||||
|
||||
**Entry points:**
|
||||
|
||||
@@ -828,7 +806,19 @@ The result: `mode` stays constant for the whole walk, exactly one `arrived` fire
|
||||
& "C:\Godot4\Godot_v4.7.1-stable_win64_console.exe" --headless --script res://tests/test_phase3c_editor.gd --path .
|
||||
```
|
||||
|
||||
Spec: `docs/phase_3c_editor_spec.md`.
|
||||
Spec: `docs/specs/phase_3c_editor_spec.md`.
|
||||
|
||||
### 24. Prop Interactions and Throw Planning (Phase 11)
|
||||
|
||||
The Sandbox Stage action queue supports one-hand prop pickup, drop, and targeted throws. In **Direct**, select a stickman and add or edit **Pick Up Prop**, **Drop Prop**, or **Throw Prop** in its action queue. A pickup selects a stage prop and a hand (`Auto`, `Left`, or `Right`); a throw captures a stage-world point.
|
||||
|
||||
**Throw target and guide:**
|
||||
|
||||
- The cursor point is the requested target. The effective target is clamped to **3,600 px from the stickman's root**; if the cursor is farther away, the guide ends at the capped point while still marking the cursor position.
|
||||
- The solver accounts for stage gravity and chooses a valid descending arc whose release speed does not exceed **2,100 px/s**. Upward targets are supported when reachable; gravity can reduce their reachable distance. Targets that cannot be reached within the solver's speed and flight-time limits are shown as unreachable.
|
||||
- The guide is clipped at the first prop/world collision. In open air, it ends at the selected target; the prop continues under normal physics after that point.
|
||||
|
||||
**Queue-aware editing preview:** when editing a queued throw, the planning guide looks at earlier actions in that queue. If an earlier pickup can provide the prop, the preview uses its grip and hand and estimates the pickup approach when needed. A hint such as **“Assumes Step 2 pickup succeeds.”** identifies the assumption; uncertain preceding actions label the guide as estimated. This preview does not run the pickup or change live prop, rig, or queue state. If no held or planned prop can be resolved, the guide is replaced by a neutral marker and an informational hint rather than a misleading trajectory. At runtime, the throw is recalculated from the actual prop, actor position, and release pose.
|
||||
|
||||
## File format (`.stk`)
|
||||
|
||||
@@ -893,7 +883,7 @@ Files are UTF-8 JSON, pretty-printed with tab indentation. The format is version
|
||||
| `version` | `string` | Format version. Currently `"1.5"`. Loading supports `"1.0"`–`"1.5"` (auto-migrated). |
|
||||
| `stickman_name` | `string` | Optional display name for the figure. |
|
||||
| `part_order` | `array[string]` | **Phase 5.** Render/Z-order of parts in the Whole Stickman preview, front-to-back semantics per array position (first = back, last = front). Absent on v1.0–v1.2 files; defaults to the internal part-key order when missing. |
|
||||
| `proportions` | `object` | **Phase 8.** Rig bone lengths used by the runtime `StkRigAdapter`. Object with 5 float keys: `upper_arm_length` (168.0), `lower_arm_length` (200.0), `upper_leg_length` (200.0), `lower_leg_length` (200.0), `torso_length` (391.5). Hardcoded **master-rig rest-pose constants** (from `master_rig.tscn`), not measured from the user's shapes. Write-only metadata — never read back on load. |
|
||||
| `proportions` | `object` | **Phase 8.** Rig bone lengths used by the runtime `StkRigAdapter`. Object with 5 float keys: `upper_arm_length` (168.0), `lower_arm_length` (200.0), `upper_leg_length` (200.0), `lower_leg_length` (200.0), `torso_length` (391.5). Hardcoded **master-rig rest-pose constants** (from `stickman_rig.tscn`), not measured from the user's shapes. Write-only metadata — never read back on load. |
|
||||
| `body_parts` | `object` | Map of `body_part_name → shape` objects. Keyed by the 10 internal part names below. |
|
||||
| `metadata.created_at` | `string` | Timestamp written on save. |
|
||||
| `metadata.modified_at` | `string` | Timestamp written on save. |
|
||||
@@ -930,6 +920,86 @@ Each entry in the `shapes` array:
|
||||
|
||||
> On load, parts missing from the file fall back to built-in default preview positions. v1.0 files have `closed` inferred from `shape_type` and `vertex_flags` default to all zeros. v1.0/v1.1 files have their single shape wrapped in a `shapes` array and default `rotation`/`scale` applied. Files without `part_order` (v1.0–v1.2) use the default part-key order. Note that shape mirroring (Phase 5) rewrites the `points` array in place, so no new shape fields are required — the resulting vertices load identically across all supported versions.
|
||||
|
||||
## File format (`.prop`)
|
||||
|
||||
The **Prop Editor** (Phase 9, extended by Phase 10a) authors vector prop assets saved as `.prop` files, stored under `res://content/props/*.prop`. Files are UTF-8 JSON, pretty-printed with tab indentation, versioned, and designed to remain **backward compatible** — the format stores the editor's full multi-shape stack, while a deterministic converter (`PropFile.flatten_to_payload()`) collapses it into the single-shape payload `PropUtils.spawn_prop()` consumes at runtime (frontmost closed polygon → else circle → else the first shape; lines are editor-only and never become collision geometry).
|
||||
|
||||
In the Prop Editor, Arrange exposes **Transform Whole Prop**, **Normalize Size**,
|
||||
**Center Prop**, and **Show Stickman Guide** in that order. Whole-prop move,
|
||||
origin-based rotation, and uniform resize preview from a snapshot and commit once;
|
||||
Snap rounds movement, Ctrl snaps rotation to 15°, and Esc cancels. The Sandbox
|
||||
Stage has a separate single-prop corner scale gesture whose visual and collision
|
||||
bounds remain synchronized during PLAY.
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"prop_name": "My Crate",
|
||||
"material_preset": "wood",
|
||||
"shapes": [
|
||||
{
|
||||
"shape_type": "polygon",
|
||||
"points": [
|
||||
{ "x": -24.0, "y": -24.0 },
|
||||
{ "x": 24.0, "y": -24.0 },
|
||||
{ "x": 24.0, "y": 24.0 },
|
||||
{ "x": -24.0, "y": 24.0 }
|
||||
],
|
||||
"fill_color": "#8C6133",
|
||||
"outline_color": "#40290F",
|
||||
"outline_width": 2.0,
|
||||
"closed": true,
|
||||
"vertex_flags": [0, 0, 0, 0],
|
||||
"reshaped": false
|
||||
},
|
||||
{
|
||||
"shape_type": "circle",
|
||||
"radius": 24.0,
|
||||
"fill_color": "#E63333",
|
||||
"outline_color": "#590D0D",
|
||||
"outline_width": 2.0,
|
||||
"closed": true,
|
||||
"vertex_flags": [],
|
||||
"reshaped": false
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"created_at": "2026-09-18T10:00:00",
|
||||
"modified_at": "2026-09-18T10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Root object
|
||||
|
||||
| Key | Type | Description |
|
||||
|---|---|---|
|
||||
| `version` | `string` | Format version. Currently `"1.0"`. A non-`"1.0"` version is rejected on load. |
|
||||
| `prop_name` | `string` | Optional display name; an empty name falls back to the filename basename. |
|
||||
| `material_preset` | `string` | `"none"` \| `"wood"` \| `"rubber"` \| `"cardboard"` \| `"metal"`. Missing/invalid → `"none"`. Sets `mass` + `physics_material_override` (from `PropBlock`'s static preset tables). |
|
||||
| `shapes` | `array` | Array of shape objects (see below). Draw/Z-order = array order (first = back, last = front). |
|
||||
| `metadata.created_at` | `string` | Timestamp written on save. Write-only — ignored on load. |
|
||||
| `metadata.modified_at` | `string` | Timestamp written on save. Write-only — ignored on load. |
|
||||
|
||||
### Shape object
|
||||
|
||||
Each entry in the `shapes` array:
|
||||
|
||||
| Key | Type | Description |
|
||||
|---|---|---|
|
||||
| `shape_type` | `string` | `"polygon"`, `"circle"`, or `"line"`. Missing → `"polygon"`. |
|
||||
| `points` | `array` | Array of `{ "x": float, "y": float }` vertices — polygon/line only. Missing → `[]`. |
|
||||
| `radius` | `float` | Circle only; default `24.0`. |
|
||||
| `fill_color` / `outline_color` | `string` | Hex colour (`#RRGGBB` / `#RRGGBBAA`). Missing → the material tint (from `PropBlock.tint_for`). |
|
||||
| `outline_width` | `float` | Vector outline thickness. Default `2.0` (`PropBlock.DEFAULT_OUTLINE_WIDTH`). |
|
||||
| `closed` | `bool` | Polygon/circle `true` (filled); line `false` (outline-only). |
|
||||
| `vertex_flags` | `array[int]` | Same length as `points`. `0` = original vertex, `1` = user-created via "Create Point" (circles: empty). |
|
||||
| `reshaped` | `bool` | **Round 6.** `false` by default. Set `true` when the shape's vertices were edited (insert/remove/drag) or a circle was scaled non-uniformly; cleared by `set_shape_radius()`. The inspector hides primitive-specific fields (today: the circle Radius row) when set. Additive/backward-compatible — old files load as `false`. |
|
||||
|
||||
> **Backward compatibility rule:** unknown/missing keys fall back to defaults, and only **additive** keys may be introduced — never change the meaning of an existing key. The `reshaped` flag is the Round 6 addition; a `material_preset` of `"none"` and a missing `shape_type` both fall back gracefully.
|
||||
|
||||
> **Save-serialization note (Round 5):** point coordinates must be written through a Variant-coercion helper (`_coerce_points`). Assigning an `Array` of `{x,y}` dictionaries directly to a typed `PackedVector2Array` silently zeroes every coordinate in Godot — files saved by the Round 1–4 build were unrecoverable.
|
||||
|
||||
## Settings file (`user://settings.json`)
|
||||
|
||||
Phase 3 introduces a global settings file stored in Godot's **user data** directory (`user://`), separate from the `.stk` figure files. It persists the grid configuration and is versioned for future extensibility:
|
||||
@@ -958,53 +1028,61 @@ Behavior:
|
||||
- **Scope** — global; all body-part panels and the Whole Stickman preview share the same grid size and snap setting.
|
||||
- **Pan offsets are NOT persisted** — they reset on load, clear, and "Reset Views".
|
||||
|
||||
> **Prop Editor settings (Phase 9, separate files):** the standalone Prop Editor uses its own user-data files — `user://prop_editor_settings.json` (schema `{ "version": 1, "recent_props": [...] }`, the last up-to-5 opened/saved `.prop` paths, most-recent-first) and `user://prop_editor_autosave.prop` (the debounced 1.0 s autosave, written atomically via `PropFile.save_safe` with `metadata.autosave`/`source_path`/`modified_unix`; cleared on save/load/new/discard, kept after Restore, and dropped when stale at startup). The Prop Editor does **not** read or write `user://settings.json`.
|
||||
|
||||
## Project structure
|
||||
|
||||
| Path | Purpose |
|
||||
|---|---|
|
||||
| `res://project.godot` | Engine config; sets main scene to the editor and enabled features. |
|
||||
| `res://scenes/stickman_editor.tscn` | **Main scene** — editor layout, File/Edit/View menu bar, dialogs (`GridConfigDialog` + SpinBox), column containers (unique-name nodes). |
|
||||
| `res://scenes/body_part_panel.tscn` | Reusable single body-part editor panel (title, drawing area, context menu, `ColorPickerPopup`); expands vertically in its column. |
|
||||
| `res://scripts/stickman_editor.gd` | Editor controller — File/Edit/View menu actions, save/load/clear, JSON v1.5 serialization with multi-shape/rotation/scale, `part_order`, Phase 8 `proportions`/`pivot`/`length`, and Phase 9 Round 5 per-part `guide_offset` export, `settings.json` load/save, editor-wide shape clipboard (Copy/Paste across panels), broadcast of grid/snap settings to panels, Reset Views, populates panels, coordinates selection across panels. |
|
||||
| `res://scripts/stk_rig_adapter.gd` | **Phase 8, extended by Phase 9 (Rounds 4–6 bugfix).** Standalone runtime adapter (`class_name StkRigAdapter`, `static func apply(stk_data, rig)`): fits an instantiated `master_rig.tscn` to a loaded `.stk` by re-fitting the 8 limb bones (`Skeleton2D/Torso/...` `Bone2D` lengths + lower-bone origins), recalibrating the IK targets (`IK_Targets/Left|Right_Hand`, `Left|Right_Leg`), and mounting the `.stk` shapes onto the `Body/*` visual nodes (**one node per shape**: closed → single `Polygon2D` fill, open → single `Line2D` width 2). Shape mounting recomputes each part's bounding box at mount time (file `pivot`/`length` are no longer trusted) and derives a mount transform in the rig's **hanging convention** (joint anchor at the local origin, far end along local `+Y`) via `_compute_mount_transform()`: the part's preview transform `E(P) = C + R(rot)·S·(P − C)` (rotation + scale about the bbox center — the editor's exact Whole-Stickman-preview transform) is composed **first**, then the anchor/alignment θ/bone-fit scale are computed on the **transformed geometry**; rotations near ±180° (`|wrapf(rot)| > 0.75π`) swap the attachment to the drawn far end so flips are visible (e.g. the 180° torso shows its drawn neck end at the hip joint). Anchors (raw family rules): head/torso bottom-center `(cx, max_y)`, left horizontal limbs `(max_x, cy)`, right horizontal limbs `(min_x, cy)`, vertically drawn limbs top-center `(cx, min_y)`; alignment rotation θ maps the far end onto `+Y`; scaling is **anisotropic** — only the **auto-detected drawn long axis** (`width >= height`) scales to the bone length (`bone_length/extent`, guard `extent <= 0.0001` → `1.0`), cross-axis thickness stays 1:1. The `RemoteTransform2D` drivers keep `update_rotation = true`, so mounted shapes follow their bones under IK flexing. (Phase 9 Round 5) when a part dict carries `guide_offset`, the mounted geometry is translated by `t = (guide_offset + (A − C)).rotated(−c_node)`; (Phase 9 Round 6) when `guide_offset` is present, the joint anchor is whichever transformed end (`E(J_raw)` or `E(F_pt_raw)`) is nearest the part's guide joint (`center − guide_offset`), replacing the per-side family choice + 180° flip heuristic for that case (fixing the lower-left-leg and lower-right-arm, which were mounted 180° off their bones) — old files without the key keep the family rules + flip heuristic as the fallback in the driver's bone frame (A = mount anchor incl. the 180° flip rule, C = raw bbox center, `c_node` = driver `RemoteTransform2D.global_rotation`), so the harness reproduces the editor's guide-relative placement 1:1; old files without the key keep the offset-0 behavior (head falls back to `HEAD_CHIN_DROP`). Each `Body/*` container's scale is reset to `(1,1)` / rotation `0` (position untouched). (Phase 9) also fits the head bone (`Head.position.y = -proportions.torso_length`) while mounting the head as **full geometry** — it clears the head's inline `@tool` circle script and mounts `.stk` head shapes as `Line2D`/`Polygon2D`, and zeroes the Head driver's local position so the chin sits on the neck joint; the head mounts upright (`θ = 0`, `s = 1`) but still applies the part scale via `E` (face ≈160 px). `_mount_shapes()` also handles **v1.0/v1.1 single-shape** part dicts (wraps the part dict as one shape when it carries `points` but no `shapes` array), so older `.stk` files mount as visible geometry instead of being cleared. **Not used by the editor** — consumed by the runtime pipeline. |
|
||||
| `res://scripts/stickman_factory.gd` | **Phase 9.** Runtime entry point (`class_name StickmanFactory`, `extends RefCounted`); a static factory that turns a `.stk` file into a live, rigged `master_rig.tscn` instance. `load_stk(path)` reads + parses the file (`{}` + `push_warning` on failure); `spawn_from_data(stk_data)` instantiates `res://master_rig.tscn`, calls `StkRigAdapter.apply(stk_data, rig)`, and returns the rig root **typed as `StickmanRig`** (the rig now carries the `StickmanRig` root script); `spawn(path)` chains them (`null` on empty data). **Not used by the editor.** |
|
||||
| `res://scripts/stickman_rig.gd` | **Phase 9 Task 4.** `class_name StickmanRig`, `extends Node2D`; the runtime owner of facing direction, per-joint bone bend, `Body/*` z-order, and (Phase 10/11) the **kinematic-to-ragdoll** state switch with instant handoff + stand-up recovery, attached to the `master_rig.tscn` root `Master`. Exports a `facing_profile` preset (`FacingProfile` LEFT/RIGHT/FORWARD, default FORWARD) and four `@export_enum("Normal","Inverted")` per-joint bend vars (`left_arm_bend`/`right_arm_bend`/`left_leg_bend`/`right_leg_bend`), plus (Phase 11) `rest_timeout` (2.0 s) and `auto_recover` (true) exports. Non-`@tool`: resolves `Skeleton2D`/`Body`/bend joints at runtime, enables its own modification stack, and applies the profile (flag writes + `Body/*` reorder) in `_ready()` and setters. Signals `facing_profile_changed` / `bend_flag_changed` / `state_changed`; public API `set_facing_profile`/`get_facing_profile`, `set_joint_bend_flipped`/`get_joint_bend_flipped`, `get_bend_joints()`, `get_bend_joint_global_position()`, plus the ragdoll API `set_ragdoll(enabled)`/`toggle_ragdoll()`/`is_in_ragdoll()`/`request_recovery()` with `state` / `enum RigState { ANIMATED, RAGDOLL, RECOVERING }`. The recovery cycle is **pre-capture → ragdoll pose capture (7-ray ground probe) → mirror-aware re-anchor → snap (entry-captured chain offsets, `(−π, π]`-normalized bones, ankle clamp) → 2.0 s tween to the pre-ragdoll pose (arms/head bone-driven with `_natural_joint_target` for elbows; legs IK-driven) → finish (profile + bend flags + LookAt restored)**, with every per-joint bend decision editable in the `RAGDOLL_JOINT_BAND_LIMITS` / `RECOVERY_LEG_SIDE_FORCE` / `RECOVERY_JOINT_PATH` tables (Joint bend configuration (EDIT ME)). Diagnostics are gated behind `DEBUG_RECOVERY := false`. **Phase 6** adds PLAY-only `begin_terrain_fall()` / `set_terrain_following_enabled()`, center/per-foot TerrainBlock ray fans with self-proxy filtering, layered leg base markers vs live IK targets, continuous stance/swing blending with a predictive foot guard, accumulated root elevation/pelvis compensation across ramps/steps, and bounded free-fall. (Phase 4b) `_update_walking()` latches `_walk_mode` once per walk (`LATCH_PROBE_MAX_FRAMES` 6), unifies arrival on the final target at `ARRIVE_DISTANCE` (snap-on-arrive), steers to the final target when close, and re-asserts standing markers one frame after stop — fixing the walk-waypoint arrival jitter. (Phase 4.5) builds ten top-level `AnimatableBody2D` collision proxies, explicitly synchronizes them to the rendered `Body/*` transforms each physics frame, derives the head circle center/radius from mounted geometry (90 px minimum), and applies bounded, contact-quadrant-aware bone flinches that decay to captured base rotations. `snap_to_standing()` and the stage's PLAY→DIRECT reset restore authored transforms and pose state. Null-guarded (`push_warning` + skip). **Not used by the editor.** |
|
||||
| `res://scripts/create_animations.gd` | **Phase 11.** `@tool extends EditorScript`; a **standalone editor utility** (run manually with `master_rig.tscn` open; not auto-loaded or referenced at runtime) that supersedes the deleted `scripts/create_walk.gd`. `_run()` bakes `walk_left`/`walk_right` (same keyframes as the old script) and a one-shot `stand_up` (`POSE_DOWN` → `POSE_STANDING`, `STAND_UP_DURATION` 2.0, `loop_mode = LOOP_NONE`) into the open scene's default `AnimationLibrary`. The baked `stand_up` is an **authored reference only** — runtime recovery does not play it (`StickmanRig` tweens the IK targets directly from the captured ragdoll pose, since a fixed first keyframe can never match an arbitrary rest pose). `walk_right` is the **canonical walk** clip; `walk_left` remains baked in the library but is **not used at runtime** (facing is set explicitly and the rig root X-mirrors for LEFT). |
|
||||
| `res://scripts/test_harness.gd` | **Phase 9.** Standalone staging scene (run via **F6** on `res://scenes/test_harness.tscn`, not wired into the editor) for debugging bone scales, vector-drawing offsets, and IK limits in isolation. Top UI bar: "Open .stk…" / quick-select buttons (`stickmen/break.stk`, `stickmen/basic.stk`, `stickmen/test.stk`), "Show Bones" / "Show IK Handles" toggles, loaded-filename label. `SubViewport` world + enabled `Camera2D` (middle-mouse pan, wheel zoom, recenter on spawn); each load frees the previous rig and spawns a fresh one via `StickmanFactory.spawn()`. A world-space debug overlay draws true bone segments (joint dots + parent→child lines, with limb leaf bones drawn out to their IK targets so wrist/ankle joints are visible; the **Head** leaf is the exception — its target is a LookAt aim point, not a joint, so it draws a ~90 px segment along the bone's own direction instead) and colored IK-target markers (hands green, feet blue, head yellow, torso magenta) plus a semi-transparent yellow head-aim line; the **6** `Marker2D` IK targets are click-draggable — the 4 limb targets flex limbs live via `SkeletonModificationStack2D` TwoBoneIK (the rig self-enables its stack), the Torso target translates the whole rig via its `RemoteTransform2D`, and the Head target drives the head's LookAt aim rotation (Phase 9 Round 7). |
|
||||
| `res://scenes/test_harness.tscn` | **Phase 9.** Standalone staging scene backing `scripts/test_harness.gd` (run via **F6**; not wired into the editor). |
|
||||
| `res://scripts/terrain_block.gd` | **Vector Terrain System.** `class_name TerrainBlock`, `extends StaticBody2D` — a reusable vector terrain component building `Polygon2D` (fill) + `Line2D` (border) + `CollisionPolygon2D` (`BUILD_SOLIDS`, supports concave) children in code. Has a `spawn_id: String` property (set by `StageSpawner`) so same-template terrain overlaps are detectable during drag-painting. |
|
||||
| `res://scripts/terrain_utils.gd` | **Vector Terrain System.** `class_name TerrainUtils`, `extends RefCounted` — static `sanitize_points()` (grid snap → local `_simplify_polyline()` → clockwise enforcement) and a `spawn_block()` factory. |
|
||||
| `res://scripts/physics_test_harness.gd` | **Vector Terrain System / Dynamic Vector Props.** Standalone staging scene root building flat/ramp/step terrain via `TerrainUtils`, instantiating `master_rig.tscn`, spawning props via **1/2/3** (`PropUtils`), and adding a rig collision proxy (run via **F6**; not wired into the editor). A toggle-mode button flips the rig's kinematic-to-ragdoll mode via `_rig.set_ragdoll()`, plus (Phase 11) a **Rest** `SpinBox` (writes `_rig.rest_timeout`) and **"Recover Now"** button (`_rig.request_recovery()`); the rig's `state_changed` signal removes the proxy on `RAGDOLL` and re-adds it (idempotently) on `ANIMATED`/`RECOVERING`. |
|
||||
| `res://scenes/physics_test_harness.tscn` | **Vector Terrain System / Dynamic Vector Props.** Standalone staging scene backing `scripts/physics_test_harness.gd` (run via **F6**; not wired into the editor). |
|
||||
| `res://scripts/prop_block.gd` | **Dynamic Vector Props / Phase 4.5.** `class_name PropBlock`, `extends RigidBody2D` — a reusable physical prop building `Polygon2D` (fill) + `Line2D` (outline) + `CollisionPolygon2D`/`CollisionShape2D` (polygon/circle collision) children in code, with material presets (mass + friction/bounce), live-updating exports, contact monitoring, shape-cast CCD, and `collided(other, contact_normal, contact_position)` / `separated(other)` signals carrying world-space contact data. |
|
||||
| `res://scripts/prop_utils.gd` | **Dynamic Vector Props.** `class_name PropUtils`, `extends RefCounted` — static `create_box()` / `create_ball()` / `create_plank()` / `create_triangle()` primitive generators and a `spawn_prop()` factory (sanitizes polygon points via `TerrainUtils`). |
|
||||
| `res://scripts/sandbox_stage.gd` | **Sandbox Stage Builder / Phase 4.5.** `class_name SandboxStage`, `extends Node2D` — root controller: `enum StageMode { EDIT, DIRECT, PLAY }` state machine (freezes props with `FREEZE_MODE_KINEMATIC`; runs stickman queues + rags props/areas in PLAY), placement mode + terrain drag-painting, a grid spatial dictionary, camera pan/zoom, deletion, bottom status bar, mode badge/frame/cursors, the `res://sandbox_theme.json` loader, and signal fan-out (`mode_changed(mode: int)` / `object_placed` / `object_selected` / `object_deselected` / `object_deleted`). **Phase 3b** instantiates the `AssetSelector` popup + thumbnail renderers, owns the selector open/close flow and lazy per-frame thumbnail drain (§22). **Phase 3c** instantiates the queue/rule panels + editors + waypoint context, owns the unified `CaptureKind` target-capture system, the "Edit Queue…"/"Edit Rules…" + right-click context entry points, the shared confirmation dialog, and consequence-only rule editing (§23). **Phase 4.5** routes `PropBlock` physics contacts through proxy metadata, tracks per-part body IDs for pair debouncing, preserves rig→prop rule ordering, purges stale pairs on separation/deletion/ragdoll, and restores authored rig state when returning PLAY→DIRECT. Standalone staging scene run via **F6**; not wired into the editor. |
|
||||
| `res://scripts/stage_spawner.gd` | **Sandbox Stage Builder.** `class_name StageSpawner`, `extends RefCounted` — registry-driven factory (`Array[Dictionary]`, no id `match`); reuses `TerrainUtils` / `PropUtils` / `StickmanFactory`; centers terrain on its origin. Exposes `is_terrain_id()` / `get_template_aabb()` and tags spawned terrain with a `spawn_id`. `get_template_aabb(id)` mirrors `_spawn_terrain()`'s sanitize pass (`TerrainUtils.sanitize_points` at `TERRAIN_GRID_SIZE` 16), so the returned extent matches the real placed footprint — e.g. the 200-px-wide Ground template returns a **192-px** stride — and drives the block-unit paint stride, ghost sizing, and cell rasterization. **Phase 3b:** registry ids `ground/ramp/step/prop/stickman/area` (separate `crate`/`ball` removed); holds `selected_stickman_path` / `selected_prop_id` session state + a per-path `_stickman_cache`; `prop`/`stickman` spawn the **selected** asset (§22). |
|
||||
| `res://scripts/stickman_library.gd` | **Asset Library (Phase 3b).** `class_name StickmanLibrary`, `extends RefCounted` — scans `res://stickmen/*.stk` into `{path, name, data}` entries (corrupt/missing-`body_parts` skipped; name = `stickman_name` else filename basename); `make_entry(path)` for Browse-chosen paths. |
|
||||
| `res://scripts/prop_library.gd` | **Asset Library (Phase 3b).** `class_name PropLibrary`, `extends RefCounted` — static registry of the 4 prop templates (Crate/Wood, Ball/Rubber, Plank/Metal, Triangle/Cardboard); `get_default_id()` = `"crate"`. |
|
||||
| `res://scripts/asset_selector.gd` | **Asset Library (Phase 3b).** `class_name AssetSelector`, `extends PopupPanel` — grid popup controller (root of `scenes/asset_selector.tscn`): pagination 12/page, empty state, per-cell thumbnail + name + prop material badge, Browse/Refresh/Close, Esc. |
|
||||
| `res://scripts/thumbnails/stickman_thumbnail.gd` | **Asset Library (Phase 3b).** `class_name StickmanThumbnail`, `extends Node` — renders a parsed `.stk` to a `Texture2D` via the real rig in an offscreen `SubViewport`. |
|
||||
| `res://scripts/thumbnails/prop_thumbnail.gd` | **Asset Library (Phase 3b).** `class_name PropThumbnail`, `extends Node` — renders a prop template to a `Texture2D` (lightweight non-physics visual). |
|
||||
| `res://scripts/thumbnails/thumbnail_cache.gd` | **Asset Library (Phase 3b).** `class_name ThumbnailCache`, `extends RefCounted` — disk PNG cache (`user://thumbnails/`) keyed by basename+mtime (stickmen) / `id_v<PROP_VERSION>` (props); load/save/stale cleanup. |
|
||||
| `res://scenes/asset_selector.tscn` | **Asset Library (Phase 3b).** `PopupPanel` root + `asset_selector.gd` — minimal shell (title bar, empty grid, footer); dynamic cells built in code. |
|
||||
| `res://scripts/action_registry.gd` | **Editor Tools (Phase 3c).** `class_name ActionRegistry`, `extends RefCounted` — const registry of the 5 action templates (`walk_to`/`speak`/`wait`/`ragdoll`/`recover`: label/icon/params); static `types()`/`has_type`/`label`/`icon`, `to_rule_action()`/`from_rule_action()`, `summarize()`. |
|
||||
| `res://scripts/trigger_registry.gd` | **Editor Tools (Phase 3c).** `class_name TriggerRegistry`, `extends RefCounted` — const registry of the 5 trigger templates (label/icon/`target_type`); static `types()`/`has_type`/`label`/`icon`/`target_type`/`summarize()`. |
|
||||
| `res://scripts/queue_panel.gd` | **Editor Tools (Phase 3c).** `class_name QueuePanel`, `extends PopupPanel` — Action Queue panel (one stickman's actions with ✎/✕/drag-reorder); mutates the rig queue via its API. |
|
||||
| `res://scripts/rule_panel.gd` | **Editor Tools (Phase 3c).** `class_name RulePanel`, `extends PopupPanel` — rule list panel filtered by source stickman or waypoint, with ✎/✕/drag-reorder + Add Rule/Clear All. |
|
||||
| `res://scripts/action_editor.gd` | **Editor Tools (Phase 3c).** `class_name ActionEditor`, `extends PopupPanel` — add/edit single-action editor; type dropdown + params generated from `ActionRegistry`; `walk_to` target captured on stage. |
|
||||
| `res://scripts/rule_editor.gd` | **Editor Tools (Phase 3c).** `class_name RuleEditor`, `extends PopupPanel` — rule editor in **full** or **consequence-only** modes (trigger read-only); actions add/edit/remove. |
|
||||
| `res://scripts/waypoint_context.gd` | **Editor Tools (Phase 3c).** `class_name WaypointContext`, `extends PopupMenu` — right-click waypoint menu: Edit/Delete Walk, Insert action before/after, Edit Trigger Rules. |
|
||||
| `res://scenes/queue_panel.tscn` / `rule_panel.tscn` / `action_editor.tscn` / `rule_editor.tscn` | **Editor Tools (Phase 3c).** Minimal `PopupPanel` shells (bare root + root script); all UI is built in code at `_ready()`. |
|
||||
| `res://scripts/stage_selection.gd` | **Sandbox Stage Builder.** `class_name StageSelection`, `extends RefCounted` — hover/click/box selection via geometric world-space AABB hit-testing (frontmost `World` child wins; `RagdollBodyContainer` subtree excluded); `hover_changed` / `selection_changed` signals. |
|
||||
| `res://scripts/stage_gizmos.gd` | **Sandbox Stage Builder.** `class_name StageGizmos`, `extends Node2D` — hover highlight + selection outline + rotate ring via `_draw()` and distance-based hit-testing; objects are dragged directly (no move handle); drives `global_position` / `global_rotation`; emits `transform_committed`. |
|
||||
| `res://scripts/stage_grid.gd` | **Sandbox Stage Builder.** `class_name StageGrid`, `extends Node2D` — optional world-space grid overlay (major line every 5 cells) that pans/zooms with the camera; `grid_size` / `enabled` set by `SandboxStage`. |
|
||||
| `res://scripts/stage_placement_overlay.gd` | **Sandbox Stage Builder (Phase 4b).** `class_name StagePlacementOverlay`, `extends Node2D` — world-space overlay drawing the terrain drag-painting dashed guide line (`set_terrain_guide` / `clear_terrain_guide`) and the director action rubber-band trajectory + ghost marker (`set_action_trajectory` / `clear_action`); pure drawing, no hit-testing. |
|
||||
| `res://scenes/main.tscn` | **Startup wrapper** configured as `run/main_scene`; hosts the Stickman Editor. |
|
||||
| `res://scenes/editors/stickman/stickman_editor.tscn` | Stickman Editor layout, File/Edit/View menu bar, dialogs (`GridConfigDialog` + SpinBox), column containers (unique-name nodes). |
|
||||
| `res://scenes/editors/stickman/body_part_panel.tscn` | Reusable single body-part editor panel (title, drawing area, context menu, `ColorPickerPopup`); expands vertically in its column. |
|
||||
| `res://scripts/editors/stickman/stickman_editor.gd` | Editor controller — File/Edit/View menu actions, save/load/clear, JSON v1.5 serialization with multi-shape/rotation/scale, `part_order`, Phase 8 `proportions`/`pivot`/`length`, and Phase 9 Round 5 per-part `guide_offset` export, `settings.json` load/save, editor-wide shape clipboard (Copy/Paste across panels), broadcast of grid/snap settings to panels, Reset Views, populates panels, coordinates selection across panels. |
|
||||
| `res://scripts/characters/stickman/stk_rig_adapter.gd` | **Phase 8, extended by Phase 9 (Rounds 4–6 bugfix).** Standalone runtime adapter (`class_name StkRigAdapter`, `static func apply(stk_data, rig)`): fits an instantiated `stickman_rig.tscn` to a loaded `.stk` by re-fitting the 8 limb bones (`Skeleton2D/Torso/...` `Bone2D` lengths + lower-bone origins), recalibrating the IK targets (`IK_Targets/Left|Right_Hand`, `Left|Right_Leg`), and mounting the `.stk` shapes onto the `Body/*` visual nodes (**one node per shape**: closed → single `Polygon2D` fill, open → single `Line2D` width 2). Shape mounting recomputes each part's bounding box at mount time (file `pivot`/`length` are no longer trusted) and derives a mount transform in the rig's **hanging convention** (joint anchor at the local origin, far end along local `+Y`) via `_compute_mount_transform()`: the part's preview transform `E(P) = C + R(rot)·S·(P − C)` (rotation + scale about the bbox center — the editor's exact Whole-Stickman-preview transform) is composed **first**, then the anchor/alignment θ/bone-fit scale are computed on the **transformed geometry**; rotations near ±180° (`|wrapf(rot)| > 0.75π`) swap the attachment to the drawn far end so flips are visible (e.g. the 180° torso shows its drawn neck end at the hip joint). Anchors (raw family rules): head/torso bottom-center `(cx, max_y)`, left horizontal limbs `(max_x, cy)`, right horizontal limbs `(min_x, cy)`, vertically drawn limbs top-center `(cx, min_y)`; alignment rotation θ maps the far end onto `+Y`; scaling is **anisotropic** — only the **auto-detected drawn long axis** (`width >= height`) scales to the bone length (`bone_length/extent`, guard `extent <= 0.0001` → `1.0`), cross-axis thickness stays 1:1. The `RemoteTransform2D` drivers keep `update_rotation = true`, so mounted shapes follow their bones under IK flexing. (Phase 9 Round 5) when a part dict carries `guide_offset`, the mounted geometry is translated by `t = (guide_offset + (A − C)).rotated(−c_node)`; (Phase 9 Round 6) when `guide_offset` is present, the joint anchor is whichever transformed end (`E(J_raw)` or `E(F_pt_raw)`) is nearest the part's guide joint (`center − guide_offset`), replacing the per-side family choice + 180° flip heuristic for that case (fixing the lower-left-leg and lower-right-arm, which were mounted 180° off their bones) — old files without the key keep the family rules + flip heuristic as the fallback in the driver's bone frame (A = mount anchor incl. the 180° flip rule, C = raw bbox center, `c_node` = driver `RemoteTransform2D.global_rotation`), so the harness reproduces the editor's guide-relative placement 1:1; old files without the key keep the offset-0 behavior (head falls back to `HEAD_CHIN_DROP`). Each `Body/*` container's scale is reset to `(1,1)` / rotation `0` (position untouched). (Phase 9) also fits the head bone (`Head.position.y = -proportions.torso_length`) while mounting the head as **full geometry** — it clears the head's inline `@tool` circle script and mounts `.stk` head shapes as `Line2D`/`Polygon2D`, and zeroes the Head driver's local position so the chin sits on the neck joint; the head mounts upright (`θ = 0`, `s = 1`) but still applies the part scale via `E` (face ≈160 px). `_mount_shapes()` also handles **v1.0/v1.1 single-shape** part dicts (wraps the part dict as one shape when it carries `points` but no `shapes` array), so older `.stk` files mount as visible geometry instead of being cleared. **Not used by the editor** — consumed by the runtime pipeline. |
|
||||
| `res://scripts/characters/stickman/stickman_factory.gd` | **Phase 9.** Runtime entry point (`class_name StickmanFactory`, `extends RefCounted`); a static factory that turns a `.stk` file into a live, rigged `stickman_rig.tscn` instance. `load_stk(path)` reads + parses the file (`{}` + `push_warning` on failure); `spawn_from_data(stk_data)` instantiates `res://scenes/characters/stickman/stickman_rig.tscn`, calls `StkRigAdapter.apply(stk_data, rig)`, and returns the rig root **typed as `StickmanRig`** (the rig now carries the `StickmanRig` root script); `spawn(path)` chains them (`null` on empty data). **Not used by the editor.** |
|
||||
| `res://scripts/characters/stickman/stickman_rig.gd` | **Phase 9 Task 4.** `class_name StickmanRig`, `extends Node2D`; the runtime owner of facing direction, per-joint bone bend, `Body/*` z-order, and (Phase 10/11) the **kinematic-to-ragdoll** state switch with instant handoff + stand-up recovery, attached to the `stickman_rig.tscn` root `Master`. Exports a `facing_profile` preset (`FacingProfile` LEFT/RIGHT/FORWARD, default FORWARD) and four `@export_enum("Normal","Inverted")` per-joint bend vars (`left_arm_bend`/`right_arm_bend`/`left_leg_bend`/`right_leg_bend`), plus (Phase 11) `rest_timeout` (2.0 s) and `auto_recover` (true) exports. Non-`@tool`: resolves `Skeleton2D`/`Body`/bend joints at runtime, enables its own modification stack, and applies the profile (flag writes + `Body/*` reorder) in `_ready()` and setters. Signals `facing_profile_changed` / `bend_flag_changed` / `state_changed`; public API `set_facing_profile`/`get_facing_profile`, `set_joint_bend_flipped`/`get_joint_bend_flipped`, `get_bend_joints()`, `get_bend_joint_global_position()`, plus the ragdoll API `set_ragdoll(enabled)`/`toggle_ragdoll()`/`is_in_ragdoll()`/`request_recovery()` with `state` / `enum RigState { ANIMATED, RAGDOLL, RECOVERING }`. The recovery cycle is **pre-capture → ragdoll pose capture (7-ray ground probe) → mirror-aware re-anchor → snap (entry-captured chain offsets, `(−π, π]`-normalized bones, ankle clamp) → 2.0 s tween to the pre-ragdoll pose (arms/head bone-driven with `_natural_joint_target` for elbows; legs IK-driven) → finish (profile + bend flags + LookAt restored)**, with every per-joint bend decision editable in the `RAGDOLL_JOINT_BAND_LIMITS` / `RECOVERY_LEG_SIDE_FORCE` / `RECOVERY_JOINT_PATH` tables (Joint bend configuration (EDIT ME)). Diagnostics are gated behind `DEBUG_RECOVERY := false`. **Phase 6** adds PLAY-only `begin_terrain_fall()` / `set_terrain_following_enabled()`, center/per-foot TerrainBlock ray fans with self-proxy filtering, layered leg base markers vs live IK targets, continuous stance/swing blending with a predictive foot guard, accumulated root elevation/pelvis compensation across ramps/steps, and bounded free-fall. (Phase 4b) `_update_walking()` latches `_walk_mode` once per walk (`LATCH_PROBE_MAX_FRAMES` 6), unifies arrival on the final target at `ARRIVE_DISTANCE` (snap-on-arrive), steers to the final target when close, and re-asserts standing markers one frame after stop — fixing the walk-waypoint arrival jitter. (Phase 4.5) builds ten top-level `AnimatableBody2D` collision proxies, explicitly synchronizes them to the rendered `Body/*` transforms each physics frame, derives the head circle center/radius from mounted geometry (90 px minimum), and applies bounded, contact-quadrant-aware bone flinches that decay to captured base rotations. `snap_to_standing()` and the stage's PLAY→DIRECT reset restore authored transforms and pose state. Null-guarded (`push_warning` + skip). **Not used by the editor.** |
|
||||
| `res://scripts/tools/create_animations.gd` | **Phase 11.** `@tool extends EditorScript`; a **standalone editor utility** (run manually with `stickman_rig.tscn` open; not auto-loaded or referenced at runtime) that supersedes the deleted `scripts/create_walk.gd`. `_run()` bakes `walk_left`/`walk_right` (same keyframes as the old script) and a one-shot `stand_up` (`POSE_DOWN` → `POSE_STANDING`, `STAND_UP_DURATION` 2.0, `loop_mode = LOOP_NONE`) into the open scene's default `AnimationLibrary`. The baked `stand_up` is an **authored reference only** — runtime recovery does not play it (`StickmanRig` tweens the IK targets directly from the captured ragdoll pose, since a fixed first keyframe can never match an arbitrary rest pose). `walk_right` is the **canonical walk** clip; `walk_left` remains baked in the library but is **not used at runtime** (facing is set explicitly and the rig root X-mirrors for LEFT). |
|
||||
| `res://scripts/tools/test_harness.gd` | **Phase 9.** Standalone staging scene (run via **F6** on `res://scenes/tools/test_harness.tscn`, not wired into the editor) for debugging bone scales, vector-drawing offsets, and IK limits in isolation. Top UI bar: "Open .stk…" / quick-select buttons (`content/stickmen/break.stk`, `content/stickmen/basic.stk`, `content/stickmen/test.stk`), "Show Bones" / "Show IK Handles" toggles, loaded-filename label. `SubViewport` world + enabled `Camera2D` (middle-mouse pan, wheel zoom, recenter on spawn); each load frees the previous rig and spawns a fresh one via `StickmanFactory.spawn()`. A world-space debug overlay draws true bone segments (joint dots + parent→child lines, with limb leaf bones drawn out to their IK targets so wrist/ankle joints are visible; the **Head** leaf is the exception — its target is a LookAt aim point, not a joint, so it draws a ~90 px segment along the bone's own direction instead) and colored IK-target markers (hands green, feet blue, head yellow, torso magenta) plus a semi-transparent yellow head-aim line; the **6** `Marker2D` IK targets are click-draggable — the 4 limb targets flex limbs live via `SkeletonModificationStack2D` TwoBoneIK (the rig self-enables its stack), the Torso target translates the whole rig via its `RemoteTransform2D`, and the Head target drives the head's LookAt aim rotation (Phase 9 Round 7). |
|
||||
| `res://scenes/tools/test_harness.tscn` | **Phase 9.** Standalone staging scene backing `scripts/tools/test_harness.gd` (run via **F6**; not wired into the editor). |
|
||||
| `res://scripts/terrain/terrain_block.gd` | **Vector Terrain System.** `class_name TerrainBlock`, `extends StaticBody2D` — a reusable vector terrain component building `Polygon2D` (fill) + `Line2D` (border) + `CollisionPolygon2D` (`BUILD_SOLIDS`, supports concave) children in code. Has a `spawn_id: String` property (set by `StageSpawner`) so same-template terrain overlaps are detectable during drag-painting. |
|
||||
| `res://scripts/terrain/terrain_utils.gd` | **Vector Terrain System.** `class_name TerrainUtils`, `extends RefCounted` — static `sanitize_points()` (grid snap → local `_simplify_polyline()` → clockwise enforcement) and a `spawn_block()` factory. |
|
||||
| `res://scripts/tools/physics_test_harness.gd` | **Vector Terrain System / Dynamic Vector Props.** Standalone staging scene root building flat/ramp/step terrain via `TerrainUtils`, instantiating `stickman_rig.tscn`, spawning props via **1/2/3** (`PropUtils`), and adding a rig collision proxy (run via **F6**; not wired into the editor). A toggle-mode button flips the rig's kinematic-to-ragdoll mode via `_rig.set_ragdoll()`, plus (Phase 11) a **Rest** `SpinBox` (writes `_rig.rest_timeout`) and **"Recover Now"** button (`_rig.request_recovery()`); the rig's `state_changed` signal removes the proxy on `RAGDOLL` and re-adds it (idempotently) on `ANIMATED`/`RECOVERING`. |
|
||||
| `res://scenes/tools/physics_test_harness.tscn` | **Vector Terrain System / Dynamic Vector Props.** Standalone staging scene backing `scripts/tools/physics_test_harness.gd` (run via **F6**; not wired into the editor). |
|
||||
| `res://scripts/props/prop_block.gd` | **Dynamic Vector Props / Phase 4.5.** `class_name PropBlock`, `extends RigidBody2D` — a reusable physical prop building `Polygon2D` (fill) + `Line2D` (outline) + `CollisionPolygon2D`/`CollisionShape2D` (polygon/circle collision) children in code, with material presets (mass + friction/bounce), live-updating exports, contact monitoring, shape-cast CCD, and `collided(other, contact_normal, contact_position)` / `separated(other)` signals carrying world-space contact data. Also the single source of truth for the Prop Editor's inspector physics readouts. |
|
||||
| `res://scripts/editors/prop/prop_editor.gd` | **Prop Editor (Phase 9).** `class_name PropEditor`, `extends Control` — standalone vector-prop authoring controller (run via **F6** on `res://scenes/editors/prop/prop_editor.tscn`; **not** the main scene). Owns the 📁 File (🆕 New / 💾 Save / 📄 Save As… / 📂 Load… / 🕑 Recent) and 👁️ View (🔍 Reset View) menus, the top-right Grid spinbox + Snap checkbox, the centered Arrange/Reshape mode toolbar, the material-preset + per-shape inspector (physics readouts from `PropBlock`; hides the circle Radius row + shows a "reshaped" note when a shape's `reshaped` flag is set), the status bar, the window title builder, the exit dialog (💾 Save / 🗑️ Discard / ❌ Cancel), recent-props persistence (`user://prop_editor_settings.json`, max 5), and the debounced autosave/recovery pipeline (`user://prop_editor_autosave.prop` via `PropFile.save_safe`). Saves export a cached 200×200 thumbnail. |
|
||||
| `res://scripts/editors/prop/prop_canvas.gd` | **Prop Editor (Phase 9).** `class_name PropCanvas`, `extends Control` — multi-shape vector canvas: cursor-centered zoom/pan (wheel, pinch, middle-mouse), `EditMode { TRANSFORM, POINTS }` ("Arrange"/"Reshape") gating input + drawing only, rotation dot + corner scale crosses (Ctrl = 15° snap / aspect lock), color-matched vertex handles with Create/Remove Point (0.6 s flash), per-mode right-click menus, a local clipboard, mirror + z-order, the per-shape `reshaped` flag, sanitize-on-commit via `TerrainUtils`, and two-tone halo selection. |
|
||||
| `res://scripts/editors/prop/prop_file.gd` | **Prop Editor (Phase 9).** `class_name PropFile`, `extends RefCounted` — static `.prop` v1.0 schema + converters: `to_file_dict`/`from_file_dict` (round-trip, version rejection, missing-key defaults), `preset_to_string`/`from_string`, `sanitize_shape`, `flatten_to_payload` (frontmost closed polygon → circle → first shape), `save`/`load`, and the atomic `save_safe` (tmp/`.bak` swap). Points must be coerced via `_coerce_points` when serializing (Round 5). |
|
||||
| `res://scripts/editors/prop/prop_theme.gd` | **Prop Editor (Phase 9).** `class_name PropTheme`, `extends RefCounted` — validated loader for `res://prop_theme.json` (deep-merge, warn-once, clamped accessors); hierarchy theme file → `DEFAULT_CONFIG` → `PropBlock` constants. Physics is never themeable. Holds the Round 2–4 `ui` tokens (fonts, hit targets, colors). Applied through a **local** Theme only. |
|
||||
| `res://scenes/editors/prop/prop_editor.tscn` | **Prop Editor (Phase 9).** Standalone scene backing `scripts/editors/prop/prop_editor.gd` (run via **F6**; not the main scene): minimal shell (`%MenuBar` in `%TopRow` beside `%TopRightControls`, `%TopBar`/`%PropNameEdit`, `%MainLayout`/`%CanvasPanel`/`%CanvasArea`/`%ModeBar`/`%PropCanvas`, `%InspectorColumn`/`%InspectorList`, status bar, dialogs); UI built in code. |
|
||||
| `res://scripts/props/prop_utils.gd` | **Dynamic Vector Props.** `class_name PropUtils`, `extends RefCounted` — static `create_box()` / `create_ball()` / `create_plank()` / `create_triangle()` primitive generators and a `spawn_prop()` factory (sanitizes polygon points via `TerrainUtils`). `PropFile.flatten_to_payload()` produces the payload it consumes. |
|
||||
| `res://scripts/editors/stage/sandbox_stage.gd` | **Sandbox Stage Builder / Phase 4.5.** `class_name SandboxStage`, `extends Node2D` — root controller: `enum StageMode { EDIT, DIRECT, PLAY }` state machine (freezes props with `FREEZE_MODE_KINEMATIC`; runs stickman queues + rags and props/areas in PLAY), placement mode + terrain drag-painting, a grid spatial dictionary, camera pan/zoom, deletion, bottom status bar, mode badge/frame/cursors, the `res://sandbox_theme.json` loader, and signal fan-out (`mode_changed(mode: int)` / `object_placed` / `object_selected` / `object_deselected` / `object_deleted`). **Phase 3b** instantiates the `AssetSelector` popup + thumbnail renderers, owns the selector open/close flow and lazy per-frame thumbnail drain (§22). **Phase 3c** instantiates the queue/rule panels + editors + waypoint context, owns the unified `CaptureKind` target-capture system, the "Edit Queue…"/"Edit Rules…" + right-click context entry points, the shared confirmation dialog, and consequence-only rule editing (§23). **Phase 4.5** routes `PropBlock` physics contacts through proxy metadata, tracks per-part body IDs for pair debouncing, preserves rig→prop rule ordering, purges stale pairs on separation/deletion/ragdoll, and restores authored rig state when returning PLAY→DIRECT. Standalone staging scene run via **F6**; not wired into the editor. |
|
||||
| `res://scripts/stage/stage_spawner.gd` | **Sandbox Stage Builder.** `class_name StageSpawner`, `extends RefCounted` — registry-driven factory (`Array[Dictionary]`, no id `match`); reuses `TerrainUtils` / `PropUtils` / `StickmanFactory`; centers terrain on its origin. Exposes `is_terrain_id()` / `get_template_aabb()` and tags spawned terrain with a `spawn_id`. `get_template_aabb(id)` mirrors `_spawn_terrain()`'s sanitize pass (`TerrainUtils.sanitize_points` at `TERRAIN_GRID_SIZE` 16), so the returned extent matches the real placed footprint — e.g. the 200-px-wide Ground template returns a **192-px** stride — and drives the block-unit paint stride, ghost sizing, and cell rasterization. **Phase 3b:** registry ids `ground/ramp/step/prop/stickman/area` (separate `crate`/`ball` removed); holds `selected_stickman_path` / `selected_prop_id` session state + a per-path `_stickman_cache`; `prop`/`stickman` spawn the **selected** asset (§22). |
|
||||
| `res://scripts/characters/stickman/stickman_library.gd` | **Asset Library (Phase 3b).** `class_name StickmanLibrary`, `extends RefCounted` — scans `res://content/stickmen/*.stk` into `{path, name, data}` entries (corrupt/missing-`body_parts` skipped; name = `stickman_name` else filename basename); `make_entry(path)` for Browse-chosen paths. |
|
||||
| `res://scripts/props/prop_library.gd` | **Asset Library (Phase 3b).** `class_name PropLibrary`, `extends RefCounted` — static registry of the 4 prop templates (Crate/Wood, Ball/Rubber, Plank/Metal, Triangle/Cardboard); `get_default_id()` = `"crate"`. |
|
||||
| `res://scripts/shared/ui/asset_selector.gd` | **Asset Library (Phase 3b).** `class_name AssetSelector`, `extends PopupPanel` — grid popup controller (root of `scenes/stage/asset_selector.tscn`): pagination 12/page, empty state, per-cell thumbnail + name + prop material badge, Browse/Refresh/Close, Esc. |
|
||||
| `res://scripts/shared/thumbnails/stickman_thumbnail.gd` | **Asset Library (Phase 3b).** `class_name StickmanThumbnail`, `extends Node` — renders a parsed `.stk` to a `Texture2D` via the real rig in an offscreen `SubViewport`. |
|
||||
| `res://scripts/shared/thumbnails/prop_thumbnail.gd` | **Asset Library (Phase 3b).** `class_name PropThumbnail`, `extends Node` — renders a prop template to a `Texture2D` (lightweight non-physics visual). |
|
||||
| `res://scripts/shared/thumbnails/thumbnail_cache.gd` | **Asset Library (Phase 3b).** `class_name ThumbnailCache`, `extends RefCounted` — disk PNG cache (`user://thumbnails/`) keyed by basename+mtime (stickmen) / `id_v<PROP_VERSION>` (props); load/save/stale cleanup. |
|
||||
| `res://scenes/stage/asset_selector.tscn` | **Asset Library (Phase 3b).** `PopupPanel` root + `asset_selector.gd` — minimal shell (title bar, empty grid, footer); dynamic cells built in code. |
|
||||
| `res://scripts/stage/action_registry.gd` | **Editor Tools (Phase 3c).** `class_name ActionRegistry`, `extends RefCounted` — const registry of the 5 action templates (`walk_to`/`speak`/`wait`/`ragdoll`/`recover`: label/icon/params); static `types()`/`has_type`/`label`/`icon`, `to_rule_action()`/`from_rule_action()`, `summarize()`. |
|
||||
| `res://scripts/stage/trigger_registry.gd` | **Editor Tools (Phase 3c).** `class_name TriggerRegistry`, `extends RefCounted` — const registry of the 5 trigger templates (label/icon/`target_type`); static `types()`/`has_type`/`label`/`icon`/`target_type`/`summarize()`. |
|
||||
| `res://scripts/editors/stage/queue_panel.gd` | **Editor Tools (Phase 3c).** `class_name QueuePanel`, `extends PopupPanel` — Action Queue panel (one stickman's actions with ✎/✕/drag-reorder); mutates the rig queue via its API. |
|
||||
| `res://scripts/editors/stage/rule_panel.gd` | **Editor Tools (Phase 3c).** `class_name RulePanel`, `extends PopupPanel` — rule list panel filtered by source stickman or waypoint, with ✎/✕/drag-reorder + Add Rule/Clear All. |
|
||||
| `res://scripts/editors/stage/action_editor.gd` | **Editor Tools (Phase 3c).** `class_name ActionEditor`, `extends PopupPanel` — add/edit single-action editor; type dropdown + params generated from `ActionRegistry`; `walk_to` target captured on stage. |
|
||||
| `res://scripts/editors/stage/rule_editor.gd` | **Editor Tools (Phase 3c).** `class_name RuleEditor`, `extends PopupPanel` — rule editor in **full** or **consequence-only** modes (trigger read-only); actions add/edit/remove. |
|
||||
| `res://scripts/stage/waypoint_context.gd` | **Editor Tools (Phase 3c).** `class_name WaypointContext`, `extends PopupMenu` — right-click waypoint menu: Edit/Delete Walk, Insert action before/after, Edit Trigger Rules. |
|
||||
| `res://scenes/editors/stage/queue_panel.tscn` / `rule_panel.tscn` / `action_editor.tscn` / `rule_editor.tscn` | **Editor Tools (Phase 3c).** Minimal `PopupPanel` shells (bare root + root script); all UI is built in code at `_ready()`. |
|
||||
| `res://scripts/stage/stage_selection.gd` | **Sandbox Stage Builder.** `class_name StageSelection`, `extends RefCounted` — hover/click/box selection via geometric world-space AABB hit-testing (frontmost `World` child wins; `RagdollBodyContainer` subtree excluded); `hover_changed` / `selection_changed` signals. |
|
||||
| `res://scripts/stage/stage_gizmos.gd` | **Sandbox Stage Builder.** `class_name StageGizmos`, `extends Node2D` — hover highlight + selection outline + rotate ring via `_draw()` and distance-based hit-testing; objects are dragged directly (no move handle); drives `global_position` / `global_rotation`; emits `transform_committed`. |
|
||||
| `res://scripts/stage/stage_grid.gd` | **Sandbox Stage Builder.** `class_name StageGrid`, `extends Node2D` — optional world-space grid overlay (major line every 5 cells) that pans/zooms with the camera; `grid_size` / `enabled` set by `SandboxStage`. |
|
||||
| `res://scripts/stage/stage_placement_overlay.gd` | **Sandbox Stage Builder (Phase 4b).** `class_name StagePlacementOverlay`, `extends Node2D` — world-space overlay drawing the terrain drag-painting dashed guide line (`set_terrain_guide` / `clear_terrain_guide`) and the director action rubber-band trajectory + ghost marker (`set_action_trajectory` / `clear_action`); pure drawing, no hit-testing. |
|
||||
| `res://sandbox_theme.json` | **Sandbox Stage Builder (Phase 4b).** Hand-editable styling defaults for the sandbox (font paths/sizes, grid snap default, mode accent + guide-line colors); loaded by `SandboxStage._load_theme()` with defaults on missing/malformed file. **Phase 3c** extends the `fonts` block (bold/italic variant paths, per-widget sizes/style flags, optional `action_popup` object form) and drives the panels'/editors' `apply_font(...)` (§21.3 / spec §14). |
|
||||
| `res://scenes/sandbox_stage.tscn` | **Sandbox Stage Builder.** Standalone staging scene backing `scripts/sandbox_stage.gd` (run via **F6**; not wired into the editor): root `Node2D` + `Camera2D` + empty `World`; the gizmo layer, placement overlay, and CanvasLayer UI (mode switcher, toolbars, bottom status bar, badge, tooltip) are built in code. |
|
||||
| `res://scripts/body_part_panel.gd` | Multi-shape creation, vertex editing, shape dragging, per-panel zoom & pan, grid drawing & snap-to-grid, ColorPicker, shape/vertex delete, Z-ordering (Send Back / Bring Forward), shape Copy/Paste, shape Mirror X/Y, drawing (fill + outline for closed shapes). |
|
||||
| `res://scripts/whole_stickman_preview.gd` | Assembly preview, drag-to-reposition, part selection with white bounding box, rotation gizmo (circle below box) with Ctrl 15° snap, scale gizmo (corner crosses) with Ctrl aspect lock, part Z-ordering (Send Back / Bring Forward) via `part_order`, part Mirror X/Y (scale negation), zoom & pan, grid drawing & snap-to-grid, pose silhouette guide (Phase 7), part hit-bounds, labels, and (Phase 9 Round 5) `get_guide_joint_preview()` — the preview-space position of a guide joint, used by the editor to export per-part `guide_offset`. |
|
||||
| `res://scenes/stage/sandbox_stage.tscn` | **Sandbox Stage Builder.** Standalone staging scene backing `scripts/editors/stage/sandbox_stage.gd` (run via **F6**; not wired into the editor): root `Node2D` + `Camera2D` + empty `World`; the gizmo layer, placement overlay, and CanvasLayer UI (mode switcher, toolbars, bottom status bar, badge, tooltip) are built in code. |
|
||||
| `res://scripts/editors/stickman/body_part_panel.gd` | Multi-shape creation, vertex editing, shape dragging, per-panel zoom & pan, grid drawing & snap-to-grid, ColorPicker, shape/vertex delete, Z-ordering (Send Back / Bring Forward), shape Copy/Paste, shape Mirror X/Y, drawing (fill + outline for closed shapes). |
|
||||
| `res://scripts/editors/stickman/whole_stickman_preview.gd` | Assembly preview, drag-to-reposition, part selection with white bounding box, rotation gizmo (circle below box) with Ctrl 15° snap, scale gizmo (corner crosses) with Ctrl aspect lock, part Z-ordering (Send Back / Bring Forward) via `part_order`, part Mirror X/Y (scale negation), zoom & pan, grid drawing & snap-to-grid, pose silhouette guide (Phase 7), part hit-bounds, labels, and (Phase 9 Round 5) `get_guide_joint_preview()` — the preview-space position of a guide joint, used by the editor to export per-part `guide_offset`. |
|
||||
| `res://addons/curved_lines_2d/` | Scalable Vector Shapes 2D addon (v2.27.7) — required dependency. |
|
||||
| `res://stick.tscn` | **Legacy** rigged/animated stick figure scene (Skeleton2D + IK). Not used by the editor. |
|
||||
| `res://scenes/legacy/scenes/legacy/stick.tscn` | **Legacy** rigged/animated stick figure scene (Skeleton2D + IK). Not used by the editor. |
|
||||
| `res://AGENTS.md` | Guidance for AI agents working in this codebase. |
|
||||
|
||||
### Menu bar structure
|
||||
@@ -1082,25 +1160,27 @@ BodyPartPanel.shape_selected() ---(bound to part_name)---> stickman_editor
|
||||
|
||||
> **Phase 6 — Continuous Dynamic IK & Terrain-Following Locomotion (implemented and editor-verified):** PLAY enables a kinematic terrain controller. Unsupported rigs free-fall under bounded gravity; walking animation pauses while airborne and resumes on landing. The centerline uses a three-ray terrain fan and each lower-leg endpoint uses an independent three-ray fan; only upward-facing `TerrainBlock` hits are accepted, with self collision proxies excluded. `AnimationTargets/*_Base` markers hold the animation pose while live leg IK targets receive continuous stance/swing blending, world-space stance locks, a predictive foot guard, and centerline pelvis/root compensation. Runtime root elevation accumulates over ramps and steps. EDIT/DIRECT disable terrain following and restore authored transforms. The Sandbox navigation bake uses exposed upward-surface ribbons with short step bridges; `NavigationAgent2D` remains at `(0, +385)` and terrain owns vertical motion while arrival remains baseline-aligned. Trigger areas use swept visible bounds across physics frames to detect fast-fall entries. Reactive takeover batches preserve order, so `ragdoll` followed by `recover` executes both in sequence. `DEBUG_TERRAIN` is off by default. No foot/ankle bones were added.
|
||||
|
||||
> **Phase 7:** Adds the pose silhouette guide to the Whole Stickman preview — a semi-transparent, color-coded stick figure (left cyan-blue, right orange-red, central white) whose 13 joint anchors match the rest-pose pivots of the future `master_rig.tscn` rig, drawn above the grid and in front of user parts (ghosting over them, below the selection gizmos and drag highlight), centered in the preview at the default view. Toggleable via the dynamic **View → Hide/Show Pose Guide** label (on by default, persisted to `settings.json`). The guide is a view aid only: **no `.stk` format change** — `FILE_VERSION` stays `"1.3"`.
|
||||
> **Phase 7:** Adds the pose silhouette guide to the Whole Stickman preview — a semi-transparent, color-coded stick figure (left cyan-blue, right orange-red, central white) whose 13 joint anchors match the rest-pose pivots of the future `stickman_rig.tscn` rig, drawn above the grid and in front of user parts (ghosting over them, below the selection gizmos and drag highlight), centered in the preview at the default view. Toggleable via the dynamic **View → Hide/Show Pose Guide** label (on by default, persisted to `settings.json`). The guide is a view aid only: **no `.stk` format change** — `FILE_VERSION` stays `"1.3"`.
|
||||
|
||||
> **Phase 8:** The `.stk` export evolved to **v1.4** with write-only metadata the editor never reads back. A top-level `proportions` object stores the 5 master-rig rest-pose bone lengths (`upper_arm_length` 168.0, `lower_arm_length` 200.0, `upper_leg_length` 200.0, `lower_leg_length` 200.0, `torso_length` 391.5) — hardcoded constants from `master_rig.tscn`, not measured from the user's shapes. Each `body_parts` entry gains `pivot` (local bounding-box center = rotation origin) and `length` (bbox extent along the segment axis: width for arms, height for torso/legs/head). v1.0–v1.3 files load unchanged and gain these keys on their next save. A new standalone `res://scripts/stk_rig_adapter.gd` (`class_name StkRigAdapter`) fits an instantiated `master_rig.tscn` to a loaded `.stk` (bone fitting + IK recalibration + visual shape mount); it is **not** used by the editor and is reserved for a future runtime pipeline.
|
||||
> **Phase 8:** The `.stk` export evolved to **v1.4** with write-only metadata the editor never reads back. A top-level `proportions` object stores the 5 master-rig rest-pose bone lengths (`upper_arm_length` 168.0, `lower_arm_length` 200.0, `upper_leg_length` 200.0, `lower_leg_length` 200.0, `torso_length` 391.5) — hardcoded constants from `stickman_rig.tscn`, not measured from the user's shapes. Each `body_parts` entry gains `pivot` (local bounding-box center = rotation origin) and `length` (bbox extent along the segment axis: width for arms, height for torso/legs/head). v1.0–v1.3 files load unchanged and gain these keys on their next save. A new standalone `res://scripts/characters/stickman/stk_rig_adapter.gd` (`class_name StkRigAdapter`) fits an instantiated `stickman_rig.tscn` to a loaded `.stk` (bone fitting + IK recalibration + visual shape mount); it is **not** used by the editor and is reserved for a future runtime pipeline.
|
||||
|
||||
> **Phase 9:** Adds the **runtime pipeline** for turning a `.stk` file into a live, rigged `master_rig.tscn` instance, plus a standalone staging scene to debug it. A new `res://scripts/stickman_factory.gd` (`class_name StickmanFactory`) provides the runtime entry point: `load_stk(path)` reads/parses a `.stk` (`FileAccess` + `JSON.parse_string`, `{}` + `push_warning` on failure), `spawn_from_data(stk_data)` instantiates `master_rig.tscn` and applies `StkRigAdapter.apply(stk_data, rig)`, and `spawn(path)` chains them (`null` on empty data). `StkRigAdapter` is extended to also fit the head bone (`Head.position.y = -proportions.torso_length`) and to mount the head as **full geometry** like every other part — clearing its inline `@tool` circle script and mounting `.stk` head shapes as `Line2D`/`Polygon2D` (removed the dead `_mount_head_circle`, `_compute_shapes_bbox`, and `_first_shape_color` helpers). A new standalone scene/resource pair, `res://scenes/test_harness.tscn` + `res://scripts/test_harness.gd` (run via **F6**), loads `.stk` files (open dialog + quick-select for `stickmen/break.stk`, `stickmen/basic.stk`, `stickmen/test.stk`), toggles a world-space debug overlay (true bone segments — parent→child lines with joint dots, limb leaf bones drawn to their IK targets and the Head leaf along its own direction — plus IK-target markers), pans/zooms a `Camera2D`, and lets you click-drag the 4 limb IK targets with live TwoBoneIK flexing (`SkeletonModificationStack2D` enabled on spawn). Neither the factory nor the harness is wired into the editor. **No `.stk` format change** — `FILE_VERSION` stays `"1.4"`.
|
||||
> **Phase 9:** Adds the **runtime pipeline** for turning a `.stk` file into a live, rigged `stickman_rig.tscn` instance, plus a standalone staging scene to debug it. A new `res://scripts/characters/stickman/stickman_factory.gd` (`class_name StickmanFactory`) provides the runtime entry point: `load_stk(path)` reads/parses a `.stk` (`FileAccess` + `JSON.parse_string`, `{}` + `push_warning` on failure), `spawn_from_data(stk_data)` instantiates `stickman_rig.tscn` and applies `StkRigAdapter.apply(stk_data, rig)`, and `spawn(path)` chains them (`null` on empty data). `StkRigAdapter` is extended to also fit the head bone (`Head.position.y = -proportions.torso_length`) and to mount the head as **full geometry** like every other part — clearing its inline `@tool` circle script and mounting `.stk` head shapes as `Line2D`/`Polygon2D` (removed the dead `_mount_head_circle`, `_compute_shapes_bbox`, and `_first_shape_color` helpers). A new standalone scene/resource pair, `res://scenes/tools/test_harness.tscn` + `res://scripts/tools/test_harness.gd` (run via **F6**), loads `.stk` files (open dialog + quick-select for `content/stickmen/break.stk`, `content/stickmen/basic.stk`, `content/stickmen/test.stk`), toggles a world-space debug overlay (true bone segments — parent→child lines with joint dots, limb leaf bones drawn to their IK targets and the Head leaf along its own direction — plus IK-target markers), pans/zooms a `Camera2D`, and lets you click-drag the 4 limb IK targets with live TwoBoneIK flexing (`SkeletonModificationStack2D` enabled on spawn). Neither the factory nor the harness is wired into the editor. **No `.stk` format change** — `FILE_VERSION` stays `"1.4"`.
|
||||
|
||||
> **Phase 9 Round 2 bugfix:** `StkRigAdapter._mount_shapes()` no longer trusts the file's `pivot`/`length`; it recomputes each part's bounding box at mount time and mounts geometry in the rig's **hanging convention** (joint anchor at the local origin, far end along local `+Y`) with a per-family alignment rotation (head `0`, torso `π`, left limbs `−π/2`, right limbs `+π/2`, vertical-drawn limbs `0`). Anchors: head/torso bottom-center, left horizontal limbs `max_x`, right horizontal limbs `min_x`, vertical limbs top-center. Scaling is **anisotropic** — only the **auto-detected drawn long axis** (`width >= height`) scales to the bone length (`bone_length/extent`, guard `extent <= 0.0001` → `1.0`), cross-axis thickness stays 1:1. Driver rotation neutralization was **removed** — the 10 `RemoteTransform2D` drivers keep `update_rotation = true`, so mounted shapes follow their bones under IK flexing. `Body/*` container transforms are reset (scale `(1,1)`, rotation `0`, position untouched), the Head driver's local position is zeroed so the chin lands on the neck joint, and `DEFAULT_LINE_WIDTH` is 2.0 (editor's 2 px outline). The harness `_draw_bones()` was rewritten to draw true parent→child bone segments with leaf bones out to their IK targets (wrist/ankle joints now visible). Per docs/phase9_round2_bugfix_spec.md; verified with a 46-assertion headless smoke test.
|
||||
> **Phase 9 Round 2 bugfix:** `StkRigAdapter._mount_shapes()` no longer trusts the file's `pivot`/`length`; it recomputes each part's bounding box at mount time and mounts geometry in the rig's **hanging convention** (joint anchor at the local origin, far end along local `+Y`) with a per-family alignment rotation (head `0`, torso `π`, left limbs `−π/2`, right limbs `+π/2`, vertical-drawn limbs `0`). Anchors: head/torso bottom-center, left horizontal limbs `max_x`, right horizontal limbs `min_x`, vertical limbs top-center. Scaling is **anisotropic** — only the **auto-detected drawn long axis** (`width >= height`) scales to the bone length (`bone_length/extent`, guard `extent <= 0.0001` → `1.0`), cross-axis thickness stays 1:1. Driver rotation neutralization was **removed** — the 10 `RemoteTransform2D` drivers keep `update_rotation = true`, so mounted shapes follow their bones under IK flexing. `Body/*` container transforms are reset (scale `(1,1)`, rotation `0`, position untouched), the Head driver's local position is zeroed so the chin lands on the neck joint, and `DEFAULT_LINE_WIDTH` is 2.0 (editor's 2 px outline). The harness `_draw_bones()` was rewritten to draw true parent→child bone segments with leaf bones out to their IK targets (wrist/ankle joints now visible). Per docs/specs/phase9_round2_bugfix_spec.md; verified with a 46-assertion headless smoke test.
|
||||
|
||||
> **Phase 9 Round 3 bugfix:** `StkRigAdapter._mount_shapes()` now reads each part's `rotation` (degrees, default 0.0) and `scale` (`{x,y}`, default `(1,1)`) and composes the preview's part transform `E(P) = C + R(rot)·S·(P − C)` (scale-then-rotate about the bbox center) **before** the hanging-convention mount — the anchor, alignment θ, and bone-fit scale are computed on the transformed geometry, so every rotation/scale the user applied in the Whole Stickman preview renders in the harness. Rotations near ±180° (`|wrapf(rot)| > 0.75π`) swap the attachment to the drawn far end so flips are visible (the 180° torso shows its drawn neck end at the hip joint); the bone-fit scale `s = bone_length/|V|` is measured on the transformed extent so user-scaled parts are not double-fitted. The head mounts upright (`θ = 0`, `s = 1`) but still applies the part scale via `E` (face ≈160 px), chin at the neck joint. `_mount_shape()` mounts **one node per shape** — closed → single `Polygon2D` (fill only), open → single `Line2D` (width 2) — removing the previous Polygon2D + Line2D outline duplication. The harness head-leaf overlay now draws along the bone's own direction (the LookAt aim point is not a joint) instead of a line to `IK_Targets/Head`, eliminating the bone sticking out of the head. Per docs/phase9_round3_bugfix_spec.md; verified with a 26-assertion headless smoke test.
|
||||
> **Phase 9 Round 3 bugfix:** `StkRigAdapter._mount_shapes()` now reads each part's `rotation` (degrees, default 0.0) and `scale` (`{x,y}`, default `(1,1)`) and composes the preview's part transform `E(P) = C + R(rot)·S·(P − C)` (scale-then-rotate about the bbox center) **before** the hanging-convention mount — the anchor, alignment θ, and bone-fit scale are computed on the transformed geometry, so every rotation/scale the user applied in the Whole Stickman preview renders in the harness. Rotations near ±180° (`|wrapf(rot)| > 0.75π`) swap the attachment to the drawn far end so flips are visible (the 180° torso shows its drawn neck end at the hip joint); the bone-fit scale `s = bone_length/|V|` is measured on the transformed extent so user-scaled parts are not double-fitted. The head mounts upright (`θ = 0`, `s = 1`) but still applies the part scale via `E` (face ≈160 px), chin at the neck joint. `_mount_shape()` mounts **one node per shape** — closed → single `Polygon2D` (fill only), open → single `Line2D` (width 2) — removing the previous Polygon2D + Line2D outline duplication. The harness head-leaf overlay now draws along the bone's own direction (the LookAt aim point is not a joint) instead of a line to `IK_Targets/Head`, eliminating the bone sticking out of the head. Per docs/specs/phase9_round3_bugfix_spec.md; verified with a 26-assertion headless smoke test.
|
||||
|
||||
> **Phase 9 Round 4 bugfix:** the mounted **head** was too high in the harness — its chin (the local origin) landed on the neck joint at `y = −391.5`, floating above the torso. The editor's silhouette guide draws the head as a radius-100 circle centered at the Head joint `(0, −463.5)` (bottom at `−363.5`), so `StkRigAdapter` now applies a `+28 px` rig-space translation (`const HEAD_CHIN_DROP := 28.0`) to the mounted head points after the part transform and the `(θ = 0, s = 1)` transform. The chin lands at world ≈ `(0, −363.5)` — the guide circle's bottom — overlapping the torso (top at `−391.5`) by 28 px, matching the editor guide. The drop is flip-agnostic (a rig-space fixture applied after part scale/rotation). Per docs/phase9_round4_bugfix_spec.md; verified with a 15-assertion headless smoke test.
|
||||
> **Phase 9 Round 4 bugfix:** the mounted **head** was too high in the harness — its chin (the local origin) landed on the neck joint at `y = −391.5`, floating above the torso. The editor's silhouette guide draws the head as a radius-100 circle centered at the Head joint `(0, −463.5)` (bottom at `−363.5`), so `StkRigAdapter` now applies a `+28 px` rig-space translation (`const HEAD_CHIN_DROP := 28.0`) to the mounted head points after the part transform and the `(θ = 0, s = 1)` transform. The chin lands at world ≈ `(0, −363.5)` — the guide circle's bottom — overlapping the torso (top at `−391.5`) by 28 px, matching the editor guide. The drop is flip-agnostic (a rig-space fixture applied after part scale/rotation). Per docs/specs/phase9_round4_bugfix_spec.md; verified with a 15-assertion headless smoke test.
|
||||
|
||||
> **Phase 9 Round 5:** the `.stk` export evolved to **v1.5** with per-part **`guide_offset`** — the part's bbox center minus its silhouette-guide joint (both in preview space, a pure master-space delta). `StkRigAdapter` applies it only when present as a node-frame translation `t = (guide_offset + (A − C)).rotated(−c_node)` (A = the mount anchor incl. the 180° flip rule, C = the raw bbox center, `c_node` = the part's driver `RemoteTransform2D.global_rotation` at apply time), so the harness reproduces the editor's guide-relative placement **1:1**; old files without the key keep the previous offset-0 behavior and the head falls back to the Round 4 `HEAD_CHIN_DROP`. The head maps to the guide **Neck** joint — the head bone's rig attachment origin, **not** the circle center (which sits 72 px above the neck). `guide_offset` is **write-only** metadata like `pivot`/`length` — the load path ignores it, so v1.0–v1.4 files load unchanged and gain the key on their next save. **Note:** `.stk` files must be re-saved from the editor to populate the offsets. Per docs/phase9_round5_bugfix_spec.md.
|
||||
> **Phase 9 Round 5:** the `.stk` export evolved to **v1.5** with per-part **`guide_offset`** — the part's bbox center minus its silhouette-guide joint (both in preview space, a pure master-space delta). `StkRigAdapter` applies it only when present as a node-frame translation `t = (guide_offset + (A − C)).rotated(−c_node)` (A = the mount anchor incl. the 180° flip rule, C = the raw bbox center, `c_node` = the part's driver `RemoteTransform2D.global_rotation` at apply time), so the harness reproduces the editor's guide-relative placement **1:1**; old files without the key keep the previous offset-0 behavior and the head falls back to the Round 4 `HEAD_CHIN_DROP`. The head maps to the guide **Neck** joint — the head bone's rig attachment origin, **not** the circle center (which sits 72 px above the neck). `guide_offset` is **write-only** metadata like `pivot`/`length` — the load path ignores it, so v1.0–v1.4 files load unchanged and gain the key on their next save. **Note:** `.stk` files must be re-saved from the editor to populate the offsets. Per docs/specs/phase9_round5_bugfix_spec.md.
|
||||
|
||||
> **Phase 9 Round 6 bugfix:** `StkRigAdapter._compute_mount_transform()` now selects the joint anchor as whichever transformed end (`E(J_raw)` or `E(F_pt_raw)`) is **nearest the part's stored guide joint** (`center − guide_offset`) when a part carries `guide_offset`. This replaces the per-side family choice and the 180° flip heuristic for that case, fixing the **lower left leg** and **lower right arm**, which were mounted 180° off their bones (the far end attached at the joint) because the user's drawn-side conventions are inconsistent across parts — the stored guide placement is the ground truth for which drawn end is the joint. The nearest-end rule naturally preserves the 180° flip behavior (a flipped part's far end lands nearest the joint), the head chin, and every previously-correct case. Old files without the key keep the family rules + flip heuristic exactly as before. `theta`, `s`, the Round 5 offset `t`, and the head `HEAD_CHIN_DROP` fallback are unchanged. Per docs/phase9_round6_bugfix_spec.md; verified with a 32-assertion headless smoke test.
|
||||
> **Phase 9 Round 6 bugfix:** `StkRigAdapter._compute_mount_transform()` now selects the joint anchor as whichever transformed end (`E(J_raw)` or `E(F_pt_raw)`) is **nearest the part's stored guide joint** (`center − guide_offset`) when a part carries `guide_offset`. This replaces the per-side family choice and the 180° flip heuristic for that case, fixing the **lower left leg** and **lower right arm**, which were mounted 180° off their bones (the far end attached at the joint) because the user's drawn-side conventions are inconsistent across parts — the stored guide placement is the ground truth for which drawn end is the joint. The nearest-end rule naturally preserves the 180° flip behavior (a flipped part's far end lands nearest the joint), the head chin, and every previously-correct case. Old files without the key keep the family rules + flip heuristic exactly as before. `theta`, `s`, the Round 5 offset `t`, and the head `HEAD_CHIN_DROP` fallback are unchanged. Per docs/specs/phase9_round6_bugfix_spec.md; verified with a 32-assertion headless smoke test.
|
||||
|
||||
> **Phase 9 Round 7:** the test harness (`scripts/test_harness.gd`) now exposes **6** draggable IK handles. `IK_HANDLE_PATHS` gains `"Head"` (`IK_Targets/Head`, the `SkeletonModification2DLookAt` aim point) and `"Torso"` (`IK_Targets/Torso`, whose child `RemoteTransform2D` moves the hip bone). Dragging the **Torso** handle moves **bones only** (no target following) — the marker's `RemoteTransform2D` translates the hip bone, and the whole skeleton + `Body/*` visuals follow rigidly, while the limb/head targets stay put so dragging the figure away from them stretches the limbs toward the stationary targets (per user decision). Dragging the **Head** handle drives the Head bone's LookAt rotation (the solver now uses a full-range, non-inverted band solved in global space — `constraint_angle_min = -180 / max = 180`, `constraint_invert = false`, `constraint_in_localspace = false` — so the head converges to the aim point with no per-frame mirror oscillation; the earlier authored ~55° clamp is gone); `Body/Head` follows. `_handle_color()` colors the head marker yellow (`HANDLE_COLOR_HEAD`) and the torso marker magenta (`HANDLE_COLOR_TORSO`); hands stay green, feet blue. The IK overlay additionally draws a null-guarded semi-transparent yellow aim line from the Head bone origin to the head marker (visual aid for the LookAt test). **No `.stk` format change.** Per docs/phase9_round7_feature_spec.md; verified with a 17-assertion headless test.
|
||||
> **Phase 9 Round 7:** the test harness (`scripts/tools/test_harness.gd`) now exposes **6** draggable IK handles. `IK_HANDLE_PATHS` gains `"Head"` (`IK_Targets/Head`, the `SkeletonModification2DLookAt` aim point) and `"Torso"` (`IK_Targets/Torso`, whose child `RemoteTransform2D` moves the hip bone). Dragging the **Torso** handle moves **bones only** (no target following) — the marker's `RemoteTransform2D` translates the hip bone, and the whole skeleton + `Body/*` visuals follow rigidly, while the limb/head targets stay put so dragging the figure away from them stretches the limbs toward the stationary targets (per user decision). Dragging the **Head** handle drives the Head bone's LookAt rotation (the solver now uses a full-range, non-inverted band solved in global space — `constraint_angle_min = -180 / max = 180`, `constraint_invert = false`, `constraint_in_localspace = false` — so the head converges to the aim point with no per-frame mirror oscillation; the earlier authored ~55° clamp is gone); `Body/Head` follows. `_handle_color()` colors the head marker yellow (`HANDLE_COLOR_HEAD`) and the torso marker magenta (`HANDLE_COLOR_TORSO`); hands stay green, feet blue. The IK overlay additionally draws a null-guarded semi-transparent yellow aim line from the Head bone origin to the head marker (visual aid for the LookAt test). **No `.stk` format change.** Per docs/specs/phase9_round7_feature_spec.md; verified with a 17-assertion headless test.
|
||||
|
||||
> **Phase 10 (Kinematic-to-Ragdoll):** adds a reversible **kinematic-to-ragdoll** state switch to the runtime rig. `StickmanRig` gains `enum RigState { ANIMATED, RAGDOLL }`, `var state: RigState`, `signal state_changed(new_state)`, and the `set_ragdoll(enabled)` / `toggle_ragdoll()` / `is_in_ragdoll()` API. In `RAGDOLL` mode the IK modification stack is disabled, the `AnimationPlayer` stopped, and the `Body/*` visuals hidden; a procedural network of **10** `RigidBody2D` (torso `CapsuleShape2D` mass 8.0, head `CircleShape2D` radius 100, limb capsules radius 8) + **9** `PinJoint2D` (elbow/knee fold-only ±bands, shoulder/hip ±160°, neck free) is built in code and reparented into a `"RagdollBodyContainer"` under the rig's **parent** (world root), layer 1/mask 1 so it collides with terrain and props. The rig root's momentum (tracked in `_physics_process`) is applied to the ragdoll Torso body for a seamless handoff. Exiting frees the ragdoll, re-shows `Body/*`, re-enables IK, and stops the animation. The physics harness toggles via its **Stickman ↔ Ragdoll** button, removing the `RigCollisionProxy` on entry and re-adding it (idempotently) on exit. `master_rig.tscn` is **not** modified.
|
||||
> **Phase 10 (Kinematic-to-Ragdoll):** adds a reversible **kinematic-to-ragdoll** state switch to the runtime rig. `StickmanRig` gains `enum RigState { ANIMATED, RAGDOLL }`, `var state: RigState`, `signal state_changed(new_state)`, and the `set_ragdoll(enabled)` / `toggle_ragdoll()` / `is_in_ragdoll()` API. In `RAGDOLL` mode the IK modification stack is disabled, the `AnimationPlayer` stopped, and the `Body/*` visuals hidden; a procedural network of **10** `RigidBody2D` (torso `CapsuleShape2D` mass 8.0, head `CircleShape2D` radius 100, limb capsules radius 8) + **9** `PinJoint2D` (elbow/knee fold-only ±bands, shoulder/hip ±160°, neck free) is built in code and reparented into a `"RagdollBodyContainer"` under the rig's **parent** (world root), layer 1/mask 1 so it collides with terrain and props. The rig root's momentum (tracked in `_physics_process`) is applied to the ragdoll Torso body for a seamless handoff. Exiting frees the ragdoll, re-shows `Body/*`, re-enables IK, and stops the animation. The physics harness toggles via its **Stickman ↔ Ragdoll** button, removing the `RigCollisionProxy` on entry and re-adding it (idempotently) on exit. `stickman_rig.tscn` is **not** modified.
|
||||
|
||||
> **Phase 11 (Instant Handoff & Recovery):** replaces the hard ragdoll entry/exit with an **instant handoff** and adds a **stand-up recovery** path. `StickmanRig` gains `enum RigState { ANIMATED, RAGDOLL, RECOVERING }` plus exports `rest_timeout` (2.0 s) and `auto_recover` (true). On entering `RAGDOLL` the ragdoll is built from the **current solved bone positions** (the player is stopped with `keep_state`), then `Body/*` is hidden and the IK stack disabled in the same call — no crossfade, since the ragdoll spawns at exactly the same pose and a fade would only read as ghosting (an earlier `transition_duration` blend was removed on director feedback). Rest detection reads the Torso body — sleeping, or linear ≤ `REST_LINEAR_THRESHOLD` (5.0 px/s, tuned up from the plan's 0.1 because a soft-pinned ragdoll micro-jitters around ~0.5 px/s) and angular ≤ 0.1 rad/s — then after `rest_timeout` + `STABILIZATION_DELAY` (0.1 s) with `auto_recover` on, calls `_start_recovery()`. Recovery first calls `_capture_pre_ragdoll_state()` (6 IK markers, 8 limb + head bone rotations, facing profile, 4 bend flags, head LookAt state, per-leg `leg_sides`, and entry chain offsets `torso_chain_offset`/`head_chain_offset`) as the END target, then `_capture_ragdoll_pose()` records the 10 bodies' rig-local pose **and** probes the terrain via `_probe_ground_y()` (a 7-ray fan with a tolerance band, excluding the ragdoll RIDs), re-anchors the rig root so the standing figure's **feet** sit on the ground at the landing X (`_reanchor_root_to_landing()`, `new_root = feet + FOOT_OFFSET`, with a mirror-aware local shift `local_shift = to_local(shift) − to_local(Vector2.ZERO)`), destroys the ragdoll, sets `state = RECOVERING` + emits, snap-solves via `_snap_skeleton_to_pose()` — the 6 IK targets plus direct arm/head bone rotations (`rot_u = chain(u) − θ_t − bone_angle_u`, `rot_l = chain(l) − chain(u) + bone_angle_u − bone_angle_l`, head via `head_chain_offset`), all normalized into `(−π, π]`, with the ankles clamped onto the terrain and the two leg IK mods enabled with the captured knee side — and finally `_play_stand_up()` runs a **2.0 s** sine-in-out tween of the markers → their pre-ragdoll values and the arm/head bones to the snap-computed `_recovery_bones` targets (elbows via `_natural_joint_target`), legs IK-driven. `_on_stand_up_finished()` restores the facing profile + bend flags + LookAt state, re-enables the arm mods, and returns to `ANIMATED`. The per-joint bend decisions live in three editable tables — `RAGDOLL_JOINT_BAND_LIMITS`, `RECOVERY_LEG_SIDE_FORCE`, `RECOVERY_JOINT_PATH` (Joint bend configuration (EDIT ME)); diagnostics are gated behind `DEBUG_RECOVERY := false`.
|
||||
Torso bone's `bone_angle` (copying the body rotation directly would slam the skeleton −90° and lay it flat). `request_recovery()` is public (no-op unless in `RAGDOLL`); `set_ragdoll(true)` during `RECOVERING` kills the stand-up tween and rebuilds the ragdoll, `set_ragdoll(false)` during `RAGDOLL` routes through recovery, and calls are otherwise idempotent. `is_in_ragdoll()` stays `state == RAGDOLL` (so `RECOVERING` reads as "Stickman"). A new `res://scripts/create_animations.gd` editor script (superseding the deleted `create_walk.gd`) bakes `walk_left`/`walk_right`/the one-shot `stand_up` into `master_rig.tscn`'s `AnimationLibrary` (the baked `stand_up` is an authored reference only — recovery does not play it) — **no `.stk` format change**; `master_rig.tscn` scene nodes are unchanged (only its baked animations are added). The physics harness gains a **Rest** `SpinBox` (0.1–10 s, writes `_rig.rest_timeout`), a **"Recover Now"** button (`request_recovery()`), and a `state_changed` hook that removes the `RigCollisionProxy` on `RAGDOLL` and re-adds it (idempotently) on `ANIMATED`/`RECOVERING`.
|
||||
Torso bone's `bone_angle` (copying the body rotation directly would slam the skeleton −90° and lay it flat). `request_recovery()` is public (no-op unless in `RAGDOLL`); `set_ragdoll(true)` during `RECOVERING` kills the stand-up tween and rebuilds the ragdoll, `set_ragdoll(false)` during `RAGDOLL` routes through recovery, and calls are otherwise idempotent. `is_in_ragdoll()` stays `state == RAGDOLL` (so `RECOVERING` reads as "Stickman"). A new `res://scripts/tools/create_animations.gd` editor script (superseding the deleted `create_walk.gd`) bakes `walk_left`/`walk_right`/the one-shot `stand_up` into `stickman_rig.tscn`'s `AnimationLibrary` (the baked `stand_up` is an authored reference only — recovery does not play it) — **no `.stk` format change**; `stickman_rig.tscn` scene nodes are unchanged (only its baked animations are added). The physics harness gains a **Rest** `SpinBox` (0.1–10 s, writes `_rig.rest_timeout`), a **"Recover Now"** button (`request_recovery()`), and a `state_changed` hook that removes the `RigCollisionProxy` on `RAGDOLL` and re-adds it (idempotently) on `ANIMATED`/`RECOVERING`.
|
||||
|
||||
> **Phase 9 Prop Editor (Rounds 1–7):** a standalone, kid-friendly vector-prop authoring tool — the authoring counterpart to the stickman editor — run via **F6** on `res://scenes/editors/prop/prop_editor.tscn` (not the main scene). It adds a new `.prop` v1.0 JSON format (`res://content/props/*.prop`, multi-shape stack + deterministic `PropFile.flatten_to_payload()` conversion), a dedicated `PropCanvas` multi-shape canvas, a validated `PropTheme` (`res://prop_theme.json`) with a Round 2–4 `ui` token section, and a save-side 200×200 thumbnail pipeline reusing `PropThumbnail` + a mtime-keyed `ThumbnailCache.prop_file_png`. Round highlights: **R2** — two explicit canvas modes ("Arrange"/"Reshape"), the stickman-style bottom rotation dot + corner scale crosses, color-matched 3 px vertex handles, and cursor-projection "Create Point" with a 0.6 s flash; **R3** — POINTS-mode right-click is point-editing only (segment proximity via `hit_test_segment`), centered mode toolbar with emoji, window title `Untitled — file.prop *`, exit dialog (💾/🗑️/❌), and a debounced autosave/recovery prompt; **R4** — selected-mode is clearly outlined (`FOCUS_NONE` + accent-border `pressed` stylebox), bigger theme-driven defaults, the Grid spinbox + Snap checkbox moved to the menu row (Edit menu removed), File → New with a save prompt, and **Ball removed** from the add menus; **R5** — File → 🕑 Recent (last 5, persisted) and a critical serialization fix (typed `PackedVector2Array` assignments from `{x,y}` dicts silently zeroed every coordinate — `_serialize_shape` now routes through `_coerce_points`); **R6** — Recent updates on save, a per-shape **`reshaped`** flag gates the circle Radius row, and fill-adaptive selection contrast; **R7** — two-tone halo selection (dark backing + bright core) so outlines/boxes/dots/crosses/handles read on any background. Several Prop Editor rows are logged in `docs/architecture/tech_debt_and_optimizations.md` (#29–#35).
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,166 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
},
|
||||
"primary_grip": {
|
||||
"allowed_hands": "both",
|
||||
"role": "grip",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 1
|
||||
}
|
||||
},
|
||||
"material_preset": "rubber",
|
||||
"metadata": {
|
||||
"created_at": "2026-09-22T00:26:21",
|
||||
"modified_at": "2026-09-22T00:26:21"
|
||||
},
|
||||
"prop_name": "Baseball",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#F5F5F0FF",
|
||||
"outline_color": "#A0A0A0FF",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 25.1999988555908,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": 21.8231983184814,
|
||||
"y": 12.5999994277954
|
||||
},
|
||||
{
|
||||
"x": 12.5999994277954,
|
||||
"y": 21.8231983184814
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": 25.1999988555908
|
||||
},
|
||||
{
|
||||
"x": -12.5999994277954,
|
||||
"y": 21.8231983184814
|
||||
},
|
||||
{
|
||||
"x": -21.8231983184814,
|
||||
"y": 12.5999994277954
|
||||
},
|
||||
{
|
||||
"x": -25.1999988555908,
|
||||
"y": 0.0
|
||||
},
|
||||
{
|
||||
"x": -21.8231983184814,
|
||||
"y": -12.5999994277954
|
||||
},
|
||||
{
|
||||
"x": -12.5999994277954,
|
||||
"y": -21.8231983184814
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -25.1999988555908
|
||||
},
|
||||
{
|
||||
"x": 12.5999994277954,
|
||||
"y": -21.8231983184814
|
||||
},
|
||||
{
|
||||
"x": 21.8231983184814,
|
||||
"y": -12.5999994277954
|
||||
}
|
||||
],
|
||||
"radius": 25.1996288299561,
|
||||
"reshaped": false,
|
||||
"shape_type": "circle",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#D62828FF",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -8.64000034332275,
|
||||
"y": -20.1599998474121
|
||||
},
|
||||
{
|
||||
"x": -15.8400001525879,
|
||||
"y": -10.0799999237061
|
||||
},
|
||||
{
|
||||
"x": -15.8400001525879,
|
||||
"y": 10.0799999237061
|
||||
},
|
||||
{
|
||||
"x": -8.64000034332275,
|
||||
"y": 20.1599998474121
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": false,
|
||||
"fill_color": "#00000000",
|
||||
"outline_color": "#D62828FF",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 8.64000034332275,
|
||||
"y": -20.1599998474121
|
||||
},
|
||||
{
|
||||
"x": 15.8400001525879,
|
||||
"y": -10.0799999237061
|
||||
},
|
||||
{
|
||||
"x": 15.8400001525879,
|
||||
"y": 10.0799999237061
|
||||
},
|
||||
{
|
||||
"x": 8.64000034332275,
|
||||
"y": 20.1599998474121
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "line",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": "1.0"
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"material_preset": "none",
|
||||
"metadata": {
|
||||
"created_at": "2026-09-19T16:03:21",
|
||||
"modified_at": "2026-09-19T16:03:21"
|
||||
},
|
||||
"prop_name": "",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "ffffffff",
|
||||
"outline_color": "#40290F",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 1258.0,
|
||||
"y": 499.732421875
|
||||
},
|
||||
{
|
||||
"x": 1230.26721191406,
|
||||
"y": 603.232421875
|
||||
},
|
||||
{
|
||||
"x": 1154.5,
|
||||
"y": 678.999694824219
|
||||
},
|
||||
{
|
||||
"x": 1051.0,
|
||||
"y": 706.732421875
|
||||
},
|
||||
{
|
||||
"x": 947.5,
|
||||
"y": 678.999694824219
|
||||
},
|
||||
{
|
||||
"x": 871.732727050781,
|
||||
"y": 603.232421875
|
||||
},
|
||||
{
|
||||
"x": 844.0,
|
||||
"y": 499.732421875
|
||||
},
|
||||
{
|
||||
"x": 871.732727050781,
|
||||
"y": 396.232421875
|
||||
},
|
||||
{
|
||||
"x": 947.5,
|
||||
"y": 371.465148925781
|
||||
},
|
||||
{
|
||||
"x": 1044.0,
|
||||
"y": 507.732421875
|
||||
},
|
||||
{
|
||||
"x": 1152.5,
|
||||
"y": 367.465148925781
|
||||
},
|
||||
{
|
||||
"x": 1230.26721191406,
|
||||
"y": 396.232421875
|
||||
}
|
||||
],
|
||||
"radius": 182.826955159505,
|
||||
"reshaped": true,
|
||||
"shape_type": "circle",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#8C6133",
|
||||
"outline_color": "#40290F",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 1146.23413085938,
|
||||
"y": 564.821594238281
|
||||
},
|
||||
{
|
||||
"x": 1194.23413085938,
|
||||
"y": 564.821594238281
|
||||
},
|
||||
{
|
||||
"x": 1194.23413085938,
|
||||
"y": 612.821594238281
|
||||
},
|
||||
{
|
||||
"x": 1146.23413085938,
|
||||
"y": 612.821594238281
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": "1.0"
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"anchors": {
|
||||
"origin": {
|
||||
"allowed_hands": "both",
|
||||
"role": "pivot",
|
||||
"rotation_deg": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z_index_offset": 0
|
||||
},
|
||||
"primary_grip": {
|
||||
"allowed_hands": "both",
|
||||
"role": "grip",
|
||||
"rotation_deg": 90.0,
|
||||
"x": 0.0,
|
||||
"y": -82.066291809082,
|
||||
"z_index_offset": 1
|
||||
}
|
||||
},
|
||||
"material_preset": "wood",
|
||||
"metadata": {
|
||||
"created_at": "2026-09-24T23:17:51",
|
||||
"modified_at": "2026-09-24T23:17:51"
|
||||
},
|
||||
"prop_name": "Brown Briefcase",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#3D2314FF",
|
||||
"outline_color": "#26150CFF",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -48.2742919921875,
|
||||
"y": -57.9291458129883
|
||||
},
|
||||
{
|
||||
"x": -48.2742919921875,
|
||||
"y": -106.20344543457
|
||||
},
|
||||
{
|
||||
"x": 48.2742919921875,
|
||||
"y": -106.20344543457
|
||||
},
|
||||
{
|
||||
"x": 48.2742919921875,
|
||||
"y": -57.9291458129883
|
||||
},
|
||||
{
|
||||
"x": 34.7574882507324,
|
||||
"y": -57.9291458129883
|
||||
},
|
||||
{
|
||||
"x": 34.7574882507324,
|
||||
"y": -90.7556686401367
|
||||
},
|
||||
{
|
||||
"x": -34.7574882507324,
|
||||
"y": -90.7556686401367
|
||||
},
|
||||
{
|
||||
"x": -34.7574882507324,
|
||||
"y": -57.9291458129883
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#6D3C19FF",
|
||||
"outline_color": "#3B200AFF",
|
||||
"outline_width": 3.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -135.168014526367,
|
||||
"y": -57.9291458129883
|
||||
},
|
||||
{
|
||||
"x": 135.168014526367,
|
||||
"y": -57.9291458129883
|
||||
},
|
||||
{
|
||||
"x": 135.168014526367,
|
||||
"y": 77.2388610839844
|
||||
},
|
||||
{
|
||||
"x": -135.168014526367,
|
||||
"y": 77.2388610839844
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#D4AF37FF",
|
||||
"outline_color": "#8B7500FF",
|
||||
"outline_width": 1.5,
|
||||
"points": [
|
||||
{
|
||||
"x": -86.8937225341797,
|
||||
"y": -61.791088104248
|
||||
},
|
||||
{
|
||||
"x": -57.9291458129883,
|
||||
"y": -61.791088104248
|
||||
},
|
||||
{
|
||||
"x": -57.9291458129883,
|
||||
"y": -42.481372833252
|
||||
},
|
||||
{
|
||||
"x": -86.8937225341797,
|
||||
"y": -42.481372833252
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#D4AF37FF",
|
||||
"outline_color": "#8B7500FF",
|
||||
"outline_width": 1.5,
|
||||
"points": [
|
||||
{
|
||||
"x": 57.9291458129883,
|
||||
"y": -61.791088104248
|
||||
},
|
||||
{
|
||||
"x": 86.8937225341797,
|
||||
"y": -61.791088104248
|
||||
},
|
||||
{
|
||||
"x": 86.8937225341797,
|
||||
"y": -42.481372833252
|
||||
},
|
||||
{
|
||||
"x": 57.9291458129883,
|
||||
"y": -42.481372833252
|
||||
}
|
||||
],
|
||||
"reshaped": false,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": "1.0"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,726 @@
|
||||
{
|
||||
"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:31",
|
||||
"modified_at": "2026-10-21T23:13:31"
|
||||
},
|
||||
"prop_name": "End Table",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B49A82FF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 3.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -98.0,
|
||||
"y": -118.0
|
||||
},
|
||||
{
|
||||
"x": 98.0,
|
||||
"y": -118.0
|
||||
},
|
||||
{
|
||||
"x": 98.0,
|
||||
"y": -43.0
|
||||
},
|
||||
{
|
||||
"x": -98.0,
|
||||
"y": -43.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#347E91FF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 3.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -83.0,
|
||||
"y": -102.0
|
||||
},
|
||||
{
|
||||
"x": 83.0,
|
||||
"y": -102.0
|
||||
},
|
||||
{
|
||||
"x": 83.0,
|
||||
"y": -51.0
|
||||
},
|
||||
{
|
||||
"x": -83.0,
|
||||
"y": -51.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#B3D1E4FF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -76.0,
|
||||
"y": -95.0
|
||||
},
|
||||
{
|
||||
"x": 76.0,
|
||||
"y": -95.0
|
||||
},
|
||||
{
|
||||
"x": 76.0,
|
||||
"y": -58.0
|
||||
},
|
||||
{
|
||||
"x": -76.0,
|
||||
"y": -58.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E9F6F9FF",
|
||||
"outline_color": "#E9F6F9FF",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -73.0,
|
||||
"y": -92.0
|
||||
},
|
||||
{
|
||||
"x": 73.0,
|
||||
"y": -92.0
|
||||
},
|
||||
{
|
||||
"x": 73.0,
|
||||
"y": -87.0
|
||||
},
|
||||
{
|
||||
"x": -73.0,
|
||||
"y": -87.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#65ADBDFF",
|
||||
"outline_color": "#65ADBDFF",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -73.0,
|
||||
"y": -65.0
|
||||
},
|
||||
{
|
||||
"x": 73.0,
|
||||
"y": -65.0
|
||||
},
|
||||
{
|
||||
"x": 73.0,
|
||||
"y": -60.0
|
||||
},
|
||||
{
|
||||
"x": -73.0,
|
||||
"y": -60.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EBD8B5FF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 3.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -96.0,
|
||||
"y": -30.0
|
||||
},
|
||||
{
|
||||
"x": 96.0,
|
||||
"y": -30.0
|
||||
},
|
||||
{
|
||||
"x": 96.0,
|
||||
"y": -14.0
|
||||
},
|
||||
{
|
||||
"x": -96.0,
|
||||
"y": -14.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FFF0CEFF",
|
||||
"outline_color": "#FFF0CEFF",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -92.0,
|
||||
"y": -28.0
|
||||
},
|
||||
{
|
||||
"x": 92.0,
|
||||
"y": -28.0
|
||||
},
|
||||
{
|
||||
"x": 92.0,
|
||||
"y": -23.0
|
||||
},
|
||||
{
|
||||
"x": -92.0,
|
||||
"y": -23.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#EBD8B5FF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 3.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -96.0,
|
||||
"y": 76.0
|
||||
},
|
||||
{
|
||||
"x": 96.0,
|
||||
"y": 76.0
|
||||
},
|
||||
{
|
||||
"x": 96.0,
|
||||
"y": 92.0
|
||||
},
|
||||
{
|
||||
"x": -96.0,
|
||||
"y": 92.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FFF0CEFF",
|
||||
"outline_color": "#FFF0CEFF",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -92.0,
|
||||
"y": 78.0
|
||||
},
|
||||
{
|
||||
"x": 92.0,
|
||||
"y": 78.0
|
||||
},
|
||||
{
|
||||
"x": 92.0,
|
||||
"y": 83.0
|
||||
},
|
||||
{
|
||||
"x": -92.0,
|
||||
"y": 83.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E5CDA9FF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 3.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -102.0,
|
||||
"y": -126.0
|
||||
},
|
||||
{
|
||||
"x": -82.0,
|
||||
"y": -126.0
|
||||
},
|
||||
{
|
||||
"x": -82.0,
|
||||
"y": 142.0
|
||||
},
|
||||
{
|
||||
"x": -102.0,
|
||||
"y": 142.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FFF0CEFF",
|
||||
"outline_color": "#FFF0CEFF",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -98.0,
|
||||
"y": -118.0
|
||||
},
|
||||
{
|
||||
"x": -93.0,
|
||||
"y": -118.0
|
||||
},
|
||||
{
|
||||
"x": -93.0,
|
||||
"y": 136.0
|
||||
},
|
||||
{
|
||||
"x": -98.0,
|
||||
"y": 136.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E5CDA9FF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 3.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 82.0,
|
||||
"y": -126.0
|
||||
},
|
||||
{
|
||||
"x": 102.0,
|
||||
"y": -126.0
|
||||
},
|
||||
{
|
||||
"x": 102.0,
|
||||
"y": 142.0
|
||||
},
|
||||
{
|
||||
"x": 82.0,
|
||||
"y": 142.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FFF0CEFF",
|
||||
"outline_color": "#FFF0CEFF",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 86.0,
|
||||
"y": -118.0
|
||||
},
|
||||
{
|
||||
"x": 91.0,
|
||||
"y": -118.0
|
||||
},
|
||||
{
|
||||
"x": 91.0,
|
||||
"y": 136.0
|
||||
},
|
||||
{
|
||||
"x": 86.0,
|
||||
"y": 136.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#E72F4AFF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 4.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -116.0,
|
||||
"y": -142.0
|
||||
},
|
||||
{
|
||||
"x": 116.0,
|
||||
"y": -142.0
|
||||
},
|
||||
{
|
||||
"x": 116.0,
|
||||
"y": -122.0
|
||||
},
|
||||
{
|
||||
"x": -116.0,
|
||||
"y": -122.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#DFD0B9FF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": -112.0,
|
||||
"y": -142.0
|
||||
},
|
||||
{
|
||||
"x": 112.0,
|
||||
"y": -142.0
|
||||
},
|
||||
{
|
||||
"x": 112.0,
|
||||
"y": -135.0
|
||||
},
|
||||
{
|
||||
"x": -112.0,
|
||||
"y": -135.0
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#D72E4CFF",
|
||||
"outline_color": "#30213DFF",
|
||||
"outline_width": 2.5,
|
||||
"points": [
|
||||
{
|
||||
"x": 9.0,
|
||||
"y": -76.0
|
||||
},
|
||||
{
|
||||
"x": 8.69299983978271,
|
||||
"y": -73.6710052490234
|
||||
},
|
||||
{
|
||||
"x": 7.79400014877319,
|
||||
"y": -71.5
|
||||
},
|
||||
{
|
||||
"x": 6.36399984359741,
|
||||
"y": -69.6360015869141
|
||||
},
|
||||
{
|
||||
"x": 4.5,
|
||||
"y": -68.2060012817383
|
||||
},
|
||||
{
|
||||
"x": 2.3289999961853,
|
||||
"y": -67.306999206543
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -67.0
|
||||
},
|
||||
{
|
||||
"x": -2.3289999961853,
|
||||
"y": -67.306999206543
|
||||
},
|
||||
{
|
||||
"x": -4.5,
|
||||
"y": -68.2060012817383
|
||||
},
|
||||
{
|
||||
"x": -6.36399984359741,
|
||||
"y": -69.6360015869141
|
||||
},
|
||||
{
|
||||
"x": -7.79400014877319,
|
||||
"y": -71.5
|
||||
},
|
||||
{
|
||||
"x": -8.69299983978271,
|
||||
"y": -73.6710052490234
|
||||
},
|
||||
{
|
||||
"x": -9.0,
|
||||
"y": -76.0
|
||||
},
|
||||
{
|
||||
"x": -8.69299983978271,
|
||||
"y": -78.3289947509766
|
||||
},
|
||||
{
|
||||
"x": -7.79400014877319,
|
||||
"y": -80.5
|
||||
},
|
||||
{
|
||||
"x": -6.36399984359741,
|
||||
"y": -82.3639984130859
|
||||
},
|
||||
{
|
||||
"x": -4.5,
|
||||
"y": -83.7939987182617
|
||||
},
|
||||
{
|
||||
"x": -2.3289999961853,
|
||||
"y": -84.693000793457
|
||||
},
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -85.0
|
||||
},
|
||||
{
|
||||
"x": 2.3289999961853,
|
||||
"y": -84.693000793457
|
||||
},
|
||||
{
|
||||
"x": 4.5,
|
||||
"y": -83.7939987182617
|
||||
},
|
||||
{
|
||||
"x": 6.36399984359741,
|
||||
"y": -82.3639984130859
|
||||
},
|
||||
{
|
||||
"x": 7.79400014877319,
|
||||
"y": -80.5
|
||||
},
|
||||
{
|
||||
"x": 8.69299983978271,
|
||||
"y": -78.3289947509766
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"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
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#FFE3DBFF",
|
||||
"outline_color": "#FFE3DBFF",
|
||||
"outline_width": 0.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 0.0,
|
||||
"y": -79.0
|
||||
},
|
||||
{
|
||||
"x": -0.228000000119209,
|
||||
"y": -77.8520050048828
|
||||
},
|
||||
{
|
||||
"x": -0.879000008106232,
|
||||
"y": -76.8789978027344
|
||||
},
|
||||
{
|
||||
"x": -1.85199999809265,
|
||||
"y": -76.2279968261719
|
||||
},
|
||||
{
|
||||
"x": -3.0,
|
||||
"y": -76.0
|
||||
},
|
||||
{
|
||||
"x": -4.14799976348877,
|
||||
"y": -76.2279968261719
|
||||
},
|
||||
{
|
||||
"x": -5.12099981307983,
|
||||
"y": -76.8789978027344
|
||||
},
|
||||
{
|
||||
"x": -5.77199983596802,
|
||||
"y": -77.8520050048828
|
||||
},
|
||||
{
|
||||
"x": -6.0,
|
||||
"y": -79.0
|
||||
},
|
||||
{
|
||||
"x": -5.77199983596802,
|
||||
"y": -80.1479949951172
|
||||
},
|
||||
{
|
||||
"x": -5.12099981307983,
|
||||
"y": -81.1210021972656
|
||||
},
|
||||
{
|
||||
"x": -4.14799976348877,
|
||||
"y": -81.7720031738281
|
||||
},
|
||||
{
|
||||
"x": -3.0,
|
||||
"y": -82.0
|
||||
},
|
||||
{
|
||||
"x": -1.85199999809265,
|
||||
"y": -81.7720031738281
|
||||
},
|
||||
{
|
||||
"x": -0.879000008106232,
|
||||
"y": -81.1210021972656
|
||||
},
|
||||
{
|
||||
"x": -0.228000000119209,
|
||||
"y": -80.1479949951172
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [],
|
||||
"version": "1.1"
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
{
|
||||
"material_preset": "none",
|
||||
"metadata": {
|
||||
"created_at": "2026-09-19T21:11:33",
|
||||
"modified_at": "2026-09-19T21:11:33"
|
||||
},
|
||||
"prop_name": "",
|
||||
"shapes": [
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "ffffffff",
|
||||
"outline_color": "#40290F",
|
||||
"outline_width": 4.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 1294.0,
|
||||
"y": 556.848999023438
|
||||
},
|
||||
{
|
||||
"x": 1274.30578613281,
|
||||
"y": 630.348999023438
|
||||
},
|
||||
{
|
||||
"x": 1220.5,
|
||||
"y": 684.154724121094
|
||||
},
|
||||
{
|
||||
"x": 1147.0,
|
||||
"y": 703.848999023438
|
||||
},
|
||||
{
|
||||
"x": 1073.5,
|
||||
"y": 684.154724121094
|
||||
},
|
||||
{
|
||||
"x": 1019.69427490234,
|
||||
"y": 630.348999023438
|
||||
},
|
||||
{
|
||||
"x": 1000.0,
|
||||
"y": 556.848999023438
|
||||
},
|
||||
{
|
||||
"x": 1019.69427490234,
|
||||
"y": 483.348999023438
|
||||
},
|
||||
{
|
||||
"x": 1079.5,
|
||||
"y": 453.543273925781
|
||||
},
|
||||
{
|
||||
"x": 1152.0,
|
||||
"y": 455.848999023438
|
||||
},
|
||||
{
|
||||
"x": 1223.5,
|
||||
"y": 454.543273925781
|
||||
},
|
||||
{
|
||||
"x": 1274.30578613281,
|
||||
"y": 483.348999023438
|
||||
}
|
||||
],
|
||||
"radius": 139.647333145142,
|
||||
"reshaped": false,
|
||||
"shape_type": "circle",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "3b52bbff",
|
||||
"outline_color": "#40290F",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 1207.81555175781,
|
||||
"y": 569.486694335938
|
||||
},
|
||||
{
|
||||
"x": 1199.5625,
|
||||
"y": 600.287231445313
|
||||
},
|
||||
{
|
||||
"x": 1177.01501464844,
|
||||
"y": 622.834716796875
|
||||
},
|
||||
{
|
||||
"x": 1146.21447753906,
|
||||
"y": 631.087768554688
|
||||
},
|
||||
{
|
||||
"x": 1115.41394042969,
|
||||
"y": 622.834716796875
|
||||
},
|
||||
{
|
||||
"x": 1092.86645507813,
|
||||
"y": 600.287231445313
|
||||
},
|
||||
{
|
||||
"x": 1084.61340332031,
|
||||
"y": 569.486694335938
|
||||
},
|
||||
{
|
||||
"x": 1092.86645507813,
|
||||
"y": 538.686157226563
|
||||
},
|
||||
{
|
||||
"x": 1115.41394042969,
|
||||
"y": 516.138671875
|
||||
},
|
||||
{
|
||||
"x": 1146.21447753906,
|
||||
"y": 507.885620117188
|
||||
},
|
||||
{
|
||||
"x": 1177.01501464844,
|
||||
"y": 516.138671875
|
||||
},
|
||||
{
|
||||
"x": 1199.5625,
|
||||
"y": 538.686157226563
|
||||
}
|
||||
],
|
||||
"radius": 61.6010309855143,
|
||||
"reshaped": false,
|
||||
"shape_type": "circle",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "000000ff",
|
||||
"outline_color": "#40290F",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 1147.79870605469,
|
||||
"y": 526.655395507813
|
||||
},
|
||||
{
|
||||
"x": 1160.27172851563,
|
||||
"y": 532.014404296875
|
||||
},
|
||||
{
|
||||
"x": 1169.40283203125,
|
||||
"y": 546.655395507813
|
||||
},
|
||||
{
|
||||
"x": 1172.74487304688,
|
||||
"y": 566.655395507813
|
||||
},
|
||||
{
|
||||
"x": 1169.40283203125,
|
||||
"y": 586.655395507813
|
||||
},
|
||||
{
|
||||
"x": 1160.27185058594,
|
||||
"y": 601.29638671875
|
||||
},
|
||||
{
|
||||
"x": 1147.79870605469,
|
||||
"y": 606.655395507813
|
||||
},
|
||||
{
|
||||
"x": 1135.32568359375,
|
||||
"y": 601.29638671875
|
||||
},
|
||||
{
|
||||
"x": 1126.19470214844,
|
||||
"y": 586.655395507813
|
||||
},
|
||||
{
|
||||
"x": 1122.8525390625,
|
||||
"y": 566.655395507813
|
||||
},
|
||||
{
|
||||
"x": 1126.19470214844,
|
||||
"y": 546.655395507813
|
||||
},
|
||||
{
|
||||
"x": 1135.32556152344,
|
||||
"y": 532.014404296875
|
||||
}
|
||||
],
|
||||
"radius": 32.9105350176493,
|
||||
"reshaped": false,
|
||||
"shape_type": "circle",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"closed": true,
|
||||
"fill_color": "#8C6133",
|
||||
"outline_color": "#40290F",
|
||||
"outline_width": 2.0,
|
||||
"points": [
|
||||
{
|
||||
"x": 966.386901855469,
|
||||
"y": 478.505645751953
|
||||
},
|
||||
{
|
||||
"x": 1051.41577148438,
|
||||
"y": 447.389190673828
|
||||
},
|
||||
{
|
||||
"x": 1146.44836425781,
|
||||
"y": 434.252014160156
|
||||
},
|
||||
{
|
||||
"x": 1260.01403808594,
|
||||
"y": 452.928924560547
|
||||
},
|
||||
{
|
||||
"x": 1342.70739746094,
|
||||
"y": 480.989318847656
|
||||
},
|
||||
{
|
||||
"x": 1286.82446289063,
|
||||
"y": 375.060638427734
|
||||
},
|
||||
{
|
||||
"x": 989.98193359375,
|
||||
"y": 375.060638427734
|
||||
}
|
||||
],
|
||||
"reshaped": true,
|
||||
"shape_type": "polygon",
|
||||
"vertex_flags": [
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": "1.0"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,206 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 328.366180419922,
|
||||
"y": -711.875732421875
|
||||
},
|
||||
"zoom": 0.375657439231873
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -336.0,
|
||||
"y": -972.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": 696.0,
|
||||
"y": -612.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ragdoll"
|
||||
},
|
||||
{
|
||||
"type": "recover"
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": -167.4599609375,
|
||||
"y": -596.639892578125
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ragdoll"
|
||||
},
|
||||
{
|
||||
"type": "recover"
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": -792.1015625,
|
||||
"y": -615.075927734375
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": -576.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1789757195,
|
||||
"modified_unix": 1789779264.018,
|
||||
"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,501 @@
|
||||
{
|
||||
"version": "1.2",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": -5.46832084655762,
|
||||
"y": -891.389526367188
|
||||
},
|
||||
"zoom": 0.500000059604645
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1536.0,
|
||||
"y": -192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": -192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": -192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": -192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": -192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": -192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": -192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": -192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": -224.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": -600.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "pick_up_prop",
|
||||
"target_prop_id": "prop_38150657_356201114_1",
|
||||
"hand": "auto"
|
||||
},
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -1352.0,
|
||||
"y": -246.0
|
||||
},
|
||||
"style": "run"
|
||||
},
|
||||
{
|
||||
"type": "set_down_prop",
|
||||
"target_position": {
|
||||
"x": 324.0,
|
||||
"y": -552.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -1452.0,
|
||||
"y": -276.0
|
||||
},
|
||||
"style": "run"
|
||||
},
|
||||
{
|
||||
"type": "speak",
|
||||
"text": "I Don't feel good",
|
||||
"duration": 1.8,
|
||||
"stop_current": false,
|
||||
"keep_acting": false,
|
||||
"arrangement": "together",
|
||||
"bubble_layout": "stack",
|
||||
"connect_bubbles": false,
|
||||
"reveal": "instant",
|
||||
"pop_in": false,
|
||||
"duration_mode": "just_enough",
|
||||
"bubbles": [
|
||||
{
|
||||
"text": "I Don't feel good",
|
||||
"visual": {
|
||||
"bubble_style": "talk",
|
||||
"font_preset": "comic",
|
||||
"size_preset": "medium",
|
||||
"color": "#202020",
|
||||
"effect": "none",
|
||||
"reveal": "instant",
|
||||
"pop_in": false,
|
||||
"word_styles": [
|
||||
{
|
||||
"start": 8,
|
||||
"end": 12,
|
||||
"effect": "wave",
|
||||
"color": "#e53935"
|
||||
}
|
||||
]
|
||||
},
|
||||
"placement": {
|
||||
"mode": "manual",
|
||||
"center": {
|
||||
"x": -19.8551330566406,
|
||||
"y": -681.649047851563
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "ragdoll"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": 324.0,
|
||||
"y": -684.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/championship_belt.prop",
|
||||
"stage_object_id": "prop_38150657_356201114_1",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "physics",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": true,
|
||||
"released_blocks_stickmen": false,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 4
|
||||
},
|
||||
{
|
||||
"file_id": "prop_2",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": 288.0,
|
||||
"y": -408.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/end_table.prop",
|
||||
"stage_object_id": "prop_43861651_287430243_2",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "physics",
|
||||
"holds_other_props": true,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": false,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "prop_3",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": 288.0,
|
||||
"y": -1236.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/flower_pot.prop",
|
||||
"stage_object_id": "prop_250061258_3458839433_3",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "physics",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": true,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_2",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": 888.0,
|
||||
"y": -636.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/test.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": []
|
||||
}
|
||||
],
|
||||
"event_rules": [
|
||||
{
|
||||
"id": 1,
|
||||
"trigger": {
|
||||
"type": "prop_picked_up",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": "prop_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_2",
|
||||
"params": {
|
||||
"text": "It's JOHN CENA",
|
||||
"duration": 1.6,
|
||||
"stop_current": false,
|
||||
"keep_acting": true,
|
||||
"arrangement": "together",
|
||||
"bubble_layout": "stack",
|
||||
"connect_bubbles": true,
|
||||
"reveal": "instant",
|
||||
"pop_in": false,
|
||||
"duration_mode": "just_enough",
|
||||
"bubbles": [
|
||||
{
|
||||
"text": "It's JOHN CENA",
|
||||
"visual": {
|
||||
"bubble_style": "talk",
|
||||
"font_preset": "scary",
|
||||
"size_preset": "huge",
|
||||
"color": "#202020",
|
||||
"effect": "shake",
|
||||
"reveal": "instant",
|
||||
"pop_in": false,
|
||||
"word_styles": []
|
||||
},
|
||||
"placement": {
|
||||
"mode": "manual",
|
||||
"center": {
|
||||
"x": -17.8550415039063,
|
||||
"y": -674.849975585938
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "I feel sick",
|
||||
"visual": {
|
||||
"bubble_style": "talk",
|
||||
"font_preset": "scary",
|
||||
"size_preset": "huge",
|
||||
"color": "#202020",
|
||||
"effect": "shake",
|
||||
"reveal": "instant",
|
||||
"pop_in": false,
|
||||
"word_styles": [
|
||||
{
|
||||
"start": 7,
|
||||
"end": 11,
|
||||
"effect": "wave"
|
||||
}
|
||||
]
|
||||
},
|
||||
"placement": {
|
||||
"mode": "manual",
|
||||
"center": {
|
||||
"x": 7.14495849609375,
|
||||
"y": -841.75
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ragdoll",
|
||||
"target_id": "stickman_2",
|
||||
"params": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"created_unix": 1791598662.56,
|
||||
"modified_unix": 1791598662.56,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,546 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 1721.90795898438,
|
||||
"y": -1162.85546875
|
||||
},
|
||||
"zoom": 0.413223177194595
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -1116.0,
|
||||
"y": -312.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "recover"
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": -433.3017578125,
|
||||
"y": 137.068603515625
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "pick_up_prop",
|
||||
"target_prop_id": "prop_1",
|
||||
"hand": "auto"
|
||||
},
|
||||
{
|
||||
"type": "recover"
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": 1373.3974609375,
|
||||
"y": 142.9248046875
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "throw_prop",
|
||||
"target_position": {
|
||||
"x": 2352.0,
|
||||
"y": -1176.0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -96.0,
|
||||
"y": -72.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/briefcase.prop",
|
||||
"stage_object_id": "prop_1",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2304.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2496.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2688.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_19",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2880.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_20",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3072.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_21",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3264.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_22",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3456.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_23",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3648.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "area_1",
|
||||
"type": "area",
|
||||
"position": {
|
||||
"x": 624.0,
|
||||
"y": -36.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"size": {
|
||||
"x": 96.0,
|
||||
"y": 96.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_2",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": 3516.0,
|
||||
"y": -1273.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/test.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": 3011.76782226563,
|
||||
"y": -930.535400390625
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "speak",
|
||||
"text": "THROW ME THAT CASE BRO!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 9.0
|
||||
},
|
||||
{
|
||||
"type": "pick_up_prop",
|
||||
"target_prop_id": "prop_1",
|
||||
"hand": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"event_rules": [
|
||||
{
|
||||
"id": 0,
|
||||
"trigger": {
|
||||
"type": "entered_area",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": "area_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_1",
|
||||
"params": {
|
||||
"text": "I'm gonna throw this!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"trigger": {
|
||||
"type": "prop_thrown",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": "prop_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_1",
|
||||
"params": {
|
||||
"text": "HYAHHH!!!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"trigger": {
|
||||
"type": "prop_picked_up",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": "prop_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_1",
|
||||
"params": {
|
||||
"text": "Max is a BABY!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"trigger": {
|
||||
"type": "prop_picked_up",
|
||||
"source_id": "stickman_2",
|
||||
"target_id": "prop_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_2",
|
||||
"params": {
|
||||
"text": "I'm GONNA JUMP!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target_id": "stickman_2",
|
||||
"params": {
|
||||
"target": {
|
||||
"x": 4416.0,
|
||||
"y": -960.0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"created_unix": 1790221912,
|
||||
"modified_unix": 1790393015.073,
|
||||
"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": ""
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,321 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -400.0
|
||||
},
|
||||
"zoom": 0.5
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1536.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1536.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1728.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_19",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1920.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_20",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2112.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -1368.0,
|
||||
"y": -156.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 2580.0,
|
||||
"y": 228.0
|
||||
},
|
||||
"style": "run"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1791088389,
|
||||
"modified_unix": 1791167929.379,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,567 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 1932.47973632813,
|
||||
"y": -1292.90002441406
|
||||
},
|
||||
"zoom": 0.413223147392273
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1536.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1536.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1728.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_19",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1920.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_20",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2112.0,
|
||||
"y": 288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -1368.0,
|
||||
"y": -156.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 2604.0,
|
||||
"y": -1092.0
|
||||
},
|
||||
"style": "run"
|
||||
},
|
||||
{
|
||||
"type": "speak",
|
||||
"text": "Wow! Look how high I am!",
|
||||
"duration": 2.2,
|
||||
"stop_current": false,
|
||||
"keep_acting": false,
|
||||
"arrangement": "together",
|
||||
"bubble_layout": "stack",
|
||||
"connect_bubbles": false,
|
||||
"reveal": "letter",
|
||||
"pop_in": true,
|
||||
"duration_mode": "just_enough",
|
||||
"bubbles": [
|
||||
{
|
||||
"text": "Wow! Look how high I am!",
|
||||
"visual": {
|
||||
"bubble_style": "talk",
|
||||
"font_preset": "comic",
|
||||
"size_preset": "medium",
|
||||
"color": "#202020",
|
||||
"effect": "none",
|
||||
"reveal": "letter",
|
||||
"pop_in": true,
|
||||
"word_styles": [
|
||||
{
|
||||
"start": 14,
|
||||
"end": 18,
|
||||
"effect": "shake",
|
||||
"color": "#e53935"
|
||||
}
|
||||
]
|
||||
},
|
||||
"placement": {
|
||||
"mode": "manual",
|
||||
"center": {
|
||||
"x": 17.1448974609375,
|
||||
"y": -731.795837402344
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 4083.85961914063,
|
||||
"y": -1101.71997070313
|
||||
},
|
||||
"style": "run"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_21",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 252.0,
|
||||
"y": 120.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_22",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 504.0,
|
||||
"y": -132.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_23",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 744.0,
|
||||
"y": -384.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_24",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 996.0,
|
||||
"y": -636.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_25",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1248.0,
|
||||
"y": -888.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_26",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1476.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_27",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1668.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_28",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1860.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_29",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2052.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_30",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2244.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_31",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2436.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_32",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2628.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_33",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2820.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_34",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3012.0,
|
||||
"y": -996.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1791088389,
|
||||
"modified_unix": 1791172671.377,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
{
|
||||
"version": "1.2",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": -795.213195800781,
|
||||
"y": -804.61474609375
|
||||
},
|
||||
"zoom": 0.550000071525574
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -1140.0,
|
||||
"y": -564.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -491.576904296875,
|
||||
"y": -206.43310546875
|
||||
},
|
||||
"style": "run"
|
||||
},
|
||||
{
|
||||
"type": "pick_up_prop",
|
||||
"target_prop_id": "prop_87555809_220550165_4",
|
||||
"hand": "auto"
|
||||
},
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -878.849609375,
|
||||
"y": -197.342041015625
|
||||
},
|
||||
"style": "run"
|
||||
},
|
||||
{
|
||||
"type": "set_down_prop",
|
||||
"target_position": {
|
||||
"x": -156.0,
|
||||
"y": -516.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -1157.03149414063,
|
||||
"y": -200.978515625
|
||||
},
|
||||
"style": "run"
|
||||
},
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 735.69580078125,
|
||||
"y": -200.978515625
|
||||
},
|
||||
"style": "run"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -156.0,
|
||||
"y": -1512.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/briefcase.prop",
|
||||
"stage_object_id": "prop_87555809_220550165_4",
|
||||
"roles": {
|
||||
"depth": "front",
|
||||
"start_motion": "physics",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": true,
|
||||
"released_blocks_stickmen": false,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "prop_2",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -168.0,
|
||||
"y": -324.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "crate",
|
||||
"stage_object_id": "prop_1055778436_3931179398_5",
|
||||
"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
|
||||
},
|
||||
"scale": {
|
||||
"x": 4.12768173217773,
|
||||
"y": 4.12768173217773
|
||||
},
|
||||
"material_preset": 1
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1791342771,
|
||||
"modified_unix": 1791471934.192,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": -496.058837890625,
|
||||
"y": -1357.21496582031
|
||||
},
|
||||
"zoom": 0.454545497894287
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -480.0,
|
||||
"y": -685.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "speak",
|
||||
"text": "Hello Everyone",
|
||||
"duration": 1.5,
|
||||
"stop_current": false,
|
||||
"arrangement": "together",
|
||||
"duration_mode": "just_enough",
|
||||
"bubbles": [
|
||||
{
|
||||
"text": "Hello Everyone",
|
||||
"visual": {
|
||||
"bubble_style": "shout",
|
||||
"font_preset": "comic",
|
||||
"size_preset": "huge",
|
||||
"color": "#202020",
|
||||
"reveal": "letter",
|
||||
"pop_in": true,
|
||||
"word_styles": [
|
||||
{
|
||||
"start": 6,
|
||||
"end": 14,
|
||||
"font_preset": "scary",
|
||||
"color": "#0077b6",
|
||||
"effect": "bounce"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"placement": {
|
||||
"mode": "manual",
|
||||
"center": {
|
||||
"x": 664.741455078125,
|
||||
"y": 271.705322265625
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": -96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": -96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": -96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": -96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1790483201,
|
||||
"modified_unix": 1790517359.218,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
{
|
||||
"version": "1.3",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": -312.75048828125,
|
||||
"y": -243.914947509766
|
||||
},
|
||||
"zoom": 0.885780572891235
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -756.0,
|
||||
"y": -241.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "use_prop",
|
||||
"target_prop_id": "prop_20906175_2821870920_1",
|
||||
"target_spot_id": "spot_1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -144.0,
|
||||
"y": -732.0
|
||||
},
|
||||
"rotation": 0.993539273629036,
|
||||
"asset_id": "res://content/props/championship_belt.prop",
|
||||
"stage_object_id": "prop_20906175_2821870920_1",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "still",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": true,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"use_spots": [
|
||||
{
|
||||
"id": "spot_1",
|
||||
"number": 1,
|
||||
"name": "Button",
|
||||
"position": {
|
||||
"x": -179.254028320313,
|
||||
"y": -63.7373542785645
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "spot_2",
|
||||
"number": 2,
|
||||
"name": "Lever",
|
||||
"position": {
|
||||
"x": 182.606811523438,
|
||||
"y": -29.3857421875
|
||||
}
|
||||
}
|
||||
],
|
||||
"next_use_spot_number": 5,
|
||||
"scale": {
|
||||
"x": 0.999997615814209,
|
||||
"y": 0.999997615814209
|
||||
},
|
||||
"material_preset": 4
|
||||
},
|
||||
{
|
||||
"file_id": "prop_2",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -1008.0,
|
||||
"y": -408.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/baseball.prop",
|
||||
"stage_object_id": "prop_109116485_2472952225_1",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "still",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": true,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"use_spots": [],
|
||||
"next_use_spot_number": 1,
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 2
|
||||
}
|
||||
],
|
||||
"event_rules": [
|
||||
{
|
||||
"id": 0,
|
||||
"trigger": {
|
||||
"type": "prop_used",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": null,
|
||||
"params": {
|
||||
"target_prop_id": "prop_20906175_2821870920_1",
|
||||
"spot_scope": "specific",
|
||||
"target_spot_id": "spot_1"
|
||||
}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_1",
|
||||
"params": {
|
||||
"text": "I pushed it!",
|
||||
"duration": 1.6,
|
||||
"stop_current": false,
|
||||
"keep_acting": true,
|
||||
"arrangement": "together",
|
||||
"bubble_layout": "stack",
|
||||
"connect_bubbles": false,
|
||||
"reveal": "instant",
|
||||
"pop_in": false,
|
||||
"duration_mode": "just_enough",
|
||||
"bubbles": [
|
||||
{
|
||||
"text": "I pushed it!",
|
||||
"visual": {
|
||||
"bubble_style": "talk",
|
||||
"font_preset": "comic",
|
||||
"size_preset": "medium",
|
||||
"color": "#202020",
|
||||
"effect": "none",
|
||||
"reveal": "instant",
|
||||
"pop_in": false,
|
||||
"word_styles": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"created_unix": 1791684250,
|
||||
"modified_unix": 1791849418.99,
|
||||
"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,297 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -400.0
|
||||
},
|
||||
"zoom": 0.5
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -132.0,
|
||||
"y": -673.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "speak",
|
||||
"text": "What is new?",
|
||||
"duration": 12.0,
|
||||
"stop_current": false,
|
||||
"arrangement": "take_turns",
|
||||
"bubble_layout": "stack",
|
||||
"connect_bubbles": true,
|
||||
"reveal": "letter",
|
||||
"pop_in": true,
|
||||
"duration_mode": "longest",
|
||||
"bubbles": [
|
||||
{
|
||||
"text": "What is new?",
|
||||
"visual": {
|
||||
"bubble_style": "talk",
|
||||
"font_preset": "comic",
|
||||
"size_preset": "medium",
|
||||
"color": "#202020",
|
||||
"effect": "none",
|
||||
"reveal": "letter",
|
||||
"pop_in": true,
|
||||
"word_styles": []
|
||||
},
|
||||
"placement": {
|
||||
"mode": "manual",
|
||||
"center": {
|
||||
"x": 97.1448669433594,
|
||||
"y": -701.999938964844
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "What's going on today?\nI'm planning to go to the park.\nWe will play an have fun. 👍",
|
||||
"visual": {
|
||||
"bubble_style": "shout",
|
||||
"font_preset": "comic",
|
||||
"size_preset": "medium",
|
||||
"color": "#202020",
|
||||
"effect": "none",
|
||||
"reveal": "letter",
|
||||
"pop_in": true,
|
||||
"word_styles": [
|
||||
{
|
||||
"start": 49,
|
||||
"end": 53,
|
||||
"effect": "shake",
|
||||
"color": "#0077b6"
|
||||
}
|
||||
]
|
||||
},
|
||||
"placement": {
|
||||
"mode": "manual",
|
||||
"center": {
|
||||
"x": 105.144866943359,
|
||||
"y": -942.999938964844
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": 850.0,
|
||||
"y": -350.0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1536.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1728.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": -256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -256.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1790567936,
|
||||
"modified_unix": 1790975418.635,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,18 @@
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 1070.22937011719,
|
||||
"y": -54.6092796325684
|
||||
"x": 976.030700683594,
|
||||
"y": 725.191955566406
|
||||
},
|
||||
"zoom": 0.375657439231873
|
||||
"zoom": 0.282236993312836
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 544.0
|
||||
"x": -960.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -27,8 +27,8 @@
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 544.0
|
||||
"x": -768.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -41,8 +41,8 @@
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 544.0
|
||||
"x": -576.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -55,8 +55,8 @@
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 544.0
|
||||
"x": -384.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -69,8 +69,8 @@
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 544.0
|
||||
"x": -192.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -83,8 +83,8 @@
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 544.0
|
||||
"x": 0.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -97,8 +97,8 @@
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 544.0
|
||||
"x": 192.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -111,8 +111,8 @@
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 544.0
|
||||
"x": 384.0,
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -124,65 +124,9 @@
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 544.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 544.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 544.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 544.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 544.0
|
||||
"y": -288.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -195,31 +139,90 @@
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -335.466552734375,
|
||||
"y": 132.287109375
|
||||
"x": -222.0,
|
||||
"y": -959.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://stickmen/break.stk",
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": 3112.55639648438,
|
||||
"y": 493.14306640625
|
||||
"x": -1302.19653320313,
|
||||
"y": -305.856567382813
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ragdoll"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 2048.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 2048.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 2048.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 2048.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 349.146484375,
|
||||
"y": 394.255798339844
|
||||
"x": 1536.0,
|
||||
"y": 2080.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
@@ -229,11 +232,11 @@
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 604.29833984375,
|
||||
"y": 139.10400390625
|
||||
"x": 1728.0,
|
||||
"y": 2080.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
@@ -243,11 +246,11 @@
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 860.076782226563,
|
||||
"y": -115.671752929688
|
||||
"x": 1920.0,
|
||||
"y": 2080.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
@@ -257,11 +260,11 @@
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1113.59301757813,
|
||||
"y": -367.9462890625
|
||||
"x": 2112.0,
|
||||
"y": 2080.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
@@ -271,11 +274,11 @@
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1372.07690429688,
|
||||
"y": -625.188110351563
|
||||
"x": -2112.0,
|
||||
"y": 2016.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "step",
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
@@ -285,8 +288,8 @@
|
||||
"file_id": "terrain_19",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 544.0
|
||||
"x": -1920.0,
|
||||
"y": 2016.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -299,8 +302,8 @@
|
||||
"file_id": "terrain_20",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 544.0
|
||||
"x": -1728.0,
|
||||
"y": 2016.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -313,8 +316,8 @@
|
||||
"file_id": "terrain_21",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1536.0,
|
||||
"y": 544.0
|
||||
"x": -1536.0,
|
||||
"y": 2016.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -327,8 +330,8 @@
|
||||
"file_id": "terrain_22",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1728.0,
|
||||
"y": 544.0
|
||||
"x": -1344.0,
|
||||
"y": 1984.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -341,8 +344,8 @@
|
||||
"file_id": "terrain_23",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1920.0,
|
||||
"y": 544.0
|
||||
"x": -1152.0,
|
||||
"y": 1984.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -355,8 +358,8 @@
|
||||
"file_id": "terrain_24",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2112.0,
|
||||
"y": 544.0
|
||||
"x": -960.0,
|
||||
"y": 1984.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -369,8 +372,8 @@
|
||||
"file_id": "terrain_25",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2304.0,
|
||||
"y": 544.0
|
||||
"x": -768.0,
|
||||
"y": 1984.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -383,8 +386,8 @@
|
||||
"file_id": "terrain_26",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2496.0,
|
||||
"y": 544.0
|
||||
"x": -576.0,
|
||||
"y": 1984.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
@@ -392,100 +395,12 @@
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_27",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2688.0,
|
||||
"y": 544.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_28",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2880.0,
|
||||
"y": 544.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_29",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3072.0,
|
||||
"y": 544.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "area_1",
|
||||
"type": "area",
|
||||
"position": {
|
||||
"x": 1650.52270507813,
|
||||
"y": -186.824584960938
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"size": {
|
||||
"x": 96.0,
|
||||
"y": 96.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"event_rules": [
|
||||
{
|
||||
"id": 0,
|
||||
"trigger": {
|
||||
"type": "entered_area",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": "area_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "ragdoll",
|
||||
"target_id": "stickman_1",
|
||||
"params": {}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"target_id": "stickman_1",
|
||||
"params": {
|
||||
"duration": 2.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "recover",
|
||||
"target_id": "stickman_1",
|
||||
"params": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1789479607,
|
||||
"modified_unix": 1789529735.774,
|
||||
"created_unix": 1789666501,
|
||||
"modified_unix": 1789666824.739,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
@@ -325,7 +325,7 @@
|
||||
"y": 255.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://stickmen/break.stk",
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
@@ -465,7 +465,7 @@
|
||||
"y": -2177.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://stickmen/bad.stk",
|
||||
"stk_path": "res://content/stickmen/bad.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": []
|
||||
}
|
||||
@@ -325,7 +325,7 @@
|
||||
"y": 255.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://stickmen/break.stk",
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
@@ -325,7 +325,7 @@
|
||||
"y": 255.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://stickmen/break.stk",
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
@@ -0,0 +1,546 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 1721.90795898438,
|
||||
"y": -1162.85546875
|
||||
},
|
||||
"zoom": 0.413223177194595
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": 192.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -1116.0,
|
||||
"y": -312.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "recover"
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": -433.3017578125,
|
||||
"y": 137.068603515625
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "pick_up_prop",
|
||||
"target_prop_id": "prop_1",
|
||||
"hand": "auto"
|
||||
},
|
||||
{
|
||||
"type": "recover"
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": 1373.3974609375,
|
||||
"y": 142.9248046875
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "throw_prop",
|
||||
"target_position": {
|
||||
"x": 2352.0,
|
||||
"y": -1176.0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -96.0,
|
||||
"y": -72.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/briefcase.prop",
|
||||
"stage_object_id": "prop_1",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2304.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2496.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2688.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_19",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2880.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_20",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3072.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_21",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3264.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_22",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3456.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_23",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 3648.0,
|
||||
"y": -864.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "area_1",
|
||||
"type": "area",
|
||||
"position": {
|
||||
"x": 624.0,
|
||||
"y": -36.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"size": {
|
||||
"x": 96.0,
|
||||
"y": 96.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_2",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": 3516.0,
|
||||
"y": -1273.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/test.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target": {
|
||||
"x": 3011.76782226563,
|
||||
"y": -930.535400390625
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "speak",
|
||||
"text": "THROW ME THAT CASE BRO!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 9.0
|
||||
},
|
||||
{
|
||||
"type": "pick_up_prop",
|
||||
"target_prop_id": "prop_1",
|
||||
"hand": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"event_rules": [
|
||||
{
|
||||
"id": 0,
|
||||
"trigger": {
|
||||
"type": "entered_area",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": "area_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_1",
|
||||
"params": {
|
||||
"text": "I'm gonna throw this!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"trigger": {
|
||||
"type": "prop_thrown",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": "prop_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_1",
|
||||
"params": {
|
||||
"text": "HYAHHH!!!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"trigger": {
|
||||
"type": "prop_picked_up",
|
||||
"source_id": "stickman_1",
|
||||
"target_id": "prop_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_1",
|
||||
"params": {
|
||||
"text": "Max is a BABY!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"trigger": {
|
||||
"type": "prop_picked_up",
|
||||
"source_id": "stickman_2",
|
||||
"target_id": "prop_1",
|
||||
"params": {}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "speak",
|
||||
"target_id": "stickman_2",
|
||||
"params": {
|
||||
"text": "I'm GONNA JUMP!",
|
||||
"duration": 2.0,
|
||||
"stop_current": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "walk_to",
|
||||
"target_id": "stickman_2",
|
||||
"params": {
|
||||
"target": {
|
||||
"x": 4416.0,
|
||||
"y": -960.0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"created_unix": 1790221912,
|
||||
"modified_unix": 1790393027.475,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
{
|
||||
"version": "1.4",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -400.0
|
||||
},
|
||||
"zoom": 0.5
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -120.0,
|
||||
"y": -240.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/end_table.prop",
|
||||
"stage_object_id": "prop_17571232_4221072249_1",
|
||||
"roles": {
|
||||
"depth": "front",
|
||||
"start_motion": "physics",
|
||||
"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": true,
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -708.0,
|
||||
"y": -469.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": 936.0,
|
||||
"y": -120.0
|
||||
},
|
||||
"style": "run"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1344.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_15",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1536.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_16",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1728.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_17",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1920.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_18",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 2112.0,
|
||||
"y": -64.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1791912219,
|
||||
"modified_unix": 1791922588.754,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
{
|
||||
"version": "1.4",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -400.0
|
||||
},
|
||||
"zoom": 0.5
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -384.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -192.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 192.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 384.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 576.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 768.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 960.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1152.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -792.0,
|
||||
"y": -120.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/end_table.prop",
|
||||
"stage_object_id": "prop_15501231_3425066006_1",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "still",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": true,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"use_spots": [],
|
||||
"next_use_spot_number": 1,
|
||||
"wobble_on_impact": true,
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "prop_2",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -972.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/baseball.prop",
|
||||
"stage_object_id": "prop_26034886_2936602825_2",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "physics",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": true,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"use_spots": [],
|
||||
"next_use_spot_number": 1,
|
||||
"wobble_on_impact": true,
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 2
|
||||
},
|
||||
{
|
||||
"file_id": "prop_3",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": 12.0,
|
||||
"y": -48.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "crate",
|
||||
"stage_object_id": "prop_316151302_224236905_3",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "still",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": false,
|
||||
"can_pick_up": true,
|
||||
"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": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1791922794,
|
||||
"modified_unix": 1791923002.879,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
{
|
||||
"version": "1.4",
|
||||
"scene_name": "Untitled",
|
||||
"camera": {
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": -400.0
|
||||
},
|
||||
"zoom": 0.5
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"file_id": "terrain_1",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1344.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_2",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -1152.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_3",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -960.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_4",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -768.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_5",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -576.0,
|
||||
"y": 96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_6",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -492.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_7",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -300.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_8",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": -108.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_9",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 84.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_10",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 276.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_11",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 468.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_12",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 660.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_13",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 852.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "terrain_14",
|
||||
"type": "terrain",
|
||||
"position": {
|
||||
"x": 1044.0,
|
||||
"y": 708.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "ground",
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"file_id": "prop_1",
|
||||
"type": "prop",
|
||||
"position": {
|
||||
"x": -240.0,
|
||||
"y": 516.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"asset_id": "res://content/props/end_table.prop",
|
||||
"stage_object_id": "prop_15501231_3425066006_1",
|
||||
"roles": {
|
||||
"depth": "behind",
|
||||
"start_motion": "still",
|
||||
"holds_other_props": false,
|
||||
"blocks_stickmen": true,
|
||||
"can_pick_up": true,
|
||||
"released_blocks_stickmen": true,
|
||||
"released_bumps_other_props": true,
|
||||
"legacy_draw_order": false
|
||||
},
|
||||
"use_spots": [],
|
||||
"next_use_spot_number": 1,
|
||||
"wobble_on_impact": true,
|
||||
"scale": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"material_preset": 1
|
||||
},
|
||||
{
|
||||
"file_id": "stickman_1",
|
||||
"type": "stickman",
|
||||
"position": {
|
||||
"x": -1284.0,
|
||||
"y": -312.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"stk_path": "res://content/stickmen/break.stk",
|
||||
"facing_profile": "FORWARD",
|
||||
"action_queue": [
|
||||
{
|
||||
"type": "move_to",
|
||||
"target": {
|
||||
"x": -540.0,
|
||||
"y": 48.0
|
||||
},
|
||||
"style": "run"
|
||||
},
|
||||
{
|
||||
"type": "ragdoll"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"event_rules": [],
|
||||
"metadata": {
|
||||
"created_unix": 1791922794,
|
||||
"modified_unix": 1791948300.039,
|
||||
"autosave": false,
|
||||
"source_path": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# Documentation
|
||||
|
||||
- `guides/` contains user guides and practical project workflows.
|
||||
- `architecture/` describes implemented systems and maintained technical references.
|
||||
- `specs/` contains feature specifications, including completed phase specs.
|
||||
- `ideas/` contains the live backlog of future feature ideas.
|
||||
- `plans/` contains accepted phase design briefs and active or future implementation plans.
|
||||
- `archive/` preserves older project references and completed plan drafts.
|
||||
- `known_issues.md` tracks current bugs and deferred fixes.
|
||||
|
||||
Keep `README.md` and `AGENTS.md` at the repository root for project onboarding and implementation rules.
|
||||
|
||||
## Architecture references
|
||||
|
||||
- [Repository organization](architecture/repository_organization.md) documents the feature-based folder layout, legacy content-path mapping, and serialized file-format compatibility contract.
|
||||
@@ -0,0 +1,362 @@
|
||||
# Sandbox theme reference
|
||||
|
||||
`res://sandbox_theme.json` is the hand-editable presentation configuration for
|
||||
the Sandbox Stage (`res://scenes/stage/sandbox_stage.tscn`). It is loaded by
|
||||
`SandboxStage` during `_ready()`, before the code-built UI is created. The
|
||||
loader is `res://scripts/stage/sandbox_theme.gd` (`class_name SandboxTheme`).
|
||||
|
||||
The committed file uses schema `"2.0"`. The theme controls presentation
|
||||
defaults only; it does not save a scene, placement, or action data.
|
||||
|
||||
## Load, merge, and validation rules
|
||||
|
||||
The load path is:
|
||||
|
||||
```text
|
||||
res://sandbox_theme.json
|
||||
│
|
||||
▼
|
||||
SandboxTheme.DEFAULT_CONFIG
|
||||
│ deep-merge file values
|
||||
▼
|
||||
SandboxStage._build_ui() and visual overlays
|
||||
```
|
||||
|
||||
- Missing, unreadable, malformed, or non-object JSON uses the built-in default
|
||||
configuration and emits one warning. The stage continues to run.
|
||||
- Missing nested keys inherit the built-in value. Unknown keys are retained in
|
||||
the raw dictionary but have no effect until a consumer is added.
|
||||
- `stylebox(component)` resolves styles in this order:
|
||||
`global` → `<section>.style_defaults` → the component object. For example,
|
||||
`palette` is resolved from `global`, then `palette.style_defaults`, then
|
||||
`palette`.
|
||||
- Colors must be strings in `#RRGGBB` or `#RRGGBBAA` form. Invalid colors use
|
||||
the requested fallback and emit a warning.
|
||||
- Numeric accessors accept finite integers/floats and clamp them to the range
|
||||
requested by the consumer. Invalid or non-finite numbers use that consumer's
|
||||
fallback. Size arrays are accepted when they contain two numeric values;
|
||||
individual controls apply their own minimum sizes.
|
||||
- Font paths are `res://` resource paths. A missing resource, or a resource
|
||||
that is not a `Font`, uses `ThemeDB.fallback_font` and emits a warning.
|
||||
- The theme is loaded once per Sandbox Stage instance. Restart the scene (F6)
|
||||
to see edits; there is no live file watcher or reload button.
|
||||
|
||||
The live grid size, snap toggle, and grid visibility are stored in
|
||||
`user://sandbox_settings.json`. `grid.snap_size` supplies the initial grid-size
|
||||
default; it does not overwrite a value already saved in user settings.
|
||||
|
||||
## Schema overview
|
||||
|
||||
Every current top-level block is listed below. The values shown are the
|
||||
defaults in the committed `sandbox_theme.json` (not necessarily the fallback
|
||||
used by an older caller).
|
||||
|
||||
### Current consumer status
|
||||
|
||||
The schema intentionally includes forward-looking values for the reusable
|
||||
widget and speech work. The current Sandbox runtime applies these groups:
|
||||
|
||||
- `global` style values used by resolved styleboxes and the selector control
|
||||
theme (background/border/radius/padding); `global.text_color` and
|
||||
`global.muted_text_color` are available presentation values but are not
|
||||
applied to every existing label automatically.
|
||||
- `fonts.ui_font`, `emoji_font`, bold/italic variants, the nested `sizes`
|
||||
entries for action popups, tooltips, status pills, queue/rule/action editors,
|
||||
panel rows/titles, `file_menu`, `file_menu_popup`, and `mode_switcher`, plus
|
||||
the related `flags`.
|
||||
- `mode_colors.edit`, `direct`, `play`, and `guide`; `grid.snap_size` as the
|
||||
first-run grid default; dialog sizes/fonts; `chrome.mode_switcher` width;
|
||||
palette width/card size/drag threshold/style; selector cell and thumbnail
|
||||
sizes; and all `overlays` values.
|
||||
|
||||
These declared values currently remain reserved or require a legacy adapter:
|
||||
|
||||
- `chrome.top_bar.height`, `status_bar.height`, `mode_frame`, `mode_badge`,
|
||||
and `tooltip` describe the intended chrome contract, but the corresponding
|
||||
layout/style constants are still authored in `SandboxStage`.
|
||||
- `popups.action_menu.font_size` and `popups.asset_selector.backdrop_alpha`
|
||||
are reserved component overrides. The active action-menu size comes from
|
||||
`fonts.sizes.action_popup`; selector `cell_size` and `thumbnail_size` are
|
||||
active.
|
||||
- `palette.icon_size` and `palette.selected_border_width` are reserved for
|
||||
the palette card renderer; the current card has its own glyph/border values.
|
||||
- `fonts.sizes.assignment_badge`, `rule_label`, `asset_label`, and
|
||||
`asset_badge` are part of the resolved schema, but the current direct call
|
||||
into `StageDirectorVisuals` still reads the legacy flat badge/label names.
|
||||
Use the legacy names documented below when changing those director visuals.
|
||||
- `fonts.presets` and every `widgets` list are exposed through reusable
|
||||
controls, but the current Sandbox Speak action does not instantiate those
|
||||
controls yet. They are future speech-customization data.
|
||||
|
||||
### `version`
|
||||
|
||||
| Key | Format | Current value | Notes |
|
||||
|---|---|---:|---|
|
||||
| `version` | string | `"2.0"` | Use `"2.0"` when using the nested schema below. |
|
||||
|
||||
### `global`
|
||||
|
||||
Global style values are inherited by `SandboxTheme.stylebox()` and the default
|
||||
control theme.
|
||||
|
||||
| Key | Format | Default | Purpose |
|
||||
|---|---|---:|---|
|
||||
| `font_preset` | string | `"ui"` | Named base-font selection for future/general UI use. |
|
||||
| `font_size` | integer | `18` | Default `Control` font size. |
|
||||
| `text_color`, `muted_text_color` | color string | `#F5F7FA`, `#AAB2C0` | Primary and secondary text colors. |
|
||||
| `bg_color`, `surface_color` | color string | `#171B24F2`, `#252B38FA` | Global and raised-surface backgrounds. |
|
||||
| `border_color` | color string | `#FFFFFF33` | Default border color. |
|
||||
| `border_width` | integer | `1` | Default border width. |
|
||||
| `corner_radius` | integer | `10` | Default corner radius. |
|
||||
| `padding`, `spacing` | integer | `8`, `8` | Default style padding and layout spacing. |
|
||||
|
||||
### `fonts`
|
||||
|
||||
Font paths may be empty (`""`) to use the engine fallback. `presets` is an
|
||||
object of arbitrary preset IDs; each entry has a display `label` and a `path`.
|
||||
The committed file provides `ui`, `comic`, `pixel`, and `scary` entries.
|
||||
|
||||
| Key | Format | Default | Consumer |
|
||||
|---|---|---:|---|
|
||||
| `ui_font`, `emoji_font` | `res://` path or empty | `""` | Base UI and emoji-capable stage/director controls. |
|
||||
| `ui_font_bold`, `ui_font_italic` | `res://` path or empty | `""` | Optional style variants; bold can be generated from the base font when no dedicated path is supplied. |
|
||||
| `presets` | object `{id:{label,path}}` | see JSON | `font_presets()` and future font selectors. |
|
||||
| `sizes.action_popup` | integer | `24` | Director/action popup text. |
|
||||
| `sizes.action_popup_emoji` | integer | `22` | Effective popup size when a popup font is active (Godot popup menus have one font size). |
|
||||
| `sizes.assignment_badge` | integer | `20` | Reserved resolved-theme value; current director visuals use legacy `fonts.assignment_badge_font_size`. |
|
||||
| `sizes.rule_label` | integer | `18` | Reserved resolved-theme value; current director visuals use legacy `fonts.rule_label_font_size`. |
|
||||
| `sizes.status_pill` | integer | `18` | Mode badge/pill. |
|
||||
| `sizes.tooltip` | integer | `18` | Cursor-attached targeting tooltip. |
|
||||
| `sizes.file_menu` | integer | `22` | `File` button in the top bar. |
|
||||
| `sizes.file_menu_popup` | integer | `26` | File menu and Open Recent popup rows. |
|
||||
| `sizes.mode_switcher` | integer | `24` | Edit/Direct/Play buttons. |
|
||||
| `sizes.queue_panel`, `sizes.rule_panel` | integer | `22`, `22` | Queue and rule editor panels. |
|
||||
| `sizes.action_editor`, `sizes.rule_editor` | integer | `22`, `22` | Action and rule editor controls. |
|
||||
| `sizes.panel_row`, `sizes.panel_title` | integer | `20`, `24` | Editor row text and panel titles. |
|
||||
| `sizes.asset_label`, `sizes.asset_badge` | integer | `18`, `14` | Reserved asset-card text sizing. |
|
||||
| `flags.panel_title_bold` | boolean | `true` | Bold queue/rule panel titles. |
|
||||
| `flags.rule_label_bold` | boolean | `false` | Bold director rule labels. |
|
||||
| `flags.badge_bold` | boolean | `true` | Bold director badges. |
|
||||
| `flags.action_popup_bold`, `flags.action_popup_italic` | boolean | `false`, `false` | Popup style flags. |
|
||||
|
||||
### `mode_colors`
|
||||
|
||||
Each value is a color string. These accents are used by the mode badge/frame,
|
||||
active mode controls, targeting feedback, and related stage chrome.
|
||||
|
||||
| Key | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `edit` | `#22C6FF` | Edit-mode accent. |
|
||||
| `direct` | `#FFB300` | Direct-mode accent. |
|
||||
| `play` | `#33DD77` | Play-mode accent. |
|
||||
| `guide` | `#22C6FF` | Terrain painting guide line. |
|
||||
|
||||
### `grid`
|
||||
|
||||
| Key | Format | Default | Purpose |
|
||||
|---|---|---:|---|
|
||||
| `snap_size` | finite number | `15.0` | Initial grid size, clamped to the stage's supported range. |
|
||||
|
||||
### `chrome`
|
||||
|
||||
`style_defaults` is the optional common style object for chrome components. Its
|
||||
style keys follow the `global` style formats (`bg_color`, `border_color`,
|
||||
`border_width`, `corner_radius`, `padding`).
|
||||
|
||||
| Key | Format | Default | Purpose |
|
||||
|---|---|---:|---|
|
||||
| `style_defaults` | style object | `{ "bg_color":"#171B24F2", "corner_radius":10 }` | Shared chrome style base. |
|
||||
| `top_bar.height` | number | `64` | Top navigation bar height. |
|
||||
| `status_bar.height` | number | `38` | Bottom status bar height. |
|
||||
| `mode_switcher.segment_min_width` | number | `124` | Minimum width of each Edit/Direct/Play segment. |
|
||||
| `mode_frame.border_width` | integer | `3` | Colored stage frame width. |
|
||||
| `mode_badge.corner_radius` | integer | `12` | Mode badge corner radius. |
|
||||
| `mode_badge.padding` | number | `10` | Mode badge padding. |
|
||||
| `tooltip.bg_color` | color | `#101010E6` | Targeting tooltip background. |
|
||||
| `tooltip.border_width` | integer | `1` | Targeting tooltip border. |
|
||||
| `dialogs.queue_size` | `[width,height]` | `[680,520]` | Queue editor window minimum size. |
|
||||
| `dialogs.rule_size` | `[width,height]` | `[720,560]` | Rule editor window minimum size. |
|
||||
| `dialogs.action_size` | `[width,height]` | `[560,390]` | Action editor window minimum size. |
|
||||
| `dialogs.confirm_size` | `[width,height]` | `[620,300]` | Rename, unsaved, missing-assets, and other confirmation/error windows. |
|
||||
| `dialogs.font_size` | integer | `22` | Dialog controls/buttons. |
|
||||
| `dialogs.message_font_size` | integer | `26` | Centered AcceptDialog message text. |
|
||||
|
||||
### `popups`
|
||||
|
||||
`style_defaults` accepts the normal style keys and is inherited by popup
|
||||
components.
|
||||
|
||||
| Key | Format | Default | Purpose |
|
||||
|---|---|---:|---|
|
||||
| `style_defaults` | style object | bg `#202633FA`, border `#FFFFFF33`, radius `12`, padding `12` | Common popup surface. |
|
||||
| `action_menu.font_size` | integer | `24` | Reserved action-menu component override; use `fonts.sizes.action_popup` for the active menu. |
|
||||
| `dialog` | object | `{}` | Reserved per-dialog popup overrides. |
|
||||
| `asset_selector.backdrop_alpha` | finite number | `0.55` | Reserved selector backdrop opacity. |
|
||||
| `asset_selector.cell_size` | `[width,height]` | `[190,220]` | Prop/stickman selector cell size. |
|
||||
| `asset_selector.thumbnail_size` | `[width,height]` | `[156,156]` | Prop/stickman selector thumbnail size. |
|
||||
|
||||
### `palette`
|
||||
|
||||
`style_defaults` uses normal style keys and styles the stage placement palette.
|
||||
|
||||
| Key | Format | Default | Purpose |
|
||||
|---|---|---:|---|
|
||||
| `style_defaults` | style object | bg `#252B38FA`, radius `10`, padding `6` | Palette surface/card base. |
|
||||
| `dock_width` | number | `116` | Palette width in Edit mode and stage-frame inset. |
|
||||
| `card_size` | `[width,height]` | `[96,94]` | Placement-card minimum size; the card keeps room for its label. |
|
||||
| `icon_size` | number | `30` | Reserved palette icon/glyph size. |
|
||||
| `drag_threshold` | number | `8` | Pointer distance before a card becomes a drag. |
|
||||
| `selected_border_width` | integer | `3` | Reserved selected palette card border. |
|
||||
|
||||
### `overlays`
|
||||
|
||||
`style_defaults` controls dashed overlay geometry in world pixels; colors are
|
||||
RGBA strings.
|
||||
|
||||
| Key | Format | Default | Purpose |
|
||||
|---|---|---:|---|
|
||||
| `style_defaults.line_width` | number | `2` | Dashed trajectory/guide width. |
|
||||
| `style_defaults.dash_length` | number | `8` | Dash length. |
|
||||
| `style_defaults.dash_gap` | number | `5` | Gap length. |
|
||||
| `terrain_guide.color` | color | `#22C6FF` | Terrain paint guide. |
|
||||
| `valid.color` | color | `#4DE66680` | Valid director target/placement feedback. |
|
||||
| `same_type.color` | color | `#FFFFFF26` | Same-type placement feedback. |
|
||||
| `invalid.color` | color | `#FF4D4D80` | Invalid target/placement feedback. |
|
||||
|
||||
### `widgets`
|
||||
|
||||
These lists feed reusable controls (`EmojiQuickGrid`, `FontPresetPicker`, and
|
||||
`PresetSizeToggle`). They are data sources, not speech-action persistence.
|
||||
|
||||
| Key | Format | Default | Purpose |
|
||||
|---|---|---|---|
|
||||
| `swatches` | array of color strings | white, black, cyan, amber, green, red | Color selector entries. |
|
||||
| `size_presets` | array of `{id,label,value}` objects | Small/Medium/HUGE (`20/28/40`) | Size selector entries; `value` is an integer-like size. |
|
||||
| `emoji` | array of strings | eight emoji entries | Emoji quick-grid entries. |
|
||||
|
||||
## Practical edits
|
||||
|
||||
Make the top navigation easier to read:
|
||||
|
||||
```json
|
||||
{
|
||||
"fonts": {
|
||||
"sizes": {
|
||||
"file_menu": 26,
|
||||
"file_menu_popup": 30,
|
||||
"mode_switcher": 28
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Change the mode frame and make the stage colors more distinct:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode_colors": {
|
||||
"edit": "#4DD9FF",
|
||||
"direct": "#FF8A3D",
|
||||
"play": "#65E68A",
|
||||
"guide": "#4DD9FF"
|
||||
},
|
||||
"chrome": { "mode_frame": { "border_width": 4 } }
|
||||
}
|
||||
```
|
||||
|
||||
Give selectors larger cards and thumbnails:
|
||||
|
||||
```json
|
||||
{
|
||||
"popups": {
|
||||
"asset_selector": {
|
||||
"cell_size": [220, 260],
|
||||
"thumbnail_size": [190, 190]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Make kid-facing editors and confirmations larger:
|
||||
|
||||
```json
|
||||
{
|
||||
"chrome": {
|
||||
"dialogs": {
|
||||
"queue_size": [760, 600],
|
||||
"rule_size": [800, 640],
|
||||
"font_size": 26,
|
||||
"message_font_size": 30
|
||||
}
|
||||
},
|
||||
"fonts": {
|
||||
"sizes": {
|
||||
"queue_panel": 24,
|
||||
"rule_panel": 24,
|
||||
"action_editor": 24,
|
||||
"rule_editor": 24,
|
||||
"panel_row": 22,
|
||||
"panel_title": 28
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Legacy v1 files
|
||||
|
||||
Older Phase 4b/3c theme files used flat keys such as
|
||||
`fonts.action_popup_font_size`, `fonts.queue_panel_font_size`,
|
||||
`fonts.panel_title_font_size`, and mode keys such as
|
||||
`mode_colors.edit_accent` and `mode_colors.guide_line`. They remain accepted.
|
||||
The loader aliases the legacy mode names and selected flat font-size names into
|
||||
the nested structure, while `SandboxStage` retains the old precedence for a
|
||||
file that does not declare version `"2.0"`.
|
||||
|
||||
The complete legacy names still read by the current runtime are:
|
||||
|
||||
```text
|
||||
fonts.action_popup_font_size fonts.action_popup_emoji_size
|
||||
fonts.assignment_badge_font_size fonts.assignment_badge_radius
|
||||
fonts.rule_label_font_size fonts.status_pill_font_size
|
||||
fonts.tooltip_font_size fonts.queue_panel_font_size
|
||||
fonts.rule_panel_font_size fonts.action_editor_font_size
|
||||
fonts.rule_editor_font_size fonts.panel_row_font_size
|
||||
fonts.panel_title_font_size fonts.panel_title_bold
|
||||
fonts.rule_label_bold fonts.badge_bold
|
||||
fonts.action_popup = { size, bold, italic }
|
||||
|
||||
mode_colors.edit_accent mode_colors.direct_accent
|
||||
mode_colors.play_accent mode_colors.guide_line
|
||||
```
|
||||
|
||||
For a migration, copy the values into the nested keys in this document and set
|
||||
`"version": "2.0"`. Keep only one spelling of each setting so the result is
|
||||
easy to maintain.
|
||||
|
||||
## Fonts, emoji, and troubleshooting
|
||||
|
||||
- Use project-relative paths such as `res://fonts/kids_font.ttf`; do not use a
|
||||
machine-specific absolute path.
|
||||
- If text falls back to the Godot default, check the path, import status, and
|
||||
that the resource is actually a `Font`/font file. Restart the Sandbox after
|
||||
correcting it.
|
||||
- Emoji availability depends on the selected font and platform glyph support.
|
||||
A missing `emoji_font` is non-fatal; the normal UI fallback remains usable.
|
||||
- If a color or number is ignored, check JSON commas/quotes, use a supported
|
||||
color form, and keep numbers finite. The warning identifies the affected key.
|
||||
- If a selector or dialog looks cramped, increase its size array and its
|
||||
related font size together; restart F6 to reload the file.
|
||||
|
||||
## Speech customization status
|
||||
|
||||
`fonts.presets` (`ui`, `comic`, `pixel`, `scary`), `widgets.size_presets`,
|
||||
`widgets.swatches`, and `widgets.emoji` are the reusable data contract for a
|
||||
future speech-customization UI. They are intentionally available now so a
|
||||
future Speak dialog can consume the same theme.
|
||||
|
||||
The current Sandbox speech action still stores and renders text through the
|
||||
existing `StickmanSpeechBubble`; these theme lists do not yet change saved
|
||||
speech actions, bubble shape, bubble colors, or bubble font at runtime. Do not
|
||||
assume that changing a preset changes an existing speech action. Treat
|
||||
speech-specific fields under `popups.dialog` or future bubble sections as
|
||||
reserved until that feature is implemented.
|
||||
@@ -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,46 @@
|
||||
# Repository organization
|
||||
|
||||
## Maintained layout
|
||||
|
||||
| Path | Responsibility |
|
||||
|---|---|
|
||||
| `scenes/main.tscn` | Startup wrapper; configured as `run/main_scene` and hosts the Stickman Editor. |
|
||||
| `scenes/editors/{stickman,prop,stage}/` | Feature editor scenes. |
|
||||
| `scenes/stage/` | Sandbox Stage runtime scenes. |
|
||||
| `scenes/characters/stickman/` | Stickman runtime rig scenes. |
|
||||
| `scenes/tools/` | Test and physics harness scenes. |
|
||||
| `scenes/legacy/` | Preserved legacy rig scenes. |
|
||||
| `scripts/editors/{stickman,prop,stage}/` | Editor controllers and feature-specific editing systems. |
|
||||
| `scripts/{stage,characters/stickman,props,terrain,speech}/` | Runtime and domain systems grouped by feature. |
|
||||
| `scripts/shared/` | Reusable UI, thumbnail, and content-path utilities. |
|
||||
| `scripts/tools/` | Harness and rig-authoring scripts. |
|
||||
| `content/{stickmen,props,stages}/` | Project-managed `.stk`, `.prop`, and `.scene` libraries. |
|
||||
| `resources/fonts/` | Project fonts. |
|
||||
| `docs/{guides,architecture,specs,plans}/` | Maintained guides, architecture references, specifications, and active plans. |
|
||||
| `docs/archive/` | Older project references and completed plan drafts. |
|
||||
|
||||
Scripts and scenes remain separate roots, with feature-specific editor code and scenes grouped by workflow. Godot `.gd.uid` files stay beside their scripts; scene resource UIDs are retained when scenes move.
|
||||
|
||||
## Content path compatibility
|
||||
|
||||
`ContentPaths` is implemented in `scripts/shared/content_paths.gd`. Its `canonicalize(path: String) -> String` helper maps project-relative legacy paths to the new library locations:
|
||||
|
||||
| Legacy project path | Canonical path |
|
||||
|---|---|
|
||||
| `res://stickmen/<file>.stk` | `res://content/stickmen/<file>.stk` |
|
||||
| `res://props/<file>.prop` | `res://content/props/<file>.prop` |
|
||||
| `res://game_scenes/<file>.scene` | `res://content/stages/<file>.scene` |
|
||||
|
||||
Equivalent project-relative inputs (for example, `stickmen/<file>.stk`) map to relative `content/...` paths, and absolute paths under the project root keep their absolute form while their legacy directory is rewritten. `user://` paths, unrelated relative paths, unknown project folders, and absolute paths outside the project are passed through unchanged. Keep path-bearing loads, saves, persisted references, recents, and recovery metadata routed through `canonicalize()` so existing project references continue to resolve after the move.
|
||||
|
||||
## Serialized file compatibility
|
||||
|
||||
The organization change moves libraries and code without changing the `.stk`, `.prop`, or `.scene` document schemas. It adds no serialized fields and requires no format-version bump. Existing field meanings and codec migrations remain authoritative:
|
||||
|
||||
| Format | Current codec version | Compatibility |
|
||||
|---|---|---|
|
||||
| `.stk` | `1.5` | The Stickman Editor accepts `1.0`–`1.4` files and migrates them on load. |
|
||||
| `.prop` | `1.0` | `PropFile` accepts version `1.0`; missing supported optional fields use codec defaults. |
|
||||
| `.scene` | `1.1` | `StageSceneIO` accepts `1.0` and migrates it to `1.1` on load. |
|
||||
|
||||
When a stage is loaded or saved, its document path and path-valued asset references are canonicalized. A legacy reference such as `res://stickmen/basic.stk` may therefore be serialized as `res://content/stickmen/basic.stk` on the next save. This changes the stored path value only: the `.scene` field structure and version remain unchanged, with no added keys.
|
||||
@@ -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`.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Speech System — As Built
|
||||
|
||||
**Updated:** 2026-10-03
|
||||
|
||||
This is the current implementation overview for speech authoring and playback. It records the reviewed UX and the behavior present in the stage scripts. The detailed specifications linked below provide payload and layout specifics; older plans and superseded proposals are historical context, not the current UI contract.
|
||||
|
||||
## Editor flow
|
||||
|
||||
`SandboxStage` opens a speech editing session anchored to the character and keeps a live bubble preview on the stage. `SpeechComposer` owns the editable draft, selected bubble, Message editor, recovery data, and preview clock. Stage-side controls are split by scope:
|
||||
|
||||
| Control | Scope | Current behavior |
|
||||
| --- | --- | --- |
|
||||
| **Speech Style** | Selected bubble | Message, Frame, Letters, and Effects; selecting a stage word targets that word, otherwise text/font/size/color/effect choices apply to the bubble. |
|
||||
| **Show speech** | Whole sequence | Show all or One at a time, Stack or Same spot placement actions, and a separate Connect bubbles toggle. More speech settings contains reveal, entrance motion, timing, and Keep acting while talking. |
|
||||
| **Preview speech** | Whole sequence | Plays the current draft on the stage without committing it. |
|
||||
| **Done styling** | Style controls | Hides Speech Style while leaving the speech session open. |
|
||||
| **Done speech / Cancel speech** | Editing session | Done commits the validated draft to its queue/rule destination. Cancel discards the session, with confirmation for changed drafts. |
|
||||
|
||||
Draft changes are recoverable while editing. They do not mutate the queued action until Done speech. Scene saving remains a separate operation after the in-memory speech commit.
|
||||
|
||||
## Bubble editing and presentation
|
||||
|
||||
- Each bubble has its own message, frame, font, size, text color, effects, and stage position. Numbered stage badges select bubbles; Earlier/Later changes their reading order without changing placement.
|
||||
- Add bubble inserts after the selected bubble and carries over its bubble-level appearance defaults. The current cap is eight bubbles, with a hint at five. Remove is unavailable for the last bubble; Undo appears only after a removal and restores that bubble.
|
||||
- Stack arranges the sequence upward from Bubble 1. Same spot aligns bubbles to Bubble 1's center. These are placement actions; Connect bubbles is a separate on/off presentation setting. With connections on, the sequence builds cumulatively: Bubble 1 points to the character and later balloons attach to the prior bubble. Think uses thought dots; SFX has no connector.
|
||||
- Show all and One at a time remain the sequence visibility choices. Reveal supports all at once, letter by letter, and word by word. Entrance motion is Bounce in or Just appear; timing is Normal, Slow, or Slower. Reactive speech can use Keep acting while talking.
|
||||
- The Message sub-dialog is attached to Speech Style and does not dim the stage. Its text field stays in place as the emoji grid opens and the dialog grows downward. Opening Message puts the caret at the end; emoji inserts at the caret.
|
||||
- Text edits preserve valid word styling: edits within styled words retain styling on remaining/replacement content; inserted text inherits the preceding token's style, or the following token's style at the start. Bubble-level controls change only the selected bubble unless a stage word is targeted.
|
||||
- Talk, Shout, and Whisper render a continuous filled body-and-tail contour. Think uses dots; SFX is tailless. Text is measured against the selected font and size with added inner padding, including larger Shout padding. Preview and runtime use the same generated bubble geometry; no external bubble SVG is required.
|
||||
- Speech order badges remain screen-sized across camera zoom and do not move when selection changes. Crowded badges are sorted into a row/rail; intersecting bubble frames form a sorted row above the largest frame when space allows. Speech panels avoid the resolved badge bounds.
|
||||
- Bubble dragging hit-tests the smallest bubble under the pointer, breaking equal-size ties in favor of the topmost bubble. A click where bubbles overlap still opens the bubble picker; clicking a badge selects that numbered bubble and brings it forward for editing.
|
||||
|
||||
## Data and rendering flow
|
||||
|
||||
Speech is stored as a normalized action `Dictionary` with action-wide sequence settings and an ordered `bubbles[]` array. Each bubble stores plain text, visual defaults, optional whole-word style spans, and placement. `SpeechPayload` validates and normalizes data before the stage preview, queue/rule routing, scene serialization, or runtime playback. Legacy single-text speech remains loadable; legacy comic-chain payloads are normalized to the current connection setting.
|
||||
|
||||
The editor preview and runtime playback share `SpeechBubble`. `StickmanActionRunner` owns runtime elapsed time and speech completion; `StageSceneIO` and `ActionRegistry` preserve speech fields in saved scenes and rule actions. The editor preview is separate from runner playback and does not advance or replace runtime speech state.
|
||||
|
||||
## Main implementation files
|
||||
|
||||
| File | Responsibility |
|
||||
| --- | --- |
|
||||
| `scripts/editors/stage/speech_composer.gd`, `scenes/editors/stage/speech_composer.tscn` | Draft editing, bubble management, Message/Emoji UI, recovery, style context, and preview state. |
|
||||
| `scripts/speech/speech_style_toolbar.gd` | Bubble-scoped stage controls and attached choosers. |
|
||||
| `scripts/speech/speech_show_toolbar.gd` | Whole-sequence controls, layout presets, preview/done/cancel, and More settings. |
|
||||
| `scripts/speech/speech_payload.gd` | Payload defaults, validation, migration, word spans, and duration calculation. |
|
||||
| `scripts/speech/stickman_speech_bubble.gd` | Shared preview/playback renderer, bubble measurement and geometry, word targeting, order badges, and bubble hit testing. |
|
||||
| `scripts/editors/stage/sandbox_stage.gd` | Session lifecycle, stage input routing, toolbar placement, badge avoidance, and queue/rule commit. |
|
||||
| `scripts/characters/stickman/stickman_action_runner.gd` | Runtime speech clocks and bubble ownership. |
|
||||
| `scripts/stage/stage_scene_io.gd`, `scripts/stage/action_registry.gd` | Scene and rule serialization adapters. |
|
||||
| `scripts/stage/sandbox_theme.gd`, `sandbox_theme.json`, `resources/fonts/` | Theme-backed speech font presets and per-font base sizes; Comic, Pixel, and Scary font assets are included. |
|
||||
|
||||
## Detailed behavior specifications
|
||||
|
||||
- [Whole-sequence Show controls](../docs/specs/speech_whole_sequence_show.md)
|
||||
- [Speech Style toolbar](../docs/specs/speech_style_toolbar.md), [live editing](../docs/specs/speech_style_toolbar_live_edit.md), and [Message/Emoji/Timing](../docs/specs/speech_message_emoji_timing.md)
|
||||
- [Bubble layout presets](../docs/specs/speech_bubble_layout_presets.md) and [bubble visuals](../docs/specs/speech_bubble_visuals.md)
|
||||
- [Badge stability, grouping, and toolbar avoidance](../docs/specs/speech_badge_stability.md)
|
||||
- [Phase 13 payload and playback details](../docs/specs/phase_13_speech_bubbles.md)
|
||||
|
||||
## Validation status
|
||||
|
||||
The user reviewed the recent badge clustering and overlapping-bubble drag behavior and reported that the speech editor looked good. Focused Godot syntax checks and `git diff --check` passed for those latest fixes. The saved `content/stages/talk.scene` had also loaded through the Sandbox Stage CLI without a skipped-speech warning during the earlier Phase 13 verification (2026-09-28). This does not claim a complete automated or GUI regression pass for every speech control and runtime mode.
|
||||
@@ -0,0 +1,197 @@
|
||||
# Technical Debt & Optimization Log
|
||||
|
||||
## Overview
|
||||
|
||||
This document tracks known technical debt, optimization opportunities, and minor improvements for the Stickman Studio project. Items are prioritized by impact and effort. Update this log as issues are identified, resolved, or deprioritized.
|
||||
|
||||
---
|
||||
|
||||
## Current Observations
|
||||
|
||||
| # | Issue | Priority | Status | Notes |
|
||||
| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1 | **Ragdoll Neck Angular Limits** — The ragdoll neck `PinJoint2D` remains unrestricted, so a violent physical tumble can still rotate the head freely. | Medium | Open | Phase 4.5 fixes the separate ANIMATED collision-flinch accumulation bug by bounding offsets from a captured base rotation; it does not change ragdoll neck limits. Consider a tuned angular band/stiffness when natural ragdoll head motion is revisited. |
|
||||
| 2 | **Torso Capsule Origin** — The torso capsule's local origin should be at its midpoint for natural rotation. Currently derived from bone distance; verify alignment. | Low | Open | Test by rotating the torso body in ragdoll mode — it should spin about its center, not its top. Adjust `position` offset if needed. |
|
||||
| 3 | **Collision Layers Separation** — Bodies and terrain share layer 1/mask 1. This may cause self‑collision issues (limbs clipping through each other) under high stress. | Low | Open | Future enhancement: assign ragdoll limbs to layer 2, terrain to layer 1, and use masks to allow limb‑limb collision only where desired. |
|
||||
| 4 | **Performance (Ragdoll Pooling)** — Spawning 10 bodies + 9 joints procedurally is fine for a single rig. If the scene ever contains dozens of ragdolls, consider a pooling system to avoid allocation spikes. | Low | Open | Not needed now, but worth noting if scaling to large crowds. |
|
||||
| 5 | **Animated Collision Proxy Approximation** — Stickman collision proxies use fixed-radius capsules for torso and limbs rather than exact mounted-shape polygons. | Low | Open | Phase 4.5 synchronizes ten proxies to the rendered parts and grows the head circle to cover mounted geometry (minimum radius 90 px), but torso/limb capsule radii remain approximate and do not adapt to arbitrary custom widths. Consider per-shape collision generation only if visible misses justify the complexity. (2026-09-12) |
|
||||
| 6 | **Recovery Animation Starting Pose** — The `stand_up` animation must work from any captured ragdoll pose. Currently uses a fixed start frame. | High | ✅ Resolved | Phase 11: `_start_recovery()` captures the 10 bodies' rig‑local pose, snap‑solves the skeleton via the 6 IK targets, then `_play_stand_up()` tweens the markers **directly** from the captured values to `STAND_POSE` (`STAND_UP_DURATION`, sine ease‑in‑out) — the baked `stand_up` animation is **not** played (a fixed first keyframe can never match an arbitrary rest pose; the earlier bridge‑into‑the‑animation approach caused a visible jump and was removed). Revision: the snap now derives the hip (`pos − dir·half`) and wrist/ankle (`pos + dir·half`) from the capsule ends and subtracts the Torso bone's `bone_angle` for the marker rotation, so recovery starts from the ragdoll's exact final pose (e.g. sitting stays sitting). (2026‑08‑27) |
|
||||
| 7 | **Transition Visual Pop** — The crossfade between kinematic and ragdoll currently uses a simple `modulate.a` lerp. This may cause ghosting if the kinematic and ragdoll poses are misaligned. | Medium | ✅ Resolved | Phase 11: the entry is now an **instant handoff** — the ragdoll is built from the **current solved bone positions** (`AnimationPlayer.stop(true)` keeps the pose), then `Body/*` is hidden and the IK stack disabled in the same call. The earlier opacity crossfade + pin‑softness ramp was **removed on director feedback** (it read as ghosting, since both poses are identical). Recovery snap‑solves the kinematic skeleton to the captured ragdoll pose before re‑showing `Body/*`, eliminating the pop on both directions. (2026‑08‑27) |
|
||||
| 8 | **Rest Timeout UI** — The director can adjust `rest_timeout` via inspector, but there is no in‑world UI in the physics harness yet. | Low | ✅ Resolved | Phase 11: added a Rest `SpinBox` (0.1–10 s, step 0.1) to the harness UI that writes `_rig.rest_timeout` (runtime‑only), plus a "Recover Now" button → `_rig.request_recovery()`. (2026‑08‑27) |
|
||||
| 9 | **Animation Generation DRY** — `create_walk.gd` is a standalone script. It should be merged into a unified `create_animations.gd` that also generates `stand_up` and idle animations. | Medium | ✅ Resolved | Phase 11: `create_walk.gd` deleted; new `scripts/tools/create_animations.gd` (`@tool extends EditorScript`) bakes `walk_left`/`walk_right` (same keyframes) and a one‑shot `stand_up` into the scene's `AnimationLibrary` (the baked `stand_up` is an authored reference only — runtime recovery tweens the IK targets directly). (2026‑08‑27) |
|
||||
| 10 | **Rig Collision Proxy Re‑addition** — The proxy is re‑added on ragdoll exit, but may cause a brief visual pop if it appears while the kinematic rig is visible. | Low | Open | Phase 11 still re‑adds the proxy as soon as `RECOVERING` begins (`state_changed` handler), while `Body/*` is already visible — the static box can pop in around the standing figure before the stand‑up completes. Consider delaying re‑addition until after recovery finishes (`ANIMATED`). (2026‑08‑27) |
|
||||
| 11 | **Stage Freeze Abstraction** — Sandbox Stage EDIT‑mode freezing is type‑specific: `RigidBody2D.freeze_mode = FREEZE_MODE_KINEMATIC` for props, `StickmanRig.set_ragdoll(false)` for stickmen, nothing for `StaticBody2D` terrain. There is no unified "freeze" abstraction over the mixed physics population. | Low | Open | A future physics type (e.g. `Area2D`‑based sensors) will need another case in `scripts/editors/stage/sandbox_stage.gd` `_enter_edit_mode()` / `_enter_play_mode()`. Consider a duck‑typed `set_simulating(bool)` interface once more physical object kinds appear. (2026‑08‑27) |
|
||||
| 12 | **Stage AABB Selection Precision** — `StageSelection.get_world_aabb` uses conservative world‑space AABBs (polygon point union / fixed rig rect), not point‑in‑polygon. | Low | Open | Clicks in the bounding‑box corners of large or rotated terrain may select a block even outside its polygon, and overlapping blocks can mis‑select. Refine with `Geometry2D.is_point_in_polygon()` for `TerrainBlock`/`PropBlock` polygons (and circle distance for ball props) once selection precision matters. (2026‑08‑27) |
|
||||
| 13 | **Slope-aware walking physics & dynamic obstacle avoidance (deferred)** — Phase 3a bakes a real navigation mesh (per-`TerrainBlock` polygon decomposition into a code-built `NavigationRegion2D`) and `walk_to` follows `NavigationAgent2D` paths, but the figure walks the path with an upright pose (no tilt to the slope, no physics sliding) and `avoidance_enabled = false`, so it can path through props and other stickmen. | Medium | Open | A stickman crossing a ramp/stair follows the sloped footprint but looks flat-footed, and does not avoid moving props or each other. Future: tilt/rotate the figure to the path slope and enable RVO avoidance (`avoidance_enabled`, avoidance layers, `velocity` handling) once content/props/other stickmen are registered as obstacles. (2026‑08‑29) |
|
||||
| 14 | **Phase 4 event engine is O(rigs×props + areas×movables) per physics frame** — `sandbox_stage.gd` `_update_area_entry()` / `_update_stickman_prop_collision()` run all-pairs geometric tests every physics frame in PLAY. | Low | Open | Fine at sandbox scale, but degrades quadratically with dozens of dynamic objects. A cell-keyed spatial broadphase (e.g. `_grid_cells`) can cull candidate pairs before the visible-AABB/feet-point tests. Phase 4b implemented that index (see #16, now Resolved) but the event engine does **not yet query it** — #14 remains Open until `_update_area_entry()` / `_update_stickman_prop_collision()` use it. (2026‑08‑30 / note updated 2026‑09‑02) |
|
||||
| 15 | **Walk arrival jitter (mode re-evaluated per frame + arrival-radius mismatch)** — `StickmanRig._update_walking()` re-computes `_walk_mode` from `is_target_reachable()` every physics frame, and finishes via `is_navigation_finished()` (`NAV_TARGET_DESIRED_DISTANCE` 12 px, feet-space) *or* the `ARRIVE_DISTANCE` 8 px root-space guard. Near the nav-mesh boundary (clicked waypoints often sit just off placed terrain) `is_target_reachable()` can flip, swapping `root_target` between the nav path point and the raw waypoint — two points with a small vertical offset → up/down jitter. | Medium | ✅ Resolved | Phase 4b: `StickmanRig._update_walking()` now **latches `_walk_mode` once per walk** (probes up to `LATCH_PROBE_MAX_FRAMES` = 6 after the map syncs, latching `"nav"` when reachable or `"direct"` on the bound) so it can never flip between frames, unifies arrival on the **final target** at `ARRIVE_DISTANCE` 8 px (snap-on-arrive), steers straight at the final target when within `2 × ARRIVE_DISTANCE`, and re-asserts the standing markers one extra physics frame after stop (`_settle_walk_markers()`) to clear any residual body-bob. Exactly one `arrive` fires; `global_position` is unchanged after arrival. See `docs/archive/plans/PHASE_4b_SPEC.md` §3. (2026-09-02) |
|
||||
| 16 | **No grid spatial dictionary** — terrain placement (`sandbox_stage.gd` `_place_at`) is single-click with no occupancy tracking; the 3-state "empty/same-type/blocked" drag-paint query and any spatial broadphase need a cell→nodes index. | Low | ✅ Resolved | Phase 4b adds an **advisory** grid spatial dictionary `_grid_cells` (cell `Vector2i` @ `TERRAIN_GRID_SIZE` 16 → `Array[Node2D]`) plus `_rasterize_aabb_to_cells()` to index every world AABB's covered cells; it drives the terrain drag-painting 3-state ghost query and the director target-validity test (skipping cells whose nodes include a `TerrainBlock`). It is populated on place, rebuilt on move/rotate/delete, and is **never authoritative** (the `World` tree is). It is **not yet wired into the Phase 4 event engine** — #14 stays Open for that. See `docs/archive/plans/PHASE_4b_SPEC.md` §2.6. (2026-09-02) |
|
||||
| 17 | **Thumbnail caching has no eviction / cap; render is deferred one-per-frame** — Phase 3b (`stickman_library.gd` / `prop_library.gd` + `thumbnails/*`) caches rig/prop thumbnails to `user://thumbnails/` keyed by stickman basename+mtime and prop `id_v<PROP_VERSION>`. | Low | Open | PNGs accumulate unboundedly on disk (only `clean_stale_stickmen` prunes superseded basenames; nothing caps total bytes), and in-headless the renderers return `null` → a placeholder is shown until a **manual F6 run** populates real captures. Future: a disk-size/LRU eviction policy, a version/cleanup sweep on stage open, and an explicit cache-warm pass (or skip-the-placeholder note) for headless/CI. (2026-09-03) |
|
||||
| 18 | **Asset selection is session-only, not saved** — `StageSpawner.selected_stickman_path` / `selected_prop_id` reset on scene reload (Phase 3b decision, per spec). | Low | Open | Deliberate for Phase 3b (spec §2 decision 1: no disk save, do not extend `_save_settings`). A future persistence phase could persist the last-chosen stickman/prop to `user://sandbox_settings.json` for convenience. (2026-09-03) |
|
||||
| 19 | **Phase 3c editor-popup host-visibility discipline is ad-hoc** — the new `QueuePanel` / `RulePanel` / `ActionEditor` / `RuleEditor` are `exclusive = true` `PopupPanel`s, so the stage must hide a host popup before entering a stage-click capture (or opening a nested editor) and re-show it on resolve/cancel. That logic is spread across `_open_action_editor`, `_on_action_editor_committed` / `_cancelled`, `_begin_walk_edit`, and `_on_rule_editor_trigger_target_requested`, with one-off `_restore_queue_panel` / `_restore_rule_panel` / `_restore_rule_build_panel` helpers. | Medium | Open | Works, but fragile: any future editor popup must remember to hide its host before every capture or the exclusive window swallows the stage click. A small popup-stack abstraction (push host → capture → pop) would make that impossible to forget. (2026-09-04) |
|
||||
| 20 | **Rule Panel "Add Rule" has no source in waypoint-filtered panels** — `_on_rule_panel_add_requested` bails with a toast when `_rule_panel_source_id < 0`, which is exactly the state of the waypoint-filtered "Edit Trigger Rules" panel (opened from the waypoint context menu). | Low | Open | The trigger source is genuinely ambiguous there (a waypoint can be targeted by rules authored by several stickmen). Acceptable for now; a future pass could default the source to `_ctx_waypoint_rig` (the rig that owns the waypoint) or open the builder in "any stickman" (source −1) mode. (2026-09-04) |
|
||||
| 21 | **Phase 3c drag-reorder uses nearest-row-center, not an insertion point** — `QueuePanel` / `RulePanel` reorder computes the drop target as the row whose vertical center is nearest the mouse, then moves the dragged item to that index. | Low | Open | Functional, but the drop position can read off-by-one near row boundaries (it snaps to a whole row rather than an edge between rows). A true insertion-point indicator (a line drawn between rows) would be clearer; not worth the complexity until reordering long queues/rules is common. (2026-09-04) |
|
||||
| 22 | **`--check-only --script` needs a prior `--editor` rescan for new `class_name` scripts** — a freshly added `class_name` (e.g. `QueuePanel`) is not resolvable by `--check-only --script res://scripts/editors/stage/sandbox_stage.gd` until `--headless --editor --quit` regenerates `.godot/global_script_class_cache.cfg`. | Low | Open | Verification-workflow gotcha only (not a runtime bug): in-editor the cache is always current. CI/headless scripts that add new `class_name`s should run an `--editor` pass before per-script `--check-only`. (2026-09-04) |
|
||||
| 23 | **Phase 3c confirmation dialog is popped over an exclusive panel** — Queue delete / Clear All (`_on_queue_panel_delete_requested` / `_on_queue_panel_clear_requested`) and Rule delete / Clear All (`_on_rule_panel_delete_requested` / `_on_rule_panel_clear_requested`) call the shared `ConfirmationDialog` (`_ask_confirm`) **without first hiding the `exclusive = true` `QueuePanel` / `RulePanel`**. | Low | Open | Distinct facet of #19 (host-visibility discipline): popping a second exclusive window over a visible exclusive panel logs a **non-fatal engine warning** and the confirmation may render **non-modal**. It still functions (the panel is re-shown after the callback) — cosmetic. A fix would hide the host panel around `_ask_confirm` and re-show it in the confirm callback (and on the dialog's cancel/hide). Deliberate non-debt note: plan §11.2's separate confirmation dialog for editing `ragdoll`/`recover` actions was implemented instead as a paramless `ActionEditor` pre-fill — recorded in `docs/specs/phase_3c_editor_spec.md` §2 decision 5, not as a debt row. (2026-09-04) |
|
||||
| 24 | **Sandbox rule references use session instance IDs at runtime** — trigger sources/targets and action actors use `Object.get_instance_id()` integers; StageSceneIO remaps these through per-save `file_id` values. | Low | Open | This is correct for the current in-memory engine and save/load remapping. Phase 11’s approved spec adds persistent per-instance prop `stage_object_id` values for queue/rule prop actions and upgrades the scene format to 1.1; implementation and compatibility verification remain open. (2026‑09‑11; spec decision 2026‑09‑24) |
|
||||
| 25 | **Contact direct-state timing fallback** — `PropBlock` may receive `body_entered` before a matching direct-state contact row is available. | Low | Open | `_on_body_entered()` uses the documented center-direction / prop-position fallback when the row is absent, so the signal remains safe but the normal and position are less precise on that edge. (2026-09-12) |
|
||||
| 26 | **Impact speed is a coarse magnitude** — collision reactions currently scale from `prop.linear_velocity.length()`, not normal-relative velocity or an impulse computed from contact mass. | Low | Open | This keeps the signal contract simple and deterministic. Use the normal component and/or contact impulse if reaction strength needs to reflect glancing impacts accurately. (2026-09-12) |
|
||||
| 27 | **Post-IK reaction timing is engine-order-sensitive** — bounded flinch offsets are applied at the end of `StickmanRig._physics_process()`, after the IK/head-pin work. | Low | Open | The current slot is verified and prevents cumulative rotation, but future changes to Skeleton2D modification ordering could overwrite or delay the visible reaction. Revisit only with a targeted engine-order regression. (2026-09-12) |
|
||||
| 28 | **Airborne collision sweep cost scales per proxy** — Phase 6a tests the horizontal movement against each of the rig's ten synchronized collision proxies every airborne physics frame. | Low | Open | The per-proxy `PhysicsShapeQueryParameters2D.cast_motion()` checks reuse the existing proxy shapes and avoid a second body-size approximation; this is acceptable for the current sandbox scale. With many simultaneously falling rigs, the cost grows with `rigs × 10` casts per physics frame. Consider a combined query shape or broadphase candidate filter if airborne crowds become a target. (2026-09-17) |
|
||||
| 29 | **Prop Editor multi-shape → single-shape `PropBlock` flattening** — Phase 9 (`.prop` v1.0) stores a full multi-shape `shapes[]` stack, but `PropFile.flatten_to_payload()` collapses it into the one payload `PropUtils.spawn_prop()` consumes (frontmost closed polygon → circle → first shape). Also: a circle whose vertices were hand-edited still flattens by an average-distance radius, and a non-NONE preset thumbnail ignores payload colors because `PropThumbnail` re-tints from the preset. | Low | Open | Deliberate contract until a multi-shape `PropBlock` composition (multiple `Polygon2D`/`Line2D` children + merged collision) exists; recorded per `docs/specs/phase_9_prop_editor.md` §6. Custom `.prop` thumbnails are mtime-keyed (`ThumbnailCache.prop_file_key`/`prop_file_png`, `<basename>_<mtime>.png`), so re-edits invalidate the cached PNG; built-in template PNGs stay `id_v<PROP_VERSION>`-keyed. (2026-09-18) |
|
||||
| 30 | **Prop Editor Round 2 interaction model** — vertex editing and shape transform are separated into two explicit canvas modes (`EditMode { TRANSFORM, POINTS }`, kid-facing "Move & Resize" / "Edit Points") driven by an always-visible toolbar toggle; "Create Point" inserts at the cursor's segment projection and flashes the new vertex (0.6 s) instead of inserting an invisible collinear midpoint. | Low | Open | Deliberate, user-approved design (`docs/specs/phase_9_prop_editor_round2.md` §5): modes gate *input* only — all public math APIs stay mode-agnostic. "Create Point" stays outline-only per user decision; auto-begin-drag was rejected as modal/surprising. Revisit only if kids find the two modes confusing in practice. (2026-09-18) |
|
||||
| 31 | **Prop Editor Round 3 chrome/autosave decisions** — exit-save skips the thumbnail render (fast, deterministic quit; the PNG is a cache nicety), autosave is debounced 1.0 s to `user://prop_editor_autosave.prop` via `PropFile.save_safe` (atomic tmp/bak swap), and all human-facing strings (mode labels/emoji, menu copy) live in the `prop_editor.gd` controller while the canvas stays string-free. | Low | Open | User-approved (`docs/specs/phase_9_prop_editor_round3.md` §6). `save_safe` leaves a `.bak` window during the rename — acceptable on desktop, revisit if autosaves ever run on a filesystem without atomic rename. (2026-09-18) |
|
||||
| 32 | **Prop Editor mode buttons drop keyboard focus** — `_make_mode_button` sets `focus_mode = FOCUS_NONE` because the Button `focus` stylebox draws after `pressed` and (with the themed `focus` = normal panel) masked the selected/accent state until the cursor moved away. | Low | Open | Round 4 fix (`docs/specs/phase_9_prop_editor_round4.md`). Trade-off: the Arrange/Reshape toggle is mouse-only. Revisit if keyboard accessibility for the mode toggle becomes a requirement — a focus stylebox matching the pressed state (or a focus-visible-only border) would restore it. (2026-09-19) |
|
||||
| 33 | **Prop File save-serialization zeroed every point (fixed, Round 5)** — `PropFile._serialize_shape` assigned an export-format `Array` of `{x,y}` dicts directly to a typed `PackedVector2Array`; Godot's implicit conversion cannot build `Vector2` from a dictionary and silently yielded `Vector2.ZERO` per element, so every `.prop` saved by Round 1-4 wrote all points as `(0,0)` (loading as invisible/degenerate geometry). | High | ✅ Resolved | Round 5: `_serialize_shape` now routes points through `_coerce_points`; regression assertions check point *values* through `to_file_dict` and the full round-trip, plus an end-to-end canvas→save→load test. The previously saved `content/props/eye.prop` and `content/props/box.prop` are unrecoverable (coordinates were zeroed at save time) and were re-authored. Lesson: any typed `Packed*Array` assignment from dictionary/JSON data needs a Variant-coercion helper. (2026-09-19) |
|
||||
| 34 | **Prop Editor per-shape `reshaped` flag** — every shape carries `reshaped` (false by default; set by vertex insert/remove/drag and non-uniform circle scaling, cleared by `set_shape_radius`), which gates primitive-specific inspector fields (today: the circle Radius row, replaced by a muted "reshaped" note). | Low | Open | Round 6 (`docs/specs/phase_9_prop_editor_round6.md`). Only the circle consumes the flag today; future primitive params (box W/H, plank length/thickness) should reuse it instead of adding per-type detection. An "un-reshape" affordance (restoring a clean primitive from its params) is a possible future feature. (2026-09-19) |
|
||||
| 35 | **Prop Editor selection uses a two-tone halo** — after Round 6's fill-based contrast failed for the reported "shape in front of a white shape" case (the selection extends beyond the shape onto the background), every selection element (outline polyline, bbox, rotation dot, scale crosses, vertex handles) is drawn as a dark backing pass + bright core pass. | Low | Open | Round 7 (`docs/specs/phase_9_prop_editor_round7.md`). The pair is visible on any background but doubles the selection draw calls; negligible at sandbox scale. If a custom selection color is ever wanted (e.g. per-user theme), it should replace the core pass while keeping the halo. (2026-09-19) |
|
||||
| 36 | **Phase 9a anchor roles have no gameplay consumers yet** — `.prop` assets can author/query `grip`, `emitter`, `impact`, `mount`, and `custom`, but Phase 9a is Prop Editor-only. Secondary grips do not drive two-hand IK, and no role dispatches runtime effects, damage, mounting, or equip behavior. | Medium | Open | User-approved staging in `docs/specs/phase_9a_prop_attach.md`: land a stable authoring/schema seam plus an isolated one-hand IK preview first. A separately approved future runtime phase must design custom-prop loading, equip/release ownership, two-hand IK, emitters, melee impacts, accessory mounting, throwing, and selector/stage persistence without assuming the editor preview is gameplay-authoritative. (2026-09-20) |
|
||||
| 37 | **Prop Editor still has no document-wide undo/redo** — Phase 9a anchor edits use the existing dirty/autosave/recovery pipeline, but there is no `UndoRedo` history for either shapes or anchors. | Medium | Open | An anchor-only stack was explicitly rejected because Arrange/Reshape edits would remain non-undoable and the UI would be inconsistent. Future work should introduce one document-level command/history boundary covering shapes, anchors, material/name changes, and preset replacement together. (2026-09-20) |
|
||||
| 38 | **Phase 9a preview does not establish runtime attachment parity** — the Prop Editor uses a private, non-physics, full-multi-shape rig preview with editor-only facing and z-order conventions. It intentionally proves anchor authoring and arm-IK evaluation, not Sandbox loading, collision, physics, mirroring, per-limb interleaving, or attachment lifecycle. | Medium | Open | A future runtime spec must independently validate the anchor transform against gameplay animation/physics and decide its visual representation, sockets or solved-wrist API, mirror strategy, collision/freeze behavior, per-limb draw order, release/ragdoll handling, and multi-shape fidelity. Do not treat preview acceptance tests as runtime tests. (2026-09-20) |
|
||||
| 39 | **Phase 9b prop centering is geometric AABB centering, not physical center of mass** — `Center Prop` uses the union AABB of internal polygon/line/circle points and deliberately excludes outline expansion, anchors, material mass, and collision geometry. | Low | Open | This is deterministic and appropriate for the fixed authoring origin, but a future physics-pivot workflow may need a separately designed center-of-mass or collision-bounds command. Phase 9b keeps canonical `origin` fixed/serialized, hides it from editing, never auto-centers after edits, and uses an explicit-save warning heuristic of `max(1024 px, 2 × bounds diagonal)`. Document-wide undo remains tracked separately by #37. (2026-09-20) |
|
||||
| 40 | **Phase 9c walking preview uses exclusive gait-or-manual ownership of the selected hand target** — the private AnimationPlayer owns the target while gait plays; beginning a cyan-target drag pauses the gait before pointer input takes ownership. | Low | Open | This deterministic policy prevents AnimationPlayer and manual IK from overwriting the same Marker2D in one frame. It means an author cannot add a live hand offset while the walk continues. If that becomes valuable, design a preview-only additive offset/blend layer rather than relying on process order. The gait remains an in-place, non-physics authoring preview and is not navigation/runtime parity (#38). (2026-09-21) |
|
||||
| 41 | **Phase 10 custom prop collision uses one convex hull** — the planned Sandbox prop renders every authored layer, but collision encloses all valid closed-shape points in one solid hull. | Low | Planned | User-approved in `docs/specs/phase_10_prop_integration.md`: one fixture keeps dynamic rigid bodies stable and avoids overlapping per-shape contacts. Hollows and concavities collide as filled space; revisit compound collision only if playtesting shows material misses. `PropFile.flatten_to_payload()` remains for legacy single-shape consumers; #29 stays open until implementation lands. (2026-09-21) |
|
||||
| 42 | **Phase 10 Browse keeps external `.prop` paths as scene asset IDs** — arbitrary filesystem files are used in place rather than copied into `res://content/props/`. | Medium | Planned | This matches stickman Browse and avoids filename/import conflicts, but scenes depend on the external path remaining valid. A missing custom prop becomes an inert placeholder that preserves its original scene entry and rule references through later saves; restoring the file and reloading resolves it. Existing missing-stickman rule skipping is unchanged. See `docs/specs/phase_10_prop_integration.md`. (2026-09-21) |
|
||||
| 43 | **Phase 10 thumbnail invalidation relies on path plus mtime** — custom cache keys will hash the full canonical path and include file modification time. | Low | Planned | This prevents equal basenames in different folders from sharing a PNG, while retaining cheap refresh checks. A filesystem with coarse timestamp resolution can miss two same-tick edits; content hashing is deferred unless observed. Cleanup must not remove built-in or unrelated external thumbnails. See `docs/specs/phase_10_prop_integration.md`. (2026-09-21) |
|
||||
| 44 | **Phase 10a Sandbox prop scaling depends on rigid-body collision scale behavior** — the approved corner gesture changes `PropBlock.scale`, so visual and physics bounds must agree for built-in circles/polygons and custom one-hull props. | Medium | Resolved | `PropBlock.begin_play_instance_scale()` transfers authored scale into child visuals and collision geometry during PLAY, including custom one-hull props and the nonuniform circle fallback, then `end_play_instance_scale()` restores the authored root scale in EDIT. `tests/test_phase10a_prop_scaling.gd` verifies scaled polygon and circle extents, rotated polygon contacts, dynamic PLAY contacts, and legacy nonuniform circle ellipse contacts. (2026-09-22) |
|
||||
| 45 | **Phase 10a geometric normalization excludes stroke and physical mass distribution** — Normalize Size fits the union of shape points to 96 px on its longest axis, scaling about the fixed prop origin while leaving outline width unchanged. | Low | Planned | This preserves anchor offsets and current Center Prop AABB semantics; an off-origin prop remains proportionally off-origin. A future visual-stroke fit or center-of-mass sizing tool would require a separate contract. Existing #39 tracks AABB versus physical center; #37 tracks missing document-wide undo. See `docs/specs/phase_10a_prop_scaling.md`. (2026-09-21) |
|
||||
| 46 | **Phase 12 live queue editing needs session-only action identity and history** — authored indices shift during edits, and a reactive takeover replaces the runner's unconsumed runtime slice. | Medium | ✅ Resolved | Implemented stable session action IDs and a separate COMPLETED/INTERRUPTED ledger. Reactive consequences remain transient; a canceled primary action stays INTERRUPTED and runs only on the next `t = 0` run. Pending actions alone can reorder, active remains fixed, and consumed entries are delete-only. IDs are not serialized. Verified during Phase 12 editor verification. (2026-09-24) |
|
||||
| 47 | **Phase 12 pause requires explicit ownership of physics and procedural clocks** — ragdoll bodies, the runner, locomotion AnimationPlayer, and recovery tween have independent clocks. | Medium | ✅ Resolved | Pause/resume now snapshots and restores dynamic prop/ragdoll state, pauses runner and recovery-tween clocks, and resumes only locomotion animation that Phase 12 paused. A recovery already in progress stays in `RECOVERING` and completes after Resume; pausing does not rebuild a ragdoll. Stable ragdoll ownership supports multiple rigs. User verified the recovery-pause path and visible recovery result. (2026-09-24) |
|
||||
| 48 | **Phase 12 paused paths use one representative ground anchor** — the nearest terrain ray below live feet or ragdoll bounds supplies the pending path origin. | Low | ✅ Resolved | Implemented the approved representative ground anchor, with a live-feet fallback when the probe finds no surface. Multi-contact path planning across a sprawled ragdoll and uneven terrain remains outside Phase 12, but the current anchor is stable and inspectable for paused queue authoring. (2026-09-24) |
|
||||
| 49 | **Phase 12 event edges must be rebaselined without replay** — freezing bodies may emit contact exits/entries, and the stage polls area overlap before child rig movement. | Medium | ✅ Resolved | Event dispatch remains gated until a silent contact/overlap baseline is established on Resume. Existing overlaps do not refire because of the pause transition, and rules authored while paused apply to future events only. Reset clears runtime event edges. (2026-09-24) |
|
||||
| 50 | **Phase 12 paused-edit autosave stores authored state, not the frozen snapshot** — queue/rule edits occur at `t > 0` while stage bodies are at temporary physical transforms. | Medium | ✅ Resolved | A 1.0 s debounce writes the existing `.scene` schema using authored object transforms plus current queues/rules. The timer can finish after Resume; runtime pose, velocities, reactive consequences, and action history are session-only. Paused edits therefore autosave without turning the live pose into the authored starting layout. (2026-09-24) |
|
||||
| 51 | **Phase 11 throw distance and speed are shared across prop types** — the landing-target solver does not yet tune throwability by material or weight. | Low | Open | Deliberately deferred from the approved landing-target amendment. If playtesting needs it, add an explicit gameplay throwability factor based on prop weight/material; do not rely on rigid-body mass to change gravity or mutate physical mass for throw balance. Current shared limits are a 3,600 px target radius and 2,100 px/s speed cap. (2026-09-25) |
|
||||
| 52 | **Throw target preview ignores earlier queued pickups** — the live preview requires `_held_prop`, so editing a pending throw after a pending pickup at `t = 0` cannot show the actual planned throw arc. | Medium | ✅ Resolved | The preview now infers a virtual held-prop state from the authored queue prefix and provides a pure, non-mutating planning trajectory using the prop/grip and predicted pickup stand-off. When a prop cannot be resolved, it shows a neutral explanation; runtime still recomputes from actual state. User verified the result. (2026-09-25) |
|
||||
| 53 | **Phase 13 speech stacks may exceed very small stage viewports** — long simultaneous stacks compete with the side composer and stage chrome. | Low | Planned | The spec sets defensive eight-card and per-card text bounds, keeps frames near a stable screen size, fits the displayed group within the visible stage area without changing saved character-relative placement, and requires a visible overflow cue when a stack cannot fit legibly. Responsive paging for unusually small windows is deferred until observed in editor playtesting. See `docs/specs/phase_13_speech_bubbles.md`. (2026-09-26) |
|
||||
| 54 | **Phase 13 font samples vary by platform until fonts are bundled** — OS `SystemFont` aliases can resolve Comic/Pixel/Scary choices to different families or generic fallbacks. | Low | Deferred | User explicitly deferred font bundling. Keep system-font previews now; a later task can add visually distinct, redistributable fonts with license/attribution files and point the speech presets to them. See `docs/specs/phase_13_speech_bubbles.md`. (2026-09-27) |
|
||||
| 55 | **Speech styling has no general Undo history** — style choices update the recoverable draft immediately, but committed text, bubble order/placement, and styling share no undo stack. | Medium | Deferred | User chose immediate style application and deferred Undo for this release. Save speech commits the complete draft to the scene; composer Cancel discards the whole edit session. A future undo command boundary should cover the whole speech draft; token offsets must remain coherent after text edits. See `docs/specs/speech_style_toolbar_live_edit.md`. (2026-09-29) |
|
||||
| 56 | **RichTextLabel has no dependable per-token 44 px hit rectangles for mixed-font speech** — exact metadata clicks can target narrow punctuation only at its rendered glyph. | Low | Planned | Use a temporary picker of tokens on the tapped rendered line, each with a 44 × 44 px hit area, while retaining exact metadata taps for comfortable words. Avoid estimating glyph boxes from raw string widths because shaping and wrapping can disagree. Revisit a dedicated token renderer only if editor playtesting shows the picker is insufficient. See `docs/specs/speech_style_toolbar.md`. (2026-09-28) |
|
||||
| 57 | **Speech composition must temporarily own stage input** — normal scene controls can otherwise select or alter characters and props while the user is editing speech. | Medium | Planned | Gate stage object interactions while the composer is open; keep speech bubble selection/drag, explicit speech placement, and camera-only navigation available. A non-bubble stage click clears the token target but must not activate the object underneath. Verify deferred token clicks and drag thresholds. See `docs/specs/speech_style_toolbar_refinements.md`. (2026-09-28) |
|
||||
| 58 | **Speech-wide Show settings retain per-bubble render copies** — action-level reveal and motion settings are mirrored into every bubble visual for the current renderer and duration calculations. | Low | Planned | `SpeechPayload.normalize()` is the synchronization boundary; scene and rule encoders must retain the new action-level fields. Older mixed bubble settings intentionally migrate from the first bubble when edited, so later distinct motion/reveal choices are no longer expressible in the group model. If a future renderer reads action-level settings directly, the duplicate visual keys can be removed in a versioned payload migration. See `docs/specs/speech_whole_sequence_show.md`. (2026-09-30) |
|
||||
| 59 | **Stage-only speech edits remain drafts until session completion** — a recoverable draft can differ from its queue/rule target while the child is styling. | Medium | Planned | Done speech is the single validated in-memory commit boundary. A Scene Save request during composition is deferred until the user explicitly completes speech; it never commits implicitly or writes the stale queue/rule target. Cancel speech confirms before discarding an edited draft. This avoids premature persistence of blank bubbles and stale scene data. Recovery remains draft-only. See `docs/specs/speech_stage_only_editor.md`. (2026-09-30) |
|
||||
| 60 | **Run contact timing and baked IK poses share authored gait facts** — clip duration/contact phases must agree with locomotion's stance weights and fixed travel pace. | Medium | Planned | Phase 16 keeps one locomotion controller and an authored Run clip. Tune the speed, cycle duration, foot travel, and contact windows together; flight windows must release both foot locks. The generator and runtime each need phase data, so a future data-driven gait asset may be useful if more styles are added. See `docs/specs/phase_16_running_stickman.md`. (2026-10-03) |
|
||||
| 61 | **Move To migration crosses action and trigger identities** — an old `walk_to` completion filter can silently stop matching after an action becomes `move_to`. | High | Planned | Phase 16 canonicalizes old queue/rule movement actions and `action_finished.params.action_type` filters before validation, while preserving actor IDs, waypoint positions, action order, and rule IDs. Verify old scenes at the boundary and retain the `StickmanRig.walk_to` scripting facade. See `docs/specs/phase_16_running_stickman.md`. (2026-10-03) |
|
||||
| 62 | **Grounded movement currently writes the stickman root transform directly** — limb proxy contacts alone cannot prevent walking through a prop marked Blocks stickmen. | High | Planned | Phase 17a adds a swept body check to grounded movement and arrival snaps, and reports a blocked approach without false arrival. Keep ordinary ground and navigation tied to terrain; use the same actor-blocking profile for walking, airborne sweeps, ragdoll bodies, and contact events. See `docs/specs/phase_17a_prop_roles.md`. (2026-10-05) |
|
||||
| 63 | **Per-placement prop contact permissions need pair reconciliation** — layer/mask changes on one body alone can leave contacts from the other body's scan. | Medium | Planned | Phase 17a centralizes authored-start/held/released profiles on `PropBlock`, uses named physics bits, and adds symmetric pair exceptions on discrete role/scene transitions. Reconcile affected pairs on role edits, pickup/release, load, and reset; avoid per-frame pair work. See `docs/specs/phase_17a_prop_roles.md`. (2026-10-05) |
|
||||
| 64 | **Legacy scene draw order can interleave props and characters** — the new two-choice depth control cannot exactly encode an older prop between two characters. | Low | Planned | Preserve `World` order with a persisted `legacy_draw_order` marker and z-index zero until the child explicitly picks Behind or In front. Show an Old scene order cue in the card; selecting a depth applies that choice relative to every character. See `docs/specs/phase_17a_prop_roles.md`. (2026-10-05) |
|
||||
| 65 | **Large custom prop switches need state parity with native buttons** — a drawn 64 × 34 px switch inside a full-row `Button` replaces the stock small `CheckButton` icon. | Low | Planned | The proposed `PropSettingsToggleRow` should keep native focus, keyboard activation, disabled state, and one `toggled` emission per press; its child labels must ignore pointer input. A compact depth cue lives inside each choice button, while the stage remains the live preview. See `docs/specs/prop_settings_card_refinement.md`. (2026-10-09) |
|
||||
| 66 | **Stage selection panels duplicate layout and visual rules** — the prop card owns its own shell sizing, choice styles, and `stage_prop_settings` tokens, making later inspector cards prone to drift. | Low | Planned | Promote the current prop card to a small shared Stage inspector shell, choice group, and toggle row with `stage_panels` theme tokens. Keep domain handlers in `SandboxStage`; preserve the existing prop role schema. During migration, resolve old prop tokens as fallback only temporarily and remove duplicate reads once the prop card uses the shared controls. See `docs/specs/stage_panel_ui_system.md`. (2026-10-09) |
|
||||
| 67 | **SandboxStage controller is too large for comfortable Godot IDE editing** — stage UI, terrain painting, document workflow, runtime rules, and speech coordination shared one roughly 7,600-line script. | High | In Progress | Approved slices 1–16 extracted reusable stage components and reduced `sandbox_stage.gd` to 5,009 lines (about 34%); the below-3,800-line target remains unmet by 1,209 lines. Root input/selection, authored queue/rule writes, recovery application, and save/commit ordering remain coordinated there. Root `--check-only` parse passes; behavior and in-editor responsiveness checks are pending. See `docs/specs/sandbox_stage_composition_refactor.md`. (2026-10-10) |
|
||||
| 68 | **Use preview cannot predict all prior rules or moving props** — DIRECT can see the current actor and prop plus a limited deterministic queue prefix, but reactive rules and rigid-body motion may change either before a pending Use action runs. | Low | Planned | Phase 17b displays an amber conditional preview when the future pose is uncertain and always recalculates reach during PLAY. One bounded target-movement replan handles ordinary drift without freezing physics. A future predictive timeline may improve authoring accuracy, but must not change persistent prop/spot IDs or claim certainty for simulated rule consequences. See `docs/specs/phase_17b_use_spots.md`. (2026-10-10) |
|
||||
| 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) |
|
||||
|
||||
---
|
||||
|
||||
## Suggested Future Improvements (Beyond Current Scope)
|
||||
|
||||
| Improvement | Description | Status / Priority |
|
||||
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------- |
|
||||
| **Soft Transition Blending** | Add physical blending (joint stiffness ramp) to complement visual crossfade. | ✅ Done, then removed — implemented with Phase 11, but the whole crossfade was removed on director feedback (ghosting); entry is now an instant handoff. |
|
||||
| **Ragdoll Recovery Interruptibility** | Allow the director to force a mode switch mid‑recovery (e.g., if they want the character to ragdoll again immediately). | ✅ Done |
|
||||
| **Multiple Rig Support** | Ensure all state variables are instance‑specific (already true) and that the harness can manage multiple rigs. | Future |
|
||||
| **Animation Blending (IK vs. Physics)** | Blend between the animation‑driven pose and the ragdoll pose during transition to prevent snapping. | Future |
|
||||
| **Save/Load for Ragdoll State** | Save the current ragdoll pose to `.stk` (e.g., for storyboarding a fall). | Future |
|
||||
|
||||
---
|
||||
|
||||
## How to Use This Log
|
||||
|
||||
1. **New Issues:** Add a row with `#`, description, `Priority` (Low/Medium/High), `Status` (Open/In Progress/Resolved/Deprecated), and `Notes`.
|
||||
2. **Resolving Issues:** Change `Status` to `Resolved` and add a note with the date and fix details.
|
||||
3. **Deprioritizing:** If an issue is no longer relevant, mark it `Deprecated` with a brief reason.
|
||||
4. **Quarterly Review:** Revisit this log every major milestone to reassess priorities.
|
||||
|
||||
---
|
||||
|
||||
## Change Log
|
||||
|
||||
| Date | Change |
|
||||
| ---------- | -------------------------------------------------------------- |
|
||||
| 2026-08-26 | Initial creation — migrated observations from Phase 10 review. |
|
||||
| 2026-08-27 | Phase 11 resolved #6 (recovery starting pose), #7 (transition visual pop), #8 (rest timeout UI), #9 (animation generation DRY); #10 (proxy re‑addition) remains open with updated scope. Later revision: stand‑up recovery switched from bridge‑into‑baked‑animation to a direct marker tween (captured pose → `STAND_POSE`), fixing a visible jump; baked `stand_up` kept as authored reference only. Second revision: ragdoll entry builds from the current solved bone positions (IK disabled only after the blend completes) and the recovery snap derives joint ends from capsule half‑heights with Torso `bone_angle` compensation, fixing the entry pose‑pop and the "recovery starts lying" bugs. Third revision: the entire crossfade/blend (`transition_duration`, `BlendDirection`, opacity fade, softness ramp) was **removed on director feedback** — entry is now an instant handoff (build at current pose → hide `Body/*` → disable IK in one call), since the ragdoll spawns at the identical pose and a fade only read as ghosting. |
|
||||
| 2026-08-27 | Sandbox Stage Builder (Phase 2) added `scripts/editors/stage/sandbox_stage.gd` + `stage_spawner.gd` / `stage_selection.gd` / `stage_gizmos.gd` + `scenes/stage/sandbox_stage.tscn`. Logged #11 (no unified freeze abstraction over the mixed `StaticBody2D` / `RigidBody2D` / `Node2D` population) and #12 (selection hit‑testing uses world‑space AABBs rather than point‑in‑polygon). |
|
||||
| 2026-08-29 | Phase 3a (Core Director Functionality) spec written (`docs/specs/phase_3a_spec.md`). Logged #13 (slope-aware walking physics + dynamic obstacle avoidance deferred — the nav mesh itself is built in 3a). Notable non-debt decisions recorded in the spec: Play mode now runs the director script instead of auto-ragdolling stickmen; `walk_to(target)` treats `target` as a feet/ground destination via `FOOT_OFFSET`, with the `NavigationAgent2D` child placed at the feet `(0,+385)` so it paths on the ground-level nav mesh. |
|
||||
| 2026-08-29 | **`walk_to` stops-after-a-few-px bug fixed.** `_update_walking` (Phase 3a) now defers nav reads until `NavigationServer2D.map_get_iteration_id(...) != 0` (map-sync guard) and forces the path query via `get_next_path_position()` before any empty-path/finished check. **Follow-up (same day):** the initial "warn + finish in place" unreachable-target policy was itself reported as "stickman stands still with a waypoint" and was replaced by **hybrid nav/direct steering** — an on-mesh target follows the nav path (`_walk_mode = "nav"`), an off-mesh/unreachable target walks **straight to the clicked waypoint** (`_walk_mode = "direct"`, root target = waypoint + `FOOT_OFFSET`), with **no** `push_warning`; `_walk_path_grace` removed (map-sync guard + forced path query replace it); the debug trace now carries `mode=nav|direct`. Off-by-default `DEBUG_WALK` (`stickman_rig.gd`) / `DEBUG_STAGE` (`sandbox_stage.gd`) traces added. #13 remains **Open** (slope physics + RVO avoidance are still deferred; the fix only changes unreachable-target handling). Logged in `docs/known_issues.md`; verified with a 44-assertion headless regression suite. |
|
||||
| 2026-08-30 | Phase 4 (Triggers & Event System) implemented: `scripts/stage/trigger_area.gd` (NEW placeable sensor), `sandbox_stage.gd` rule system (`_event_rules`, geometric event engine `_update_area_entry` / `_update_stickman_prop_collision`, rule-builder UI state machine, `_cleanup_rules_for_nodes`), `stickman_rig.gd` (`arrived` gains a `target` payload; new `enqueue_reactive`), `prop_block.gd` (`collided` physics signal), `stage_director_visuals.gd` rule visualization, `stage_spawner.gd` / `stage_selection.gd` `"area"` palette + duck-typed `get_area_rect`. Logged #14 (all-pairs event engine scales O(rigs×props + areas×movables); spatial hash suggested). |
|
||||
| 2026-09-02 | Phase 4b (Polish) spec written (`docs/archive/plans/PHASE_4b_SPEC.md`). Logged #15 (walk-arrival jitter: `_walk_mode` re-evaluated per frame + arrival-radius mismatch) and #16 (no grid spatial dictionary; Phase 4b adds one for terrain drag-painting + event-engine broadphase). |
|
||||
| 2026-09-02 | Phase 4b (Polish) implemented. Resolved **#15** (walk-mode latch once per walk, unified `ARRIVE_DISTANCE` arrival with snap-on-arrive, steer-to-final-when-close, one-frame marker re-assert) and **#16** (grid spatial dictionary `_grid_cells` @ `TERRAIN_GRID_SIZE` for the drag-painting 3-state query + director target-validity). #14 remains **Open** — the dictionary is not yet wired into the Phase 4 event engine (note updated). Added `res://sandbox_theme.json`, `scripts/stage/stage_placement_overlay.gd`, the 3-segment mode switcher / status bar / badge / frame / cursors, and director tooltip/trajectory/reticle UX. |
|
||||
| 2026-09-03 | Phase 3b (Asset Library) implemented (`docs/specs/phase_3b_asset_grid_spec.md`): `scripts/characters/stickman/stickman_library.gd` / `prop_library.gd`, `scripts/shared/thumbnails/thumbnail_cache.gd` / `stickman_thumbnail.gd` / `prop_thumbnail.gd`, `scripts/shared/ui/asset_selector.gd` + `scenes/stage/asset_selector.tscn`. The Stickman/Prop palette buttons now open visual selector grids (pagination 12/page, session-only selection, Browse/Refresh); `StageSpawner` registry becomes `ground/ramp/step/prop/stickman/area` (`crate`/`ball` removed) with `selected_*` session state + per-path stickman cache; `SandboxStage` owns the selector open/close flow, Esc priority, and the one-per-frame lazy thumbnail drain. Logged #17 (thumbnail cache growth / headless placeholder) and #18 (session-only selection). Verified with the new headless suite `tests/test_phase3b_library.gd` plus the updated `tests/test_phase4b1_fixes.gd`. |
|
||||
| 2026-09-03 | **Selector UI bugfix round** (5 bugs, documented via `tests/test_phase3b_ui_fixes.gd` + docs in `docs/specs/phase_3b_asset_grid_spec.md` / `README.md` / `AGENTS.md`): `AssetSelector.open()` drops its selection params (`selected_path`/`selected_id`) — no cell is pre-highlighted on open (selected stylebox removed); the selector re-centers on window resize (`size_changed` → `popup_centered()`); the stage adds a dim backdrop `_selector_dim` (`SELECTOR_DIM_ALPHA` 0.5) behind the grid; the selector's `popup_hide` routes to `_on_selector_cancelled()` (idempotency-guarded) so an outside-click un-presses the palette button; and the Direct-mode action popup opens **right of the clicked stickman** (`_world_to_screen` + 24 px) instead of at the cursor. Reviewed #17 and #18 — neither is obsolete (both concern thumbnail-cache growth/headless placeholders and session-only *persistence*, orthogonal to these UI fixes), so both remain **Open** unchanged; no duplicate rows introduced. |
|
||||
| 2026-09-03 | **Rule-builder popup-anchor bugfix round** (`sandbox_stage.gd`, documented in `README.md` / `AGENTS.md`): the Phase 4 rule-builder context menus used to re-pop at the live mouse position on every re-open, so cycling "⚡ When…" → "⬅ Back to actions" → "When…" walked the menu down the screen. Now a **session anchor** records the first context menu's screen position (`_popup_anchor: Rect2i` / `_popup_anchor_set`; Direct first menu = right of the clicked stickman; rule-label edit entry = the click position) and all child popups reuse it via `_set_popup_anchor(rect)` / `_clear_popup_anchor()` / `_popup_anchor_rect()`, until cleared on confirm (`_finalize_rule`), cancel (`_cancel_rule_build`), or Direct-mode/flow exit (`_clear_director_pending`) — but **not** on `_reset_rule_builder()` (Back-to-actions reuses it). No numbered debt row described the old cursor-following behavior, so no row was flipped to Resolved and no duplicates introduced; recorded here in the Change Log only. |
|
||||
| 2026-09-04 | Phase 3c (Editor Tools — Action & Rule Editing) implemented: `scripts/stage/action_registry.gd` / `trigger_registry.gd` (extensible action/trigger templates), `scripts/editors/stage/action_editor.gd` / `rule_editor.gd` / `queue_panel.gd` / `rule_panel.gd` + `scenes/*.tscn` shells, `scripts/stage/waypoint_context.gd`, plus integration in `sandbox_stage.gd` (unified `CaptureKind` target-capture, "Edit Queue…/Edit Rules…" + right-click stickman/waypoint context menus, confirmation dialog, consequence-only rule editor) and `stage_director_visuals.gd` (`hit_test_waypoint_action`, waypoint edit highlight). Logged #19 (ad-hoc popup host-visibility discipline), #20 ("Add Rule" has no source in waypoint-filtered panels), #21 (drag-reorder nearest-row-center), #22 (`--check-only --script` needs a prior `--editor` rescan), and later the same day #23 (Phase 3c confirmation dialog popped over an exclusive panel — the delete/clear-all confirm paths do not hide the `QueuePanel`/`RulePanel` first). Documented the plan-§11.2 deviation (paramless `ActionEditor` pre-fill instead of a separate ragdoll/recover confirmation dialog) in `docs/specs/phase_3c_editor_spec.md` §2 decision 5 — a design decision, so no debt row. Static-verified via headless `--editor --quit` + per-script `--check-only`; runtime F6 flows (queue/rule panel edit-delete-reorder, waypoint context menu, visual walk edit, full vs consequence-only rule editor) still need manual verification. |
|
||||
| 2026-09-11 | Phase 4c (Trigger Area Reliability) verified: `sandbox_stage.gd` `entered_area` now requires source + area instance IDs and detects visible world-AABB overlap for ANIMATED content/stickmen/unfrozen props, edge-triggered per area/movable pair. The prop enumeration scope bug was corrected. `tests/test_phase4c_area.gd` passed all 19 assertions, including transformed-area, leg-level overlap, wildcard/re-entry, speech consequence, stale-target, and deletion-cleanup coverage; editor verification confirmed the speech bubble fires for the configured source stickman. Logged #24 (session-only instance-ID rule references). |
|
||||
| 2026-09-12 | Phase 4.5 collision bodies verified: ten explicitly synchronized `AnimatableBody2D` proxies replace the old feet-point stickman collision poll; `PropBlock` supplies world-space contact data with shape-cast CCD; stage routing preserves rig→prop rules with per-part pair debouncing; bounded quadrant-aware flinches and PLAY→DIRECT authored-pose restoration were verified. `tests/test_phase45_collision_bodies.gd` passed 223 assertions; Phase 4b (53), Phase 4c (19), and Phase 3c (96) remained green. Reconciled #1/#5 and retained #25–#27 as intentional implementation limitations. |
|
||||
| 2026-09-17 | Phase 6a (Airborne Momentum, Procedural Air Pose, and Landing Absorption) implemented and user-verified. `StickmanRig` now carries signed ledge momentum with tuned exponential drag (`AIR_DRAG_X = 0.75`), swept horizontal proxy collision, additive free-fall pose with forward-before-lift arms, and height-driven landing absorption: falls below 80 px are soft; 80..900 px maps to 32..160 px torso compression and 270..520 px hand drop over 0.30 s. Independent foot contacts preserve ramps/stairs, while `LANDING_IMPACT` blocks primary queue progression and direct ragdoll remains an immediate preemption. `tests/test_phase6a_airborne_landing.gd` passed 24 assertions; `tests/test_phase4b_terrain.gd` passed 8 assertions. Logged #28 (per-proxy airborne sweep scaling). |
|
||||
| 2026-09-20 | Phase 9a Prop Attach specification written and refined (`docs/specs/phase_9a_prop_attach.md`). Approved architecture: append Attach to the existing Arrange/Reshape system; additive role-based `.prop` anchors with a fixed synthesized `origin`; and an isolated Prop Editor stickman preview that uses real arm IK while showing the full authored prop. All Sandbox/custom-prop loading, attachment, sockets, physics/collision, lifecycle, and runtime tests are explicitly deferred. Logged #36 (all gameplay consumers deferred), #37 (document-wide undo remains absent), and #38 (editor preview is not a runtime-parity guarantee). Existing #29 remains open independently because the current runtime still flattens multi-shape props. |
|
||||
| 2026-09-20 | Phase 9b Prop Centering specification written (`docs/specs/phase_9b_prop_centering.md`). Approved architecture: hide canonical origin from editable anchors while retaining it in `.prop` v1.0; draw a passive constant-screen-size `(0,0)` marker in all three modes; add an always-visible Center Prop document transaction; center the authoring camera on origin for startup/New/load/reset and preserve zoom after centering; and warn explicit saves with Center & Save / Save Anyway / Cancel when displacement exceeds `max(1024 px, 2 × bounds diagonal)`. Autosave stays silent and automatic recenter-on-edit is explicitly rejected. Logged #39 (AABB authoring center is not a future physics center of mass); #37 continues to track document-wide undo. |
|
||||
| 2026-09-21 | Phase 9c Prop Editor UX specification written (`docs/specs/phase_9c_prop_editor_ux.md`). Approved architecture: a single Front Pose / Walk Left / Walk Right preview-motion selector with dynamic Pause/Resume; manual arm IK pauses gait before taking target ownership; modal typed anchor rename; Show Other Markers controls origin plus unselected anchors; one global Snap source; theme-driven `#262C39` inspector; container-driven unclipped chrome; simplified full-figure preview with no blue border. The preview directly plays the proven in-place gait/mirror policy and remains isolated from navigation, physics, actions, and Sandbox state. Logged #40 (exclusive gait/manual hand-target ownership). |
|
||||
| 2026-09-21 | Phase 10 custom prop integration specification written (`docs/specs/phase_10_prop_integration.md`) after user approval of full layered visuals with one convex collision hull, direct external-path Browse, and missing-prop placeholders that preserve scene entries and rule references. The design reuses Sandbox prop freeze/restore and save flows, extends PropLibrary with a merged scan while retaining its four-template API, and gives custom thumbnails path-unique mtime keys. Logged #41–#43; #29 remains open pending implementation. |
|
||||
| 2026-09-21 | Phase 10a Prop Scaling specification written (`docs/specs/phase_10a_prop_scaling.md`) after approval of origin-based Normalize Size and single-`PropBlock` uniform corner scaling around its local origin; an initial numeric document-scale control was removed during final UI refinement. The editor scales points, circle radius, and non-origin anchors as one transaction; a world-space 1:1 stickman guide defaults OFF and persists only in editor settings. Sandbox reuses its existing scene scale and PLAY→EDIT authored-state lifecycle. Logged #44 for physics collision verification and #45 for geometry-only fit; #37 and #39 remain open. |
|
||||
| 2026-09-22 | Phase 10a whole-prop drag amendment approved (`docs/specs/phase_10a_prop_scaling.md` §3.4). In Arrange, a visible **Resize Whole Prop** toggle displays one union-bounds outline with large handles; dragging previews all shape points, circle radii, and non-origin anchors uniformly about canonical `(0,0)` from a captured snapshot. Release calls the existing document-scale transaction once; Esc, mode switch, toggle OFF, New, Load, and Clear discard a live preview. The preview stays outside authoritative save/autosave state, and the toggle adds no `.prop` field or fourth primary mode. Existing per-shape Arrange behavior remains when the toggle is OFF. Document-wide undo stays deferred under #37; this drag should become one future undo command. |
|
||||
| 2026-09-22 | Phase 10a whole-prop transform extension approved and implemented (`docs/specs/phase_10a_prop_scaling.md` §3.4). The prior Resize Whole Prop toggle becomes one **Transform Whole Prop** tool that mirrors Arrange: drag visible geometry to move the whole document, drag the union rotation dot to rotate it about canonical `(0,0)`, and drag a corner for the existing uniform origin-based resize. Move translates every point and non-origin anchor (snapping the baseline delta when Snap is ON); rotate transforms every point/anchor position and adds the angle to editable anchor orientations; circle radius changes only on resize. All gestures preview from snapshots outside authoritative save state and commit once on release; Esc cancellation, selection restoration, mode lifecycle, `.prop` v1.0, and deferred document undo remain unchanged. |
|
||||
| 2026-09-22 | Phase 10a implementation and final UI were user verified. The Arrange top bar is ordered **Transform Whole Prop**, **Normalize Size**, **Center Prop**, **Show Stickman Guide**; the numeric scale textbox and Apply Scale button are removed. Transform Whole Prop and Normalize Size are hidden in Reshape and Attach, while Center Prop and Show Stickman Guide remain available. Whole-prop move, 15-degree Ctrl rotation, uniform resize, anchor following, Snap movement, and Esc cancellation are documented in `docs/guides/prop_editor_user_guide.md`; focused tests and the Prop Editor startup smoke test passed. |
|
||||
| 2026-09-24 | Phase 12 Live Director implemented and editor-verified. PLAY/DIRECT pause and resume preserve simulation time and live state; the top-bar clock is visible, Space toggles on key press, and paused DIRECT supports action/event editing without object transforms. Pending-only reorder, consumed-action deletion, interrupted-action history, contact rebaseline, and authored-state autosave are documented in the README and spec. Follow-up fixes make locomotion animation resume reliably, preserve a paused recovery tween instead of re-ragdolling, and clear stale foot-contact locks so recovery does not cross the feet. Rows #46–#50 resolved; no `.scene` format change. |
|
||||
| 2026-09-24 | Phase 11 Prop Interactions architecture spec written (`docs/specs/phase_11_prop_interactions.md`) after approval of fixed stage-world throw targets, one prop in one compatible hand per stickman, and persistent per-instance prop IDs. The design adds a per-rig PropInteractor, keeps pickup auto-approach inside one authored queue action, carries existing .prop anchors into runtime, uses a bounded Godot-coordinate ballistic solver, emits events only after committed prop transitions, and migrates StageSceneIO 1.0 scenes to 1.1. Row #24 remains Open pending implementation. |
|
||||
| 2026-09-25 | Phase 11 throw UX amendment approved (`docs/specs/phase_11_prop_interactions.md` §1.1): treat the saved cursor point as aim plus power (distance maps smoothly to a 300–1,250 px/s capped speed), preview the collision-limited ballistic impact, and replace the short windup with a reach-clamped overhand arc that releases during its forward sweep. The existing `{type, target_position}` queue payload remains unchanged. |
|
||||
| 2026-09-25 | Phase 11 throw landing-target amendment approved (`docs/specs/phase_11_prop_interactions.md` §1.2): clamp the cursor's effective target to 800 px from the stickman root, solve the fastest valid descending trajectory under a 1,250 px/s cap, distinguish the raw cursor/effective target/early collision markers, and preserve the fixed world-space queue payload. Open-air targets remain valid; prop weight/material throwability is deferred under #51. |
|
||||
| 2026-09-25 | Phase 11 throw-range tuning updated after user feedback: target radius 3,600 px and speed cap 2,100 px/s. The queue-aware, non-mutating target-preview amendment (`docs/specs/phase_11_prop_interactions.md` §1.3) was approved, implemented, and user verified; row #52 is resolved. Throw limits remain shared across prop types under open row #51. |
|
||||
| 2026-09-26 | Phase 13 comic speech specification drafted for user sign-off (`docs/specs/phase_13_speech_bubbles.md`). Approved choices: a side composer with a live character-attached preview; simultaneous stacks by default or one-at-a-time transitions; automatic reading time with optional longer choices; character-relative placement; and reactive speech that temporarily takes visual priority, then resumes queued speech at its saved time. One tap targets one whole word; effect, font, and color controls apply to that word, while font/color controls edit bubble defaults with no target. The target remains visible while controls take focus; separate tapped words retain separate safe, validated style records. Drag highlighting, Shift-click, and multiselect/append are outside the interaction. The architecture uses one normalized Dictionary payload across queue/rule JSON, a shared RichTextLabel renderer, and runner-owned elapsed clocks for pause-safe replay. It preserves legacy `{text,duration}` actions. Logged #53 for tiny-viewport stack fit; arbitrary BBCode and per-bubble Resource files are deliberate scope exclusions, not open defects. |
|
||||
| 2026-09-27 | Phase 13 composer refinement written for final user sign-off (`docs/specs/phase_13_speech_bubbles.md`): one active text editor with high-contrast snippet tabs and a vertical-only responsive inspector; example frame/font/size controls; 16 named text-color swatches; graphical whole-word target; separate Effects/Show/Timing groups; Show all/One at a time and Normal/Slow/Slower labels mapped to existing serialized IDs; clarified Bounce in/Simply appear; no placement arrows or auto-seconds label; live-head triangular tails with no line crossing the character; and a full replay followed by a one-second blank stage. User chose recoverable local drafts while retaining **Save speech** as the commit point. Draft recovery never mutates queues/rules/scene state; Save commits and clears, Cancel discards and clears, and stale targets recover only as an unbound draft pending an explicit destination. |
|
||||
| 2026-09-27 | User approved the Phase 13 composer refinement for implementation. Font binaries are explicitly deferred; keep OS system-font aliases for the sample buttons and retain #54 as deferred. |
|
||||
| 2026-09-27 | User approved the Phase 13 follow-up (`docs/specs/phase_13_speech_bubbles.md` §9): keep core inspector cards open with larger ribbon headers; clarify word targeting; fix full-word markers and selected-control states; give bubbles independent character-local placement and an above-character stagger that never fits downward across the actor; route scrolling to the composer under the pointer; and preserve valid speech through queue save/load while rejecting partial scene saves. Code is implemented, syntax checks passed, and in-editor verification is pending. |
|
||||
| 2026-09-27 | Phase 13 verification follow-up: strengthened rounded word-marker coverage/clipping, added per-word size styling alongside font and color, and made speech commits confirm that the action actually entered the character queue before closing the composer. Syntax checks passed; verify save/reload and marker behavior in-editor. |
|
||||
| 2026-09-28 | Fixed Phase 13 scene-load rejection for saved per-word styles: JSON parsing yields whole-number offsets as floats, while speech validation required `int`. Validation now accepts finite integral numeric offsets and normalization stores them as integers. `content/stages/talk.scene` loaded through the Sandbox Stage CLI without a skipped-speech warning; the scene file was not modified. |
|
||||
| 2026-09-28 | Speech styling toolbar architecture spec written for final user sign-off (`docs/specs/speech_style_toolbar.md`). The stage-anchored Frame/Letters/Effects toolbar uses one theme-backed chooser and a provisional visual copy: Done commits a style to the composer draft; Cancel discards it without affecting recovery. A shared token scanner extends saved half-open style offsets to punctuation, and a temporary rendered-line token picker provides 44 px choices when glyphs are cramped. The inspector keeps Message and Save speech. User deferred general Undo; logged #55 and #56. No implementation code was changed in this phase. |
|
||||
| 2026-09-28 | Speech style toolbar refinements approved and implemented (`docs/specs/speech_style_toolbar_refinements.md`). The chooser now sizes to content with overflow scrolling, ribbon headings, active categories, and centered large buttons; stage clicks clear the token target while preserving bubble selection, and speech composition blocks unrelated scene edits while retaining bubble controls and camera navigation. The full-sequence control is **Preview speech** beside Save speech. Godot headless syntax checks pass; in-editor verification is pending. |
|
||||
| 2026-09-29 | Speech style live-edit refinement approved and implemented (`docs/specs/speech_style_toolbar_live_edit.md`). Choices now update the recoverable draft directly; token effects demo for one second without replaying the sequence; **Done styling** hides the toolbar while keeping speech editing open; selected choice borders persist on hover; and the token target uses a translucent rounded marker. Godot headless syntax checks pass; editor verification is pending. |
|
||||
| 2026-09-29 | Speech style follow-up fixes: hold bubble geometry steady during the one-second token effect demo; center speech text after font/size changes; and make whole-bubble font/size/color defaults clear matching per-word overrides. Godot headless syntax checks pass; editor verification is pending. |
|
||||
|
||||
---
|
||||
|
||||
| 2026-09-29 | Speech Message/Emoji/Timing follow-up approved for implementation (docs/specs/speech_message_emoji_timing.md): move Message plus its emoji picker and action-wide Timing to the stage toolbar; use two Speech/Style rows; make unselected Effects apply to the whole bubble via a backward-compatible bubble default with token overrides; keep text editing separate from stage token targeting and preserve unaffected style spans. |
|
||||
|
||||
| 2026-09-30 | Stage speech-wide Show architecture specification written for user sign-off (`docs/specs/speech_whole_sequence_show.md`). No bubble focus presents Bubbles, Words appear, and Bubble motion directly beside the group; a bubble/token click swaps to Speech Style, while Done styling or an empty stage click returns to group controls. The action owns reveal and motion values, all existing/future bubbles inherit them, and older mixed settings migrate from the first bubble. Logged #58 for synchronized per-bubble render copies. No implementation code changed. |
|
||||
| 2026-09-30 | Stage-only speech editor architecture specification drafted for user sign-off (`docs/specs/speech_stage_only_editor.md`). Removes the Comic Speech Inspector, moves Show/Timing/Preview/More to Show Speech and Message/Frame/Letters/Effects plus sequence controls to Speech Style, and keeps persistent Done speech and Cancel speech controls. Draft recovery remains immediate; Done commits once to the queue/rule buffer, while Scene Save waits for the explicit Done commit. New bubble defaults, placement, one-step removal Undo, order controls, input ownership, and the existing eight-bubble cap are specified. Logged #59. No implementation code changed. |
|
||||
| 2026-10-01 | Comic Chain speech behavior revised after preview feedback (`docs/specs/speech_comic_chain_layout.md`): Comic chain is the third persistent **Show bubbles** choice and builds cumulatively, while Stack/Same spot remain placement actions. Entering the mode applies measured Stack positions. Later balloon connectors use blunt joins drawn behind predecessor frames; Think uses dots. Older `bubble_layout: comic_chain` payloads migrate to `arrangement: comic_chain`. |
|
||||
| 2026-10-03 | Speech bubble order badges now use selection-independent positions (`docs/specs/speech_badge_stability.md`). Badge clustering responds to actual proximity; Show Speech and Speech Style panels avoid the stable badge bounds instead of moving badges when selection changes. |
|
||||
| 2026-10-03 | Speech badge clusters now also form when bubble frames intersect. For overlapping bubbles, the sorted badge row anchors above the largest frame, preventing a smaller bubble's badge from appearing through the larger bubble's text. |
|
||||
| 2026-10-03 | Phase 16 Move To/Run architecture specification written for user sign-off (`docs/specs/phase_16_running_stickman.md`). Approved canonical `move_to` plus Walk/Run style, migration of old movement and completion-filter types, a short arrival settle, and visual verification across Ground, Ramp, Step, seams, edges, and existing fall/landing behavior. Logged #60 for duplicated gait phase facts and #61 for the migration boundary. No implementation code changed. |
|
||||
|
||||
| 2026-10-05 | Phase 17a prop roles and Set Down architecture specification written for final user sign-off (`docs/specs/phase_17a_prop_roles.md`). Retain `PropBlock` as a stable `RigidBody2D` with authored-start/held/released profiles; make Set Down a world release target with terrain-grounded reach and physics settling; use explicit contact-pair policy and a grounded walking sweep. Legacy scenes migrate with dynamic prop behavior and a saved draw-order marker. Logged #62–#64. No implementation code changed. |
|
||||
| 2026-10-09 | Proposed Prop settings card refinement written for user approval (`docs/specs/prop_settings_card_refinement.md`): full-width 64 × 34 px switches, explicit selected choice styling, plain-language copy, nearby help, compact scrollable card, and small front/behind cues. Logged #65 for custom control state parity. No implementation code changed. |
|
||||
| 2026-10-09 | Proposed Stage selection panel UI system drafted for user approval (`docs/specs/stage_panel_ui_system.md`). The current prop card is the reference; a shared shell, choice group, toggle row, and theme tokens support later Stage inspectors. Logged #66 for duplicated panel presentation. No implementation code changed. |
|
||||
| 2026-10-10 | Sandbox Stage composition refactor specified for developer handoff (`docs/specs/sandbox_stage_composition_refactor.md`). Defines state ownership, explicit component APIs, compatibility facades, and an ordered migration beginning with spatial indexing and terrain painting. Logged #67; implementation followed in the entries below. |
|
||||
| 2026-10-10 | Sandbox Stage composition refactor slices 1–16 implemented (`docs/specs/sandbox_stage_composition_refactor.md`): extracted spatial indexing, terrain painting, stage chrome and views, document/scene adapters, run/director/rule/action/speech sessions, asset browsing, theme loading, and target capture. `sandbox_stage.gd` is 5,009 lines, about 34% smaller than the approximate 7,600-line baseline; the below-3,800-line target remains open. Godot 4.7.1 root `--check-only` parse passes. No behavior tests or in-editor checks were run; #67 remains In Progress. |
|
||||
| 2026-10-10 | Phase 17b Use spots implemented from the approved architecture/UI specs (`docs/specs/phase_17b_use_spots.md`, `docs/specs/phase_17b_use_spots_ui.md`). Instance-local numbered spots persist in `.scene` v1.3; Use requires empty hands, targets keep normal physics with one bounded approach replan, and reach stays grounded. `prop_used` fires only after hand contact; missing references remain repairable after save/load. Phase 17b suite passes 27/27, Phase 17a regression passes 46/46, and edited scripts parse; ready for in-editor user verification. Logged #68 for conditional preview of earlier rules/moving physics; #12, #19, #24, and #67 already cover AABB selection, popup host visibility, session rule IDs, and root controller size. |
|
||||
| 2026-10-13 | Phase 17c Impact wobble architecture specification drafted for final user sign-off (`docs/specs/phase_17c_impact_wobble.md`). A placed prop's saved boolean controls a visual-only wobble in PLAY and a brief EDIT preview. Contact entry plus identified stickman blocking sweeps feed a shared approach-speed gate, including ragdolls and both members of a prop-prop hit. Mass stays independent of the switch, with impact scoring isolated for future mass or impulse work. Scene version advances to 1.4 with older scenes defaulting Off. Logged #69–#70. No implementation code changed. |
|
||||
| 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,130 @@
|
||||
# Architectural Plan: Dynamic `.prop` Loading & Sandbox Integration
|
||||
|
||||
This document outlines the architectural plan to transition `PropLibrary` from a static registry into a dynamic filesystem-backed library (matching `StickmanLibrary`) and integrate user-created `.prop` files into the Sandbox Stage.
|
||||
|
||||
---
|
||||
|
||||
## 1. System Architecture Overview
|
||||
|
||||
The system bridges custom prop files produced by the Prop Editor into the sandbox physics simulation through four primary layers:
|
||||
|
||||
1. **Library & File Scanning (`PropLibrary`):** Scans `res://props/` for `*.prop` files, deserializes them via `PropFile`, flattens multi-shape hierarchies into collision payloads, and merges them with built-in templates.
|
||||
|
||||
2. **Thumbnail Pipeline (`ThumbnailCache` & `PropThumbnail`):** Computes cache keys using file modification timestamps (`mtime`), renders visual previews offscreen, and streams textures to the selector grid.
|
||||
|
||||
3. **UI Integration (`AssetSelector` & `SandboxStage`):** Presents custom props alongside built-in presets in a unified grid, offering folder scanning, ad-hoc file browsing, and palette live-refresh.
|
||||
|
||||
4. **World Spawning & Physics Lifecycle (`StageSpawner` & `PropBlock`):** Instantiates `RigidBody2D` nodes configured with custom collision geometry and material physical properties (mass, friction, bounce), tracking authored positions across sandbox mode transitions.
|
||||
|
||||
---
|
||||
|
||||
## 2. Component Specifications
|
||||
|
||||
### A. Library Layer (`res://scripts/prop_library.gd`)
|
||||
|
||||
- **Dual-Source Registry:** Maintain built-in templates (Crate, Ball, Plank, Triangle) as default presets while scanning `res://props/*.prop` on demand.
|
||||
|
||||
- **Entry Model Schema:** Standardize entry dictionaries returned to the UI:
|
||||
- **Identifier (`id`):** Resource path (`res://props/chair.prop`) for custom files, or string key (`crate`) for templates.
|
||||
|
||||
- **Display Name (`name`):** Extracted from `.prop` metadata, with fallback to capitalized file basename.
|
||||
|
||||
- **Material Preset & Label:** Physical properties index (Wood, Metal, Rubber, Cardboard) and human-readable label.
|
||||
|
||||
- **Payload (`payload`):** Flattened shape and collision dictionary generated via `PropFile.flatten_to_payload()`.
|
||||
|
||||
- **Provenance Flags:** Boolean flag indicating whether the entry is custom and string path reference for scene serialization.
|
||||
|
||||
- **Error Handling:** Skip invalid or corrupted `.prop` files gracefully while outputting descriptive warnings.
|
||||
|
||||
### B. Thumbnail Pipeline (`ThumbnailCache` & `PropThumbnail`)
|
||||
|
||||
- **Dynamic Keying Strategy:**
|
||||
- Built-in prop templates compute keys using internal version constants.
|
||||
|
||||
- Custom `.prop` files compute keys combining file basename and filesystem modification timestamp (`FileAccess.get_modified_time`).
|
||||
|
||||
- **Renderer Extension (`PropThumbnail`):** Extend offscreen rendering to support composite shapes and custom vector styling (fill color, outline width, polygons, circles) rather than single primitive shapes.
|
||||
|
||||
- **Stale Cache Cleanup:** Automatically purge superseded PNG thumbnails when custom `.prop` files are edited or deleted.
|
||||
|
||||
### C. World Spawning Pipeline (`StageSpawner`)
|
||||
|
||||
- **Payload Forwarding:** Pass the entry payload directly to `PropUtils.spawn_prop()`, which generates the corresponding `PropBlock` node with `CollisionPolygon2D` or `CollisionShape2D` nodes.
|
||||
|
||||
- **Provenance Tagging:** Store `spawn_id` and source path metadata on spawned instances to support scene serialization and reloading.
|
||||
|
||||
- **Authored Pose Capture:** Save placement positions to instance metadata (`_authored_position`, `_authored_rotation`) during **Edit** mode.
|
||||
|
||||
### D. UI & Sandbox Integration (`AssetSelector` & `SandboxStage`)
|
||||
|
||||
- **Grid Population:** Trigger `PropLibrary.scan()` when opening the prop selector, populating grid cells with thumbnails and display names.
|
||||
|
||||
- **Browse & Refresh Integration:** Connect the "Browse…" button to a file dialog for arbitrary `*.prop` selection, and the "Refresh" button to re-scan `res://props/`.
|
||||
|
||||
- **Lazy Thumbnail Processing:** Process offscreen thumbnail generation non-blockingly during stage frame processing to keep UI interactions responsive.
|
||||
|
||||
---
|
||||
|
||||
## 3. Physics & Sandbox Lifecycle Integration
|
||||
|
||||
Custom `.prop` instances must follow the existing 3-mode sandbox state machine:
|
||||
|
||||
| Stage Mode | Prop Physics State | Interaction Capabilities | Reset Behavior |
|
||||
| ---------- | -------------------------------------------------- | ------------------------ | -------------- |
|
||||
| **Edit** | RigidBody frozen (`freeze = true`, kinematic mode) |
|
||||
|
||||
| Move, rotate, scale, or delete via selection gizmos
|
||||
|
||||
| N/A (Authored state recorded on movement)
|
||||
|
||||
|
|
||||
| **Direct** | RigidBody frozen (`freeze = true`, kinematic mode)
|
||||
|
||||
| Gizmos active for rule/trigger assignment; spawner palette hidden
|
||||
|
||||
| N/A
|
||||
|
||||
|
|
||||
| **Play** | RigidBody unfrozen (`freeze = false`)
|
||||
|
||||
| Full physical simulation, collisions with terrain/stickmen/props
|
||||
|
||||
| Mode exit restores initial authored position/rotation and zeroes linear/angular velocity
|
||||
|
||||
|
|
||||
|
||||
---
|
||||
|
||||
## 4. Implementation Roadmap
|
||||
|
||||
```
|
||||
[ Phase 1: Library & Data Layer ]
|
||||
└─ Extend PropLibrary (res://props/*.prop scanning + PropFile parsing)
|
||||
└─ Define unified Prop Entry Dictionary schema
|
||||
|
||||
[ Phase 2: Thumbnail Pipeline ]
|
||||
└─ Update PropThumbnail to render multi-shape custom payloads
|
||||
└─ Implement modification timestamp cache invalidation in ThumbnailCache
|
||||
|
||||
[ Phase 3: Spawning & UI Integration ]
|
||||
└─ Update StageSpawner to tag custom prop provenance
|
||||
└─ Wire AssetSelector grid refresh and file dialog browsing
|
||||
|
||||
[ Phase 4: Stage Lifecycle & Verification ]
|
||||
└─ Verify Edit -> Play -> Edit position resets for custom props
|
||||
└─ Validate scene saving/loading persistence
|
||||
|
||||
```
|
||||
|
||||
### Milestone Checklist for Architect Agent
|
||||
|
||||
1. **Directory Scanning:** `PropLibrary` reads `res://props/` and extracts payloads via `PropFile`.
|
||||
|
||||
2. **Visual Previews:** `PropThumbnail` renders multi-polygon custom vector props to textures.
|
||||
|
||||
3. **Palette Display:** `AssetSelector` displays merged built-in templates and `.prop` files.
|
||||
|
||||
4. **Physics Interaction:** Custom props unfreeze during **Play** mode, participating in physics simulation and collision events.
|
||||
|
||||
5. **State Reset:** Props return to their original authored transforms when switching from **Play** back to **Edit** mode.
|
||||
@@ -0,0 +1,118 @@
|
||||
Here is the revised architectural specification incorporating your exact adjustments for your architect agent:
|
||||
|
||||
---
|
||||
|
||||
# Architectural Spec: Dual-Layer Prop Scaling System (Revised)
|
||||
|
||||
Status: **implemented and user verified** (2026-09-22).
|
||||
|
||||
This specification outlines the architecture for supporting prop scaling across two layers: permanent template scaling in the **Prop Editor** and contextual instance scaling in the **Sandbox Stage**.
|
||||
|
||||
---
|
||||
|
||||
## 1. System Architecture & Division of Responsibilities
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ PROP EDITOR (Phase 9) │
|
||||
│ • Permanent template geometry mutation │
|
||||
│ • Vertex & radius coordinate transformations │
|
||||
│ • Anchor offset auto-scaling │
|
||||
│ • Stickman guide silhouette (Default: OFF) │
|
||||
└────────────────────────────┬────────────────────────────┘
|
||||
│ Saves .prop file
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ SANDBOX STAGE (Phase 10) │
|
||||
│ • Contextual instance scaling via corner gizmos only │
|
||||
│ • Locked aspect ratio (uniform scaling) │
|
||||
│ • Physics mass decoupled from visual scale │
|
||||
└────────────────────────────┴────────────────────────────┘
|
||||
|
||||
```
|
||||
|
||||
| Layer | Target Entity | Operation Type | Scaling Behavior | Data Persistence |
|
||||
| ----------------- | ----------------------------- | --------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| **Prop Editor** | Template Asset (`.prop`) | Permanent geometry mutation | Bakes scale into raw vector vertices, radii, and anchor offsets. | Persists into `.prop` file. |
|
||||
| **Sandbox Stage** | Object Instance (`PropBlock`) | Node transform scaling | Pure gizmo scaling with **locked aspect ratio**. | Persists into `.scene` file (`scale: { x, y }`). |
|
||||
|
||||
---
|
||||
|
||||
## 2. Prop Editor Implementation (Template Sizing)
|
||||
|
||||
### A. Document Geometry Scale Tool
|
||||
|
||||
- **Scope:** Modifies raw geometry arrays (`points` for polygons/lines, `radius` for circles) in the shape stack.
|
||||
|
||||
- **Anchor Recalculation:** All registered anchor offset positions (`x`, `y`) automatically multiply by the scale factor so grip, pivot, and emitter points maintain exact relative alignment.
|
||||
|
||||
- **Normalize Size Action:** Adds a canvas action (📏 **Normalize Size**) alongside 🎯 **Center Prop** that computes the bounding box union of all shapes and uniformly scales the document to fit within a standard $96 \times 96\text{ px}$ canvas box.
|
||||
|
||||
### B. Stickman Visual Reference Silhouette
|
||||
|
||||
- **Overlay Guide:** Renders a semi-transparent 1:1 Stickman figure silhouette on the canvas background for scale context against full character rigs ($\approx 336 \times 940\text{ px}$).
|
||||
|
||||
- **Default State:** Toggleable via the UI / canvas controls and **defaults to OFF**.
|
||||
|
||||
- **View Aid Only:** Non-selectable, non-interactive visual guide that is excluded from `.prop` file serialization.
|
||||
|
||||
---
|
||||
|
||||
## 3. Sandbox Stage Implementation (Instance Sizing)
|
||||
|
||||
### A. Gizmo-Driven Scaling (No UI SpinBoxes / No Presets)
|
||||
|
||||
- **Corner Scale Handles:** Extends `StageGizmos` in `EDIT` mode to render corner cross handles on selected prop bounding boxes.
|
||||
|
||||
- **Aspect Ratio Locking:** Dragging any corner handle scales the object while strictly **locking the aspect ratio** (uniform scaling).
|
||||
|
||||
- **Streamlined UI:** No numeric scale SpinBoxes or preset buttons (`S`/`M`/`L`) are added to the stage UI; all scaling is performed intuitively directly on the canvas via gizmo manipulation.
|
||||
|
||||
### B. Mode Lifecycle & Physics Rules
|
||||
|
||||
- **Decoupled Mass Contract:** Scaling a prop adjusts node visual geometry (`Polygon2D`, `Line2D`) and collision bounds (`CollisionPolygon2D`, `CollisionShape2D`). RigidBody `mass` remains independent, governed strictly by the assigned Material Preset (Wood, Metal, Rubber, Cardboard).
|
||||
|
||||
- **Lifecycle State Handling (`PLAY` $\rightarrow$ `EDIT`):** Transitioning from `PLAY` back to `EDIT` mode restores the authored `position` and `rotation` and zeroes linear/angular velocity, but **does not reset or alter the node scale**. The authored scale set during editing is retained as-is.
|
||||
|
||||
---
|
||||
|
||||
## 4. Implementation Roadmap
|
||||
|
||||
1. **Phase A (Prop Editor Tooling):**
|
||||
|
||||
- Implement document-wide geometry and anchor scaling logic in `PropEditor`.
|
||||
|
||||
- Add the toggleable Stickman Reference Silhouette (**default OFF**) and "Normalize Size" canvas button.
|
||||
|
||||
2. **Phase B (Sandbox Gizmo Scaling):**
|
||||
|
||||
- Extend `StageGizmos` with corner scale handles that lock aspect ratio during drag operations.
|
||||
|
||||
- Ensure `StageSelection` AABB bounding boxes recalculate accurately to account for scaled instances.
|
||||
|
||||
3. **Phase C (Persistence & Verification):**
|
||||
|
||||
- Verify scene save/load serialization of scaled `PropBlock` instances.
|
||||
|
||||
- Confirm that `EDIT` $\rightarrow$ `PLAY` $\rightarrow$ `EDIT` mode switches restore authored position/rotation while keeping object scale intact.
|
||||
|
||||
## 5. Verified final Prop Editor controls
|
||||
|
||||
The Arrange mode top bar presents these controls in order:
|
||||
|
||||
1. **Transform Whole Prop**
|
||||
2. **Normalize Size**
|
||||
3. **Center Prop**
|
||||
4. **Show Stickman Guide**
|
||||
|
||||
The numeric scale textbox and Apply Scale button were removed. Transform Whole
|
||||
Prop previews and commits whole-document move, rotation, and uniform resize
|
||||
gestures around the canonical origin. Grid Snap rounds move deltas, Ctrl snaps
|
||||
rotation to 15-degree increments, editable anchors follow the geometry, and Esc
|
||||
cancels an active preview. Normalize Size fits the shape-point bounds to a 96 px
|
||||
maximum dimension. Transform Whole Prop and Normalize Size are hidden in Reshape
|
||||
and Attach; Center Prop and Show Stickman Guide remain available in all modes.
|
||||
|
||||
Sandbox instance scaling remains a separate prop-only uniform corner-gizmo
|
||||
operation. It retains the authored scene scale, preset-governed mass, and
|
||||
PLAY-to-EDIT position/rotation restoration behavior.
|
||||
@@ -0,0 +1,268 @@
|
||||
# Architecture Specification: Interactive Prop System & Event Engine
|
||||
|
||||
This specification details the technical architecture for bringing interactive prop capabilities—including auto-approach, IK socket binding, parabolic throwing, ragdoll disarming, and "When..." rule triggers—into the Sandbox Stage.
|
||||
|
||||
---
|
||||
|
||||
## 1. System Overview & Layer Interactions
|
||||
|
||||
Prop interactions bridge five core subsystems across the runtime stack:
|
||||
|
||||
```
|
||||
[ Director UI / Target Selector ]
|
||||
│
|
||||
▼
|
||||
[ StickmanActionRunner ] ──(Auto-Approach)──► [ StickmanLocomotion ]
|
||||
│
|
||||
▼
|
||||
[ StickmanRig IK ] ──(Socket Binding)──► [ PropBlock Physics ]
|
||||
│
|
||||
▼
|
||||
[ StageEventRegistry ] ──("When..." Rules)──► [ Reactive Actions ]
|
||||
|
||||
```
|
||||
|
||||
1. **Director UI & Target Selection:** Captures spatial throw targets and enqueues prop interaction commands.
|
||||
|
||||
2. **Action Runner & Locomotion:** Evaluates spatial reach; automatically inserts `walk_to` sub-goals when props are out of arm's reach.
|
||||
|
||||
3. **IK & Bone Socketing:** Extends arm IK targets toward prop `grip` anchors and manages `RemoteTransform2D` binding.
|
||||
|
||||
4. **Physics Lifecycle:** Unfreezes/freezes `PropBlock` bodies and inherits velocity during release, throw, or ragdoll disarm transitions.
|
||||
|
||||
5. **Event Registry:** Emits and evaluates edge-triggered prop rules within the stage's "When → Then" engine.
|
||||
|
||||
---
|
||||
|
||||
## 2. Dynamic Action Queue & Auto-Approach (`walk_to`)
|
||||
|
||||
To ensure smooth director interaction, the action queue automatically resolves spatial gaps between the stickman and target props.
|
||||
|
||||
### Action Payload Schemas
|
||||
|
||||
- **`pick_up_prop`**: `{ "type": "pick_up_prop", "target_prop_id": String, "hand": "auto" | "left" | "right" }`
|
||||
|
||||
- **`drop_prop`**: `{ "type": "drop_prop" }`
|
||||
|
||||
- **`throw_prop`**: `{ "type": "throw_prop", "target_position": Vector2, "force": float }`
|
||||
|
||||
### Smart Approach Execution
|
||||
|
||||
When `StickmanActionRunner` receives a `pick_up_prop` payload:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ pick_up_prop Action Start │
|
||||
└──────────────────────┬───────────────────────┘
|
||||
│
|
||||
┌──────────────────────▼───────────────────────┐
|
||||
│ Distance = |rig.position - prop.position| │
|
||||
└──────────────────────┬───────────────────────┘
|
||||
│
|
||||
Is Distance > Reach Radius (e.g. 40px)?
|
||||
┌───────────────────────┴───────────────────────┐
|
||||
│ │
|
||||
[ YES ] [ NO ]
|
||||
│ │
|
||||
┌─────────────────▼─────────────────┐ ┌─────────────────▼─────────────────┐
|
||||
│ 1. Pause pick_up_prop sequence │ │ 1. Skip locomotion step │
|
||||
│ 2. Prepend walk_to(prop_offset) │ │ 2. Trigger arm IK reach animation │
|
||||
│ 3. Resume pickup on arrival │ └───────────────────────────────────┘
|
||||
└───────────────────────────────────┘
|
||||
|
||||
```
|
||||
|
||||
1. **Distance Check:** Evaluates global horizontal/spatial distance between the stickman root and prop `origin` pivot.
|
||||
|
||||
2. **Sub-Goal Injection:** If outside reach radius, `StickmanActionRunner` pauses the pickup sequence and internally issues a `walk_to` command to a stand point adjacent to the prop.
|
||||
|
||||
3. **Sequence Resume:** Upon receiving `StickmanLocomotion.arrived_at_waypoint`, the runner resumes the pickup sequence and triggers arm IK extension.
|
||||
|
||||
---
|
||||
|
||||
## 3. Pickup, Drop, and Throw Pipelines
|
||||
|
||||
### A. Prop Pickup Sequence & IK Socketing
|
||||
|
||||
1. **IK Reach Phase (150 ms):** `TwoBoneIK` targets for the selected arm interpolate toward the world position of the prop's `grip` anchor.
|
||||
|
||||
**Edit:** Torso position should also move up/down based on grip anchor. The stickman should look like it is bending or extending legs to make pickup look more realistic.
|
||||
|
||||
2. **Socket Attachment:**
|
||||
|
||||
- Set `PropBlock.freeze = true` (kinematic mode) to suspend environmental physics forces.
|
||||
|
||||
- Instantiate or activate a `RemoteTransform2D` node attached to the lower arm / wrist joint, targeting the `PropBlock`.
|
||||
|
||||
- Apply anchor local offsets (`x, y, rotation_deg, z_index_offset`) to align the prop grip directly within the hand geometry.
|
||||
|
||||
3. **Holding Stance Latch:** Lock upper limb IK targets into a carried stance during subsequent walk cycles.
|
||||
|
||||
### B. Prop Drop Sequence
|
||||
|
||||
1. **Unbinding:** Clear `RemoteTransform2D` target and reparent `PropBlock` back to the stage world root.
|
||||
|
||||
2. **Physics Activation:** Set `PropBlock.freeze = false` to re-enable rigid body simulation, gravity, and collision shapes.
|
||||
|
||||
3. **Inertia Inheritance:** Set `PropBlock.linear_velocity` equal to the stickman's current movement velocity (`_last_grounded_walk_velocity_x`) so dropped items retain forward momentum.
|
||||
|
||||
4. **Arm Recovery:** Blend wrist IK targets smoothly back to standard locomotion/idle rest positions.
|
||||
|
||||
### C. Prop Throw Sequence & Trajectory Selection
|
||||
|
||||
#### Director Target UI Flow
|
||||
|
||||
- **Targeting Mode:** Selecting "Throw Prop" in Director/Play mode activates an aim reticle cursor and dynamic arc preview.
|
||||
|
||||
**EDIT:** When the user clicks the stickman in DIRECT mode, 3 new additions should appear in the action context menu
|
||||
|
||||
1. Pick up
|
||||
2. Drop
|
||||
3. Throw
|
||||
[Give these proper emoji]
|
||||
|
||||
- If Drop is added to the queue, and the action is run when the stickman holds nothing, the action is skipped (marked as done)
|
||||
- If Throw is added to the queue, and the action is run when the stickman holds nothing, the action is skipped (marked as done)
|
||||
- These 3 actions should also be selectable when handling a 'When' event
|
||||
|
||||
- **Trajectory Math:** Given hand release point $P_0$, target landing point $P_t$, base speed $v_0$, and gravity $g$:
|
||||
|
||||
$$\theta = \arctan\left(\frac{v_0^2 \pm \sqrt{v_0^4 - g(g \cdot x^2 + 2 y \cdot v_0^2)}}{g \cdot x}\right)$$
|
||||
|
||||
Calculates exact initial launch velocity components $V_{\text{launch}} = (v_0 \cos\theta, v_0 \sin\theta)$.
|
||||
|
||||
#### Keyframe Throw Animation Arc
|
||||
|
||||
```
|
||||
[ Windup: 100ms ] ──► [ Release Frame: 150ms ] ──► [ Follow-Through: 50ms ]
|
||||
- Torso tilts -15° - Arm sweeps to angle - Arm extends along arc
|
||||
- Arm pulls backward - Prop unfreezes + impulse - Blends back to idle
|
||||
|
||||
```
|
||||
|
||||
1. **Windup (100 ms):** Torso rotates backward opposite the launch vector while the arm pulls back.
|
||||
2. **Release Frame (150 ms):**
|
||||
|
||||
- Arm sweeps rapidly along the calculated launch angle $\theta$.
|
||||
**EDIT:** The arm should go overhead - not an underhand throw.
|
||||
- Unbind `RemoteTransform2D` and reparent prop to world root.
|
||||
|
||||
- Set `PropBlock.freeze = false` and execute `apply_central_impulse(V_launch)`.
|
||||
|
||||
- Apply rotational torque proportional to the distance between hand grip and prop center-of-mass.
|
||||
|
||||
3. **Follow-Through (50 ms):** Arm extends toward launch vector, then smoothly dampens back to default idle/walking pose.
|
||||
|
||||
---
|
||||
|
||||
## 4. Physics & State Machine Lifecycle (Ragdoll Disarm Handoff)
|
||||
|
||||
When `StickmanRig.set_ragdoll(true)` is executed (via impact, command, or keypress), any held prop must be immediately disarmed before kinematic nodes are hidden and ragdoll bodies are built.
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ StickmanRig.set_ragdoll(true) │
|
||||
└──────────────────────┬───────────────────────┘
|
||||
│
|
||||
┌──────────────────────▼───────────────────────┐
|
||||
│ 1. Pre-Ragdoll Intercept │
|
||||
│ Query if held_prop != null │
|
||||
└──────────────────────┬───────────────────────┘
|
||||
│
|
||||
┌──────────────────────▼───────────────────────┐
|
||||
│ 2. Execute Disarm Handoff │
|
||||
│ - Clear RemoteTransform2D binding │
|
||||
│ - Reparent PropBlock to world root │
|
||||
│ - Set prop.freeze = false │
|
||||
│ - Apply cached momentum (_track_momentum) │
|
||||
└──────────────────────┬───────────────────────┘
|
||||
│
|
||||
┌──────────────────────▼───────────────────────┐
|
||||
│ 3. Build Physics Ragdoll │
|
||||
│ Hide animated body, build RigidBody2D │
|
||||
│ network at current solved bone positions │
|
||||
└──────────────────────────────────────────────┘
|
||||
|
||||
```
|
||||
|
||||
1. **Pre-Ragdoll Intercept:** Prior to clearing collision proxies or hiding body meshes, check for an active `held_prop` binding.
|
||||
|
||||
2. **Physics Unbind:**
|
||||
|
||||
- Detach the `RemoteTransform2D` socket.
|
||||
|
||||
- Reparent prop to the world root and set `PropBlock.freeze = false`.
|
||||
|
||||
- Transfer cached rig momentum (`_track_momentum()`) directly to `PropBlock.linear_velocity` and `angular_velocity` so the prop tumbles naturally alongside the falling figure.
|
||||
|
||||
3. **Ragdoll Construction:** Proceed with standard `_build_ragdoll()` processing at current solved bone transforms.
|
||||
|
||||
---
|
||||
|
||||
## 5. Event System Integration ("When..." Triggers)
|
||||
|
||||
Three new edge-triggered prop event types are added to `StageEventRegistry` (`sandbox_stage.gd`) to support the director's "When → Then" mental model.
|
||||
|
||||
### Prop Trigger Specifications
|
||||
|
||||
| Trigger Type | Source Object | Target Object | Firing Condition |
|
||||
| ---------------- | --------------- | --------------- | ------------------------------------------------------------------------------- |
|
||||
| `prop_picked_up` | Stickman / Prop | Prop / Stickman | Emitted as soon as IK arm reach completes and `RemoteTransform2D` socket locks. |
|
||||
|
||||
|
|
||||
| `prop_dropped` | Stickman / Prop | Prop / Stickman | Emitted when a stickman drops a prop manually or via ragdoll disarm.
|
||||
|
|
||||
| `prop_thrown` | Stickman / Prop | Prop / Stickman | Emitted at the exact release frame of a throw animation arc.
|
||||
|
|
||||
|
||||
### Signal Routing & Evaluation
|
||||
|
||||
1. `StickmanActionRunner` emits `prop_action_executed(action_type, stickman, prop)` upon completing or releasing an anchor attachment.
|
||||
|
||||
2. `StageEventRegistry` matches active stage rules where `rule.trigger.type` equals `prop_picked_up`, `prop_dropped`, or `prop_thrown`.
|
||||
|
||||
3. Matching rules trigger reactive actions on target stickmen or props (e.g., _When Stickman A picks up Sword X $\rightarrow$ Stickman B ragdolls_).
|
||||
|
||||
---
|
||||
|
||||
## 6. Implementation Roadmap for Architect Agent
|
||||
|
||||
```
|
||||
[ Phase 1: Action Queue & Locomotion ]
|
||||
├─ Add pick_up_prop, drop_prop, and throw_prop to StickmanActionRunner
|
||||
└─ Implement distance evaluation & auto-enqueueing of walk_to sub-goals
|
||||
|
||||
[ Phase 2: Socket Attachment & IK Handshake ]
|
||||
├─ Implement RemoteTransform2D socketing to wrist joint with grip offsets
|
||||
└─ Implement holding stance arm pose blending
|
||||
|
||||
[ Phase 3: Throw Mechanics & Trajectory UI ]
|
||||
├─ Add trajectory solver & reticle target selector to Director UI
|
||||
└─ Build throw animation timeline (windup -> release impulse -> follow-through)
|
||||
|
||||
[ Phase 4: State Machine Integration & Disarm ]
|
||||
├─ Intercept held props during set_ragdoll(true) transitions
|
||||
└─ Transfer cached linear/angular momentum to disarmed prop physics body
|
||||
|
||||
[ Phase 5: Event System Expansion ]
|
||||
├─ Register prop_picked_up, prop_dropped, prop_thrown triggers in StageEventRegistry
|
||||
└─ Wire action signals to trigger "When -> Then" rule evaluations
|
||||
|
||||
```
|
||||
|
||||
## 7. Design Questions / Rules
|
||||
|
||||
1. When creating a Throw action, the user must create an arc defining the throw. However, when the scene is playing, the stickman might be in a whole different position for when the throw must happen. Should we define a new arc and make a best effort to throw the prop towards the (x,y) location selected or should we use the same arc, but translate the throw endpoint relevant to the stickman's current position.
|
||||
2. The stickman profile direction should change to whichever direction the prop will be thrown.
|
||||
|
||||
### Architectural Acceptance Criteria Checklist
|
||||
|
||||
- [ ] **Auto-Approach:** Requesting pickup of a distant prop automatically causes the stickman to walk to the prop before reaching out.
|
||||
|
||||
- [ ] **Grip Alignment:** Hand attaches precisely to the prop's authored `grip` anchor, respecting local position, rotation, and Z-index offsets.
|
||||
|
||||
- [ ] **Trajectory Accuracy:** Thrown props follow the calculated parabolic arc toward the director's targeted ground point.
|
||||
|
||||
- [ ] **Ragdoll Disarm:** Entering ragdoll mode immediately detaches held props and applies rig momentum so items tumble realistically.
|
||||
|
||||
- [ ] **Event Rule Engine:** Rules configured with `When prop_picked_up`, `When prop_dropped`, or `When prop_thrown` execute downstream actions reliably.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Architecture Summary: Live Director System
|
||||
|
||||
The **Live Director System** transitions the sandbox from a static "plan-then-watch" tool into an interactive **Director Loop** ($\text{Play} \leftrightarrow \text{Pause/Direct} \leftrightarrow \text{Resume}$). Users can freeze the simulation mid-flight at any timestamp $t$, inspect current states, append or modify action paths relative to stickmen's live positions, and resume simulation seamlessly.
|
||||
|
||||
---
|
||||
|
||||
## 1. Core State & Control Model
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
│ EDIT Mode (Authored t=0) │
|
||||
└──────────────────┬───────────────────┘
|
||||
│ Play (from t=0)
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ PLAY Mode (Simulating) │
|
||||
└──────────┬────────────────▲──────────┘
|
||||
Pause / Direct │ │ Resume Sim
|
||||
(Freeze state at t) ▼ │
|
||||
┌──────────────────────────────────────┐
|
||||
│ DIRECT Mode (Mid-Sim State at t) │
|
||||
└──────────────────┬───────────────────┘
|
||||
│ Stop / Reset
|
||||
▼
|
||||
Restores Authored t=0
|
||||
|
||||
```
|
||||
|
||||
- **Unified Pause Alias**: Pressing **`Spacebar`**, clicking **`⏸️ Pause`**, or selecting **`🎬 Direct`** while in `PLAY` mode triggers the exact same transition: freezing simulation at timestamp $t$ and opening Direct Mode editing.
|
||||
- **Resume**: Pressing **`Spacebar`** or clicking **`▶️ Play`** unfreezes physics and resumes simulation.
|
||||
- **Reset**: Clicking **`↺ Reset`** or selecting **`✏️ Edit`** returns the stage and props to $t=0$ authored positions.
|
||||
|
||||
---
|
||||
|
||||
## 2. Physics, Timing, & State Freeze Mechanics
|
||||
|
||||
- **Multi-Part Ragdoll Velocity Caching**: Transitioning to Direct Mode iterates over all **10 individual bone `RigidBody2D` parts** in `StickmanRagdoll` as well as dynamic stage props. Linear and angular velocities are saved to node metadata (`set_meta`), and nodes are set to `freeze = true` (`FREEZE_MODE_KINEMATIC`). Momentum is restored per body upon unfreezing.
|
||||
- **Collision Penetration Protection**: Body transforms are recorded on pause and synced via `PhysicsServer2D` prior to waking up physics bodies on resume to prevent force ejection glitches.
|
||||
- **Tween & Process Clock Freezing**: Active procedural `Tween`s (`tween.pause()`), speech bubble timers, and runner process clocks freeze during pause.
|
||||
|
||||
---
|
||||
|
||||
## 3. UI Chrome & Visual Hierarchy
|
||||
|
||||
- **Live Timestamp Display (`TimestampBadge`)**:
|
||||
- **Location**: Top-right corner of the viewport (`PRESET_TOP_RIGHT`).
|
||||
- **Format**: Displays `⏱️ MM:SS.ms` (e.g. `00:04.25`).
|
||||
- **Theming**: The display's size and font should be dictated by the **sandbox_theme.json** file.
|
||||
- **Lifecycle**: Ticks continuously in `PLAY`, freezes on the exact paused frame in `DIRECT`, and resets to `00:00.00` in `EDIT`.
|
||||
|
||||
- **Viewport Path Visuals**:
|
||||
- **Completed History ($0 \rightarrow t$)**: Displayed in a **faded ghost style (20% alpha / desaturated grey)** or hidden to eliminate clutter.
|
||||
- **Pending Futures ($t \rightarrow \infty$)**: Displayed at **100% full opacity** with bright accent vectors originating at the stickman's live feet position ($P_{\text{live}}$) at time $t$.
|
||||
|
||||
- **Airborne & Ragdoll Spatial Anchoring**:
|
||||
- For airborne or ragdolled stickmen, a vertical down-raycast locates the nearest ground point ($P_{\text{ground}}$).
|
||||
- A vertical drop-line connects the character to $P_{\text{ground}}$, and new path vectors anchor directly to $P_{\text{ground}}$.
|
||||
|
||||
---
|
||||
|
||||
## 4. Action Execution & Edge Case Handling
|
||||
|
||||
- **Auto-Recovery**: Assigning a `walk_to` movement action to a ragdolled stickman automatically prepends a `recover` action so they stand up from their current location before navigating.
|
||||
- **Landing Barrier Compliance**: Actions appended while paused during a landing crouch compression (`LANDING_IMPACT`) stay queued behind `_is_action_queue_blocked()` until landing animation compression completes upon resuming.
|
||||
- **Active Action Cancellation**: Editing or deleting an action currently in progress at timestamp $t$ calls `_cancel_current_primary()` on `StickmanActionRunner` to clear active IK paths and speech overlays cleanly.
|
||||
- **Ragdoll Hitbox Selection**: Selection clicks in Direct Mode evaluate all child bone collision shapes in `RagdollBodyContainer` to ensure reliable clicking regardless of pose.
|
||||
- **Queue Persistence**: Actions added mid-sim ($t > 0$) append sequentially into the stickman's master queue. Resetting to $t=0$ restores stage layout but retains all newly authored queue actions for playback from the start.
|
||||
|
||||
---
|
||||
|
||||
## 5. Explicitly Out of Scope
|
||||
|
||||
- **Stage & Action Undo/Redo (`Ctrl+Z` / `Ctrl+Y`)**: Stage-wide and action queue undo/redo stacks remain explicitly **OUT OF SCOPE** for this implementation phase. Misplaced items or actions are modified or removed manually via viewport gizmos and selection menus.
|
||||
@@ -0,0 +1,157 @@
|
||||
## Summary of Speech & Speech Bubble Features
|
||||
|
||||
The goal is to expand the existing single-bubble `SpeechBubble` system into a comic-book movie engine designed for young directors.
|
||||
|
||||
### 1. Data Contract & Theme Integration
|
||||
|
||||
- **Expanded Action Payload**: Extend the `speak` action payload to support explicit visual parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "speak",
|
||||
"text": "Look out for the [shake]MONSTER![/shake]",
|
||||
"duration": 2.5,
|
||||
"stop_current": false,
|
||||
"visual": {
|
||||
"bubble_style": "yell",
|
||||
"font_preset": "comic",
|
||||
"size_preset": "huge",
|
||||
"color": "#FF3333",
|
||||
"anim_mode": "typewriter"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Theme Fallbacks**: Route missing keys through `sandbox_theme.json` defaults $\rightarrow$ Global Theme $\rightarrow$ Godot `ThemeDB.fallback_font`.
|
||||
|
||||
### 2. Rich Text & Visual Styles
|
||||
|
||||
- **`RichTextLabel` Migration**: Shift text rendering from raw `draw_string()` calls to an internal `RichTextLabel` child node to enable full BBCode support (`[wave]`, `[shake]`, bolding, inline colors).
|
||||
|
||||
- **Shape Presets (`BubbleStyle`)**:
|
||||
- **Standard**: Classic rounded rectangle + downward tail triangle.
|
||||
|
||||
- **Yell / Shout**: Multi-pointed starburst polygon.
|
||||
- **Thought**: Arc/circle cluster cloud boundary + descending bubble chain dots.
|
||||
- **Whisper**: Semi-transparent fill with dashed border lines (`draw_dashed_line()`).
|
||||
- **Comic SFX**: Borderless, high-contrast banner box for sound effect popups ("BOOM!", "POW!").
|
||||
|
||||
### 3. Dynamic Text & Bubble Animations
|
||||
|
||||
- **Typewriter & Word Reveals**: Animate `visible_characters` via Godot `Tween` for letter-by-letter or word-by-word reveals.
|
||||
- **Elastic Entrances & Transitions**: Scale bubble from $0 \rightarrow 1$ using `TRANS_ELASTIC` on pop-in; morph bounding sizes with smooth squish-and-stretch tweens when swapping text lines back-to-back.
|
||||
- **Word-Specific Shake & Wave**: Support inline animated text effects wrapped in BBCode tags.
|
||||
|
||||
### 4. Advanced Layout & Stagger Stacking
|
||||
|
||||
- **Comic Stagger Stacking**: Allow multiple speech lines to chain into vertical bubble stacks. The bottom bubble anchors to the stickman's head via the main tail, while higher bubbles stack upward connected by bridge geometry (`draw_colored_polygon()`).
|
||||
|
||||
- **Mirroring & Viewport Clamping**: Keep X-scale counter-mirroring active (`_sync_speech_bubble_mirror`). Clamp bubble bounds inside `get_viewport_rect()` so bubbles flip tail anchors or offset position to remain on-screen.
|
||||
|
||||
### 5. Director UI Upgrades
|
||||
|
||||
- **Kid-Friendly Controls**: Color swatch buttons, size toggles (**Small**, **Medium**, **HUGE**), font style pickers, and an emoji grid picker inside the `Speak` parameter dialog.
|
||||
|
||||
- **Text Highlight Formatting Bar**: Selecting text in the dialogue input shows quick-action buttons (🫨 **Shake**, 🌊 **Wave**, 🔥 **Bounce**) that automatically inject BBCode tags.
|
||||
- **Auto-Duration Calculator**: Default `duration` automatically calculates based on word count ($1.0\text{s base} + 0.2\text{s/word}$).
|
||||
|
||||
---
|
||||
|
||||
## Detailed Implementation Plan
|
||||
|
||||
### Phase 1: Engine Migration & Data Foundation
|
||||
|
||||
**Goal:** Upgrade `SpeechBubble` to use `RichTextLabel` and expand data contracts without breaking existing scene functionality.
|
||||
|
||||
1. **Update Action Data Pipeline**:
|
||||
|
||||
- Update `ActionRegistry` and `StageSceneIO` to preserve the optional `visual` dictionary payload on `speak` actions.
|
||||
|
||||
- Ensure `StickmanRig.speak()` parses both flat strings and full visual dictionaries.
|
||||
|
||||
2. **Refactor `SpeechBubble` Node Structure (`scripts/stickman_speech_bubble.gd`)**:
|
||||
|
||||
- Add a child `RichTextLabel` node to `SpeechBubble`.
|
||||
|
||||
- Set `RichTextLabel.bbcode_enabled = true` and configure autowrap.
|
||||
- Modify `_draw()`: Calculate background rectangle bounds dynamically using `RichTextLabel.get_content_height()` and text size metrics, then draw the background polygon/rect and tail under the text.
|
||||
|
||||
### Phase 2: Animated Reveals & Line Transitions
|
||||
|
||||
**Goal:** Implement typewriter effects, word reveals, and smooth line-swapping transitions.
|
||||
|
||||
1. **Typewriter & Word Reveal Engine**:
|
||||
|
||||
- Add `_play_typewriter(text: String, duration: float, mode: String)` to `SpeechBubble`.
|
||||
- Use a Godot `Tween` targeting `RichTextLabel.visible_characters` from `0` to total character length over the target duration.
|
||||
- Implement word-by-word step incrementing by parsing space/punctuation indices in the input string.
|
||||
|
||||
2. **Line Swap & Elastic Transitions**:
|
||||
|
||||
- Update `show_text()`: If a bubble is already visible when a new `speak` command arrives:
|
||||
|
||||
- Scale container down ($1.0 \rightarrow 0.8$) via `EASE_IN` tween.
|
||||
- Swap payload and recalculate bounds.
|
||||
- Scale container back out ($0.8 \rightarrow 1.0$) using `TRANS_ELASTIC` / `EASE_OUT`.
|
||||
|
||||
- Add squish-and-stretch size morphing when text length changes between consecutive lines.
|
||||
|
||||
### Phase 3: Polygon Shape Styles & Comic Geometry
|
||||
|
||||
**Goal:** Generate dynamic background shapes for distinct bubble styles.
|
||||
|
||||
1. **Shape Draw Functions**:
|
||||
|
||||
- **`_draw_standard_bubble(rect)`**: Existing rounded rect + downward tail triangle.
|
||||
|
||||
- **`_draw_yell_bubble(rect)`**: Generate an outer jagged polygon by iterating around `rect` perimeter and alternating vertex radii with random/sine noise offsets.
|
||||
- **`_draw_thought_bubble(rect)`**: Draw overlapping circles along the bounding box edges using `draw_circle()`, followed by 2–3 smaller descending circles pointing to origin.
|
||||
- **`_draw_whisper_bubble(rect)`**: Draw semi-transparent background fill; outline using `draw_dashed_line()` around the perimeter.
|
||||
|
||||
2. **Viewport Boundary Protection**:
|
||||
|
||||
- Calculate global screen position of bubble rect in `_process()`.
|
||||
- If top or side edges exit `get_viewport_rect()`, offset the bubble box downward/inward and flip tail geometry anchor accordingly.
|
||||
|
||||
### Phase 4: Staggered Multi-Bubble Stacking
|
||||
|
||||
**Goal:** Support chained comic bubbles stacking upward from a single character.
|
||||
|
||||
1. **Stack Container Logic**:
|
||||
|
||||
- Extend `SpeechBubble` to manage an array of child `BubbleItem` records.
|
||||
- When a multi-line or stacked speech payload is received, instantiate child bubble slots.
|
||||
|
||||
2. **Stack Geometry & Bridge Rendering**:
|
||||
|
||||
- Anchor the bottom-most bubble to `SPEECH_BUBBLE_OFFSET`.
|
||||
|
||||
- Position preceding bubbles vertically above it with vertical spacing gaps.
|
||||
- In `_draw()`, calculate bridge vertices between `Bubble N` bottom-center and `Bubble N+1` top-center, drawing connecting polygons using `draw_colored_polygon()`.
|
||||
- Restrict the downward head tail exclusively to the bottom bubble in the stack.
|
||||
|
||||
### Phase 5: Director UI & Formatting Controls
|
||||
|
||||
**Goal:** Expose all visual styling tools to kids in the editor UI.
|
||||
|
||||
1. **Integrate Theme Controls into `Speak` Parameter Dialog**:
|
||||
|
||||
- Add `ColorSwatchGrid` popover hooked into theme colors.
|
||||
|
||||
- Add `SizeToggle` segmented control (**Small**, **Medium**, **HUGE**) mapping to font scale metrics.
|
||||
|
||||
- Add `StylePicker` icon buttons (**Standard**, **Yell**, **Thought**, **Whisper**).
|
||||
- Embed `EmojiPicker` grid widget.
|
||||
|
||||
2. **Implement Selection Highlight Formatting Bar**:
|
||||
|
||||
- Attach a floating mini-toolbar above the dialogue `LineEdit` / `TextEdit` field in the `Speak` dialog.
|
||||
- Detect text selection (`get_selected_text()`). When text is highlighted, show mini-buttons:
|
||||
- 🫨 **Shake** $\rightarrow$ wraps selection in `[shake rate=20.0 level=10.0]...[/shake]`
|
||||
- 🌊 **Wave** $\rightarrow$ wraps selection in `[wave amp=50.0 freq=5.0]...[/wave]`
|
||||
- 🔥 **Bounce** $\rightarrow$ wraps selection in `[bounce]...[/bounce]`
|
||||
|
||||
3. **Auto-Duration & Stagger Helpers**:
|
||||
|
||||
- Add auto-duration calculation checkbox/toggle in dialog.
|
||||
- Add **"+ Add Stacked Bubble"** button in the speech dialog to split longer dialogue into chained stack items easily.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user