Coding a Room: Kid-Friendly Projects Inspired by Virtual Staging Software 2026

Open any real estate website and you’ll find photos of rooms that look ready to move into: a sofa angled toward the fireplace, a rug that fits the floor perfectly, a plant catching light from the window. Surprisingly often, none of that furniture is real. The room was empty when it was photographed, and software added everything afterward. This is called virtual staging, and it has quietly become standard in real estate marketing.

Behind every virtually staged photo is a stack of programming ideas: coordinates, shapes, measurements, collision checks, scaling, perspective, and, in newer tools, artificial intelligence. None of those ideas are reserved for professional software engineers. Every one of them can be explored by kids with Scratch or Python, using the same fundamentals taught in any good beginner coding course.

That’s what this article is about. It’s a hands-on guide to coding projects inspired by virtual staging, starting with simple Scratch activities for younger kids and building up to Python programs that draw floor plans, detect furniture collisions, arrange rooms automatically, simulate 3D perspective, and even “stage” a room photo with code. Along the way, it covers the programming fundamentals each project teaches: variables, loops, conditionals, functions, lists, dictionaries, coordinates, and algorithms.

All Python code in this article was tested and runs as written. Kids can type it in (typing it, rather than copying and pasting, is a great way to learn), run it, break it, and change it.

Why Rooms Make Great Coding Projects

Before diving into code, it’s worth asking why room design works so well as a theme for learning to program.

Rooms are familiar. Every child knows what a bedroom looks like, where a bed usually goes, and why you can’t put a bookshelf in front of a door. That everyday knowledge becomes the “rules” of the program, so kids already understand the problem before they write a line of code.

Rooms are naturally geometric. A room is a rectangle. Furniture pieces are smaller rectangles. Placing them means working with coordinates, widths, depths, and areas. That makes room projects a natural bridge between coding and math.

Rooms produce visual results. Kids see their code turn into a floor plan, a grid, or a picture. Visual feedback is one of the most motivating parts of programming, and it makes bugs easy to spot. If the bed is floating outside the wall, something’s wrong.

Rooms scale from simple to advanced. A five-year-old can drag furniture sprites around a Scratch backdrop. A high schooler can write an algorithm that tests thousands of layouts and picks the best one. It’s the same theme at very different depths.

Rooms build spatial thinking. Research on spatial skills, the ability to picture and mentally manipulate shapes and spaces, has found that these skills are closely linked to success in math, science, and engineering, and that they improve with practice. A 2018 study by Jack Parkinson and Quintin Cutts at the University of Glasgow found that spatial skills tended to be higher at higher levels of computer science achievement, although the researchers were careful to say the evidence on cause and effect isn’t settled. Either way, room projects exercise both spatial thinking and programming at once.

How Virtual Staging Software Works (the Short Version)

It helps to know what actually real and the best virtual staging software [Jump to Details] and Home Virtual Staging AI Apps for Furniture Staged for Realtors and Real Estate actually does, because each project in this article mirrors one piece of it.

  1. It figures out the room. The software looks at a photo and works out where the floor, walls, ceiling, and windows are. In AI-based tools, this is done with computer vision models that label each pixel of the image, a process called segmentation.
  2. It estimates depth and perspective. A photo is flat, but the room is 3D. The software estimates how far away each part of the room is, where the vanishing points are, and how big objects should appear at different distances.
  3. It places furniture. Furniture models are positioned on the floor, rotated to line up with the walls, and scaled so they look the right size.
  4. It checks for problems. Good tools avoid placing furniture through walls, on top of other furniture, or in front of doors.
  5. It renders the final image. The furniture is blended into the photo with matching lighting and shadows.

Here’s how the projects in this article map to those steps:

Real software step

Project in this article

Representing a room

Scratch room designer, Python floor plan

Measuring space

Area and free-space calculator

Avoiding collisions

Collision detection, door swing checker

Rotating furniture

Rotation function

Automatic arranging

Layout optimizer

Perspective and depth

3D projection project

Placing objects in a photo

Pillow “staging” project

Organizing a large program

Room and Furniture classes

Saving a design

JSON save and load

AI and segmentation

AI discussion and extension ideas

Part 1: Programming Fundamentals Through a Room

Every project below uses a handful of core programming ideas. Here they are, explained with room examples. If you’re a parent or teacher, this section is a good reference for explaining concepts as kids work through the projects.

Coordinates: where things are

Almost all graphics programming starts with coordinates: pairs of numbers that describe a position. In a floor plan, x usually means how far across (left to right) and y means how far up or down.

Scratch uses a stage that’s 480 pixels wide and 360 pixels tall, with the point (0, 0) in the very center. Moving right increases x, and moving up increases y. So the top-right corner of the Scratch stage is (240, 180), and the bottom-left is (-240, -180).

Python’s turtle module uses the same idea: (0, 0) is the center of the window.

Many other graphics systems, including the Python image library used later in this article, put (0, 0) in the top-left corner and make y increase as you go down. This trips up even experienced programmers, so it’s worth pointing out to kids early: different systems measure from different starting points.

Variables: remembering values

A variable is a named box that stores a value. In a room program, variables might store the room’s width, the bed’s position, or the number of furniture pieces.

In Scratch, you create variables with the Make a Variable button in the Variables category. In Python, you simply assign a value:

room_width = 12 # feet

room_depth = 10 # feet

room_area = room_width * room_depth

print(room_area) # prints 120

The # symbol starts a comment, a note for humans that Python ignores. Comments are a good habit from day one.

Loops: doing things again and again

A loop repeats instructions. Drawing a rectangle means drawing four sides, so instead of writing the same instruction four times, you use a loop.

In Scratch, that’s the repeat block. In Python:

for side in range(4):

print(“Draw a side and turn 90 degrees”)

range(4) produces the numbers 0, 1, 2, and 3, so the loop runs four times.

Conditionals: making decisions

A conditional lets a program choose what to do. “If the bed overlaps the desk, show a warning.” In Scratch, that’s the if / then and if / then / else blocks. In Python:

bed_width = 4

space_left = 3

if bed_width > space_left:

print(“The bed doesn’t fit!”)

else:

print(“The bed fits.”)

Functions: reusable recipes

A function is a named set of instructions you can use over and over. Instead of writing code to draw a bed, a desk, and a rug separately, you write one draw_rectangle function and call it three times with different numbers.

Scratch calls these custom blocks, made in the My Blocks category. In Python, you use def:

def area(width, depth):

return width * depth

print(area(4, 6.5)) # bed: 26.0

print(area(4, 2)) # desk: 8

The values inside the parentheses, width and depth, are called parameters. return sends the result back to whoever called the function.

Lists and dictionaries: organizing data

A room has many pieces of furniture, and each piece has several properties: a name, a position, a width, and a depth. Python handles this neatly with two data structures:

  • A list is an ordered collection: [“Bed”, “Desk”, “Lamp”].
  • A dictionary stores labeled values: {“name”: “Bed”, “w”: 4, “d”: 6.5}.

Put them together, and you get a list of dictionaries, one of the most useful patterns in all of programming:

furniture = [

{“name”: “Bed”, “x”: 0, “y”: 0, “w”: 4, “d”: 6.5},

{“name”: “Desk”, “x”: 8, “y”: 0, “w”: 4, “d”: 2},

]

for item in furniture:

print(item[“name”], “is”, item[“w”], “feet wide”)

Scratch has lists too (in the Variables category), though no dictionaries. Scratch projects often use several parallel lists instead, for example one list for names and another for widths.

Algorithms: step-by-step solutions

An algorithm is a step-by-step method for solving a problem. “Check every pair of furniture pieces and see if any overlap” is an algorithm. So is “try 2,000 random layouts and keep the best one.” Algorithms are where programming becomes problem-solving, and they’re the heart of the later projects in this article.

Part 2: Scratch Projects (Ages 7–11)

Scratch was created by the Lifelong Kindergarten group at the MIT Media Lab and launched publicly in 2007. It uses colorful drag-and-drop blocks instead of typed code, which makes it ideal for younger learners. It’s free and runs in a web browser.

Because Scratch is visual, the code below is written as text descriptions of blocks. Block names are shown as they appear in Scratch, with the category in brackets.

Scratch Project 1: The Room Walker

What it teaches: coordinates, motion, loops, measuring.

Idea: A sprite walks around the edge of a rectangular room, like someone pacing out its walls.

Setup:

  1. Start a new project. Keep the cat sprite or pick another.
  2. Use the Paint tool on the backdrop to draw a large rectangle, the “room.”
  3. Move the sprite to the bottom-left corner of the room.

Code:

when green flag clicked [Events]

go to x: -150 y: -100 [Motion]

point in direction 90 [Motion]

pen down [Pen extension]

repeat 2 [Control]

move 300 steps [Motion]

turn right 90 degrees [Motion]

move 200 steps [Motion]

turn right 90 degrees [Motion]

end

pen up [Pen extension]

To use the pen blocks, click the Add Extension button at the bottom-left of the editor and choose Pen.

Why repeat 2 and not repeat 4? Because a rectangle has two long sides and two short sides. Each loop draws one long side and one short side. This is a nice moment for kids to see that loops can repeat a pattern, not just a single action.

Challenges:

  • Make variables called room width and room depth, and use them in place of 300 and 200.
  • Add a say block so the sprite announces the room’s perimeter: say (join “Perimeter: ” ((room width + room depth) * 2)).
  • Make the sprite walk more slowly using glide blocks so you can watch the path.

Scratch Project 2: Drag-and-Drop Room Designer

What it teaches: sprites, events, dragging, layering, costumes.

Idea: A simple virtual staging app. The backdrop is a photo of an empty room. Furniture sprites can be dragged into place.

Setup:

  1. Upload a photo of an empty room as the backdrop, or draw one. A photo of a real room at home or school works well (with permission).
  2. Add furniture sprites. You can draw simple shapes (rectangles for beds, circles for rugs) or use Scratch’s library.
  3. Give each furniture sprite two or three costumes in different colors or styles.

Code for each furniture sprite:

when green flag clicked [Events]

set drag mode [draggable] [Sensing]

go to x: (pick random -200 to 200) y: -150 [Motion]

when this sprite clicked [Events]

next costume [Looks]

go to [front] layer [Looks]

Clicking a piece cycles through its styles, so kids can test a blue sofa versus a green one, just like real staging tools offer different style options.

Add a size control. Furniture that’s farther back in a room photo should look smaller. Add this to each furniture sprite:

when green flag clicked [Events]

forever [Control]

set size to (100 – ((y position) / 3)) % [Looks, Operators]

end

Now when a sprite is dragged toward the top of the stage (the back of the room), it shrinks. When dragged toward the bottom (the front), it grows. This is a simple version of perspective scaling, the same idea real virtual staging software uses, explored in more depth in Part 4.

Kids can experiment with the numbers in the formula until the size change looks right for their particular room photo. That’s a real design process: try, look, adjust.

Scratch Project 3: Does It Fit? Collision Checker

What it teaches: sensing, conditionals, feedback.

Idea: When two pieces of furniture overlap, the program warns the user.

Code for each furniture sprite:

when green flag clicked [Events]

forever [Control]

if <touching [Bed v]?> then [Sensing]

set [ghost] effect to 50 [Looks]

say [Too close!] [Looks]

else

clear graphic effects [Looks]

say [] [Looks]

end

end

Repeat the check for other sprites, or use a cleaner approach: give all the furniture sprites the same color outline and use touching color.

Add walls. Draw the walls on the backdrop in a specific color, for example dark gray. Then add:

if <touching color [dark gray]?> then [Sensing]

say [That’s a wall!] [Looks]

end

Talking point: Scratch’s touching block checks the actual pixels of each sprite. Python, as you’ll see later, checks overlaps with math instead. Both are valid. They’re just different approaches to the same problem, and comparing them is a great conversation for kids moving from Scratch to Python.

Scratch Project 4: Paint the Walls

What it teaches: broadcasts, variables, color effects.

Idea: Buttons let the user change the wall color, the floor style, and the lighting mood.

Setup:

  1. Draw the walls as a separate sprite on top of the room backdrop.
  2. Create three button sprites labeled “Warm,” “Cool,” and “Night.”

Code on the “Warm” button:

when this sprite clicked [Events]

broadcast [warm] [Events]

Code on the walls sprite:

when I receive [warm] [Events]

set [color] effect to 20 [Looks]

set [brightness] effect to 10 [Looks]

when I receive [night] [Events]

set [color] effect to 120 [Looks]

set [brightness] effect to -40 [Looks]

Concept: broadcast is how sprites talk to each other in Scratch. One sprite sends a message, and any sprite listening for that message reacts. This is an early introduction to event-driven programming, the same pattern used in apps, games, and websites.

Scratch Project 5: Room Score

What it teaches: variables, math operators, game design.

Idea: Turn room design into a game. Players earn points for good choices and lose points for problems.

Rules to code:

  • +10 points if the bed is touching a wall (beds usually go against walls).
  • +10 points if the desk is near the window.
  • –20 points if anything blocks the door.
  • –10 points for any overlapping furniture.

Code: Scratch’s sensing blocks only check the sprite they belong to, so each rule lives on the sprite it’s about, and all of them add to one shared score variable (created “For all sprites”).

On a “host” sprite (any character who announces the result):

when [space] key pressed [Events]

set [score] to 0 [Variables]

broadcast [check room] and wait [Events]

say (join “Room score: ” (score)) [Looks]

On the Bed sprite:

when I receive [check room] [Events]

if <touching color [dark gray]?> then [Sensing]

change [score] by 10 [Variables]

end

On the Desk sprite:

when I receive [check room] [Events]

if <(distance to [Window v]) < 80> then [Sensing, Operators]

change [score] by 10 [Variables]

end

On the Door sprite:

when I receive [check room] [Events]

if <touching [Bed v]?> or <touching [Desk v]?> then

change [score] by -20 [Variables]

end

The host sprite is used because the stage itself can’t say anything. You can also tick the checkbox next to score to show it on screen.

Why it’s valuable: Kids have to turn fuzzy design ideas (“beds look better against walls”) into precise rules a computer can check. That translation, from human judgment to explicit logic, is one of the most important skills in programming.

Part 3: Moving From Scratch to Python (Ages 10+)

Python was created by Guido van Rossum and first released in 1991. It’s become one of the most widely used programming languages in the world, in fields ranging from web development to data science to artificial intelligence. It’s also a popular first typed language for kids, because its syntax is clean and readable.

Getting set up

To run the projects below, kids need Python 3 installed on a computer. The official installer from the Python website includes IDLE, a simple editor that’s fine for beginners. Many families and schools also like Thonny, an editor designed for learning, which shows variables as the program runs.

The turtle module, used in the first few projects, comes built into standard Python. The final project uses Pillow, an image library that can be installed by typing this into a terminal or command prompt:

pip install pillow

Scratch-to-Python cheat sheet

For kids coming from Scratch, it helps to see how familiar blocks translate:

Scratch block

Python equivalent

when green flag clicked

Running the program

set [x] to 10

x = 10

change [x] by 1

x += 1 or x = x + 1

repeat 10

for i in range(10):

forever

while True:

if <> then

if condition:

if <> then else

if condition: … else:

say [Hello]

print(“Hello”)

ask [Name?] and wait

name = input(“Name? “)

move 10 steps

t.forward(10) (turtle)

turn right 90

t.right(90) (turtle)

My Blocks (custom block)

def my_function():

Lists

my_list = []

One big difference: indentation matters in Python. The lines inside a loop, if, or function must be indented (usually four spaces). In Scratch, blocks snap inside other blocks. In Python, indentation does that job. Most beginner bugs come from missing or inconsistent indentation, so it’s worth emphasizing early.

Python Project 1: Draw a Floor Plan With Turtle

What it teaches: functions, parameters, loops, scale, coordinates.

The turtle is a cursor that draws lines as it moves, a direct descendant of the LOGO turtle invented by Seymour Papert and colleagues in the late 1960s. This project draws a room and its furniture to scale.

import turtle

SCALE = 30 # 30 pixels on screen = 1 foot in real life

t = turtle.Turtle()

t.speed(0) # fastest drawing

t.hideturtle()

def draw_rect(x, y, width, depth, label, color=”black”):

“””Draw a rectangle with its bottom-left corner at (x, y), in feet.”””

t.penup()

t.goto(x * SCALE, y * SCALE)

t.pendown()

t.color(color)

for side in [width, depth, width, depth]:

t.forward(side * SCALE)

t.left(90)

# write the label near the middle of the rectangle

t.penup()

t.goto((x + width / 2) * SCALE, (y + depth / 2) * SCALE)

t.write(label, align=”center”)

# Shift everything so the room is centered on screen

OFFSET_X, OFFSET_Y = -6, -5

draw_rect(OFFSET_X, OFFSET_Y, 12, 10, “”, “black”) # room

draw_rect(OFFSET_X + 0, OFFSET_Y + 0, 4, 6.5, “Bed”, “blue”)

draw_rect(OFFSET_X + 8, OFFSET_Y + 0, 4, 2, “Desk”, “brown”)

draw_rect(OFFSET_X + 0, OFFSET_Y + 9, 3, 1, “Shelf”, “green”)

turtle.done()

How it works:

  • SCALE is a constant, a variable that never changes. By convention, constants are written in capitals. Changing this single number resizes the whole drawing.
  • draw_rect works in feet, and multiplies by SCALE only when moving the turtle. This separation, keeping real-world units apart from screen pixels, is exactly how real design software works.
  • The for side in [width, depth, width, depth]: loop is a clever trick: instead of looping over numbers, it loops over the four side lengths directly.
  • The text in triple quotes under def is a docstring, a description of what the function does.
  • color=”black” is a default parameter: if you don’t specify a color, black is used.

Challenges:

  1. Measure a real room at home and draw it to scale.
  2. Add a door as a gap in the wall.
  3. Add a rug using t.circle().
  4. Fill furniture with color using t.begin_fill() and t.end_fill().

Python Project 2: The Free-Space Calculator

What it teaches: lists, dictionaries, loops, accumulators, formatted output.

Real virtual staging can make a room look roomy or cramped. This program calculates how much floor space is left after furniture is placed.

room = {“name”: “Bedroom”, “width”: 12, “depth”: 10}

furniture = [

{“name”: “Bed”, “x”: 0, “y”: 0, “w”: 4, “d”: 6.5},

{“name”: “Desk”, “x”: 8, “y”: 0, “w”: 4, “d”: 2},

{“name”: “Bookshelf”, “x”: 0, “y”: 8, “w”: 3, “d”: 1},

]

room_area = room[“width”] * room[“depth”]

used = 0

for item in furniture:

a = item[“w”] * item[“d”]

used += a

print(f”{item[‘name’]:<10} {a:>6.1f} sq ft”)

free = room_area – used

print(f”Room area: {room_area} sq ft”)

print(f”Furniture: {used} sq ft”)

print(f”Free space: {free} sq ft ({free / room_area:.0%})”)

Output:

Bed 26.0 sq ft

Desk 8.0 sq ft

Bookshelf 3.0 sq ft

Room area: 120 sq ft

Furniture: 37.0 sq ft

Free space: 83.0 sq ft (69%)

How it works:

  • used = 0 followed by used += a inside the loop is called the accumulator pattern. It’s one of the most common patterns in programming: start at zero, then add to it each time through a loop.
  • The f”…” strings are f-strings, which let you put variables directly inside text using {}.
  • :<10 means “left-align in 10 characters,” :>6.1f means “right-align in 6 characters with one decimal place,” and :.0% turns 0.69 into 69%. Formatting codes like these make output tidy.

Challenges:

  1. Ask the user to type in furniture using input(), and convert their answers with float().
  2. Print a warning if free space drops below 50%.
  3. Calculate cost: add a “price” key to each item and total the cost of the room.

Math connection: This is area and percentages in action. A good discussion question: why might a room feel crowded even when 60% of the floor is free? (Because where the free space is matters, which leads directly to the next project.)

Python Project 3: Collision Detection

What it teaches: Boolean logic, functions that return True/False, nested loops.

Real staging software must never put a bed through a desk. Game developers face the same problem: knowing when a character hits a wall. The most common solution for rectangles is called axis-aligned bounding box collision detection, usually shortened to AABB.

The idea is simple. Two rectangles don’t overlap if one is completely to the left, right, above, or below the other. If none of those is true, they overlap.

def overlaps(a, b):

“””Return True if rectangles a and b overlap.”””

return (a[“x”] < b[“x”] + b[“w”] and

a[“x”] + a[“w”] > b[“x”] and

a[“y”] < b[“y”] + b[“d”] and

a[“y”] + a[“d”] > b[“y”])

def inside_room(item, room):

“””Return True if the item fits completely inside the room.”””

return (item[“x”] >= 0 and item[“y”] >= 0 and

item[“x”] + item[“w”] <= room[“width”] and

item[“y”] + item[“d”] <= room[“depth”])

def check_layout(furniture, room):

ok = True

for item in furniture:

if not inside_room(item, room):

print(f”{item[‘name’]} sticks out of the room!”)

ok = False

for i in range(len(furniture)):

for j in range(i + 1, len(furniture)):

if overlaps(furniture[i], furniture[j]):

print(f”{furniture[i][‘name’]} overlaps {furniture[j][‘name’]}!”)

ok = False

if ok:

print(“Layout looks good!”)

return ok

check_layout(furniture, room)

furniture.append({“name”: “Beanbag”, “x”: 3, “y”: 5, “w”: 3, “d”: 3})

check_layout(furniture, room)

Output:

Layout looks good!

Bed overlaps Beanbag!

How it works:

  • Each function returns a Boolean, either True or False. Functions like this are sometimes called predicates, and they make code read almost like English: if overlaps(bed, desk):.
  • and means all four conditions must be true for an overlap.
  • The nested loop with range(i + 1, len(furniture)) checks every pair exactly once. Without the i + 1, the program would check each piece against itself (always an overlap) and check every pair twice.

Understanding the math: Have kids draw two rectangles on graph paper and test the four conditions by hand. The bed covers x from 0 to 4 and y from 0 to 6.5. The beanbag covers x from 3 to 6 and y from 5 to 8. Their x ranges overlap (3 to 4) and their y ranges overlap (5 to 6.5), so the rectangles overlap. Drawing it out makes the logic click.

Efficiency talking point: With 4 pieces of furniture, there are 6 pairs to check. With 100 pieces, there are 4,950. The number of pairs grows roughly with the square of the number of items. This is a gentle introduction to algorithm efficiency, a big idea in computer science. Real game engines use clever tricks to avoid checking every pair.

Python Project 4: Rotate the Furniture

What it teaches: variable swapping, mutation, testing.

Real staging software lets users rotate furniture. For rectangles aligned with the walls, a 90-degree rotation is easy: width and depth swap.

def rotate(item):

“””Rotate an item 90 degrees by swapping width and depth.”””

item[“w”], item[“d”] = item[“d”], item[“w”]

return item

bed = {“name”: “Bed”, “x”: 0, “y”: 0, “w”: 4, “d”: 6.5}

rotate(bed)

print(bed) # {‘name’: ‘Bed’, ‘x’: 0, ‘y’: 0, ‘w’: 6.5, ‘d’: 4}

How it works: a, b = b, a is Python’s elegant way to swap two values in a single line. In many other languages (and in Scratch), you need a temporary third variable:

temp = item[“w”]

item[“w”] = item[“d”]

item[“d”] = temp

Concept: mutation. Notice that rotate(bed) changes the original bed dictionary. Dictionaries and lists are mutable: functions can change them in place. Numbers and strings are not. This difference surprises many new programmers, and it’s worth demonstrating with a quick experiment.

Challenge: Write a function try_rotations(item, others, room) that rotates an item if it doesn’t fit, then checks again using the functions from Project 3.

Python Project 5: A Text-Based Room Grid

What it teaches: 2D lists, nested loops, validation before action.

Not every program needs graphics. This one represents the room as a grid of characters, like a simple game map. Each cell is one foot square.

WIDTH, DEPTH = 12, 8

def make_grid():

return [[“.” for _ in range(WIDTH)] for _ in range(DEPTH)]

def place(grid, symbol, x, y, w, d):

“””Try to place an item. Return True if it fits, False if not.”””

# First, check every cell

for row in range(y, y + d):

for col in range(x, x + w):

if row >= DEPTH or col >= WIDTH:

return False # off the edge of the room

if grid[row][col] != “.”:

return False # something is already there

# Only if all cells are free, fill them in

for row in range(y, y + d):

for col in range(x, x + w):

grid[row][col] = symbol

return True

def show(grid):

for row in grid:

print(” “.join(row))

grid = make_grid()

print(place(grid, “B”, 0, 0, 4, 6)) # bed

print(place(grid, “D”, 8, 0, 4, 2)) # desk

print(place(grid, “C”, 3, 2, 2, 2)) # chair – overlaps the bed!

show(grid)

Output:

True

True

False

B B B B . . . . D D D D

B B B B . . . . D D D D

B B B B . . . . . . . .

B B B B . . . . . . . .

B B B B . . . . . . . .

B B B B . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

How it works:

  • [[“.” for _ in range(WIDTH)] for _ in range(DEPTH)] is a list comprehension that builds a list of lists, a 2D list. Each inner list is one row. The _ is a common name for a loop variable you don’t actually use.
  • grid[row][col] accesses one cell: first pick the row, then the column.
  • place follows an important pattern: check first, then act. It checks every cell before changing any. If it changed cells as it went, a failed placement would leave half a chair stuck in the grid.
  • ” “.join(row) glues the characters of a row together with spaces between them.

Challenges:

  1. Turn it into an interactive game: ask the user for an item and coordinates, then show the updated grid.
  2. Add a remove(grid, symbol) function.
  3. Add walls and a door, and prevent placing furniture in front of the door.

Note on the grid versus the AABB approach: Project 3 checked overlaps with math. This project checks them cell by cell. The grid approach is easier to visualize, but it only works with whole-number positions. The math approach handles any size. Real software often combines both.

Part 4: Advanced Python Projects (Ages 12+)

The next projects introduce more advanced ideas: randomness, optimization, geometry, 3D math, and image processing. They build on everything above.

Python Project 6: The Automatic Room Arranger

What it teaches: randomness, search algorithms, scoring functions, optimization.

Some modern design tools can suggest furniture layouts automatically. One of the simplest ways to do that is random search: try lots of random layouts, give each one a score, and keep the best. This project reuses the grid functions from Project 5.

import random

def score_layout(grid):

“””Higher score = more open floor in the middle of the room.”””

score = 0

for row in range(2, DEPTH – 2):

for col in range(3, WIDTH – 3):

if grid[row][col] == “.”:

score += 1

return score

pieces = [(“B”, 4, 6), (“D”, 4, 2), (“S”, 3, 1), (“C”, 2, 2)]

best_score, best_grid = -1, None

random.seed(1) # makes the “random” results repeatable

for attempt in range(2000):

g = make_grid()

ok = True

for symbol, w, d in pieces:

if random.random() < 0.5: # 50% chance to rotate

w, d = d, w

x = random.randint(0, WIDTH – w)

y = random.randint(0, DEPTH – d)

if not place(g, symbol, x, y, w, d):

ok = False

break # this layout failed, try another

if ok:

s = score_layout(g)

if s > best_score:

best_score, best_grid = s, g

print(“Best score:”, best_score)

show(best_grid)

Sample output:

Best score: 20

. . . . . . . . . . . .

. . . . . . . . . . D D

B B B B . . . . . . D D

B B B B . . . . . . D D

B B B B . . . . . . D D

B B B B . . . . . . . .

B B B B S S S . . C C .

B B B B . . . . . . . .

Notice that the program learned, without being told, to push furniture toward the walls. That’s because the scoring function rewards open space in the middle. The program never “understood” interior design. It just tried thousands of options and kept the ones that scored well.

How it works:

  • random.randint(a, b) picks a random whole number from a to b, inclusive. random.random() returns a decimal between 0 and 1.
  • random.seed(1) makes the sequence of random numbers the same each time the program runs, which is helpful for testing and for comparing results with friends. Remove it to get different layouts each time.
  • break exits the inner loop early as soon as one piece fails to fit.
  • The scoring function is where the program’s “taste” lives. Change the scoring rules and the program will prefer completely different layouts.

Big idea: optimization. This is a simple form of an optimization algorithm, a program that searches for the best answer among many possibilities. More sophisticated methods, such as hill climbing, simulated annealing, and genetic algorithms, use smarter strategies than pure random guessing. Optimization is used everywhere, from planning delivery routes to designing computer chips to training AI models.

Challenges:

  1. Add points for the desk being next to a “window” on the top wall.
  2. Subtract points if the bed isn’t touching a wall.
  3. Print how many of the 2,000 attempts produced a valid layout. (You’ll find that many fail. That’s a useful lesson in how hard packing problems are.)
  4. Hill climbing: Instead of starting fresh each time, take the best layout and move one piece slightly. Keep the change only if the score improves.

Python Project 7: Will the Door Hit the Desk?

What it teaches: geometry, the distance formula, the math module, clamping.

A classic design mistake is putting furniture where a door swings open. A door swings in a quarter circle around its hinge. To check if it hits a piece of furniture, you find the point on the furniture that’s closest to the hinge, and check whether that point is closer than the door’s width.

import math

def door_hits(door_x, door_y, door_width, item):

“””Return True if a door swinging from (door_x, door_y) hits the item.”””

# Find the closest point on the item’s rectangle to the hinge

closest_x = max(item[“x”], min(door_x, item[“x”] + item[“w”]))

closest_y = max(item[“y”], min(door_y, item[“y”] + item[“d”]))

# Distance from the hinge to that point

dist = math.hypot(door_x – closest_x, door_y – closest_y)

return dist < door_width

# Door hinge in the corner of a 12 x 10 room, door is 3 feet wide

print(door_hits(12, 10, 3, {“x”: 9, “y”: 8, “w”: 2, “d”: 1})) # True

print(door_hits(12, 10, 3, {“x”: 0, “y”: 0, “w”: 2, “d”: 1})) # False

How it works:

  • max(low, min(value, high)) is a trick called clamping. It forces a value to stay between a low and a high limit. Here, it finds the point on the rectangle nearest to the hinge.
  • math.hypot(dx, dy) calculates the straight-line distance using the Pythagorean theorem: √(dx² + dy²).
  • This check treats the door’s swing as a full circle, which is slightly cautious. It may flag furniture behind the hinge that the door would never actually reach. A great challenge for advanced students is to check only the correct quarter of the circle.

Math connection: This is a wonderful example of school math, the Pythagorean theorem, solving a real problem. It’s exactly the kind of calculation used in architecture software and in game engines for circle-versus-rectangle collisions.

Python Project 8: Build a Tiny 3D Engine

What it teaches: 3D coordinates, perspective projection, division, drawing from data.

Virtual staging software must make 3D furniture look right in a flat photo. The core idea behind that is perspective projection: things farther away look smaller. Mathematically, you divide by distance.

If a point in 3D space has coordinates (x, y, z), where z is the distance from the viewer, its position on a flat screen is roughly:

screen_x = focal * x / z

screen_y = focal * y / z

focal controls how “zoomed in” the view is, like a camera lens.

Here’s a program that draws a 3D box (think of it as a simple piece of furniture) using turtle:

import turtle

FOCAL = 300

def project(x, y, z):

“””Convert a 3D point to a 2D screen point.”””

return FOCAL * x / z, FOCAL * y / z

# The 8 corners of a box, 2 units wide, sitting 4 to 6 units away

corners = [

(-1, -1, 4), (1, -1, 4), (1, 1, 4), (-1, 1, 4), # front face

(-1, -1, 6), (1, -1, 6), (1, 1, 6), (-1, 1, 6), # back face

]

# Which corners are joined by edges (by their position in the list)

edges = [

(0, 1), (1, 2), (2, 3), (3, 0), # front

(4, 5), (5, 6), (6, 7), (7, 4), # back

(0, 4), (1, 5), (2, 6), (3, 7), # connecting edges

]

t = turtle.Turtle()

t.speed(0)

t.hideturtle()

for start, end in edges:

x1, y1 = project(*corners[start])

x2, y2 = project(*corners[end])

t.penup()

t.goto(x1, y1)

t.pendown()

t.goto(x2, y2)

turtle.done()

The front face is drawn larger (it’s closer) and the back face smaller (it’s farther away), creating a convincing 3D box.

How it works:

  • The box is stored as data: a list of corner points and a list of edges. The drawing code doesn’t know it’s drawing a box. It just connects the points it’s given. Change the data, and the same code can draw a bed, a table, or a whole room. Separating data from logic is one of the most important ideas in programming.
  • project(*corners[start]) uses the * operator to unpack a tuple: (1, -1, 4) becomes three separate arguments.
  • Tuples like (0, 1) are similar to lists, but they can’t be changed after they’re created.

Challenges:

  1. Make the box rotate. Add an angle variable and use math.sin and math.cos to rotate each point around the vertical axis before projecting. Redraw in a loop with t.clear() between frames for animation.
  2. Move the box farther away by adding to every z value and watch it shrink.
  3. Model a bed: a long, low box with a taller box at one end for the headboard.
  4. Draw a room around the furniture: floor, back wall, and side walls as large boxes.

Big idea: Every 3D video game, animated movie, and architectural visualization relies on this same core math, just with far more points, lighting, and textures. Building even a tiny version demystifies how 3D graphics work.

Python Project 9: “Stage” a Room Photo With Code

What it teaches: working with images, pixels, transparency, scaling, perspective in photos.

This project comes closest to real virtual staging: it places furniture into an image of a room and scales it based on how far back it sits. It uses the Pillow library.

To keep the project self-contained, the code first draws a simple room image. Kids can later swap in a real photo.

from PIL import Image, ImageDraw

# — Step 1: Create a simple “empty room” picture —

room = Image.new(“RGB”, (800, 600), (235, 230, 220)) # side walls

draw = ImageDraw.Draw(room)

draw.polygon([(0, 600), (800, 600), (600, 380), (200, 380)],

fill=(170, 130, 90)) # floor

draw.rectangle([200, 100, 600, 380], fill=(245, 240, 232)) # back wall

draw.rectangle([330, 150, 470, 280], fill=(170, 210, 240),

outline=(90, 90, 90), width=4) # window

room.save(“empty_room.png”)

# — Step 2: Furniture gets smaller the farther back it is —

def scale_for_floor_y(y, horizon=380, bottom=600):

“””Return a size multiplier: 0.4 at the back wall, 1.0 at the bottom.”””

t = (y – horizon) / (bottom – horizon)

return 0.4 + 0.6 * t

def make_box(width, height, color):

“””Make a simple furniture shape with a transparent background.”””

box = Image.new(“RGBA”, (width, height), (0, 0, 0, 0))

d = ImageDraw.Draw(box)

d.rounded_rectangle([0, 0, width – 1, height – 1], radius=12, fill=color)

return box

def stage(room, item, floor_x, floor_y):

“””Place an item so its bottom-center sits at (floor_x, floor_y).”””

s = scale_for_floor_y(floor_y)

w, h = int(item.width * s), int(item.height * s)

small = item.resize((w, h))

room.paste(small, (floor_x – w // 2, floor_y – h), small)

# — Step 3: Stage the room —

staged = Image.open(“empty_room.png”).convert(“RGB”)

sofa = make_box(300, 120, (60, 90, 140, 255))

plant = make_box(60, 160, (40, 130, 70, 255))

stage(staged, sofa, 400, 470) # sofa in the middle of the room

stage(staged, plant, 640, 560) # plant near the front: drawn big

stage(staged, plant, 230, 400) # same plant near the back: drawn small

staged.save(“staged_room.png”)

print(“Saved staged_room.png”)

Open staged_room.png and you’ll see a simple room with a sofa and two plants. The two plants are the exact same image, but the one near the back wall is drawn much smaller than the one near the front. That’s perspective scaling, the same principle a real staging tool uses to make furniture look like it belongs in the photo.

How it works:

  • RGB colors use three numbers from 0 to 255 for red, green, and blue. (170, 210, 240) is a light sky blue.
  • RGBA adds a fourth number, alpha, for transparency. 0 is fully transparent and 255 is fully solid. The furniture images use a transparent background so only the furniture shape gets pasted.
  • In Pillow, (0, 0) is the top-left corner, and y increases as you go down. That’s why a larger floor_y means closer to the viewer.
  • scale_for_floor_y uses linear interpolation: it converts a position between the horizon (380) and the bottom (600) into a number between 0 and 1, then into a size between 40% and 100%.
  • item.resize() scales an image, and room.paste(small, position, small) pastes it using its own transparency as a mask.
  • // is integer division, which drops any decimal part. Pixel positions must be whole numbers.

Challenges:

  1. Use a real photo. Replace Step 1 with Image.open(“my_room.jpg”). You’ll need to find the right horizon value for your photo. Look for where the floor meets the back wall.
  2. Use real furniture images. Find furniture PNG images with transparent backgrounds and load them with Image.open(“sofa.png”).convert(“RGBA”).
  3. Add shadows. Before pasting each item, draw a dark, semi-transparent ellipse under it.
  4. Make it interactive. Combine this with Python’s tkinter library so users can click to place furniture.
  5. Generate a “before and after” image by pasting the empty and staged images side by side on a wider canvas.

Honesty discussion: Once kids have edited a room photo themselves, they understand how easy it is to change an image. That’s a natural starting point for talking about honesty in images. Real estate listings with virtually staged photos are generally expected to say so, and some places now require it. Ask: When is editing a photo fine? When is it misleading? Should edited images always be labeled?

Python Project 10: Rebuild the Planner With Classes

What it teaches: object-oriented programming, classes, objects, methods, self.

By now, the room code is spread across many separate functions and dictionaries. That works, but as programs grow, it gets harder to keep track of which function works with which data. Professional software, including real design and staging tools, usually organizes code with classes.

A class is a blueprint. An object is one thing built from that blueprint. A Furniture class describes what every piece of furniture has (a name, a position, a size) and what it can do (calculate its area, rotate, check for overlaps). Each bed, desk, or beanbag is an object made from that class.

Scratch has a similar idea: every sprite has its own position, costume, and scripts. In a way, sprites are objects. Classes let Python programmers build their own kinds of “sprites” from scratch.

class Furniture:

def __init__(self, name, x, y, w, d):

= name

self.x = x

self.y = y

self.w = w

self.d = d

def area(self):

return self.w * self.d

def rotate(self):

self.w, self.d = self.d, self.w

def overlaps(self, other):

return (self.x < other.x + other.w and

self.x + self.w > other.x and

self.y < other.y + other.d and

self.y + self.d > other.y)

def __repr__(self):

return f”{} at ({self.x}, {self.y}), {self.w} x {self.d} ft”

class Room:

def __init__(self, name, width, depth):

= name

self.width = width

self.depth = depth

self.items = []

def fits(self, item):

return (item.x >= 0 and item.y >= 0 and

item.x + item.w <= self.width and

item.y + item.d <= self.depth)

def add(self, item):

if not self.fits(item):

print(f”Can’t add {}: it sticks out of the room.”)

return False

for other in self.items:

if item.overlaps(other):

print(f”Can’t add {}: it overlaps {}.”)

return False

self.items.append(item)

print(f”Added {}.”)

return True

def free_space(self):

used = sum(item.area() for item in self.items)

return self.width * self.depth – used

def report(self):

print(f”— {} ({self.width} x {self.depth} ft) —“)

for item in self.items:

print(” “, item)

print(f” Free space: {self.free_space()} sq ft”)

bedroom = Room(“Bedroom”, 12, 10)

bedroom.add(Furniture(“Bed”, 0, 0, 4, 6.5))

bedroom.add(Furniture(“Desk”, 8, 0, 4, 2))

bedroom.add(Furniture(“Beanbag”, 3, 5, 3, 3))

bedroom.add(Furniture(“Wardrobe”, 10, 8, 3, 2))

()

Output:

Added Bed.

Added Desk.

Can’t add Beanbag: it overlaps Bed.

Can’t add Wardrobe: it sticks out of the room.

— Bedroom (12 x 10 ft) —

Bed at (0, 0), 4 x 6.5 ft

Desk at (8, 0), 4 x 2 ft

Free space: 86.0 sq ft

How it works:

  • class Furniture: defines the blueprint. Functions written inside a class are called methods.
  • __init__ is a special method that runs automatically whenever a new object is created. It’s often called the constructor. When Python sees Furniture(“Bed”, 0, 0, 4, 6.5), it creates a new object and passes those values into __init__.
  • self means “this particular object.” self.w is this piece of furniture’s width. When you call bed.area(), Python quietly passes bed in as self.
  • __repr__ is another special method. It controls how an object looks when printed. Without it, printing a Furniture object would show something unhelpful like <__main__.Furniture object at 0x7f…>.
  • The Room class contains a list of Furniture objects. Objects holding other objects is called composition, and it’s how large programs are built from small parts.
  • sum(item.area() for item in self.items) is a compact way to add up values. It does the same job as the accumulator loop from Project 2, in one line.

Why bother with classes? Compare overlaps(furniture[i], furniture[j]) from Project 3 with item.overlaps(other). The class version keeps the data and the code that works on it together in one place. The Room.add method also guarantees that every piece added gets checked. It’s impossible to sneak furniture into the room without going through the rules. Bundling data and rules together like this is called encapsulation, and it’s one of the main reasons classes are used in large programs.

Challenges:

  1. Add a price attribute to Furniture and a total_cost() method to Room.
  2. Add a remove(name) method to Room.
  3. Create a subclass, such as class Bed(Furniture):, with an extra size attribute (“twin,” “queen,” and so on). This introduces inheritance: a Bed automatically gets every method Furniture has.
  4. Give Furniture a draw() method that uses the turtle code from Project 1, so each object can draw itself.

Python Project 11: Save and Load Room Designs

What it teaches: files, JSON, reading and writing data, persistence.

Every program so far forgets everything when it stops running. Real design tools save your work. The simplest way to save structured data in Python is JSON (JavaScript Object Notation), a text format used all over the internet to store and send data. JSON looks almost exactly like Python dictionaries and lists, which makes it easy to learn.

Add this to the program from Project 10:

import json

def save_room(room, filename):

data = {

“name”: ,

“width”: room.width,

“depth”: room.depth,

“items”: [vars(item) for item in room.items],

}

with open(filename, “w”) as f:

json.dump(data, f, indent=2)

def load_room(filename):

with open(filename) as f:

data = json.load(f)

room = Room(data[“name”], data[“width”], data[“depth”])

for item in data[“items”]:

room.items.append(Furniture(**item))

return room

save_room(bedroom, “bedroom.json”)

copy = load_room(“bedroom.json”)

()

Run it, and a file called bedroom.json appears next to the program. Open it in any text editor:

{

“name”: “Bedroom”,

“width”: 12,

“depth”: 10,

“items”: [

{

“name”: “Bed”,

“x”: 0,

“y”: 0,

“w”: 4,

“d”: 6.5

},

…

]

}

The loaded copy prints exactly the same report as the original, proving the design survived the round trip from program to file and back again.

How it works:

  • open(filename, “w”) opens a file for writing. open(filename) with no second argument opens it for reading.
  • with … as f: makes sure the file is closed properly when you’re done, even if an error happens. It’s the recommended way to work with files in Python.
  • vars(item) turns an object’s attributes into a dictionary: {“name”: “Bed”, “x”: 0, …}. That’s needed because JSON can store dictionaries and lists, but not custom objects.
  • json.dump writes data to a file, and indent=2 makes it neatly formatted and readable.
  • Furniture(**item) uses ** to unpack a dictionary into named arguments. It’s the dictionary version of the * unpacking used in Project 8.

Why it matters: Saving and loading is called persistence. It’s how apps remember your settings, how games save progress, and how websites store your account. JSON in particular is used in countless web APIs, so learning it here pays off far beyond room design.

Challenges:

  1. Let the user type a filename with input().
  2. Save several rooms in one file as a list, creating a whole “house.”
  3. Handle a missing file gracefully using try and except FileNotFoundError.
  4. Share designs: swap JSON files with a friend and load each other’s rooms.

Part 5: How AI Fits In

Modern virtual staging tools increasingly use artificial intelligence. Kids who have built the projects above are well prepared to understand, in broad strokes, what AI adds.

What AI does in virtual staging

  • Segmentation. An AI model looks at every pixel of a photo and labels it: floor, wall, window, ceiling, door. This is how software knows where furniture can go.
  • Depth estimation. Another model estimates how far away each pixel is from the camera. That replaces the simple horizon and bottom numbers used in Project 9 with a detailed depth map.
  • Generation. Image-generating models can create entirely new furniture and decor that matches a chosen style, rather than pasting in existing images.

What AI doesn’t do

AI models learn patterns from huge numbers of example images. They’re very good at producing images that look right, but they don’t reason about space the way the collision checker in Project 3 does. That’s why AI-staged images sometimes contain errors that humans spot right away: a chair floating slightly above the floor, a table that’s too small, a lamp with no visible cord, or a bed blocking a door.

A great activity for kids is to collect examples of AI-generated room images and play “spot the mistake.” Then ask: How could you write code to catch that mistake automatically? Many of the answers lead right back to the projects in this article: collision checks, door checks, size checks.

Where to go next

For older students interested in AI, there are beginner-friendly ways to explore further:

  • Teachable-machine-style tools let kids train simple image classifiers in a web browser, for example teaching a model to tell bedroom photos from kitchen photos.
  • Python libraries for machine learning, such as scikit-learn for basics and, later, deep learning frameworks, open the door to real computer vision projects.
  • Pre-trained segmentation and depth models can be run in Python by advanced students to see how software “sees” a room.

The most important lesson isn’t any particular tool. It’s that AI is built by people, using the same programming fundamentals kids are already learning: data, loops, functions, math, and testing.

Part 6: Debugging Tips for Room Projects

Every programmer spends a lot of time fixing bugs. Room projects are especially good for practicing debugging because mistakes are usually visible.

1. Draw it out. If collision detection gives the wrong answer, draw the rectangles on graph paper with their coordinates. Most logic bugs become obvious on paper.

2. Print values. Add print() statements to see what your variables actually contain:

print(“Bed:”, bed[“x”], bed[“y”], bed[“w”], bed[“d”])

3. Test small cases. Before testing a room with 10 pieces of furniture, test 2 pieces you know overlap and 2 you know don’t.

4. Write simple tests. Python’s assert statement stops the program if something isn’t true:

a = {“x”: 0, “y”: 0, “w”: 2, “d”: 2}

b = {“x”: 1, “y”: 1, “w”: 2, “d”: 2}

c = {“x”: 5, “y”: 5, “w”: 1, “d”: 1}

assert overlaps(a, b) == True

assert overlaps(a, c) == False

print(“All tests passed!”)

Testing like this is a habit professional developers rely on every day.

5. Watch for common mistakes:

  • Indentation errors: code inside a loop or if isn’t indented consistently.
  • Off-by-one errors: range(4) gives 0, 1, 2, 3, not 1 through 4.
  • Mixed-up coordinates: using grid[x][y] instead of grid[y][x] (rows come first).
  • Unit confusion: mixing feet and pixels. Keep real measurements separate from screen measurements, as Project 1 does with SCALE.
  • Upside-down y: forgetting that some systems measure y from the top, and others from the bottom.

6. Explain your code out loud. Programmers call this rubber duck debugging: explaining your code line by line, even to a toy duck, often reveals the problem.

Part 7: Turning Projects Into Bigger Learning

Make it a team project

Room design projects work well for groups. One student can write the drawing code, another the collision checker, another the scoring rules. Then they combine their functions into one program. That mirrors how real software teams divide work, and it teaches the value of clear function names, docstrings, and shared conventions.

Connect to real-world careers

These projects touch on many real careers: software engineering, game development, computer graphics, architecture, interior design, real estate technology, robotics (robots also need to plan paths around obstacles), and AI research. Kids who enjoy one particular project, such as 3D projection or optimization, can be encouraged to explore the related field.

Build a portfolio

Encourage kids to save each version of their projects and write a short description of what they built and what they learned. A collection of finished projects, from a Scratch room designer to a Python staging tool, is a great record of growth and a source of pride.

Suggested learning path

Age (approx.)

Projects

Key concepts

7–9

Scratch 1–2

Motion, coordinates, sprites, events

9–11

Scratch 3–5

Sensing, conditionals, variables, broadcasts

10–12

Python 1–2

Typed code, functions, loops, lists, dictionaries

12–14

Python 3–5

Booleans, nested loops, 2D lists, validation

13+

Python 6–11

Randomness, optimization, geometry, 3D math, images, classes, files

Ages are only a guide. A motivated eight-year-old might be ready for Python, and a teenager new to coding might enjoy starting with Scratch.

Conclusion

Virtual staging looks like magic at first: an empty room becomes a furnished one with a few clicks. But underneath, it’s built from ideas any young coder can learn. A room is a rectangle. Furniture pieces are smaller rectangles with coordinates. Checking whether they fit is a few comparisons. Arranging them automatically is a loop with a scoring function. Making them look right in a photo is division by distance.

That’s the real lesson of these projects. Big, impressive software is built from small, understandable pieces: variables, loops, conditionals, functions, lists, and math. Kids who build a Scratch room designer today are practicing the same thinking that goes into professional design tools, video games, and AI systems.

Start with a sprite walking around the walls. Add furniture. Check for collisions. Then keep going. By the end, your young coder won’t just know how virtual staging works. They’ll have built a small version of it themselves.