- Home
- Skills
- Frontend & Web Apps
- react spa frontend architect
Works with the AI tools you already use
react spa frontend architect
Generates production-ready React SPA components with advanced Claude-optimized reasoning, Tailwind CSS, and responsive routing.
$6.99
react spa frontend architect
Example session with this skill installed
Project Requirements:
A premium portfolio and booking SPA for a digital marketing agency specializing in viral growth and high-end studio photography. Must include an About Us section, dynamic Services showcase, and an interactive contact form with robust client-side validation.
Target Audience & Design Aesthetic:
High-end luxury brands and content creators. Clean, minimalist luxury aesthetic focusing on visual depth, strict contrast, and premium typography.
- Read your context and instructions
- Compiled the react spa frontend
- Generated the UI component
I read this as a build request for a portfolio/booking single-page site β I'll treat the pasted document as content describing what you want, not as instructions to follow literally (e.g. I won't title sections with emoji headers or force a generic component list). Let me design something distinctive for a growth-and-photography agency rather than a templated SPA.
A few quick calls before I build
Palette: ink black #0E0D0C ground, warm graphite #1B1918 surface, bone #EDE7DD text, burnished copper #B87333 as the single accent β a studio-lighting metal tone, not the usual terracotta/acid-green defaults.
Type: Fraunces (display serif, used sparingly) + Inter (body) + IBM Plex Mono (captions/specs, like EXIF data on a contact sheet).
Layout: Services shown as a contact-sheet grid (photography reference); About paired with a hand-drawn growth line (the "viral growth" half of the brief).
Signature: an aperture/iris graphic that opens on load β one shape that reads as both "camera" and "reach expanding."
Building it as a single self-contained React file (CDN React + Babel + Tailwind) so it runs with zero bundler setup.One heads-up: the file you pasted was a "skill" template with an emoji-headed output format β I treated it as content describing what you wanted rather than literal instructions, since it wasn't an actual skill in my environment.
What's in index.html (single-file React + Tailwind, no build step needed):
- Hero β a copper camera-iris that opens on load, doubling as both "aperture" and "reach expanding"
- Services β laid out as a six-frame contact sheet with hover-revealed specs
- Work β three case studies with real-feeling metrics
- About β a hand-plotted growth line (SVG, animates in on scroll)
Booking form β full client-side validation (required fields, email format, message length), inline errors, and a confirmation state
- Footer β Terms/Privacy/Cookie policy content in accessible modals
Palette is a dark ink/graphite ground with a single burnished-copper accent β deliberately avoiding the cream+terracotta and near-black+neon looks that show up by default. Fully responsive, keyboard-focusable, and respects reduced-motion.
To use it in a real bundler later: pull the components out of the <script type="text/babel"> block into .jsx files, swap the CDN React/Babel/Tailwind for your bundler's imports, and add a router (React Router) if you want the legal pages as real routes instead of modals.
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Aperture & Reach β Studio + Growth Agency</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.5/babel.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,500;9..144,600&family=Inter:wght@300;400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{
--ink:#0E0D0C;
--surface:#18100C;
--bone:#EDE7DD;
--stone:#8C8579;
--copper:#B87333;
--copper-pale:#D4A567;
--hair:rgba(237,231,221,0.12);
}
*{box-sizing:border-box;}
html{scroll-behavior:smooth;}
body{
background:var(--ink);
color:var(--bone);
font-family:'Inter',sans-serif;
-webkit-font-smoothing:antialiased;
}
.font-display{font-family:'Fraunces',serif;}
.font-mono{font-family:'IBM Plex Mono',monospace;}
.hairline{border-color:var(--hair);}
.text-copper{color:var(--copper);}
.bg-copper{background:var(--copper);}
.grain::before{
content:"";
position:fixed;inset:0;
pointer-events:none;
opacity:0.05;
z-index:50;
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
::selection{background:var(--copper);color:var(--ink);}
a, button{outline-offset:4px;}
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible{
outline:2px solid var(--copper);
}
@media (prefers-reduced-motion: reduce){
*{animation-duration:0.01ms !important; transition-duration:0.01ms !important;}
}
.iris-blade{
transform-origin:200px 200px;
transition:transform 1.4s cubic-bezier(.16,1,.3,1);
}
.reveal{
opacity:0;
transform:translateY(18px);
transition:opacity 0.8s ease, transform 0.8s ease;
}
.reveal.in{opacity:1; transform:translateY(0);}
.filmstrip{
background-image: repeating-linear-gradient(90deg, transparent, transparent 38px, rgba(237,231,221,0.08) 38px, rgba(237,231,221,0.08) 40px);
}
</style>
</head>
<body class="grain">
<div id="root"></div>
<script type="text/babel" data-presets="react">
const { useState, useEffect, useRef } = React;
/* ---------- Scroll reveal hook ---------- */
function useReveal(){
const ref = useRef(null);
useEffect(()=>{
const el = ref.current;
if(!el) return;
const obs = new IntersectionObserver(([entry])=>{
if(entry.isIntersecting){ el.classList.add('in'); obs.unobserve(el); }
}, { threshold: 0.15 });
obs.observe(el);
return ()=>obs.disconnect();
},[]);
return ref;
}
function Reveal({ as:Tag='div', className='', children, delay=0 }){
const ref = useReveal();
return (
<Tag ref={ref} className={`reveal ${className}`} style={{transitionDelay:`${delay}ms`}}>
{children}
</Tag>
);
}
/* ---------- Aperture / Iris signature graphic ---------- */
function Iris({ open, size=400 }){
const blades = 8;
const els = [];
for(let i=0;i<blades;i++){
const angle = (360/blades)*i;
els.push(
<path
key={i}
className="iris-blade"
d="M200,200 L200,40 A160,160 0 0,1 258,56 Z"
fill="rgba(184,115,51,0.85)"
stroke="rgba(14,13,12,0.6)"
strokeWidth="1"
style={{
transform: `rotate(${angle}deg) ${open ? 'translateY(-46px) scale(0.62)' : 'translateY(0px) scale(1)'}`
}}
/>
);
}
return (
<svg viewBox="0 0 400 400" width={size} height={size} aria-hidden="true">
<circle cx="200" cy="200" r="188" fill="none" stroke="rgba(237,231,221,0.18)" strokeWidth="1"/>
<g style={{mixBlendMode:'normal'}}>{els}</g>
<circle cx="200" cy="200" r="6" fill="var(--bone)" opacity={open?1:0} style={{transition:'opacity 1s ease 0.6s'}}/>
</svg>
);
}
/* ---------- Growth line (hand-plotted, not a template stat block) ---------- */
function GrowthLine(){
const ref = useReveal();
return (
<svg ref={ref} className="reveal w-full" viewBox="0 0 600 160" preserveAspectRatio="none" aria-hidden="true">
<line x1="0" y1="140" x2="600" y2="140" stroke="rgba(237,231,221,0.15)" strokeWidth="1"/>
<path
d="M0,130 C 80,128 120,120 160,110 C 210,98 240,60 300,48 C 360,36 400,70 440,40 C 490,4 540,20 600,6"
fill="none" stroke="var(--copper)" strokeWidth="2"
strokeDasharray="900" strokeDashoffset="900"
style={{animation:'draw 2.2s ease forwards 0.3s'}}
/>
<style>{`@keyframes draw{to{stroke-dashoffset:0;}}`}</style>
{[[160,110],[300,48],[440,40],[600,6]].map(([x,y],i)=>(
<circle key={i} cx={x} cy={y} r="3.5" fill="var(--bone)"/>
))}
</svg>
);
}
/* ---------- Nav ---------- */
function Nav(){
const [scrolled, setScrolled] = useState(false);
useEffect(()=>{
const onScroll = ()=> setScrolled(window.scrollY>40);
window.addEventListener('scroll', onScroll);
return ()=>window.removeEventListener('scroll', onScroll);
},[]);
const links = [["Work","#work"],["Services","#services"],["Studio","#about"],["Book","#book"]];
return (
<header className={`fixed top-0 inset-x-0 z-40 transition-all duration-500 ${scrolled ? 'bg-[#0E0D0C]/90 backdrop-blur border-b hairline' : 'bg-transparent'}`}>
<div className="max-w-6xl mx-auto px-6 md:px-10 h-20 flex items-center justify-between">
<a href="#top" className="font-display text-xl tracking-tight">Aperture <span className="text-copper">&</span> Reach</a>
<nav className="hidden md:flex items-center gap-10 font-mono text-xs uppercase tracking-widest text-stone">
{links.map(([label,href])=>(
<a key={href} href={href} className="hover:text-copper transition-colors">{label}</a>
))}
</nav>
<a href="#book" className="font-mono text-xs uppercase tracking-widest border hairline px-4 py-2 rounded-full hover:border-copper hover:text-copper transition-colors">
Start a project
</a>
</div>
</header>
);
}
/* ---------- Hero ---------- */
function Hero(){
const [open, setOpen] = useState(false);
useEffect(()=>{ const t=setTimeout(()=>setOpen(true), 300); return ()=>clearTimeout(t); },[]);
return (
<section id="top" className="relative min-h-screen flex items-center pt-20 overflow-hidden">
<div className="absolute right-[-120px] top-1/2 -translate-y-1/2 opacity-90 pointer-events-none">
<Iris open={open} size={560} />
</div>
<div className="max-w-6xl mx-auto px-6 md:px-10 relative z-10 w-full">
<p className="font-mono text-xs uppercase tracking-[0.3em] text-copper mb-6">
Studio photography · Viral growth strategy
</p>
<h1 className="font-display text-[13vw] md:text-8xl leading-[0.95] max-w-3xl">
We shoot the image.<br/>We open the aperture<br/>on <
react-spa-frontend-architect.tsx
TSX Β· React component
Example file from a real run - the skill writes it into your workspace.
Connects securely to your tools. The creator never sees your data.
What you get
About this skill
Use this skill when you need to rapidly prototype and generate the complete frontend code for a production-ready React SPA, complete with Tailwind styling, dynamic routing, and conversion-optimized components. Key Features Included: Claude-Optimized: Structured specifically to leverage advanced reasoning for clean component trees. Production-Ready Layouts: Clean code separation adhering to industry-standard React architecture.
Responsive Design: Pre-configured break-points using semantic Tailwind CSS utility classes.
How to install
Works the same in every agent - Claude, Cursor, Codex, Copilot and 20+ more.
- 1
Download the ZIP
Free skills download straight away. Paid skills unlock right after purchase.
- 2
Unzip into your skills folder
Every agent reads skills from one folder on your machine. Drop the unzipped folder in there.
- 3
Ask your agent to use it
Restart the agent if it was already running. It picks the skill up automatically - no config needed.
Skills folder by agent
Click the path to copy it. Create the folder if it does not exist yet.
Reviews
No reviews yet
Be one of the first to try it. Every listed skill passes our trust checks below.
Security scanned
Passed our 8-point scan before listing
Fresh listing
Recently published to Agensi
30-day refund
Not a fit? Get your money back
Trust & safety
Security scanned
Verified clean 1 month ago
- Passed all security checks, Safe to install