nous-branding
Generate images and content consistent with the Nous Research brand identity. Use when creating visuals in the Nous / Theia / Hermes ecosystem: a "cyber-classical" style blending neo-classical statuary, cyberpunk/industrial grunge, and retro anime illustration. Covers official br
#image-generation
Install
npx skills add https://github.com/magnus919/agent-skills/tree/main/nous-branding
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install magnus919-agent-skills@llmmart
git clone https://github.com/magnus919/agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole magnus919/agent-skills collection as a plugin from our marketplace. Git is the plain clone.
README
Nous Research Brand Identity — Image & Content Generation
Generate images and content consistent with the Nous Research brand identity — a "cyber-classical" style blending neo-classical statuary, cyberpunk grunge, and retro manga illustration.
Why Install This Skill
When your agent loads this skill, it can create on-brand visuals for the Nous / Theia / Hermes ecosystem. That means:
- Understand the brand DNA — classical Greek myth meets cyberpunk meets retro anime
- Use the correct color palette — electric blue, dark grunge, marble tones — with hex-accurate values
- Depict the Nous Girl mascot — canonical poses, expressions, and accessories
- Generate consistent imagery — reference-image-driven workflows for texture, grain, and style
- Match brand typography — Inter, IBM Plex Sans, JetBrains Mono, distressed display faces
What You Get
| Directory | Purpose |
|---|---|
SKILL.md |
Complete brand identity reference with style fusion, color palette, typography, mascot specs |
assets/ |
4+ reference images: color palette card, official mascot, style reference, brand collage — usable as img2img inputs |
Triggers
Load this when creating visuals in the Nous Research ecosystem — blog headers, social media, presentation slides, or brand assets.
Requirements
Image generation backend for prompt-based workflows. Reference-image (img2img) workflows require an API supporting image inputs.
Quick Start
Start with the setup and first workflow in SKILL.md, then use the linked resources for the specific task you need to complete.
Skill manifest
Nous Branding
Generate images and brand-consistent visual content inspired by Nous Research ("The AI accelerator company").
When not to use
- Non-Nous design work — this skill encodes one specific brand system; do not apply its palette, textures, mascot, or compliance rules to unrelated brands or generic design requests.
- Official brand representation — the Nous Girl mascot is not a substitute for the logo; use the Nous Research wordmark/symbol for official brand use.
Reference Images
This skill ships reference images in assets/ that can be used as visual anchors for img2img, style transfer, image variation, or prompt construction:
| File | Description | Usage |
|---|---|---|
assets/palette-typography-reference.png |
Brand identity system card showing the 6-color palette swatches with hex codes, typography specimen (Inter, IBM Plex Sans, JetBrains Mono, heavy display), and classified-dossier layout | Upload as reference for color palette and typography style |
assets/nous-girl-official.webp |
Official high-resolution (2669×2709) Nous Girl mascot from nousresearch.com. High-contrast black-and-white retro manga portrait. Three-quarter profile facing left, white headband (primary badge variant). 51% dark / 47% light, pure b&w with no gray. | Primary mascot reference — the single most authentic brand image |
assets/nous-girl-official-badge.png |
Official badge portrait from the brand booklet (5760×7454). Shows the Nous Girl in her canonical form: white headband, three-quarter profile, neutral attentive expression, stark black/white manga style. | Use when the badge/primary variant is needed |
assets/nous-girl-sketch-sheet.png |
Official character sheet from the brand booklet showing all 4 canonical poses: primary badge, headphone ¾ profile, headphone profile left, and headphone small profile. | Use for pose reference and character consistency |
assets/nous-girl-philosophy.png |
Brand philosophy page from the booklet showing the Nous Girl alongside the "decentralization of good design" mission statement. | Use for brand context and philosophy reference |
assets/nous-girl-style-reference.png |
Generated reference portrait with "NOUS" on headphones, electric blue accents, and color swatch label | Color-application reference and prompt examples |
assets/brand-collage-reference.png |
Cyber-classical brand collage with Theia marble statue, glowing electric blue eye with targeting reticle, system architecture diagram, CRT noise overlay | Multi-panel brand layout and HUD aesthetic reference |
Brand Identity Overview
Nous Research's visual identity is a three-way fusion:
| Influence | Expression |
|---|---|
| Classical / Greek myth | Statuary of Theia (Titaness of Sight), marble textures, mythological naming |
| Cyberpunk / Industrial | Grunge textures, CRT scan lines, photocopy noise, distressed type, dark palette |
| Retro Anime / Manga | The "Nous Girl" mascot, cel-shaded illustration, large expressive eyes, 1970s-80s manga aesthetic |
| Tech / Brutalist | Heavy display typography, system diagrams, blueprint-style layouts, monospace code labels |
Tagline: "The AI accelerator company" Key phrases: "Advance human rights and freedoms", "Open source language models", "Unrestricted availability and use" Vibe: Intellectual but gritty — a cutting-edge research lab operating in the shadows
Loading Guide
Load references on demand — do not load everything at once.
| File | Load when |
|---|---|
| references/style-lanes.md | Choosing a style lane or writing a lane-specific prompt — full lane grammar, prompt cues, example prompts, and the asset-to-lane Reference Catalog |
| references/visual-system.md | Constructing or reviewing an image against the visual system — hero + extended palettes, Nous Girl spec and pose variants, typography, texture system, art style |
| references/post-processing.md | Delivering any generated image — mandatory post-process modes (imprint/nous/standard) and intensity calibration for scripts/postprocess.py |
references/pitfalls.md |
Output doesn't match expectations — known failure modes and mitigations |
Image Prompt Templates
Method 1: Full Brand Portrait
A cyber-classical brand identity illustration in the style of Nous Research / Project Theia.
[SUBJECT DESCRIPTION]. High-contrast dramatic lighting with deep near-black background (#00000E).
Electric blue (#3847FF) primary accent. Soft lavender (#BDA6FF) and burnt orange (#D6825A)
secondary accents. Deep teal (#2E706B) shadow tones. Overlaid with risograph grain texture,
photocopy noise, and subtle CRT scan lines. Retro anime cel-shading combined with neo-classical
sculptural forms. Geometric HUD overlay lines in burnt orange. Bold, distressed display typography.
Raw, analog, imperfect finish. No corporate polish.
Palette: #00000E bg, #3847FF accent, #BDA6FF secondary, #D6825A warm, #E6E6E6 text.
Method 2: Nous Girl Mascot
High-contrast retro manga anime portrait, 1970s-80s cel-shaded style.
A young woman with large anime eyes, shoulder-length dark hair with blunt
straight-across bangs. White over-ear headphones. Three-quarter profile facing left.
Melancholic introspective expression. Bold heavy outlines. Pure black and white with
no grayscale. [Optional: Electric blue #3847FF hair highlights for color version].
Method 3: Brand System Sheet / Collage
Multi-panel brand identity system sheet in Nous Research / Project Theia style.
Grid layout. [Describe panels]. Color palette: #3847FF electric blue, #BDA6FF lavender,
#D6825A burnt orange, #2E706B deep teal, #E6E6E6 off-white, #00000E near-black.
Texture swatches: risograph grain, photocopy noise, CRT scan lines, paper fiber, ink smudge.
Typography: heavy distressed display for titles, Inter/IBM Plex Sans for labels,
JetBrains Mono for technical data. Grunge textures throughout. Dark near-black background.
Method 4: Reference-Image-Driven Generation (Recommended)
This is the preferred method for generating brand-consistent images. Use the scripts/generate-with-ref.py script which reads your Hermes config, determines the active image provider, and hits the API directly with the reference image as contextual input — bypassing the built-in image_generate tool which only supports text prompts.
python3 scripts/generate-with-ref.py \
--prompt "Your prompt describing the desired image" \
--reference assets/nous-girl-official-badge.png \
--aspect landscape \
--quality medium
Features:
--prompt(required) — image description--reference(required) — path to a reference image (useassets/images from this skill)--aspect—landscape(1536×1024),portrait(1024×1536), orsquare(1024×1024)--quality—low,medium(default), orhigh--output— custom output path--dry-run— preview without executing
How it works:
- Reads
~/.hermes/config.yamlto find your active image generation provider - For OpenAI: uses
/v1/images/editswith multipart upload — the only endpoint that accepts image input with gpt-image-2 - Automatically crops the reference to square (1024×1024) as required by the edits endpoint
- Saves output to
~/.hermes/cache/images/ - Returns JSON with
image,model,aspect_ratio, andprovider
Why this matters: Text-only generation loses the precise manga style, character proportions, and contrast balance of the Nous Girl. Uploading the official badge preserves the specific 1970s–80s cel-shaded ink style.
Prompting for reference workflows: State what to preserve from the reference, then what to add:
- "Keep the character's white over-ear headphones, white collared shirt, solid black hair with blunt bangs, neutral expression"
- "Maintain the same high-contrast black ink on white manga style"
- Then add the scene details, text, lighting, etc.
Prompt Formula
[STYLE: cyber-classical / Nous Research]
+ [SUBJECT DESCRIPTION]
+ [PALETTE: #00000E bg, #3847FF accent, #BDA6FF, #D6825A]
+ [TEXTURES: risograph grain, photocopy noise, CRT scan lines, paper fiber, ink smudge]
+ [LIGHTING: high-contrast chiaroscuro, dramatic spot, neon edge highlights]
+ [MOOD: intellectual, gritty, underground, calm/attentive]
+ [TYPOGRAPHY: heavy distressed display, Inter/IBM Plex Sans labels, JetBrains Mono code]
Post-Processing
Raw AI-generated images are too clean for the Nous aesthetic. Post-processing is mandatory after every generation — the raw generated image is never the final deliverable.
python3 scripts/postprocess.py input.png output.png --mode imprint --intensity 0.7
Run it as the final step after any generation method (text-only, img2img, multi-pass, or any provider). For mode selection (imprint / nous / standard) and intensity calibration per output type, load references/post-processing.md.
API Workflow Notes
| API | Approach |
|---|---|
| DALL-E 3 | Text-only. Use Method 1–3 prompts with hex values. |
| OpenAI Variations / Edit | Upload assets/*.png as image input. Prompt describes differences. |
| Midjourney | --sref <asset-url> with --iw 1.5–2.0. Include palette hex values in prompt. |
| ComfyUI | IPAdapter or Reference-Only ControlNet from assets. Denoise 0.6–0.7. Post-process with grain overlay. |
| Replicate / SD img2img | Upload reference. Prompt strength 0.7–0.8. CFG 7. |
What Is NOT On-Brand
Avoid these common anti-patterns:
| Anti-Pattern | Why It's Wrong |
|---|---|
| Sad/melancholic expression | Model defaults to sad for manga characters unless explicitly told "not sad, not crying" |
| Dark/black headphones | Nous Girl wears white over-ear headphones in all canonical poses |
| Facial markings (teardrop, tattoos, scars) | The character has clean, clear skin — no markings whatsoever |
| Wrong ethnicity (Asian instead of French) | Model defaults to Asian features for anime style; explicitly state "French Caucasian" |
| Busy/cluttered compositions | The brand is restrained — dark background, 1-2 accent colors, 2-3 text elements max |
| Smooth digital illustration | The brand is never clean — every image needs grain, noise, or analog texture |
| Cartoon/anime with glossy rendering | The manga style is stark black ink on white paper — no soft shading, no gradients |
| Corporate/sterile tech aesthetic | The finish should feel like an underground research lab, not a SaaS landing page |
| Over-detailed backgrounds | Let the subject breathe. Negative space is a feature. |
For a complete list of known failure modes and mitigations, see references/pitfalls.md.
Brand Compliance Checklist
- Background is near-black (#00000E) or very dark
- Electric blue (#3847FF) is used as primary accent
- At least one grunge texture visibly applied (grain, noise, scan lines, paper, ink)
- High contrast — dramatic light/dark difference
- Palette is restricted to the specified colors
- If mascot appears: white headphones, manga style, neutral attentive expression, three-quarter profile
- If text appears: heavy distressed display for titles, clean sans for labels, monospace for code
- No flat/clean/corporate polish — finish is raw and tactile
- Overall impression: intellectual, gritty, underground research lab
Full color tables, the complete Nous Girl mascot specification with pose variants, typography roles, texture definitions, and art-style attributes live in references/visual-system.md; lane-specific prompt construction lives in references/style-lanes.md.
Available Scripts
| Script | Purpose | Invocation |
|---|---|---|
scripts/generate-with-ref.py |
Reference-image-driven generation: reads the active image provider from ~/.hermes/config.yaml, uploads the reference via the provider's image-input endpoint (square-cropped), and saves the result as JSON with output path. Run it for any Method 4 generation where brand fidelity matters — it preserves the manga style that text-only prompts lose. Use --dry-run first to preview provider and parameters. |
python3 scripts/generate-with-ref.py --prompt "..." --reference assets/nous-girl-official-badge.png --aspect landscape --quality medium |
scripts/postprocess.py |
Mandatory analog post-processing: applies grain/noise/scan-line modes (standard, risograph, nous, imprint) at a calibrated intensity. Run it as the final step on every generated image — raw AI output is never the deliverable. Load references/post-processing.md to pick mode and intensity. |
python3 scripts/postprocess.py input.png output.png --mode imprint --intensity 0.7 |
Prerequisites
- Python 3 for both scripts;
postprocess.pyadditionally needs an imaging backend (Pillow) available. - For
generate-with-ref.py: a configured Hermes image-generation provider in~/.hermes/config.yaml(or an explicit--provider) whose API accepts image inputs — text-only endpoints cannot do reference-driven generation. - The bundled reference images in
assets/, which serve as img2img anchors; pass one via--reference. - An agent or client capable of image generation when working outside the scripts (per
compatibility).
Limitations
- This skill encodes one specific brand system — the palette, mascot rules, textures, and compliance checklist here are not general design guidance and must not be applied to other brands (see When not to use).
- The Nous Girl is not a logo substitute; official brand representation requires the wordmark/symbol, not generated mascot art.
- Generated imagery approximates the style even with references: always run the Brand Compliance Checklist before delivering, and consult
references/pitfalls.mdwhen output drifts (sad expressions, dark headphones, glossy rendering). - Model/provider behavior changes over time — flag-specific details like endpoint names may drift from what the scripts assume; verify against your configured provider.
Files (agent-skills)
-
assets
-
brand-collage-reference.png 2.3 MB · in bundle
-
nous-girl-official-badge.png 1.7 MB · in bundle
-
nous-girl-official.webp 78.1 KB · in bundle
-
nous-girl-philosophy.png 1.1 MB · in bundle
-
nous-girl-sketch-sheet.png 2.6 MB · in bundle
-
nous-girl-style-reference.png 1.2 MB · in bundle
-
palette-typography-reference.png 1.7 MB · in bundle
-
-
evals
-
evals.json 8.3 KB
{ "schema_version": 1, "skill_name": "nous-branding", "evals": [ { "id": "mascot-prompt-construction", "prompt": "Generate an image of the Nous Research mascot girl for a brand post. She keeps coming out sad and with black headphones — write me a prompt that gets her right.", "expected_output": "Uses Method 2 (Nous Girl Mascot) prompt construction from the skill: high-contrast retro manga/anime portrait, 1970s-80s cel-shaded style, large anime eyes, solid black bob with blunt straight-across bangs, white over-ear headphones, three-quarter profile facing left, pure black ink on white with no grayscale. Explicitly negates the two known failure modes: states 'neutral, calm, attentive expression — not sad, not crying' (calm alone is insufficient, models default to melancholy) and specifies white headphones because black headphones are a known model failure. Does not add facial markings. For color variants, electric blue #3847FF hair highlights are optional; the default is pure black-and-white.", "assertions": [ "Specifies white over-ear headphones explicitly as part of the prompt.", "Includes explicit negation of sadness: neutral calm attentive, not sad, not crying.", "Describes the retro 1970s-80s manga cel-shaded style in high-contrast black and white.", "Requests three-quarter profile facing left with blunt bangs / voluminous black bob hair.", "Contains no facial markings (no teardrop, tattoos, or scars)." ] }, { "id": "palette-and-texture-compliance", "prompt": "I need a hero image for our Nous Research landing page. Make it look clean and modern with a light background so it feels professional.", "expected_output": "Pushes back on the clean/light direction because it violates the brand system: the aesthetic is cyber-classical with deep near-black (#00000E) backgrounds, electric blue (#3847FF) as the primary accent, soft lavender #BDA6FF / burnt orange #D6825A / deep teal #2E706B support, off-white #E6E6E6 text, and mandatory grunge texture (risograph grain, photocopy noise, CRT scan lines) — never flat, clean color blocks. Corporate/sterile polish is listed as an anti-pattern; the correct vibe is intellectual but gritty, an underground research lab. Offers the compliant alternative: dark background, high-contrast chiaroscuro lighting, textured finish, palette restricted to the specified hex values, verified against the Brand Compliance Checklist.", "assertions": [ "Cites near-black #00000E background and electric blue #3847FF primary accent from the hero palette.", "Explains that clean/corporate polish is off-brand and textures (grain, scan lines, photocopy noise) are mandatory.", "Restricts the palette to the specified hex values rather than inventing colors.", "Proposes the intellectual-gritty underground-lab mood instead of a SaaS landing-page feel." ], "case_set": "regression" }, { "id": "style-lane-selection-and-reference-image", "prompt": "Announce our new open-source model release with a stark social media image in the Nous brand style. Which visual approach should I use, and should I attach any reference images?", "expected_output": "Selects the Xerox Poster lane: high-contrast xerox-style poster on pale cyan paper stock, black/dark teal ink with dense horizontal scanlines and harsh bitmap thresholding, bold block NOUS wordmark near top, centered anonymous subject, worn border and crop marks — best for release announcements and stark social images. Uses the lane's example prompt template adapted to the release subject. For references, recommends the palette-typography reference card (per the rule of thumb, more useful than the mascot badge for xerox lanes); if the mascot should appear, uses assets/nous-girl-sketch-sheet.png or the official badge for pose consistency. Reminds that the raw generation must be post-processed afterward (imprint mode) before publishing.", "assertions": [ "Recommends the Xerox Poster lane for a release announcement social image.", "Describes the lane's grammar: pale cyan paper, black/dark teal ink, scanlines, NOUS wordmark, crop marks.", "Adapts or provides the lane's example prompt rather than generic brand prose.", "Points at the palette-typography reference image (or sketch sheet/badge if the mascot appears) per the asset-to-lane mapping.", "Notes that post-processing is required after generation." ] }, { "id": "post-processing-mandatory-before-delivery", "prompt": "I just generated a Nous-branded image and it looks great raw. Can I ship it as-is?", "expected_output": "Says no — raw AI output is too clean for the Nous aesthetic and is never the final deliverable; post-processing is mandatory after every generation. Runs scripts/postprocess.py on the raw file first, e.g. `python3 scripts/postprocess.py input.png output.png --mode imprint --intensity 0.7`. Chooses the mode deliberately: imprint (all 14 effects) as the default for current targets, nous (base 9 effects) only for legacy luminous PNW/celestial requests, standard (light touch) when minimal texture is wanted. Calibrates intensity to content — roughly 0.45-0.55 for fine manga linework to keep detail visible, up to 0.65-0.8 for xerox-poster heaviness — and warns that 0.8+ can make typography hard to read.", "assertions": [ "States that raw generated output must not be delivered without post-processing.", "Gives a concrete scripts/postprocess.py command with mode and intensity flags.", "Distinguishes the imprint, nous, and standard modes and when each applies.", "Calibrates intensity to the artwork type (lower for fine linework, higher for heavy print effect)." ], "case_set": "release" }, { "id": "reference-image-workflow-over-text-only", "prompt": "What's the best way to generate consistent Nous Girl images across many generations?", "expected_output": "Recommends Method 4: reference-image-driven generation using scripts/generate-with-ref.py, which reads the Hermes config, resolves the active image provider, and uploads an official assets/ reference (e.g., assets/nous-girl-official-badge.png) as contextual input via the provider's image-edit endpoint — bypassing text-only image_generate. Explains why: text-only prompts lose the precise cel-shaded ink style, proportions, and contrast balance. Shows the command shape (--prompt, --reference, --aspect, --quality) and how to phrase prompts for reference workflows: state what to preserve from the reference (white over-ear headphones, collared shirt, blunt bangs, neutral expression, high-contrast black-on-white manga style), then add scene details. Notes the API alternatives table (OpenAI edits/variations, Midjourney --sref, ComfyUI IPAdapter, SD img2img strength 0.7-0.8) when not using the script.", "assertions": [ "Recommends reference-image-driven generation over text-only prompting for consistency.", "Names scripts/generate-with-ref.py with its key flags including --reference pointing at an assets/ image.", "Instructs stating what to preserve from the reference before adding new scene details.", "Mentions at least one alternative API workflow for reference-based generation." ] }, { "id": "non-brand-request-routes-away", "prompt": "Design a minimalist pastel logo for my bakery's new packaging, something soft and friendly.", "expected_output": "Recognizes this is outside the skill's scope and says so: nous-branding exists for visuals in the Nous Research / Theia / Hermes ecosystem and its brand rules (dark palettes, grunge textures, cyber-classical style, the Nous Girl) would be actively wrong for a friendly pastel bakery identity. Declines to apply Nous brand constraints and offers to help with a generic brand/logo design task instead, without invoking the Nous palette, mascot, texture system, or compliance checklist.", "assertions": [ "Declines to apply the Nous brand system to a non-Nous design request.", "Does not inject Nous palette hex values, textures, or mascot elements into the deliverable.", "Offers a path forward for the user's actual (generic branding) need." ], "case_set": "dev" } ] }
-
-
references
-
pitfalls.md 9 KB
# Nous Branding — Pitfalls & Known Failure Modes This document catalogs known failure modes, gotchas, and mitigations accumulated across multiple sessions of generating Nous-branded images. Use it as a troubleshooting reference when output doesn't match expectations. --- ## 1. Mascot Generation Failures ### 1.1 Sad / Melancholic Expression **Symptom:** The Nous Girl looks sad, crying, or melancholic. **Cause:** Image models default to a melancholic expression for manga-style characters when the prompt doesn't specify otherwise. **Fix:** Always include: `"Neutral calm attentive expression — not sad, not crying"` in the character description. This must be explicit negation — "calm" alone is insufficient. ### 1.2 Dark / Black Headphones **Symptom:** The mascot appears with black or dark-colored headphones matching the scene's palette. **Cause:** The model matches the headphones to the scene's dominant colors instead of the brand's canonical white headphones. **Fix:** Always state both the color AND the headphone structure: `"White over-ear headphones — the cushioned white band arches across the crown."` ### 1.3 Teardrop / Facial Markings **Symptom:** A teardrop appears under the eye, or the face has tattoos, scars, or cyberpunk markings. **Cause:** The model free-associates "manga" or "cyberpunk" with facial markings. **Fix:** Include explicit exclusions: `"No tattoos, no scars, no markings, clean clear skin. No teardrop."` ### 1.4 Wrong Ethnicity **Symptom:** The Nous Girl appears Asian instead of French/Caucasian. **Cause:** Image models default to Asian features when the prompt specifies "anime" or "manga" style. **Fix:** Explicitly state: `"French Caucasian, fair skin, light-colored eyes (blue or grey), delicate European features, about 13 years old — NOT Asian."` ### 1.5 Wrong Clothing / Costume **Symptom:** The character is dressed in a hoodie, dark cyberpunk outfit, or elaborate costume instead of the brand's white collared shirt. **Cause:** The model matches the character's clothing to the scene's aesthetic rather than the brand specification. **Fix:** Always state `"white collared shirt"` and add `"not a hoodie, not a dark top"` for complex scenes. ### 1.6 Generic Anime Instead of Retro Manga **Symptom:** Output looks like modern glossy anime rather than 1970s-80s cel-shaded manga. **Fix:** Use the exact phrase `"1970s-80s cel-shaded manga style, high-contrast black ink on white paper"`. --- ## 2. Image Editing / Reference Workflow Pitfalls ### 2.1 Text Disappears from Edited Images **Symptom:** When editing an image that contains text (meme captions, labels, headlines), the model corrupts or drops the text. **Fix:** Regenerate with `"Keep all text exactly as shown. Do not change or remove any text."` Or add text as a post-processing step. This is a known limitation of the `/v1/images/edits` endpoint. ### 2.2 Square Input Requirement **Symptom:** The edits endpoint rejects non-square input images. **Fix:** The `generate-with-ref.py` script handles this by center-cropping to 1024x1024. Use `--pad` to pad with average edge color instead of cropping. ### 2.3 Reference Is Not a Guarantee **Symptom:** Uploading the official Nous Girl badge as a reference doesn't guarantee the output matches the canonical design. **Cause:** `/v1/images/edits` does not extract style embeddings like IPAdapter or ControlNet. The reference provides pixel-level context but style transfer is not guaranteed. **Fix:** Always restate all key identifiers in the text prompt (white headphones, black hair, white collared shirt, neutral expression) AND all exclusions (no teardrop, no markings). Prefer the sketch sheet (`nous-girl-sketch-sheet.png`) over a single-pose badge for better character understanding. ### 2.4 Multi-Pass Editing Complexity **Symptom:** Each editing pass degrades image quality or loses fidelity. **Fix:** Limit to 3-4 passes maximum. Each pass handles ONE transformation. The working sequence: character swap → style conversion → demographic correction. More passes introduce cumulative artifacts. ### 2.5 Aspect Ratio Confusion **Symptom:** Output is cropped or distorted when using non-square source images. **Fix:** The edits endpoint outputs landscape (1536x1024), portrait (1024x1536), or square (1024x1024). Set the desired output size explicitly via the `size` parameter in `generate-with-ref.py` or via `--aspect` flag. --- ## 3. Safety / Moderation Blocks ### 3.1 OpenAI Moderation Rejects Horror Content **Symptom:** The safety system blocks prompts containing ominous language, body horror descriptors, or threat-adjacent vocabulary. **Fix:** Strip all emotional/response language from the prompt. Describe only neutral visual phenomena. Instead of "horrifying spiral consuming the town," use "spiral shapes in the clouds and on buildings." The concept survives through visual contrast alone — no need to label it as horror. **Known blockers:** terrifying, disturbing, grotesque, contorted, twisted (when applied to figures), Uzumaki, body horror. ### 3.2 Threatening Character Descriptions **Symptom:** `/v1/images/edits` blocks prompts with "henchmen," "weapons," "crime scene," or threatening-character groups. **Fix:** Rephrase as neutral physical descriptions: "a group of men in dark suits" not "henchmen." Remove weapon references. Describe the scene's visual elements without labeling their intent. --- ## 4. Provider-Specific Quirks ### 4.1 OpenAI /v1/images/edits | Issue | Workaround | |-------|------------| | Text vanishes from edits | Include explicit preservation instructions | | Square input only | Use `--pad` flag to preserve non-square content | | Extra auto-generated text (labels, headlines) | Explicitly specify "ONLY the following text: [exact text]. No other text anywhere." | | Reference doesn't guarantee fidelity | Restate all identifiers in prompt | ### 4.2 DALL-E 3 (Text-Only) | Issue | Workaround | |-------|------------| | Can't use reference images | Must specify all details in the prompt text | | Sad default expression | Explicit negation required | | Wrong headphones | Must specify color and structure | | Safety system blocks horror | Strip emotional language, describe visual phenomena only | ### 4.3 ComfyUI / IPAdapter | Issue | Workaround | |-------|------------| | Reference can overpower prompt | Lower denoise to 0.6-0.7 | | Texture/loss of analog feel | Post-process with `scripts/postprocess.py` | | Style transfer incomplete | Use Reference-Only ControlNet not just IPAdapter | --- ## 5. Prompt Engineering Anti-Patterns ### 5.1 Not Specifying Emotional State The single most important lesson: if the prompt says anything about the character's emotional state without specifying "not sad," the model defaults to sad. Always end character descriptions with explicit negations of the default failure modes. ### 5.2 Not Specifying Ethnicity For manga-style characters, the model defaults to Asian features. Always state "French Caucasian" for the Nous Girl. ### 5.3 Assuming Reference Images Replace Text Description Uploading a reference image does NOT replace the need for a detailed text prompt. The reference influences style and composition, but the model still needs to know what to generate. Always provide: - Character identifiers (hair, headphones, shirt) - Palette constraints (hex values if possible) - Expression (with exclusions) - What NOT to include (teardrop, markings, dark headphones) --- ## 6. Pipeline / Tooling Pitfalls ### 6.1 `generate-with-ref.py` Crashes If the script crashes, check: - Python dependencies: `pillow` installed? - Reference path exists: `ls -la assets/` - Config file readable: `~/.hermes/config.yaml` - Active image provider set in config ### 6.2 Post-Processing Too Aggressive If `scripts/postprocess.py --mode imprint` destroys too much detail, reduce intensity or switch mode: - `--intensity 0.45` for fine linework - `--mode nous` for legacy luminous targets (no xerox/registration/scuffs) - `--mode standard` for light touch only ### 6.3 Reference Images Are Placeholders The assets in `assets/` are full-resolution reference images. If the skill was installed via `cp -r` and the assets directory is empty, sync from the repo: ```bash cp -r /path/to/agent-skills/nous-branding/assets/ ~/.hermes/skills/creative/nous-branding/assets/ ``` --- ## Quick Reference: Fixes for Common Problems | Problem | Fix | |---------|-----| | Sad expression | Add "not sad, not crying" to prompt | | Black headphones | Specify "white over-ear headphones" + "cushioned white band arches across crown" | | Teardrop/markings | Add "no tattoos, no scars, no markings, no teardrop" | | Wrong ethnicity | Add "French Caucasian, NOT Asian" | | Wrong clothing | Add "white collared shirt, not a hoodie" | | Glossy anime instead of manga | Use "1970s-80s cel-shaded manga style, high-contrast black ink on white paper" | | Text disappears in edits | Add "Keep all text exactly as shown" or add text post-process | | Image too clean | Run `python3 scripts/postprocess.py input.png output.png --mode imprint --intensity 0.7` | | Reference not matching | Use sketch sheet, restate all identifiers in prompt | -
post-processing.md 2.1 KB
# Nous Branding — Post-Processing Load this file whenever a generated image is about to be delivered: raw AI output is never the final deliverable. This file holds the post-processing modes, intensity calibration, and integration commands for `scripts/postprocess.py`. Raw AI-generated images are too clean for the Nous aesthetic. **Post-processing is mandatory** after every generation. The `scripts/postprocess.py` script applies analog-print degradation effects locally using Pillow + numpy — no API calls needed. ## Quick Start ```bash python3 scripts/postprocess.py input.png output.png --mode imprint --intensity 0.7 ``` ## Modes | Mode | Effects | When | |------|---------|------| | `imprint` | All 14 effects: warm grade, CRT scanlines, film grain, Bayer dither, vignette, chromatic aberration, screen print texture, paper fiber, ink bleed, palette compression, xerox threshold, registration offset, plate wobble, print scuffs | **Default for v9/v10/v11 targets** — maximum analog print character | | `nous` | Base 9 effects (warm grade → ink bleed) — no xerox/registration/wobble/scuffs | Legacy luminous PNW/celestial requests | | `standard` | Base 6 effects (warm grade → chromatic aberration) only | When you want just a light texture touch | ## Intensity Calibration | Intensity | Best for | |-----------|----------| | `0.45–0.55` | Fine manga linework, Future Halftone, Portal Minimal — keep detail visible | | `0.55–0.65` | Blueprint Scene, general use — avoid crushing midtones | | `0.65–0.8` | Xerox Poster, Acid Signal, heavy print effect — when the raw output is too clean | | `0.8+` | Aggressive degradation — typography may become hard to read | ## Integration Run post-processing as the final step after any generation method (text-only, img2img, multi-pass, or any provider): ```bash # After any generation method: python3 scripts/postprocess.py output-raw.png output-final.png --mode imprint --intensity 0.7 # For legacy luminous targets: python3 scripts/postprocess.py output-raw.png output-final.png --mode nous --intensity 0.5 ``` **The raw generated image is never the final deliverable.** -
style-lanes.md 6.1 KB
# Nous Branding — Style Lanes & Reference Catalog Load this file when choosing a style lane for a Nous-branded image: it encodes each lane's composition grammar, palette discipline, print technology, prompt cues, and example prompts, plus the mapping from `assets/` reference images to lanes. The lane overview table also lives in SKILL.md; this file is the deep version you need before writing a lane-specific prompt. ## Lane Selection Choose the lane that matches your output's purpose. Each lane encodes a distinct composition grammar, palette discipline, and print technology. | Lane | Palette | Best For | |------|---------|----------| | **Xerox Poster** | Pale cyan paper, black/dark teal ink, optional red accent | Release announcements, stark social images | | **Manual / Letterpress Cover** | Aged tan paper, dark teal-black ink, red rule | Specs, manuals, technical announcements | | **Industrial Duotone** | Cobalt blue, acid yellow, black | Product shots, system graphics, infrastructure | | **Minimal Stipple Field** | Cream paper, navy stipple, turquoise border | Quiet editorial covers, abstract banners | | **Blue Registration Character** | Deep blue, orange registration marks | Agent identity, symbolic personas | | **Legacy PNW / Celestial** | Electric blue, purple, amber, off-white | Classic luminous Hermes/PNW requests | ## Lane 1 — Xerox Poster For stark announcements and punchy social images. High-contrast xerox-style poster on colored paper stock. Prompt cues: high-contrast xerox poster, pale cyan paper stock, black/dark teal ink, dense horizontal scanlines, harsh bitmap thresholding, bold block `NOUS` wordmark near top, centered anonymous subject, worn border/crop marks. ```text High-contrast xerox-style poster release announcement on pale cyan paper. [Subject description]. Black ink with dense horizontal scanlines, rough halftone breakup. Bold block `NOUS` wordmark near top. Centered poster composition with worn border and crop marks. --ar 16:9 ``` ## Lane 2 — Manual / Letterpress Cover For specs, manuals, and technical documentation covers. Distressed letterpress on aged stock. Prompt cues: distressed letterpress technical manual cover, aged tan paper stock, thick dark teal-black border, compact all-caps condensed typography, red horizontal rule accent, scuffed ink, worn paper corners, `NOUS` as leading stamped brand word. ```text Distressed letterpress technical manual cover for [project]. Aged tan paper stock, thick dark teal-black border, compact all-caps condensed typography, red horizontal rule accent, scuffed ink and worn paper corners. `NOUS` as leading stamped brand word. --ar 4:5 ``` ## Lane 3 — Industrial Duotone Grid For product shots, system graphics, and infrastructure visuals. Edge-to-edge duotone with repeated artifacts. Prompt cues: edge-to-edge industrial duotone print, repeated rounded branded artifacts, saturated cobalt blue and acid yellow, blown-out ink highlights, dense halftone dots, small embedded `NOUS` marks. ```text Edge-to-edge industrial duotone print for [product/release]. Repeated branded components in cobalt blue and acid yellow against black. Dense halftone dots, blown-out ink highlights, small embedded `NOUS` marks on artifacts. --ar 16:9 ``` ## Lane 4 — Minimal Stipple Field For quiet, refined, abstract graphics with generous negative space. Prompt cues: abstract risograph/screenprint poster, cream paper base, navy stipple field fading downward, thin turquoise double border, small centered `NOUS` capsule mark, lots of negative space. ```text Abstract risograph poster on cream paper. Navy stipple field fading downward, thin turquoise double border, small centered `NOUS` capsule mark. Generous negative space. Restrained, editorial. --ar 4:5 ``` ## Lane 5 — Blue Registration Character For agent identity and symbolic character posters. Moody blue screenprint with technical registration marks. Prompt cues: moody blue screenprint poster, anonymous illustrated character, electric-blue posterized lighting, dark cyan-black field, orange registration marks, thin frame lines, scratches, analog grain. ```text Moody blue screenprint poster for [project/agent]. Anonymous character subject with electric-blue posterized lighting against dark cyan-black field. Orange registration marks, thin frame lines, scratches, analog grain. --ar 4:5 ``` ## Legacy Lane — PNW / Celestial For classic Nous/Hermes luminous imagery. Used when the request explicitly asks for the misty, glowing, portal-driven aesthetic. Prompt cues: dark navy background, misty atmospheric depth, portal/orb/beam light source, electric blue and purple accents, sacred geometry, lone figure. ```text Dark atmospheric scene with [subject description]. Misty PNW atmosphere, luminous portal/orb light source, electric blue accent, soft bloom, geometric framing. Match the classic luminous Hermes visual style. --ar 16:9 ``` ## Reference Catalog Each asset in `assets/` maps to specific style lanes. Use this table to find the right reference image for your generation: | Asset | Lanes | Best Used For | |-------|-------|---------------| | `assets/nous-girl-official-badge.png` | All lanes (mascot subject) | Primary Nous Girl reference — badge portrait, white headphones, 3/4 profile | | `assets/nous-girl-sketch-sheet.png` | All lanes (mascot subject) | Character pose reference — all 4 canonical poses | | `assets/nous-girl-philosophy.png` | Legacy PNW / Celestial | Brand philosophy visual context | | `assets/nous-girl-official.webp` | All lanes (mascot subject) | Web-resolution mascot from nousresearch.com | | `assets/palette-typography-reference.png` | All lanes (palette/style) | Color palette and typography specimen reference — use with any lane | | `assets/brand-collage-reference.png` | Legacy PNW / Celestial, Blue Registration | Cyber-classical HUD collage reference | | `assets/nous-girl-style-reference.png` | All lanes (headphone variant) | Stylized mascot with headphones and electric blue accents | **Rule of thumb:** Load the reference image that matches your lane's visual grammar. For Xerox Poster lanes, the palette-typography card is more useful than the mascot badge. For character-focused outputs, the sketch sheet is the primary reference. -
visual-system.md 6.5 KB
# Nous Branding — Visual System Load this file for the full visual-system specification: color palette, the Nous Girl mascot and her canonical poses, typography, texture system, and the cyber-classical art style (including what the style is NOT). SKILL.md keeps only the overview and compliance rules; this file holds the detail you need when constructing or reviewing an image against the brand system. ## Color Palette ### Hero Palette | Color | Hex | RGB | Usage | |-------|-----|-----|-------| | Electric Blue | `#3847FF` | (56, 71, 255) | Primary accent, mascot hair highlights, interactive elements, key brand color | | Soft Lavender | `#BDA6FF` | (189, 166, 255) | Secondary accent, gradient blends, soft highlights | | Burnt Orange | `#D6825A` | (214, 130, 90) | Geometric overlay lines, text accents, HUD elements | | Deep Teal | `#2E706B` | (46, 112, 107) | Secondary backgrounds, zine section fills | | Off-White | `#E6E6E6` | (230, 230, 230) | Text on dark backgrounds, paper backgrounds | | Near Black | `#00000E` | (0, 0, 14) | Primary background, heavy text, dark framing | ### Extended Palette | Color | Hex | Usage | |-------|-----|-------| | Deep Navy | `#003681` | Secondary brand color, headers | | Medium Blue | `#0051c3` | Interactive elements, links | | Coral Red | `#fc574a` | Alerts, emphasis accents | | Gold | `#E6C666` | Constellation lines, geometric overlays | | Charcoal | `#1d1d1d` | Dark UI backgrounds | ### Palette Principles - **High contrast is the rule** — deep near-black backgrounds against bright electric blue accents - **Electric blue (#3847FF) is the signature color** — use it for the most important accent elements - **Grunge textures over solid colors** — never use flat, clean color blocks; always overlay with grain, noise, or scan lines - **Color is reserved for hero/feature content** — the brand booklet is >95% grayscale - **Gold/orange geometric lines** (`#D6825A`, `#E6C666`) for HUD-style overlays and constellation motifs ## Logo & Mascot ### The Nous Girl (primary mascot) The single most recognizable brand element. Based on the official brand booklet (pages 8-9). | Element | Description | |---------|-------------| | **Style** | Retro 1970s-80s manga/anime cel-shaded, high-contrast pure black/white | | **Head-to-body** | Head proportionally large (manga proportions) | | **Pose** | Three-quarter profile, looking upward and to the left | | **Features** | One large detailed eye with long spiky lashes, small delicate nose, lips slightly parted | | **Hair** | Distinctive voluminous bob, solid black with sharp jagged edges against white background, straight bangs covering forehead | | **Headphones** | The white cushioned arch visible across the crown IS the headphone band — the ear cups are partially obscured by the hair in the badge portrait. **White over-ear headphones** in all canonical poses. Black headphones are incorrect. | | **Alternate** | 3 alternate poses showing different angles of the same headphone variant | | **Expression** | Neutral, calm, attentive — a quiet stillness. Not sad, not melancholic, not crying. The brand booklet describes her as "neutral, perhaps slightly surprised or attentive." | | **Shirt** | White structured collared shirt | | **Technique** | Pure black ink on white paper — no gray, no shading, no digital gradients | | **Facial markings** | None — clean, clear skin, no tattoo, no tear, no scar | ### Official Pose Variants | Pose | Angle | Primary Use | |------|-------|-------------| | **Primary Badge** | Three-quarter profile, looking upward-left | Main logo lockup, merchandise, official branding | | **Headphone — ¾ Profile** | Three-quarter facing right | Hermes/Theia ecosystem, tech contexts | | **Headphone — Profile Left** | Full profile facing left | Social media, alternate applications | | **Headphone — Small Profile** | Smaller profile facing left | Secondary placement, watermarks | ### Usage Rules - The mascot is **not a substitute for the logo** — use the Nous Research wordmark/symbol for official brand representation - **White over-ear headphones** in all poses — the ear cups are partially obscured by the voluminous hair in the badge portrait, but the white cushioned arch across the crown confirms headphones in every variant - Black headphones are incorrect - **No facial markings** — clean skin, no tattoo, no scar, no tear - Pure black-and-white high-contrast is the default; electric blue accents are for hero/feature content only ## Typography From the Hermes-Theia brand system sheet (visible in `assets/palette-typography-reference.png`): | Role | Font | Treatment | |------|------|-----------| | **Display / Headline** | Heavy sans-serif (Druk Condensed / Impact style) | Massive, uppercase, with distressed/grunge texture | | **Body / Supporting** | Inter or IBM Plex Sans | Clean sans-serif, uppercase with loose tracking | | **Code / Technical** | JetBrains Mono | Small, compact, monospace — for version numbers, technical labels | ## Texture System The brand defines five key textures that should be applied to all visuals. Reference examples available in `assets/palette-typography-reference.png`: | Texture | Description | Application | |---------|-------------|-------------| | **Risograph Grain** | Coarse, halftone-style dot grain | Background fills, image overlays | | **Photocopy Noise** | Speckled noise, static | Shadow areas, dark regions | | **CRT / Scan Lines** | Horizontal scan lines | Technical/screen elements | | **Paper Fiber** | Subtle paper texture | Backgrounds, zine sections | | **Ink Smudge** | Irregular ink spread/bleed | Edges of type, borders | **Key rule:** These textures should feel **raw, analog, and imperfect** — the opposite of polished corporate design. ## Art Style ### Core Attributes | Attribute | Description | |-----------|-------------| | **Primary aesthetic** | "Cyber-classical" — classical sculpture meets cyberpunk | | **Medium** | Digital mixed media: renders + photomontage + hand-drawn illustration | | **Technique** | Photomontage (classical statues with digital overlays), blueprint technical drawings, cel-shaded anime | | **Shading** | High-contrast chiaroscuro — deep shadows against bright highlights | | **Texture** | Always textured — never clean or flat | | **Lighting** | Dramatic spot lighting, light beams from eyes, neon edge highlights | | **Composition** | Multi-panel grid layouts (system sheets); dramatic offset subjects (hero images) | ### What the Style is NOT - NOT flat vector illustration - NOT corporate minimalist - NOT purely photographic - NOT bright, saturated, or cheerful - NOT glossy/skeuomorphic
-
-
scripts
-
generate-with-ref.py 10.9 KB
#!/usr/bin/env python3 """ Nous Branding — Reference-Image-Driven Generation Reads the Hermes Agent config to determine which image-generation provider is active, then hits that provider's API directly with a reference image as contextual input (bypassing the built-in image_generate tool which only supports text prompts). Supported providers: - OpenAI (gpt-image-2 via /v1/images/edits) - More to come (ComfyUI, Replicate, etc.) Usage: python3 scripts/generate-with-ref.py [options] Options: --prompt TEXT Generation prompt (required) --reference PATH Path to reference image (required) --aspect RATIO landscape|portrait|square (default: landscape) --quality Q low|medium|high (default: medium) --output PATH Output file path (default: auto-named in cache) --provider NAME Force provider (default: read from config) --dry-run Print what would be sent without executing --debug Print full request/response details """ import argparse import base64 import json import os import re import sys import time from pathlib import Path from typing import Any, Dict, Optional, Tuple # --------------------------------------------------------------------------- # Config helpers # --------------------------------------------------------------------------- HERMES_HOME = Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes")) CACHE_DIR = HERMES_HOME / "cache" / "images" CACHE_DIR.mkdir(parents=True, exist_ok=True) SIZES = { "landscape": (1536, 1024), "square": (1024, 1024), "portrait": (1024, 1536), } SIZE_STR = { "landscape": "1536x1024", "square": "1024x1024", "portrait": "1024x1536", } def load_config() -> Dict[str, Any]: """Load Hermes config.yaml — returns {} on failure.""" try: import yaml cfg_path = HERMES_HOME / "config.yaml" if cfg_path.exists(): with open(cfg_path) as f: return yaml.safe_load(f) or {} return {} except Exception: return {} def read_env(key: str) -> Optional[str]: """Read a key from ~/.hermes/.env""" env_path = HERMES_HOME / ".env" if not env_path.exists(): return os.environ.get(key) with open(env_path) as f: for line in f: line = line.strip() if line.startswith(key + "="): val = line.split("=", 1)[1].strip("\"'") if val: return val return os.environ.get(key) def get_image_gen_config() -> Tuple[str, str]: """ Return (provider_name, model_id) from config.yaml. Falls back to ('openai', 'gpt-image-2-medium'). """ cfg = load_config() ig = cfg.get("image_gen", {}) or {} provider = ig.get("provider", "openai") model = ig.get("model", "gpt-image-2-medium") return provider, model # --------------------------------------------------------------------------- # Image helpers # --------------------------------------------------------------------------- def prepare_reference_image(path: str, aspect: str) -> bytes: """ Load a reference image, crop to square (for edits endpoint), resize to 1024x1024, return PNG bytes. """ try: from PIL import Image except ImportError: print("ERROR: PIL/Pillow is required. Install with: pip install Pillow", file=sys.stderr) sys.exit(1) img = Image.open(path).convert("RGB") # For edits endpoint, the image must be square. Crop center square. target_size = 1024 sz = min(img.size) left = (img.width - sz) // 2 top = (img.height - sz) // 2 img_cropped = img.crop((left, top, left + sz, top + sz)) img_resized = img_cropped.resize((target_size, target_size), Image.LANCZOS) import io buf = io.BytesIO() img_resized.save(buf, format="PNG") return buf.getvalue() def save_output(b64: str, output_path: Optional[str] = None) -> str: """Save base64 image data to disk, return path.""" if output_path is None: ts = time.strftime("%Y%m%d_%H%M%S") output_path = str(CACHE_DIR / f"nous_ref_{ts}.png") with open(output_path, "wb") as f: f.write(base64.b64decode(b64)) return output_path def revised_prompt_from_meta(revised: Optional[str]) -> Optional[str]: """Return a revised_prompt if it differs meaningfully from original.""" if revised and len(revised) > 10: return revised return None # --------------------------------------------------------------------------- # Provider handlers # --------------------------------------------------------------------------- def generate_openai( prompt: str, reference_bytes: bytes, aspect: str, quality: str, model: str, dry_run: bool = False, debug: bool = False, ) -> Dict[str, Any]: """ Use OpenAI /v1/images/edits with a reference image. Supports gpt-image-2 (low/medium/high quality). """ api_key = read_env("OPENAI_API_KEY") if not api_key: return {"error": "OPENAI_API_KEY not set in ~/.hermes/.env"} # Strip quality suffix from model name to get the API model api_model = "gpt-image-2" # Build multipart form-data boundary = f"----NousFormBoundary{int(time.time())}x" def field(name: str, value: str) -> bytes: return f"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"\r\n\r\n{value}\r\n".encode() body = b"" body += field("model", api_model) body += f'--{boundary}\r\nContent-Disposition: form-data; name="image"; filename="reference.png"\r\nContent-Type: image/png\r\n\r\n'.encode() body += reference_bytes body += b"\r\n" body += field("prompt", prompt) body += field("n", "1") body += field("size", SIZE_STR[aspect]) body += field("quality", quality) body += f"--{boundary}--\r\n".encode() if dry_run: print(f"[DRY RUN] Would POST to https://api.openai.com/v1/images/edits") print(f" Model: {api_model}") print(f" Size: {SIZE_STR[aspect]}") print(f" Quality: {quality}") print(f" Prompt length: {len(prompt)} chars") print(f" Image bytes: {len(reference_bytes)}") return {"status": "dry_run"} import urllib.request req = urllib.request.Request( "https://api.openai.com/v1/images/edits", data=body, headers={ "Content-Type": f"multipart/form-data; boundary={boundary}", "Authorization": f"Bearer {api_key}", }, ) if debug: print(f"POST https://api.openai.com/v1/images/edits") print(f" Model: {api_model}, Size: {SIZE_STR[aspect]}, Quality: {quality}") print(f" Prompt: {prompt[:120]}...") print(f" Image bytes: {len(reference_bytes)}") sys.stdout.flush() try: resp = urllib.request.urlopen(req, timeout=180) result = json.loads(resp.read().decode()) except Exception as exc: error_body = "" if hasattr(exc, "read"): try: error_body = exc.read().decode()[:2000] except Exception: pass return {"error": f"API call failed: {exc}", "detail": error_body} import logging data_list = result.get("data", []) if not data_list: return {"error": "API returned no image data"} first = data_list[0] b64_json = first.get("b64_json") revised = first.get("revised_prompt") if not b64_json: return {"error": "API response missing b64_json"} return { "b64_json": b64_json, "revised_prompt": revised, "model": model, "api_model": api_model, } # --------------------------------------------------------------------------- # Main # --------------------------------------------------------------------------- PROVIDER_HANDLERS = { "openai": generate_openai, } def main(): parser = argparse.ArgumentParser( description="Generate images with reference image as context" ) parser.add_argument("--prompt", required=True, help="Generation prompt") parser.add_argument("--reference", required=True, help="Path to reference image") parser.add_argument("--aspect", choices=["landscape", "portrait", "square"], default="landscape", help="Aspect ratio") parser.add_argument("--quality", choices=["low", "medium", "high"], default="medium", help="Quality tier") parser.add_argument("--output", help="Output file path") parser.add_argument("--provider", help="Force provider (default: from config)") parser.add_argument("--dry-run", action="store_true", help="Preview without executing") parser.add_argument("--debug", action="store_true", help="Verbose output") args = parser.parse_args() # Resolve provider provider = args.provider if not provider: provider, model = get_image_gen_config() else: _, model = get_image_gen_config() # Read model from config _, model = get_image_gen_config() if args.debug: print(f"Provider: {provider}") print(f"Model: {model}") print(f"Reference: {args.reference}") sys.stdout.flush() # Validate reference image exists ref_path = Path(args.reference) if not ref_path.exists(): print(f"ERROR: Reference image not found: {ref_path}", file=sys.stderr) sys.exit(1) # Get handler for this provider handler = PROVIDER_HANDLERS.get(provider) if not handler: print(f"ERROR: Unsupported provider '{provider}'. " f"Supported: {list(PROVIDER_HANDLERS.keys())}", file=sys.stderr) sys.exit(1) # Prepare reference image try: ref_bytes = prepare_reference_image(str(ref_path), args.aspect) except Exception as exc: print(f"ERROR: Could not process reference image: {exc}", file=sys.stderr) sys.exit(1) if args.debug: from PIL import Image import io img = Image.open(io.BytesIO(ref_bytes)) print(f"Reference prepared: {img.size[0]}x{img.size[1]} PNG, " f"{len(ref_bytes) / 1024:.0f} KB") sys.stdout.flush() # Generate result = handler( prompt=args.prompt, reference_bytes=ref_bytes, aspect=args.aspect, quality=args.quality, model=model, dry_run=args.dry_run, debug=args.debug, ) if args.dry_run: return if "error" in result: print(f"ERROR: {result['error']}", file=sys.stderr) if result.get("detail"): print(f"Detail: {result['detail']}", file=sys.stderr) sys.exit(1) # Save output out_path = save_output(result["b64_json"], args.output) # Print result (machine-readable JSON for the agent) output = { "image": out_path, "model": result.get("model", "unknown"), "aspect_ratio": args.aspect, "provider": provider, } revised = result.get("revised_prompt") if revised: output["revised_prompt"] = revised print(json.dumps(output, indent=2)) if __name__ == "__main__": main() -
postprocess.py 11.4 KB
#!/usr/bin/env python3 """ postprocess.py — Analog print effects for Nous-branded images. Applies a sequence of analog-print degradation effects to AI-generated images, transforming clean digital output into something that looks physically printed, xeroxed, or risographed. Inspired by plntrprotocol/nous-branding (MIT) — same goals, independent implementation. See https://github.com/plntrprotocol/nous-branding Modes: --mode imprint Full 14-effect print degradation (default, for v9/v10/v11) --mode nous Legacy: warm grade + grain + screen print (no xerox/registration) --mode standard Light touch: grain + vignette + chroma aberration only Usage: python3 scripts/postprocess.py input.png output.png --mode imprint --intensity 0.7 """ import argparse import os import numpy as np from PIL import Image, ImageFilter, ImageEnhance, ImageOps # ── Imprint palette (constrained 2-4 ink print colors for palette compression) ── IMPRINT_PALETTE = [ "#F7EDE3", "#E8E0D4", "#C15811", "#F59E0B", "#0E2723", "#1A3A32", "#00AEEF", "#8B5CF6", "#6B7280", "#2D5016", "#0A0A1A", "#D946EF", "#BFE8F2", "#071616", "#F04A23", "#D8D061", ] def warm_grade(img, strength=0.15): """Warm color grade — push shadows toward amber/gold.""" arr = np.array(img).astype(np.float32) lum = (arr[:, :, 0] * 0.299 + arr[:, :, 1] * 0.587 + arr[:, :, 2] * 0.114) / 255 shadow = 1.0 - lum arr[:, :, 0] += shadow * strength * 12 arr[:, :, 2] -= shadow * strength * 6 return Image.fromarray(np.clip(arr, 0, 255).astype(np.uint8)) def crt_scanlines(img, opacity=0.06, every=2): """Faint horizontal CRT scanlines.""" w, h = img.size overlay = Image.new("L", (w, h), 255) px = overlay.load() for y in range(h): if y % every == 0: for x in range(w): px[x, y] = int(255 * (1 - opacity)) return Image.composite(img, Image.new("RGB", img.size, (0, 0, 0)), overlay) def film_grain(img, intensity=0.04): """Fine Gaussian noise across entire image.""" w, h = img.size noise = np.random.normal(0, 255 * intensity, (h, w, 3)).astype(np.float32) return Image.fromarray(np.clip(np.array(img).astype(np.float32) + noise, 0, 255).astype(np.uint8)) def bayer_dither(img, strength=0.3, levels=12): """4x4 ordered Bayer dither matrix — simulates risograph halftone.""" bayer = np.array([[0, 8, 2, 10], [12, 4, 14, 6], [3, 11, 1, 9], [15, 7, 13, 5]], dtype=np.float32) bayer_n = (bayer / 16.0 - 0.5) * strength w, h = img.size tile = np.tile(bayer_n, ((h + 3) // 4, (w + 3) // 4))[:h, :w] tile3 = np.stack([tile] * 3, axis=-1) * 255 arr = np.array(img).astype(np.float32) q = np.round(arr / (256 / levels)) * (256 / levels) d = q + tile3 * (256 / levels) / levels return Image.fromarray(np.clip(d, 0, 255).astype(np.uint8)) def vignette(img, strength=0.35): """Darken and warm edges toward corners.""" w, h = img.size x = np.linspace(-1, 1, w) y = np.linspace(-1, 1, h) xx, yy = np.meshgrid(x, y) dist = np.sqrt(xx**2 + yy**2) mask = np.clip(1.0 - (dist / np.sqrt(2)) * strength, 0.3, 1.0) arr = np.array(img).astype(np.float32) m3 = np.stack([mask] * 3, axis=-1) v = arr * m3 edge = (1 - mask) * 8 v[:, :, 0] += edge v[:, :, 2] -= edge * 0.5 return Image.fromarray(np.clip(v, 0, 255).astype(np.uint8)) def chromatic_aberration(img, shift=1.0): """Subtle RGB channel separation at edges.""" arr = np.array(img) px = max(1, int(round(shift))) r = np.roll(arr[:, :, 0], -px, axis=1) b = np.roll(arr[:, :, 2], px, axis=1) out = arr.copy() out[:, :, 0] = r out[:, :, 2] = b return Image.fromarray(out) def screen_print_texture(img, intensity=0.3): """Simulate risograph/screen-print halftone dot pattern.""" w, h = img.size dot_size = 3 yy, xx = np.mgrid[0:h, 0:w] offset = (np.arange(h) // dot_size % 2) * (dot_size // 2) cx = (xx + offset[:, None]) % dot_size cy = yy % dot_size dist = np.sqrt((cx - dot_size / 2) ** 2 + (cy - dot_size / 2) ** 2) lum = np.array(img.convert("L")).astype(float) / 255.0 dot_mask = np.clip(1.0 - dist / (dot_size * 0.7), 0, 1) dot_mask = dot_mask * (1.0 - lum) * intensity dot_3 = np.stack([dot_mask] * 3, axis=-1) arr = np.array(img).astype(np.float32) textured = arr * (1.0 - dot_3 * 0.15) return Image.fromarray(np.clip(textured, 0, 255).astype(np.uint8)) def paper_texture(img, intensity=0.15): """Subtle paper/canvas fiber substrate.""" w, h = img.size noise = np.random.normal(0, 1, (max(1, h // 4), max(1, w // 4))).astype(np.float32) denom = max(float(noise.max() - noise.min()), 1e-6) n_img = Image.fromarray(((noise - noise.min()) / denom * 255).astype(np.uint8)) n_img = n_img.resize((w, h), Image.Resampling.BILINEAR) n_arr = np.array(n_img).astype(float) / 255.0 n_3 = np.stack([n_arr] * 3, axis=-1) arr = np.array(img).astype(float) textured = arr * (1.0 + (n_3 - 0.5) * intensity) return Image.fromarray(np.clip(textured, 0, 255).astype(np.uint8)) def ink_bleed(img, intensity=0.2): """Slight blur + darken at dark edges to simulate ink spread on paper.""" blurred = img.filter(ImageFilter.GaussianBlur(radius=0.5)) arr_orig = np.array(img).astype(float) arr_blur = np.array(blurred).astype(float) edges_img = img.convert("L").filter(ImageFilter.FIND_EDGES).filter(ImageFilter.GaussianBlur(radius=0.6)) edges = np.array(edges_img).astype(float) if edges.max() > 0: edges = edges / edges.max() edge_3 = np.stack([edges] * 3, axis=-1) blended = arr_orig * (1 - edge_3 * intensity) + arr_blur * (edge_3 * intensity) return Image.fromarray(np.clip(blended, 0, 255).astype(np.uint8)) def palette_compress(img, strength=0.45): """Pull clean RGB renders toward a limited 2-4 ink print palette.""" palette = Image.new("P", (1, 1)) colors = [] for hx in IMPRINT_PALETTE: hx = hx.lstrip("#") colors.extend([int(hx[i:i + 2], 16) for i in (0, 2, 4)]) colors.extend([0] * (768 - len(colors))) palette.putpalette(colors) quantized = img.quantize(palette=palette, dither=Image.Dither.FLOYDSTEINBERG).convert("RGB") return Image.blend(img, quantized, float(np.clip(strength, 0, 1))) def xerox_threshold(img, strength=0.25): """Degraded photocopy contrast with breakup.""" gray = ImageOps.grayscale(img) gray = ImageEnhance.Contrast(gray).enhance(1.0 + 2.4 * strength) arr = np.array(gray).astype(np.float32) noise = np.random.normal(0, 24 * strength, arr.shape) arr = np.clip(arr + noise, 0, 255) poster = np.where(arr > (128 - 18 * strength), 235, 20).astype(np.uint8) tint = ImageOps.colorize(Image.fromarray(poster), black="#071616", white="#DCEAF0") return Image.blend(img, tint, float(np.clip(strength * 0.55, 0, 0.45))) def registration_offset(img, shift=1.0, opacity=0.35): """Simulate misregistered cyan/orange ink plates.""" px = max(1, int(round(shift))) op = float(np.clip(opacity, 0, 1)) arr = np.array(img).astype(np.float32) cyan = np.roll(arr, -px, axis=1) orange = np.roll(arr, px, axis=0) out = arr.copy() out[:, :, 1] = out[:, :, 1] * (1 - op * 0.16) + cyan[:, :, 1] * op * 0.16 out[:, :, 2] = out[:, :, 2] * (1 - op * 0.24) + cyan[:, :, 2] * op * 0.24 out[:, :, 0] = out[:, :, 0] * (1 - op * 0.18) + orange[:, :, 0] * op * 0.18 return Image.fromarray(np.clip(out, 0, 255).astype(np.uint8)) def plate_wobble(img, strength=0.35): """Subtle row-wise print wobble so crisp lines stop feeling digital.""" arr = np.array(img) h, w = arr.shape[:2] rng = np.random.default_rng() coarse = rng.normal(0, max(0.15, strength), max(4, h // 48)) offsets = np.interp(np.arange(h), np.linspace(0, h - 1, len(coarse)), coarse) out = np.empty_like(arr) for y in range(h): out[y] = np.roll(arr[y], int(round(offsets[y])), axis=0) return Image.fromarray(out) def print_scuffs(img, intensity=0.25): """Sparse scratches and imperfect ink pickup.""" w, h = img.size arr = np.array(img).astype(np.float32) scuff = np.zeros((h, w), dtype=np.float32) rng = np.random.default_rng() for _ in range(int(24 * intensity) + 3): y = int(rng.integers(0, h)) x0 = int(rng.integers(0, max(1, w - 1))) length = int(rng.integers(max(8, w // 24), max(12, w // 5))) thickness = int(rng.integers(1, 3)) x1 = min(w, x0 + length) scuff[max(0, y - thickness):min(h, y + thickness + 1), x0:x1] = float(rng.uniform(0.25, 0.8)) scuff_img = Image.fromarray((scuff * 255).astype(np.uint8)).filter(ImageFilter.GaussianBlur(radius=0.6)) mask = (np.array(scuff_img).astype(np.float32) / 255.0)[:, :, None] paper = np.array(Image.new("RGB", img.size, "#F7EDE3")).astype(np.float32) out = arr * (1 - mask * intensity * 0.35) + paper * (mask * intensity * 0.35) return Image.fromarray(np.clip(out, 0, 255).astype(np.uint8)) def process(input_path, output_path, intensity=0.5, mode="imprint"): """Run the full processing pipeline.""" print(f"Processing: {input_path} (mode={mode}, intensity={intensity})") img = Image.open(input_path).convert("RGB") w, h = img.size print(f" Input: {w}x{h}") s = intensity steps = [ ("Warm grade", lambda: warm_grade(img, 0.12 * s)), ("CRT scanlines", lambda: crt_scanlines(img, 0.04 * s, 2)), ("Film grain", lambda: film_grain(img, 0.035 * s)), ("Bayer dither", lambda: bayer_dither(img, 0.2 * s, 12)), ("Vignette", lambda: vignette(img, 0.3 * s)), ("Chromatic aberr.", lambda: chromatic_aberration(img, 0.8 * s)), ] if mode in ("risograph", "nous", "imprint"): steps.extend([ ("Screen print", lambda: screen_print_texture(img, 0.25 * s)), ("Paper texture", lambda: paper_texture(img, 0.12 * s)), ("Ink bleed", lambda: ink_bleed(img, 0.15 * s)), ]) if mode == "imprint": steps.extend([ ("Palette compress", lambda: palette_compress(img, 0.55 * s)), ("Xerox threshold", lambda: xerox_threshold(img, 0.35 * s)), ("Registration", lambda: registration_offset(img, 1.4 * s, 0.45 * s)), ("Plate wobble", lambda: plate_wobble(img, 0.7 * s)), ("Print scuffs", lambda: print_scuffs(img, 0.35 * s)), ]) for i, (name, fn) in enumerate(steps): print(f" [{i + 1}/{len(steps)}] {name}...") img = fn() img.save(output_path, "PNG") sz = os.path.getsize(output_path) print(f" Saved: {output_path} ({sz // 1024}KB)") return True if __name__ == "__main__": parser = argparse.ArgumentParser( description="Analog print effects for Nous-branded images." ) parser.add_argument("input", help="Input image path") parser.add_argument("output", nargs="?", default=None, help="Output image path (default: input with -processed suffix)") parser.add_argument("--intensity", "-i", type=float, default=0.5, help="Effect intensity 0.0-1.0 (default: 0.5)") parser.add_argument("--mode", "-m", choices=["standard", "risograph", "nous", "imprint"], default="imprint", help="Processing mode (default: imprint)") args = parser.parse_args() out = args.output or args.input.replace(".png", "-processed.png") process(args.input, out, args.intensity, args.mode) print("Done.")
-
-
README.md 1.6 KB
# Nous Research Brand Identity — Image & Content Generation Generate images and content consistent with the Nous Research brand identity — a "cyber-classical" style blending neo-classical statuary, cyberpunk grunge, and retro manga illustration. ## Why Install This Skill When your agent loads this skill, it can **create on-brand visuals** for the Nous / Theia / Hermes ecosystem. That means: - **Understand the brand DNA** — classical Greek myth meets cyberpunk meets retro anime - **Use the correct color palette** — electric blue, dark grunge, marble tones — with hex-accurate values - **Depict the Nous Girl mascot** — canonical poses, expressions, and accessories - **Generate consistent imagery** — reference-image-driven workflows for texture, grain, and style - **Match brand typography** — Inter, IBM Plex Sans, JetBrains Mono, distressed display faces ## What You Get | Directory | Purpose | |-----------|---------| | `SKILL.md` | Complete brand identity reference with style fusion, color palette, typography, mascot specs | | `assets/` | 4+ reference images: color palette card, official mascot, style reference, brand collage — usable as img2img inputs | ## Triggers Load this when creating visuals in the Nous Research ecosystem — blog headers, social media, presentation slides, or brand assets. ## Requirements Image generation backend for prompt-based workflows. Reference-image (img2img) workflows require an API supporting image inputs. ## Quick Start Start with the setup and first workflow in SKILL.md, then use the linked resources for the specific task you need to complete. -
SKILL.md 15.6 KB
--- name: nous-branding description: >- Generate images and content consistent with the Nous Research brand identity. Use when creating visuals in the Nous / Theia / Hermes ecosystem: a "cyber-classical" style blending neo-classical statuary, cyberpunk/industrial grunge, and retro anime illustration. Covers official brand color palette, typography (Inter/IBM Plex Sans, JetBrains Mono, heavy distressed display faces), the Nous Girl mascot, texture system, and image prompt construction. Ships reference images for palette, mascot, and brand collage that can be used as img2img inputs. Do not use this skill for unrelated requests; route to the nearest named specialist. license: MIT compatibility: Compatible with any agent capable of image generation or brand analysis. Reference-image workflows (img2img, style transfer, variations) require an API endpoint supporting image inputs — use the assets/ images as input. metadata: tags: nous-research, theia, hermes, brand, illustration, mascot, image-generation, style-guide, cyber-classical sources: https://nousresearch.com, {"Reference image"=>"assets/palette-typography-reference.png"}, {"Reference image"=>"assets/nous-girl-official.webp (official mascot, 2669×2709)"}, {"Reference image"=>"assets/nous-girl-style-reference.png"}, {"Reference image"=>"assets/brand-collage-reference.png"}, https://nousresearch.com/wp-content/uploads/2024/03/NOUS-BRAND-BOOKLET-firstedition_1.pdf version: 1.1.0 --- # Nous Branding Generate images and brand-consistent visual content inspired by **Nous Research** ("The AI accelerator company"). ## When not to use - **Non-Nous design work** — this skill encodes one specific brand system; do not apply its palette, textures, mascot, or compliance rules to unrelated brands or generic design requests. - **Official brand representation** — the Nous Girl mascot is not a substitute for the logo; use the Nous Research wordmark/symbol for official brand use. ## Reference Images This skill ships reference images in `assets/` that can be used as visual anchors for img2img, style transfer, image variation, or prompt construction: | File | Description | Usage | |------|-------------|-------| | `assets/palette-typography-reference.png` | Brand identity system card showing the 6-color palette swatches with hex codes, typography specimen (Inter, IBM Plex Sans, JetBrains Mono, heavy display), and classified-dossier layout | Upload as reference for color palette and typography style | | `assets/nous-girl-official.webp` | Official high-resolution (2669×2709) Nous Girl mascot from nousresearch.com. High-contrast black-and-white retro manga portrait. Three-quarter profile facing left, white headband (primary badge variant). 51% dark / 47% light, pure b&w with no gray. | Primary mascot reference — the single most authentic brand image | | `assets/nous-girl-official-badge.png` | Official badge portrait from the brand booklet (5760×7454). Shows the Nous Girl in her canonical form: white headband, three-quarter profile, neutral attentive expression, stark black/white manga style. | Use when the badge/primary variant is needed | | `assets/nous-girl-sketch-sheet.png` | Official character sheet from the brand booklet showing all 4 canonical poses: primary badge, headphone ¾ profile, headphone profile left, and headphone small profile. | Use for pose reference and character consistency | | `assets/nous-girl-philosophy.png` | Brand philosophy page from the booklet showing the Nous Girl alongside the "decentralization of good design" mission statement. | Use for brand context and philosophy reference | | `assets/nous-girl-style-reference.png` | Generated reference portrait with "NOUS" on headphones, electric blue accents, and color swatch label | Color-application reference and prompt examples | | `assets/brand-collage-reference.png` | Cyber-classical brand collage with Theia marble statue, glowing electric blue eye with targeting reticle, system architecture diagram, CRT noise overlay | Multi-panel brand layout and HUD aesthetic reference | --- ## Brand Identity Overview Nous Research's visual identity is a **three-way fusion**: | Influence | Expression | |-----------|-----------| | **Classical / Greek myth** | Statuary of Theia (Titaness of Sight), marble textures, mythological naming | | **Cyberpunk / Industrial** | Grunge textures, CRT scan lines, photocopy noise, distressed type, dark palette | | **Retro Anime / Manga** | The "Nous Girl" mascot, cel-shaded illustration, large expressive eyes, 1970s-80s manga aesthetic | | **Tech / Brutalist** | Heavy display typography, system diagrams, blueprint-style layouts, monospace code labels | **Tagline:** "The AI accelerator company" **Key phrases:** "Advance human rights and freedoms", "Open source language models", "Unrestricted availability and use" **Vibe:** Intellectual but gritty — a cutting-edge research lab operating in the shadows --- ## Loading Guide Load references on demand — do not load everything at once. | File | Load when | |------|-----------| | [references/style-lanes.md](references/style-lanes.md) | Choosing a style lane or writing a lane-specific prompt — full lane grammar, prompt cues, example prompts, and the asset-to-lane Reference Catalog | | [references/visual-system.md](references/visual-system.md) | Constructing or reviewing an image against the visual system — hero + extended palettes, Nous Girl spec and pose variants, typography, texture system, art style | | [references/post-processing.md](references/post-processing.md) | Delivering any generated image — mandatory post-process modes (`imprint`/`nous`/`standard`) and intensity calibration for `scripts/postprocess.py` | | [`references/pitfalls.md`](references/pitfalls.md) | Output doesn't match expectations — known failure modes and mitigations | --- ## Image Prompt Templates ### Method 1: Full Brand Portrait ``` A cyber-classical brand identity illustration in the style of Nous Research / Project Theia. [SUBJECT DESCRIPTION]. High-contrast dramatic lighting with deep near-black background (#00000E). Electric blue (#3847FF) primary accent. Soft lavender (#BDA6FF) and burnt orange (#D6825A) secondary accents. Deep teal (#2E706B) shadow tones. Overlaid with risograph grain texture, photocopy noise, and subtle CRT scan lines. Retro anime cel-shading combined with neo-classical sculptural forms. Geometric HUD overlay lines in burnt orange. Bold, distressed display typography. Raw, analog, imperfect finish. No corporate polish. Palette: #00000E bg, #3847FF accent, #BDA6FF secondary, #D6825A warm, #E6E6E6 text. ``` ### Method 2: Nous Girl Mascot ``` High-contrast retro manga anime portrait, 1970s-80s cel-shaded style. A young woman with large anime eyes, shoulder-length dark hair with blunt straight-across bangs. White over-ear headphones. Three-quarter profile facing left. Melancholic introspective expression. Bold heavy outlines. Pure black and white with no grayscale. [Optional: Electric blue #3847FF hair highlights for color version]. ``` ### Method 3: Brand System Sheet / Collage ``` Multi-panel brand identity system sheet in Nous Research / Project Theia style. Grid layout. [Describe panels]. Color palette: #3847FF electric blue, #BDA6FF lavender, #D6825A burnt orange, #2E706B deep teal, #E6E6E6 off-white, #00000E near-black. Texture swatches: risograph grain, photocopy noise, CRT scan lines, paper fiber, ink smudge. Typography: heavy distressed display for titles, Inter/IBM Plex Sans for labels, JetBrains Mono for technical data. Grunge textures throughout. Dark near-black background. ``` ### Method 4: Reference-Image-Driven Generation (Recommended) **This is the preferred method for generating brand-consistent images.** Use the `scripts/generate-with-ref.py` script which reads your Hermes config, determines the active image provider, and hits the API directly with the reference image as contextual input — bypassing the built-in `image_generate` tool which only supports text prompts. ``` python3 scripts/generate-with-ref.py \ --prompt "Your prompt describing the desired image" \ --reference assets/nous-girl-official-badge.png \ --aspect landscape \ --quality medium ``` **Features:** - `--prompt` (required) — image description - `--reference` (required) — path to a reference image (use `assets/` images from this skill) - `--aspect` — `landscape` (1536×1024), `portrait` (1024×1536), or `square` (1024×1024) - `--quality` — `low`, `medium` (default), or `high` - `--output` — custom output path - `--dry-run` — preview without executing **How it works:** 1. Reads `~/.hermes/config.yaml` to find your active image generation provider 2. For **OpenAI**: uses `/v1/images/edits` with multipart upload — the only endpoint that accepts image input with gpt-image-2 3. Automatically crops the reference to square (1024×1024) as required by the edits endpoint 4. Saves output to `~/.hermes/cache/images/` 5. Returns JSON with `image`, `model`, `aspect_ratio`, and `provider` **Why this matters:** Text-only generation loses the precise manga style, character proportions, and contrast balance of the Nous Girl. Uploading the official badge preserves the specific 1970s–80s cel-shaded ink style. **Prompting for reference workflows:** State what to **preserve** from the reference, then what to **add**: - "Keep the character's white over-ear headphones, white collared shirt, solid black hair with blunt bangs, neutral expression" - "Maintain the same high-contrast black ink on white manga style" - Then add the scene details, text, lighting, etc. ### Prompt Formula ``` [STYLE: cyber-classical / Nous Research] + [SUBJECT DESCRIPTION] + [PALETTE: #00000E bg, #3847FF accent, #BDA6FF, #D6825A] + [TEXTURES: risograph grain, photocopy noise, CRT scan lines, paper fiber, ink smudge] + [LIGHTING: high-contrast chiaroscuro, dramatic spot, neon edge highlights] + [MOOD: intellectual, gritty, underground, calm/attentive] + [TYPOGRAPHY: heavy distressed display, Inter/IBM Plex Sans labels, JetBrains Mono code] ``` --- ## Post-Processing Raw AI-generated images are too clean for the Nous aesthetic. **Post-processing is mandatory** after every generation — the raw generated image is never the final deliverable. ```bash python3 scripts/postprocess.py input.png output.png --mode imprint --intensity 0.7 ``` Run it as the final step after any generation method (text-only, img2img, multi-pass, or any provider). For mode selection (`imprint` / `nous` / `standard`) and intensity calibration per output type, load [references/post-processing.md](references/post-processing.md). --- ## API Workflow Notes | API | Approach | |-----|----------| | **DALL-E 3** | Text-only. Use Method 1–3 prompts with hex values. | | **OpenAI Variations / Edit** | Upload `assets/*.png` as image input. Prompt describes differences. | | **Midjourney** | `--sref <asset-url>` with `--iw 1.5–2.0`. Include palette hex values in prompt. | | **ComfyUI** | IPAdapter or Reference-Only ControlNet from assets. Denoise 0.6–0.7. Post-process with grain overlay. | | **Replicate / SD img2img** | Upload reference. Prompt strength 0.7–0.8. CFG 7. | --- ## What Is NOT On-Brand Avoid these common anti-patterns: | Anti-Pattern | Why It's Wrong | |-------------|----------------| | **Sad/melancholic expression** | Model defaults to sad for manga characters unless explicitly told "not sad, not crying" | | **Dark/black headphones** | Nous Girl wears **white** over-ear headphones in all canonical poses | | **Facial markings (teardrop, tattoos, scars)** | The character has clean, clear skin — no markings whatsoever | | **Wrong ethnicity (Asian instead of French)** | Model defaults to Asian features for anime style; explicitly state "French Caucasian" | | **Busy/cluttered compositions** | The brand is restrained — dark background, 1-2 accent colors, 2-3 text elements max | | **Smooth digital illustration** | The brand is **never** clean — every image needs grain, noise, or analog texture | | **Cartoon/anime with glossy rendering** | The manga style is stark black ink on white paper — no soft shading, no gradients | | **Corporate/sterile tech aesthetic** | The finish should feel like an underground research lab, not a SaaS landing page | | **Over-detailed backgrounds** | Let the subject breathe. Negative space is a feature. | For a complete list of known failure modes and mitigations, see [`references/pitfalls.md`](references/pitfalls.md). --- ## Brand Compliance Checklist - [ ] Background is near-black (#00000E) or very dark - [ ] Electric blue (#3847FF) is used as primary accent - [ ] At least one grunge texture visibly applied (grain, noise, scan lines, paper, ink) - [ ] High contrast — dramatic light/dark difference - [ ] Palette is restricted to the specified colors - [ ] If mascot appears: white headphones, manga style, neutral attentive expression, three-quarter profile - [ ] If text appears: heavy distressed display for titles, clean sans for labels, monospace for code - [ ] No flat/clean/corporate polish — finish is raw and tactile - [ ] Overall impression: intellectual, gritty, underground research lab Full color tables, the complete Nous Girl mascot specification with pose variants, typography roles, texture definitions, and art-style attributes live in [references/visual-system.md](references/visual-system.md); lane-specific prompt construction lives in [references/style-lanes.md](references/style-lanes.md). ## Available Scripts | Script | Purpose | Invocation | |---|---|---| | `scripts/generate-with-ref.py` | Reference-image-driven generation: reads the active image provider from `~/.hermes/config.yaml`, uploads the reference via the provider's image-input endpoint (square-cropped), and saves the result as JSON with output path. Run it for any Method 4 generation where brand fidelity matters — it preserves the manga style that text-only prompts lose. Use `--dry-run` first to preview provider and parameters. | `python3 scripts/generate-with-ref.py --prompt "..." --reference assets/nous-girl-official-badge.png --aspect landscape --quality medium` | | `scripts/postprocess.py` | Mandatory analog post-processing: applies grain/noise/scan-line modes (`standard`, `risograph`, `nous`, `imprint`) at a calibrated intensity. Run it as the final step on every generated image — raw AI output is never the deliverable. Load `references/post-processing.md` to pick mode and intensity. | `python3 scripts/postprocess.py input.png output.png --mode imprint --intensity 0.7` | ## Prerequisites - Python 3 for both scripts; `postprocess.py` additionally needs an imaging backend (Pillow) available. - For `generate-with-ref.py`: a configured Hermes image-generation provider in `~/.hermes/config.yaml` (or an explicit `--provider`) whose API accepts image inputs — text-only endpoints cannot do reference-driven generation. - The bundled reference images in `assets/`, which serve as img2img anchors; pass one via `--reference`. - An agent or client capable of image generation when working outside the scripts (per `compatibility`). ## Limitations - This skill encodes one specific brand system — the palette, mascot rules, textures, and compliance checklist here are not general design guidance and must not be applied to other brands (see When not to use). - The Nous Girl is not a logo substitute; official brand representation requires the wordmark/symbol, not generated mascot art. - Generated imagery approximates the style even with references: always run the Brand Compliance Checklist before delivering, and consult `references/pitfalls.md` when output drifts (sad expressions, dark headphones, glossy rendering). - Model/provider behavior changes over time — flag-specific details like endpoint names may drift from what the scripts assume; verify against your configured provider.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.