How to Try Bevy Contact Shadows - First Indie Soft Contact Spike 2026

If you are searching bevy contact shadows, you do not need another “Bevy 0.19 has BSN now” roundup. You need a Monday path: pin Bevy ≥ 0.19, place a floor and a prop under a directional light, add the ContactShadows component to the camera, set contact_shadows_enabled on the lights you care about, capture before/after soft contact on the ground plane, then write keep / hold / rewrite before anyone promises raytraced polish on a mid-tier laptop.
On June 19, 2026, Bevy shipped 0.19 with contact shadows as a complementary fix for short-range shadow failure modes that shadow maps alone cannot solve — peter-panning and shadow acne up close (Bevy 0.19 release notes, 0.18→0.19 migration). Official framing: contact shadows help shadows capture object detail and attach properly to nearby surfaces without the cost of full raytracing.
This evening is not Bevy 0.19 BSN (bsn! scenes). It is not the 0.17 2D platformer weekend. It is not the schedule hitch debug. It is not Phaser cone lights or Godot AreaLight3D. It is the dedicated bevy contact shadows soft-contact spike on a throwaway 3D lab.
| If you are… | Start here | Done when |
|---|---|---|
| Beginner | Glossary → pin 0.19 → one directional + ContactShadows | Soft contact visible on floor |
| Creator / producer | Gates B1–B6 → Discord brief + receipt | Keep/hold line + before/after stills |
| Working eng | Cost formula + mid-PC FPS note | Receipt JSON + light-count cap |
| Studio lead | Diligence zip + promote condition | Dual owners named |
Time: about 60–90 minutes on a lab Bevy 0.19 3D project. Longer if you must migrate from 0.17/0.18 first.
Why this matters now
Three clocks make bevy contact shadows worth an evening this month:
- Contact shadows are first-class in 0.19. Release notes put them next to BSN and Feathers as a polish feature teams will ask about in Discord (Bevy 0.19).
- Shadow maps alone fail up close. Official notes explain peter-panning vs acne when casters sit near receivers — resolution bumps do not fix the geometry problem without prohibitive memory cost.
- Cost is measurable, not mystical. Contact shadows are toggled per light; cost scales with pixels lit by those lights × number of such lights. That sentence belongs in your receipt.
If you still need Rust/Bevy fundamentals, skim the 0.17 platformer weekend and the free Bevy resource list on a different night — tonight stays on soft contact.
Glossary - plain words
| Term | What it means |
|---|---|
| Contact shadows | Screen-space (or complementary) short-range shadows that glue casters to nearby surfaces. |
ContactShadows |
Camera component that enables contact-shadow computation for the view. |
contact_shadows_enabled |
Per-light bool on directional / point / spot lights. |
| Shadow map | Classic depth-from-light shadow technique — strong at distance, weak for tight contact. |
| Peter-panning | Object looks like it floats because the shadow disconnects from the base. |
| Shadow acne | Self-intersecting / noisy shadow artifacts from depth bias fights. |
| Solari | Bevy’s higher-end GI / lighting path — contact shadows here are the non-Solari polish path called out in 0.19 notes. |
| Keep / hold / rewrite | Keep = adopt on hero interiors; hold = lab only; rewrite = stay on shadow maps + bias tuning. |
What Bevy 0.19 contact shadows actually claim (true summary)
From the Bevy 0.19 release notes:
- Contact shadows help shadows capture object details and attach properly to nearby surfaces.
- Outside Solari, Bevy shadows previously relied on (cascaded) shadow maps alone.
- Shadow maps struggle when caster-to-receiver distance is small — peter-panning or acne depending on depth bias.
- Raising shadow-map resolution only moves the failure threshold and burns memory.
- Contact shadows fill the short-range gap with an affordable screen-space raycast from surfaces toward lights, checking for nearby occluders (per 0.19 notes).
- Results cling to surfaces and emphasize subtle curves on props and characters.
- Supported for directional, point, and spot lights.
- Toggled per light via
contact_shadows_enabled = true. - Add the
ContactShadowscomponent to your camera. - Tuning values on that component control how contact shadows are computed across the scene.
- Cost scales with number of pixels on screen lit by lights with contact shadows enabled, multiplied by the number of such lights.
Honest limits: contact shadows are not full raytracing and not a substitute for art direction. They will not fix muddy materials, missing ambient, or a scene that never cast shadows. This spike does not replace Solari evaluation if that is your GI bet, and it does not replace the BSN evening if scenes are the real blocker.
Keep / hold / rewrite - Monday decisions
| Decision | Choose when | Do not pretend |
|---|---|---|
| Keep | Lab shows readable floor contact; mid-PC FPS acceptable with a light-count cap | That contact shadows alone make lighting “AAA” |
| Hold | Spike works but ship still on 0.17/0.18; need migration week | That “we’ll bump Friday before trailer” without a pin PR |
| Rewrite | Bias/resolution already look fine, or mobile primary SKU fails cost gate | That every light in the level needs contact shadows on day one |
Write the decision on the receipt before anyone enables contact shadows on every PointLight in the open world.
Prerequisites
- Rust toolchain (
rustup) and Cargo - A lab Bevy 0.19 3D project (throwaway crate or branch)
- Basic mesh + material + light spawn comfort
- About 60–90 minutes blocked calendar
- Optional: Tracy / frame-time HUD for a mid-PC note
Beginner path - first evening (no jargon first)
1) Pin Bevy 0.19 on a lab crate
[dependencies]
bevy = "0.19"
Confirm the lock resolves to 0.19.x. Do not bump production Cargo.toml on day one.
cargo new bevy_contact_shadows_lab
cd bevy_contact_shadows_lab
# edit Cargo.toml, then:
cargo run
2) Spawn a floor, a prop, a camera, a directional light
Keep the scene boring: a ground plane, a crate or capsule resting on it, one sun-like directional light with shadows on. Goal: classic shadow-map contact that looks slightly “floaty” or acne-prone up close — that is your before shot.
3) Add ContactShadows to the camera
use bevy::prelude::*;
fn setup(mut commands: Commands) {
commands.spawn((
Camera3d::default(),
ContactShadows::default(), // enable contact-shadow pass for this view
Transform::from_xyz(4.0, 3.0, 6.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}
If your exact 0.19 patch uses a slightly different import path for ContactShadows, follow the compiler and the 0.19 notes — the evening contract is camera component + per-light flag, not winning a docs trivia fight.
4) Enable contact shadows on the light
commands.spawn((
DirectionalLight {
shadows_enabled: true,
contact_shadows_enabled: true,
illuminance: light_consts::lux::OVERCAST_DAY,
..default()
},
Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 0.7, -0.9)),
));
Repeat the same contact_shadows_enabled: true pattern for a lab PointLight or SpotLight if you want a second still — still one primary light for the FPS gate tonight.
5) Capture before / after
Toggle contact_shadows_enabled (or remove ContactShadows from the camera) and screenshot the caster base on the floor. Soft attachment should improve without inventing a second sun.
6) Write keep / hold and stop
Do not refactor BSN, Feathers, or Solari tonight. One soft-contact proof + receipt is the spike.
Working-dev path - gates B1–B6
B1 - Pin matrix
| Check | Pass if |
|---|---|
| Bevy version | 0.19.x in Cargo.lock |
| Lab isolation | Spike crate / branch, not silent main bump |
| 3D app | DefaultPlugins boots a window without panic |
cargo tree -p bevy -i bevy | head
B2 - Camera ContactShadows
| Check | Pass if |
|---|---|
| Component present | Primary gameplay / lab camera has ContactShadows |
| Tuning noted | Default first; optional note if you changed thickness/range-style fields |
B3 - Per-light enable
| Check | Pass if |
|---|---|
| Light types | At least one directional or point or spot with contact_shadows_enabled |
| Shadows still on | Classic shadows_enabled still true where you expect maps |
| Cap | ≤2 contact-enabled lights for the first FPS pass |
B4 - Visual proof
| Check | Pass if |
|---|---|
| Before still | Shadow-map-only contact looks weaker / floatier |
| After still | Soft attachment reads on floor or wall |
| Same camera | No cheating with different FOV / exposure |
B5 - Cost honesty
| Check | Pass if |
|---|---|
| Formula written | “pixels lit × contact-enabled lights” on the receipt |
| Mid-PC note | Optional but preferred 1% lows or frame-time delta |
| Cap policy | Written max contact-enabled lights for ship scenes |
B6 - Keep/hold + owners
| Artifact | Required |
|---|---|
| Decision line | keep / hold / rewrite |
| Owners | Eng + art (or eng + producer) |
| Capture paths | before/after stills or 10s clip |
| Promote flag | promoted_to_ship: false until humans say otherwise |
Receipt template - bevy_contact_shadows_receipt_v1.json
{
"schema": "bevy_contact_shadows_receipt_v1",
"project": "lab-contact-shadows-spike",
"bevy_version": "0.19.x",
"gates": {
"B1_pin": "GREEN",
"B2_camera_contact_shadows": "GREEN",
"B3_per_light_enable": "GREEN",
"B4_visual_proof": "GREEN",
"B5_cost_honesty": "GREEN",
"B6_capture_decision": "GREEN"
},
"camera_has_contact_shadows": true,
"lights_with_contact_shadows": ["DirectionalLight"],
"contact_enabled_light_count": 1,
"before_capture": "artifacts/contact_before.png",
"after_capture": "artifacts/contact_after.png",
"fps_note": "optional mid-tier frame-time delta with 1 contact-enabled light",
"decision": "keep",
"decision_notes": "Floor contact readable; cap ship scenes to 1–2 contact-enabled lights until profiling expands.",
"owners": {
"engineering": "NAME",
"art_or_producer": "NAME"
},
"promoted_to_ship": false
}
Store beside other evidence habits from BUILD_RECEIPT. Do not invent studio names — use your real owners.
Common mistakes (and fast fixes)
| Mistake | Symptom | Fix |
|---|---|---|
Forgot ContactShadows on camera |
Per-light flag does nothing obvious | Add the camera component |
Forgot contact_shadows_enabled |
Camera component alone looks unchanged | Enable on the light(s) |
| Shadows disabled entirely | No maps, no contact | Turn shadows_enabled on first |
| Ten PointLights all flagged | FPS cliff | Cap to one hero light tonight |
| Comparing different exposures | Fake “win” | Lock camera / exposure for A/B |
| Expecting Solari quality | Disappointment | Contact shadows ≠ full GI path |
| Mixing BSN migration tonight | Context switch chaos | BSN is a separate evening |
| Shipping without stills | Standup arguments | Before/after PNGs beat vibes |
| Mobile SKU assumed free | Surprise cost | Measure the target SKU or hold |
| Bias fights after enable | Acne returns | Revisit bias; contact is complementary, not magic |
Worked example - indoor prop contact (lab template)
Use as a fill-in table, not universal truth.
| Setting | Lab value |
|---|---|
| Scene | Floor + one crate / capsule |
| Primary light | Directional, shadows on, contact on |
| Secondary light | Off for B5 |
| Camera | ContactShadows::default() |
| Capture | Base of prop on floor, same FOV |
| Pass rule | Soft attachment readable; frame-time delta under team threshold |
Pass rule: if you only see improvement after enabling contact on every light in a dense interior, hold density expansion and profile — the official cost model punishes lit-pixel × light-count product (0.19 notes).
Optional - point and spot lab branch
After B1–B6 green on directional:
- Disable directional contact; enable one SpotLight aimed at the prop.
- Capture again.
- Note which light type sells your genre (sun exteriors vs lamp interiors).
Stop after one branch if the clock hits 90 minutes — receipt first.
Art pipeline notes (creators)
- Blockout with shadow maps only so composition reads before contact polish.
- Promote contact on hero interiors and prop close-ups — not every fill light.
- Keep albedo honest — soft contact will not fix muddy materials.
- Trailer cameras may use higher contact density; tag
non_ship_lightingin receipt notes if trailer ≠ gameplay. - Share a Discord brief with before/after stills — producers need the look, not only the field name.
Performance and diligence honesty
Official cost model (paraphrased from 0.19 notes):
Cost scales with pixels lit by contact-enabled lights × number of those lights.
Company diligence language: a producer zip can include the receipt JSON, Cargo.lock Bevy pin, before/after stills, and the release-notes link. That shows the team evaluated soft-contact polish without claiming Solari or raytrace parity.
Mid-PC / Deck-class targets: measure with your real resolution scale. If B5 fails with one light, do not “fix” by adding more — hold and profile overdraw.
Format ladder - same cluster, different jobs
| Format | Angle (do not cannibalize) |
|---|---|
| This blog | Strategy + keep/hold + B1–B6 + receipt |
| Guide chapter (forward) | One step - add ContactShadows + one light flag |
| Help (forward) | Fix - “contact shadows not visible / missing camera component” |
| Resource | Discovery - free Bevy lighting / profiling crates |
| Course lesson | Milestone - soft-contact interior in a project week |
Cross-engine lighting cousins stay on their keywords: Phaser cone lights, Godot AreaLight3D, Defold lights.
How this differs from other Bevy spikes
| Spike | Primary keyword | Tonight? |
|---|---|---|
| BSN scene evening | bevy bsn | No |
| 0.17 platformer | bevy 0.17 platformer | No |
| Schedule hitch | bevy schedule / menu hitch | No |
| Contact shadows | bevy contact shadows | Yes |
Same keep/hold culture; different ship risk.
Stretch goals (only after B1–B6 green)
- Tune
ContactShadowsfields (thickness / quality style knobs on your patch) and document defaults vs tuned. - One spot-lamp interior A/B for art direction.
- Tracy capture with contact on/off for a one-line cost note.
- Compare a Solari prototype another night — do not expand tonight’s receipt.
Stop at one stretch if the clock hits 90 minutes.
Secondary 0.19 features (park for later)
Do not expand tonight’s receipt to cover:
- BSN /
bsn!— BSN evening - Feathers widgets
- EditableText / richer fonts
- App settings framework
- Vignette / lens distortion
- Rectangular area lights (separate lighting spike)
- Physically based SSR
Tonight is bevy contact shadows only.
Discord / stand-up brief (copy/paste)
Bevy contact shadows spike (0.19+)
- Pin: Bevy ____
- Camera ContactShadows: yes/no
- Lights with contact: ____ (count ____)
- B1–B6: ____ / ____ / ____ / ____ / ____ / ____
- Before/after: ____
- Decision: keep | hold | rewrite
- Owners: eng ____ / art-producer ____
Paste into the stand-up channel your team already uses — do not invent a GamineAI community URL.
Key takeaways
- bevy contact shadows shipped in Bevy 0.19 as short-range soft contact without full raytracing.
- Add
ContactShadowsto the camera and setcontact_shadows_enabledon lights. - Supported light types: directional, point, spot.
- Shadow maps alone fail up close (peter-panning / acne) — contact is complementary.
- Cost scales with lit pixels × contact-enabled light count.
- Cap to one hero light for the first FPS gate.
- Gates B1–B6 make the evening auditable for eng and producers.
- File
bevy_contact_shadows_receipt_v1.jsonwith dual owners. - Do not confuse this with BSN, platformer, or schedule-debug evenings.
- Cite Bevy 0.19 when API field names drift on patches.
- Trailer density ≠ ship density — tag non-ship lighting honestly.
- Before/after stills beat “it looked nicer in the editor.”
FAQ
What are Bevy contact shadows?
A Bevy 0.19 feature that improves short-range shadow attachment and detail as a complement to shadow maps, without full raytracing (release notes).
How do I enable them?
Add the ContactShadows component to your camera and set contact_shadows_enabled: true on directional, point, or spot lights.
Do I still need shadow maps?
Yes for longer-range shadows. Contact shadows address the up-close failure modes shadow maps struggle with.
Which lights support contact shadows?
Directional, point, and spot lights per the 0.19 notes.
Why is nothing changing on screen?
Usual causes: missing camera ContactShadows, light flag still false, shadows disabled entirely, or ambient so bright contact is invisible. Walk B2–B3.
Are contact shadows free?
No. Cost scales with pixels lit by contact-enabled lights multiplied by how many such lights you enable.
Is this the same as Solari?
No. Contact shadows are called out as a polish path alongside the broader 0.19 lighting toolkit; Solari remains a different evaluation if you need that GI stack.
Is this the same as Bevy BSN?
No. BSN is scene notation — see Your First Bevy 0.19 BSN Scene.
How long should the spike take?
About 60–90 minutes for pin → camera + one light → before/after → receipt.
Should we migrate production the same night?
No. Keep the lab green, schedule lighting regression, then bump ship pins with owners named on the receipt.
Related reading
- Your First Bevy 0.19 BSN Scene - One Evening 2026
- Your First Bevy 0.17 2D Platformer - One Weekend 2026
- Bevy 0.17 ECS Plugin Schedule Order Debug - Fest Demo Menu Hitch
- How to Try Phaser Cone Lights - First Indie Flashlight Vision Spike 2026
- How to Try Godot AreaLight3D - First Indie Soft Light Spike 2026
- Your First BUILD_RECEIPT.json and Upload Log
- 25 Free Bevy Rust Game Development Resources 2026
- Bevy 0.17 Required Components Panic Fix
Official and useful sources
Conclusion
Bevy contact shadows turn floaty prop bases into readable soft contact — ContactShadows on the camera, per-light contact_shadows_enabled, and an honest cost model — without raytrace theater. Pin 0.19 on a lab 3D crate, prove one floor contact, fill B1–B6, then let humans own the ship merge. Bookmark this keep/hold beside the Bevy 0.19 notes and keep the receipt where producers can find it.