Files
pos-system/microservices/.agent/skills/pencil-design/references/BUILD_SYSTEM.md
Ho Ngoc Hai 76d75c753b Migrate
2026-05-23 18:37:02 +07:00

9.9 KiB

Build System Reference

Complete guide to the Pencil build system for component linking and monolithic builds.

Overview

The build system enables:

  • Component Linking: Reference components across files
  • Monolithic Builds: Merge all pages + components into one file
  • Standard Builds: Inject components into individual pages
  • Validation: Ensure output structure is valid

Configuration

pencil.config.json

Create in project root:

{
  "version": "1.0",
  "sourceDir": "src",
  "buildDir": "build",
  "componentLibrary": "src/components/ui-kit.pen",
  "buildOptions": {
    "minify": false,
    "validateAfterBuild": true,
    "preserveComments": true
  }
}
Field Description
sourceDir Source files directory
buildDir Build output directory
componentLibrary Path to component library .pen file
minify Minify JSON output
validateAfterBuild Validate JSON after build
preserveComments Keep JSON comments

Build Modes

Merges all pages + component library into one file.

Commands:

python3 scripts/build.py --monolithic
python3 scripts/build.py -m
python3 scripts/build.py --mode monolithic

# Custom output name
python3 scripts/build.py -m --output myDesign.pen

Output:

  • File: tPOS.pen (project root)
  • Contains: All pages + component library as separate frames
  • Size: ~326KB (example)
  • Use case: Opening complete design, sharing, archiving

Example structure:

{
  "version": "2.6",
  "children": [
    {
      "type": "frame",
      "name": "Component Library",
      "children": [ /* All reusable components */ ]
    },
    {
      "type": "frame",
      "name": "Desktop Home Page",
      "children": [ /* Page content */ ]
    },
    {
      "type": "frame",
      "name": "Mobile Home Page",
      "children": [ /* Page content */ ]
    }
  ],
  "variables": { /* Design tokens */ }
}

Component Library Build (Atomic Design)

Merges distributed atomic components into a single library file.

Command:

python3 scripts/build.py --library
python3 scripts/build.py -l

Output:

  • File: src/components/ui-kit.pen (or configured path)
  • Contains: All atoms, molecules, organisms merged into one file
  • Use case: Generating the library to use during page design

Standard Build

Builds individual pages with component injection.

Command:

python3 scripts/build.py
python3 scripts/build.py --mode standard

Output:

  • Directory: build/
  • Files: Separate .pen files with injected components
  • Use case: Development workflow, testing component refs

Example:

build/
├── desktop-home.pen    # With injected components
├── mobile-home.pen     # With injected components
└── tablet-home.pen     # With injected components

Build Process

What the Build Script Does

  1. Load Component Library: Read ui-kit.pen
  2. Extract Components: Find all reusable: true components
  3. Extract Variables: Get design tokens
  4. Find Component Refs: Search for component_ref types in pages
  5. Resolve Paths: Match ui-kit#Button/Primary to actual component
  6. Inject Components: Add component definitions to pages
  7. Convert Refs: Transform component_refref with proper IDs
  8. Validate: Check output structure

Transformation Example

Before build (source file):

{
  "type": "component_ref",
  "component": "ui-kit#Button/Primary",
  "name": "submitButton",
  "overrides": {
    "label_id": {
      "content": "Submit"
    }
  }
}

After build (output file):

Step 1: Component injected at top of children array

{
  "type": "frame",
  "id": "abc123",
  "name": "Button/Primary",
  "reusable": true,
  "children": [
    {
      "type": "text",
      "id": "label_id",
      "content": "Button"
    }
  ]
}

Step 2: Reference converted

{
  "type": "ref",
  "ref": "abc123",
  "name": "submitButton",
  "descendants": {
    "label_id": {
      "content": "Submit"
    }
  }
}

Project Structure

project-name/
├── src/
│   ├── components/
│   │   └── ui-kit.pen           # Component library + design tokens
│   └── pages/
│       ├── desktop-home.pen     # Desktop (1440px)
│       ├── mobile-home.pen      # Mobile (390px)
│       └── tablet-home.pen      # Tablet (768px)
├── build/                       # Standard build output (gitignore)
│   ├── desktop-home.pen         # With injected components
│   └── ...
├── scripts/
│   └── build.py                 # Build script
├── pencil.config.json           # Build configuration
├── tPOS.pen                     # Monolithic build output
└── USAGE_GUIDE.md               # Documentation

Atomic Design Structure

For enterprise-scale UI Kits:

project-name/
├── src/
│   ├── foundations/
│   │   └── design-tokens.pen           # Design system variables
│   ├── atoms/                          # Smallest building blocks
│   │   ├── buttons.pen
│   │   ├── inputs.pen
│   │   └── badges.pen
│   ├── molecules/                      # Combinations of atoms
│   │   ├── form-fields.pen
│   │   └── search-bar.pen
│   ├── organisms/                      # Complex UI sections
│   │   ├── cards.pen
│   │   └── navigation.pen
│   └── pages/                          # Complete pages
│       ├── desktop-home.pen
│       └── mobile-home.pen
├── build/
├── scripts/
│   └── build.py
├── pencil.config.json
└── tPOS.pen

Build Commands Reference

Basic Commands

# Help
python3 scripts/build.py --help

# Monolithic build
python3 scripts/build.py -m

# Standard build
python3 scripts/build.py

# Custom output
python3 scripts/build.py -m --output custom.pen

Validation Commands

# Validate JSON
jq empty tPOS.pen && echo "✅ Valid JSON"

# Check structure
jq '{version, childrenCount: (.children | length)}' tPOS.pen

# List frame names
jq '[.children[].name]' tPOS.pen

# Extract design tokens
jq '.variables' tPOS.pen

# Count components
jq '[.children[0].children[] | select(.reusable == true)] | length' tPOS.pen

Workflows

1. Layout & Components:
   - Update atoms/molecules in `src/atoms/` etc.
   - Run `python3 scripts/build.py --library` to update component library

2. Page Design:
   - Open `src/pages/desktop-home.pen`
   - Use components from the generated `src/components/ui-kit.pen`

3. Production Build:
   - Run `python3 scripts/build.py -m`
   - Output `tPOS.pen` contains everything

Legacy/Mockup Workflow

1. Design in modular files:
   - Edit components in `src/components/ui-kit.pen`
   - Edit pages in `src/pages/*.pen`
   - Use `component_ref` to reference components

2. Build for testing:
   python3 scripts/build.py  # Standard build
   # Open files in build/ to test

3. Build for production:
   python3 scripts/build.py -m  # Monolithic
   # Share tPOS.pen with team/clients

4. Convert to code:
   # Use agent to convert tPOS.pen to HTML/CSS/React/Blazor

Component Library Updates

1. Update component in ui-kit.pen
2. Save file
3. Rebuild all pages:
   python3 scripts/build.py -m
4. Test in Pencil app
5. If OK, commit changes

Adding New Components

1. Open ui-kit.pen in Pencil
2. Create component with:
   - Unique ID
   - Descriptive name (e.g., "Button/Secondary")
   - `reusable: true`
3. Save file
4. Use in pages with component_ref:
   {
     "type": "component_ref",
     "component": "ui-kit#Button/Secondary"
   }
5. Build and test

Best Practices

1. Component References

✅ DO: Use component_ref in source files
❌ DON'T: Hardcode components into pages

✅ DO: Keep components in ui-kit.pen
❌ DON'T: Duplicate components across files

2. Build Before Testing

✅ DO: Build before opening in Pencil
❌ DON'T: Open source files directly

# Correct workflow:
python3 scripts/build.py -m
open tPOS.pen

# Component refs will be resolved ✅

3. Version Control

✅ DO: Commit source files (src/)
✅ DO: Gitignore build output (build/, tPOS.pen)

# .gitignore
build/
tPOS.pen
*.pen.backup

4. Validation

✅ DO: Validate after build
❌ DON'T: Skip validation

# Always validate:
jq empty tPOS.pen && echo "✅ Valid"

5. Configuration Consistency

✅ DO: Keep pencil.config.json in sync
❌ DON'T: Hardcode paths in scripts

# Update config when structure changes

Troubleshooting

Build Script Errors

Error: Component library not found

# Check config
cat pencil.config.json

# Verify path exists
ls -la src/components/ui-kit.pen

Error: Invalid JSON in source file

# Validate source files
jq empty src/components/ui-kit.pen
jq empty src/pages/desktop-home.pen

Error: Component ref not resolved

# Check component exists in library
jq '[.children[0].children[] | select(.name == "Button/Primary")]' src/components/ui-kit.pen

# Check component path syntax
# Correct: "ui-kit#Button/Primary"
# Wrong: "Button/Primary" (missing library prefix)

Output Validation

# Check file was created
ls -lh tPOS.pen

# Validate JSON structure
jq . tPOS.pen > /dev/null && echo "✅ Valid"

# Check version
jq '.version' tPOS.pen

# Count frames
jq '.children | length' tPOS.pen

# List frame names
jq '[.children[].name]' tPOS.pen

Resources