Illustrative Mathematics® Learn Math for life

Architecture Overview

Integral's turborepo architecture

Turborepo Structure

This design system is built as Turborepo packages, enabling shared code and consistent tooling across all packages and applications.

Directory Structure

.
├── apps/
│   ├── curriculum-app/          # Main application (port 3000)
│   ├── design-system-docs/      # Design system documentation (port 4000)
│   ├── platform-content-app/    # Payload application (port 3001)
│   └── a11y/                    # Accessibility report generator cli
├── packages/
│   ├── @im/integral.            # Unified design system
│   │   ├── components/
│   │   │   ├── primitives/      # Pure TSX components (i.e. from shadcn/radix)
│   │   │   └── styled/          # CSS/SCSS themed components
│   │   └── styles/
│   │       ├── components/      # Component-level SCSS styles
│   │       │   ├── primitives/  # Styles for primitive components (i.e. from shadcn/radix)
│   │       │   └── styled/      # CSS/SCSS for Styled components
│   │       ├── foundations/     # Foundational SCSS styles
│   │       ├── legacy/          # Legacy SCSS styles
│   │       ├── mixins/          # Mixins, for use within the packages, possibly app level in the future
│   │       ├── tailwind/        # Brand Tailwind Config
│   │       └── whimsical/       # Animation library
│   ├── @im/integral-tokens      # Design tokens
│   └── @im/typescript-config    # Shared TS configs
└── turbo.json                   # Turborepo configuration
└── biome.json                   # Code formatting & linting

Key Design Decisions

Below are the major technical choices that shape the design system’s architecture.

1. Hybrid Styling Architecture

Pure CSS vs SCSS

  • Foundations Styles: SCSS for design system styles
  • Legacy Styles: Legacy SCSS for application-wide styles
  • Mixins: SCSS Mixin utilites for within the design system package
  • Styled Component Styles: SCSS with variables, mixins, and nesting (Overrides foundations, legacy, and primitives styles)
  • Whimsical Styles: Optional SCSS animations
  • Tailwind Config: Applies design token overrides to tailwind config
  • Tailwind Utilities: App level tailwind overrides all CSS cascade layers

2. CSS Cascade Layers Architecture

We use CSS Cascade Layers to manage style precedence:

@layer tokens, resets, base, theme, legacy, integral, app, utilities;
@layer integral {
  @layer foundations, whimsical, utilities.primitives, utilities.styled;
}

Layer Structure:

  1. tokens: Design tokens (optional layer)
  2. resets: Global CSS Resets
  3. base: Fumadocs, Tailwind preflight (optional layer)
  4. theme: Design tokens, Tailwind theme, Design System theme
  5. legacy: Global styles for accessim.org
  6. integral: Design system styles with sub-layers:
    • integral.foundations: System-wide styles
    • integral.whimsical: Animations
    • integral.utilities.primitives: Primitive components
    • integral.utilities.styled: Styled components
  7. app: app level styles (optional layer)
  8. utilities: Tailwind utility classes

Why Cascade Layers?

  • Predictable specificity without !important
  • Mix SCSS, CSS, and Tailwind seamlessly
  • Clear override hierarchy
  • Performance optimizations (tree shaking, lazy loading)

3. Build Configuration

Hybrid Build Process

  • Tokens: Compiled to CSS, SCSS, JS via style-dictionary CLI
  • SCSS: Compiled to CSS via sass CLI, imported to layers at app level
  • CSS: Exported directly, JIT compilation at app level
  • Components: Export raw .tsx files, JIT compilation at app level

Design System Build Pipeline

Design Token Exports

"exports": {
    "./css/tokens.css": "./dist/css/tokens.css",
    "./scss/_tokens.scss": "./dist/scss/_tokens.scss"
  }

Design System Exports

"exports": {
    "./styles/resets.css": "./src/styles/legacy/b-baseline/b-resets.css",
    "./styles/themes.css": "./src/styles/legacy/b-baseline/b-themes.css",
    "./styles/legacy.css": "./dist/styles/legacy/styles.css",
    "./styles/foundations.css": "./dist/styles/foundations/styles.css",
    "./styles/components/primitives.css": "./src/styles/components/primitives/styles.css",
    "./styles/components/styled.css": "./dist/styles/components/styled/styles.css",
    "./styles/tailwind.css": "./dist/styles/tailwind/styles.css",
    "./styles/whimsical.css": "./dist/styles/whimsical/styles.css",
    "./components/primitives": "./src/components/primitives/index.ts",
    "./components/styled": "./src/components/styled/index.ts"
  },

Style Dictionary for Tokens

  • JSON source → CSS variables + SCSS variables + JS variables
  • Automated token generation
  • Framework-agnostic output

4. Import Strategies

Component Imports

// Primitives (pure primitive components)
import { Button } from '@im/integral/components/primitives';

// Styled components (Design-aligned components)
import { SampleButton } from '@im/integral/components/styled';

Style Imports (in global.css)

/* Import with cascade layers */
@layer tokens, base, theme, legacy, integral, app, utilities;
@import 'tailwindcss/preflight.css' layer(base);
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
@import '@im/integral/styles/resets.css' layer(base);
@import '@im/integral/styles/themes.css' layer(theme);
@import 'tailwindcss/theme.css' layer(theme);
@import '@im/integral/styles/tailwind.css' layer(theme);
@import '@im/integral/styles/legacy.css' layer(legacy);
@import '@im/integral/styles/foundations.css' layer(integral.foundations);
@import '@im/integral/styles/whimsical.css' layer(integral.whimsical);
@import '@im/integral/styles/components/primitives.css'
  layer(integral.utilities.primitives);
@import '@im/integral/styles/components/styled.css'
  layer(integral.utilities.styled);
@import 'tailwindcss/utilities.css' layer(utilities);

These @import paths work because the packages use exports fields in package.json, and the monorepo is configured with TypeScript path aliases and Next.js's built-in support for CSS and module resolution.

5. Styling Approach

Tailwind CSS v4

  • PostCSS-based configuration
  • Design tokens integration
  • Component primitive utilities are manually converted via @apply (required for use in css cascade layer)

SCSS Integration

  • Styled components use SCSS features:
    • Variables for theming
    • Mixins for reusable patterns
    • Nesting for component structure
    • Functions for calculations

Primitive Components

  • Pure CSS only (no SCSS)
  • Tailwind utilities via @apply
  • Minimal specificity for brand and app level overrides

Development Workflow

Design System Development

For Primitive Components (i.e. from Shadcn)

  1. Create component in packages/integral/src/components/primitives/
  2. Add any included styles in packages/integral/src/styles/components/primitives/[component].css (i.e. styles that may be from radix or shadcn)
  3. Convert any Tailwind utilities with @apply
  4. Export from primitives index

For Styled Components (SCSS)

  1. Create component in packages/integral/src/components/styled/
  2. Add styles in packages/integral/src/styles/components/styled/[component].scss
  3. Use SCSS features for theming
  4. Export from styled index

Build Process

# Build all apps and packages
turbo build
# or for curriculum-app
turbo build:local
# Start all apps and packages in dev mode
turbo dev

Dev Mode

turbo dev will start all apps and packages with watchers or hot module reloading. Changes to any source file in any package or app should immediately reflect in the running apps.

# Alias to launch docs app
turbo docs
# Build design system
turbo @im/integral#build

# or
turbo build --filter=@im/integral
# Build design tokens
turbo @im/integral-tokens#build

# or
turbo build --filter=@im/integral-tokens

Turborepo Task Dependencies

Turborepo has all of the packages setup as workspace dependencies, so running turbo dev, turbo build, turbo docs, or turbo build:local will all first build any packages listed in the package.json dependencies or the devDependencies.

Performance Optimizations

Tree Shaking

  • sideEffects: false in package.json
  • Direct imports avoid importing entire libraries

CSS Loading Strategy

  • Cascade layers ensure proper specificity
  • Split bundles for primitives vs brand components
  • PostCSS optimization in production
  • Selective imports for smaller bundles or non-branded apps

Development Speed

  • Package builds are typically minimized during development
    • Turbo caches unchanged packages
    • Direct file exports are used for just in time (JIT) compilation at app level
  • Hot reload works across package boundaries

Best Practices

Design System Guidelines

  • Tokens: Use for all colors/spacing/typography
  • Layers: Flexible cascade hierarchy
  • Primitives: Pure CSS, no SCSS features, Use to collect styles included from external components like shadcn
  • Styled Components: Use SCSS for complex styling
  • Utilities: App level overrides using tailwind utilities

App Guidelines

  • Import styles in correct layer order
  • Use design tokens over hard-coded values
  • Prefer local app level overrides with tickets to migrate to shared design system
  • Test any package modifications across apps before committing

Summary

This architecture provides:

  • Hybrid Styling: Supports CSS, SCSS, and Tailwind all in one ecosystem
  • Cascade Control: CSS layers eliminate specificity issues
  • Unified System: All design assets in one package
  • Performance: Optimized builds with selective compilation
  • Developer Experience: Clear patterns and fast iteration
  • Flexibility: Mix styling approaches based on needs

The combination of Turborepo, CSS Cascade Layers, Tailwind CSS v4, and our hybrid CSS/SCSS approach creates a modern, performant foundation for building scalable applications with a consistent design language.