{ "cells": [ { "cell_type": "markdown", "id": "a83efdb6", "metadata": {}, "source": [ "# Frontend with GPT-5\n", "\n", "GPT-5 is a large leap forward in frontend development. We have seen the model be excellent at developing full stack applications in one shot, making complex refactors look easy, and making surgical edits within large codebases. \n", "\n", "In this cookbook we will show some examples and some learnings of developing frontend applications with GPT-5 across multiple axes. \n", "\n", "## Intro\n", "There are some general principles we have seen be effective in developing strong frontend applications. We share some of these learnings in the [prompt guide](https://cookbook.openai.com/examples/gpt-5/gpt-5_prompting_guide). Below are some important pieces to consider when building frontend applications.\n", "\n", "Here are libraries and packages we recommend to start with steering the model:\n", "- Frameworks: Next.js (TypeScript), React, HTML\n", "- Styling / UI: Tailwind CSS, shadcn/ui, Radix Themes\n", "- Icons: Material Symbols, Heroicons, Lucide\n", "- Animation: Motion\n", "- Fonts: San Serif, Inter, Geist, Mona Sans, IBM Plex Sans, Manrope\n", "\n", "These packages are not an exhaustive list and we have seen many different application styles. \n", "\n", "Below you'll find an easy way to iterate over frontend abstractions on the API. We’re excited to see how users can unlock creativity with GPT-5.\n" ] }, { "cell_type": "markdown", "id": "1c2168a3", "metadata": {}, "source": [ "## Interactive Example\n", "\n", "Let's dive into an example of creating frontends from scratch. First let's create some help functions to see the generated websites from GPT-5." ] }, { "cell_type": "code", "execution_count": null, "id": "194e6566", "metadata": {}, "outputs": [], "source": [ "import os\n", "import re\n", "import webbrowser\n", "from pathlib import Path\n", "\n", "import openai\n", "from openai.types.responses import ResponseInputParam\n", "\n", "client = openai.OpenAI()\n", "\n", "\n", "def get_response_output_text(input: str | ResponseInputParam):\n", " \n", " response = client.responses.create(\n", " model=\"gpt-5\",\n", " input=input,\n", " )\n", " return response.output_text\n", "\n", "\n", "def extract_html_from_text(text: str):\n", " \"\"\"Extract an HTML code block from text; fallback to first code block, else full text.\"\"\"\n", " html_block = re.search(r\"```html\\s*(.*?)\\s*```\", text, re.DOTALL | re.IGNORECASE)\n", " if html_block:\n", " result = html_block.group(1)\n", " return result\n", " any_block = re.search(r\"```\\s*(.*?)\\s*```\", text, re.DOTALL)\n", " if any_block:\n", " result = any_block.group(1)\n", " return result\n", " return text\n", "\n", "\n", "def save_html(html: str, filename: str) -> Path:\n", " \"\"\"Save HTML to outputs/ directory and return the path.\"\"\"\n", " try:\n", " base_dir = Path(__file__).parent\n", " except NameError:\n", " base_dir = Path.cwd()\n", "\n", " folder = \"outputs\"\n", " outputs_dir = base_dir / folder\n", " outputs_dir.mkdir(parents=True, exist_ok=True)\n", "\n", " output_path = outputs_dir / filename\n", " output_path.write_text(html, encoding=\"utf-8\")\n", " return output_path\n", "\n", "def open_in_browser(path: Path) -> None:\n", " \"\"\"Open a file in the default browser (macOS compatible).\"\"\"\n", " try:\n", " webbrowser.open(path.as_uri())\n", " except Exception:\n", " os.system(f'open \"{path}\"')\n", "\n" ] }, { "cell_type": "markdown", "id": "6aee99e6", "metadata": {}, "source": [ "Now, let's combine the above into one helper function." ] }, { "cell_type": "code", "execution_count": 7, "id": "8bb59cc7", "metadata": {}, "outputs": [], "source": [ "def make_website_and_open_in_browser(*, website_input: str | ResponseInputParam, filename: str = \"website.html\"):\n", " response_text = get_response_output_text(website_input)\n", " html = extract_html_from_text(response_text)\n", " output_path = save_html(html, filename)\n", " open_in_browser(output_path)" ] }, { "cell_type": "markdown", "id": "17e785bc", "metadata": {}, "source": [ "We'll start with a simple example: one-shot building a retro gaming store with the right theme" ] }, { "cell_type": "code", "execution_count": 8, "id": "a597c44a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "get_response: finished\n", "extract_html_from_text: finished (raw text)\n", "save_html: finished -> outputs/retro_dark.html\n", "open_in_browser: finished\n" ] } ], "source": [ "make_website_and_open_in_browser(\n", " website_input=\"Make me landing page for a retro-games store. Retro-arcade noir some might say\",\n", " filename=\"retro_dark.html\",\n", ")" ] }, { "cell_type": "markdown", "id": "65153df1", "metadata": {}, "source": [ "Not bad for a one line, one shot prompt!\n", "\n", "\n", "\n", "\n", "Now let's steer it to be lighter, and a bit softer" ] }, { "cell_type": "code", "execution_count": 9, "id": "84228036", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "get_response: finished\n", "extract_html_from_text: finished (raw text)\n", "save_html: finished -> outputs/retro_light.html\n", "open_in_browser: finished\n" ] } ], "source": [ "make_website_and_open_in_browser(\n", " website_input=\"Make me landing page for a retro-games store. Make it light, more pastel coloured & flowery (think Mario, not cyberpunk)\", \n", " filename=\"retro_light.html\"\n", ")" ] }, { "cell_type": "markdown", "id": "d2cc44f0", "metadata": {}, "source": [ "As you can see GPT-5 is incredibly steerable - with just a one line you can change entire applications effortlessly\n", "\n", "" ] }, { "cell_type": "markdown", "id": "6ffde671", "metadata": {}, "source": [ "But what if you have existing website designs that you want to make additions to? For example, we already have this dashboard.\n", "\n", "\n", "\n", "Since GPT-5 is natively multimodal and accepts both image and text input, when you are generating frontend applications we can take advantage of image input to improve model performance. " ] }, { "cell_type": "code", "execution_count": 10, "id": "24aa52f0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "get_response: finished\n", "extract_html_from_text: finished (raw text)\n", "save_html: finished -> outputs/login_page.html\n", "open_in_browser: finished\n" ] } ], "source": [ "import base64\n", "from openai.types.responses import ResponseInputImageParam\n", "\n", "# Function to encode the image\n", "def encode_image(image_path: str):\n", " with open(image_path, \"rb\") as image_file:\n", " return base64.b64encode(image_file.read()).decode(\"utf-8\")\n", "\n", "image_path=\"../../images/input_image.png\"\n", "encoded_image = encode_image(image_path)\n", "input_image: ResponseInputImageParam = {\"type\": \"input_image\", \"image_url\": f\"data:image/png;base64,{encoded_image}\", \"detail\": \"auto\"}\n", "input: ResponseInputParam = [\n", " {\n", " \"role\": \"user\",\n", " \"content\": [\n", " {\"type\": \"input_text\", \"text\": \"Can you make a login page for this website that maintains the same theme\"},\n", " input_image,\n", " ],\n", " }\n", "]\n", "\n", "make_website_and_open_in_browser(\n", " website_input=input, \n", " filename=\"login_page.html\"\n", ")" ] }, { "cell_type": "markdown", "id": "93dcda0b", "metadata": {}, "source": [ "As you can see, GPT-5 does an incredible job of matching the existing style & vibe of the app.\n", "\n", "" ] }, { "cell_type": "markdown", "id": "352f57b9", "metadata": {}, "source": [ "So far this has been pretty static - let's try a more interactive task" ] }, { "cell_type": "code", "execution_count": 11, "id": "a1f80a93", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "get_response: finished\n", "extract_html_from_text: finished (raw text)\n", "save_html: finished -> outputs/snake_game.html\n", "open_in_browser: finished\n" ] } ], "source": [ "make_website_and_open_in_browser(\n", " website_input=\"Make me a snake game. It should be futuristic, neon, cyberpunk style. Make sure the typography is suitably cool.\", \n", " filename=\"snake_game.html\"\n", ")" ] }, { "cell_type": "markdown", "id": "fc11b7b2", "metadata": {}, "source": [ "We've got a theme consistent snake game: matching colours, typography, and even sound\n", "\n", "" ] }, { "cell_type": "markdown", "id": "6274e5f9", "metadata": {}, "source": [ "We hope this has given some ideas of how powerful GPT-5 is at frontend. From a single underspecified prompt and API call, we get production grade outputs. \n", "\n", "Now it's your turn - we can't wait to see what you'll build" ] }, { "cell_type": "code", "execution_count": 12, "id": "935abf26", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "get_response: finished\n", "extract_html_from_text: finished (raw text)\n", "save_html: finished -> outputs/your_website.html\n", "open_in_browser: finished\n" ] } ], "source": [ "your_prompt = \"[edit this! what website would you like to build?]\"\n", "\n", "make_website_and_open_in_browser(\n", " website_input=your_prompt, \n", " filename=\"your_website.html\"\n", ")" ] } ], "metadata": { "kernelspec": { "display_name": "openai", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.9" } }, "nbformat": 4, "nbformat_minor": 5 }