penframe
v0.3.0
Published
A lightweight DSL-based wireframe and UI structure visualization tool.
Maintainers
Readme
PenFrame
A lightweight DSL-based wireframe and UI structure visualization tool. ✏️ Powered by PenFrame syntax.
PenFrameは、シンプルなDSL(Domain Specific Language)を使ってワイヤーフレームやUI構造を記述し、SVG形式で可視化できるツールです。
Installation
NPM Package
npm install -g penframeFrom Source
git clone https://github.com/ai-program/penframe.git
cd penframe
npm install
npm run buildQuick Start
1. Create a PenFrame file
Create a file with .pf extension:
@app { width: 1200, height: 600, title: "My App" }
@headline "Welcome" { level: 1, color: "#333" }
@hr
@p "Welcome to our app!" { align: "center" }
@button "Get Started" { color: "#007bff", textColor: "#ffffff" }
@tabs { items: ["Home", "Features", "Contact"], active: 0 }
@badge "New" { color: "#e74c3c" }2. Generate SVG and PNG
# Parse DSL to JSON AST
penframe input.pf
# Generate SVG
penframe input.pf --svg output.svg
# Generate PNG (using Puppeteer for high quality)
penframe input.pf --png output.png
# PNG with custom size and high DPI
penframe input.pf --png output.png --width 1000 --scale 2
# PNG with custom background
penframe input.pf --png output.png --background transparent
# Convert AST JSON to PNG
node src/ast2png.js examples/ast_sample.json output.png --width 800 --scale 3Supported Elements
PenFrame supports the following UI elements:
Basic Elements
@headline "Text"- Page headlines@p "Text"- Text paragraphs@button "Text"- Interactive buttons@hr- Horizontal dividers
Layout Elements
@container {...}- Container blocks@tabs { items: ["Tab1", "Tab2"] }- Tab navigation@table [[...]]- Data tables
Form Elements
@formcontrol "label" { control: "textbox" }- Input fields@list { items: ["Item1", "Item2"] }- Lists
Media & Indicators
@image { url: "path" }- Images@badge "Text"- Status badges
Configuration
Each element supports configuration options:
@button "Submit" {
color: "#28a745",
textColor: "#ffffff",
width: 120,
height: 40
}
@tabs {
items: ["Home", "Profile", "Settings"],
active: 0,
width: 300
}
@badge "New" {
color: "#dc3545",
borderRadius: 8
}Project Structure
src/parser/grammar.pegjs- PEG.js grammar definitiondist/parser.js- Built parser (generated)src/svg/astToSvg.js- AST to SVG convertersrc/svg/astToPng.js- AST to PNG converter (Puppeteer)src/cli.js- Command line interfaceexamples/- Sample files and AST examplesdocs/- Documentation
Development
Build Parser
npm run buildRun Tests
npm testParse DSL File
npm start -- examples/sample.pfConvert AST to SVG
node src/svg/ast2svg.js examples/ast_sample.json output.svgConvert AST to PNG
node src/ast2png.js examples/ast_sample.json output.png --width 800 --scale 2API Usage
Module Import (for VScode extensions, etc.)
// ES6 import (recommended for modern projects)
import { penframeToSvg, penframeToPng, parse } from 'penframe';
// CommonJS require
const { penframeToSvg, penframeToPng, parse } = require('penframe');Direct DSL to SVG/PNG Conversion
const { penframeToSvg, penframeToPng, penframeToPngFile } = require('penframe');
const fs = require('fs');
const dslCode = `
@headline "Hello World" { level: 1, color: "#333" }
@button "Click Me" { color: "#007bff", textColor: "#ffffff" }
@badge "New" { color: "#e74c3c" }
`;
// Convert to SVG
const svg = penframeToSvg(dslCode);
fs.writeFileSync('output.svg', svg);
// Convert to PNG buffer (for in-memory use)
const pngBuffer = await penframeToPng(dslCode, {
width: 800,
deviceScaleFactor: 2,
background: 'white'
});
// Convert to PNG file
await penframeToPngFile(dslCode, 'output.png', {
width: 800,
height: 600,
deviceScaleFactor: 2
});Lower-level API (AST-based)
const { parse, astToSvg, astToPngFile } = require('penframe');
const dslCode = fs.readFileSync('input.pf', 'utf8');
const ast = parse(dslCode);
console.log(JSON.stringify(ast, null, 2));
const svg = astToSvg(ast);
fs.writeFileSync('output.svg', svg);
await astToPngFile(ast, 'output.png', {
width: 800,
height: 600,
deviceScaleFactor: 2
});VSCode Extension Usage
For VSCode extensions (like Mermaid preview), you can use PenFrame as follows:
// In your VSCode extension
import { penframeToSvg } from 'penframe';
// Get PenFrame DSL from markdown code block
const penframeDsl = `
@app { width: 800, height: 400, title: "My Wireframe" }
@headline "Dashboard" { level: 1 }
@tabs { items: ["Overview", "Analytics", "Settings"], active: 0 }
@button "Save Changes" { color: "#28a745" }
`;
// Convert to SVG for preview
const svgContent = penframeToSvg(penframeDsl);
// Display in webview
webviewPanel.webview.html = `
<!DOCTYPE html>
<html>
<body>
${svgContent}
</body>
</html>
`;Example Markdown Integration
```penframe
@app { width: 600, height: 300 }
@headline "Login Form" { level: 2 }
@formcontrol "Username" { control: "textbox" }
@formcontrol "Password" { control: "textbox" }
@button "Login" { color: "#007bff" }
```Browser Usage
PenFrame can also be used directly in browsers via CDN or by downloading the minified file.
CDN Usage
<!-- Include PenFrame from CDN -->
<script src="https://unpkg.com/penframe@latest/dist/penframe.min.js"></script>
<script>
// Parse DSL
const dslCode = `
@app { width: 600, height: 300, title: "My App" }
@headline "Hello Browser!" { level: 1 }
@button "Click Me" { color: "#007bff" }
`;
// Generate SVG
const svg = PenFrame.penframeToSvg(dslCode);
document.body.innerHTML = svg;
// Generate PNG Data URL
PenFrame.penframeToPngDataURL(dslCode, {
width: 600,
height: 400,
scale: 2
}).then(dataURL => {
const img = document.createElement('img');
img.src = dataURL;
document.body.appendChild(img);
});
</script>Local File Usage
- Download
penframe.min.jsfrom the releases - Include it in your HTML:
<script src="./penframe.min.js"></script>
<script>
// Use PenFrame global object
const svg = PenFrame.penframeToSvg('@headline "Hello!" { level: 1 }');
</script>Browser API
The browser version provides:
PenFrame.parse(dslCode)- Parse DSL to ASTPenFrame.penframeToSvg(dslCode)- Convert DSL to SVGPenFrame.penframeToPngDataURL(dslCode, options)- Convert to PNG Data URLPenFrame.penframeToPngBlob(dslCode, options)- Convert to PNG Blob
Note: Browser version uses Canvas API for PNG generation instead of Puppeteer.
Live Demo
Check out the live demo at examples/browser-demo.html after building:
npm run build:browser
# Open examples/browser-demo.html in your browserContributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
