Visual Tuner for AI-generated code. Adjust UI values in the browser and save changes directly to source files.
- 🎛️ Visual Controls - Sliders, color pickers, gradient editors, box-shadow editors, and more
- 💾 Save to Source - Click Save or ⌘S to write changes back to source files via AST modification
- ⚡ Hot Reload - See changes instantly in the browser
- 🎨 Cyberpunk Theme - Dark mode UI that stays out of your way
- 📋 Copy Prompt - Copy changes in AI-friendly format
- 🔧 Framework Support - Works with Vite and Next.js
- ↩️ Undo/Redo - Full history support with keyboard shortcuts
- 📱 Responsive Preview - Test layouts at different viewport sizes
- 🔍 Search & Filter - Quickly find controls in large projects
- 🔦 Element Highlighting - Hover elements in your app to highlight them in the control panel
- 📐 Spacing Overlay - Visualize margins and padding
npm install tangent-core vite-plugin-tangentnpm install tangent-core next-plugin-tangentVite (vite.config.ts):
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tangent from "vite-plugin-tangent";
export default defineConfig({
plugins: [react(), tangent()],
});Next.js (next.config.js):
const { withTangent } = require("next-plugin-tangent");
module.exports = withTangent({
// your next config
});Vite (App.tsx):
import { TangentProvider } from "tangent-core";
function App() {
return <TangentProvider>{/* your app */}</TangentProvider>;
}Next.js (layout.tsx):
"use client";
import { TangentProvider } from "tangent-core";
export default function RootLayout({ children }) {
return (
<html>
<body>
<TangentProvider endpoint="/api/tangent/update">
{children}
</TangentProvider>
</body>
</html>
);
}Create app/api/tangent/update/route.ts:
import { POST, GET } from "next-plugin-tangent/api";
export { POST, GET };import { useTangent, TangentRoot } from "tangent-core";
function Hero() {
const styles = useTangent("HeroSection", {
padding: 60,
headerColor: "#00ff9f",
fontSize: 48,
heroGradient: "linear-gradient(135deg, #00ff9f 0%, #00d4ff 100%)",
titleShadow: "0px 4px 20px 0px rgba(0, 255, 159, 0.4)",
});
return (
<TangentRoot
tangent={styles}
style={{
padding: styles.padding,
background: styles.heroGradient,
}}
>
<h1
style={{
color: styles.headerColor,
fontSize: styles.fontSize,
textShadow: styles.titleShadow,
}}
>
Welcome
</h1>
</TangentRoot>
);
}Once set up, a floating control panel appears in your app:
- Drag header to move the panel anywhere
- Drag right edge to resize width
- Click section headers to collapse/expand
- Use search box to filter controls
- Click ▼ to collapse panel to icon-only mode
| Type | Control | Example |
|---|---|---|
number |
Slider + input | padding: 60 |
string (hex/rgb color) |
Color picker | color: '#00ff9f' |
string (gradient) |
Gradient editor | background: 'linear-gradient(...)' |
string (box-shadow) |
Shadow editor | boxShadow: '0px 4px 20px...' |
string (easing) |
Curve editor | easing: 'cubic-bezier(0.4, 0, 0.2, 1)' |
string (other) |
Text input | text: 'Hello' |
boolean |
Toggle | visible: true |
Visual editor for CSS gradients with:
- Draggable color stops
- Click to add stops, double-click to remove
- Linear/Radial type toggle
- Angle slider for linear gradients
Visual editor for CSS box-shadows with:
- X, Y, Blur, Spread sliders
- Color picker
- Inset toggle
- Live preview
| Shortcut | Action |
|---|---|
⌘⇧T / Ctrl+Shift+T |
Toggle control panel |
⌘Z / Ctrl+Z |
Undo |
⌘⇧Z / Ctrl+Shift+Z |
Redo |
⌘⇧S / Ctrl+Shift+S |
Toggle spacing overlay |
↑ / ↓ |
Adjust number ±1 |
Shift + ↑ / ↓ |
Adjust number ±10 |
Click the </> button to open the code preview panel:
- Diff tab - Shows changes as a diff from original values
- CSS Vars tab - Exports all values as CSS custom properties
:root {
--hero-section-padding: 60px;
--hero-section-header-color: #00ff9f;
--hero-section-hero-gradient: linear-gradient(...);
}Test your layouts at different viewport sizes:
| Icon | Size | Width |
|---|---|---|
| 📱 | Mobile | 375px |
| 📟 | Tablet | 768px |
| 🖥 | Desktop | 1024px |
| ⬜ | Full | 100% |
useTangentregisters tunable values with the control panel- When you adjust a value, Tangent sends a request to the dev server
- The server uses AST modification (via magicast) to update the source file
- Your bundler's HMR picks up the change and hot reloads
const values = useTangent("ComponentName", {
padding: 60,
color: "#fff",
});id- Unique identifier for this set of valuesdefaultValues- Object with default values (number, string, or boolean)- Returns the current values object extended with
tangentProps
Wrapper component that enables element highlighting.
<TangentRoot tangent={values} as="section" className="hero">
{children}
</TangentRoot>Props:
tangent- The object returned fromuseTangentas- (Optional) Component to render (default:'div')- All other props are passed to the underlying element
<TangentProvider endpoint="/api/tangent/update">{children}</TangentProvider>Props:
endpoint- API endpoint for updates (default:/__tangent/updatefor Vite)
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run Vite playground
pnpm dev
# Run Next.js playground
pnpm -C playground-next devtangent/
├── packages/
│ ├── core/ # React hooks and UI components
│ ├── vite/ # Vite plugin
│ ├── next/ # Next.js plugin
│ └── transform/ # Shared AST transformation logic
├── playground/ # Vite demo app
└── playground-next/ # Next.js demo app
We welcome contributions! Here's how to get started:
-
Fork & Clone
git clone https://github.com/YOUR_USERNAME/tangent.git cd tangent -
Install Dependencies
pnpm install
-
Build Packages
pnpm build
-
Start Development
# Vite playground pnpm dev # Or Next.js playground pnpm -C playground-next dev
-
Create a feature branch
git checkout -b feature/my-feature
-
Make your changes in the relevant package(s)
-
Test your changes in both playgrounds
-
Build to ensure no type errors
pnpm build
-
Commit with a descriptive message
git commit -m "feat: add new input type for X"
- One feature per PR - Keep PRs focused and easy to review
- Update README - If adding new features, document them
- Test both frameworks - Ensure changes work in Vite and Next.js
- Follow existing patterns - Match the code style of existing files
- 🎨 New input types - Border radius editor, font picker, spacing editor
- 🌐 Internationalization - Translate UI text
- ♿ Accessibility - Improve keyboard navigation and screen reader support
- 📚 Documentation - Tutorials, examples, better API docs
- 🧪 Testing - Unit tests, integration tests, E2E tests
- 🐛 Bug fixes - Check issues for reported bugs
When reporting bugs, please include:
- Browser and OS version
- Framework (Vite/Next.js) and version
- Steps to reproduce
- Expected vs actual behavior
| Package | Description |
|---|---|
tangent-core |
React hooks and UI components |
vite-plugin-tangent |
Vite plugin with dev server middleware |
next-plugin-tangent |
Next.js plugin with API route handlers |
tangent-transform |
Shared source code transformation logic |
MIT
