بنقرة واحدة
build-react-apps
Produce high-quality React apps from natural language descriptions.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Produce high-quality React apps from natural language descriptions.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
How authenticated HTTP calls to the Opal backend work — the host/guest architecture, fetchWithCreds, the fetch allowlist, and the OpalBackendClient migration. Read this before adding, modifying, or debugging any backend call.
Learn how to make widgets on canvas
Produce high-quality React apps from natural language descriptions.
Teaches you how to properly operate in the sandboxed environment you're in.
Learn how to present your work as a structured surface — a curated manifest of artifacts that the user's application renders in real time.
Learn how to use `window.opalSDK` inside your sandboxed React component to read files, call host services, and listen for events from the application.
| 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 / minmax for multi-column layouts:
grid-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).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.