Repository navigation
Description
Describe the bug
Changing only an element's opacity with the SDK can permanently change its color. When the inline style contains an earlier !important declaration followed by an ordinary declaration of the same property, the SDK reads the ordinary value and writes it back during the unrelated edit. Saving, reopening and undoing the opacity edit keep the wrong color.
Minimal reproduction
Run this in a project using @hyperframes/sdk@0.8.193:
import { openComposition } from "@hyperframes/sdk";
const html = `<!doctype html><html><body>
<h1 data-hf-id="hf-title"
style="color: red !important; color: blue; font-size: 48px">
Release notes
</h1>
</body></html>`;
const comp = await openComposition(html, { coalesceMs: 0 });
comp.setStyle("hf-title", { opacity: "0.5" });
console.log(comp.serialize());
comp.undo();
console.log(comp.serialize());
comp.dispose();Steps to reproduce
- Open the HTML above. Its text renders red in Chrome because the earlier declaration is important.
- Change opacity with
setStyle()and serialize the composition. - Inspect the serialized style or reopen it in the browser.
- Undo the opacity edit and inspect the result again.
Expected behavior
The text remains red after the opacity edit, persistence, reopening and undo. The unrelated edit must preserve the declaration that determines its color.
Actual behavior
| Stage | Inline style | Computed color |
|---|---|---|
| Authored HTML | color: red !important; color: blue; font-size: 48px |
rgb(255, 0, 0) |
| Opacity edit | color: blue; font-size: 48px; opacity: 0.5 |
rgb(0, 0, 255) |
| Undo | color: blue; font-size: 48px |
rgb(0, 0, 255) |
The public element snapshot already reports blue before the edit. The patch stream records only opacity, so history cannot recover the lost color. The same loss survives the memory persistence adapter and a cancelled batch.
Environment
- SDK, core and parsers: published
0.8.193, with tarball integrity verified. - Reproduced on main
f21c3e3e7e8387ec9638cac2179f39c630ffabcfand independently verified with the exact latest-base model on6e77d783c7c19fa0c5c3833b7cf23d70fb14b70f. - Linux x64, Bun
1.4.4, Node26.11.1, Chrome152.0.7977.42.
Published package probes reused compatible external dependencies in isolation; this was not a clean consumer installation.
The reproduction uses valid inline CSS and the documented standalone SDK editing flow. No Studio UI or video render is needed.
Related work
SDK parser and parity work in #1350, #1565 and #5246 was checked, including reviews. The shorthand/longhand ordering case discussed in #1550 is separate from this duplicate-priority loss.
Activity
miguel-heygen commentedon Oct 25, 2026
Thanks for the clear repro. I can reproduce it with the latest published
@hyperframes/sdk0.8.194: aftersetStyle("hf-title", { opacity: "0.5" })the serialized style iscolor: blue; font-size: 48px; opacity: 0.5, and afterundo()it stayscolor: blue; font-size: 48px.The cause is
parseStyleAttrinpackages/sdk/src/engine/model.ts. It keeps the last declaration of each property regardless of!important, andsetStylewrites that whole map back, so any style edit on the element drops the earlier important declaration. Undo can't restore it because the edit only records the property that changed.#6268 fixes it in that function and is the one to follow.