소스 정보
- 저장소
- breadboard-ai/breadboard
- 최근 소스 활동
- 2026년 4월 30일 03:42
- 감지된 SKILL.md 언어
- 영어
- 스타
- 414
- 포크
- 74
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/breadboard-ai/breadboard --skill build-react-apps명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | build-react-apps |
| title | How to build React apps |
| description | Produce high-quality React apps from natural language descriptions. |
| allowed-tools | ["files.*","sandbox.*","system.*"] |
A multi-file React component bundle rendered in a sandboxed iframe. The bundle consists of:
App.jsx — the root component that accepts configuration propscomponents/*.jsx — reusable sub-componentsstyles.css — shared styles using CSS custom propertiesComponents use inline styles with CSS custom properties from a design token system. Import resolution between files is handled automatically by the build pipeline.
Your UI MUST work from 320px to 1200px+. This is not optional.
Write the app an its components as files in your directory.
Build the bundle with bundler.mjs:
node ./skills/{name of this skill}/scripts/bundler.mjs
If you do not run this exact command, the user will see a blank screen.
Follow these rules strictly.
App.jsx and
contain a function called App.App
with realistic defaults.components/ should
render standalone with sensible defaults. Document all props with @prop
JSDoc.import React from "react" in
every JSX file. Import sub-components with relative paths (e.g.
import Header from "./components/Header").import "./styles.css" in App.jsx for shared
styles.export default its component
function.--cg- design
tokens. No hex colors, no rgb(), no named colors, no raw pixel values.
Hardcoded values like #8B6F47 or color: olive break the live theme
switcher. This is a build error, not a suggestion.localStorage, sessionStorage,
IndexedDB, or any Web Storage APIs. The iframe environment may not have
storage access due to origin restrictions. All state lives in React component
state or is passed via props and the SDK.background: black, background: #000, color: #fff, or any dark-theme
values. All backgrounds must use var(--cg-color-surface*) tokens and all
text must use var(--cg-color-on-surface*) tokens. The tokens will natively
map to their light theme variants.flex-wrap: wrap on any flex container with multiple children that
should stack on narrow screens.auto-fit / for multi-column layouts:
.These particular paterns are forbidden.
width: 800px, width: 600px, or similar. Use max-width with a percentage
or min() instead: max-width: min(100%, 800px).min-width exceeding 320px on any layout container. This prevents
rendering on small screens.CRITICAL FORBIDDEN PATTERN: NO TAILWIND!
flex, min-h-screen,
p-4, bg-red-500). Tailwind is NOT INSTALLED.className="hero-container").styles.css file using Vanilla CSS.import "./styles.css"; at the top of your App.jsx. If you
don't write and import a CSS file, your design will be completely unstyled.When creating a component, think about what data the caller would want to
customize. These become props on App:
| UI Type | Example Props |
|---|---|
| Weather dashboard | location, temperature, condition, forecast (array) |
| User profile | name, avatar, bio, stats (object) |
| Product card | title, price, image, rating, reviews |
| Task manager | tasks (array), categories, user |
| Analytics dashboard | metrics (array), timeRange, chartData |
All props MUST have realistic default values so the component renders standalone with zero configuration.
Reminder: this is a hard rule (see above). Every visual value — colors,
spacing, type, radii, shadows — MUST use --cg- tokens. No exceptions.
| Category | Use | Never |
|---|---|---|
| Colors | var(--cg-color-...) | #hex, rgb(), named colors |
| Spacing | var(--cg-sp-...) | Raw pixel values for padding/margin/gap |
| Font sizes | var(--cg-text-...-size) | 14px, 1rem |
| Border radius | var(--cg-radius-...) or var(--cg-card-radius) | 12px, 24px |
| Shadows | var(--cg-elevation-...) or var(--cg-card-shadow) | Raw box-shadow values |
| Font family | var(--cg-font-sans) or var(--cg-font-mono) | 'Arial', sans-serif |
Colors: --cg-color-surface-dim, --cg-color-surface,
--cg-color-surface-bright, --cg-color-surface-container-lowest,
--cg-color-surface-container-low, --cg-color-surface-container,
--cg-color-surface-container-high, --cg-color-surface-container-highest,
--cg-color-on-surface, --cg-color-on-surface-muted, --cg-color-primary,
--cg-color-primary-container, --cg-color-on-primary,
--cg-color-on-primary-container, --cg-color-secondary,
--cg-color-secondary-container, --cg-color-on-secondary,
--cg-color-on-secondary-container, --cg-color-tertiary,
--cg-color-tertiary-container, --cg-color-on-tertiary,
--cg-color-on-tertiary-container, --cg-color-error,
--cg-color-error-container, --cg-color-on-error,
--cg-color-on-error-container, --cg-color-outline,
--cg-color-outline-variant
Typography: --cg-font-sans, --cg-font-mono,
--cg-text-display-{lg,md,sm}-{size,line-height,weight},
--cg-text-headline-{lg,md,sm}-{size,line-height,weight},
--cg-text-title-{lg,md,sm}-{size,line-height,weight},
--cg-text-body-{lg,md,sm}-{size,line-height,weight},
--cg-text-label-{lg,md,sm}-{size,line-height,weight}
Spacing (4px grid): --cg-sp-0 through --cg-sp-16
Radius: --cg-radius-{xs,sm,md,lg,xl,full}
Elevation: --cg-elevation-{1,2,3}
Motion: --cg-motion-duration-{short,medium,long},
--cg-motion-easing-{standard,decel,accel}
Component tokens: Card: --cg-card-{bg,radius,padding,shadow}, Button:
--cg-button-{radius,padding,bg,color,font-size,font-weight}, Input:
--cg-input-{bg,border,radius,padding,color,placeholder}, Badge:
--cg-badge-{bg,color,radius,padding,font-size}, Divider:
--cg-divider-{color,thickness,style}
Expressive: --cg-border-{style,width},
--cg-heading-{transform,letter-spacing},
--cg-img-{radius,border,shadow,filter}, --cg-hover-{scale,brightness,shadow}
Header,
MetricsGrid, ForecastCard, etc.Google Material Symbols Outlined is available via a web font:
<span className="material-symbols-outlined" style={{ fontSize: "20px" }}>
search
</span>
CRITICAL: DO NOT import third-party icon packages. You do not have
lucide-react, heroicons, or react-icons installed. Using them will break
the build. ONLY use the material-symbols-outlined span.
Components should be interactive where appropriate. Use useState, useEffect
with cleanup. Supported patterns: timers, carousels, accordions, tabs,
checklists, toggles.
Never use Date.now(), Math.random(), or new Date() in default parameters.
Compute once at module level or use useState(() => ...).
Your React app is one segment of a wider orchestrated journey. Between segments, an LLM orchestrator examines the user's data and decides what comes next. This means:
ark.emit() to
hand collected data back to the orchestrator. Without this, the journey
stalls.Each state gets its own component file named after the state:
App.jsx — shell that renders the initial stateviews/InputRequirements.jsx — one view per stateviews/SelectModels.jsxviews/DetailedComparison.jsxviews/DecisionReport.jsxcomponents/*.jsx — shared sub-components (reusable across views)styles.css — shared stylesWithin the segment, views navigate using window.opalSDK.navigateTo. At the
boundary (the segment's final view), use window.opalSDK.emit to send data
back to the orchestrator.
The SDK is available as window.opalSDK. It has three methods:
// Navigate to another view WITHIN this segment.
window.opalSDK.navigateTo("select_models", { teamProfile });
// Send data BACK TO THE ORCHESTRATOR (segment boundary).
// Use on the final view's CTA — this is what connects segments.
window.opalSDK.emit("journey:result", { decision, comparisonSet });
// Read a file from the shared workspace (async, returns text or null).
const data = await window.opalSDK.readFile("groceries.json");
Do not call any other methods on window.opalSDK. There is no
onNavigation, subscribe, or event listener API. Navigation state is managed
internally by your App component (e.g. useState + switch statement), not by
the SDK.
readFileUse readFile to load data files from the shared workspace at runtime instead
of hardcoding data into your component. Paths are relative to the workspace
root. You can read files written by any agent in the workspace — for example, a
menu planner can read files produced by a diet researcher.
import React, { useState, useEffect } from "react";
export default function GroceryList() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
window.opalSDK.readFile("groceries.json").then((text) => {
if (text) {
setItems(JSON.parse(text));
}
setLoading(false);
});
}, []);
if (loading) return <div>Loading…</div>;
return (
<ul>
{items.map((item, i) => (
<li key={i}>{item}</li>
))}
</ul>
);
}
Rules for readFile:
Promise<string | null>. null means the file was not found."analysis/results.json",
"diet_research/notes.md").null case gracefully — the file may not exist yet.Each view component receives two props:
data — the journey context relevant to this stateonTransition — callback for state transitions (wired to
window.opalSDK.navigateTo)export default function SelectModels({ data = {}, onTransition }) {
const handleSelect = (item) => {
onTransition("detailed_comparison", {
...data,
shortlist: [...(data.shortlist || []), item],
});
};
// ...
}
components/. Headers, cards, buttons used
across multiple views should be extracted.readFile to load shared workspace data.window.opalSDK.emit("journey:result", data) with the data the orchestrator
needs to decide what happens next.React, useState, useEffect, useRef, useCallback, useMemo,
useContext, useReducer, useLayoutEffect, memo, forwardRef,
createContext, Fragment
Be creative and visually impressive.
minmaxgrid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr))clamp() for font sizes that should scale with viewport:
font-size: clamp(1rem, 2vw + 0.5rem, 2rem).