# Les 2 — OpenCode Pro
## Lesstof — Rules, Worktrees & Scroll Animations

**Vak:** AI-Assisted Development
**Opleiding:** NOVI Hogeschool Utrecht
**Onderwerp:** OpenCode Desktop professioneel inzetten met regels, config en parallel worktrees

---

## Inhoudsopgave

1. [OpenCode in 2026](#1-opencode-in-2026)
2. [TUI vs Desktop — welke kies je?](#2-tui-vs-desktop)
3. [Plan/Build/@explore + /init](#3-planbuildexplore--init)
4. [`AGENTS.md` — het officiële regelbestand](#4-agentsmd--het-officiele-regelbestand)
5. [`opencode.json` — config & permissies](#5-opencodejson--config--permissies)
6. [Plugins & `opencode-worktree`](#6-plugins--opencode-worktree)
7. [De scroll-animatie stack (Next.js 16)](#7-de-scroll-animatie-stack)
8. [Vercel & Preview Deployments](#8-vercel--preview-deployments)
9. [Project setup van A tot Z](#9-project-setup-van-a-tot-z)
10. [Workflow patterns](#10-workflow-patterns)
11. [Bronnen](#11-bronnen)

---

## 1. OpenCode in 2026

OpenCode is een open-source AI coding-IDE. 60.000+ GitHub stars. Gemaakt door SST. Provider-agnostisch — werkt met OpenAI, Anthropic, Google, Groq, lokale modellen via Ollama, en meer.

Vergelijkbaar concept als Cursor of Claude Code, maar:
- **Open source** — geen vendor lock-in
- **Provider-keuze** — niet vast aan één AI-bedrijf
- **Script-vriendelijk** — perfect voor automation, CI/CD, plugins
- **Twee smaken:** Desktop (UI) en TUI (terminal)

### Desktop App (vandaag onze keuze)

Native app voor macOS, Windows, Linux. Download via https://opencode.ai/download.

Layout (globaal):
- **File tree** links — bestanden + folders, right-click voor acties
- **Diff viewer** midden — visueel groen/rood met klik-accept/reject
- **Chat panel** onder — prompts naar de agent
- **Sessions sidebar** links — meerdere parallelle sessies (voor worktrees!)
- **Ingebouwde terminal** — onderaan, optioneel

### TUI (terminal)

```bash
npm i -g opencode-ai@latest
opencode
```

Zelfde engine, zelfde commando's, zelfde plugins. Goed voor SSH, scripts, CI/CD.

---

## 2. TUI vs Desktop — Welke kies je?

| Aspect | TUI | Desktop |
|--------|-----|---------|
| Leercurve | Steiler — alles via keyboard | Vlakker — visueel |
| Diff review | Plain text inline | Visuele diff-viewer |
| Files browsen | Via @-references | File tree zichtbaar |
| Sessies parallel | Tmux / aparte terminals | Sessions sidebar |
| SSH / headless servers | ✅ | ❌ (X-server nodig) |
| Worktree plugin auto-spawn | ✅ (spawnt terminal) | ❌ (handmatige tab) |
| Snel typen / muscle memory | ✅ | Ok, maar trager |
| Scripted workflows | ✅ | Beperkt |

### Wanneer wel TUI?

- **SSH-only servers** — geen X11 nodig
- **CI/CD pipelines** — scripted invocaties
- **Tmux fans** — past in je tmux setup
- **Worktree power-users** — auto-terminal-spawn van de plugin

### Onze keuze voor deze les en eindopdracht: Desktop

Sneller te leren, visueler, beter voor parallel-werken via Sessions sidebar.

---

## 3. Plan/Build/@explore + /init

### Plan vs Build mode

OpenCode heeft twee modes — Tab om te wisselen.

**Plan mode** is read-only. Tools: `read`, `grep`, `glob`, `webfetch`. Geen edits, geen shell commands. Goed voor brainstorm / verkenning.

**Build mode** is default. Alle tools aan. Schrijft code, voert commands uit.

Best practice: begin **altijd** in plan-mode. Laat het uitleggen wat het van plan is. Geef feedback. Pas dan Tab → build.

### Sub-agents

Drie ingebouwde sub-agents:

| Naam | Wat | Wanneer |
|------|-----|---------|
| `@explore` | Read-only verkenning | "Waar staat X?" "Wat is dit?" |
| `@general` | Brede taak-agent | Default voor de meeste taken |
| `@scout` | Gerichte zoekopdracht | "Vind alle plaatsen waar..." |

Manuele aanroep: `@explore vind alle authenticatie code`. Primaire agent kan ze ook autonoom inschakelen.

### `/init` commando

In de chat: `/init`. OpenCode scant je repo, stelt vragen, en genereert/update je `AGENTS.md`.

Doe dit **als eerste actie** in elk nieuw project. Daarna kun je het bestand uitbreiden met jouw specifieke regels.

### Belangrijke keybinds (Desktop én TUI)

| Shortcut | Actie |
|----------|-------|
| `Tab` | Wissel plan ↔ build |
| `Enter` | Submit |
| `Esc` | Cancel |
| `Ctrl+X h` | Help (alle bindings) |
| `Ctrl+D` | Exit (TUI) |

Leader-key voor commando-specifieke bindings: `Ctrl+X`. Customizen via `~/.config/opencode/tui.json` of in Desktop settings.

---

## 4. `AGENTS.md` — Het officiële regelbestand

`AGENTS.md` is markdown in je project-root die OpenCode automatisch in elke context laadt. Officieel format. Expliciet vergeleken in de docs met Cursor's `.cursorrules`.

### Twee locaties

| Pad | Wanneer |
|-----|---------|
| `./AGENTS.md` | Per project (in repo, geversioneerd) |
| `~/.config/opencode/AGENTS.md` | Globaal voor alle projecten |

### Externe regels referencen

```markdown
# Stack rules
@rules/styling.md
@rules/security.md
```

OpenCode laadt deze lazy via z'n Read-tool — pas wanneer relevant.

### Voorbeeld voor scroll-animatie project

```markdown
# Project Rules

## Why this stack
High-end scroll storytelling site (Awwwards/FWA niveau).
GSAP + Lenis = pro standaard — Apple, Stripe, OpenAI, Active Theory,
Locomotive, Darkroom Engineering. Framer Motion is voor app UI, niet voor
scroll storytelling. Kies GSAP voor timing-precisie + GPU-perf.

## Stack
- Next.js 16 (App Router, TypeScript, Turbopack)
- TailwindCSS voor styling
- GSAP 3.15+ (incl. ScrollTrigger, SplitText) met `@gsap/react`
- Lenis 1.3+ (`lenis/react`) voor smooth scroll

## Hard rules
- Geen Framer Motion, react-spring, AOS
- Animaties altijd in Client Components (`"use client"`)
- ScrollTrigger registratie 1x per file
- Animatie-code altijd binnen `useGSAP(() => {}, { scope: ref })`
- Nooit `useEffect` voor GSAP code
- Lenis sync: `gsap.ticker.add` met `autoRaf: false`
- **Async params (Next 16):** altijd `await params` en `await searchParams`

## Patterns
- Eén `<SmoothScroll>` wrapper in `app/layout.tsx`
- Refs i.p.v. globale selectors; scope animaties
- Tailwind voor layout/typografie; GSAP voor transform/opacity
- Geen `transition-*` Tailwind classes op geanimeerde elementen

## Done = 
- Geen hydration warnings
- Werkt in React Strict Mode
- `ScrollTrigger.refresh()` na dynamische content
```

**De `## Why this stack` sectie is cruciaal.** Hiermee snapt de agent *waarom*
we deze keuzes maken — niet alleen *wat*. Resultaat: hij stelt op eigen
initiatief geen Framer Motion meer voor, want hij begrijpt dat we voor scroll
storytelling werken.

### Tips voor goede AGENTS.md

- **Concreet, niet vaag.** "Gebruik clean code" werkt niet. "useGSAP alleen, geen useEffect" wel.
- **Versie-pinning** voor libraries die snel veranderen.
- **Definitie van klaar** — checkpoints die de agent zelf kan toetsen.
- **Anti-patterns expliciet noemen** — "Geen Framer Motion" voorkomt veel discussie.

---

## 5. `opencode.json` — Config & Permissies

### Locaties

| Pad | Scope |
|-----|-------|
| `./opencode.json` | Per project |
| `~/.config/opencode/opencode.json` | Globaal |

### Basis voorbeeld

```json
{
  "$schema": "https://opencode.ai/config.json",
  "model": "openai/gpt-4o-mini"
}
```

Model formaat: `provider/model-id`. Voorbeelden:
- `openai/gpt-4o-mini`
- `openai/gpt-4o`
- `anthropic/claude-sonnet-4`
- `groq/llama-3.3-70b-versatile`

### Permissies

```json
{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "bash": {
      "*": "ask",
      "git *": "allow",
      "rm *": "deny"
    },
    "edit": {
      "*": "deny",
      "app/**/*.tsx": "allow",
      "components/**": "allow"
    }
  }
}
```

Drie levels: `allow`, `ask`, `deny`. Glob patterns voor bash commands en file paths.

### Plugin syntax (npm)

```json
{
  "plugin": [
    "@anthropic/some-plugin@1.0.0"
  ]
}
```

OpenCode installeert plugins automatisch via Bun in `~/.cache/opencode/node_modules/` bij het opstarten.

### MCP servers (optioneel)

```json
{
  "mcp": {
    "context7": {
      "type": "local",
      "command": "npx",
      "args": ["-y", "@upstash/context7-mcp"]
    }
  }
}
```

Voor up-to-date library docs binnen je AI-context. Niet vereist voor deze les.

---

## 6. Plugins & `opencode-worktree`

### Wat is `opencode-worktree`?

Plugin van **kdcokenny** (community maker, ook achter `ocx` en `opencode-workspace`).

**Wat doet het?**
Geeft de agent twee nieuwe tools:
- `worktree_create` — maakt nieuwe branch + worktree-folder
- `worktree_delete` — commit changes + cleanup

**Worktree-locatie:**
`~/.local/share/opencode/worktree/<project-id>/<branch>/`

### Installatie via `ocx`

```bash
# Eenmalig: ocx installeren
curl -fsSL https://kdco.dev/ocx/install.sh | sh

# Plugin toevoegen
ocx add kdco/worktree --from https://registry.kdco.dev
```

Restart OpenCode na install.

### Verschil Desktop vs TUI

| Actie | TUI | Desktop |
|-------|-----|---------|
| `worktree_create` aanroepen | ✅ | ✅ |
| `worktree_delete` aanroepen | ✅ | ✅ |
| **Auto nieuw terminal venster** | ✅ | ❌ |
| Nieuwe context openen | Auto | Handmatig (Sessions sidebar) |

In Desktop maakt de plugin de worktree, daarna open je hem zelf in een nieuwe Sessions tab.

### Workflow in Desktop

1. In je hoofd-Session: `Maak een worktree voor feature-hero.`
2. Plugin maakt worktree-folder
3. Klik **+ New Session** in sidebar
4. **Open Folder** → navigate naar de worktree-folder
5. Nu heb je 2 sessies parallel in sidebar — main + feature-hero
6. Klik tussen sessies om te wisselen

### Handmatig alternatief (zonder plugin)

```bash
git worktree add ../mijn-repo-hero -b feature-hero
```

Dan handmatig nieuwe Session openen op die folder.

### Best practices

- Eén opencode-instance per worktree-directory (gouden regel)
- Niet wisselen tussen sessies van verschillende worktrees binnen één session-context (cwd-bug)
- Branch name = folder name (makkelijker zoeken in `git worktree list`)
- Cleanup na merge — niet stapelen

---

## 7. De scroll-animatie stack

### Next.js 16 (mei 2026)

Uitgekomen oktober 2025. **Breaking changes ten opzichte van 15:**

- **Async API's verplicht:** `cookies()`, `headers()`, `params`, `searchParams` zijn nu allemaal async. Altijd `await`:
  ```tsx
  // app/products/[id]/page.tsx
  export default async function Page({ params }: { params: Promise<{ id: string }> }) {
    const { id } = await params;  // VERPLICHT in 16
    return <div>{id}</div>;
  }
  ```
- **Turbopack is default** voor `dev` en `build`. Webpack alleen via opt-in.
- **`middleware.ts` → `proxy.ts`** met nieuwe Node.js runtime.
- **`revalidateTag` vereist 2e argument** (cacheLife profile).
- **Node.js 20.9+** vereist (18 is dropped).

### Waarom GSAP + Lenis?

Dit is **dé** stack voor scroll storytelling op pro-niveau. Niet "een" optie — de standaard.

**Wie gebruikt dit?**
- **Apple** — product pages met scroll-revealed content
- **Stripe** — homepage en product pages
- **OpenAI** marketing pages
- **Awwwards / FWA winnaars** — vrijwel altijd GSAP
- Pro studios: **Active Theory**, **Locomotive**, **Resn**, **Darkroom Engineering** (makers van Lenis)

**Waarom niet Framer Motion?**
- Framer Motion is uitstekend voor **app UI** — modals, page transitions, micro-interacties
- Maar voor **scroll storytelling** (jouw eindopdracht): GSAP heeft betere timing-precisie en GPU-optimalisaties
- Daarom: Framer Motion voor app-werk, GSAP voor scroll-werk

**Andere voordelen:**
- **GSAP sinds januari 2025: 100% gratis** onder de "no charge" license — incl. ScrollTrigger, SplitText, MorphSVG (vroeger premium)
- **Lenis** integreert naadloos met ScrollTrigger via één RAF sync
- Beide zijn **populair op v0 en Cursor** — AI's kennen de patterns goed

Schrijf dit op in je `AGENTS.md` (sectie `## Why this stack`). Dan kiest je AI agent dezelfde keuzes om dezelfde redenen.

### Packages

```bash
npm install gsap @gsap/react lenis
```

**Belangrijk:**
- Pakket heet **`lenis`** (niet meer `@studio-freight/lenis`)
- `@gsap/react` geeft je de officiele `useGSAP` hook

### De `useGSAP` hook

Drop-in vervanger voor `useEffect`/`useLayoutEffect` voor GSAP code. Doet automatisch cleanup via `gsap.context()`. Werkt veilig met React Strict Mode en SSR.

```tsx
"use client";
import { useRef } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";

gsap.registerPlugin(useGSAP, ScrollTrigger);

export default function FadeIn() {
  const ref = useRef<HTMLDivElement>(null);

  useGSAP(() => {
    gsap.from(".fade-item", {
      opacity: 0,
      y: 60,
      duration: 1,
      stagger: 0.15,
      scrollTrigger: {
        trigger: ref.current,
        start: "top 80%",
      },
    });
  }, { scope: ref });

  return (
    <section ref={ref}>
      <h2 className="fade-item text-5xl font-bold">Hello scroll</h2>
      <p className="fade-item">Ik fade in.</p>
    </section>
  );
}
```

### Lenis sync met ScrollTrigger

Zonder sync lopen GSAP en Lenis hun eigen requestAnimationFrame — animaties haperen. Officieel patroon: `autoRaf: false` op Lenis, GSAP's ticker drijft Lenis aan.

```tsx
// components/SmoothScroll.tsx
"use client";
import { ReactLenis, type LenisRef } from "lenis/react";
import { useEffect, useRef } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

export default function SmoothScroll({ children }: { children: React.ReactNode }) {
  const lenisRef = useRef<LenisRef>(null);

  useEffect(() => {
    function update(time: number) {
      lenisRef.current?.lenis?.raf(time * 1000);
    }
    gsap.ticker.add(update);
    gsap.ticker.lagSmoothing(0);
    return () => gsap.ticker.remove(update);
  }, []);

  return (
    <ReactLenis root ref={lenisRef} options={{ autoRaf: false, lerp: 0.1 }}>
      {children}
    </ReactLenis>
  );
}
```

In `app/layout.tsx`:

```tsx
import SmoothScroll from "@/components/SmoothScroll";
import "./globals.css";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="nl">
      <body>
        <SmoothScroll>{children}</SmoothScroll>
      </body>
    </html>
  );
}
```

---

## 8. Vercel & Preview Deployments

Vercel maakt **automatisch een unieke URL** voor elke branch die je naar GitHub pusht. Voor scroll-storytelling is dit goud — animaties moet je *zien* om over te oordelen.

### Hoe het werkt

| Branch | Type deploy | URL pattern |
|--------|-------------|-------------|
| `main` | Production | `jouw-app.vercel.app` |
| `feature-hero` | Preview | `jouw-app-git-feature-hero-jij.vercel.app` |
| `feature-gallery` | Preview | `jouw-app-git-feature-gallery-jij.vercel.app` |
| Pull request | Preview met PR-comment | Unieke URL per PR |

Iedere nieuwe push naar dezelfde branch overschrijft de bestaande preview deploy.

### Setup (eenmalig)

```bash
# 1. Vercel CLI installeren
npm i -g vercel

# 2. Inloggen
vercel login

# 3. Koppel project (in repo root)
vercel link

# 4. Eerste productie deploy
vercel --prod
```

Of via dashboard: vercel.com → New Project → Import van GitHub.

Vercel installeert een eigen GitHub App. Vanaf nu detecteert het automatisch elke push.

### Combinatie met worktrees

Je worktree-workflow + Vercel preview deployments past perfect samen:

```
1 worktree   =   1 branch   =   1 preview URL
```

Drie features parallel ontwikkelen?
- `feature-hero` worktree → eigen preview URL
- `feature-gallery` worktree → eigen preview URL
- `feature-footer` worktree → eigen preview URL

Drie verschillende stakeholders kunnen tegelijk reviewen.

### Pull request flow

```
1. Push feature-branch
2. Vercel deploy (preview URL)
3. Open PR op GitHub
4. Vercel bot plakt preview URL in PR comment
5. Reviewer klikt URL, ziet live versie, geeft feedback
6. Merge naar main → automatische productie deploy
```

Voor je eindopdracht: gebruik deze flow. Het scheelt enorm in feedback-rondes.

### Environment variables

Heeft je app secrets nodig (API keys etc.)?
- Vercel dashboard → Project → Settings → Environment Variables
- Voor scroll-animatie sites meestal niet nodig
- Maar handig om te weten voor latere lessen

### Wat NIET commiten

```gitignore
.env*.local
.vercel
```

`.vercel` folder bevat link-info — staat al standaard in `.gitignore` van Next.js starter.

---

## 9. Project setup van A tot Z

### Stap 1 — Next.js 16 project aanmaken

```bash
npx create-next-app@latest scroll-site \
  --typescript --tailwind --app --eslint --no-src-dir --turbopack
cd scroll-site
```

### Stap 2 — Animation dependencies

```bash
npm install gsap @gsap/react lenis
```

### Stap 3 — Git init + first commit

```bash
git init
git add .
git commit -m "init: next 16 + gsap + lenis"
```

### Stap 4 — `AGENTS.md` toevoegen

Plak het voorbeeld uit sectie 4 in `AGENTS.md` in root. Pas aan op jouw project.

### Stap 5 — `opencode.json` toevoegen

```json
{
  "$schema": "https://opencode.ai/config.json",
  "model": "openai/gpt-4o-mini",
  "permission": {
    "bash": {
      "*": "ask",
      "git *": "allow",
      "npm *": "allow",
      "rm *": "deny"
    }
  }
}
```

### Stap 6 — OpenCode Desktop starten

Open OpenCode Desktop → File → Open Folder → `scroll-site`.

In chat: `/init` om je AGENTS.md te valideren.

### Stap 7 — SmoothScroll wrapper bouwen

Vraag in chat:
> Bouw een SmoothScroll wrapper component volgens onze AGENTS.md. Plaats hem in `components/SmoothScroll.tsx` en wrap children in `app/layout.tsx`.

Plan-mode → review → Tab → Build-mode.

### Stap 8 — Eerste worktree

> Maak een worktree voor feature-hero en bouw daar een hero-sectie met een SplitText-reveal op scroll.

Plugin maakt worktree → open nieuwe Sessions tab op die folder → agent bouwt.

---

## 10. Workflow patterns

### Pattern 1 — Plan eerst, dan Build

Begin altijd in **plan-mode**. Laat de agent uitleggen wat het van plan is. Geef feedback. Pas dan Tab → build.

### Pattern 2 — Eén worktree per feature

Werk niet alles in main. Een feature = een worktree = een branch. Makkelijk parallel + makkelijk reviewen via PR.

### Pattern 3 — `AGENTS.md` evolueert

Loop je tegen iets aan dat steeds verkeerd gaat? Voeg toe aan AGENTS.md. Het is een levend document.

### Pattern 4 — `@explore` voor verkenning

Nieuwe codebase of vergeten waar iets staat? `@explore` eerst, dan pas hoofd-agent inzetten. Spaart tokens en geeft jou betere context.

### Pattern 5 — Permissions matchen je risico

Beginnersproject: `bash.*` op `ask`. Productie-werk: alleen specifieke folders editable. Schrijf permissions naar het werk dat je doet.

### Pattern 6 — Sessions sidebar = jouw parallel werk

Eén Session = orchestrator (in main). Worktrees met aparte Sessions = workers. Orchestrator stuurt, workers bouwen. Klik tussen tabs.

---

## 11. Bronnen

### OpenCode officieel
- Hoofdsite: https://opencode.ai
- Download (Desktop): https://opencode.ai/download
- Docs: https://opencode.ai/docs/
- Rules (`AGENTS.md`): https://opencode.ai/docs/rules/
- Config: https://opencode.ai/docs/config/
- Plugins: https://opencode.ai/docs/plugins/
- Agents (sub-agents): https://opencode.ai/docs/agents/
- Modes: https://opencode.ai/docs/modes/
- Commands: https://opencode.ai/docs/commands/
- Permissions: https://opencode.ai/docs/permissions/
- GitHub: https://github.com/sst/opencode
- DeepWiki Desktop apps: https://deepwiki.com/sst/opencode/6.7-desktop-applications

### Plugin ecosystem
- `opencode-worktree`: https://github.com/kdcokenny/opencode-worktree
- `ocx` extension manager: https://github.com/kdcokenny/ocx
- `opencode-workspace` (uitgebreidere variant): https://github.com/kdcokenny/opencode-workspace

### Next.js 16
- Blog post: https://nextjs.org/blog/next-16
- Upgrade guide: https://nextjs.org/docs/app/guides/upgrading/version-16
- create-next-app CLI: https://nextjs.org/docs/app/api-reference/cli/create-next-app

### GSAP
- Docs v3: https://gsap.com/docs/v3/
- React guide (`useGSAP`): https://gsap.com/resources/React/
- License (sinds 2025 gratis): https://gsap.com/standard-license
- ScrollTrigger: https://gsap.com/docs/v3/Plugins/ScrollTrigger/
- SplitText: https://gsap.com/docs/v3/Plugins/SplitText/

### Lenis
- GitHub: https://github.com/darkroomengineering/lenis
- React README: https://github.com/darkroomengineering/lenis/blob/main/packages/react/README.md
- Homepage: https://lenis.darkroom.engineering/

### Vercel
- Preview Deployments: https://vercel.com/docs/deployments/preview-deployments
- Git Integration: https://vercel.com/docs/git
- Vercel CLI docs: https://vercel.com/docs/cli

### Combinaties / patterns
- GSAP forum: Next 15/16 best practices: https://gsap.com/community/forums/topic/43831-what-are-the-best-practices-for-using-gsap-with-next-15-clientserver-components/
- Tutorial: Next.js + Lenis + GSAP: https://devdreaming.com/blogs/nextjs-smooth-scrolling-with-lenis-gsap

### Volgende les preview
Les 3: **Introductie Cursor**. De commerciele tegenhanger van OpenCode. Cursor rules vs AGENTS.md, Composer mode, Tab-completion, @-references. Wanneer kies je welke tool?
