Skip to content

feat: add AI-generated project icons - #69

Open
saphid wants to merge 2 commits into
pr-11845-monogramsfrom
agent/web-ai-generated-icons
Open

saphid wants to merge 2 commits into
pr-11845-monogramsfrom
agent/web-ai-generated-icons

Conversation

@saphid

@saphid saphid commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

What Changed

The project icon picker in Settings → Project gets a Generate tab. Projects on a provider that supports image generation (Codex app-server) can describe the look they want in a small "Vibe" field, optionally tweak the auto-populated prompt under "Edit prompt", and press Generate. One Codex image-generation turn produces a single image with three icon variants; the server slices it into individual tiles, drops blank or duplicate variants, crops each kept tile to its content and centers it on a transparent square, and falls back to a single cropped icon when the model draws fewer than three distinct variants. Tiles preview in the dialog before saving; saving one stores the path on the project and renders through the existing project-favicon asset route, so the icon shows up in web and desktop alike.

Generated icons live in the server state directory (<state>/generated-icons/), not the workspace, so nothing is written to the user's project. Providers without image-generation capability (Claude, Cursor, Grok, OpenCode) see a plain "this provider doesn't support image generation" notice instead of a broken form — capability comes from a new supportsImageGeneration flag on the server provider snapshot, so gating is server-driven.

Scope: this stacks on pingdotgg#11845 and touches the web icon picker, the server (new generateProjectIcons orchestration RPC, Codex adapter, PNG slicing pipeline in apps/server/src/imageGeneration/), and the orchestration contracts. It does not touch mobile, other providers' adapters, or the checkpoint/reactor layers.

Why

pingdotgg#11845 made project icons customizable, but the palette is still a fixed set — a project's identity depends on picking whichever preset is closest. AI generation is the natural extension: the user already has an image-generation-capable provider running in the app. Keeping the model interaction server-side (one ephemeral Codex app-server thread per generation, mechanical "three variants in one image" prompt framing, defensive slicing) means the client stays dumb and the failure modes (blank variants, duplicates, symbol collages, multi-image turns) are handled in one tested place rather than per client.

Verification

  • Typechecks (tsc --noEmit): @t3tools/contracts, @t3tools/client-runtime, t3 (server), web — all pass (suggestion-level diagnostics only, same as base).
  • vp test run apps/server/src/imageGeneration apps/server/src/server.test.ts: 210 passed, 0 failed — includes 24 pngGrid tests covering horizontal/vertical/stacked layouts, transparent and opaque backgrounds, gap-following cuts, 2-variant cuts, blank-tile/fragment handling, duplicate rejection, single-icon fallback, sparse-artwork density crops, stacked-column reframing, and full-bleed single-icon detection.
  • Hardening pass after a 4-round live bake across 60+ real generations (see head bdd4ea4b7b): fixed corner background sampling on non-square canvases, added density crops for sparse floating artwork, stacked-column reframing, and full-bleed single-icon detection; the prompt now encodes the actual render context (16px rounded-square slot on a dark sidebar).
  • vp test run apps/web/src/components/settings/ProjectIconPickerDialog.test.tsx: 1 passed.
  • Live end-to-end in a paired browser against a clean dev server: real Codex generation, tile previews render before saving (asset route returns 200), Save persists the absolute path to projection_projects.favicon_path, and the settings row renders the saved icon with the "Custom image" label.
  • Known, unrelated: 3 CodexDriver installer-path test failures reproduce on the stacked base commit (35a4aff472) as well — not introduced here.

UI Changes

After — Generate tab with a freshly generated tile previewing before save:

Generate tab with a generated icon tile in the picker dialog

After — saved generated icon rendered in the settings row:

Saved generated icon rendered in project settings

The before state is the stacked base (pingdotgg#11845 head): the picker offers Icons/Emoji/Monogram only, with no Generate tab. No base capture is attached.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (after-only; the before state is the absence of the Generate tab in the stacked base)

Implementation used GLM (enablers/large) in T3 Code (OpenCode harness).

Projects could only pick icons from a fixed palette, so a project's
identity in the sidebar depended on whoever remembered to pick something
close. This adds a Generate tab to the icon picker: providers that
support image generation (Codex app-server) produce one image with three
icon variants in a single turn; the server slices it into individual
tiles, drops blank or duplicate variants, and falls back to a single
cropped icon when the model draws fewer than three. Icons live in the
server state dir, so they render in every client through the existing
project-favicon asset route. Providers without image generation see a
plain notice instead of a broken form.

Implementation used GLM (enablers/large) in T3 Code (OpenCode harness).
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Sep 18, 2026
Live testing across dozens of generations exposed four slicer and prompt
defects: corner background sampling read mid-image pixels on non-square
canvases, sparse floating artwork escaped the content crop, icons stacked
in a single canvas column defeated gap detection, and uniform or
full-bleed single-icon canvases were cut into transparent strips. The
prompt now bakes in the constraints of the actual render context (16px
rounded-square slot on a dark sidebar): full-bleed solid cards, blocky
silhouettes, saturated mid-bright backgrounds, no busy scenes.

Implementation used GLM (enablers/large) in T3 Code (OpenCode harness).
@github-actions

Copy link
Copy Markdown

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for bdd4ea4.

This comment will update automatically after the next completed run.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant