Manual illustrations: six nano-banana images, web-sized JPEGs

Generated with tools/gen_manual_art.py (gemini-3-pro / 3.1-flash /
2.5-flash), consistent picture-book style, no text in images, ~480KB total.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-07-07 17:16:44 +10:00
parent 01b9f8097b
commit a01a53648f
9 changed files with 20 additions and 17 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.DS_Store
__pycache__/
googlers.txt

BIN
img/manual/01-cover.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
img/manual/02-open.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
img/manual/03-link.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
img/manual/04-follow.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
img/manual/05-adjust.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
img/manual/06-care.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View File

@ -33,7 +33,7 @@
<div class="sub">Bilateral stimulation for therapy — on whatever screen you already have.</div>
<div class="step">
<img src="img/manual/01-cover.png" alt="" onerror="this.style.display='none'">
<img src="img/manual/01-cover.jpg" alt="" onerror="this.style.display='none'">
<h2>What is this?</h2>
<p>A gentle moving dot (and optional sound) that a patient follows with
their eyes while you guide the session. It runs in any web browser —
@ -41,7 +41,7 @@
</div>
<div class="step">
<img src="img/manual/02-open.png" alt="" onerror="this.style.display='none'">
<img src="img/manual/02-open.jpg" alt="" onerror="this.style.display='none'">
<h2><span class="n">1</span>Open it</h2>
<p>Open the site on your computer. You'll see one big green
<strong>START</strong> button and a few large sliders. That's the whole
@ -49,7 +49,7 @@
</div>
<div class="step">
<img src="img/manual/03-link.png" alt="" onerror="this.style.display='none'">
<img src="img/manual/03-link.jpg" alt="" onerror="this.style.display='none'">
<h2><span class="n">2</span>Give the patient a screen</h2>
<p>Easiest: tap <strong>Open patient screen</strong> and turn that window
to face them. Or tap <strong>Copy link</strong> and open it on their
@ -57,7 +57,7 @@
</div>
<div class="step">
<img src="img/manual/04-follow.png" alt="" onerror="this.style.display='none'">
<img src="img/manual/04-follow.jpg" alt="" onerror="this.style.display='none'">
<h2><span class="n">3</span>Press start</h2>
<p>The dot glides left and right. The patient follows it with their
eyes while you lead the session. Sound can tick from side to side too
@ -65,7 +65,7 @@
</div>
<div class="step">
<img src="img/manual/05-adjust.png" alt="" onerror="this.style.display='none'">
<img src="img/manual/05-adjust.jpg" alt="" onerror="this.style.display='none'">
<h2><span class="n">4</span>Make it comfortable</h2>
<p>Slide between turtle and rabbit until the pace feels right. Change
the size, the color, the sound — the patient's screen updates
@ -73,7 +73,7 @@
</div>
<div class="step safety">
<img src="img/manual/06-care.png" alt="" onerror="this.style.display='none'">
<img src="img/manual/06-care.jpg" alt="" onerror="this.style.display='none'">
<h2>⚠️ Go gently</h2>
<p>Ask about seizure history before showing moving or pulsing visuals.
Bilateral stimulation can bring up strong feelings — this tool assists

View File

@ -11,8 +11,8 @@ KEY = os.environ.get("GEMINI_API_KEY")
if not KEY:
sys.exit('set GEMINI_API_KEY in the environment first')
MODELS = ['gemini-2.5-flash-image', 'gemini-2.5-flash-image-preview',
'gemini-2.0-flash-preview-image-generation']
MODELS = ['gemini-3-pro-image', 'gemini-3.1-flash-image',
'gemini-2.5-flash-image']
STYLE = ("Flat vector cartoon illustration in a warm, friendly picture-book style. "
"Soft rounded shapes, thick clean outlines, muted palette of deep teal, warm coral, "
@ -52,15 +52,17 @@ def generate(prompt):
'%s:generateContent?key=%s' % (model, KEY))
req = urllib.request.Request(url, data=body,
headers={'Content-Type': 'application/json'})
try:
with urllib.request.urlopen(req, timeout=120) as r:
data = json.load(r)
for part in data['candidates'][0]['content']['parts']:
if 'inlineData' in part:
return base64.b64decode(part['inlineData']['data']), model
last = 'no image part in response from %s' % model
except Exception as e:
last = '%s: %s' % (model, e)
for attempt in (1, 2):
try:
with urllib.request.urlopen(req, timeout=300) as r:
data = json.load(r)
for part in data['candidates'][0]['content']['parts']:
if 'inlineData' in part:
return base64.b64decode(part['inlineData']['data']), model
last = 'no image part in response from %s' % model
break # empty response: don't retry same model, fall through
except Exception as e:
last = '%s (try %d): %s' % (model, attempt, e)
raise RuntimeError(last)