# Instrument.com — Technical Analysis
## JS, Effects & Interaction Patterns

---

## Stack
- **Framework:** Nuxt.js (Vue SSR)
- **CMS:** Storyblok (headless CMS — seen in `.storyblok__outline` classes)
- **Carousel:** Splide.js (`splide--loop`, `splide--draggable`, `is-active`, `is-initialized`)
- **No GSAP detected** — animations are CSS-driven + Vue transitions
- **No Lenis/Locomotive** — standard scroll behavior

## Key Finding: Simpler Than It Looks
The site feels premium but the tech is **straightforward**:
- CSS transitions (not complex JS animation libraries)
- Splide.js for the horizontal carousel (lightweight, 30kb)
- Vue/Nuxt for component rendering and state
- IntersectionObserver for scroll-triggered reveals (via Vue directives)
- No heavy animation framework

---

## Effects Breakdown

### 1. Horizontal Portfolio Carousel
**Implementation:** Splide.js
```
.splide--loop .splide--ltr .splide--draggable
```
- Loop mode (infinite scroll)
- LTR direction
- Drag-to-scroll enabled
- Slides have states: `is-active`, `is-visible`, `is-next`, `is-prev`
- Clone slides for seamless looping (`splide__slide--clone`)

**CSS:**
```css
/* Cards dim on hover — non-hovered cards fade */
.card-grid:not(.no-hover) .card-grid__cards--dim:hover .card-grid__card-container { 
  opacity: 0.5; 
}
.card-grid:not(.no-hover) .card-grid__cards--dim .card-grid__card-container:hover { 
  opacity: 1; 
}
```
**Translation for us:** We can use Splide.js directly (MIT license, 30kb) or CSS scroll-snap for a simpler version.

### 2. Scroll Reveal Animations
**Implementation:** CSS transitions triggered by class toggling (likely via IntersectionObserver in a Vue directive)
```css
/* Elements start invisible, become visible on scroll */
transition: opacity 0.6s ease, transform 0.6s ease;
/* Hidden state */
opacity: 0; transform: translateY(20px);
/* Visible state (.is-visible) */
opacity: 1; transform: translateY(0);
```
**Translation for us:** Simple IntersectionObserver + CSS classes. ~20 lines of JS.

### 3. Accordion (Capabilities Section)
**Implementation:** Vue component with height animation
```css
/* AccordionItem.css */
/* Toggle max-height with transition */
transition: max-height 0.4s ease;
```
- Click toggles `is-active` class
- Content area animates max-height from 0 to measured height
- `+` icon rotates to `×` via CSS transform

**Translation for us:** Pure CSS/JS accordion, no framework needed.

### 4. Nav Pill Buttons
```css
.button-small.button-abacus {
  /* Pill shape */
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.3);
  padding: 8px 16px;
  transition: background 0.2s ease, border-color 0.2s ease;
}
/* Active state */
.router-link-active.button-abacus {
  background: rgba(255,255,255,0.15);
}
```

### 5. Media Components (Video Cards)
```css
.media-component--in-carousel {
  /* Full bleed within carousel slide */
}
.media-component--center.media-component--full {
  /* Centered, full-width */
}
```
- Videos autoplay muted with `<video>` elements
- Pause button is a simple toggle
- `border-radius: 12-16px` on cards

### 6. Quote Section
```css
.quote--standalone.quote--center {
  /* Centered testimonial */
  text-align: center;
  max-width: 800px;
  margin: 0 auto;
  padding: 120px 0;
}
.quote__text {
  font-family: serif; /* Their serif font */
  font-size: 36px;
  line-height: 1.3;
}
.quote__author-container {
  /* Small caps attribution */
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 12px;
}
```

### 7. Card Grid (Responsive)
```css
.card-grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-cols), 1fr);
}
/* Responsive columns via CSS custom properties */
--card-grid-columns-medium  /* 40rem breakpoint */
--card-grid-columns-large   /* 64rem breakpoint */
--card-grid-columns-xlarge  /* 90rem breakpoint */
--card-grid-columns-max     /* 120rem breakpoint */
```

### 8. Transitions Found
| Element | Transition |
|---------|-----------|
| Card hover dim | `opacity 0.25s` |
| Nav buttons | `background 0.2s, border-color 0.2s` |
| Scroll reveals | `opacity 0.6s, transform 0.6s` |
| Accordion | `max-height 0.4s` |
| Links/buttons | `color 0.2s, opacity 0.2s` |

---

## What We CAN Reproduce (No Framework Needed)

| Effect | Complexity | Approach |
|--------|-----------|----------|
| Horizontal carousel | Low | Splide.js (same lib) or CSS scroll-snap |
| Scroll reveal | Low | IntersectionObserver + CSS transitions (~20 lines JS) |
| Accordion | Low | Pure JS + CSS max-height transition |
| Pill nav buttons | Trivial | CSS only |
| Card hover dim/brighten | Trivial | CSS :hover with opacity |
| Quote section | Trivial | HTML + CSS |
| Responsive grid | Low | CSS Grid with custom properties |
| Video autoplay | Low | `<video autoplay muted loop playsinline>` |
| Dark chromatic background | Trivial | CSS background-color |

## What We Should Skip

| Effect | Why |
|--------|-----|
| Nuxt/Vue SSR | Overkill — static HTML is fine for a portfolio |
| Storyblok CMS | Not needed — content is fixed |
| Complex routing | Single page, no SPA needed |

---

## Verdict: Totally Buildable

The Instrument site looks $200k but the interaction layer is **surprisingly simple**:
- 1 library: Splide.js (carousel)
- ~50 lines of custom JS (scroll reveals + accordion)
- Everything else is CSS transitions

We can build the full Instrument-level interaction quality with:
1. Static HTML
2. Splide.js CDN (or CSS scroll-snap)
3. ~50 lines of vanilla JS
4. Well-crafted CSS

**No React, no Vue, no GSAP, no animation libraries needed.**
