Acceptance Criteria
- A
frames registry exists in theme config, structurally parallel to backgrounds, with extends resolution shared with bg/tint. frame="preset" applies a named preset; inline frame-aspect|displace|offset|oversize|place|anchor|shadow override facets and work without a preset.offset is a named scale (none|sm|md|lg|xl) backed by --rf-spacing-*; the resolveOffset raw-length fallthrough is closed (unknown values warn).- The frame shadow facet renders as
drop-shadow (silhouette), never colliding with elevation's box-shadow.
Approach
Reuse the bg pipeline: engine.ts bg resolution, BgPresetDefinition, merge.ts extends. SPEC-086 §2.
Resolution
Completed: 2026-06-09
Branch: claude/spec-086-surface-chrome
What was done
FramePresetDefinition + ThemeConfig.frames (types.ts); mergeThemeConfig merges frames (merge.ts).frame + frame-{aspect,displace,offset,oversize,place,anchor,shadow} universal attributes (lib/index.ts, attribute-presets.ts), injected as <meta data-field> so the engine reads them via the bg meta channel.- Engine
resolveFrameChrome (engine.ts): resolves the preset (+ one extends level) and inline facet overrides; facets work standalone. - Completed the
offset named scale (none|sm|md|lg|xl → --rf-spacing-*) and closed resolveOffset's raw-length fallthrough (unknown → warn → none) in helpers.ts. frame-shadow renders as drop-shadow in dimensions/frame.css; elevation stays box-shadow — never collide.
Notes
- Tests in
packages/transform/test/frames.test.ts.