Beautiful headshots

Beautiful headshots

Generate stunning portraits in different styles.

Created with prompt

[user]: Build a React Native (Expo + TypeScript) iOS-first app that is a “portrait style generator + gallery”. The UI must be ultra-minimal, soft-white, and rounded in the exact aesthetic described below. Include small “sprinkles” of React Native, Skia, and JSON so the implementation is unambiguous. AI RULES (NON-NEGOTIABLE) - All intelligence / thinking / prompt-writing / suggestion generation = Gemini 3 Pro. - All image generation (final portraits + style thumbnails + demo images) = Nano Banana Pro. - Treat Gemini 3 Pro as the “prompt composer” and Nano Banana Pro as the “renderer”. GLOBAL LAYOUT & VISUAL SYSTEM - App background: very light warm gray (#F3F3F3-ish). - The entire app content lives inside a single “rounded device surface” panel: - Large corner radius ~44–56. - Panel background: off-white (#FAFAFA to #FFFFFF). - Subtle shadow: 0 18 50 rgba(0,0,0,0.10) with soft spread. - Internal padding: 18–22 horizontal, 18–22 top. - Typography: SF Pro (iOS default). Use bold for headlines, medium for labels, regular for body. - Icon style: simple, rounded-line icons (SF Symbols vibe). - Gallery images ALWAYS 4:5 portrait aspect ratio everywhere in the app (including placeholders). - Cards: rounded corners ~26–30, soft shadow, no harsh borders. - Buttons: big black pills with white icons + white text, subtle top highlight, shadow underneath. NAVIGATION MODEL - Single tabless flow (keep it clean): 1) Home screen (gallery grid or empty state). 2) Editor screen (after upload/take photo). 3) “Create new style” as a modal or bottom sheet overlay from the editor. - Use React Navigation (native stack). The “Create new style” screen should be presented modally (iOS sheet feel). DATA MODELS (JSON FOR ACCURACY) Persist everything in AsyncStorage/SQLite (either is fine), but the shapes must match: 1) Style model: { "id": "style_linkedin", "name": "LinkedIn", "prompt": "string (human-readable style instruction)", "thumbnail": { "uri": "local or remote image uri", "generationPrompt": "string prompt for Nano Banana Pro to create the thumbnail" }, "createdAt": "ISO date", "isBuiltIn": true } 2) Gallery item model: { "id": "uuid", "createdAt": "ISO date", "sourcePhotoUri": "uri", "generatedUri": "uri", "styleId": "style_linkedin", "styleNameAtTime": "LinkedIn", "finalPromptUsed": "string", "liked": true } 3) Generation job model (in-memory + persisted for crash recovery): { "jobId": "uuid", "status": "idle | composing_prompt | generating_image | success | error", "progressLabel": "Generating photo", "styleId": "style_linkedin", "sourcePhotoUri": "uri", "finalPrompt": "string", "resultUri": "uri | null", "error": "string | null", "startedAt": "ISO date" } DEFAULT BUILT-IN STYLES (MUST SHIP WITH THESE) You must ship with these 4 built-in styles + a “New style” tile at the end: A) LinkedIn (built-in) - Name: “LinkedIn” - Purpose: professional headshot refinement - Nano Banana Pro FINAL IMAGE prompt (this is the style prompt; Gemini 3 Pro may add constraints later): “Create a realistic, professional corporate headshot from the provided portrait photo. Keep the person’s identity and facial structure intact. Clean neutral background (soft gray-beige), even softbox lighting, subtle skin retouch (natural texture preserved), sharp eyes, gentle contrast, no heavy color grading, no dramatic shadows. Clothing stays realistic and conservative. Photorealistic, DSLR look, 85mm lens feel, shallow depth of field. Output 4:5 portrait.” - Thumbnail generation prompt (Nano Banana Pro) for the style icon: “Abstract professional gradient thumbnail: smooth wavy bands of warm sand + muted orange fading into cool slate-blue, soft blur, modern corporate feel, no text, no logos, minimal, 1:1 square, rounded-corner-friendly composition.” B) Fashion (built-in) - Name: “Fashion” - FINAL IMAGE prompt: “Transform the portrait into an editorial fashion photo. Keep the person recognizable. Golden-hour warmth, stylish magazine color grade, slightly lifted blacks, crisp micro-contrast, subtle film grain, elegant background blur, refined complexion retouch, tasteful highlight sheen, premium studio/editorial look. Output 4:5 portrait.” - Thumbnail prompt: “Minimal fashion thumbnail: macro photograph of a single yellow flower with soft petals against a pale sky-blue background, dreamy bokeh, clean editorial feel, no text, 1:1 square.” C) Cartoon (built-in) - Name: “Cartoon” - FINAL IMAGE prompt: “Create a high-quality stylized cartoon portrait based on the person’s photo. Keep identity cues (face shape, hairline, eyes) but stylize: smooth 3D animated look, slightly exaggerated eyes, clean shapes, vibrant but tasteful colors, soft rim light, playful background with subtle neon accents, no text, no watermark. Output 4:5 portrait.” - Thumbnail prompt: “Abstract cartoon thumbnail: silky flowing 3D waves in blue-to-purple gradient with soft highlights, playful but clean, no characters, no text, 1:1 square.” D) Glamour (built-in) - Name: “Glamour” - FINAL IMAGE prompt: “Convert the portrait into a glamour beauty shot. Keep the person recognizable. Cinematic lighting with soft specular highlights, subtle beauty retouch, richer color saturation, clean background, polished look, elegant contrast, premium magazine beauty vibe. Output 4:5 portrait.” - Thumbnail prompt: “Abstract glamour thumbnail: glitchy silhouette-like vertical smear in black with electric cyan + hot red chromatic edges on a pale gray background, modern digital glamour vibe, no text, 1:1 square.” E) New style tile (NOT a style yet) - A square thumbnail tile with light gray background and a centered ‘+’ icon. - Label underneath: “New style”. - Tapping opens the “Create new style” modal/sheet. HOME SCREEN (EMPTY STATE) — EXACT BEHAVIOR & LAYOUT Condition: If galleryItems.length === 0, show empty state. 1) Background grid of empty “slots” - Two-column grid covering most of the screen behind the foreground content. - Each slot is a rounded rectangle, 4:5 portrait aspect ratio, extremely subtle border. - Inside each slot, centered “+” icon (thin, light gray). - The entire grid fades out toward the bottom: - Top slots: clearly visible outlines. - Mid slots: lighter. - Bottom: nearly invisible. Implementation hint (Skia mask): - Draw the placeholder grid either as Views OR via Skia. - Apply a Skia alpha mask gradient that goes from alpha=1 at ~top 30% to alpha=0 at bottom. Example sprinkle: <Canvas style={StyleSheet.absoluteFill}> <Mask mask={<Rect x={0} y={0} width={W} height={H}> <LinearGradient start={vec(0,0)} end={vec(0,H)} colors={['rgba(0,0,0,1)','rgba(0,0,0,0.9)','rgba(0,0,0,0)']} positions={[0,0.55,1]} /> </Rect>}> {/* draw rounded rect slots + plus icons */} </Mask> </Canvas> 2) Center “stacked sample cards” (must be generated images) - Two floating image cards centered over the grid, around mid-screen. - Each card is 4:5 portrait ratio, rounded corners ~26–30, strong soft shadow. - Cards overlap: left card slightly behind and offset left; right card on top offset right. - Right/top card is rotated slightly clockwise (~6–10 degrees). Left card rotated slightly counterclockwise (~-4 to -6). - These two images must be generated by Nano Banana Pro at app install time (or bundled). Sample generation prompts (Nano Banana Pro), 4:5: 1) “Moody cinematic studio portrait of a middle-aged man with curly hair and moustache, wearing a textured brown blazer, dark painterly background, soft Rembrandt lighting, ultra-realistic, 85mm lens look, shallow depth of field, no text.” 2) “Handmade wool-felt puppet portrait of an elderly woman with oversized round blue glasses, warm blush cheeks, fuzzy fiber texture visible, pastel teal background, whimsical but detailed, shallow depth of field, no text.” 3) Empty-state text block (centered) - Headline, bold, black, large: “You don’t have any photos yet” (force a line break so it’s 2 lines, with the break after “have”) - Subtext, smaller, medium gray: “Start by taking a photo or uploading from your photo library.” (two lines, centered) 4) Bottom action buttons (fixed) - Two big black pill buttons side-by-side, anchored near bottom inside the rounded panel. - Left button: icon (photo/image outline) + label “Upload”. - Right button: icon (camera outline) + label “Take photo”. - Both have identical height (~64–72), big radius (999), soft shadow. - Tapping either opens image picker or camera, then navigates to Editor. HOME SCREEN (GALLERY STATE) — EXACT BEHAVIOR & LAYOUT Condition: If galleryItems.length > 0 - Display a 2-column grid of saved generated portraits. - Every cell is 4:5 portrait, rounded corners, soft shadow, no visible border. - Tight but breathable spacing: - Outer padding ~20 - Column gap ~16–18 - Row gap ~16–18 - Scrollable behind the bottom buttons; bottom buttons remain fixed and float above the grid. - Bottom buttons are the same two black pills (“Upload”, “Take photo”) and remain visible as a floating bar. EDITOR SCREEN — AFTER USER SELECTS/TAKES A PHOTO This screen is a single layout with 3 states: idle (just photo), loading, finished. Shared structure: - Top: huge preview card occupying most of the screen width. - Preview card is 4:5 portrait and centered with generous margins. - Card has deep rounded corners and subtle shadow. - The preview area is swipeable horizontally when there is a generated result: Page 1: the original uploaded photo Page 2: the generated output - A page indicator (two dots) sits centered just below the preview card. Bottom of editor: - A horizontal list of style thumbnails (square tiles with rounded corners) with labels beneath. - Thumbnails are 1:1 squares ~76–92 px wide with radius ~18–22. - Selected style: - Thick dark border around the thumbnail. - Label text darker (near-black). - Unselected styles: - No border. - Label text is lighter gray. - The list scrolls horizontally and ends with the “New style” plus tile. EDITOR: STATE 1 — PHOTO LOADED (NO GENERATION YET) - Preview shows the user’s photo. - Top-left overlay pill button on the preview: “Retake photo” - Pill background: translucent dark gray/black (~rgba(0,0,0,0.45)) - White icon on left (refresh/retake) - White text “Retake photo” - Slight blur behind pill (optional) to feel native. - Selecting a style immediately triggers generation (see AI pipeline below). EDITOR: STATE 2 — LOADING (PERSISTENT UNTIL DONE) - Preview becomes blurred + dimmed. - Center overlay on preview: - iOS spinner (activity indicator) - Label underneath: “Generating photo” (large, light gray/white) - Style strip remains visible but appears disabled: - Non-selected labels dim further - Prevent taps during generation Implementation hint (Skia blur): - Render the preview image, then overlay a Skia blur filter and a translucent dark layer. Example sprinkle: <Canvas> <Image image={photo} fit="cover" /> <Group> <BackdropBlur blur={18} /> <Rect color="rgba(0,0,0,0.35)" /> </Group> </Canvas> - The loading overlay MUST stay until Nano Banana Pro returns a resultUri. EDITOR: STATE 3 — FINISHED (GENERATION COMPLETE) - Preview shows the generated portrait (page 2) with ability to swipe back to original. - Top-right overlay pill button: “Generate new” - Icon: refresh/rotate arrows - Same translucent dark pill styling - Top-left small circular button with trash icon: - Circle background: translucent dark - Trash icon tinted soft pink - Deletes the generated result (reverts to just original photo state) - Bottom-center overlay action buttons inside the preview (three circular icon buttons): 1) Save in app gallery (adds to Home grid) - Icon resembles “save to app” / “disk” / “bookmark-like” 2) Save in phone gallery (write to MediaLibrary) - Download icon (down arrow to tray) 3) Share - Share arrow icon - Each button is a circular translucent dark chip with white icon, soft shadow. - Spacing between circles ~14–18. - These float just above the bottom edge of the preview card. AI PIPELINE (GEMINI 3 PRO + NANO BANANA PRO) When a style is tapped: 1) Create job.status = “composing_prompt” 2) Call Gemini 3 Pro to produce the FINAL prompt string used for Nano Banana Pro. Gemini must: - Start from the selected style.prompt - Add universal constraints: - “Output 4:5 portrait.” - “No text, no watermark, no logos.” - “Keep subject identity consistent with the input photo.” - “Avoid changing age/ethnicity/gender presentation unless explicitly asked.” - Return JSON: { "finalPrompt": "string", "negativePrompt": "string optional" } 3) Set job.status = “generating_image” 4) Call Nano Banana Pro with: - input image: sourcePhotoUri - prompt: finalPrompt - aspect ratio: 4:5 - high face/identity consistency - output: 1 image (uri) 5) Set job.status = “success”, store resultUri, store finalPromptUsed. On any failure: - job.status = “error” - Show a single-line error toast and return to State 1. “CREATE NEW STYLE” MODAL / BOTTOM SHEET Opened when user taps the “New style” tile in the style strip. Presentation: - iOS sheet feel with rounded corners at top, visible drag handle centered near top. - Background: white. - Title top-left: “Create new style” (large, bold). - Top-right: black pill button labeled “Create”. Main input: - A large multiline text input occupying most of the sheet height. - Big font (headline/body blend), black text. - Cursor and typing feel iOS-native. - Default placeholder: empty, but if user tapped a suggestion pill, it populates instantly. Suggestion pills row (above the keyboard) - Horizontal list of pill-shaped suggestion cards. - Each pill: - light gray background - left side: tiny square thumbnail with rounded corners - right side: two-line label like “Suggestion prompt 1” - Tapping a suggestion pill: - autopopulates the big text input with that suggestion’s prompt - optional: haptic tap - These suggestions are generated by Gemini 3 Pro when the sheet opens. Gemini 3 Pro output for suggestions (REQUIRED FORMAT) When the sheet opens, call Gemini 3 Pro: Return JSON array of 6–10 suggestions: [ { "name": "Suggestion prompt 1", "prompt": "A fully detailed style prompt the user can reuse", "thumbnailPrompt": "A 1:1 thumbnail prompt for Nano Banana Pro representing the style visually" } ] Then: - For each suggestion, generate the thumbnail image using Nano Banana Pro + thumbnailPrompt. - Render those thumbnails in the suggestion pills. Creating the style: - When user taps “Create”: - Validate prompt length (min 12 chars). - Gemini 3 Pro generates: - a concise style name (1–2 words) - a thumbnailPrompt (1:1) matching the style’s vibe - Nano Banana Pro generates the thumbnail image. - Append new style to the style strip BEFORE the “New style” tile. - Persist it. SAVE / SHARE RULES - “Save in app gallery”: - creates a GalleryItem with generatedUri and sourcePhotoUri - sets liked=true - returns user to Home where the new image appears at the top-left of the grid (newest-first). - “Save in phone gallery”: - request permission (iOS) - save to Photos - show subtle confirmation toast - “Share”: - opens system share sheet with the generated image. REACT NATIVE + SKIA IMPLEMENTATION SPRINKLES (DO NOT OVERDO, JUST ENOUGH) - Use react-native-skia for: 1) Home empty-state background grid fade (gradient mask). 2) Editor loading blur overlay. - Use FlatList for: - Home gallery grid (numColumns=2). - Style strip (horizontal). - Use pagingEnabled ScrollView or react-native-pager-view for the preview swipe. - Use a small state store (Zustand) holding: - styles[] - galleryItems[] - currentJob - selectedStyleId - sourcePhotoUri - Keep animation minimal (no bouncy motion). Only subtle fades between states. FINAL REQUIREMENTS CHECKLIST - Home empty state: faded placeholder 4:5 slots + stacked generated demo cards + centered text + bottom Upload/Take photo buttons. - Home with items: 2-column 4:5 grid + same bottom buttons floating. - Editor: big preview card + style strip. - Loading: blurred/dim preview + spinner + “Generating photo” until done. - Finished: “Generate new”, trash button, 3 action buttons (save app, save phone, share), page dots. - Style strip ends with “New style” tile (+). - Create new style sheet: big title, Create button, large text input, suggestion pills populated by Gemini 3 Pro; thumbnails generated by Nano Banana Pro. [assistant]: Creating your "Portrait Style Generator + Gallery" app plan with the ultra-minimal aesthetic and detailed functionality described. Hang tight!