diff --git a/.cursor/environment.json b/.cursor/environment.json index 06198657e..faca89c27 100644 --- a/.cursor/environment.json +++ b/.cursor/environment.json @@ -2,4 +2,4 @@ "agentCanUpdateSnapshot": true, "install": "pnpm install", "start": "pnpm dev:start" -} \ No newline at end of file +} diff --git a/.cursor/worktrees.json b/.cursor/worktrees.json index e57556bc0..bf9e730d2 100644 --- a/.cursor/worktrees.json +++ b/.cursor/worktrees.json @@ -1,5 +1,3 @@ { - "setup-worktree": [ - "pnpm install" - ] + "setup-worktree": ["pnpm install"] } diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea782..9b77ea713 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,15 +24,17 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d6..2bc5d5f71 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,10 +1,9 @@ --- name: Feature request about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- **Is your feature request related to a problem? Please describe.** diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f42fcbe8a..d1fbd05f0 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,7 +4,7 @@ Describe the change and why it is needed. ## Changes -- +- ## Test Plan diff --git a/.github/workflows/build-js.yml b/.github/workflows/build-js.yml index ba5065df4..8a909bb31 100644 --- a/.github/workflows/build-js.yml +++ b/.github/workflows/build-js.yml @@ -2,9 +2,9 @@ name: Build JS on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: build: @@ -20,7 +20,7 @@ jobs: with: node-version: 20 cache: pnpm - cache-dependency-path: 'pnpm-lock.yaml' + cache-dependency-path: "pnpm-lock.yaml" - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/.prettierrc.json b/.prettierrc.json index f94891b0a..27bc9781b 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -5,4 +5,4 @@ "printWidth": 100, "tabWidth": 2, "plugins": ["prettier-plugin-organize-imports"] -} \ No newline at end of file +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 20bcc4f64..a545f08a3 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,3 @@ - # Contributor Covenant Code of Conduct ## Our Pledge @@ -18,23 +17,23 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or advances of +- The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities diff --git a/README.md b/README.md index f16e5b052..b11272a6b 100644 --- a/README.md +++ b/README.md @@ -12,18 +12,12 @@ - OpenUI is a full-stack Generative UI framework — a compact streaming-first language, a React runtime with built-in component libraries, and ready-to-use chat interfaces — that is up to 67% more token-efficient than JSON. - - --- - - [Docs](https://openui.com) · [Playground](https://www.openui.com/playground) · [Sample Chat App](./examples/openui-chat) · [Discord](https://discord.com/invite/Pbv5PsqUSv) · [Contributing](./CONTRIBUTING.md) · [Code of Conduct](./CODE_OF_CONDUCT.md) · [Security](./SECURITY.md) · [License](./LICENSE) - --- ## What is OpenUI @@ -43,7 +37,6 @@ At the center of OpenUI is **OpenUI Lang**: a compact, streaming-first language - **Streaming renderer** — Parse and render model output progressively in React as tokens arrive. - **Chat and app surfaces** - Use the same foundation for assistants, copilots, and broader interactive product flows. - ## Quick Start ```bash @@ -62,8 +55,6 @@ What this gives you: - **Streaming support** - Update the UI progressively as output arrives. - **Working app foundation** - Start from a ready-to-run example instead of wiring everything manually. - - ## How it works Your components define what the model can generate. @@ -87,12 +78,12 @@ Try it yourself in the [Playground](https://www.openui.com/playground) — gener ## Packages -| Package | Description | -| :--- | :--- | -| [`@openuidev/react-lang`](./packages/react-lang) | Core runtime — component definitions, parser, renderer, prompt generation | -| [`@openuidev/react-headless`](./packages/react-headless) | Headless chat state, streaming adapters, message format converters | -| [`@openuidev/react-ui`](./packages/react-ui) | Prebuilt chat layouts and two built-in component libraries | -| [`@openuidev/cli`](./packages/openui-cli) | CLI for scaffolding apps and generating system prompts | +| Package | Description | +| :------------------------------------------------------- | :------------------------------------------------------------------------ | +| [`@openuidev/react-lang`](./packages/react-lang) | Core runtime — component definitions, parser, renderer, prompt generation | +| [`@openuidev/react-headless`](./packages/react-headless) | Headless chat state, streaming adapters, message format converters | +| [`@openuidev/react-ui`](./packages/react-ui) | Prebuilt chat layouts and two built-in component libraries | +| [`@openuidev/cli`](./packages/openui-cli) | CLI for scaffolding apps and generating system prompts | ```bash npm install @openuidev/react-lang @openuidev/react-ui @@ -154,7 +145,6 @@ Good places to start: - [Discord](https://discord.com/invite/Pbv5PsqUSv) — Ask questions, share what you're building - [GitHub Issues](https://github.com/thesysdev/openui/issues) — Report bugs or request features - ## Contributing Contributions are welcome. See [`CONTRIBUTING.md`](./CONTRIBUTING.md) for contribution guidelines and ways to get involved. diff --git a/benchmarks/README.md b/benchmarks/README.md index 19f4aaf63..f0c4cc0cc 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -44,7 +44,6 @@ Measured with `tiktoken` (`gpt-5` model encoder). Generated by GPT-5.2 at temper | e-commerce-product | 2145 | 2449 | 2381 | 1166 | -45.6% | -52.4% | -51.0% | | **TOTAL** | **9122** | **10180** | **9948** | **4800** | **-47.4%** | **-52.8%** | **-51.7%** | - ## Running ### Prerequisites @@ -55,7 +54,6 @@ Export `OPENAI_API_KEY` in your shell: export OPENAI_API_KEY=sk-... ``` - ### 1. Generate samples (calls OpenAI) ```bash diff --git a/docs/app/(home)/components/CompatibilitySection/CompatibilitySection.tsx b/docs/app/(home)/components/CompatibilitySection/CompatibilitySection.tsx index b2717d257..661608d29 100644 --- a/docs/app/(home)/components/CompatibilitySection/CompatibilitySection.tsx +++ b/docs/app/(home)/components/CompatibilitySection/CompatibilitySection.tsx @@ -54,17 +54,9 @@ function Chip({ item }: { item: CompatibilityItem }) { style={{ backgroundColor: item.badgeBg }} > {/* eslint-disable-next-line @next/next/no-img-element */} - {item.name} + {item.name} - - {item.name} - + {item.name} ); } @@ -80,16 +72,12 @@ export function CompatibilitySection() {
{/* LLMs row */}
- - Any LLM - + Any LLM
{LLMS.map((item) => ( ))} - - + more - + + more
@@ -98,16 +86,12 @@ export function CompatibilitySection() { {/* Frameworks row */}
- - Any Framework - + Any Framework
{FRAMEWORKS.map((item) => ( ))} - - + more - + + more
diff --git a/docs/app/(home)/components/FadeInSection/FadeInSection.tsx b/docs/app/(home)/components/FadeInSection/FadeInSection.tsx index adf65cea7..5942cb7d4 100644 --- a/docs/app/(home)/components/FadeInSection/FadeInSection.tsx +++ b/docs/app/(home)/components/FadeInSection/FadeInSection.tsx @@ -9,9 +9,5 @@ interface FadeInSectionProps { } export function FadeInSection({ children, className = "" }: FadeInSectionProps) { - return ( -
- {children} -
- ); + return
{children}
; } diff --git a/docs/app/(home)/components/FeaturesSection/FeaturesSection.tsx b/docs/app/(home)/components/FeaturesSection/FeaturesSection.tsx index c64d53872..8453a2a58 100644 --- a/docs/app/(home)/components/FeaturesSection/FeaturesSection.tsx +++ b/docs/app/(home)/components/FeaturesSection/FeaturesSection.tsx @@ -88,13 +88,9 @@ function DesktopFeatureRow({ feature, index }: { feature: Feature; index: number
- - {feature.title} - + {feature.title} - - {feature.description} - + {feature.description} ); } @@ -103,12 +99,8 @@ function MobileFeatureRow({ feature, index }: { feature: Feature; index: number return (
- - {feature.title} - - - {feature.description} - + {feature.title} + {feature.description}
diff --git a/docs/app/(home)/components/Footer/Footer.tsx b/docs/app/(home)/components/Footer/Footer.tsx index af87b02c9..daa9464c6 100644 --- a/docs/app/(home)/components/Footer/Footer.tsx +++ b/docs/app/(home)/components/Footer/Footer.tsx @@ -1,8 +1,8 @@ "use client"; -import type { CSSProperties } from "react"; import svgPaths from "@/imports/svg-urruvoh2be"; import mascotSvgPaths from "@/imports/svg-xeurqn3j1r"; +import type { CSSProperties } from "react"; import styles from "./Footer.module.css"; // --------------------------------------------------------------------------- @@ -158,9 +158,7 @@ export function Footer() {
-

- Handcrafted with a lot of love. -

+

Handcrafted with a lot of love.

@@ -179,9 +177,7 @@ export function Footer() { {/* Bottom bar */}
-

- 355 Bryant St, San Francisco, CA 94107 -

+

355 Bryant St, San Francisco, CA 94107

© {new Date().getFullYear()} Thesys Inc. All Rights Reserved @@ -194,9 +190,7 @@ export function Footer() {

© {new Date().getFullYear()} Thesys Inc. All Rights Reserved

-

- 355 Bryant St, San Francisco, CA 94107 -

+

355 Bryant St, San Francisco, CA 94107

diff --git a/docs/app/(home)/components/HeroSection/HeroSection.module.css b/docs/app/(home)/components/HeroSection/HeroSection.module.css index 346663af9..7a42c2afa 100644 --- a/docs/app/(home)/components/HeroSection/HeroSection.module.css +++ b/docs/app/(home)/components/HeroSection/HeroSection.module.css @@ -429,4 +429,4 @@ .taglineBreak { display: inline; } -} \ No newline at end of file +} diff --git a/docs/app/(home)/components/HeroSection/HeroSection.tsx b/docs/app/(home)/components/HeroSection/HeroSection.tsx index 4a7ef8423..e4e982e4e 100644 --- a/docs/app/(home)/components/HeroSection/HeroSection.tsx +++ b/docs/app/(home)/components/HeroSection/HeroSection.tsx @@ -10,7 +10,8 @@ import styles from "./HeroSection.module.css"; const LazyMobileActionFigure = lazy(() => import("@/imports/MobileActionFigure")); -const HERO_BUTTON_SHADOW = "0 1.5px 5px 0 rgba(22, 34, 51, 0.06), 0 12px 24px 0 rgba(22, 34, 51, 0.04)"; +const HERO_BUTTON_SHADOW = + "0 1.5px 5px 0 rgba(22, 34, 51, 0.06), 0 12px 24px 0 rgba(22, 34, 51, 0.04)"; const HERO_BUTTON_STYLE = { "--hero-button-shadow": HERO_BUTTON_SHADOW, } as CSSProperties; @@ -57,18 +58,11 @@ function NpmButton({ className = "" }: { className?: string }) { style={HERO_BUTTON_STYLE} onClick={onCopy} > - - {primaryCTA} - + {primaryCTA} - - {primaryCTA} - - @@ -102,10 +96,7 @@ function NpmButton({ className = "" }: { className?: string }) { function DesktopPlaygroundButton({ className = "" }: { className?: string }) { return ( - + {secondaryCTA} @@ -143,11 +134,7 @@ const MASCOT_FILLED_PATHS = [ function MascotSvg() { return ( - + {MASCOT_STROKED_PATHS.map((d) => ( ))} @@ -232,10 +219,7 @@ function DesktopHero() {
{/* CTA buttons */} -
+
diff --git a/docs/app/(home)/components/Navbar/Navbar.tsx b/docs/app/(home)/components/Navbar/Navbar.tsx index 5da6d286a..2478079c9 100644 --- a/docs/app/(home)/components/Navbar/Navbar.tsx +++ b/docs/app/(home)/components/Navbar/Navbar.tsx @@ -37,11 +37,7 @@ function DesktopNavTabs() { return (
{NAV_TABS.map((tab) => ( - + {tab} ))} @@ -103,10 +99,7 @@ function MobileMenu({ starCount, onClose }: { starCount: number; onClose: () => {NAV_TABS.map((tab, index) => (
{index > 0 && diff --git a/docs/app/(home)/components/PossibilitiesSection/PossibilitiesSection.tsx b/docs/app/(home)/components/PossibilitiesSection/PossibilitiesSection.tsx index 9d3a1cffd..772f1b31c 100644 --- a/docs/app/(home)/components/PossibilitiesSection/PossibilitiesSection.tsx +++ b/docs/app/(home)/components/PossibilitiesSection/PossibilitiesSection.tsx @@ -45,9 +45,7 @@ function Card({ title }: { title: string }) {
)}
-

- {title} -

+

{title}

@@ -147,9 +145,7 @@ export function PossibilitiesSection() { {/* Header */}
-

- Endless possibilities. Built in realtime. -

+

Endless possibilities. Built in realtime.

diff --git a/docs/app/(home)/components/ShiroMascot/ShiroMascot.tsx b/docs/app/(home)/components/ShiroMascot/ShiroMascot.tsx index 9e44a08e4..8c2e83d5e 100644 --- a/docs/app/(home)/components/ShiroMascot/ShiroMascot.tsx +++ b/docs/app/(home)/components/ShiroMascot/ShiroMascot.tsx @@ -5,11 +5,7 @@ export function ShiroMascot() { return (
- + diff --git a/docs/app/(home)/components/StepsSection/StepsSection.tsx b/docs/app/(home)/components/StepsSection/StepsSection.tsx index c21a70d9c..a4ff37369 100644 --- a/docs/app/(home)/components/StepsSection/StepsSection.tsx +++ b/docs/app/(home)/components/StepsSection/StepsSection.tsx @@ -88,9 +88,7 @@ function StepBadge({ num, isActive }: { num: number; isActive: boolean }) {
- - {num} - + {num}
); } @@ -102,9 +100,7 @@ function Divider() { function StepDetails({ step, hideDetails }: { step: Step; hideDetails?: boolean }) { return (
-

- {step.description} -

+

{step.description}

{!hideDetails && step.details.length > 0 && (
{step.detailsTitle &&

{step.detailsTitle}

} @@ -141,10 +137,7 @@ function StepIllustration({ stepNumber, mobile }: { stepNumber: number; mobile?: if (mobile) { return ( -
+
-

- {step.title} -

+

{step.title}

{isActive && ( @@ -248,9 +239,7 @@ function MobileStep({
@@ -288,10 +277,7 @@ export function StepsSection() { return (
-
+
{/* Desktop */}
{STEPS.map((step, i) => ( diff --git a/docs/app/(home)/components/UILibrariesSection/UILibrariesSection.tsx b/docs/app/(home)/components/UILibrariesSection/UILibrariesSection.tsx index 9cb5cdaee..6da0c5dff 100644 --- a/docs/app/(home)/components/UILibrariesSection/UILibrariesSection.tsx +++ b/docs/app/(home)/components/UILibrariesSection/UILibrariesSection.tsx @@ -1,6 +1,6 @@ -import type { CSSProperties } from "react"; import mascotSvgPaths from "@/imports/svg-10waxq0xyc"; import svgPaths from "@/imports/svg-urruvoh2be"; +import type { CSSProperties } from "react"; import styles from "./UILibrariesSection.module.css"; // --------------------------------------------------------------------------- @@ -105,10 +105,7 @@ function LibraryCard({ lib }: { lib: UILibrary }) {
{/* Icon */} -
+
{lib.isMascot ? (
@@ -164,9 +161,7 @@ function LibraryCard({ lib }: { lib: UILibrary }) {
{/* Name */} - - {displayName} - + {displayName}
); diff --git a/docs/app/(home)/components/shared/shared.tsx b/docs/app/(home)/components/shared/shared.tsx index d7078a5db..712e1572d 100644 --- a/docs/app/(home)/components/shared/shared.tsx +++ b/docs/app/(home)/components/shared/shared.tsx @@ -5,7 +5,8 @@ import styles from "./shared.module.css"; // Design tokens shared across multiple sections // --------------------------------------------------------------------------- -export const BUTTON_SHADOW = "0px 1px 3px 0px rgba(22,34,51,0.08), 0px 12px 24px 0px rgba(22,34,51,0.04)"; +export const BUTTON_SHADOW = + "0px 1px 3px 0px rgba(22,34,51,0.08), 0px 12px 24px 0px rgba(22,34,51,0.04)"; // --------------------------------------------------------------------------- // Shared components diff --git a/docs/app/blog/[slug]/page.tsx b/docs/app/blog/[slug]/page.tsx index e0122576f..9040a0000 100644 --- a/docs/app/blog/[slug]/page.tsx +++ b/docs/app/blog/[slug]/page.tsx @@ -1,13 +1,11 @@ import { blog } from "@/lib/source"; import { getMDXComponents } from "@/mdx-components"; -import { TOCProvider, TOCScrollArea } from "fumadocs-ui/components/toc/index"; import { TOCItems } from "fumadocs-ui/components/toc/default"; +import { TOCProvider, TOCScrollArea } from "fumadocs-ui/components/toc/index"; import type { Metadata } from "next"; import { notFound } from "next/navigation"; -export default async function BlogPostPage(props: { - params: Promise<{ slug: string }>; -}) { +export default async function BlogPostPage(props: { params: Promise<{ slug: string }> }) { const params = await props.params; const page = blog.getPage([params.slug]); @@ -19,9 +17,7 @@ export default async function BlogPostPage(props: {