Skip to main content
Glama

shade_region_by_light

Shade a flat region as a lit form using a color ramp and light direction. Scope to one material via base color or selection to keep separate parts distinct.

Instructions

Shade a flat region as a lit form, using a ramp and a light direction.

Turns a flat fill into a shaded one: an asymmetric terminator, a darker core away
from the light, and optional rim light. Every output pixel comes from `ramp`.

Scope this to one material. Shading a whole layer flattens materials together: a
sword shaded in one pass turns steel, brass and leather into the same colours, where
three scoped calls keep all three. Scope it by passing `base_color`, by making a
selection first (`select_by_color` is the usual way), or both.

What it cannot do: a distance field measures depth inside a silhouette, so it cannot
invent form boundaries that are not in the outline. An overlapping head and torso
drawn as one flat shape become one mass. Shade them as separate regions.

Args:
    ramp: Colours darkest first, as from `generate_ramp`. Output uses only these.
    base_color: Only shade pixels near this colour. Defaults to every opaque pixel
        in scope, which is usually what you want once a selection is active.
    light_angle: Degrees. 0 is from the right, 90 from above, 135 from the upper
        left, which is the conventional pixel-art key light.
    light_z: How much the light comes from the viewer, 0 to 1. Higher flattens the
        terminator and lights more of the form.
    bulge: How rounded the form reads. 1.0 is sphere-like; lower is flatter, which
        suits cloth and flat panels; higher exaggerates the curvature.
    ambient: Floor brightness in shadow, 0 to 1. Pixel art rarely wants true black
        in shadow, so this sits well above zero by default.
    rim: Light wrapping the edge away from the key, 0 to 1. A little reads as a
        bounce; a lot reads as backlight.
    bias: Shift the whole result along the ramp, in steps. Use this when the result
        is uniformly a shade too dark or light, rather than re-tuning the lighting.
    fill_angle: Degrees, a second light. Omitted by default, which leaves the result
        exactly as it was before this argument existed. Set it opposite `light_angle`
        for the fill or bounce light that keeps a shadow side readable instead of
        letting it go flat dark: the shadow side is where a sprite stops describing
        its form, and one light can only ever leave it at `ambient`.
    fill_strength: How strong the fill is next to the key, 0 to 1 and capped below 1.
        A fill that matches the key cancels the form entirely, because the two
        terminators land on opposite sides of the same shape and sum to a flat fill,
        so the cap refuses the value that destroys what the tool is for. A third to a
        half is the conventional choice.
    tolerance: How close a pixel must be to `base_color` to count as part of the
        region, as a weighted RGB distance. Ignored when `base_color` is omitted.
        **A distance between colours, not between materials.** Two ramps of different
        materials are routinely closer than the default 24: every step of a gold ramp
        generated by `generate_ramp` is within 24 of a step of a brass one, so a pass
        scoped to the brass matched the gold as readily. Art whose fills came from
        `generate_ramp` is exact, so scope it with a tolerance near zero and keep the
        wide default for hand-drawn art that varies.
    layer: Target layer (default: top layer).
    frame: Target frame, 1-based.

The two lights are summed and clamped, not averaged: averaging would dim the key side
as the fill came up, so adding a fill light would make the whole sprite darker and
quietly cost the ramp's top step. Clamping leaves the key side as it was and lightens
only what the key did not reach, which is what a fill light is.

`per_step` in the result counts pixels per ramp entry, which is how to check a fill
actually lightened the shadow side rather than trusting that it did.

`region_components` and `region_bounds` say whether the pass went where it was meant
to, which `region_pixels` cannot: it counts matches without saying whether they are in
one place or four. A call scoped to a 27px coin that comes back with a box spanning 200
pixels of canvas has matched something else as well, and that is the mistake
`tolerance` invites.

Refuses a region with no interior to shade: below roughly 6px across, the distance
field never exceeds a pixel and there is no form to describe. The honest answer
there is two hand-placed pixels, which `draw_pixels` already does.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
rimNoDefault: 0.0.
biasNoDefault: 0.0.
rampYes
bulgeNoDefault: 1.0.
frameNoDefault: 1.
layerNo
ambientNoDefault: 0.35.
light_zNoDefault: 0.45.
filenameYes
toleranceNoDefault: 24.0.
base_colorNo
fill_angleNo
light_angleNoDefault: 135.0.
fill_strengthNoDefault: 0.35.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Addedv0.10.0

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say it is a mutating, non-open-world call. The description goes well beyond: it refuses regions below ~6px, caps fill_strength below 1 and explains why, explains that the two lights are summed and clamped rather than averaged, and describes result fields (per_step, region_components, region_bounds) that reveal intent failures. Rich disclosure for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded and every section carries real decision-relevant content, but the prose is unusually long for a tool description and a few sentences restate a point already made ('which is what a fill light is'). Dense rather than padded, yet trimming would help scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description compensates by explaining what the result fields mean and how to use them to verify the pass. It also covers refusal conditions and multi-light interaction. For a 14-parameter mutation tool, nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

At 64% schema coverage the schema itself only supplies defaults. The prose documents all 14 parameters with units, ranges, defaults, and intent — light_angle's degree convention, light_z's flattening effect, bulge's per-material guidance, the tolerance warning about gold vs brass ramps, and fill_angle's omission semantics. This far exceeds what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource+mechanism: 'Shade a flat region as a lit form, using a ramp and a light direction.' It then names the resulting visual artifacts (asymmetric terminator, darker core, rim light) and constrains the output palette, which separates it from neighbours like gradient_map, specular_highlight and shift_along_ramp.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit scope guidance ('Scope this to one material') with a concrete failure mode (sword/steel/brass/leather flattening), three named ways to scope (base_color, making a selection, naming select_by_color as the usual route, or both), an explicit 'What it cannot do' section, and an alternative for the refused case (draw_pixels). This is close to ideal when/when-not routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools