Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions domain-skills/gemini/nano-banana-images.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# gemini.google.com — Nano Banana image generation/editing

## Model picker
- Composer dropdown offers Flash-Lite / Flash / Pro tiers. Pick **Pro** before an image task to route to Nano Banana Pro (higher fidelity, runs a "Verifying Label Accuracy" thinking stage on product photos).
- There is no explicit "Nano Banana" entry; attaching an image + asking for an edit invokes it.

## CSP traps (field-tested)
- Page CSP blocks `fetch`/XHR **and** `img-src` to `http://localhost:*`. You cannot inject local files by fetching from a local server inside page JS.
- There is **no persistent `input[type=file]`** in the DOM. The "+" menu's "Upload files" item opens a native picker — dead end for automation.
- Synthetic `DragEvent` with a `DataTransfer` file on `rich-textarea` does not attach (and you can't build the File without bytes anyway, per CSP).

## Attaching a local image (works)
1. Put the image on the OS clipboard (macOS: `osascript -e 'set the clipboard to (read (POSIX file "/path/img.jpg") as JPEG picture)'`).
2. Make the Gemini tab frontmost and click into the composer.
3. Trigger `await navigator.clipboard.read()` in page context via CDP. First call may hang ~45s on a permission grant; after it resolves the image appears as a composer attachment.

@cubic-dev-ai cubic-dev-ai Bot Jul 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: It's unclear how calling clipboard.read() by itself causes the image to land in the composer — normally you'd still need to dispatch the read data into the focused element (e.g. via a synthetic paste event). If there's an implicit step, spelling it out would make this recipe reproducible.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At domain-skills/gemini/nano-banana-images.md, line 15:

<comment>It's unclear how calling `clipboard.read()` by itself causes the image to land in the composer — normally you'd still need to dispatch the read data into the focused element (e.g. via a synthetic `paste` event). If there's an implicit step, spelling it out would make this recipe reproducible.</comment>

<file context>
@@ -0,0 +1,29 @@
+## Attaching a local image (works)
+1. Put the image on the OS clipboard (macOS: `osascript -e 'set the clipboard to (read (POSIX file "/path/img.jpg") as JPEG picture)'`).
+2. Make the Gemini tab frontmost and click into the composer.
+3. Trigger `await navigator.clipboard.read()` in page context via CDP. First call may hang ~45s on a permission grant; after it resolves the image appears as a composer attachment.
+
+## Extracting generated images (works, no download dialog)
</file context>
Fix with cubic


## Extracting generated images (works, no download dialog)
- Generated images are `blob:` URLs, typically 825x1024. `curl` can't fetch them.
- In page JS: draw the `<img>` to a canvas (same-origin, not tainted), `canvas.toBlob('image/png')`, then `navigator.clipboard.write([new ClipboardItem({'image/png': blob})])`.

@cubic-dev-ai cubic-dev-ai Bot Jul 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The canvas.toBlob() call on line 19 passes 'image/png' as the first argument, but toBlob() requires a callback function as its first parameter. Passing a string will throw a TypeError at runtime and the blob variable will never be populated, breaking the entire clipboard extraction flow.

Fix by wrapping it in a Promise or passing a callback:

const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
`navigator.clipboard.write([new ClipboardItem({'image/png': blob})])`

or inline:

canvas.toBlob(blob => navigator.clipboard.write([new ClipboardItem({'image/png': blob})]), 'image/png');
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At domain-skills/gemini/nano-banana-images.md, line 19:

<comment>The `canvas.toBlob()` call on line 19 passes `'image/png'` as the first argument, but `toBlob()` requires a **callback function** as its first parameter. Passing a string will throw a `TypeError` at runtime and the `blob` variable will never be populated, breaking the entire clipboard extraction flow.

Fix by wrapping it in a Promise or passing a callback:

```javascript
const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
`navigator.clipboard.write([new ClipboardItem({'image/png': blob})])`

or inline:

canvas.toBlob(blob => navigator.clipboard.write([new ClipboardItem({'image/png': blob})]), 'image/png');
```</comment>

<file context>
@@ -0,0 +1,29 @@
+
+## Extracting generated images (works, no download dialog)
+- Generated images are `blob:` URLs, typically 825x1024. `curl` can't fetch them.
+- In page JS: draw the `<img>` to a canvas (same-origin, not tainted), `canvas.toBlob('image/png')`, then `navigator.clipboard.write([new ClipboardItem({'image/png': blob})])`.
+- On the host: save clipboard to file — `osascript -e 'write (the clipboard as «class PNGf») to f'`. Repeat per image.
+- Select images with `document.querySelectorAll('img')` filtered by `naturalWidth > 700`; DOM order is chronological.
</file context>
Fix with cubic

- On the host: save clipboard to file — `osascript -e 'write (the clipboard as «class PNGf») to f'`. Repeat per image.

@cubic-dev-ai cubic-dev-ai Bot Jul 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: This osascript one-liner writes to f, but f is never opened/defined in the snippet — running it verbatim will error. Consider showing the full sequence (open for access ... with write permission, write, close access) so the recipe is actually copy-pasteable.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At domain-skills/gemini/nano-banana-images.md, line 20:

<comment>This osascript one-liner writes to `f`, but `f` is never opened/defined in the snippet — running it verbatim will error. Consider showing the full sequence (`open for access ... with write permission`, write, `close access`) so the recipe is actually copy-pasteable.</comment>

<file context>
@@ -0,0 +1,29 @@
+## Extracting generated images (works, no download dialog)
+- Generated images are `blob:` URLs, typically 825x1024. `curl` can't fetch them.
+- In page JS: draw the `<img>` to a canvas (same-origin, not tainted), `canvas.toBlob('image/png')`, then `navigator.clipboard.write([new ClipboardItem({'image/png': blob})])`.
+- On the host: save clipboard to file — `osascript -e 'write (the clipboard as «class PNGf») to f'`. Repeat per image.
+- Select images with `document.querySelectorAll('img')` filtered by `naturalWidth > 700`; DOM order is chronological.
+
</file context>
Suggested change
- On the host: save clipboard to file — `osascript -e 'write (the clipboard as «class PNGf») to f'`. Repeat per image.
- On the host: save clipboard to file — `osascript -e 'set f to (open for access (POSIX file "/path/out.png") with write permission)' -e 'write (the clipboard as «class PNGf») to f' -e 'close access f'`. Repeat per image.
Fix with cubic

- Select images with `document.querySelectorAll('img')` filtered by `naturalWidth > 700`; DOM order is chronological.

## Waits / verification
- Generation takes 60–120s. Poll `get_page_text`-style DOM text: the trailing "Gemini said" block stays empty until the response lands. Screenshots of a long thread can appear frozen while streaming — trust the DOM text.
- Nano Banana reproduces large label text faithfully but **garbles small print** (bilingual sublines, nutrition text) and repeated "fix the spelling" prompts do not converge on tiny text. Plan to crop, blur, or composite real labels if small print must be exact.

## Misc traps
- An "Animate this image" suggestion chip appears near the composer after an image result; a stray click generates a 10s video.
- Enter submits; verify a new "You said" bubble exists before waiting on a response — typed text can silently fail to submit if focus moved.