feat(studio): bind selected element properties to variables#2055
Conversation
This was referenced Jul 8, 2026
Collaborator
Author
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Open
4 tasks
Ninth PR of the template-variables stack: the promote-a-property gesture.
Select an element on the canvas/timeline, open the Variables tab, and the
panel offers per-property bind actions.
- "Bind selected" card in the Variables panel, built from the selection:
image/media source (img/video/audio), text, text color, background, and
font. Each action declares a variable whose default is the element's
CURRENT value (promoting never changes the render — computed rgb colors
convert to hex, the first computed font family becomes the font default)
and writes the declarative binding the runtime resolves: data-var-src /
data-var-text attributes or `<prop>: var(--id)` styles. Declare + bind
run as one batched schema edit (one undo step); binding to an
already-declared id skips the declare and just binds.
- guarded to selections from the composition the session models — a
selection in another source file never writes bindings into this one.
- core: extract readVariablesForElement into runtime/variableScope.ts,
shared by color grading and the declarative bindings (was duplicated).
- fix(studio-server): buildSubCompositionHtml's extractElementAttrs
rebuilt html/body attributes without HTML-escaping values, shredding
quote-bearing attributes — data-composition-variables (a JSON array)
came out as mangled bogus attributes, so getVariables() silently
returned {} on every /preview/comp/* page (no declared defaults, no
runtime bindings). Pre-existing bug surfaced by live-testing this
feature; regression test added.
Verified end-to-end in a live session: select headline → Bind text color
→ declaration + var(--headline-color) written to disk → override in the
panel → runtime applies the custom prop and the element renders the
override.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
605efea to
a6b9835
Compare
e2af893 to
18e9bfc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
Ninth PR of the template-variables stack: the promote-a-property gesture. Select an element on the canvas/timeline, open the Variables tab, and a "Bind selected" card offers per-property actions built from the selection:
<source>deliberately excluded, rewriting it post-resource-selection is a spec no-op) →data-var-srcdata-var-text<prop>: var(--id)style bindingsEach action declares a variable whose default is the element's current value (computed
rgb()/rgba()colors convert to hex; first computed font family becomes the font default). Declare + bind is one batched schema edit (single undo step). Binding to an existing id is allowed only when the types agree (toast otherwise); the card requires the SDK session to resolve the selected element (no dead binds on unmapped sub-comp elements) and resets its form state per selection.UX polish from live testing feedback:
Also fixes two pre-existing bugs surfaced by this work:
buildSubCompositionHtml'sextractElementAttrsrebuilt<html>/<body>attributes without HTML-escaping —data-composition-variables(JSON) was shredded into bogus markup, sogetVariables()silently returned{}on every/preview/comp/*page (regression test added)htmlExtractorhad the same escape gap for&Test plan
var(--headline-color)on disk → override in panel → player iframe carries the override, runtime applies the custom prop, element renders the override; tab-pinning and selection-swap verified live🤖 Generated with Claude Code