Version: blitz 0.3.0-alpha.2 (blitz-dom)
Platform: Linux (Vulkan/Wayland), likely cross-platform — bug is in Slab indexing logic.
Repro
use blitz_dom::{DocumentConfig, Document as _};
use blitz_html::HtmlDocument;
fn main() {
let html = r#"
<style>
@keyframes pulse { 0% { opacity: 1; } 100% { opacity: 0.5; } }
.pulse { animation: pulse 2s infinite; }
</style>
<div id="pulse-node" class="pulse">animated</div>
"#;
let mut doc = HtmlDocument::from_html(html, DocumentConfig::default());
// First resolve — animation entry is registered for #pulse-node in animations.sets.
doc.as_mut().resolve(0.0);
// Remove the animated element (its slab key is now freed).
let pulse_id = doc.inner().get_element_by_id("pulse-node");
if let Some(id) = pulse_id {
doc.inner_mut().mutate().remove_and_drop_node(id);
}
// Second resolve — panics: animations.sets still references the freed slab key.
doc.as_mut().resolve(0.1); // panics here
}
Any DOM removal of an element with an active CSS animation: rule followed by a second resolve() reproduces it. The same panic also occurs in the GUI event loop when blitz internally recreates nodes between frames.
Panic
thread 'main' panicked at blitz-dom-0.3.0-alpha.2/src/stylo.rs:83:23:
invalid key
Root Cause
In resolve_stylist() (around stylo.rs:83):
self.nodes[node_id].set_restyle_hint(RestyleHint::RESTYLE_SELF);
Flow:
- First resolve —
traverse_dom matches CSS animations against the DOM,
writes node_ids into animations.sets.
- The animated node is removed from the DOM (slab key freed).
- Second resolve — iterates
animations.sets and indexes self.nodes directly.
The slab key is stale, so the bracket index panics.
Proposed Fix
Use get_mut and skip stale entries:
let Some(node) = self.nodes.get_mut(node_id) else {
continue; // stale animation entry — skip safely
};
node.set_restyle_hint(RestyleHint::RESTYLE_SELF);
Vendored locally with this patch — reproducer passes cleanly, GUI event loop runs cleanly through hundreds of frames.
PR
Happy to submit a PR with the 1-line fix + regression test if it matches your design intent.
Drafted with Claude, fix and reproduction hand-verified.
Version: blitz 0.3.0-alpha.2 (blitz-dom)
Platform: Linux (Vulkan/Wayland), likely cross-platform — bug is in Slab indexing logic.
Repro
Any DOM removal of an element with an active CSS
animation:rule followed by a secondresolve()reproduces it. The same panic also occurs in the GUI event loop when blitz internally recreates nodes between frames.Panic
Root Cause
In
resolve_stylist()(around stylo.rs:83):Flow:
traverse_dommatches CSS animations against the DOM,writes
node_ids intoanimations.sets.animations.setsand indexesself.nodesdirectly.The slab key is stale, so the bracket index panics.
Proposed Fix
Use
get_mutand skip stale entries:Vendored locally with this patch — reproducer passes cleanly, GUI event loop runs cleanly through hundreds of frames.
PR
Happy to submit a PR with the 1-line fix + regression test if it matches your design intent.
Drafted with Claude, fix and reproduction hand-verified.