# Sprint 14 — Zuhause & Garten Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add the garden/home area below the hospital floors, with interactive gift boxes, a tea pot, and camera navigation buttons in both directions. **Architecture:** The Home area lives at world position `(0, 720)` — directly below Floor 0. `RoomNavigator` gains `go_to_home()` / `go_to_hospital()` which tween the camera to `Vector2(640, 1080)`. A `HomeButton` component with `@export var go_to_garden: bool` drives navigation in both directions. No new autoloads; everything hooks into the existing `RoomNavigator` autoload. **Tech Stack:** Godot 4.6.2, GDScript (static typing), ColorRect placeholder visuals, Tween animations --- ### Task 1: RoomNavigator — go_to_home / go_to_hospital **Files:** - Modify: `scripts/systems/room_navigator.gd` - [ ] **Step 1: Replace the entire file** `scripts/systems/room_navigator.gd`: ```gdscript ## RoomNavigator — autoload that moves the Camera2D smoothly between hospital floors, rooms, and the home/garden area. extends Node signal room_changed(floor_index: int, room_index: int) signal home_entered() signal hospital_entered() const FLOOR_HEIGHT: float = 720.0 const ROOM_WIDTH: float = 1280.0 const HOME_CAMERA_X: float = 640.0 const HOME_CAMERA_Y: float = 1080.0 const CAMERA_TWEEN_DURATION: float = 0.6 var _current_floor: int = 0 var _current_room: int = 0 var _is_at_home: bool = false var _camera: Camera2D func initialize(camera: Camera2D) -> void: _camera = camera func go_to_floor(floor_index: int) -> void: go_to_room(floor_index, 0) func go_to_room(floor_index: int, room_index: int) -> void: if _camera == null: return if not _is_at_home and floor_index == _current_floor and room_index == _current_room: return _is_at_home = false _current_floor = floor_index _current_room = room_index var target_x: float = room_index * ROOM_WIDTH + ROOM_WIDTH * 0.5 var target_y: float = floor_index * -FLOOR_HEIGHT + FLOOR_HEIGHT * 0.5 var tween: Tween = create_tween() tween.set_ease(Tween.EASE_IN_OUT) tween.set_trans(Tween.TRANS_SINE) tween.tween_property(_camera, "position", Vector2(target_x, target_y), CAMERA_TWEEN_DURATION) tween.finished.connect(func() -> void: room_changed.emit(floor_index, room_index)) func go_to_home() -> void: if _camera == null: return if _is_at_home: return _is_at_home = true var tween: Tween = create_tween() tween.set_ease(Tween.EASE_IN_OUT) tween.set_trans(Tween.TRANS_SINE) tween.tween_property(_camera, "position", Vector2(HOME_CAMERA_X, HOME_CAMERA_Y), CAMERA_TWEEN_DURATION) tween.finished.connect(func() -> void: home_entered.emit()) func go_to_hospital() -> void: if _camera == null: return if not _is_at_home: return _is_at_home = false var target_x: float = _current_room * ROOM_WIDTH + ROOM_WIDTH * 0.5 var target_y: float = _current_floor * -FLOOR_HEIGHT + FLOOR_HEIGHT * 0.5 var tween: Tween = create_tween() tween.set_ease(Tween.EASE_IN_OUT) tween.set_trans(Tween.TRANS_SINE) tween.tween_property(_camera, "position", Vector2(target_x, target_y), CAMERA_TWEEN_DURATION) tween.finished.connect(func() -> void: hospital_entered.emit()) func get_current_floor() -> int: return _current_floor func get_current_room() -> int: return _current_room func is_at_home() -> bool: return _is_at_home ``` - [ ] **Step 2: Verify no parse errors** Open Godot, check the Output panel — no errors for `room_navigator.gd`. The autoload entry `RoomNavigator` should still appear in Project → Autoload. - [ ] **Step 3: Commit** ```bash git add scripts/systems/room_navigator.gd git commit -m "feat(navigator): add go_to_home / go_to_hospital with home_entered / hospital_entered signals" ``` --- ### Task 2: HomeButton component **Files:** - Create: `scripts/objects/home_button.gd` - Create: `scenes/objects/HomeButton.tscn` - [ ] **Step 1: Create the script** `scripts/objects/home_button.gd`: ```gdscript ## HomeButton — tappable button that navigates between the hospital and the garden area. class_name HomeButton extends Node2D const BUTTON_HALF_SIZE: float = 32.0 @export var go_to_garden: bool = true func _input(event: InputEvent) -> void: if not event is InputEventScreenTouch: return if not (event as InputEventScreenTouch).pressed: return var touch_pos: Vector2 = (event as InputEventScreenTouch).position var local: Vector2 = to_local(touch_pos) if abs(local.x) > BUTTON_HALF_SIZE or abs(local.y) > BUTTON_HALF_SIZE: return if go_to_garden: RoomNavigator.go_to_home() else: RoomNavigator.go_to_hospital() ``` - [ ] **Step 2: Create the scene** `scenes/objects/HomeButton.tscn`: ``` [gd_scene load_steps=2 format=3 uid="uid://cozypaw_homebtn"] [ext_resource type="Script" path="res://scripts/objects/home_button.gd" id="1_homebtn"] [node name="HomeButton" type="Node2D"] script = ExtResource("1_homebtn") [node name="ButtonBody" type="ColorRect" parent="."] offset_left = -32.0 offset_top = -32.0 offset_right = 32.0 offset_bottom = 32.0 color = Color(0.36, 0.70, 0.44, 1) [node name="ButtonIcon" type="ColorRect" parent="."] offset_left = -12.0 offset_top = -18.0 offset_right = 12.0 offset_bottom = 6.0 color = Color(0.90, 0.88, 0.70, 1) ``` - [ ] **Step 3: Verify in Godot** Open `HomeButton.tscn` — green square with a cream-coloured rectangle visible. Check Inspector: `go_to_garden` export shows as `true`. - [ ] **Step 4: Commit** ```bash git add scripts/objects/home_button.gd scenes/objects/HomeButton.tscn git commit -m "feat(home-button): add HomeButton component for hospital/garden navigation" ``` --- ### Task 3: GiftBox component **Files:** - Create: `scripts/objects/gift_box.gd` - Create: `scenes/objects/GiftBox.tscn` - [ ] **Step 1: Create the script** `scripts/objects/gift_box.gd`: ```gdscript ## GiftBox — tap while closed to open: lid rises and fades out, gift inside fades in. class_name GiftBox extends Node2D enum State { CLOSED, OPENING, OPEN } const LID_OPEN_Y: float = -120.0 const OPEN_DURATION: float = 0.5 const GIFT_FADE_DURATION: float = 0.4 const BUTTON_HALF_WIDTH: float = 40.0 const BUTTON_HALF_HEIGHT: float = 50.0 var _state: State = State.CLOSED func _ready() -> void: var gift: Node2D = get_node_or_null("Gift") as Node2D if gift != null: gift.modulate.a = 0.0 func _input(event: InputEvent) -> void: if _state != State.CLOSED: return if not event is InputEventScreenTouch: return if not (event as InputEventScreenTouch).pressed: return var touch_pos: Vector2 = (event as InputEventScreenTouch).position var local: Vector2 = to_local(touch_pos) if abs(local.x) > BUTTON_HALF_WIDTH or abs(local.y) > BUTTON_HALF_HEIGHT: return _start_opening() func _start_opening() -> void: _state = State.OPENING var lid: Node2D = get_node_or_null("Lid") as Node2D if lid == null: _state = State.OPEN return var tween: Tween = create_tween() tween.set_ease(Tween.EASE_OUT) tween.set_trans(Tween.TRANS_BACK) tween.tween_property(lid, "position:y", LID_OPEN_Y, OPEN_DURATION) tween.parallel().tween_property(lid, "modulate:a", 0.0, OPEN_DURATION) tween.finished.connect(_on_lid_opened) func _on_lid_opened() -> void: _state = State.OPEN var gift: Node2D = get_node_or_null("Gift") as Node2D if gift == null: return var tween: Tween = create_tween() tween.tween_property(gift, "modulate:a", 1.0, GIFT_FADE_DURATION) ``` - [ ] **Step 2: Create the scene** `scenes/objects/GiftBox.tscn`: ``` [gd_scene load_steps=2 format=3 uid="uid://cozypaw_giftbox"] [ext_resource type="Script" path="res://scripts/objects/gift_box.gd" id="1_giftbox"] [node name="GiftBox" type="Node2D"] script = ExtResource("1_giftbox") [node name="BoxBase" type="ColorRect" parent="."] offset_left = -40.0 offset_top = -60.0 offset_right = 40.0 offset_bottom = 0.0 color = Color(0.90, 0.28, 0.34, 1) [node name="BoxStripe" type="ColorRect" parent="."] offset_left = -6.0 offset_top = -60.0 offset_right = 6.0 offset_bottom = 0.0 color = Color(0.98, 0.82, 0.22, 1) [node name="Lid" type="Node2D" parent="."] position = Vector2(0, -60) [node name="LidShape" type="ColorRect" parent="Lid"] offset_left = -44.0 offset_top = -18.0 offset_right = 44.0 offset_bottom = 0.0 color = Color(0.98, 0.38, 0.42, 1) [node name="LidBow" type="ColorRect" parent="Lid"] offset_left = -10.0 offset_top = -28.0 offset_right = 10.0 offset_bottom = -18.0 color = Color(0.98, 0.82, 0.22, 1) [node name="Gift" type="Node2D" parent="."] position = Vector2(0, -90) [node name="GiftShape" type="ColorRect" parent="Gift"] offset_left = -20.0 offset_top = -20.0 offset_right = 20.0 offset_bottom = 20.0 color = Color(0.96, 0.76, 0.22, 1) ``` - [ ] **Step 3: Verify in Godot** Open `GiftBox.tscn` — red box body, yellow vertical stripe, red lid above it with yellow bow, yellow star-shaped gift node above lid. The `Gift` node is invisible at runtime (`_ready` sets alpha to 0). - [ ] **Step 4: Commit** ```bash git add scripts/objects/gift_box.gd scenes/objects/GiftBox.tscn git commit -m "feat(gift-box): add GiftBox with tap-to-open lid animation and gift reveal" ``` --- ### Task 4: TeaPot component **Files:** - Create: `scripts/objects/tea_pot.gd` - Create: `scenes/objects/TeaPot.tscn` - [ ] **Step 1: Create the script** `scripts/objects/tea_pot.gd`: ```gdscript ## TeaPot — tap to pour: tilts 45 degrees, holds briefly, then returns to upright. class_name TeaPot extends Node2D enum State { IDLE, POURING } const TILT_ANGLE: float = 45.0 const TILT_DURATION: float = 0.4 const POUR_HOLD: float = 0.8 const RETURN_DURATION: float = 0.4 const BUTTON_HALF_SIZE: float = 40.0 var _state: State = State.IDLE func _input(event: InputEvent) -> void: if _state != State.IDLE: return if not event is InputEventScreenTouch: return if not (event as InputEventScreenTouch).pressed: return var touch_pos: Vector2 = (event as InputEventScreenTouch).position var local: Vector2 = to_local(touch_pos) if abs(local.x) > BUTTON_HALF_SIZE or abs(local.y) > BUTTON_HALF_SIZE: return _start_pouring() func _start_pouring() -> void: _state = State.POURING var tween: Tween = create_tween() tween.set_ease(Tween.EASE_IN_OUT) tween.set_trans(Tween.TRANS_SINE) tween.tween_property(self, "rotation_degrees", TILT_ANGLE, TILT_DURATION) tween.tween_interval(POUR_HOLD) tween.tween_property(self, "rotation_degrees", 0.0, RETURN_DURATION) tween.finished.connect(func() -> void: _state = State.IDLE) ``` - [ ] **Step 2: Create the scene** `scenes/objects/TeaPot.tscn`: ``` [gd_scene load_steps=2 format=3 uid="uid://cozypaw_teapot"] [ext_resource type="Script" path="res://scripts/objects/tea_pot.gd" id="1_teapot"] [node name="TeaPot" type="Node2D"] script = ExtResource("1_teapot") [node name="PotBody" type="ColorRect" parent="."] offset_left = -30.0 offset_top = -50.0 offset_right = 30.0 offset_bottom = 0.0 color = Color(0.96, 0.92, 0.84, 1) [node name="PotLid" type="ColorRect" parent="."] offset_left = -28.0 offset_top = -58.0 offset_right = 28.0 offset_bottom = -48.0 color = Color(0.74, 0.62, 0.50, 1) [node name="PotSpout" type="ColorRect" parent="."] offset_left = 26.0 offset_top = -38.0 offset_right = 46.0 offset_bottom = -22.0 color = Color(0.96, 0.92, 0.84, 1) [node name="PotHandle" type="ColorRect" parent="."] offset_left = -48.0 offset_top = -36.0 offset_right = -36.0 offset_bottom = -14.0 color = Color(0.96, 0.92, 0.84, 1) ``` - [ ] **Step 3: Verify in Godot** Open `TeaPot.tscn` — cream-coloured pot body, brown lid on top, spout on right, handle on left all visible. - [ ] **Step 4: Commit** ```bash git add scripts/objects/tea_pot.gd scenes/objects/TeaPot.tscn git commit -m "feat(teapot): add TeaPot with tap-to-pour tilt animation" ``` --- ### Task 5: GardenParty scene **Files:** - Create: `scenes/rooms/home/GardenParty.tscn` - [ ] **Step 1: Create the scene file** `scenes/rooms/home/GardenParty.tscn`: ``` [gd_scene load_steps=4 format=3 uid="uid://cozypaw_gardenparty"] [ext_resource type="PackedScene" path="res://scenes/objects/GiftBox.tscn" id="1_giftbox"] [ext_resource type="PackedScene" path="res://scenes/objects/TeaPot.tscn" id="2_teapot"] [ext_resource type="PackedScene" path="res://scenes/objects/HomeButton.tscn" id="3_homebtn"] [node name="GardenParty" type="Node2D"] [node name="Sky" type="ColorRect" parent="."] offset_left = 0.0 offset_top = 0.0 offset_right = 1280.0 offset_bottom = 400.0 color = Color(0.53, 0.81, 0.98, 1) [node name="Grass" type="ColorRect" parent="."] offset_left = 0.0 offset_top = 400.0 offset_right = 1280.0 offset_bottom = 720.0 color = Color(0.55, 0.76, 0.46, 1) [node name="GroundEdge" type="ColorRect" parent="."] offset_left = 0.0 offset_top = 392.0 offset_right = 1280.0 offset_bottom = 404.0 color = Color(0.38, 0.62, 0.32, 1) [node name="TableTop" type="ColorRect" parent="."] offset_left = 440.0 offset_top = 464.0 offset_right = 840.0 offset_bottom = 480.0 color = Color(0.82, 0.66, 0.46, 1) [node name="TableLeg1" type="ColorRect" parent="."] offset_left = 456.0 offset_top = 480.0 offset_right = 472.0 offset_bottom = 580.0 color = Color(0.70, 0.52, 0.34, 1) [node name="TableLeg2" type="ColorRect" parent="."] offset_left = 808.0 offset_top = 480.0 offset_right = 824.0 offset_bottom = 580.0 color = Color(0.70, 0.52, 0.34, 1) [node name="TeaPot" parent="." instance=ExtResource("2_teapot")] position = Vector2(510, 464) [node name="GiftBox1" parent="." instance=ExtResource("1_giftbox")] position = Vector2(640, 464) [node name="GiftBox2" parent="." instance=ExtResource("1_giftbox")] position = Vector2(730, 464) [node name="GiftBox3" parent="." instance=ExtResource("1_giftbox")] position = Vector2(820, 464) [node name="TeaCup" type="ColorRect" parent="."] offset_left = 558.0 offset_top = 440.0 offset_right = 590.0 offset_bottom = 464.0 color = Color(0.96, 0.92, 0.84, 1) [node name="Balloon1" type="ColorRect" parent="."] offset_left = 180.0 offset_top = 120.0 offset_right = 220.0 offset_bottom = 180.0 color = Color(0.96, 0.44, 0.44, 1) [node name="Balloon2" type="ColorRect" parent="."] offset_left = 1020.0 offset_top = 100.0 offset_right = 1060.0 offset_bottom = 160.0 color = Color(0.56, 0.76, 0.96, 1) [node name="HomeButtonReturn" parent="." instance=ExtResource("3_homebtn")] position = Vector2(100, 620) go_to_garden = false ``` - [ ] **Step 2: Verify in Godot** Open `GardenParty.tscn` — blue sky, green grass, dark ground edge, brown table with two legs. TeaPot and 3 GiftBoxes sitting on the table (top at y=464). TeaCup to the left of the pots. Two balloons (red, blue). Green HomeButton bottom-left with `go_to_garden = false` in inspector. - [ ] **Step 3: Commit** ```bash git add scenes/rooms/home/GardenParty.tscn git commit -m "feat(garden): add GardenParty scene with table, gifts, teapot, balloons, and return button" ``` --- ### Task 6: Main.tscn — Home integration **Files:** - Modify: `scenes/main/Main.tscn` - [ ] **Step 1: Update load_steps** Replace: ``` [gd_scene load_steps=20 format=3 uid="uid://cozypaw_main"] ``` With: ``` [gd_scene load_steps=22 format=3 uid="uid://cozypaw_main"] ``` - [ ] **Step 2: Add ext_resources after the last existing one (id="18_nursery")** ``` [ext_resource type="PackedScene" path="res://scenes/rooms/home/GardenParty.tscn" id="19_gardenparty"] [ext_resource type="PackedScene" path="res://scenes/objects/HomeButton.tscn" id="20_homebtn"] ``` - [ ] **Step 3: Add HomeButtonToGarden on Floor0** After the last Floor0 nav arrow node (`NavLeft3to2`), add: ``` [node name="HomeButtonToGarden" parent="Hospital/Floor0" instance=ExtResource("20_homebtn")] position = Vector2(640, 620) go_to_garden = true ``` - [ ] **Step 4: Add Home node and GardenParty** After the last Floor2 node (`NavLeft2to1_F2`) and before `[node name="Characters" ...`, add: ``` [node name="Home" type="Node2D" parent="."] position = Vector2(0, 720) [node name="GardenParty" parent="Home" instance=ExtResource("19_gardenparty")] position = Vector2(0, 0) ``` - [ ] **Step 5: Verify in Godot** Run the main scene: 1. Scene loads without errors 2. Floor0 shows a green HomeButton square at the bottom centre (x=640, y=620) 3. Tap the HomeButtonToGarden → camera slides smoothly down to garden (blue sky + green grass) 4. Tap HomeButtonReturn in the garden → camera slides back up to Floor0/Reception 5. Elevator buttons between floors 0/1/2 still work correctly 6. Nav arrows between rooms still work on all three floors - [ ] **Step 6: Commit** ```bash git add scenes/main/Main.tscn git commit -m "feat(main): integrate Home/GardenParty below Floor0 with bidirectional navigation" ```