Inspiration

Everywhere we looked, we saw the same statistic: factories and clothing companies discard millions of pounds of fabric annually, including overruns that never ship, cutting-room excess, and deadstock. So we began pulling some of it back. We sourced reclaimed cotton and denim, cut and sewed a small run of pieces ourselves (heavyweight tees, a couple of hoodies, a denim jacket, some accessories), and realized we needed somewhere real to sell them. RUNOFF is that storefront. The name is to be taken literally: Everything drains somewhere, even the fabric that was left unwanted.

What it does

RUNOFF is a complete e-commerce front end for the parts we’ve built so far. Customers can choose a size, set quantity, hover to view a second product photo, open a page with an image carousel, and browse a product grid with category filters and price sorting. The cart computes the subtotal, tax, and shipping and resides in both a slide-out drawer and a full page. Because we are still packing by hand, the checkout process is three steps: shipping information, order review, and confirmation.

How we built it

Next.js 14 with the App Router, TypeScript throughout, Tailwind for styling, and a set of shadcn/ui-style components built on Radix primitives. A cart can withstand a refresh because its state is managed by Zustand with localStorage persistence. Since we haven't yet connected inventory to a backend, the catalog is currently a local JSON file that represents the small batch we've actually produced. The product image gallery is handled by Embla Carousel, toast confirmations by Sonner, and the site runs on self-hosted fonts, so no external font CDN is required at build time.

Challenges we ran into

The catalog structure had to be built before every piece was produced in order to photograph and describe products that are still in small-batch production, so the data model had to be reliable regardless of what we changed later. It took several tries to get the cart drawer and the entire cart page to share a single source of truth without repeating logic; ultimately, we decided to always derive totals from the cart lines rather than storing computed values. An empty selection provides clear feedback rather than failing silently because the size-selector-required rule required a real validation state, not just a disabled button.

Accomplishments that we're proud of

The shop-to-checkout flow works from start to finish for a brand that wants to sell recycled fabric. Filtering, sorting, hover states, cart persistence, and the multi-step checkout all come together to create a journey that a real person could take to buy a real item.

What we learned

A field requirement error state, a hovering image, or a toast notification that verifies what was added are examples of small interaction details that have a greater impact on how "real" a storefront feels than any of the major features. When the product behind it is genuine, it is even more important.

What's next for RUNOFF

Getting more inventory for our existing products and making more products and higher-quality product photography.

Built With

Share this project:

Updates

Submission history