A compiler pipeline for design systems.
Build scripts are written in Starlark:
palette = struct(primary=color.Oklch(0.5, 0.134, 242.749))
tokens = [Token("primary", light=palette.primary)]
target(
id="acme",
tokens=tokens,
artifacts=[Artifact("css", "dist/acme/css")]
)pip install forjeCreate a build.forje in your project root and run:
forje buildForje supports accessibility testing by letting you declare contrast
requirements using the wcag annotations.
load("wcag", "wcag")
surface = Token("surface", Color("#FFFFFF"))
primary = Token("primary", Color("#0284C7"))
text = Token(
"text",
Color("#1E293B"),
# Will raise a validation error if text fails to meet the AA contrast
# ratio against surface.
annotations=wcag.against(surface, role=wcag.Role.Text, level=wcag.Level.AA)
)
target(
id="acme",
tokens=[surface, primary, text],
artifacts=[Artifact("android", "acme/res")],
)Plugin interface is exposed via Python entry points. For a reference plugin
implementation, see the built-in forje.wcag module.
# DSL extension
[project.entry-points."forje.dsl"]
myplugin = "myplugin.dsl:myplugin_module"
# Type adapter
[project.entry-points."forje.adapter"]
mynode = "myplugin.models:mynode_adapter"
# Compiler pass
[project.entry-points."forje.pass"]
myplugin = "myplugin.passes:MyValidation"
# Platform backend
[project.entry-points."forje.backend"]
myplatform = "myplugin.backend:MyPlatformBackend"The following plugins are maintained alongside Forje and can be installed directly:
forje-tailwind: Tailwind CSS color palette
colors = [
Token(
"primary",
light=color.Oklch(0.5, 0.134, 242.749),
dark=color.Oklch(0.828, 0.111, 230.318),
),
Token(
"surface",
light=color.Oklch(0.97, 0, 0),
dark=color.Oklch(0.205, 0, 0),
),
]
space = [
Token("space.s", dimen.Spacing(0.5)),
Token("space.m", dimen.Spacing(1)),
Token("space.l", dimen.Spacing(2)),
Token("space.xl", dimen.Spacing(4)),
]
target(
id="acme",
tokens=colors + space,
artifacts=[
Artifact("android", "dist/acme/android"),
Artifact("apple", "dist/acme/apple"),
Artifact("compose", "dist/acme/compose", package="com.acme.android.design"),
Artifact("css", "dist/acme/css"),
],
):root {
--dimen-space-s: 0.5rem;
--dimen-space-m: 1rem;
--dimen-space-l: 2rem;
--dimen-space-xl: 4rem;
}
:root {
--color-primary: rgb(0 105 168);
--color-surface: rgb(245 245 245);
}
@media (prefers-color-scheme: dark) {
:root {
--color-primary: rgb(116 212 255);
--color-surface: rgb(23 23 23);
}
}
:root[data-theme="light"] {
--color-primary: rgb(0 105 168);
--color-surface: rgb(245 245 245);
}
:root[data-theme="dark"] {
--color-primary: rgb(116 212 255);
--color-surface: rgb(23 23 23);
}
@supports (color: oklch(0% 0 0)) {
:root {
--color-primary: oklch(0.5 0.134 242.749);
--color-surface: oklch(0.97 0 none);
}
@media (prefers-color-scheme: dark) {
:root {
--color-primary: oklch(0.828 0.111 230.318);
--color-surface: oklch(0.205 0 none);
}
}
:root[data-theme="light"] {
--color-primary: oklch(0.5 0.134 242.749);
--color-surface: oklch(0.97 0 none);
}
:root[data-theme="dark"] {
--color-primary: oklch(0.828 0.111 230.318);
--color-surface: oklch(0.205 0 none);
}
}