From agent-almanac
Create R-based pictogram glyphs for skill, agent, or team icons in the visualization layer. Covers concept sketching, ggplot2 layer composition using the primitives library, color strategy, registration in the appropriate glyph mapping file and manifest, rendering via the build pipeline, and visual verification of the neon-glow output. Use when a new entity has been added and needs a visual icon for the force-graph visualization, an existing glyph needs replacement, or when batch-creating glyphs for a new domain.
npx claudepluginhub pjt222/agent-almanacThis skill is limited to using the following tools:
Create R-based pictogram glyphs for skill, agent, or team icons in the `viz/` visualization layer. Each glyph is a pure-ggplot2 function that draws a recognizable shape on a 100x100 canvas, rendered with a neon glow effect to transparent-background WebP.
Improve an existing R-based pictogram glyph for the visualization layer. Covers visual audit of the current glyph, diagnosis of specific issues (proportions, readability, glow balance), targeted modifications to the glyph function, re-rendering, and before/after comparison. Works for skill, agent, and team glyphs. Use when a glyph renders poorly at small sizes, its visual metaphor is unclear, it has proportion issues, the neon glow effect is unbalanced, or after adding new palettes or changing the rendering pipeline.
Generates SVG icons and configurations for visual content tasks like diagrams and charts. Provides step-by-step guidance, best practices, and production-ready code. Auto-activates on 'svg icon generator' or 'svg' phrases.
Generates and edits SVG logos, icons, and graphics. Covers path commands, shape primitives, styling, accessibility, gradients, masks, sprites, optimization, and animation techniques like CSS keyframes and SVG-specific methods.
Share bugs, ideas, or general feedback.
Create R-based pictogram glyphs for skill, agent, or team icons in the viz/ visualization layer. Each glyph is a pure-ggplot2 function that draws a recognizable shape on a 100x100 canvas, rendered with a neon glow effect to transparent-background WebP.
skill, agent, or teamcreate-glyph, mystic, r-package-review) and domain (for skills)--glow-sigma value (default: 4)Identify the entity being iconified and choose a visual metaphor.
skills/<id>/SKILL.mdagents/<id>.mdteams/<id>.mdComplexity Tiers:
+----------+--------+-------------------------------------------+
| Tier | Layers | Examples |
+----------+--------+-------------------------------------------+
| Simple | 2 | glyph_flame, glyph_heartbeat |
| Moderate | 3-5 | glyph_document, glyph_experiment_flask |
| Complex | 6+ | glyph_ship_wheel, glyph_bridge_cpp |
+----------+--------+-------------------------------------------+
glyph_<descriptive_name> (snake_case, unique)Expected: A clear mental sketch of the shape with 2-6 planned layers.
On failure: If the concept is too abstract, fall back to a related concrete object. Review existing glyphs in the same domain for inspiration.
Write the R function that produces ggplot2 layers.
Function signature (immutable contract):
glyph_<name> <- function(cx, cy, s, col, bright) {
# cx, cy = center coordinates (50, 50 on 100x100 canvas)
# s = scale factor (1.0 = fill ~70% of canvas)
# col = domain color hex (e.g., "#ff88dd" for design)
# bright = brightened variant of col (auto-computed by renderer)
# Returns: list() of ggplot2 layers
}
Apply scale factor * s to ALL dimensions for consistent scaling:
r <- 20 * s # radius
hw <- 15 * s # half-width
lw <- .lw(s) # line width (default base 2.5)
lw_thin <- .lw(s, 1.2) # thinner line width
Build geometry using available primitives:
| Geometry | Usage |
|---|---|
ggplot2::geom_polygon(data, .aes(x, y), ...) | Filled shapes |
ggplot2::geom_path(data, .aes(x, y), ...) | Open lines/curves |
ggplot2::geom_segment(data, .aes(x, xend, y, yend), ...) | Line segments, arrows |
ggplot2::geom_rect(data, .aes(xmin, xmax, ymin, ymax), ...) | Rectangles |
ggforce::geom_circle(data, .aes(x0, y0, r), ...) | Circles |
Apply the color strategy:
Alpha Guide:
+----------------------+------------+--------------------------+
| Purpose | Alpha | Example |
+----------------------+------------+--------------------------+
| Large fill (body) | 0.08-0.15 | hex_with_alpha(col, 0.1) |
| Medium fill (accent) | 0.15-0.25 | hex_with_alpha(col, 0.2) |
| Small fill (detail) | 0.25-0.35 | hex_with_alpha(bright, 0.3) |
| Outline stroke | 1.0 | color = bright |
| Secondary stroke | 1.0 | color = col |
| No fill | --- | fill = NA |
+----------------------+------------+--------------------------+
Return a flat list() of layers (the renderer iterates and wraps each with glow)
Place the function in the appropriate primitives file based on entity type:
primitives.R — bushcraft, compliance, containerization, data-serialization, defensiveprimitives_2.R — devops, general, git, mcp-integrationprimitives_3.R — mlops, observability, PM, r-packages, reporting, review, web-dev, esoteric, designprimitives_4.R through primitives_19.R for newer domainsviz/R/agent_primitives.Rviz/R/team_primitives.RExpected: A working R function that returns a list of 2-6 ggplot2 layers.
On failure: If ggforce::geom_circle causes errors, ensure ggforce is installed. If coordinates are off, remember the canvas is 100x100 with (0,0) at bottom-left. Test the function interactively:
source("viz/R/utils.R"); source("viz/R/primitives.R") # etc.
layers <- glyph_<name>(50, 50, 1.0, "#ff88dd", "#ffa8f0")
p <- ggplot2::ggplot() + ggplot2::coord_fixed(xlim=c(0,100), ylim=c(0,100)) +
ggplot2::theme_void()
for (l in layers) p <- p + l
print(p)
Add the entity-to-glyph mapping in the appropriate glyph mapping file.
For skills:
viz/R/glyphs.R# -- design (3))"skill-id" = "glyph_function_name",
For agents:
viz/R/agent_glyphs.RAGENT_GLYPHS"agent-id" = "glyph_function_name",
For teams:
Open viz/R/team_glyphs.R
Find the alphabetical position in TEAM_GLYPHS
Add the entry:
"team-id" = "glyph_function_name",
Verify no duplicate ID exists in the target list
Expected: The appropriate *_GLYPHS list contains the new mapping.
On failure: If the build later reports "No glyph mapped", double-check that the entity ID exactly matches the one in the manifest and registry.
Register the icon in the appropriate manifest file.
For skills: viz/data/icon-manifest.json
{
"skillId": "skill-id",
"domain": "domain-name",
"prompt": "<domain basePrompt>, <descriptors>, dark background, vector art",
"seed": <next_seed>,
"path": "public/icons/cyberpunk/<domain>/<skill-id>.webp",
"status": "pending"
}
For agents: viz/data/agent-icon-manifest.json
{
"agentId": "agent-id",
"prompt": "<agent-specific descriptors>, dark background, vector art",
"seed": <next_seed>,
"path": "public/icons/cyberpunk/agents/<agent-id>.webp",
"status": "pending"
}
For teams: viz/data/team-icon-manifest.json
{
"teamId": "team-id",
"prompt": "<team-specific descriptors>, dark background, vector art",
"seed": <next_seed>,
"path": "public/icons/cyberpunk/teams/<team-id>.webp",
"status": "pending"
}
Expected: Valid JSON with the new entry placed among its type siblings.
On failure: Validate JSON syntax. Common mistakes: trailing comma after last array element, missing quotes.
Run the icon pipeline to render the new glyph. Always use build.sh as the entry point — it handles platform detection and R binary selection. See render-icon-pipeline for the full flag reference and pipeline architecture.
# From project root — renders all palettes, standard + HD, skips existing icons
bash viz/build.sh --only <domain> --skip-existing # skills
bash viz/build.sh --type agent --only <id> --skip-existing # agents
bash viz/build.sh --type team --only <id> --skip-existing # teams
# Dry run first:
bash viz/build.sh --only <domain> --dry-run
build.sh runs the full pipeline (palette → data → manifest → render → terminal glyphs). The non-render steps add ~10 seconds but ensure all data is current.
Output locations:
viz/public/icons/<palette>/<domain>/<skill-id>.webpviz/public/icons/<palette>/agents/<agent-id>.webpviz/public/icons/<palette>/teams/<team-id>.webpExpected: The log shows OK: <entity> (seed=XXXXX, XX.XKB) and the WebP file exists.
On failure:
"No glyph mapped" — Step 3 mapping is missing or has a typo"Unknown domain" — Domain not in get_palette_colors() in palettes.Rinstall.packages(c("ggplot2", "ggforce", "ggfx", "ragg", "magick")) firstCheck the rendered output meets quality standards.
Verify file exists and has reasonable size:
ls -la viz/public/icons/cyberpunk/<type-path>/<entity-id>.webp
# Expected: 15-80 KB typical range
Open the WebP in an image viewer to check:
Check at small sizes (the icon renders at ~40-160px in the force graph):
Expected: A clear, recognizable pictogram with even neon glow on transparent background.
On failure:
--glow-sigma 2 (default is 4)--glow-sigma 8.lw(s, base) base value)Make adjustments and re-render.
Common adjustments:
.lw(s, base) — try base = 3.0 or 3.5s (e.g., 20 * s -> 24 * s)To re-render after changes:
# Delete the existing icon first, then re-render
rm viz/public/icons/cyberpunk/<type-path>/<entity-id>.webp
# Use the appropriate build command from Step 5
When satisfied, verify the manifest status shows "done" (the build script updates it automatically on success)
Expected: The final icon passes all verification checks from Step 6.
On failure: If after 3+ iterations the glyph still doesn't read well, consider using a completely different visual metaphor (return to Step 1).
All 58 domain colors (for skills) are defined in viz/R/palettes.R (the single source of truth). Agent and team colors are also managed in palettes.R. The cyberpunk palette (hand-tuned neon colors) is in get_cyberpunk_colors(). Viridis-family palettes are auto-generated via viridisLite.
To look up a color:
source("viz/R/palettes.R")
get_palette_colors("cyberpunk")$domains[["design"]] # skill domain
get_palette_colors("cyberpunk")$agents[["mystic"]] # agent
get_palette_colors("cyberpunk")$teams[["tending"]] # team
When adding a new domain, add it to three places in palettes.R:
PALETTE_DOMAIN_ORDER (alphabetical)get_cyberpunk_colors() domains listbash viz/build.sh to regenerate palettes, data, and manifestsSee the full catalog of available glyph functions in the primitives source files:
viz/R/primitives.R through viz/R/primitives_19.R (domain-grouped)viz/R/agent_primitives.Rviz/R/team_primitives.R| Function | Signature | Purpose |
|---|---|---|
.lw(s, base) | (scale, base=2.5) | Scale-aware line width |
.aes(...) | alias for ggplot2::aes | Shorthand aesthetic mapping |
hex_with_alpha(hex, alpha) | (string, 0-1) | Add alpha to hex color |
brighten_hex(hex, factor) | (string, factor=1.3) | Brighten a hex color |
dim_hex(hex, factor) | (string, factor=0.4) | Dim a hex color |
glyph_<name>(cx, cy, s, col, bright) -> list() signature* s scaling factorcol for fills, bright for outlines, hex_with_alpha() for transparency*_glyphs.R file"status": "pending""done" after successful render* s: Hard-coded pixel values break when scale changes. Always multiply by s.y values move UP.ggfx::with_outer_glow() to every layer. Do NOT add glow inside the glyph function.get_cyberpunk_colors() in palettes.R, rendering will error. Add the color first, then regenerate.primitives*.R, agents in agent_primitives.R, teams in team_primitives.R.