-
-
-
-
- Open components
+
+
+
+
+ NPM
+
+
+ GitHub
-
+
)
}
-type ChapterMetaProps = {
- label: string
- meta: string
- number: string
-}
-
-function ChapterMeta({ label, meta, number }: ChapterMetaProps) {
+function renderHeroFeature(feature: HeroFeature): ReactNode {
return (
-
- {number}
- {label}
- {meta}
-
+
)
}
-type SubheadProps = {
- detail: string
- index: string
- title: string
-}
-
-function Subhead({ detail, index, title }: SubheadProps) {
+function renderSystemLayer(layer: SystemLayer): ReactNode {
return (
-
- {index}
- {title}
- {detail}
-
+
+
+ {layer.title}
+ {layer.description}
+
+ {renderLayerPreview(layer.key)}
+
+
)
}
-type SwatchGridProps = {
- stops: readonly (readonly [string, string, string])[]
+function renderLayerPreview(layer: SystemLayer['key']): ReactNode {
+ switch (layer) {
+ case 'applications':
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ Router
+ Ready
+
+
+ Eval batch
+ Queued
+
+
+
+
+
+
+ )
+ case 'components':
+ return (
+
+
+
+ {renderComponentExample('command-menu')}
+
+
+
+ )
+ case 'foundations':
+ return (
+
+
+ Ag
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ case 'primitives':
+ return (
+
+
+
+
+
+
+
Badge
+
+ Agent
+
+
+
+
+
+
+
+ )
+ }
}
-function SwatchGrid({ stops }: SwatchGridProps) {
+function renderPressureMode(mode: (typeof pressureModes)[number]): ReactNode {
return (
-
- {stops.map(([label, color, role], index) => (
- stops.length / 2 ? 'isLight' : undefined}
- key={label}
- style={{ '--home-swatch': color } as CSSProperties}
- >
- {label}
- {role}
-
- ))}
-
+
+
+ {mode.title}
+ {mode.mode}
+
+ {renderPressureDiagram(mode.title)}
+ {mode.body}
+
)
}
-function renderHomeTypeSample(sample: string, className: string) {
- const homeClassName = getHomeTypeClassName(className)
+function renderPressureDiagram(title: (typeof pressureModes)[number]['title']): ReactNode {
+ switch (title) {
+ case 'Editorial':
+ return (
+
+
Q2 conversion rose 18%
+
+
+
+
+
+ )
+ case 'Product':
+ return (
+
+
+
+
+
+
+
+
+ )
+ case 'Generative':
+ return (
+
+
Why did Q2 rise?
+
+
+
+
+ )
+ case 'Explainer':
+ return (
+
+ Input
+
+ Process
+
+ Output
+
+ )
+ }
+}
- return className === 'scaleBody' ? (
-
{sample}
- ) : (
-
{sample}
- )
+type SectionIntroProps = {
+ body: string
+ title: string
}
-function getHomeTypeClassName(className: string): string {
- switch (className) {
- case 'scaleDisplay':
- return 'displayRole'
- case 'scaleHero':
- return 'heroRole'
- default:
- return className
- }
+function SectionIntro({ body, title }: SectionIntroProps) {
+ return (
+
+ )
}
diff --git a/apps/docs/app/render/[kind]/[slug]/page.tsx b/apps/docs/app/render/[kind]/[slug]/page.tsx
index 119daa9..732930f 100644
--- a/apps/docs/app/render/[kind]/[slug]/page.tsx
+++ b/apps/docs/app/render/[kind]/[slug]/page.tsx
@@ -13,7 +13,8 @@ type RenderPageProps = {
export default async function RenderPage({ params, searchParams }: RenderPageProps) {
const routeParams = await params
- const query = parseRenderQuery(await searchParams)
+ const resolvedSearchParams = await searchParams
+ const query = parseRenderQuery(resolvedSearchParams)
const item = getCatalogRenderItem(routeParams.kind, routeParams.slug)
if (!item) {
@@ -24,8 +25,8 @@ export default async function RenderPage({ params, searchParams }: RenderPagePro
)
}
diff --git a/apps/docs/app/styles/base.css b/apps/docs/app/styles/base.css
index c566281..be270c7 100644
--- a/apps/docs/app/styles/base.css
+++ b/apps/docs/app/styles/base.css
@@ -60,16 +60,28 @@ body {
opacity: 1;
}
-.navIconLink {
+.navLogoLink {
justify-content: center;
- width: 28px;
+ width: 30px;
padding: 0;
+ border: 1px solid var(--concrete-border-soft);
+ background: var(--concrete-raised);
}
-.navIconLink svg {
+.navLogoLink svg {
+ display: block;
+ flex: none;
+}
+
+.npmLogo {
+ width: 22px;
+ height: 8px;
+}
+
+.githubLogo {
width: 15px;
height: 15px;
- fill: currentColor;
+ fill: currentcolor;
}
.main {
@@ -334,6 +346,66 @@ body {
align-items: stretch;
}
+.detailContractGrid {
+ display: grid;
+ grid-template-columns: minmax(0, 0.85fr) minmax(280px, 0.7fr) minmax(320px, 1fr);
+ gap: 12px;
+}
+
+.detailContractGrid article {
+ display: grid;
+ align-content: start;
+ gap: 10px;
+ min-width: 0;
+ padding: 16px;
+ border: 1px solid var(--concrete-border);
+ border-radius: var(--concrete-radius-4);
+ background: var(--concrete-surface);
+ box-shadow: var(--concrete-shadow-1);
+}
+
+.detailContractGrid svg {
+ width: 18px;
+ height: 18px;
+ color: var(--concrete-sky);
+}
+
+.detailContractGrid strong {
+ color: var(--concrete-foreground-strong);
+ font-size: 14px;
+ font-weight: 800;
+}
+
+.detailContractGrid p {
+ color: var(--concrete-foreground-muted);
+ font-size: 12.5px;
+ line-height: 1.55;
+}
+
+.detailRouteStack {
+ display: grid;
+ gap: 7px;
+}
+
+.detailRouteStack code {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.detailSeedCard pre {
+ max-height: 240px;
+ margin: 0;
+ padding: 12px;
+ overflow: auto;
+ border: 1px solid var(--concrete-border-soft);
+ border-radius: var(--concrete-radius-3);
+ background: var(--concrete-sunken);
+ color: var(--concrete-foreground-body);
+ font: 600 11px / 1.55 var(--concrete-font-mono);
+}
+
.playgroundPreview {
display: grid;
gap: 14px;
diff --git a/apps/docs/app/styles/home.css b/apps/docs/app/styles/home.css
index 9859295..6304c2b 100644
--- a/apps/docs/app/styles/home.css
+++ b/apps/docs/app/styles/home.css
@@ -1,910 +1,1309 @@
.docsHome {
- width: min(1120px, calc(100vw - 48px));
+ position: relative;
+ width: min(1320px, calc(100vw - 48px));
margin: 0 auto;
+ overflow-x: clip;
+ overflow-y: visible;
}
.docsChapter {
- padding: 72px 0;
+ padding: 48px 0;
border-bottom: 1px solid var(--concrete-border);
scroll-margin-top: 72px;
}
-.docsHero {
- padding-top: 64px;
-}
-
-.chapterMeta {
- display: grid;
- grid-template-columns: auto 1fr auto;
- gap: 12px;
- align-items: baseline;
- padding-bottom: 20px;
- border-bottom: 1px solid var(--concrete-ink-9);
- color: var(--concrete-foreground-muted);
- font-size: 12px;
- font-weight: 800;
+.homeKicker,
+.panelKicker {
+ color: var(--concrete-sky);
+ font: 800 10px / 1 var(--concrete-font-mono);
letter-spacing: 0.08em;
text-transform: uppercase;
}
-.chapterNumber {
- color: var(--concrete-sky);
+.heroEditorial h1,
+.sectionIntro h2,
+.agentIntro h2 {
+ margin: 0;
+ color: var(--concrete-foreground-strong);
font-family: var(--concrete-font-display);
- font-size: 28px;
- font-style: italic;
font-optical-sizing: var(--concrete-font-display-optical-sizing);
font-synthesis: none;
font-variation-settings: var(--concrete-font-display-settings);
font-weight: 400;
letter-spacing: 0;
- line-height: 1;
- text-transform: none;
+ text-wrap: balance;
}
-.chapterLabel {
- color: var(--concrete-foreground-muted);
+.docsHeroV3 {
+ position: relative;
+ display: grid;
+ grid-template-areas:
+ "copy preview"
+ "features preview";
+ grid-template-columns: minmax(0, 0.92fr) minmax(470px, 1.08fr);
+ gap: 18px 64px;
+ align-items: center;
+ min-height: 660px;
+ padding: 58px 0 58px;
+ overflow: visible;
+ border-bottom: 1px solid var(--concrete-border);
}
-.docsChapter h1,
-.docsChapter h2 {
- max-width: 820px;
- margin-top: 24px;
- color: var(--concrete-foreground-strong);
- font-family: var(--concrete-font-display);
- font-size: 72px;
- font-optical-sizing: var(--concrete-font-display-optical-sizing);
- font-synthesis: none;
- font-variation-settings: var(--concrete-font-display-settings);
- font-weight: 400;
- letter-spacing: 0;
- line-height: 0.98;
- text-wrap: balance;
+.homeLatticeField {
+ position: absolute;
+ inset: 0;
+ opacity: 0.68;
+ pointer-events: none;
+ mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
}
-.docsChapter h2 {
- max-width: 760px;
- font-size: 56px;
+.heroEditorial,
+.heroComponentMount,
+.heroFeatureRail {
+ position: relative;
+ z-index: 1;
+}
+
+.heroEditorial {
+ grid-area: copy;
+ min-width: 0;
+}
+
+.heroEditorial h1 {
+ max-width: 700px;
+ margin-top: 22px;
+ font-size: var(--concrete-type-72);
+ line-height: 0.94;
+}
+
+.heroShipWord {
+ font-style: italic;
+ font-weight: 650;
}
.docsLead {
- max-width: 760px;
+ max-width: 62ch;
margin-top: 22px;
color: var(--concrete-foreground-body);
- font-size: 17px;
- line-height: 1.6;
+ font-size: var(--concrete-type-17);
+ line-height: var(--concrete-line-loose);
}
-.heroInstall {
- display: inline-grid;
- grid-template-columns: auto minmax(0, 1fr);
+.heroCommandRow {
+ display: flex;
+ min-width: 0;
+ margin-top: 24px;
+}
+
+.copyCommand {
+ display: inline-flex;
align-items: center;
- max-width: 100%;
- margin-top: 18px;
+ box-sizing: border-box;
+ min-width: 0;
+ max-width: min(100%, 390px);
+ height: 34px;
+ padding: 0;
overflow: hidden;
- border: 1px solid var(--concrete-border);
+ border: 1px solid var(--concrete-ink-9);
border-radius: var(--concrete-radius-3);
- background: var(--concrete-surface);
- box-shadow: var(--concrete-shadow-1);
+ background: var(--concrete-ink-9);
+ box-shadow: var(--concrete-shadow-2);
+ color: var(--concrete-inverse-foreground);
+ font-family: var(--concrete-font-mono);
+ cursor: pointer;
}
-.heroInstall span,
-.heroInstall code {
+.copyCommand code {
+ flex: 1 1 auto;
min-width: 0;
- height: 34px;
+ padding: 0 13px;
+ overflow: hidden;
+ font: 800 var(--concrete-type-12) / 1 var(--concrete-font-mono);
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
-.heroInstall span {
+.copyCommand span {
display: inline-flex;
+ flex: none;
+ gap: 6px;
align-items: center;
- padding: 0 11px;
- border-right: 1px solid var(--concrete-border-soft);
- color: var(--concrete-foreground-muted);
- font: 800 11px / 1 var(--concrete-font-mono);
- letter-spacing: 0.08em;
+ align-self: stretch;
+ padding: 0 10px;
+ border-left: 1px solid var(--concrete-inverse-border);
+ color: var(--concrete-inverse-muted);
+ font: 800 10px / 1 var(--concrete-font-mono);
text-transform: uppercase;
}
-.heroInstall code {
- display: inline-flex;
+.copyCommand svg {
+ width: 13px;
+ height: 13px;
+}
+
+.heroComponentMount {
+ grid-area: preview;
+ display: grid;
+ gap: 12px;
+ align-content: center;
+ min-width: 0;
+}
+
+.heroComponentMount header {
+ display: flex;
align-items: center;
- padding: 0 12px;
- overflow: hidden;
- color: var(--concrete-foreground-strong);
- font: 700 13px / 1 var(--concrete-font-mono);
- text-overflow: ellipsis;
- white-space: nowrap;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 0 4px;
+ color: var(--concrete-foreground-soft);
+ font: 800 10px / 1 var(--concrete-font-mono);
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+.heroComponentMount em {
+ font-style: normal;
}
-.heroBillboard {
+.heroComposerStage {
display: grid;
- align-content: space-between;
- min-height: 330px;
- margin-top: 34px;
- padding: 32px;
- overflow: hidden;
- border: 1px solid var(--concrete-border);
- border-radius: var(--concrete-radius-4);
- background-color: var(--concrete-surface);
- background-image:
+ min-width: 0;
+ min-height: 318px;
+ place-items: center;
+ padding: 0;
+ overflow: visible;
+}
+
+.heroComposerStage > * {
+ width: 100%;
+ max-width: 690px;
+ min-width: 0;
+}
+
+.heroFeatureRail {
+ grid-area: features;
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 10px 14px;
+ max-width: 560px;
+ margin-top: 4px;
+ pointer-events: none;
+}
+
+.heroFeatureRail .homeFeatureCard .concrete-tilt-frame-surface {
+ height: 100%;
+ border: 0;
+ border-radius: 0;
+ background: transparent;
+ box-shadow: none;
+}
+
+.heroFeatureRail .homeFeatureCard .concrete-tilt-frame-content {
+ grid-template-columns: auto minmax(0, 1fr);
+ place-items: start;
+ gap: 7px;
+ min-height: 0;
+ padding: 0;
+ text-align: left;
+}
+
+.heroFeatureRail [data-slot="feature-card-icon"] {
+ width: 22px;
+ height: 22px;
+ border-radius: var(--concrete-radius-2);
+ box-shadow: none;
+}
+
+.heroFeatureRail [data-slot="feature-card-icon"] svg {
+ width: 12px;
+ height: 12px;
+}
+
+.heroFeatureRail [data-slot="feature-card-body"] {
+ gap: 2px;
+ justify-items: start;
+}
+
+.heroFeatureRail [data-slot="feature-card-body"] strong {
+ font-size: var(--concrete-type-11);
+ line-height: 1.1;
+}
+
+.heroFeatureRail [data-slot="feature-card-body"] span {
+ max-width: none;
+ font-size: 10.5px;
+ line-height: 1.25;
+}
+
+.sectionIntro {
+ display: grid;
+ gap: 10px;
+ max-width: 860px;
+ margin-bottom: 22px;
+}
+
+.sectionIntro h2 {
+ max-width: 14ch;
+ font-size: var(--concrete-type-56);
+ line-height: 0.98;
+}
+
+.sectionIntro p {
+ max-width: 72ch;
+ color: var(--concrete-foreground-muted);
+ font-size: var(--concrete-type-14);
+ line-height: var(--concrete-line-loose);
+}
+
+.systemShowcase {
+ position: relative;
+ padding: 24px 0 28px;
+ overflow: visible;
+}
+
+.systemShowcase::before {
+ position: absolute;
+ right: -10%;
+ bottom: -72px;
+ left: -10%;
+ height: 190px;
+ background:
+ linear-gradient(color-mix(in oklab, var(--concrete-sky) 18%, transparent) 1px, transparent 1px),
linear-gradient(
- 135deg,
- color-mix(in oklab, var(--concrete-sky) 10%, transparent),
- transparent 42%
+ 90deg,
+ color-mix(in oklab, var(--concrete-sky) 18%, transparent) 1px,
+ transparent 1px
),
- linear-gradient(90deg, var(--concrete-lattice) 1px, transparent 1px),
- linear-gradient(var(--concrete-lattice) 1px, transparent 1px);
+ linear-gradient(180deg, transparent, color-mix(in oklab, var(--concrete-sky) 5%, transparent));
background-size:
- auto,
- 28px 28px,
- 28px 28px;
- box-shadow: var(--concrete-shadow-2);
+ 32px 32px,
+ 32px 32px,
+ 100% 100%;
+ content: "";
+ opacity: 0.58;
+ transform: perspective(680px) rotateX(66deg);
+ transform-origin: bottom center;
}
-.heroKicker,
-.heroStrip {
- color: var(--concrete-foreground-muted);
- font: 800 12px / 1 var(--concrete-font-mono);
- letter-spacing: 0.08em;
- text-transform: uppercase;
+.systemShowcase::after {
+ position: absolute;
+ right: -3%;
+ bottom: 54px;
+ left: -3%;
+ height: 1px;
+ background: linear-gradient(90deg, transparent, var(--concrete-border), transparent);
+ content: "";
+ opacity: 0.8;
+ pointer-events: none;
}
-.heroBillboard p {
- max-width: 720px;
- margin: 0;
+.systemLayerGrid {
+ position: relative;
+ z-index: 1;
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 26px;
+}
+
+.systemLayerCard {
+ position: relative;
+ display: grid;
+ grid-template-rows: auto minmax(104px, 1fr) auto;
+ gap: 10px;
+ min-width: 0;
+ height: 270px;
+ padding: 16px;
+ overflow: visible;
+ border: 1px solid var(--concrete-border);
+ border-radius: var(--concrete-radius-4);
+ background: color-mix(in oklab, var(--concrete-surface) 93%, transparent);
+ box-shadow:
+ 0 8px 22px rgb(17 24 39 / 5%),
+ 0 1px 0 var(--concrete-border);
+ backdrop-filter: blur(8px);
+}
+
+.systemLayerCard:not(:last-child)::after {
+ position: absolute;
+ top: 50%;
+ right: -25px;
+ z-index: 3;
+ width: 24px;
+ border-top: 1px dashed color-mix(in oklab, var(--concrete-sky) 34%, var(--concrete-border));
+ content: "";
+}
+
+.systemLayerCard:not(:last-child)::before {
+ position: absolute;
+ top: calc(50% - 4px);
+ right: -26px;
+ z-index: 4;
+ width: 7px;
+ height: 7px;
+ border-top: 1px solid color-mix(in oklab, var(--concrete-sky) 42%, var(--concrete-border-strong));
+ border-right: 1px solid color-mix(in oklab, var(--concrete-sky) 42%, var(--concrete-border-strong));
+ content: "";
+ transform: rotate(45deg);
+}
+
+.systemLayerCard header {
+ display: grid;
+ gap: 4px;
+ min-width: 0;
+}
+
+.docsHome .systemLayerCard header strong {
color: var(--concrete-foreground-strong);
- font-family: var(--concrete-font-display);
- font-size: 72px;
- font-optical-sizing: var(--concrete-font-display-optical-sizing);
- font-synthesis: none;
- font-variation-settings: var(--concrete-font-display-settings);
- font-weight: 400;
- letter-spacing: 0;
- line-height: 0.94;
+ font-size: var(--concrete-type-15);
+ font-weight: 850;
}
-.heroBillboard em {
- font-synthesis: none;
- font-style: italic;
+.systemLayerCard header span {
+ color: var(--concrete-foreground-muted);
+ font-size: var(--concrete-type-12);
+ line-height: var(--concrete-line-normal);
}
-.heroStrip {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- padding-top: 16px;
- border-top: 1px solid var(--concrete-border);
+.systemLayerPreview {
+ display: grid;
+ min-width: 0;
+ min-height: 0;
+ align-content: stretch;
+ overflow: visible;
}
-.heroStrip span {
- display: inline-flex;
+.systemLayerCard footer {
+ display: flex;
+ gap: 10px;
align-items: center;
- height: 24px;
- padding: 0 8px;
- border: 1px solid var(--concrete-border-soft);
- border-radius: var(--concrete-radius-pill);
- background: color-mix(in oklab, var(--concrete-surface) 68%, transparent);
+ justify-content: space-between;
+ align-self: end;
+ min-width: 0;
}
-.docsSubhead {
- display: grid;
- grid-template-columns: 60px 1fr auto;
- gap: 14px;
- align-items: baseline;
- margin: 42px 0 16px;
+.systemLayerItems {
+ display: flex;
+ flex-wrap: nowrap;
+ gap: 0 7px;
+ align-content: start;
+ min-width: 0;
+ overflow: hidden;
+ color: var(--concrete-foreground-muted);
+ font-size: 9.5px;
+ font-weight: 700;
+ line-height: var(--concrete-line-normal);
+ white-space: nowrap;
}
-.docsSubhead span {
+.systemLayerItems span:not(:last-child)::after {
+ margin-left: 7px;
color: var(--concrete-foreground-soft);
- font: 800 12px / 1 var(--concrete-font-mono);
- letter-spacing: 0.08em;
+ content: "·";
}
-.docsSubhead strong {
- color: var(--concrete-foreground-strong);
- font-size: 15px;
+.systemLayerCard a {
+ display: inline-flex;
+ align-items: center;
+ flex: none;
+ justify-self: end;
+ color: var(--concrete-foreground-soft);
+ font-size: 10.5px;
font-weight: 800;
}
-.docsSubhead em {
+.systemLayerCard a:hover {
color: var(--concrete-foreground-muted);
- font-size: 13px;
- font-style: normal;
}
-.foundationSplit {
+.foundationPreview,
+.primitivePreviewList,
+.componentPreviewCard,
+.applicationPreview {
display: grid;
- grid-template-columns: minmax(0, 1.1fr) minmax(360px, 0.9fr);
- gap: 16px;
-}
-
-.typeSpecimen,
-.typeScaleCompact,
-.colorFigure,
-.densityGrid,
-.foundationTrio,
-.foundationUtilityGrid,
-.iconSystem,
-.homePrimitiveCard,
-.componentFeatureCard,
-.apiGrid > *,
-.apiFooter {
- border: 1px solid var(--concrete-border);
- border-radius: var(--concrete-radius-4);
- background: var(--concrete-surface);
- box-shadow: var(--concrete-shadow-1);
+ width: 100%;
+ height: 100%;
+ min-width: 0;
}
-.typeSpecimen {
- display: grid;
- min-height: 370px;
- align-items: center;
- padding: 40px;
- background-image:
- linear-gradient(90deg, var(--concrete-lattice) 1px, transparent 1px),
- linear-gradient(var(--concrete-lattice) 1px, transparent 1px);
- background-size: 24px 24px;
+.foundationPreview {
+ position: relative;
+ align-content: center;
+ gap: 14px;
+ padding: 0;
+ overflow: visible;
}
-.typeSpecimen p {
- margin: 0;
+.foundationSpecimen {
+ display: block;
+}
+
+.systemLayerPreview .foundationSpecimen strong {
color: var(--concrete-foreground-strong);
font-family: var(--concrete-font-display);
- font-size: 92px;
- font-optical-sizing: var(--concrete-font-display-optical-sizing);
- font-synthesis: none;
- font-variation-settings: var(--concrete-font-display-settings);
+ font-size: 48px;
font-weight: 400;
letter-spacing: 0;
- line-height: 0.9;
+ line-height: 0.85;
}
-.typeSpecimen em {
- font-style: italic;
+.miniSwatches {
+ display: grid;
+ grid-template-columns: repeat(5, 19px);
+ gap: 6px;
+ align-items: center;
}
-.typeScaleCompact {
- display: grid;
- align-content: start;
- overflow: hidden;
+.miniSwatches span {
+ width: 19px;
+ height: 19px;
+ border: 1px solid var(--concrete-border);
+ border-radius: var(--concrete-radius-2);
+ box-shadow: var(--concrete-shadow-1);
}
-.typeScaleCompact > div {
- display: grid;
- grid-template-columns: 84px minmax(0, 1fr);
- gap: 14px;
- align-items: baseline;
- min-height: 74px;
- padding: 16px;
- border-bottom: 1px solid var(--concrete-border-soft);
+.miniSwatches span:nth-child(1) {
+ background: var(--concrete-sky);
}
-.typeScaleCompact > div:last-child {
- border-bottom: 0;
+.miniSwatches span:nth-child(2) {
+ background: var(--concrete-sky-2);
}
-.typeScaleCompact span,
-.typeScaleCompact em {
- color: var(--concrete-foreground-soft);
- font: 800 11px / 1.2 var(--concrete-font-mono);
- font-style: normal;
- letter-spacing: 0.06em;
- text-transform: uppercase;
+.miniSwatches span:nth-child(3) {
+ background: var(--concrete-ink-9);
}
-.typeScaleCompact strong,
-.typeScaleCompact p {
- margin: 0;
- color: var(--concrete-foreground-strong);
- font-size: 32px;
- font-weight: 800;
- line-height: 1.05;
+.miniSwatches span:nth-child(4) {
+ background: var(--concrete-ink-2);
}
-.typeScaleCompact em {
- grid-column: 2;
+.miniSwatches span:nth-child(5) {
+ background: var(--concrete-surface);
}
-.typeScaleCompact p {
- font-size: 15px;
- font-weight: 400;
- line-height: 1.45;
+.foundationMarks {
+ display: flex;
+ gap: 7px;
+ align-items: center;
+ padding-top: 2px;
}
-.typeScaleCompact .displayRole,
-.typeScaleCompact .heroRole {
- font-family: var(--concrete-font-display);
- font-optical-sizing: var(--concrete-font-display-optical-sizing);
- font-synthesis: none;
- font-variation-settings: var(--concrete-font-display-settings);
- font-weight: 400;
+.foundationMarks span {
+ display: block;
+ height: 15px;
+ border: 1px solid var(--concrete-border);
+ border-radius: var(--concrete-radius-3);
+ background: var(--concrete-raised);
+ box-shadow: inset 0 1px 0 var(--concrete-surface);
}
-.typeScaleCompact .displayRole {
- font-size: 68px;
+.foundationMarks span:nth-child(1) {
+ width: 22px;
+ border-radius: var(--concrete-radius-1);
}
-.typeScaleCompact .heroRole {
- font-size: 46px;
+.foundationMarks span:nth-child(2) {
+ width: 35px;
+ border-radius: var(--concrete-radius-3);
}
-.colorFigure {
- display: grid;
- gap: 1px;
- overflow: hidden;
- background: var(--concrete-border-soft);
+.foundationMarks span:nth-child(3) {
+ width: 50px;
+ border-radius: var(--concrete-radius-5);
}
-.swatchGridCompact {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
- gap: 1px;
+.primitivePreviewList {
+ gap: 8px;
+ align-content: center;
+ padding: 2px;
}
-.swatchGridCompact span {
+.primitivePreviewRow {
display: grid;
- align-content: space-between;
- min-height: 118px;
- padding: 12px;
- background: var(--home-swatch);
- color: #fff;
+ grid-template-columns: 82px 1fr;
+ gap: 10px;
+ align-items: center;
}
-.swatchGridCompact .isLight {
- color: var(--concrete-foreground-strong);
+.primitivePreviewPillLine {
+ display: flex;
+ flex-wrap: nowrap;
+ gap: 9px;
+ align-items: center;
+ min-width: 0;
+ padding-left: 4px;
}
-.swatchGridCompact b,
-.swatchGridCompact i {
- display: block;
+.primitiveInlineControls {
+ display: inline-flex;
+ gap: 8px;
+ align-items: center;
+ justify-content: flex-start;
+ margin-left: auto;
min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
}
-.swatchGridCompact b {
- font-size: 12px;
- font-weight: 800;
+.primitivePreviewList .concrete-field {
+ width: 100%;
}
-.swatchGridCompact i {
- align-self: end;
- font-size: 11px;
- font-style: normal;
- font-weight: 700;
- opacity: 0.72;
+.componentPreviewCard,
+.applicationPreview {
+ align-items: center;
+ justify-items: center;
+ overflow: visible;
+}
+
+.systemScaleFrame,
+.systemScaleFrame .concrete-scale-frame-surface {
+ width: 100%;
+ height: 100%;
}
-.signalGrid {
+.systemScaledComponent {
display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 1px;
+ transform-origin: center;
}
-.signalTile {
+.systemScaledComponentMenu {
+ width: 360px;
+}
+
+.systemScaledApplication {
+ width: 400px;
+}
+
+.applicationDashboardPreview {
display: grid;
- grid-template-columns: auto 1fr;
- gap: 3px 10px;
- align-items: center;
- min-height: 78px;
- padding: 14px;
+ gap: 8px;
+ width: 400px;
+ padding: 11px;
+ border: 1px solid var(--concrete-border);
+ border-radius: var(--concrete-radius-4);
background: var(--concrete-surface);
+ box-shadow: var(--concrete-shadow-1);
}
-.signalTile i {
- grid-row: span 2;
- width: 12px;
- height: 12px;
- border-radius: var(--concrete-radius-pill);
- box-shadow: 0 0 0 4px color-mix(in oklab, currentColor 8%, transparent);
+.applicationDashboardPreview header,
+.applicationDashboardRows span {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
}
-.signalTile b {
+.docsHome .applicationDashboardPreview header strong {
color: var(--concrete-foreground-strong);
- font-size: 13px;
- text-transform: capitalize;
+ font-size: var(--concrete-type-13);
+ font-weight: 850;
+}
+
+.applicationDashboardMetrics {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 6px;
}
-.signalTile span {
+.applicationDashboardRows {
+ display: grid;
+ border: 1px solid var(--concrete-border-soft);
+ border-radius: var(--concrete-radius-3);
+ overflow: hidden;
+}
+
+.applicationDashboardRows span {
+ padding: 7px 9px;
+ border-bottom: 1px solid var(--concrete-border-soft);
color: var(--concrete-foreground-muted);
- font-size: 12px;
+ font-size: var(--concrete-type-11);
+}
+
+.applicationDashboardRows span:last-child {
+ border-bottom: 0;
+}
+
+.applicationDashboardRows b {
+ color: var(--concrete-foreground-strong);
+ font-weight: 800;
}
-.densityGrid {
+.applicationDashboardRows em {
+ color: var(--concrete-terminal);
+ font-style: normal;
+ font-weight: 800;
+}
+
+.pressureExplainer {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
overflow: hidden;
+ border: 1px solid var(--concrete-border);
+ border-radius: var(--concrete-radius-5);
+ background: var(--concrete-surface);
+ box-shadow:
+ 0 8px 22px rgb(17 24 39 / 4%),
+ 0 1px 0 var(--concrete-border);
}
-.densityGrid article {
+.pressureMode {
display: grid;
- gap: 4px;
+ grid-template-rows: auto 136px auto;
+ gap: 12px;
+ min-width: 0;
padding: 16px;
border-right: 1px solid var(--concrete-border);
}
-.densityGrid article:last-child {
- border-right: 0;
+.pressureMode:last-child {
+ border-right: 0;
+}
+
+.pressureMode header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding-bottom: 10px;
+ border-bottom: 1px solid var(--concrete-border-soft);
+}
+
+.docsHome .pressureMode header strong {
+ color: var(--concrete-foreground-strong);
+ font-size: var(--concrete-type-12);
+ font-weight: 850;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+
+.pressureMode header em {
+ padding: 3px 8px;
+ border: 1px solid var(--concrete-border-soft);
+ border-radius: var(--concrete-radius-pill);
+ background: transparent;
+ color: var(--concrete-foreground-muted);
+ font-style: normal;
+ font-size: 10.5px;
+ font-weight: 750;
+}
+
+.pressureDiagram {
+ position: relative;
+ display: grid;
+ height: 136px;
+ gap: 7px;
+ align-content: center;
+ padding: 14px;
+ overflow: hidden;
+ border: 1px solid var(--concrete-border-soft);
+ border-radius: var(--concrete-radius-4);
+ background: var(--concrete-raised);
+}
+
+.pressureEditorialDiagram {
+ align-content: start;
+ padding: 18px;
+ background:
+ linear-gradient(color-mix(in oklab, var(--concrete-ultra) 7%, transparent) 1px, transparent 1px),
+ linear-gradient(
+ 90deg,
+ color-mix(in oklab, var(--concrete-ultra) 7%, transparent) 1px,
+ transparent 1px
+ ),
+ var(--concrete-surface);
+ background-size: 34px 34px;
+}
+
+.docsHome .pressureEditorialDiagram strong {
+ max-width: 11ch;
+ color: var(--concrete-foreground-strong);
+ font-family: var(--concrete-font-display);
+ font-size: var(--concrete-type-22);
+ font-weight: 400;
+ line-height: 0.98;
+}
+
+.pressureEditorialDiagram span {
+ position: absolute;
+ left: 18px;
+ height: 3px;
+ border-radius: var(--concrete-radius-pill);
+ background: color-mix(in oklab, var(--concrete-ink-3) 58%, transparent);
+}
+
+.pressureEditorialDiagram span:nth-of-type(1) {
+ top: 80px;
+ width: 72px;
+}
+
+.pressureEditorialDiagram span:nth-of-type(2) {
+ top: 91px;
+ width: 54px;
+}
+
+.pressureEditorialDiagram span:nth-of-type(3) {
+ top: 102px;
+ width: 64px;
}
-.densityGrid strong {
- color: var(--concrete-foreground-strong);
- font-size: 15px;
+.pressureMiniChart {
+ position: absolute;
+ right: 14px;
+ bottom: 13px;
+ width: 92px;
+ height: 56px;
+ overflow: visible;
}
-.densityGrid span {
- color: var(--concrete-foreground-muted);
- font-size: 12px;
- line-height: 1.45;
+.pressureMiniChart path {
+ stroke-linecap: round;
+ stroke-linejoin: round;
}
-.densityGrid i {
- display: block;
- height: 178px;
- margin-top: 12px;
- border: 1px solid var(--concrete-border-soft);
- border-radius: var(--concrete-radius-3);
- background-color: var(--concrete-surface);
+.pressureMiniChart path:nth-of-type(1) {
+ fill: color-mix(in oklab, var(--concrete-sky) 9%, transparent);
+ stroke: none;
}
-.densityGrid i[data-density="editorial"] {
- background-image:
- linear-gradient(
- 90deg,
- color-mix(in oklab, var(--concrete-ultra) 16%, transparent) 1px,
- transparent 1px
- ),
- linear-gradient(color-mix(in oklab, var(--concrete-ultra) 10%, transparent) 1px, transparent 1px);
- background-size: 42px 28px;
+.pressureMiniChart path:nth-of-type(2) {
+ fill: none;
+ stroke: color-mix(in oklab, var(--concrete-sky) 72%, var(--concrete-foreground-muted));
+ stroke-width: 2;
+}
+
+.pressureMiniChart path:nth-of-type(3) {
+ fill: none;
+ stroke: var(--concrete-border);
+ stroke-width: 1;
}
-.densityGrid i[data-density="product"] {
- background-image:
+.pressureProductDiagram {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ grid-template-rows: repeat(3, minmax(0, 1fr));
+ gap: 6px;
+ padding: 10px;
+ background:
+ linear-gradient(color-mix(in oklab, var(--concrete-sky) 13%, transparent) 1px, transparent 1px),
linear-gradient(
90deg,
- color-mix(in oklab, var(--concrete-sky) 16%, transparent) 1px,
+ color-mix(in oklab, var(--concrete-sky) 13%, transparent) 1px,
transparent 1px
),
- linear-gradient(color-mix(in oklab, var(--concrete-sky) 12%, transparent) 1px, transparent 1px);
- background-size: 14px 14px;
+ color-mix(in oklab, var(--concrete-sky) 2%, var(--concrete-surface));
+ background-size: 11px 11px;
}
-.densityGrid i[data-density="generative"] {
- background-image: linear-gradient(
- color-mix(in oklab, var(--concrete-terminal) 15%, transparent) 1px,
- transparent 1px
- );
- background-size: 100% 28px;
+.pressureProductDiagram span {
+ border: 1px solid color-mix(in oklab, var(--concrete-sky) 22%, var(--concrete-border));
+ border-radius: var(--concrete-radius-3);
+ background: var(--concrete-surface);
}
-.densityGrid i[data-density="educational"] {
- background:
- linear-gradient(var(--concrete-surface), var(--concrete-surface)) center 38px / 72% 26px no-repeat,
- linear-gradient(var(--concrete-surface), var(--concrete-surface)) center 88px / 58% 26px no-repeat,
- linear-gradient(var(--concrete-surface), var(--concrete-surface)) center 138px / 66% 26px
- no-repeat,
- var(--concrete-sunken);
+.pressureProductDiagram span:nth-child(1) {
+ grid-column: span 2;
}
-.foundationTrio {
- display: grid;
- grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.9fr) minmax(220px, 0.8fr);
- gap: 0;
- overflow: hidden;
+.pressureProductDiagram span:nth-child(2) {
+ grid-column: span 2;
}
-.spacingScale {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- border-right: 1px solid var(--concrete-border);
+.pressureProductDiagram span:nth-child(3) {
+ grid-column: span 3;
}
-.spacingScale span {
- display: grid;
- align-content: end;
- min-height: 118px;
- padding: 12px;
- border-right: 1px solid var(--concrete-border-soft);
- color: var(--concrete-foreground-muted);
+.pressureProductDiagram span:nth-child(4) {
+ background: color-mix(in oklab, var(--concrete-sky) 10%, var(--concrete-surface));
}
-.spacingScale span:nth-child(4n) {
- border-right: 0;
+.pressureProductDiagram span:nth-child(5) {
+ grid-column: span 2;
}
-.spacingScale span::before {
- content: "";
- display: block;
- width: var(--home-space);
- height: var(--home-space);
- margin-bottom: 12px;
- border-radius: var(--concrete-radius-2);
- background: var(--concrete-sky-2);
- box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--concrete-sky) 14%, transparent);
+.pressureProductDiagram span:nth-child(6) {
+ grid-column: span 2;
+ background: color-mix(in oklab, var(--concrete-sky) 6%, var(--concrete-surface));
}
-.spacingScale b,
-.spacingScale i,
-.spacingScale em {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
+.pressureGenerativeDiagram {
+ align-content: start;
+ gap: 7px;
+ padding: 12px;
+ background:
+ linear-gradient(
+ 180deg,
+ transparent 0 16px,
+ color-mix(in oklab, var(--concrete-terminal) 9%, transparent) 16px 17px,
+ transparent 17px 32px
+ ),
+ var(--concrete-surface);
+ background-size: 100% 32px;
}
-.spacingScale b {
+.docsHome .pressureGenerativeDiagram strong {
+ justify-self: start;
+ padding: 6px 9px;
+ border-radius: var(--concrete-radius-pill);
+ background: color-mix(in oklab, var(--concrete-ink-2) 64%, var(--concrete-surface));
color: var(--concrete-foreground-strong);
- font-size: 12px;
- text-transform: uppercase;
+ font-size: var(--concrete-type-11);
+ font-weight: 750;
}
-.spacingScale i {
- font: 800 11px / 1.3 var(--concrete-font-mono);
- font-style: normal;
+.pressureGenerativeDiagram span {
+ display: block;
+ height: 26px;
+ border: 1px solid color-mix(in oklab, var(--concrete-sky) 10%, var(--concrete-border));
+ border-radius: var(--concrete-radius-3);
+ background: var(--concrete-surface);
}
-.spacingScale em {
- color: var(--concrete-foreground-soft);
- font-size: 11px;
- font-style: normal;
- font-weight: 700;
+.pressureGenerativeDiagram span:nth-of-type(1) {
+ width: 84%;
}
-.radiusGrid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- border-right: 1px solid var(--concrete-border);
+.pressureGenerativeDiagram span:nth-of-type(2) {
+ width: 72%;
}
-.radiusGrid article {
- display: grid;
- gap: 6px;
- padding: 12px;
- border-right: 1px solid var(--concrete-border-soft);
- border-bottom: 1px solid var(--concrete-border-soft);
+.pressureTinySparkline {
+ width: 64%;
+ height: 22px;
}
-.radiusGrid article:nth-child(2n) {
- border-right: 0;
+.pressureTinySparkline path {
+ fill: none;
+ stroke: color-mix(in oklab, var(--concrete-sky) 58%, var(--concrete-foreground-muted));
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ stroke-width: 2;
}
-.radiusGrid i {
- display: block;
- height: 44px;
- border: 1px solid var(--concrete-border);
- border-radius: var(--home-radius);
- background: var(--concrete-sunken);
+.pressureExplainerDiagram {
+ place-items: center;
+ grid-template-rows: auto minmax(10px, 1fr) auto minmax(10px, 1fr) auto;
+ gap: 0;
+ padding: 16px 0;
+ background:
+ radial-gradient(
+ color-mix(in oklab, var(--concrete-ink-5) 36%, transparent) 1px,
+ transparent 1.5px
+ ),
+ color-mix(in oklab, var(--concrete-mist) 56%, var(--concrete-surface));
+ background-size: 16px 16px;
}
-.radiusGrid b {
+.pressureExplainerDiagram span {
+ position: relative;
+ width: 72px;
+ padding: 5px 0;
+ border: 1px solid var(--concrete-border);
+ border-radius: var(--concrete-radius-2);
+ background: var(--concrete-surface);
color: var(--concrete-foreground-strong);
- font: 800 11px / 1 var(--concrete-font-mono);
+ text-align: center;
+ font-size: 10px;
+ font-weight: 800;
}
-.radiusGrid span {
- color: var(--concrete-foreground-muted);
- font-size: 11px;
+.pressureExplainerDiagram i {
+ position: relative;
+ width: 1px;
+ height: 100%;
+ min-height: 10px;
+ background: color-mix(in oklab, var(--concrete-sky) 28%, var(--concrete-border-strong));
+ transform-origin: center;
}
-.elevationGrid {
- display: grid;
- align-content: stretch;
- gap: 10px;
- padding: 14px;
+.pressureExplainerDiagram i::after {
+ position: absolute;
+ right: -2px;
+ bottom: 0;
+ width: 5px;
+ height: 5px;
+ border-right: 1px solid var(--concrete-border-strong);
+ border-bottom: 1px solid var(--concrete-border-strong);
+ content: "";
+ transform: rotate(45deg);
}
-.elevationGrid span {
- display: grid;
- place-items: center;
- min-height: 48px;
- border: 1px solid var(--concrete-border);
- border-radius: var(--concrete-radius-3);
- background: var(--concrete-surface);
+.pressureMode p {
color: var(--concrete-foreground-muted);
- font-size: 12px;
- font-weight: 800;
+ font-size: var(--concrete-type-12);
+ line-height: var(--concrete-line-loose);
}
-.elevationGrid span:nth-child(2) {
- box-shadow: var(--concrete-shadow-1);
+.agentChapter {
+ position: relative;
+ display: grid;
+ grid-template-columns: minmax(320px, 0.9fr) minmax(0, 1.1fr);
+ gap: 42px;
+ margin: 48px 0;
+ padding: 36px;
+ overflow: hidden;
+ border: 1px solid var(--concrete-inverse-border);
+ border-radius: var(--concrete-radius-5);
+ background: var(--concrete-depth-background);
+ color: var(--concrete-inverse-foreground);
+ box-shadow: 0 1px 0 var(--concrete-inverse-border);
}
-.elevationGrid span:nth-child(3) {
- box-shadow: var(--concrete-shadow-2);
+.agentDepthTexture {
+ position: absolute;
+ inset: 0;
+ opacity: 0.48;
+ pointer-events: none;
}
-.elevationGrid span:nth-child(4) {
- box-shadow: var(--concrete-shadow-3);
+.agentIntro,
+.agentContractSurface {
+ position: relative;
+ z-index: 1;
}
-.foundationUtilityGrid {
+.agentIntro {
display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0;
- overflow: hidden;
+ align-content: start;
+ gap: 20px;
}
-.motionFigure,
-.focusFigure,
-.textureFigure {
- display: grid;
- gap: 12px;
- min-height: 190px;
- padding: 16px;
- border-right: 1px solid var(--concrete-border);
+.agentIntro h2 {
+ max-width: 10ch;
+ color: var(--concrete-inverse-foreground);
+ font-size: var(--concrete-type-40);
+ line-height: 1.02;
}
-.textureFigure {
- border-right: 0;
- grid-template-columns: repeat(3, 1fr);
+.agentIntro p {
+ max-width: 48ch;
+ color: var(--concrete-inverse-muted);
+ font-size: var(--concrete-type-13);
+ line-height: var(--concrete-line-loose);
}
-.motionFigure span {
+.agentContractList {
display: grid;
- place-items: center;
- border: 1px solid var(--concrete-border-soft);
- border-radius: var(--concrete-radius-3);
- background: var(--concrete-raised);
- color: var(--concrete-foreground-muted);
- font-size: 12px;
- font-weight: 800;
- transition:
- transform var(--concrete-duration-fast) var(--concrete-ease),
- background var(--concrete-duration-fast) var(--concrete-ease);
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 9px;
}
-.motionFigure span:hover {
- transform: translateY(-1px);
- background: var(--concrete-surface);
+.agentContractList span {
+ display: inline-flex;
+ gap: 7px;
+ align-items: center;
+ color: var(--concrete-inverse-muted);
+ font-size: var(--concrete-type-12);
+ font-weight: 700;
}
-.focusFigure {
- align-content: center;
+.agentContractList svg {
+ width: 14px;
+ height: 14px;
+ color: var(--concrete-terminal);
}
-.focusFigure > * {
- justify-self: start;
+.agentGithubCallout {
+ display: grid;
+ gap: 8px;
+ margin-top: 8px;
+ padding: 14px;
+ border: 1px solid var(--concrete-inverse-border);
+ border-radius: var(--concrete-radius-4);
+ background: color-mix(in oklab, var(--concrete-ink-9) 62%, transparent);
}
-.homeFocusedButton {
- outline: 3px solid var(--concrete-focus-ring);
- outline-offset: 2px;
+.agentChapter .agentGithubCallout strong {
+ color: var(--concrete-inverse-foreground);
+ font-size: var(--concrete-type-13);
+ font-weight: 850;
}
-.textureFigure > div {
- min-height: 100%;
- border: 1px solid var(--concrete-border-soft);
+.agentChapter .agentGithubCallout p {
+ font-size: var(--concrete-type-12);
+ line-height: var(--concrete-line-normal);
+}
+
+.agentGithubCallout a,
+.footerInstall a {
+ display: inline-flex;
+ gap: 6px;
+ align-items: center;
+ justify-self: start;
+ height: 30px;
+ padding: 0 10px;
+ border: 1px solid var(--concrete-inverse-border);
border-radius: var(--concrete-radius-3);
+ background: color-mix(in oklab, var(--concrete-ink-9) 62%, transparent);
+ color: var(--concrete-inverse-foreground);
+ font-size: var(--concrete-type-12);
+ font-weight: 800;
+}
+
+.agentGithubCallout svg {
+ width: 13px;
+ height: 13px;
}
-.iconSystem {
+.agentContractSurface {
display: grid;
- grid-template-columns: 280px 1fr;
- gap: 0;
- overflow: hidden;
+ grid-template-columns: 1fr;
+ align-content: stretch;
+ min-width: 0;
}
-.iconRules {
+.agentSchemaPanel {
display: grid;
- border-right: 1px solid var(--concrete-border);
+ gap: 13px;
+ align-content: start;
+ min-width: 0;
+ padding: 22px;
+ border: 1px solid var(--concrete-inverse-border);
+ border-radius: var(--concrete-radius-4);
+ background: color-mix(in oklab, var(--concrete-ink-9) 78%, transparent);
+ box-shadow: inset 0 1px 0 var(--concrete-inverse-border);
}
-.iconRules span {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
- padding: 14px 16px;
- border-bottom: 1px solid var(--concrete-border-soft);
+.agentSchemaPanel .panelKicker {
+ color: var(--concrete-inverse-muted);
}
-.iconRules span:last-child {
- border-bottom: 0;
+.agentSchemaPanel pre {
+ min-width: 0;
+ margin: 0;
+ overflow: auto;
+ color: var(--concrete-terminal);
+ font: 600 var(--concrete-type-12) / 1.65 var(--concrete-font-mono);
}
-.iconRules b {
- color: var(--concrete-foreground-strong);
- font-size: 12px;
+.renderContractDemo {
+ grid-template-rows: auto minmax(150px, 1fr) auto auto;
}
-.iconRules i {
- color: var(--concrete-foreground-muted);
- font: 800 11px / 1 var(--concrete-font-mono);
- font-style: normal;
+.renderContractHead {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
}
-.iconLibrary {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
+.renderContractHead > span:last-child {
+ padding: 3px 8px;
+ border: 1px solid var(--concrete-inverse-border);
+ border-radius: var(--concrete-radius-pill);
+ background: color-mix(in oklab, var(--concrete-terminal) 16%, transparent);
+ color: var(--concrete-terminal);
+ font: 800 10.5px / 1 var(--concrete-font-mono);
+ text-transform: uppercase;
}
-.iconLibrary span {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- min-height: 48px;
- padding: 0 14px;
- border-right: 1px solid var(--concrete-border-soft);
- border-bottom: 1px solid var(--concrete-border-soft);
- color: var(--concrete-foreground-muted);
- font-size: 12px;
- font-weight: 800;
+.renderContractHead > span:last-child[data-valid="false"] {
+ background: color-mix(in oklab, var(--concrete-error) 13%, transparent);
+ color: var(--concrete-error);
}
-.iconLibrary svg {
- width: 16px;
- height: 16px;
- color: var(--concrete-foreground-strong);
+.renderContractDemo textarea {
+ box-sizing: border-box;
+ width: 100%;
+ min-height: 150px;
+ resize: vertical;
+ padding: 12px 13px;
+ border: 1px solid var(--concrete-inverse-border);
+ border-radius: var(--concrete-radius-3);
+ background: color-mix(in oklab, var(--concrete-ink-9) 66%, transparent);
+ color: var(--concrete-terminal);
+ font: 650 var(--concrete-type-12) / 1.6 var(--concrete-font-mono);
+ outline: none;
+ box-shadow: inset 0 1px 0 rgb(255 255 255 / 4%);
}
-.homePrimitiveGrid,
-.componentFeatureGrid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 16px;
- margin-top: 32px;
+.renderContractDemo textarea:focus {
+ border-color: color-mix(in oklab, var(--concrete-sky) 44%, var(--concrete-inverse-border));
+ box-shadow:
+ 0 0 0 3px color-mix(in oklab, var(--concrete-sky) 13%, transparent),
+ inset 0 1px 0 rgb(255 255 255 / 4%);
}
-.homePrimitiveCard,
-.componentFeatureCard {
- position: relative;
+.renderContractPreview {
display: grid;
- grid-template-rows: auto minmax(150px, 1fr);
+ grid-template-rows: auto 1fr;
gap: 12px;
+ align-items: stretch;
min-width: 0;
- padding: 16px;
- transition:
- border-color var(--concrete-duration-fast) var(--concrete-ease),
- background var(--concrete-duration-fast) var(--concrete-ease);
+ min-height: 132px;
+ padding: 12px;
+ border: 1px solid var(--concrete-inverse-border);
+ border-radius: var(--concrete-radius-3);
+ background:
+ radial-gradient(color-mix(in oklab, var(--concrete-sky) 12%, transparent) 1px, transparent 1.2px),
+ color-mix(in oklab, var(--concrete-ink-9) 54%, transparent);
+ background-size: 14px 14px;
}
-.homePrimitiveCard:hover,
-.componentFeatureCard:hover {
- border-color: var(--concrete-border-strong);
- background: var(--concrete-raised);
+.renderContractPreview[data-error="true"] {
+ border-color: color-mix(in oklab, var(--concrete-error) 36%, var(--concrete-inverse-border));
}
-.homeCardOverlay {
- position: absolute;
- inset: 0;
- z-index: 2;
- border-radius: inherit;
+.renderContractPreviewHead {
+ display: grid;
+ gap: 3px;
+ min-width: 0;
}
-.homePrimitiveCard header,
-.componentFeatureCard header {
- display: flex;
- align-items: baseline;
- justify-content: space-between;
- gap: 12px;
+.renderContractCanvas {
+ display: grid;
+ min-height: 92px;
+ place-items: center;
+ border: 1px solid color-mix(in oklab, var(--concrete-sky) 18%, var(--concrete-inverse-border));
+ border-radius: var(--concrete-radius-3);
+ background:
+ linear-gradient(color-mix(in oklab, var(--concrete-sky) 6%, transparent) 1px, transparent 1px),
+ linear-gradient(
+ 90deg,
+ color-mix(in oklab, var(--concrete-sky) 6%, transparent) 1px,
+ transparent 1px
+ ),
+ color-mix(in oklab, var(--concrete-surface) 96%, var(--concrete-ink-1));
+ background-size: 18px 18px;
+ box-shadow:
+ inset 0 1px 0 rgb(255 255 255 / 82%),
+ 0 10px 22px rgb(0 0 0 / 10%);
}
-.homePrimitiveCard strong,
-.componentFeatureCard strong {
- color: var(--concrete-foreground-strong);
- font-size: 15px;
+.renderContractPreview .concrete-button {
+ align-self: center;
+ justify-self: center;
+}
+
+.renderContractPreview span {
+ overflow: hidden;
+ color: var(--concrete-inverse-foreground);
+ font-size: var(--concrete-type-12);
font-weight: 800;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
-.homePrimitiveCard header span,
-.componentFeatureCard header span {
- color: var(--concrete-foreground-muted);
- font-size: 12px;
- font-weight: 700;
+.renderContractPreview em {
+ color: var(--concrete-inverse-muted);
+ font-style: normal;
+ font-size: 10.5px;
}
-.homePrimitiveStage,
-.componentFeatureStage {
- position: relative;
- display: grid;
- align-self: stretch;
- gap: 12px;
- height: 100%;
- min-width: 0;
- place-items: center;
- padding: 18px;
- border: var(--concrete-border-width-hairline) solid var(--docs-stage-border);
- border-radius: var(--concrete-radius-3);
- background: var(--docs-stage-background);
- box-shadow: var(--docs-stage-shadow-inset);
- overflow: visible;
+.agentRouteRow {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
}
-.homePrimitiveStage > *,
-.componentFeatureStage > * {
- max-width: 100%;
+.agentRouteRow a {
+ display: inline-flex;
+ gap: 7px;
+ align-items: center;
+ height: 30px;
+ padding: 0 10px;
+ border: 1px solid var(--concrete-inverse-border);
+ border-radius: var(--concrete-radius-3);
+ background: color-mix(in oklab, var(--concrete-ink-9) 62%, transparent);
+ color: var(--concrete-inverse-foreground);
+ font-size: var(--concrete-type-12);
+ font-weight: 850;
}
-.componentFeatureCard {
- grid-template-rows: auto minmax(252px, 1fr) auto;
+.agentRouteRow a svg {
+ width: 13px;
+ height: 13px;
+ color: var(--concrete-sky-3);
}
-.componentFeatureStage {
+.docsFooter {
+ display: grid;
+ grid-template-columns: minmax(260px, 0.9fr) minmax(0, 1.1fr) minmax(280px, auto);
+ gap: 20px;
align-items: center;
- min-height: 252px;
+ margin-bottom: 34px;
+ padding: 14px 16px;
+ border: 1px solid var(--concrete-border);
+ border-radius: var(--concrete-radius-4);
+ background:
+ linear-gradient(
+ 180deg,
+ color-mix(in oklab, var(--concrete-surface) 94%, transparent),
+ transparent
+ ),
+ color-mix(in oklab, var(--concrete-raised) 72%, var(--concrete-surface));
+ box-shadow:
+ 0 1px 0 var(--concrete-border),
+ 0 10px 24px rgb(17 24 39 / 4%);
}
-.componentFeatureCard p {
- margin: 0;
- color: var(--concrete-foreground-muted);
- font-size: 12px;
- line-height: 1.45;
-}
-
-.componentFeatureStage[data-component="area-chart"],
-.componentFeatureStage[data-component="bar-chart"],
-.componentFeatureStage[data-component="command-menu"],
-.componentFeatureStage[data-component="composer"],
-.componentFeatureStage[data-component="chart"],
-.componentFeatureStage[data-component="data-table"],
-.componentFeatureStage[data-component="date-picker"],
-.componentFeatureStage[data-component="date-range-picker"],
-.componentFeatureStage[data-component="diagram-canvas"],
-.componentFeatureStage[data-component="donut-chart"],
-.componentFeatureStage[data-component="file-upload"],
-.componentFeatureStage[data-component="flow-diagram"],
-.componentFeatureStage[data-component="form-dialog"],
-.componentFeatureStage[data-component="form-drawer"],
-.componentFeatureStage[data-component="form-shell"],
-.componentFeatureStage[data-component="heatmap"],
-.componentFeatureStage[data-component="image-upload"],
-.componentFeatureStage[data-component="line-chart"],
-.componentFeatureStage[data-component="meter"],
-.componentFeatureStage[data-component="metric-card"],
-.componentFeatureStage[data-component="multi-select"],
-.componentFeatureStage[data-component="search-bar"],
-.componentFeatureStage[data-component="settings-panel"],
-.componentFeatureStage[data-component="stacked-bar-chart"],
-.componentFeatureStage[data-component="time-picker"] {
- min-height: 320px;
-}
-
-.componentFeatureStage[data-component="date-picker"],
-.componentFeatureStage[data-component="date-range-picker"],
-.componentFeatureStage[data-component="multi-select"],
-.componentFeatureStage[data-component="time-picker"] {
- align-items: start;
-}
-
-.apiGrid {
+.footerIntro {
display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 14px;
- margin-top: 32px;
+ grid-template-columns: auto 1fr;
+ gap: 2px 10px;
+ align-items: center;
+}
+
+.footerIntro > span {
+ color: var(--concrete-foreground-soft);
+ font: 800 10px / 1 var(--concrete-font-mono);
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+.footerWordmark {
+ width: 76px;
+ height: 28px;
}
-.apiGrid p {
+.footerIntro p {
+ grid-column: 1 / -1;
+ max-width: 34ch;
color: var(--concrete-foreground-muted);
- font-size: 13px;
- line-height: 1.55;
+ font-size: var(--concrete-type-12);
+ line-height: var(--concrete-line-normal);
}
-.apiCodeRows {
+.footerRouteGrid {
display: flex;
flex-wrap: wrap;
- gap: 8px;
+ gap: 6px 16px;
+ justify-content: center;
+}
+
+.footerRouteGrid a {
+ display: inline-flex;
align-items: center;
+ justify-content: center;
+ height: auto;
+ padding: 0;
+ border: 0;
+ background: transparent;
+ color: var(--concrete-foreground-muted);
+ font-size: var(--concrete-type-12);
+ font-weight: 800;
+}
+
+.footerRouteGrid a:hover {
+ color: var(--concrete-foreground-strong);
}
-.apiSmoke {
+.footerInstall {
display: flex;
flex-wrap: wrap;
gap: 8px;
+ justify-content: flex-end;
align-items: center;
}
-.apiFooter {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- gap: 18px;
- align-items: center;
- margin-top: 16px;
- padding: 16px;
+.footerInstall .copyCommand {
+ height: 30px;
+ box-shadow: none;
}
-.apiMetrics {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 0.5fr)) minmax(120px, 0.7fr) auto;
- gap: 14px;
- align-items: center;
+.footerInstall .copyCommand code {
+ max-width: 230px;
+}
+
+.footerInstall a {
+ border-color: var(--concrete-border);
+ background: var(--concrete-surface);
+ color: var(--concrete-foreground-strong);
}
diff --git a/apps/docs/app/styles/primitives.css b/apps/docs/app/styles/primitives.css
index af300f0..099b977 100644
--- a/apps/docs/app/styles/primitives.css
+++ b/apps/docs/app/styles/primitives.css
@@ -3,5 +3,32 @@
}
.primitiveConceptCard {
+ grid-column: span 3;
min-width: 0;
+ padding: 14px;
+}
+
+.primitiveConceptCard .conceptEyebrowRow {
+ margin-bottom: 10px;
+}
+
+.primitiveConceptCard .conceptEyebrow {
+ font-size: var(--concrete-type-11);
+ letter-spacing: 0.08em;
+}
+
+.primitiveConceptCard .conceptStage {
+ min-height: 132px;
+ padding: 12px;
+ overflow: hidden;
+ border: 1px solid var(--concrete-border-soft);
+ border-radius: var(--concrete-radius-3);
+ background:
+ linear-gradient(var(--concrete-lattice) 1px, transparent 1px),
+ linear-gradient(90deg, var(--concrete-lattice) 1px, transparent 1px), var(--concrete-canvas);
+ background-size: 18px 18px;
+}
+
+.primitiveConceptCard .conceptStage > * {
+ max-width: 100%;
}
diff --git a/apps/docs/app/styles/responsive.css b/apps/docs/app/styles/responsive.css
index a1a225b..4aa08e2 100644
--- a/apps/docs/app/styles/responsive.css
+++ b/apps/docs/app/styles/responsive.css
@@ -42,6 +42,7 @@
.componentPlaygroundStageDataGrid,
.componentCatalogGrid,
.componentStateGrid,
+ .detailContractGrid,
.foundationCatalog,
.primitiveCatalog,
.foundationDataGrid {
@@ -179,6 +180,51 @@
width: min(100vw - 32px, 1120px);
}
+ .docsHeroV2,
+ .agentChapter,
+ .foundationPanelGrid,
+ .catalogHeader,
+ .readyPanel {
+ grid-template-columns: 1fr;
+ }
+
+ .docsHeroV2 {
+ min-height: auto;
+ gap: 28px;
+ padding-top: 32px;
+ }
+
+ .heroFeatureGrid,
+ .heroMiniGrid,
+ .systemLayerGrid,
+ .pressureGridV2,
+ .primitiveCatalogGrid,
+ .componentCatalogGridV2,
+ .applicationGrid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .systemLayerCard:nth-child(2n) {
+ border-right: 0;
+ }
+
+ .systemLayerCard {
+ border-bottom: 1px solid var(--concrete-border);
+ }
+
+ .systemLayerCard:nth-last-child(-n + 2) {
+ border-bottom: 0;
+ }
+
+ .agentChapter {
+ margin: 54px 0;
+ }
+
+ .catalogHeaderActions,
+ .readyPanel .readyActions {
+ justify-content: flex-start;
+ }
+
.docsChapter {
padding: 54px 0;
}
@@ -258,8 +304,69 @@
width: min(100vw - 28px, 1120px);
}
+ .docsHeroV2,
+ .agentChapter {
+ padding-right: 0;
+ padding-left: 0;
+ border-right: 0;
+ border-left: 0;
+ border-radius: 0;
+ }
+
+ .heroFeatureGrid,
+ .heroMiniGrid,
+ .systemLayerGrid,
+ .pressureGridV2,
+ .primitiveCatalogGrid,
+ .componentCatalogGridV2,
+ .applicationGrid,
+ .texturePreviewGrid,
+ .agentMiniPanels,
+ .signalGridV2 {
+ grid-template-columns: 1fr;
+ }
+
+ .sectionIntro {
+ grid-template-columns: 1fr;
+ gap: 14px;
+ }
+
+ .sectionIntro p {
+ grid-column: 1;
+ }
+
+ .heroEditorial h1 {
+ font-size: var(--concrete-type-56);
+ }
+
+ .heroCommandRow,
+ .readyPanel .readyActions {
+ align-items: stretch;
+ flex-direction: column;
+ }
+
+ .installSnippet,
+ .heroButton {
+ width: 100%;
+ justify-content: center;
+ }
+
+ .systemLayerCard,
+ .systemLayerCard:nth-child(2n) {
+ border-right: 0;
+ border-bottom: 1px solid var(--concrete-border);
+ }
+
+ .systemLayerCard:last-child {
+ border-bottom: 0;
+ }
+
+ .spaceRadiusGrid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
.docsChapter {
- padding: 42px 0;
+ padding: 34px 0;
scroll-margin-top: 96px;
}
@@ -327,3 +434,235 @@
.siteShell:has(.renderShell) .topbar {
display: none;
}
+
+@media (width <= 1240px) {
+ .systemLayerGrid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .systemLayerCard {
+ height: 238px;
+ }
+
+ .systemLayerCard::before,
+ .systemLayerCard::after {
+ display: none;
+ }
+}
+
+@media (width <= 1100px) {
+ .docsHeroV3,
+ .agentChapter,
+ .agentContractSurface,
+ .docsFooter,
+ .readyPanel {
+ grid-template-columns: 1fr;
+ }
+
+ .docsHeroV3 {
+ grid-template-areas:
+ "copy"
+ "features"
+ "preview";
+ min-height: auto;
+ gap: 24px;
+ padding-top: 34px;
+ padding-bottom: 44px;
+ }
+
+ .heroComponentMount {
+ max-width: 760px;
+ }
+
+ .pressureExplainer,
+ .footerRouteGrid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .systemLayerCard {
+ height: 238px;
+ }
+
+ .systemLayerCard::before,
+ .systemLayerCard::after {
+ display: none;
+ }
+
+ .pressureMode:nth-child(2n) {
+ border-right: 0;
+ }
+
+ .pressureMode:nth-child(-n + 2) {
+ border-bottom: 1px solid var(--concrete-border);
+ }
+
+ .footerInstall,
+ .readyPanel .readyActions {
+ justify-content: flex-start;
+ }
+
+ .systemLayerCard,
+ .systemLayerCard:nth-child(2n),
+ .systemLayerCard:nth-last-child(-n + 2) {
+ border: 1px solid var(--concrete-border);
+ }
+
+ .agentActionRow {
+ justify-content: flex-start;
+ }
+}
+
+@media (width <= 720px) {
+ .docsHome {
+ width: min(100vw - 20px, 1120px);
+ }
+
+ .nav {
+ gap: 2px 4px;
+ }
+
+ .nav a {
+ padding: 0 8px;
+ }
+
+ .nav .navLogoLink {
+ display: none;
+ }
+
+ .docsHeroV3 {
+ grid-template-columns: 1fr;
+ gap: 18px;
+ padding: 24px 0 32px;
+ }
+
+ .homeLatticeField {
+ opacity: 0.56;
+ }
+
+ .heroEditorial h1,
+ .docsChapter .sectionIntro h2,
+ .agentIntro h2,
+ .readyPanel h2 {
+ max-width: none;
+ font-size: var(--concrete-type-32);
+ }
+
+ .docsLead {
+ max-width: none;
+ margin-top: 14px;
+ font-size: var(--concrete-type-13);
+ line-height: var(--concrete-line-normal);
+ }
+
+ .heroFeatureGrid,
+ .systemLayerGrid,
+ .pressureExplainer,
+ .agentContractList {
+ grid-template-columns: 1fr;
+ }
+
+ .heroFeatureGrid {
+ gap: 14px;
+ }
+
+ .heroFeatureRail {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 8px 10px;
+ }
+
+ .heroFeatureGrid p {
+ max-width: none;
+ }
+
+ .sectionIntro {
+ grid-template-columns: 1fr;
+ margin-bottom: 16px;
+ }
+
+ .heroCommandRow,
+ .readyPanel .readyActions {
+ align-items: stretch;
+ flex-direction: column;
+ }
+
+ .copyCommand,
+ .installSnippet,
+ .heroButton {
+ width: 100%;
+ max-width: 100%;
+ justify-content: center;
+ }
+
+ .copyCommand span {
+ width: 34px;
+ justify-content: center;
+ padding: 0;
+ font-size: 0;
+ }
+
+ .systemShowcase {
+ padding: 14px 0 22px;
+ }
+
+ .systemLayerCard,
+ .systemLayerCard:nth-child(2n) {
+ height: auto;
+ min-height: 188px;
+ border: 1px solid var(--concrete-border);
+ }
+
+ .systemLayerPreview {
+ min-height: 76px;
+ }
+
+ .systemLayerCard footer {
+ justify-content: flex-end;
+ }
+
+ .systemLayerItems {
+ display: none;
+ }
+
+ .pressureMode,
+ .pressureMode:nth-child(2n),
+ .pressureMode:nth-child(-n + 2) {
+ border-right: 0;
+ border-bottom: 1px solid var(--concrete-border);
+ }
+
+ .pressureMode {
+ grid-template-rows: auto 118px auto;
+ gap: 10px;
+ padding: 14px;
+ }
+
+ .pressureDiagram {
+ height: 118px;
+ }
+
+ .pressureMode:last-child {
+ border-bottom: 0;
+ }
+
+ .agentChapter {
+ margin: 32px 0;
+ padding: 18px;
+ }
+
+ .docsFooter {
+ align-items: stretch;
+ }
+
+ .footerInstall {
+ justify-content: stretch;
+ }
+
+ .footerRouteGrid {
+ gap: 6px 12px;
+ }
+
+ .footerInstall a {
+ width: auto;
+ max-width: none;
+ }
+}
diff --git a/apps/docs/src/catalog-render-page.tsx b/apps/docs/src/catalog-render-page.tsx
index 33cd123..c937c02 100644
--- a/apps/docs/src/catalog-render-page.tsx
+++ b/apps/docs/src/catalog-render-page.tsx
@@ -1,24 +1,30 @@
-import { Badge, type ConcretePressure } from '@rubriclab/concrete'
+import { Badge, type RenderQuery } from '@rubriclab/concrete'
import type { ReactNode } from 'react'
import type { CatalogRenderItem } from '@/catalog-render-item'
+import { renderDefinitionFromSearchParams, type SearchParamsInput } from '@/rendering'
type CatalogRenderPageProps = CatalogRenderItem & {
- pressure: ConcretePressure
- state: string
+ query: RenderQuery
+ searchParams: SearchParamsInput
}
-export function CatalogRenderPage({ definition, entry, pressure, state }: CatalogRenderPageProps) {
+export function CatalogRenderPage({
+ definition,
+ entry,
+ query,
+ searchParams
+}: CatalogRenderPageProps) {
return (
-
+
- {definition.renderExample(state)}
- {renderCatalogRenderMeta(entry.name, pressure)}
+ {renderDefinitionFromSearchParams(definition, searchParams, query.state)}
+ {renderCatalogRenderMeta(entry.name, query.pressure)}
)
}
-function renderCatalogRenderMeta(name: string, pressure: ConcretePressure): ReactNode {
+function renderCatalogRenderMeta(name: string, pressure: RenderQuery['pressure']): ReactNode {
return (
{name}
diff --git a/apps/docs/src/component-playground.tsx b/apps/docs/src/component-playground.tsx
index 915a132..5db56e3 100644
--- a/apps/docs/src/component-playground.tsx
+++ b/apps/docs/src/component-playground.tsx
@@ -1,12 +1,9 @@
'use client'
-import {
- type ComponentRegistryEntry,
- getComponentDefinition,
- renderDefinitionInput
-} from '@rubriclab/concrete'
+import { type ComponentRegistryEntry, getComponentDefinition } from '@rubriclab/concrete'
import { useSearchParams } from 'next/navigation'
import { CatalogPlayground } from './catalog-playground'
+import { renderDefinitionFromSearchParams } from './rendering'
type ComponentPlaygroundProps = {
entry: ComponentRegistryEntry
@@ -19,7 +16,15 @@ export function ComponentPlayground({ entry }: ComponentPlaygroundProps) {
return (
setCopied(false), 1400)
+ } catch {
+ setCopied(false)
+ }
+ }
+
+ return (
+
+ )
+}
diff --git a/apps/docs/src/primitive-playground.tsx b/apps/docs/src/primitive-playground.tsx
index 1019757..6bd547d 100644
--- a/apps/docs/src/primitive-playground.tsx
+++ b/apps/docs/src/primitive-playground.tsx
@@ -1,12 +1,9 @@
'use client'
-import {
- getPrimitiveDefinition,
- type PrimitiveRegistryEntry,
- renderDefinitionInput
-} from '@rubriclab/concrete'
+import { getPrimitiveDefinition, type PrimitiveRegistryEntry } from '@rubriclab/concrete'
import { useSearchParams } from 'next/navigation'
import { CatalogPlayground } from './catalog-playground'
+import { renderDefinitionFromSearchParams } from './rendering'
type PrimitivePlaygroundProps = {
entry: PrimitiveRegistryEntry
@@ -19,7 +16,15 @@ export function PrimitivePlayground({ entry }: PrimitivePlaygroundProps) {
return (
)
diff --git a/apps/docs/src/render-contract-demo.tsx b/apps/docs/src/render-contract-demo.tsx
new file mode 100644
index 0000000..bc22da5
--- /dev/null
+++ b/apps/docs/src/render-contract-demo.tsx
@@ -0,0 +1,134 @@
+'use client'
+
+import { Button, ConcreteIcon } from '@rubriclab/concrete'
+import Link from 'next/link'
+import type { ChangeEvent } from 'react'
+import { useMemo, useState } from 'react'
+import { z } from 'zod/v4'
+
+const renderableButtonVariants = ['primary', 'secondary', 'sky-soft', 'ultra'] as const
+
+const buttonContractSchema = z
+ .object({
+ label: z.string().min(1).default('Ship'),
+ loading: z.boolean().default(false),
+ variant: z.enum(renderableButtonVariants).default('primary')
+ })
+ .strict()
+
+type ButtonContract = z.output
+
+type ButtonContractResult =
+ | {
+ contract: ButtonContract
+ message?: never
+ success: true
+ }
+ | {
+ contract: ButtonContract
+ message: string
+ success: false
+ }
+
+const fallbackContract = buttonContractSchema.parse({
+ label: 'Invalid JSON',
+ variant: 'secondary'
+})
+
+const initialContract = `{
+ "label": "Ship",
+ "variant": "sky-soft",
+ "loading": false
+}`
+
+export function RenderContractDemo() {
+ const [source, setSource] = useState(initialContract)
+ const result = useMemo(() => parseButtonContract(source), [source])
+ const routeQuery = useMemo(() => createRouteQuery(result.contract), [result.contract])
+ const reactRoute = `/render/primitive/button?${routeQuery}`
+ const imageRoute = `/render/primitive/button/screenshot?${routeQuery}`
+
+ function updateSource(event: ChangeEvent) {
+ setSource(event.currentTarget.value)
+ }
+
+ return (
+
+
+ Editable props JSON
+ {result.success ? 'Valid' : 'Schema error'}
+
+
+
+
+ {result.success ? 'Rendered primitive' : result.message}
+ Button contract
+
+
+
+
+
+
+
+
+ React URL
+
+
+
+ Image URL
+
+
+
+ )
+}
+
+function parseButtonContract(source: string): ButtonContractResult {
+ try {
+ const parsedValue: unknown = JSON.parse(source)
+ const parsedContract = buttonContractSchema.safeParse(parsedValue)
+
+ if (parsedContract.success) {
+ return {
+ contract: parsedContract.data,
+ success: true
+ }
+ }
+
+ return {
+ contract: fallbackContract,
+ message: parsedContract.error.issues[0]?.message ?? 'Invalid button props.',
+ success: false
+ }
+ } catch (error) {
+ return {
+ contract: fallbackContract,
+ message: error instanceof Error ? error.message : 'Invalid JSON.',
+ success: false
+ }
+ }
+}
+
+function createRouteQuery(contract: ButtonContract): string {
+ const routeQuery = new URLSearchParams({
+ label: contract.label,
+ variant: contract.variant
+ })
+
+ if (contract.loading) {
+ routeQuery.set('loading', 'true')
+ }
+
+ return routeQuery.toString()
+}
diff --git a/apps/docs/src/rendering.ts b/apps/docs/src/rendering.ts
index 3cacc54..ab8bcb7 100644
--- a/apps/docs/src/rendering.ts
+++ b/apps/docs/src/rendering.ts
@@ -1,12 +1,26 @@
-import { type ConcreteViewport, type RenderQuery, renderQuerySchema } from '@rubriclab/concrete'
+import {
+ type ComponentDefinition,
+ type ConcreteViewport,
+ type FoundationDefinition,
+ type PrimitiveDefinition,
+ type RenderQuery,
+ renderDefinitionInput,
+ renderQuerySchema
+} from '@rubriclab/concrete'
+import type { ReactNode } from 'react'
export type SearchParamsInput = Record
+export type QueryValueSource = {
+ get: (name: string) => string | null
+}
export type ViewportSize = {
height: number
width: number
}
+type RenderableDefinition = ComponentDefinition | FoundationDefinition | PrimitiveDefinition
+
export function parseRenderQuery(searchParams: SearchParamsInput): RenderQuery {
const flattened = flattenSearchParams(searchParams)
return renderQuerySchema.parse(flattened)
@@ -33,6 +47,44 @@ export function getViewportSize(viewport: ConcreteViewport): ViewportSize {
}
}
+export function renderDefinitionFromSearchParams(
+ definition: RenderableDefinition,
+ searchParams: QueryValueSource | SearchParamsInput,
+ state: string
+): ReactNode {
+ if (!hasDefinitionInputQuery(definition, searchParams)) {
+ return definition.renderExample(state)
+ }
+
+ return (
+ renderDefinitionInput(definition, createSearchParamsSource(searchParams)) ??
+ definition.renderExample(state)
+ )
+}
+
+export function hasDefinitionInputQuery(
+ definition: RenderableDefinition,
+ searchParams: QueryValueSource | SearchParamsInput
+): boolean {
+ const source = createSearchParamsSource(searchParams)
+
+ return definition.controls.some(control => source.get(control.name) !== null)
+}
+
+export function createSearchParamsSource(
+ searchParams: QueryValueSource | SearchParamsInput
+): QueryValueSource {
+ if (isQueryValueSource(searchParams)) {
+ return searchParams
+ }
+
+ const flattened = flattenSearchParams(searchParams)
+
+ return {
+ get: (name: string) => flattened[name] ?? null
+ }
+}
+
function flattenSearchParams(searchParams: SearchParamsInput): Record {
const flattened: Record = {}
@@ -51,3 +103,9 @@ function flattenSearchParams(searchParams: SearchParamsInput): Record, 'title'> & {
+ accent?: FeatureCardAccent
+ description?: ReactNode
+ icon?: IconName
+ interactive?: boolean
+ title: ReactNode
+}
+
+export function FeatureCard({
+ accent = 'ink',
+ className,
+ description,
+ icon = 'sparkles',
+ interactive = true,
+ title,
+ ...props
+}: FeatureCardProps) {
+ featureCardSchema.pick({ accent: true, interactive: true }).parse({ accent, interactive })
+
+ return (
+
+
+
+
+
+ {title}
+ {description ? {description} : null}
+
+
+ )
+}
diff --git a/packages/concrete/src/components/feature-card/examples.tsx b/packages/concrete/src/components/feature-card/examples.tsx
new file mode 100644
index 0000000..455c2fe
--- /dev/null
+++ b/packages/concrete/src/components/feature-card/examples.tsx
@@ -0,0 +1,34 @@
+import { defineExamples } from '../../factories/createExamples'
+import { FeatureCard } from './component'
+
+export const featureCardExamples = defineExamples({
+ default: {
+ description: 'Compact system feature callout with subtle depth.',
+ render: () => (
+
+ )
+ },
+ set: {
+ description: 'A connected set for hero or footer summaries.',
+ render: () => (
+ <>
+
+
+ >
+ )
+ }
+})
diff --git a/packages/concrete/src/components/feature-card/index.tsx b/packages/concrete/src/components/feature-card/index.tsx
new file mode 100644
index 0000000..3c66b36
--- /dev/null
+++ b/packages/concrete/src/components/feature-card/index.tsx
@@ -0,0 +1,40 @@
+import { exampleStates, renderExample } from '../../factories/createExamples'
+import { createComponent } from '../../factories/createItems'
+import { FeatureCard } from './component'
+import { featureCardExamples } from './examples'
+import { featureCardMeta } from './meta'
+import { type FeatureCardValue, featureCardSchema } from './schema'
+
+export type { FeatureCardAccent, FeatureCardProps } from './component'
+export { FeatureCard } from './component'
+export type { FeatureCardInput, FeatureCardValue } from './schema'
+export { featureCardPropsSchema, featureCardSchema } from './schema'
+
+export const featureCardComponentDefinition = createComponent({
+ ...featureCardMeta,
+ component: FeatureCard,
+ kind: 'component',
+ renderExample: (state?: string) => renderExample(featureCardExamples, state),
+ renderInput: input => renderFeatureCardInput(featureCardSchema.parse(input)),
+ schema: featureCardSchema,
+ slug: 'feature-card',
+ states: exampleStates(featureCardExamples, ['default', 'set'])
+})
+
+function renderFeatureCardInput({
+ accent,
+ description,
+ icon,
+ interactive,
+ title
+}: FeatureCardValue) {
+ return (
+
+ )
+}
diff --git a/packages/concrete/src/components/feature-card/meta.ts b/packages/concrete/src/components/feature-card/meta.ts
new file mode 100644
index 0000000..98930e9
--- /dev/null
+++ b/packages/concrete/src/components/feature-card/meta.ts
@@ -0,0 +1,27 @@
+import { prop } from '../../registry/props'
+import type { ConcretePressure, PrimitiveCategory } from '../../schemas'
+
+type FeatureCardMeta = {
+ category: PrimitiveCategory
+ description: string
+ guidance: string
+ name: string
+ pressure: readonly ConcretePressure[]
+ props: readonly ReturnType[]
+}
+
+export const featureCardMeta = {
+ category: 'surface',
+ description: 'Compact feature callout for system concepts and product affordances.',
+ guidance:
+ 'FeatureCard is for short, connected ideas. Prefer a small set with parallel copy over isolated marketing cards.',
+ name: 'FeatureCard',
+ pressure: ['editorial', 'product', 'generative'],
+ props: [
+ prop('title', 'ReactNode', 'Feature title.'),
+ prop('description', 'ReactNode', 'One-line supporting copy.'),
+ prop('icon', 'IconName', 'Concrete icon name.', 'sparkles'),
+ prop('accent', "'ink' | 'sky' | 'terminal' | 'ultra'", 'Small icon accent.', 'ink'),
+ prop('interactive', 'boolean', 'Enables subtle TiltFrame depth.', 'true')
+ ]
+} as const satisfies FeatureCardMeta
diff --git a/packages/concrete/src/components/feature-card/schema.ts b/packages/concrete/src/components/feature-card/schema.ts
new file mode 100644
index 0000000..fb54493
--- /dev/null
+++ b/packages/concrete/src/components/feature-card/schema.ts
@@ -0,0 +1,29 @@
+import type { z } from 'zod/v4'
+import { z as zod } from 'zod/v4'
+
+const featureCardIconValues = [
+ 'bar-chart-3',
+ 'code',
+ 'command',
+ 'image',
+ 'panel-left',
+ 'panel-right',
+ 'square',
+ 'sliders-horizontal',
+ 'sparkles',
+ 'zap'
+] as const
+
+export const featureCardSchema = zod
+ .object({
+ accent: zod.enum(['ink', 'sky', 'terminal', 'ultra']).default('ink'),
+ description: zod.string().default('A compact feature for a system concept.'),
+ icon: zod.enum(featureCardIconValues).default('sparkles'),
+ interactive: zod.boolean().default(true),
+ title: zod.string().default('Feature')
+ })
+ .strict()
+
+export { featureCardSchema as featureCardPropsSchema }
+export type FeatureCardInput = z.input
+export type FeatureCardValue = z.output
diff --git a/packages/concrete/src/components/index.tsx b/packages/concrete/src/components/index.tsx
index 717a8ab..9cf4f29 100644
--- a/packages/concrete/src/components/index.tsx
+++ b/packages/concrete/src/components/index.tsx
@@ -9,6 +9,7 @@ export * from './date-picker'
export * from './date-range-picker'
export * from './diagram-canvas'
export * from './donut-chart'
+export * from './feature-card'
export * from './file-upload'
export * from './flow-diagram'
export * from './form-dialog'
diff --git a/packages/concrete/src/foundations/motion/styles.css b/packages/concrete/src/foundations/motion/styles.css
index bb7a922..2fac446 100644
--- a/packages/concrete/src/foundations/motion/styles.css
+++ b/packages/concrete/src/foundations/motion/styles.css
@@ -63,6 +63,7 @@
--concrete-opacity-chart-area: 0.08;
--concrete-opacity-chart-comparison: 0.18;
--concrete-opacity-chart-point: 0.78;
+ --concrete-opacity-tilt-frame-glare: 0.72;
--concrete-opacity-concept-frame-muted: 0.62;
--concrete-opacity-concept-connector-muted: 0.52;
--concrete-opacity-data-table-disabled: 0.48;
diff --git a/packages/concrete/src/foundations/sizing/styles.css b/packages/concrete/src/foundations/sizing/styles.css
index 0197f17..acffaf9 100644
--- a/packages/concrete/src/foundations/sizing/styles.css
+++ b/packages/concrete/src/foundations/sizing/styles.css
@@ -246,6 +246,7 @@
--concrete-measure-preview-stage-composer: 860px;
--concrete-measure-preview-stage: var(--concrete-size-full);
--concrete-size-texture-preview: 96px;
+ --concrete-size-tilt-frame-perspective: 820px;
--concrete-size-brand-mark: var(--concrete-size-button-medium);
--concrete-size-brand-mark-glyph: 62%;
--concrete-size-wordmark-inline: 108px;
diff --git a/packages/concrete/src/foundations/textures/examples.tsx b/packages/concrete/src/foundations/textures/examples.tsx
index d3c43d8..3f18341 100644
--- a/packages/concrete/src/foundations/textures/examples.tsx
+++ b/packages/concrete/src/foundations/textures/examples.tsx
@@ -4,9 +4,9 @@ import { textureTokens } from './schema'
export const texturesExamples = defineExamples({
default: {
- description: 'Quiet lattice, dot, and line textures for structure without decoration.',
+ description: 'Quiet lattice, dot, line, and depth textures for structure without decoration.',
render: () => (
-
+
{textureTokens.map(token => (
@@ -72,6 +72,13 @@ function getTextureStyle(token: string): CSSProperties {
'linear-gradient(var(--concrete-lattice) var(--concrete-border-width-hairline), transparent var(--concrete-border-width-hairline)), linear-gradient(90deg, var(--concrete-lattice) var(--concrete-border-width-hairline), transparent var(--concrete-border-width-hairline))',
backgroundSize: 'var(--concrete-grid-unit) var(--concrete-grid-unit)'
}
+ case 'depth':
+ return {
+ backgroundColor: 'var(--concrete-depth-background)',
+ backgroundImage: 'var(--concrete-depth-background-image)',
+ backgroundSize:
+ 'var(--concrete-size-full) var(--concrete-size-full), var(--concrete-grid-unit) var(--concrete-grid-unit), var(--concrete-grid-unit) var(--concrete-grid-unit), var(--concrete-size-full) var(--concrete-size-full)'
+ }
default:
return {}
}
@@ -85,6 +92,8 @@ function getTextureDescription(token: string): string {
return 'reading and rows'
case 'lattice':
return 'diagram coordinates'
+ case 'depth':
+ return 'perspective grounds'
default:
return 'texture ground'
}
diff --git a/packages/concrete/src/foundations/textures/schema.ts b/packages/concrete/src/foundations/textures/schema.ts
index 40f1e14..8454433 100644
--- a/packages/concrete/src/foundations/textures/schema.ts
+++ b/packages/concrete/src/foundations/textures/schema.ts
@@ -2,11 +2,11 @@ import { z } from 'zod/v4'
export const textureFoundationSchema = z
.object({
- variant: z.enum(['dots', 'lattice', 'lines']).default('lattice')
+ variant: z.enum(['dots', 'lattice', 'lines', 'depth']).default('lattice')
})
.strict()
-export const textureTokens = ['lattice', 'dots', 'lines'] as const
+export const textureTokens = ['lattice', 'dots', 'lines', 'depth'] as const
export type TextureFoundationInput = z.input
export type TextureFoundationValue = z.output
diff --git a/packages/concrete/src/foundations/textures/styles.css b/packages/concrete/src/foundations/textures/styles.css
index 880ad8f..4300cd0 100644
--- a/packages/concrete/src/foundations/textures/styles.css
+++ b/packages/concrete/src/foundations/textures/styles.css
@@ -29,4 +29,25 @@
--concrete-lattice: rgb(10 11 15 / 3.5%);
--concrete-dots: rgb(10 11 15 / 14%);
--concrete-lines: rgb(10 11 15 / 6%);
+ --concrete-depth: var(--concrete-inverse-background);
+ --concrete-depth-background: #070a10;
+ --concrete-depth-line: rgb(78 139 222 / 18%);
+ --concrete-depth-line-strong: rgb(78 139 222 / 32%);
+ --concrete-depth-glow: rgb(31 111 212 / 18%);
+ --concrete-depth-fade: rgb(7 10 16 / 92%);
+ --concrete-depth-background-image:
+ radial-gradient(circle at 50% 0, var(--concrete-depth-glow), transparent 42%),
+ linear-gradient(var(--concrete-depth-line) 1px, transparent 1px),
+ linear-gradient(90deg, var(--concrete-depth-line) 1px, transparent 1px),
+ linear-gradient(180deg, transparent 12%, var(--concrete-depth-glow) 54%, transparent);
+ --concrete-tilt-frame-glare-background: linear-gradient(
+ 135deg,
+ rgb(255 255 255 / 12%),
+ transparent 36% 70%,
+ rgb(78 139 222 / 8%)
+ );
+ --concrete-tilt-frame-glare-shadow:
+ inset 0 0 0 1px rgb(78 139 222 / 14%),
+ inset 0 14px 24px -22px rgb(78 139 222 / 32%),
+ inset 0 -18px 28px -26px rgb(10 11 15 / 28%);
}
diff --git a/packages/concrete/src/primitives/index.tsx b/packages/concrete/src/primitives/index.tsx
index 90b053c..80424b7 100644
--- a/packages/concrete/src/primitives/index.tsx
+++ b/packages/concrete/src/primitives/index.tsx
@@ -58,6 +58,7 @@ export * from './radio'
export * from './range-control'
export * from './reasoning-panel'
export * from './row'
+export * from './scale-frame'
export * from './search-field'
export * from './search-token'
export * from './select'
@@ -74,6 +75,7 @@ export * from './switch'
export * from './tag'
export * from './textarea'
export * from './texture'
+export * from './tilt-frame'
export * from './time-list'
export * from './tool-call-panel'
export * from './toolbar-control'
diff --git a/packages/concrete/src/primitives/scale-frame/component.tsx b/packages/concrete/src/primitives/scale-frame/component.tsx
new file mode 100644
index 0000000..2aae527
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/component.tsx
@@ -0,0 +1,54 @@
+import type { CSSProperties, HTMLAttributes, ReactNode } from 'react'
+import { concreteClassNames } from '../../styles/class-names'
+import { cn } from '../utils'
+
+export type ScaleFrameAlign = 'center' | 'end' | 'start'
+export type ScaleFrameSurface = 'raised' | 'sunken' | 'transparent'
+
+export type ScaleFrameProps = HTMLAttributes & {
+ align?: ScaleFrameAlign
+ children?: ReactNode
+ scale?: number
+ surface?: ScaleFrameSurface
+}
+
+type ScaleFrameStyle = CSSProperties & {
+ '--concrete-scale-frame-scale'?: string
+}
+
+export function ScaleFrame({
+ align = 'center',
+ children,
+ className,
+ scale = 1,
+ style,
+ surface = 'transparent',
+ ...props
+}: ScaleFrameProps) {
+ const frameStyle: ScaleFrameStyle = {
+ '--concrete-scale-frame-scale': String(getSafeScale(scale)),
+ ...style
+ }
+
+ return (
+
+ )
+}
+
+function getSafeScale(scale: number): number {
+ if (!Number.isFinite(scale)) {
+ return 1
+ }
+
+ return Math.min(Math.max(scale, 0.15), 1.25)
+}
diff --git a/packages/concrete/src/primitives/scale-frame/examples.tsx b/packages/concrete/src/primitives/scale-frame/examples.tsx
new file mode 100644
index 0000000..057795e
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/examples.tsx
@@ -0,0 +1,30 @@
+import { defineExamples } from '../../factories/createExamples'
+import { Button } from '../button'
+import { Input } from '../input'
+import { ScaleFrame } from './component'
+
+export const scaleFrameExamples = defineExamples({
+ controls: {
+ description: 'A larger control group scaled inside fixed preview bounds.',
+ render: function renderControls() {
+ return (
+
+
+
+
+ )
+ }
+ },
+ panel: {
+ description: 'Static product surfaces keep their layout while fitting dense previews.',
+ render: function renderPanel() {
+ return (
+
+ Latency p95
+ 184ms
+ Scaled output remains deterministic.
+
+ )
+ }
+ }
+})
diff --git a/packages/concrete/src/primitives/scale-frame/index.tsx b/packages/concrete/src/primitives/scale-frame/index.tsx
new file mode 100644
index 0000000..68c3dc0
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/index.tsx
@@ -0,0 +1,30 @@
+import { exampleStates, renderExample } from '../../factories/createExamples'
+import { createPrimitive } from '../../factories/createItems'
+import { ScaleFrame } from './component'
+import { scaleFrameExamples } from './examples'
+import { scaleFrameMeta } from './meta'
+import { type ScaleFrameValue, scaleFrameSchema } from './schema'
+
+export type { ScaleFrameAlign, ScaleFrameProps, ScaleFrameSurface } from './component'
+export { ScaleFrame } from './component'
+export type { ScaleFrameInput, ScaleFrameValue } from './schema'
+export { scaleFramePropsSchema, scaleFrameSchema } from './schema'
+
+export const scaleFramePrimitiveDefinition = createPrimitive({
+ ...scaleFrameMeta,
+ component: ScaleFrame,
+ kind: 'primitive',
+ renderExample: (state?: string) => renderExample(scaleFrameExamples, state),
+ renderInput: input => renderScaleFrameInput(scaleFrameSchema.parse(input)),
+ schema: scaleFrameSchema,
+ slug: 'scale-frame',
+ states: exampleStates(scaleFrameExamples, ['controls', 'panel'])
+})
+
+function renderScaleFrameInput({ align, body, scale, surface }: ScaleFrameValue) {
+ return (
+
+ {body}
+
+ )
+}
diff --git a/packages/concrete/src/primitives/scale-frame/meta.ts b/packages/concrete/src/primitives/scale-frame/meta.ts
new file mode 100644
index 0000000..498cc90
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/meta.ts
@@ -0,0 +1,26 @@
+import { prop } from '../../registry/props'
+import type { ConcretePressure, PrimitiveCategory } from '../../schemas'
+
+type ScaleFrameMeta = {
+ category: PrimitiveCategory
+ description: string
+ guidance: string
+ name: string
+ pressure: readonly ConcretePressure[]
+ props: readonly ReturnType[]
+}
+
+export const scaleFrameMeta = {
+ category: 'surface',
+ description: 'Fixed-bounds preview container for scaled product surfaces.',
+ guidance:
+ 'Use ScaleFrame when a real primitive, component, or interface must fit a constrained preview without changing its internal layout.',
+ name: 'ScaleFrame',
+ pressure: ['product', 'generative', 'educational'],
+ props: [
+ prop('scale', 'number', 'Visual scale applied inside stable frame bounds.', '1'),
+ prop('align', "'start' | 'center' | 'end'", 'Content alignment inside the frame.', 'center'),
+ prop('surface', "'raised' | 'sunken' | 'transparent'", 'Optional frame surface.', 'transparent'),
+ prop('children', 'ReactNode', 'Scaled frame content.')
+ ]
+} as const satisfies ScaleFrameMeta
diff --git a/packages/concrete/src/primitives/scale-frame/schema.ts b/packages/concrete/src/primitives/scale-frame/schema.ts
new file mode 100644
index 0000000..05679f8
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/schema.ts
@@ -0,0 +1,14 @@
+import { z } from 'zod/v4'
+
+export const scaleFrameSchema = z
+ .object({
+ align: z.enum(['start', 'center', 'end']).default('center'),
+ body: z.string().default('Scaled preview content'),
+ scale: z.number().min(0.15).max(1.25).default(1),
+ surface: z.enum(['raised', 'sunken', 'transparent']).default('transparent')
+ })
+ .strict()
+
+export { scaleFrameSchema as scaleFramePropsSchema }
+export type ScaleFrameInput = z.input
+export type ScaleFrameValue = z.output
diff --git a/packages/concrete/src/primitives/scale-frame/styles.css b/packages/concrete/src/primitives/scale-frame/styles.css
new file mode 100644
index 0000000..bd8bd3f
--- /dev/null
+++ b/packages/concrete/src/primitives/scale-frame/styles.css
@@ -0,0 +1,43 @@
+.concrete-scale-frame {
+ display: grid;
+ min-width: var(--concrete-space-0);
+}
+
+.concrete-scale-frame-surface {
+ display: grid;
+ width: var(--concrete-size-full);
+ min-width: var(--concrete-space-0);
+ overflow: hidden;
+ border: var(--concrete-border-width-hairline) solid transparent;
+ border-radius: var(--concrete-radius-4);
+}
+
+.concrete-scale-frame[data-surface="raised"] .concrete-scale-frame-surface {
+ border-color: var(--concrete-border);
+ background: var(--concrete-surface);
+ box-shadow: var(--concrete-shadow-1);
+}
+
+.concrete-scale-frame[data-surface="sunken"] .concrete-scale-frame-surface {
+ border-color: var(--concrete-border-soft);
+ background: var(--concrete-sunken);
+}
+
+.concrete-scale-frame-content {
+ display: grid;
+ gap: var(--concrete-space-2);
+ min-width: var(--concrete-space-0);
+ place-self: center;
+ transform: scale(var(--concrete-scale-frame-scale));
+ transform-origin: center;
+}
+
+.concrete-scale-frame[data-align="start"] .concrete-scale-frame-content {
+ place-self: start;
+ transform-origin: top left;
+}
+
+.concrete-scale-frame[data-align="end"] .concrete-scale-frame-content {
+ place-self: end;
+ transform-origin: right bottom;
+}
diff --git a/packages/concrete/src/primitives/texture/component.tsx b/packages/concrete/src/primitives/texture/component.tsx
index 30db524..4b937b3 100644
--- a/packages/concrete/src/primitives/texture/component.tsx
+++ b/packages/concrete/src/primitives/texture/component.tsx
@@ -2,7 +2,7 @@ import type { HTMLAttributes } from 'react'
import { concreteClassNames, getConcreteClassName } from '../../styles/class-names'
import { cn } from '../utils'
-const textureVariantValues = ['lattice', 'dots', 'lines'] as const
+const textureVariantValues = ['lattice', 'dots', 'lines', 'depth'] as const
export type TextureVariant = (typeof textureVariantValues)[number]
@@ -11,6 +11,7 @@ export type TextureProps = HTMLAttributes & {
}
const textureClassNames = {
+ depth: getConcreteClassName('depth'),
dots: getConcreteClassName('dots'),
lattice: getConcreteClassName('lattice'),
lines: getConcreteClassName('lines')
diff --git a/packages/concrete/src/primitives/texture/examples.tsx b/packages/concrete/src/primitives/texture/examples.tsx
index 883df57..7b39d71 100644
--- a/packages/concrete/src/primitives/texture/examples.tsx
+++ b/packages/concrete/src/primitives/texture/examples.tsx
@@ -3,20 +3,25 @@ import { TexturePreview } from './component'
export const textureExamples = defineExamples({
default: {
- description: 'Dot and line texture grounds.',
+ description: 'Dot, line, lattice, and depth texture grounds.',
render: () => (
<>
+
>
)
},
+ depth: {
+ description: 'Perspective depth ground for system diagrams and high-contrast sections.',
+ render: () =>
+ },
lattice: {
description: 'Lattice texture ground.',
render: () => (
<>
-
+
>
)
}
diff --git a/packages/concrete/src/primitives/texture/index.tsx b/packages/concrete/src/primitives/texture/index.tsx
index 12a117c..aaa71f5 100644
--- a/packages/concrete/src/primitives/texture/index.tsx
+++ b/packages/concrete/src/primitives/texture/index.tsx
@@ -18,7 +18,7 @@ export const texturePrimitiveDefinition = createPrimitive({
renderInput: input => renderTextureInput(textureSchema.parse(input)),
schema: textureSchema,
slug: 'texture',
- states: exampleStates(textureExamples, ['default', 'lattice'])
+ states: exampleStates(textureExamples, ['default', 'lattice', 'depth'])
})
function renderTextureInput({ texture }: TextureValue) {
diff --git a/packages/concrete/src/primitives/texture/meta.ts b/packages/concrete/src/primitives/texture/meta.ts
index b11ea0a..1ddea76 100644
--- a/packages/concrete/src/primitives/texture/meta.ts
+++ b/packages/concrete/src/primitives/texture/meta.ts
@@ -12,13 +12,13 @@ type TextureMeta = {
export const textureMeta = {
category: 'foundation',
- description: 'Lattice, dot, and line grounds from the foundation tokens.',
+ description: 'Lattice, dot, line, and depth grounds from the foundation tokens.',
guidance:
- 'Textures are subtle instructional grounds. Keep them inside frames or small surfaces and avoid full-page decorative use.',
+ 'Textures are subtle instructional grounds. Keep them inside frames, diagrams, and bounded system surfaces.',
name: 'Texture',
pressure: ['editorial', 'educational'],
props: [
- prop('texture', "'lattice' | 'dots' | 'lines'", 'Optional tokenized ground pattern.'),
+ prop('texture', "'lattice' | 'dots' | 'lines' | 'depth'", 'Optional tokenized ground pattern.'),
prop('children', 'never', 'Texture renders only its background treatment.')
]
} as const satisfies TextureMeta
diff --git a/packages/concrete/src/primitives/texture/schema.ts b/packages/concrete/src/primitives/texture/schema.ts
index 7c71dcb..60d53a6 100644
--- a/packages/concrete/src/primitives/texture/schema.ts
+++ b/packages/concrete/src/primitives/texture/schema.ts
@@ -2,7 +2,7 @@ import { z } from 'zod/v4'
export const textureSchema = z
.object({
- texture: z.enum(['lattice', 'dots', 'lines']).default('lattice')
+ texture: z.enum(['lattice', 'dots', 'lines', 'depth']).default('lattice')
})
.strict()
diff --git a/packages/concrete/src/primitives/texture/styles.css b/packages/concrete/src/primitives/texture/styles.css
index 8cef3a5..b974707 100644
--- a/packages/concrete/src/primitives/texture/styles.css
+++ b/packages/concrete/src/primitives/texture/styles.css
@@ -35,6 +35,16 @@
background-size: var(--concrete-space-4) var(--concrete-space-4);
}
+.concrete-depth {
+ background-color: var(--concrete-depth-background);
+ background-image: var(--concrete-depth-background-image);
+ background-size:
+ var(--concrete-size-full) var(--concrete-size-full),
+ var(--concrete-grid-unit) var(--concrete-grid-unit),
+ var(--concrete-grid-unit) var(--concrete-grid-unit),
+ var(--concrete-size-full) var(--concrete-size-full);
+}
+
.concrete-texture-preview {
width: var(--concrete-size-full);
height: var(--concrete-size-texture-preview);
diff --git a/packages/concrete/src/primitives/tilt-frame/component.tsx b/packages/concrete/src/primitives/tilt-frame/component.tsx
new file mode 100644
index 0000000..4a16557
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/component.tsx
@@ -0,0 +1,124 @@
+'use client'
+
+import type { HTMLAttributes, PointerEvent, ReactNode } from 'react'
+import { useEffect, useRef } from 'react'
+import { concreteClassNames } from '../../styles/class-names'
+import { cn } from '../utils'
+
+export type TiltFrameIntensity = 'medium' | 'subtle'
+export type TiltFrameSurface = 'raised' | 'sunken' | 'transparent'
+
+export type TiltFrameProps = HTMLAttributes & {
+ children?: ReactNode
+ /** Enables cursor-driven rotation. */
+ interactive?: boolean
+ /** Rotation strength. Keep hero/product uses subtle. */
+ intensity?: TiltFrameIntensity
+ surface?: TiltFrameSurface
+}
+
+const tiltIntensityDegrees = {
+ medium: 6.5,
+ subtle: 3.5
+} satisfies Record
+
+type PendingTilt = {
+ rotateX: number
+ rotateY: number
+ target: HTMLDivElement
+}
+
+export function TiltFrame({
+ children,
+ className,
+ interactive = true,
+ intensity = 'subtle',
+ onPointerLeave,
+ onPointerMove,
+ surface = 'raised',
+ ...props
+}: TiltFrameProps) {
+ const frameReference = useRef(null)
+ const pendingTiltReference = useRef(null)
+
+ useEffect(() => {
+ return () => {
+ if (frameReference.current !== null) {
+ window.cancelAnimationFrame(frameReference.current)
+ }
+ }
+ }, [])
+
+ function updateTilt(event: PointerEvent) {
+ onPointerMove?.(event)
+
+ if (!interactive) {
+ return
+ }
+
+ const bounds = event.currentTarget.getBoundingClientRect()
+ const x = clampTiltAxis((event.clientX - bounds.left) / bounds.width - 0.5)
+ const y = clampTiltAxis((event.clientY - bounds.top) / bounds.height - 0.5)
+ const degrees = tiltIntensityDegrees[intensity]
+
+ queueTilt(event.currentTarget, roundTiltValue(-y * degrees), roundTiltValue(x * degrees))
+ }
+
+ function resetTilt(event: PointerEvent) {
+ onPointerLeave?.(event)
+
+ pendingTiltReference.current = null
+
+ if (frameReference.current !== null) {
+ window.cancelAnimationFrame(frameReference.current)
+ frameReference.current = null
+ }
+
+ event.currentTarget.style.removeProperty('--concrete-tilt-rotate-x')
+ event.currentTarget.style.removeProperty('--concrete-tilt-rotate-y')
+ }
+
+ function queueTilt(target: HTMLDivElement, rotateX: number, rotateY: number) {
+ pendingTiltReference.current = { rotateX, rotateY, target }
+
+ if (frameReference.current !== null) {
+ return
+ }
+
+ frameReference.current = window.requestAnimationFrame(() => {
+ const pendingTilt = pendingTiltReference.current
+ frameReference.current = null
+
+ if (!pendingTilt) {
+ return
+ }
+
+ pendingTilt.target.style.setProperty('--concrete-tilt-rotate-x', `${pendingTilt.rotateX}deg`)
+ pendingTilt.target.style.setProperty('--concrete-tilt-rotate-y', `${pendingTilt.rotateY}deg`)
+ })
+ }
+
+ return (
+
+ )
+}
+
+function clampTiltAxis(value: number): number {
+ return Math.max(-0.5, Math.min(0.5, value))
+}
+
+function roundTiltValue(value: number): number {
+ return Math.round(value * 100) / 100
+}
diff --git a/packages/concrete/src/primitives/tilt-frame/examples.tsx b/packages/concrete/src/primitives/tilt-frame/examples.tsx
new file mode 100644
index 0000000..506dd8d
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/examples.tsx
@@ -0,0 +1,31 @@
+import { defineExamples } from '../../factories/createExamples'
+import { Button } from '../button'
+import { Input } from '../input'
+import { Slider } from '../slider'
+import { Switch } from '../switch'
+import { TiltFrame } from './component'
+
+export const tiltFrameExamples = defineExamples({
+ controls: {
+ description: 'Stable container for live controls with subtle pointer depth.',
+ render: () => (
+
+
+
+
+
+
+ )
+ },
+ surface: {
+ description: 'Sunken depth keeps the highlight quiet inside dense product surfaces.',
+ render: () => (
+
+ Generated panel
+ One focused output, returned from typed props.
+
+ )
+ }
+})
diff --git a/packages/concrete/src/primitives/tilt-frame/index.tsx b/packages/concrete/src/primitives/tilt-frame/index.tsx
new file mode 100644
index 0000000..7baafdd
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/index.tsx
@@ -0,0 +1,30 @@
+import { exampleStates, renderExample } from '../../factories/createExamples'
+import { createPrimitive } from '../../factories/createItems'
+import { TiltFrame } from './component'
+import { tiltFrameExamples } from './examples'
+import { tiltFrameMeta } from './meta'
+import { type TiltFrameValue, tiltFrameSchema } from './schema'
+
+export type { TiltFrameIntensity, TiltFrameProps, TiltFrameSurface } from './component'
+export { TiltFrame } from './component'
+export type { TiltFrameInput, TiltFrameValue } from './schema'
+export { tiltFramePropsSchema, tiltFrameSchema } from './schema'
+
+export const tiltFramePrimitiveDefinition = createPrimitive({
+ ...tiltFrameMeta,
+ component: TiltFrame,
+ kind: 'primitive',
+ renderExample: (state?: string) => renderExample(tiltFrameExamples, state),
+ renderInput: input => renderTiltFrameInput(tiltFrameSchema.parse(input)),
+ schema: tiltFrameSchema,
+ slug: 'tilt-frame',
+ states: exampleStates(tiltFrameExamples, ['controls', 'surface'])
+})
+
+function renderTiltFrameInput({ body, interactive, intensity, surface }: TiltFrameValue) {
+ return (
+
+ {body}
+
+ )
+}
diff --git a/packages/concrete/src/primitives/tilt-frame/meta.ts b/packages/concrete/src/primitives/tilt-frame/meta.ts
new file mode 100644
index 0000000..d082961
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/meta.ts
@@ -0,0 +1,26 @@
+import { prop } from '../../registry/props'
+import type { ConcretePressure, PrimitiveCategory } from '../../schemas'
+
+type TiltFrameMeta = {
+ category: PrimitiveCategory
+ description: string
+ guidance: string
+ name: string
+ pressure: readonly ConcretePressure[]
+ props: readonly ReturnType[]
+}
+
+export const tiltFrameMeta = {
+ category: 'surface',
+ description: 'Pointer-aware depth container for one highlighted surface.',
+ guidance:
+ 'Use TiltFrame for one highlighted surface, not for every card in a dense grid. Keep the intensity subtle and pair with ScaleFrame when fixed preview scaling is needed.',
+ name: 'TiltFrame',
+ pressure: ['product', 'generative', 'educational'],
+ props: [
+ prop('interactive', 'boolean', 'Enables cursor-driven rotation.', 'true'),
+ prop('intensity', "'subtle' | 'medium'", 'Rotation strength.', 'subtle'),
+ prop('surface', "'raised' | 'sunken' | 'transparent'", 'Frame surface treatment.', 'raised'),
+ prop('children', 'ReactNode', 'Frame content.')
+ ]
+} as const satisfies TiltFrameMeta
diff --git a/packages/concrete/src/primitives/tilt-frame/schema.ts b/packages/concrete/src/primitives/tilt-frame/schema.ts
new file mode 100644
index 0000000..ddd4a57
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/schema.ts
@@ -0,0 +1,14 @@
+import { z } from 'zod/v4'
+
+export const tiltFrameSchema = z
+ .object({
+ body: z.string().default('Depth-aware surface'),
+ intensity: z.enum(['subtle', 'medium']).default('subtle'),
+ interactive: z.boolean().default(true),
+ surface: z.enum(['raised', 'sunken', 'transparent']).default('raised')
+ })
+ .strict()
+
+export { tiltFrameSchema as tiltFramePropsSchema }
+export type TiltFrameInput = z.input
+export type TiltFrameValue = z.output
diff --git a/packages/concrete/src/primitives/tilt-frame/styles.css b/packages/concrete/src/primitives/tilt-frame/styles.css
new file mode 100644
index 0000000..9a3eb9a
--- /dev/null
+++ b/packages/concrete/src/primitives/tilt-frame/styles.css
@@ -0,0 +1,67 @@
+.concrete-tilt-frame {
+ display: grid;
+ min-width: var(--concrete-space-0);
+ perspective: var(--concrete-size-tilt-frame-perspective);
+}
+
+.concrete-tilt-frame-surface {
+ position: relative;
+ display: grid;
+ min-width: var(--concrete-space-0);
+ overflow: hidden;
+ border: var(--concrete-border-width-hairline) solid var(--concrete-border);
+ border-radius: var(--concrete-radius-4);
+ background: var(--concrete-surface);
+ box-shadow: var(--concrete-shadow-2);
+ transform: rotateX(var(--concrete-tilt-rotate-x, 0deg))
+ rotateY(var(--concrete-tilt-rotate-y, 0deg)) translate3d(0, 0, 0);
+ transform-origin: center;
+ transform-style: preserve-3d;
+ transition:
+ transform var(--concrete-duration-fast) var(--concrete-ease),
+ border-color var(--concrete-duration-fast) var(--concrete-ease),
+ box-shadow var(--concrete-duration-fast) var(--concrete-ease);
+ backface-visibility: hidden;
+ contain: paint;
+ will-change: transform;
+}
+
+.concrete-tilt-frame[data-surface="sunken"] .concrete-tilt-frame-surface {
+ border-color: var(--concrete-border-soft);
+ background: var(--concrete-sunken);
+ box-shadow: inset var(--concrete-space-0) var(--concrete-border-width-hairline)
+ var(--concrete-space-0) var(--concrete-surface);
+}
+
+.concrete-tilt-frame[data-surface="transparent"] .concrete-tilt-frame-surface {
+ border-color: transparent;
+ background: transparent;
+ box-shadow: none;
+}
+
+.concrete-tilt-frame[data-interactive="true"]:hover .concrete-tilt-frame-surface {
+ border-color: var(--concrete-border-strong);
+ box-shadow: var(--concrete-shadow-2);
+}
+
+.concrete-tilt-frame-content {
+ display: grid;
+ gap: var(--concrete-space-2);
+ min-width: var(--concrete-space-0);
+ padding: var(--concrete-space-4);
+}
+
+.concrete-tilt-frame-glare {
+ position: absolute;
+ inset: var(--concrete-space-0);
+ border-radius: inherit;
+ background: var(--concrete-tilt-frame-glare-background);
+ box-shadow: var(--concrete-tilt-frame-glare-shadow);
+ opacity: var(--concrete-opacity-hidden);
+ pointer-events: none;
+ transition: opacity var(--concrete-duration-fast) var(--concrete-ease);
+}
+
+.concrete-tilt-frame[data-interactive="true"]:hover .concrete-tilt-frame-glare {
+ opacity: var(--concrete-opacity-tilt-frame-glare);
+}
diff --git a/packages/concrete/src/registry/items.tsx b/packages/concrete/src/registry/items.tsx
index 99ffc57..e232306 100644
--- a/packages/concrete/src/registry/items.tsx
+++ b/packages/concrete/src/registry/items.tsx
@@ -8,6 +8,7 @@ import { datePickerComponentDefinition } from '../components/date-picker'
import { dateRangePickerComponentDefinition } from '../components/date-range-picker'
import { diagramCanvasComponentDefinition } from '../components/diagram-canvas'
import { donutChartComponentDefinition } from '../components/donut-chart'
+import { featureCardComponentDefinition } from '../components/feature-card'
import { fileUploadComponentDefinition } from '../components/file-upload'
import { flowDiagramComponentDefinition } from '../components/flow-diagram'
import { formDialogComponentDefinition } from '../components/form-dialog'
@@ -91,6 +92,7 @@ import { radioPrimitiveDefinition } from '../primitives/radio'
import { rangeControlPrimitiveDefinition } from '../primitives/range-control'
import { reasoningPanelPrimitiveDefinition } from '../primitives/reasoning-panel'
import { rowPrimitiveDefinition } from '../primitives/row'
+import { scaleFramePrimitiveDefinition } from '../primitives/scale-frame'
import { searchFieldPrimitiveDefinition } from '../primitives/search-field'
import { searchTokenPrimitiveDefinition } from '../primitives/search-token'
import { selectPrimitiveDefinition } from '../primitives/select'
@@ -107,6 +109,7 @@ import { switchPrimitiveDefinition } from '../primitives/switch'
import { tagPrimitiveDefinition } from '../primitives/tag'
import { textareaPrimitiveDefinition } from '../primitives/textarea'
import { texturePrimitiveDefinition } from '../primitives/texture'
+import { tiltFramePrimitiveDefinition } from '../primitives/tilt-frame'
import { timeListPrimitiveDefinition } from '../primitives/time-list'
import { toolCallPanelPrimitiveDefinition } from '../primitives/tool-call-panel'
import { toolbarControlPrimitiveDefinition } from '../primitives/toolbar-control'
@@ -196,6 +199,8 @@ export const primitiveDefinitions = [
texturePrimitiveDefinition,
timeListPrimitiveDefinition,
toolCallPanelPrimitiveDefinition,
+ tiltFramePrimitiveDefinition,
+ scaleFramePrimitiveDefinition,
brandMarkPrimitiveDefinition,
wordmarkPrimitiveDefinition,
iconPrimitiveDefinition,
@@ -229,6 +234,7 @@ export const componentDefinitions = [
donutChartComponentDefinition,
heatmapComponentDefinition,
chartComponentDefinition,
+ featureCardComponentDefinition,
dataTableComponentDefinition,
flowDiagramComponentDefinition,
diagramCanvasComponentDefinition,
diff --git a/packages/concrete/src/registry/types.ts b/packages/concrete/src/registry/types.ts
index 9228b5d..5bfc0c9 100644
--- a/packages/concrete/src/registry/types.ts
+++ b/packages/concrete/src/registry/types.ts
@@ -76,6 +76,7 @@ export type PrimitiveSlug =
| 'row'
| 'search-field'
| 'search-token'
+ | 'scale-frame'
| 'select'
| 'select-control'
| 'select-menu'
@@ -91,6 +92,7 @@ export type PrimitiveSlug =
| 'textarea'
| 'texture'
| 'time-list'
+ | 'tilt-frame'
| 'tooltip'
| 'tool-call-panel'
| 'toolbar-control'
@@ -107,6 +109,7 @@ export type ComponentSlug =
| 'data-table'
| 'date-picker'
| 'date-range-picker'
+ | 'feature-card'
| 'file-upload'
| 'flow-diagram'
| 'form-dialog'
diff --git a/packages/concrete/src/styles/class-names.ts b/packages/concrete/src/styles/class-names.ts
index 4c20c5e..6c5b0a4 100644
--- a/packages/concrete/src/styles/class-names.ts
+++ b/packages/concrete/src/styles/class-names.ts
@@ -59,6 +59,7 @@ progressRingUnit progressShuttle progressSky progressTerminal progressThick prog
radio radioChecked radioDot railChip rangeSlider rangeSliderTrack rangeSliderValues reasoning
reasoningStatus reasoningSteps reasoningSummaryMain reasoningSummaryText root row rowIcon rowInteractive
rowLabel rowMeta searchBar searchInput searchLeading searchMenu searchShell searchShortcut
+scaleFrame scaleFrameContent scaleFrameSurface
`,
`
searchShortcutKey searchToken segmentedProgress select selectWrap sendButton skeleton slider
@@ -68,7 +69,8 @@ stat statDisplay statLabel statLarge statMeta statMuted statNumber statSky
statSmall statUnit statValue statXlarge statXsmall submitDock switch switchChecked
switchTrack syntaxAttribute syntaxComment syntaxFunction syntaxIdentifier syntaxKeyword syntaxNumber syntaxOperator
syntaxPunctuation syntaxString syntaxType tag tagActive tagClose tagError tagLarge
-tagOutline tagSelected tagSky tagSmall tagTerminal tagUltra textarea texturePreview timeMenu
+tagOutline tagSelected tagSky tagSmall tagTerminal tagUltra textarea tiltFrame tiltFrameContent
+tiltFrameGlare tiltFrameSurface timeMenu
`,
`
timePicker toolButton toolbar toolbarCompact toolbarDivider toolbarGroup toolbarRoot toolbarRootButton
diff --git a/packages/concrete/src/styles/manifest.ts b/packages/concrete/src/styles/manifest.ts
index 1465d41..9665136 100644
--- a/packages/concrete/src/styles/manifest.ts
+++ b/packages/concrete/src/styles/manifest.ts
@@ -99,6 +99,7 @@ export const primitiveStyleSources = [
{ kind: 'primitive', path: 'src/primitives/row/styles.css' },
{ kind: 'primitive', path: 'src/primitives/search-field/styles.css' },
{ kind: 'primitive', path: 'src/primitives/search-token/styles.css' },
+ { kind: 'primitive', path: 'src/primitives/scale-frame/styles.css' },
{ kind: 'primitive', path: 'src/primitives/select/styles.css' },
{ kind: 'primitive', path: 'src/primitives/select-control/styles.css' },
{ kind: 'primitive', path: 'src/primitives/select-menu/styles.css' },
@@ -114,6 +115,7 @@ export const primitiveStyleSources = [
{ kind: 'primitive', path: 'src/primitives/textarea/styles.css' },
{ kind: 'primitive', path: 'src/primitives/texture/styles.css' },
{ kind: 'primitive', path: 'src/primitives/time-list/styles.css' },
+ { kind: 'primitive', path: 'src/primitives/tilt-frame/styles.css' },
{ kind: 'primitive', path: 'src/primitives/tooltip/styles.css' },
{ kind: 'primitive', path: 'src/primitives/tool-call-panel/styles.css' },
{ kind: 'primitive', path: 'src/primitives/toolbar-control/styles.css' },
diff --git a/packages/concrete/src/tests/import-boundaries.test.ts b/packages/concrete/src/tests/import-boundaries.test.ts
index 1a3a5cd..7233fb0 100644
--- a/packages/concrete/src/tests/import-boundaries.test.ts
+++ b/packages/concrete/src/tests/import-boundaries.test.ts
@@ -100,6 +100,7 @@ const dynamicPrimitiveInlineStyleFiles = [
'packages/concrete/src/primitives/diagram-viewport/component.tsx',
'packages/concrete/src/primitives/progress/component.tsx',
'packages/concrete/src/primitives/range-control/component.tsx',
+ 'packages/concrete/src/primitives/scale-frame/component.tsx',
'packages/concrete/src/primitives/skeleton/component.tsx',
'packages/concrete/src/primitives/slider/component.tsx',
'packages/concrete/src/primitives/upload-item/component.tsx'
@@ -498,7 +499,7 @@ describe('Import boundaries', () => {
([key, value]) => value !== toConcreteSelector(key)
)
- expect(concreteClassNameEntries.length).toBe(514)
+ expect(concreteClassNameEntries.length).toBe(520)
expect(classNameRecord.button).toBe('concrete-button')
expect(classNameRecord.diagramCanvasEdgeSelected).toBe('concrete-diagram-canvas-edge-selected')
expect(classNameRecord.validationSummaryAction).toBe('concrete-validation-summary-action')
diff --git a/packages/concrete/src/tests/registry.test.ts b/packages/concrete/src/tests/registry.test.ts
index fe1e0ce..88ab8a9 100644
--- a/packages/concrete/src/tests/registry.test.ts
+++ b/packages/concrete/src/tests/registry.test.ts
@@ -641,6 +641,8 @@ describe('Concrete registry', () => {
'texture',
'time-list',
'tool-call-panel',
+ 'tilt-frame',
+ 'scale-frame',
'brand-mark',
'wordmark',
'icon',
@@ -673,6 +675,7 @@ describe('Concrete registry', () => {
'donut-chart',
'heatmap',
'chart',
+ 'feature-card',
'data-table',
'flow-diagram',
'diagram-canvas',