> ## Documentation Index
> Fetch the complete documentation index at: https://docs.summerengine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Compatibility renderer traps skill for AI agents

> Make a Forward+ game look right on the Compatibility renderer: instance uniforms, MultiMesh, vertex colors. A Summer Engine skill for AI agents.

`compatibility-renderer-traps` is a skill from the [Summer skill library](/mcp/skills): a guide your AI agent reads when the task matches, so it builds the good version on the first try. Make a Forward+ game look right on the Compatibility renderer: instance uniforms, MultiMesh, vertex colors.

| | |
| - | - |
| Status | Preview: not yet exercised in-engine by the Summer team |
| Domains | Rendering and lighting, Performance |
| Version | `1.0.0` |
| Engine version | `>=4.6` |
| Recommended set | Yes, installed by `--recommended` |

## When your agent uses it

* A game must run on phones or weak GPUs that may use the Compatibility or Mobile renderer
* Objects render black, pale or stop animating on one renderer but not another
* Writing shaders for many instances (crops, foliage, tiles) that must work everywhere

## Install

`summer setup` installs every skill for your agent. To add only this one:

```bash theme={null}
npx -y summer-engine@latest skills install compatibility-renderer-traps --agent claude-code
```

Swap `claude-code` for your agent, such as `codex` or `cursor`. See [Skills](/mcp/skills#quick-start) for every option.

## The skill

Games built on Forward+ can end up on the Compatibility renderer (OpenGL): phones where Metal/Vulkan is
unavailable, weak GPUs, or a project that picks it for battery. The failures are silent: no error, just
black fruit, pale colors, or objects that stop animating after the first few hundred. Each trap below
comes with its fix and the reason.

## 1. Know which renderer you actually got

* Phones use `rendering/renderer/rendering_method.mobile`, which defaults to `mobile`, not Forward+.
  Set it explicitly.
* A device can fall back to another renderer when it lacks a capability. Trust the renderer name printed
  at startup (or `RenderingServer.get_current_rendering_method()`), not the project setting.
* Preview Compatibility on your computer:
  `<summer> --path . --rendering-method gl_compatibility`.

## 2. The traps

| Symptom on Compatibility | Cause | Fix |
| - | - | - |
| Objects past roughly the 250th stop growing, lose color or read as default | GLES3 reserves 16 `instance uniform` slots per instance out of 4096, so only about 256 instances in the whole scene can use them. Beyond that, values silently read 0. | Don't use `instance uniform` for anything numerous. Put per-instance state in a one-instance MultiMesh's `INSTANCE_CUSTOM` (a vec4), or bake it into mesh vertex colors. |
| Fruit/flowers render solid black | GLES3 multiplies `COLOR` by the MultiMesh instance color, which is 0 when `use_colors` is off. | Enable `use_colors` and set every instance color to white, or don't read `COLOR` in that path. |
| Everything looks pastel on Forward+ (saturated on Compatibility) | Forward+ shades in linear space, Compatibility in sRGB. Colors you bake into vertex `COLOR` or hard-code into `ALBEDO` are usually sRGB. | Convert once, only where needed: `if (!OUTPUT_IS_SRGB) col = to_linear(col);` with the helper below (the shading language has no built-in `srgb_to_linear`). Or pass colors as `uniform vec3 c : source_color`, which converts for you. |
| Whole scene pale/lime on Compatibility while Forward+ looks right | Tonemap, glow and ambient respond differently. | Keep a Compatibility branch of your lighting profile (lower ambient and exposure) and check both. |
| Foliage glows white | Glow threshold too low for bright leaves. | Raise the glow HDR threshold (\~1.5) and keep bloom near 0. |

Everything the player must see (ripe crop, enemy, pickup) must stay readable without glow, SSR,
volumetric fog or other Forward+-only effects: use shape, color and icons too.

The helper (standard sRGB curve):

```glsl theme={null}
vec3 to_linear(vec3 c) {
	return mix(pow((c + vec3(0.055)) * (1.0 / 1.055), vec3(2.4)), c * (1.0 / 12.92), lessThan(c, vec3(0.04045)));
}
```

## 3. Keep one shader path

Write shaders in plain spatial math: vertex-color ramps, simple rim terms, no custom `light()` unless
you test it on both renderers. One path for both renderers means one set of bugs and no drift.

## 4. Verify, don't assume

1. Render the same scene on Forward+ and `gl_compatibility` offscreen:
   `<summer> --audio-driver Dummy --summer-offscreen --path . --resolution 1600x900 -s res://tools/capture.gd -- --out=<dir>`
   (add `--rendering-method gl_compatibility` for the second run).
2. Read both images side by side, and include a stress shot with many instances (the 256 limit only shows
   at scale).
3. Grep the log for `SCRIPT ERROR`, `SHADER ERROR` and `ERROR:`. A shader that fails to compile still lets
   the capture exit 0 and draws the object untextured, so a missing grep hides the failure.
4. If later captures repeat the same frame, the offscreen run froze (it happens when another engine
   renders at the same time). Check with `md5 -r *.png` and rerun alone.

## Common mistakes

* Checking only the project setting and calling it "Forward+ on phones".
* Using `instance uniform` for per-plant or per-tile state.
* Reading `COLOR` from a MultiMesh without instance colors.
* Testing Compatibility with ten objects when the game shows five hundred.
* Budgeting one run per fix: every look change needs two captures (one per renderer). Plan runs in pairs.

## See also

* `web-compatibility-look` (a finished look when the game only runs on Compatibility, as on the web)
* `3d-lighting` (lighting profiles)
* `bounded-engine-runs` (safe offscreen capture runs)

## From a shell

No Summer MCP tools in this session? Run each one as a command; when `summer --version` is missing or below 4.0, use `npx -y summer-engine@latest` in place of `summer`. Fields are flags in kebab-case (`--scene-path res://main.tscn`) or one `--input '<json>'`, and `summer ops describe <op>` prints the exact input. The `summer-cli` skill has the rest.

| In this skill | Command |
| - | - |
| `summer_get_script_errors` | `summer engine get-script-errors` |
| `summer_project_setting` | `summer engine project-setting` |

## Related skills

* [`web-compatibility-look`](/skills/web-compatibility-look): Make a browser game look high-end in the Compatibility renderer (WebGL 2): what works, recipes, speed.
* [`3d-lighting`](/skills/3d-lighting): Light a 3D scene: sun, omni and spot lights, WorldEnvironment, sky, shadows and ambient.
* [`bounded-engine-runs`](/skills/bounded-engine-runs): Run Summer headless or offscreen safely: time limits, one engine per project, import passes, crash checks.

***

Source: [`library/skills/compatibility-renderer-traps/SKILL.md`](https://github.com/SummerEngine/summer/blob/main/library/skills/compatibility-renderer-traps/SKILL.md), rendered from `summer-engine@4.3.0` on npm.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.