Design: Mockups and Rapid Prototyping
On this page
Updated November 2, 2026 — Image models.
gpt-image-1, the model this course was originally written for, was discontinued on October 23, 2026.gpt-image-1.5,gpt-image-1-mini, andchatgpt-image-latestwill be retired on December 1, 2026. Examples now usegpt-image-2.5-sunburst, which offers the highest precision for editing;gpt-image-2.5-flareis faster for standard generation. Both models also supportxhighandmaxquality settings. GPT Image models always return images in base64: theresponse_formatparameter from older DALL·E models is no longer accepted and has been removed from the code. Source: Image generation (OpenAI).
Design: Mockups and Rapid Prototyping
GPT Image changes the design phase less through the quality of its output than through the low cost of discarding it. Exploring three visual directions for a homepage used to take a day in a design tool; now it takes a few minutes. This lets you explore six directions and abandon five without hesitation. This lesson shows you how to use that freedom without confusing exploration with production.
User Interface Mockups
A generated mockup serves to pick a direction, not to be sliced into components. Your prompt must therefore aim for visual credibility: realistic UI components, clear typography, professional spacing, a consistent color palette, and a statement of the expected fidelity level—in this case, “high-fidelity render in the style of Figma/Sketch.” Note how the function selects the resolution: 1024×1536 portrait for mobile, 1536×1024 landscape for desktop. Generating a mobile screen in a landscape frame would produce a mockup that looks nothing like a real device.
from openai import OpenAI
import base64
client = OpenAI()
def ui_mockup(description: str, platform: str, output: str):
"""Generate a user interface mockup."""
prompt = (
f"UI/UX mockup for {platform}: {description}, "
"modern and clean design, realistic UI components, "
"clear typography, professional spacing, "
"consistent color palette, "
"high-fidelity render in the style of Figma/Sketch"
)
response = client.images.generate(
model="gpt-image-2.5-sunburst",
prompt=prompt,
size="1024x1536" if platform == "mobile" else "1536x1024",
quality="high",
)
data = base64.b64decode(response.data[0].b64_json)
with open(output, "wb") as f:
f.write(data)
print(f"{platform} mockup: {output}")
ui_mockup(
"analytics dashboard with charts, KPI cards, and navigation sidebar",
"desktop",
"dashboard_mockup.png"
)
ui_mockup(
"fitness tracking app with home screen, statistics, and history",
"mobile",
"fitness_app_mockup.png"
)
Exploring Multiple Visual Directions
At the start of a project, the question isn’t “which is the right mockup?” but “which aesthetic families deserve to be shown to the client?” The explore_directions function answers exactly that need by keeping the concept constant—a homepage for an online learning platform—and varying only two axes: art direction and color palette. The three proposed paths aren’t subtle variations: corporate minimal in white and navy, modern colorful in purple and orange, and premium dark in black and electric blue target three different brand positions. It’s this range that makes the presentation useful.
from openai import OpenAI
import base64
client = OpenAI()
def explore_directions(concept: str, directions: list[dict], prefix: str):
"""Generate multiple visual directions for the same concept."""
for i, direction in enumerate(directions):
prompt = (
f"{concept}, "
f"art direction: {direction['style']}, "
f"palette: {direction['palette']}, "
"professional high-quality render"
)
response = client.images.generate(
model="gpt-image-2.5-sunburst",
prompt=prompt,
size="1024x1024",
quality="high",
)
path = f"{prefix}_direction_{i+1}.png"
data = base64.b64decode(response.data[0].b64_json)
with open(path, "wb") as f:
f.write(data)
print(f"Direction {i+1} ({direction['style'][:30]}) → {path}")
explore_directions(
"Homepage for an online learning platform",
[
{
"style": "corporate minimal, lots of white space",
"palette": "white, navy blue, light gray"
},
{
"style": "modern and colorful, flat design illustrations",
"palette": "purple, orange, white"
},
{
"style": "dark and premium, subtle gradients",
"palette": "black, electric blue, gold"
},
],
"landing_page"
)
Packaging Prototyping
Packaging is probably the domain where the gain is most dramatic, because a physical prototype is expensive and arrives late. The prompt here separates three inputs deliberately—the product, the style, and the required elements—then imposes a constant staging: a 3/4 view resting on a surface, photorealistic render with soft shadows. The two examples illustrate the range this structure handles without blinking: a kraft paper bag for organic tea with handwritten typography and a transparent window on one side, a white and gold cream jar with gold lettering on the other.
from openai import OpenAI
import base64
client = OpenAI()
def packaging_prototype(product: str, style: str, elements: str, output: str):
"""Generate a product packaging prototype."""
prompt = (
f"Packaging design for {product}, "
f"style: {style}, "
f"elements: {elements}, "
"3/4 view of packaging resting on a surface, "
"photorealistic render with soft shadows, "
"professional design ready for client presentation"
)
response = client.images.generate(
model="gpt-image-2.5-sunburst",
prompt=prompt,
size="1024x1024",
quality="high",
)
data = base64.b64decode(response.data[0].b64_json)
with open(output, "wb") as f:
f.write(data)
print(f"Packaging prototype: {output}")
packaging_prototype(
"premium organic tea in a kraft bag",
"natural and artisanal, handwritten typography",
"tea leaf logo, product name, organic label, transparent window",
"packaging_tea.png"
)
packaging_prototype(
"high-end moisturizing cream in a jar",
"minimalist luxury, white and gold",
"centered logo, brand name in gold lettering, 50ml capacity",
"packaging_cream.png"
)
Automated Moodboards
A moodboard conveys an intention before showing a solution. Rather than building a board by hand by aggregating references, you describe the theme and visual ingredients, then ask for an asymmetric grid composition in the style of Pinterest. The example of a modern coworking space shows the useful level of detail: you don’t just name the place, you list the bright interior with plants, Scandinavian furniture, wood and concrete textures, relaxed human presence, and a terracotta, sage green, and off-white palette. These five inputs give the result its coherence.
from openai import OpenAI
import base64
client = OpenAI()
def generate_moodboard(theme: str, elements: list[str], output: str):
"""Generate a visual moodboard for a given theme."""
elements_str = ", ".join(elements)
prompt = (
f"Professional moodboard for the theme \"{theme}\", "
f"including: {elements_str}, "
"asymmetric grid composition in the style of Pinterest, "
"varied photos and textures, consistent palette, "
"art direction style for agency presentation"
)
response = client.images.generate(
model="gpt-image-2.5-sunburst",
prompt=prompt,
size="1024x1024",
quality="high",
)
data = base64.b64decode(response.data[0].b64_json)
with open(output, "wb") as f:
f.write(data)
print(f"Moodboard: {output}")
generate_moodboard(
"Modern coworking space",
[
"bright interior with plants",
"Scandinavian design furniture",
"wood and concrete textures",
"people working in a relaxed manner",
"terracotta, sage green, off-white palette"
],
"moodboard_coworking.png"
)
Consistent Icon Sets
A single icon is easy; a consistent set is hard, because consistency relies on details invisible to a naive prompt. The icon_set function makes them explicit: it reinjects the theme and style for each icon, requires a transparent or white background, centered framing, uniform stroke weight, and square proportions, and reminds the model that the image belongs to a set. For the five icons of a B2B SaaS app—dashboard, users, settings, notifications, analytics—it’s this reminder that prevents you from getting five different graphic styles. Using a slug ensures clean file names, handling apostrophes and spaces.
from openai import OpenAI
import base64
client = OpenAI()
def icon_set(theme: str, icons: list[str], style: str, output_prefix: str):
"""Generate a consistent set of icons."""
for icon in icons:
prompt = (
f"Single icon representing \"{icon}\", "
f"theme: {theme}, "
f"style: {style}, "
"transparent or white background, centered, "
"consistent design within an icon set, "
"uniform stroke weight, square proportions"
)
response = client.images.generate(
model="gpt-image-2.5-sunburst",
prompt=prompt,
size="1024x1024",
quality="high",
)
slug = icon.lower().replace(" ", "_").replace("'", "")
path = f"{output_prefix}_{slug}.png"
data = base64.b64decode(response.data[0].b64_json)
with open(path, "wb") as f:
f.write(data)
print(f"Icon {icon} → {path}")
icon_set(
theme="B2B SaaS application",
icons=["dashboard", "users", "settings", "notifications", "analytics"],
style="line art, 2px stroke, navy blue, rounded corners",
output_prefix="icon"
)
Refining a Mockup Through Editing
Regenerating an entire mockup to correct a single area makes you lose everything that was already satisfactory elsewhere. The workflow below proceeds differently: it first generates a complete homepage for a project management app, then opens a window in the mask between 8% and 45% of the height—that is, below the header and above the feature blocks—to replay only the hero section. The header, navigation, and three blocks remain strictly identical between v1 and v2, making the comparison honest: you see the effect of your change, and nothing else.
from openai import OpenAI
from PIL import Image, ImageDraw
import base64
client = OpenAI()
# Step 1: Generate the initial mockup
response = client.images.generate(
model="gpt-image-2.5-sunburst",
prompt=(
"Homepage mockup for a project management application, "
"modern design, header with navigation, hero section with illustration, "
"3 feature blocks, white background"
),
size="1024x1536",
quality="high",
)
data = base64.b64decode(response.data[0].b64_json)
with open("mockup_v1.png", "wb") as f:
f.write(data)
print("Mockup v1 generated")
# Step 2: Modify the hero section via editing
source = Image.open("mockup_v1.png")
w, h = source.size
mask = Image.new("RGBA", (w, h), (0, 0, 0, 255))
draw = ImageDraw.Draw(mask)
# Hero area: upper part (below the header)
draw.rectangle([0, int(h * 0.08), w, int(h * 0.45)], fill=(0, 0, 0, 0))
mask.save("mask_hero.png")
response = client.images.edit(
model="gpt-image-2.5-sunburst",
image=open("mockup_v1.png", "rb"),
mask=open("mask_hero.png", "rb"),
prompt=(
"Hero section with a 3D isometric illustration of a kanban board, "
"title 'Manage Your Projects Simply', blue CTA button, subtle gradient background"
)
)
with open("mockup_v2.png", "wb") as f:
f.write(base64.b64decode(response.data[0].b64_json))
print("Mockup v2 with modified hero")
Where AI Prototyping Stops
You need to be clear about the status of what you produce here. Generated mockups are visual explorations, not production files: the text is well rendered but may contain minor errors, components are neither interactive nor exportable to Figma, and consistency across multiple screens in the same user flow isn’t guaranteed. A designer receiving these images as a final deliverable would be right to object.
Their value lies elsewhere, and it’s considerable: they serve to validate a direction before investing in final design. Choosing between three paths in an hour instead of three days, arriving at a client meeting with images rather than adjectives, eliminating a false good idea before it consumes a week of production—that’s what AI prototyping actually buys you.
To convince yourself, build your own project kickoff tool: a script that, from a brief, generates three visual directions for a homepage, an associated moodboard for each, and a comparative HTML catalog that lets you present them side by side.