# penui > penui is a library of Roblox UI components (shops, battle passes, HUDs, inventories, bars, buttons, slots) rendered 1:1 from Figma design files, split into minimal pieces, and exposed to AI agents through an MCP server. The agent searches, sees and composes components, then builds the ScreenGui directly in Roblox Studio through the Roblox Studio MCP. Site: https://penui.dev. Short version of this file: https://penui.dev/llms.txt This document is self-contained. It covers what penui is, the packs, every MCP tool grouped by intent, setup, the Studio workflow, pricing and metering, and an FAQ. ## What penui is - Audience: Roblox game developers who already work with an AI coding agent (Claude Code, Claude Desktop, Cursor, Windsurf, any MCP client) and want production-grade game UI without hand-placing frames in Roblox Studio. - It is not a folder of PNGs and not a UI generator that guesses layouts. Every component is machine-readable: size, 9-slice insets, text layers, fonts, palette, and parent/children with exact offsets. The agent rebuilds real designer-made UI instead of hallucinating it. - Components are built from Figma `.fig` files and rendered 1:1 to PNG by a custom `.fig` renderer (exact corners, strokes, text outlines, gradients, image fills, masks, shadows, blur, blend modes). - Success case: connect the MCP and get a working, consistent screen from one sentence. - Name: "penui" (lowercase "pen", uppercase "UI" in the wordmark). The former name roferoUI is retired. ### Granularity Every component has a `kind`: - `atomic`: minimal piece with no named component inside (a button base, an icon, a frame outline, a bar fill). - `composite`: assembled from atomics; `children[]` and each child's `offsetInParent` (px, relative to parent top-left) let you rebuild it. - `screen`: full composition, reference only. Categories: button, close-button, panel, header, tile, icon, bar, input, decoration, effect-layer (blend/glow overlays, hidden by default), misc. Image metadata: `imageOrigin` is the offset of the PNG relative to the component's top-left (glows and shadows overflow the box). `notext` variants have text removed; a component's `texts[]` holds content, position, font, size, color, stroke and shadow so TextLabels can be added. `nineSlice.insetPx` maps to `ImageLabel.ScaleType = Slice` with `SliceCenter = Rect(i, i, w-i, h-i)`. ### Units (preferred) Units are pre-split, layered pieces (a button, bar, tile...). Per unit: `full.png` (flattened, with text), `notext.png`, and every layer as its own PNG, plus `links` describing how it was attached to its former parent (parent chain, offset and margins, z order, nearest sibling, loose siblings). Units are preferred over rebuilding pieces in Luau. Repeated elements (slots, cards, buttons) are stored once as a reusable template and cloned in Luau. ## Packs - 13 design packs in the library. Pack ids: slots-anime, stud-shop, ang3lz-battlepass, starter-frames, ang3lz-hud, buttons, indexx, rebirth-ui, season-pass, stud-frame-templates, wtever, skibidifig, game-icons. - Use ONE pack per screen so colors, fonts and style stay consistent. Fonts used by the library: Fredoka One and Montserrat (available in Roblox via `Font.fromName`). - The Starter (free) plan on /pricing lists four starter/open-source packs: starter-frames, ang3lz-hud, ang3lz-battlepass, game-icons (800+ CC0 icons: "Game Icon Pack" by Nieobie, https://nieobie.itch.io/free-icons). Paid plans unlock all packs. Counts shown on the site are read live from the library manifest; call `list_packs` for the current numbers. - Source `.fig` licenses belong to their authors. ## MCP tools by intent The server exposes 23 tools over stdio (Node 20+). Search and browse tools are free; metered tools are marked. - Overview and health: `ping` (version and library counts), `list_packs`, `usage` (plan and quota), resource `penui://index` (read first). - Build a screen: `get_studio_workflow` (call once), `search_units`, `get_unit`, then `compose_units` or `compose_screen` (metered), then run the returned Luau with Roblox Studio MCP `execute_luau`. - Find one piece: `search_units` (pre-split layers, preferred) or `search_components`; then `get_unit` or `get_component` (returns the image plus metadata). - Placement inside the original parent: `get_reconnection` and `get_hierarchy`. Responses include parent frame, `offsetInParent`, margins, sibling pieces with exact coordinates, `repeatPositions` for repeated elements, and ready-to-call compose recipes. - Roblox image ids: `asset_status`, `upload_unit_assets` / `upload_assets`, Studio MCP `upload_image`, `register_uploaded_assets`; or set ids manually with `set_asset_id` / `set_file_asset_id`. - Style: `list_packs` (pick one), `get_design_tokens` (fonts and palette), `list_categories`. - Textures: `list_textures`, `get_texture`. - Single Luau script for one component: `get_luau` (metered; mode auto, asset or native). Other MCP surface: resources `penui://index`, `penui://docs/usage`, `penui://docs/studio-workflow`, `penui://pack/{id}`, `penui://component/{id}`; prompt `build-roblox-ui`. Token-efficient responses: compact JSON; `get_component` returns a small thumbnail and a lean summary by default; `compose_screen` / `compose_units` return the Luau as plain text with warnings as leading comments. Unknown ids return suggestions in the error: re-search instead of guessing ids. ## Setup Requirements: Node 20 or newer; Windows 10/11, macOS or Linux. The MCP has no native dependencies (`@modelcontextprotocol/sdk` and `zod` only). ``` git clone https://github.com/StefNoob/penui && cd penui node tools/setup.mjs --client claude-code # or: claude-desktop | cursor | windsurf | vscode ``` - The setup script installs runtime dependencies only, checks Node and the library, performs a real MCP handshake, and registers the server only in the client named with `--client` (that config is backed up to `.bak` first). With no flag it changes nothing and prints the JSON config. - The server contacts the network only for metered tools (usage API, only if `PENUI_API_KEY` is set) and Roblox uploads (only if you provide a key). There is no telemetry. - `npm run doctor` re-runs the checks; `npm test` runs the full suite. - Manual registration: `claude mcp add penui -- node /absolute/path/to/mcp/server.mjs`. - Generic JSON config (Cursor, Claude Desktop, others): ```json { "mcpServers": { "penui": { "command": "node", "args": ["--no-warnings", "/absolute/path/to/mcp/server.mjs"] } } } ``` - Opening the folder in Claude Code works with no setup: `.mcp.json` is included. - For metered tools set `PENUI_API_KEY` in the server environment. Create a key on the usage page after signing in. ## Studio workflow You need two MCP servers: penui (the library) and a Roblox Studio MCP (`execute_luau`, `create_object`, `set_script_source`, `start_playtest`, `get_instance_children`). penui produces Luau; Studio MCP runs it. 1. Pre-flight (once): confirm a place is open in Studio (`list_studio_sessions` / `get_place_info`), then call penui `asset_status`. 2. Pick one pack with `list_packs`; get fonts and palette with `get_design_tokens`. 3. Find pieces: `search_units { query, pack, kind }` or `search_components`. Inspect `get_unit` / `get_component` and the `reconnection` block, or call `get_reconnection` for the full spatial map of a parent. 4. Compose: `compose_units` or `compose_screen` with name, width, height, `layout`, `expand_repeats` and `items`. If `x`/`y` are omitted in manual layout, each piece snaps to its original offset. Repeatable pieces are placed once and cloned across their repeat positions (`f:Clone()`); pass `count: N` to override or `repeat: false` for one instance. `texts: ["Buy", "$4.99"]` replaces text layers in order. Only 9-slice items should be resized with `w`/`h`. 5. Place it: run the returned Luau with Studio `execute_luau`. It creates `StarterGui/` and replaces any older version. Verify with `get_instance_children` and optionally `start_playtest`. 6. Behaviour (only if asked): add a LocalScript with `set_script_source` (open/close, hover tween, buy button to RemoteEvent). Button components are Frames; add a transparent TextButton/ImageButton over the art to make them clickable. Rules of thumb: do not mix packs in one screen; one font family; keep touch targets at least 44 px for mobile; never use one flat image for a grid of slots (use the repeatable unit); effect layers are hidden in search unless you request `category: "effect-layer"`; text uses `notext` art plus TextLabels. ### Images: native vs uploaded - Without uploads, simple pieces (button, close-button, panel, header, tile, bar, input) are built natively with Frame + UICorner + UIGradient + UIStroke. Icons, decorations and glows need art. - With uploads, components use ImageLabel with 9-slice for a pixel-exact look. - No API key needed (preferred): `upload_unit_assets { pack, ids }` returns local image paths; pass them to Studio MCP `upload_image`, then send its result unchanged to `register_uploaded_assets`. Repeat while `remainingAfterBatch > 0`. Upload only the units you use. - With an Open Cloud key: set `ROBLOX_API_KEY` plus `ROBLOX_USER_ID` or `ROBLOX_GROUP_ID` in the server environment; `upload_assets { pack }` uploads directly and records ids in `library/roblox-ids.json`. - Manual: import PNGs in Studio's Asset Manager and bind ids with `set_asset_id`. ## Pricing and metering Prices below are as published on https://penui.dev/pricing (EUR; annual billing saves 20%). Check that page for current terms. - Starter: free, no card. Local stdio MCP server, 4 starter/open-source packs (incl. the CC0 Game Icon Pack by Nieobie), native instance builder, full pixel metadata, `compose_screen` and `get_luau`, personal and prototype Roblox Studio places. - Indie: 19 EUR/month, or 15 EUR/month billed yearly (180 EUR). All packs, @1x/@2x/notext/SVG exports, Open Cloud uploader, `compose_units` and multi-pack composition, textures, commercial license for one developer, new packs included. - Studio: 49 EUR/month, or 39 EUR/month billed yearly (468 EUR). Everything in Indie plus up to 5 team seats, Roblox Group asset sync (`ROBLOX_GROUP_ID`), custom `.fig` ingestion (up to 2 files per month), private pack hosting, studio-wide commercial license, priority support. Metering of the MCP: - Search and browse tools are free. - `get_luau` costs 1. `compose_screen` and `compose_units` cost 1 per 10 distinct items (minimum 1). - Metered tools need `PENUI_API_KEY`. Plans carry daily and monthly limits and may restrict which packs are usable. When a limit is reached the tool reports it and when it resets; search and browse keep working. The `usage` tool and the /usage page (sign-in required) show plan and quota. - If the metering API is unreachable, metered tools fail closed rather than run free. - The metering plan names and quotas can differ from the marketing tiers above and may change; read them from the `usage` tool or /usage rather than assuming. ## FAQ **What does the free plan include?** The MCP server, four starter packs (including 800+ CC0 icons by Nieobie), and native Roblox instance generation, so an agent can compose a complete ScreenGui in Studio with no image uploads. **Do I need a Roblox Open Cloud API key?** No. Without one the agent can build natively, or you can upload PNGs through Studio's Asset Manager and bind them with `set_asset_id`, or use `upload_unit_assets` with Studio's `upload_image`. With a key, `upload_assets` uploads a whole pack and records the `rbxassetid://` ids. **What happens to my games if I cancel?** According to the pricing page, UI screens, scripts and image assets already built and uploaded into your experiences remain yours; cancelling stops new pack downloads and updates at the end of the billing period. **Which clients work?** Any MCP client that supports stdio servers: Claude Code, Claude Desktop, Cursor, Windsurf, VS Code, and others. A Roblox Studio MCP must also be connected to run the Luau. **Does it send my data anywhere?** No telemetry. Network use is limited to the usage API for metered tools (only when `PENUI_API_KEY` is set) and Roblox uploads (only when you provide a key). **What are the renderer's limits?** NOISE/GRAIN effects are approximated, and BACKGROUND_BLUR, angular/diamond gradients and per-run text styling are not rendered. **Why did an id lookup fail?** Unknown ids return suggestions in the error. Re-run a search instead of guessing. ## Pages - Landing: https://penui.dev/ - Library (browse packs and components): https://penui.dev/library - Docs: https://penui.dev/docs - Pricing: https://penui.dev/pricing - Usage (signed-in, not indexed): https://penui.dev/usage - Source and setup: https://github.com/StefNoob/penui