Skip to content

Instantly share code, notes, and snippets.

@statico
Created July 2, 2026 20:04
Show Gist options
  • Select an option

  • Save statico/b363068a34952634658386a7e56bae3f to your computer and use it in GitHub Desktop.

Select an option

Save statico/b363068a34952634658386a7e56bae3f to your computer and use it in GitHub Desktop.
spacemolt image generator
#!/usr/bin/env bash
# Generate a SpaceMolt-style image with Gemini nano-banana-pro.
#
# Usage:
# GEMINI_API_KEY=... ./generate-post-image.sh "a lobster captain inspecting a cargo manifest"
# GEMINI_API_KEY=... ./generate-post-image.sh -o out.jpg "prompt..."
#
# Style is loaded from patreon-post-style.json next to this script.
set -euo pipefail
MODEL="gemini-3-pro-image-preview"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
STYLE_FILE="${STYLE_FILE:-$SCRIPT_DIR/patreon-post-style.json}"
OUT=""
usage() {
echo "usage: $0 [-o output.jpg] [-s style.json] \"prompt text\"" >&2
exit 1
}
while getopts ":o:s:m:h" opt; do
case "$opt" in
o) OUT="$OPTARG" ;;
s) STYLE_FILE="$OPTARG" ;;
m) MODEL="$OPTARG" ;;
h|*) usage ;;
esac
done
shift $((OPTIND - 1))
[[ $# -ge 1 ]] || usage
PROMPT="$*"
: "${GEMINI_API_KEY:?GEMINI_API_KEY must be set in env}"
[[ -f "$STYLE_FILE" ]] || { echo "style file not found: $STYLE_FILE" >&2; exit 1; }
if [[ -z "$OUT" ]]; then
OUT="$SCRIPT_DIR/generated-$(date +%Y%m%d-%H%M%S).jpg"
fi
STYLE_JSON="$(cat "$STYLE_FILE")"
FULL_PROMPT=$(cat <<EOF
Generate an image in the following house style. The style is defined as JSON; follow every constraint (palette, lighting, composition, do/dont). Render the SUBJECT below using this style.
STYLE:
$STYLE_JSON
SUBJECT:
$PROMPT
EOF
)
REQUEST=$(jq -n --arg p "$FULL_PROMPT" '{
contents: [ { parts: [ { text: $p } ] } ]
}')
TMP_RESPONSE="$(mktemp)"
trap 'rm -f "$TMP_RESPONSE"' EXIT
HTTP_CODE=$(curl -sS -o "$TMP_RESPONSE" -w "%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
"https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent" \
-d "$REQUEST")
if [[ "$HTTP_CODE" != "200" ]]; then
echo "API request failed (HTTP $HTTP_CODE):" >&2
cat "$TMP_RESPONSE" >&2
exit 1
fi
IMAGE_B64=$(jq -r '
.candidates[0].content.parts[]
| select(.inlineData != null or .inline_data != null)
| (.inlineData.data // .inline_data.data)
' "$TMP_RESPONSE" | head -n1)
if [[ -z "$IMAGE_B64" || "$IMAGE_B64" == "null" ]]; then
echo "no image returned. response:" >&2
cat "$TMP_RESPONSE" >&2
exit 1
fi
echo "$IMAGE_B64" | base64 -d > "$OUT"
echo "wrote $OUT"
{
"style_name": "spacemolt_cinematic_illustration",
"medium": {
"type": "digital painted illustration",
"rendering": "semi-realistic concept art with painterly brushwork",
"finish": "glossy, high-contrast, cinematic",
"reference_lineage": "Pixar-meets-concept-art with EVE Online sci-fi HUDs"
},
"lighting": {
"primary": "cool cyan key light from screens and holograms",
"secondary": "warm orange rim light on organic subjects",
"ambient": "deep space backlight from nebulae",
"contrast": "high",
"color_temperature_kelvin": 6500,
"highlights": "soft bloom on glowing UI elements and chest panels"
},
"camera": {
"lens_equivalent_mm": 35,
"aperture": "f/4",
"angle": "slight low-angle, wide cinematic framing",
"depth_of_field": "shallow-to-moderate, foreground subject sharp, midground softened",
"aspect_ratio": "16:9 cinematic"
},
"color_palette": {
"primary": {
"plasma_cyan": "#22D3EE",
"deep_space_navy": "#0B1A2E",
"nebula_violet": "#3B1E5E"
},
"accent": {
"claw_orange": "#D9601F",
"shell_crimson": "#A6321A",
"alert_red": "#EF4444",
"hologram_mint": "#5EEAD4"
},
"neutral": {
"console_charcoal": "#1F2937",
"metal_steel": "#6B7280",
"ui_white": "#E5F2FF"
},
"harmony_rule": "complementary cyan/orange split with violet support"
},
"composition": {
"layout": "wide horizontal triptych, subjects framed by foreground console and background space",
"rule": "off-center hero subject left, environmental detail right, asymmetric balance",
"depth_layers": [
"foreground hero + console",
"midground floating subjects + HUD panels",
"background nebula + asteroids"
],
"negative_space": "moderate; busy but legible"
},
"subjects_treatment": {
"characters": "anthropomorphic creatures with expressive, slightly cartoonish faces but realistic textures",
"tech": "chunky retro-futurist with embedded glowing panels and rivets",
"scale_play": "exaggerated proportions for comedic effect"
},
"textures": [
"chitinous shell with subsurface scattering",
"brushed metal with scratches",
"frosted holographic glass",
"matte spacesuit fabric",
"rocky pitted asteroid surface"
],
"ui_overlays": {
"style": "floating semi-transparent HUD panels",
"borders": "1-2px cyan glow with corner brackets",
"typography": "uppercase monospaced sans-serif, slight letter-spacing",
"fill": "rgba(11, 26, 46, 0.75)",
"accents": "red highlight tokens for ALERT/ERROR words",
"placement": "callouts arranged around but not covering character faces"
},
"atmosphere": {
"effects": [
"lens bloom",
"subtle chromatic aberration on highlights",
"volumetric dust",
"distant starfield"
],
"particles": "floating debris and asteroid fragments"
},
"mood": {
"primary": "satirical, chaotic, energetic",
"secondary": "sci-fi adventurous with comedic self-awareness",
"tone_keywords": ["irreverent", "tactical", "absurd", "cinematic"]
},
"do": [
"lean into cyan/orange complementary contrast",
"keep one expressive hero subject anchoring the frame",
"use HUD overlays to add narrative without cluttering faces",
"render shells, metal, and glass with distinct material response"
],
"dont": [
"no flat vector or cel-shaded looks",
"no photorealism — keep painterly brushwork visible",
"no emoji; HUD text only in monospaced uppercase",
"avoid centered symmetrical compositions"
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment