Web Artifacts Builder
Build standalone, high-fidelity web artifacts: interactive demos, PRDs, prototypes, and offline tools delivered as a single self-contained HTML file. The workflow is framework-standard — Vite for dev/build, shadcn/ui for components, Tailwind for styling, and a single-file plugin to inline everything. Verify every library with Context7 before relying on its API; do not assume a version or config from memory.
Context7 documentation gate
Before writing or changing code that uses a library, framework, SDK, API, CLI, or cloud service:
- Read the project
package.json(or the framework docs) to determine the exact version in use. - Resolve the library in Context7. Prefer the official, high-reputation result and pin the query to the repository version when that version is available.
- Query one concrete topic at a time: API, configuration, testing, migration, or integration behavior. Use the returned documentation as the source of truth; do not rely on remembered annotations, script names, or property namespaces.
- If the exact version is not indexed, use the nearest official version only as a stated fallback, then verify the actual API in the project source before editing.
- Re-resolve and re-query after changing a dependency version. Do not mix examples from different major versions.
Use Context7 for Vite (and vite-plugin-singlefile), Tailwind CSS, shadcn/ui
and the shadcn CLI, Radix UI, framer-motion, recharts, and lucide-react.
Stack and setup
The standard stack for a modern single-file artifact:
- Vite (React + TypeScript template) for dev server and build.
- Tailwind CSS for utility-first styling — v4 is CSS-first (
@import "tailwindcss"+@theme), while v3 usestailwind.config.js. Match the version in the project; do not mix config styles. - shadcn/ui for accessible, copy-paste components built on Radix UI and
styled with Tailwind. Use the shadcn CLI (
npx shadcn@latest init -t vite,npx shadcn@latest add <component>) rather than hand-copying components. - framer-motion for animation, recharts for charts, lucide-react for icons — all optional, add only what the artifact needs.
Scaffolding a new artifact
Use the shadcn CLI to scaffold a Vite project with components wired up:
# Create a new Vite project (interactive prompts for name/framework)
npm create vite@latest my-artifact -- --template react-ts
# Initialize shadcn/ui (Tailwind v4: config lives in CSS, not a JS file)
npx shadcn@latest init -t vite
# Add only the components you need
npx shadcn@latest add button card input dialog tabs select
npx shadcn@latest initauto-detects the framework and generatescomponents.json; in Tailwind v4 thetailwind.configfield is left empty because theming is CSS-first.- Prefer the CLI over copying component files manually — it resolves the correct Radix dependencies and aliases for the project.
- If the artifact must work offline as one file, keep dependencies minimal; every extra library grows the bundle.
Single-file bundling
The goal is one portable HTML file with all JS/CSS inlined:
- Recommended:
vite-plugin-singlefile. Add it tovite.config.ts:
The plugin setsimport { defineConfig } from "vite" import react from "@vitejs/plugin-react" import { viteSingleFile } from "vite-plugin-singlefile" export default defineConfig({ plugins: [react(), viteSingleFile()], resolve: { alias: { "@": "/src" } }, })assetsInlineLimitto always inline, disables CSS code splitting, setsbase: "./", and forces a single bundle (inline dynamic imports).removeViteModuleLoader: truestrips Vite's loader for a truly standalone file. - Alternative: Parcel (
npx parcel build index.html --no-source-maps) +html-inline— an older approach that also produces a single file. Prefer the Vite plugin when on Vite, since it is the standard tooling. - After building, verify: the file loads from
file://(or any static host), has no console errors, and needs no network requests for fonts, CDNs, or APIs.
Tailwind theming
- Tailwind v4: define tokens with
@themein the CSS entry:
Theme variables generate utility classes automatically and are available as plain CSS variables.@import "tailwindcss"; @theme { --color-primary: oklch(0.55 0.18 160); /* generates bg-primary, etc. */ --font-display: "Satoshi", sans-serif; } - Tailwind v3: extend
themeintailwind.config.js(colors, fontFamily, keyframes/animation), withcontentpointing atindex.htmlandsrc. - Dark mode: class-based (
darkMode: "class"in v3,@custom-variant darkin v4) with a theme provider such asnext-themes. - Keep interactive colors accessible: choose a primary that meets 4.5:1 contrast with the foreground (white or dark), not a bright brand color with white text. Define semantic tokens (background, foreground, card, muted, destructive, border, ring) so components stay consistent.
Component and interaction patterns
- Use shadcn components (button, card, input, dialog, tabs, etc.) for
consistent, accessible UI. They support
asChild(via Radix Slot), CVA variants, andcn()(clsx+tailwind-merge) for merging classes. - Compose, don't rebuild:
App.tsxcomposes components; keep business logic in hooks/utilities so the artifact stays readable. - Icons: lucide-react SVG components at fixed sizes; no emojis as icons.
- Interactive tables/lists: filter + sort with
useMemo; animate enter/exit with framer-motionAnimatePresence. - Live-feel demos: simulate streaming data with a hook (
useState+setIntervalproducing mock events, capped) instead of calling real backends — keeps the artifact self-contained. - Charts: recharts with
ResponsiveContainer; style tooltips/axes to match the theme and remain readable in light and dark mode.
Motion and accessibility
- Motion: framer-motion, durations ~0.3–0.5s,
easeOut/spring; stagger for lists. Honor reduced motion viauseReducedMotion(orprefers-reduced-motion) — never ship motion that ignores it. - Accessibility is non-negotiable:
- Contrast 4.5:1 normal text / 3:1 large UI.
- Visible focus rings, keyboard operability, semantic HTML, ARIA labels.
- Touch targets ≥ 44×44px; no layout shift (use skeletons for async).
cursor-pointeron clickable elements (or the shadcn--pointeroption).
Quality checklist
- Context7 resolved the exact library and the pinned version was checked.
- Scaffolded with the shadcn CLI (
init -t vite,add <component>); no hand-copied components with broken aliases. - Tailwind version matched (v4
@themeCSS-first, or v3 config) and tokens define semantic colors. - Primary action color meets 4.5:1 contrast with its foreground.
- Responsive at 375px, 768px, 1024px, 1920px; touch targets ≥ 44×44px.
- Icons are lucide SVGs; no emojis;
cursor-pointeron clickables. - Motion is 0.3–0.5s and honors reduced motion.
- All buttons, filters, and interactive states work; error states handled.
- Built with single-file bundling (
vite-plugin-singlefilepreferred); output loads offline with no console errors and no external requests. - Bundle size reported with command output; no unnecessary dependencies.