Les 2 Klas B — OpenCode Pro met AGENTS.md, worktrees & GSAP/Lenis
This commit is contained in:
536
v2-klasB/Les02-OpenCode/Les02-Docenttekst.md
Normal file
536
v2-klasB/Les02-OpenCode/Les02-Docenttekst.md
Normal file
@@ -0,0 +1,536 @@
|
|||||||
|
# Les 2 — OpenCode Pro: Rules, Worktrees & Scroll Animations
|
||||||
|
## Docenttekst + Docenthandleiding (Klas B — 2 uur, online)
|
||||||
|
|
||||||
|
**Les:** 2 van 18
|
||||||
|
**Duur:** 120 minuten online
|
||||||
|
**Vorige les:** Les 1 — Introductie AI Developer leerlijn
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Leerdoelen
|
||||||
|
- Begrijpen waarom we OpenCode kiezen i.p.v. Cursor (multi-provider, open source, alternatieven)
|
||||||
|
- OpenCode Desktop kunnen draaien met Plan/Build/@explore/init
|
||||||
|
- `AGENTS.md` regelbestand schrijven (officieel format)
|
||||||
|
- `opencode.json` config met permissions
|
||||||
|
- `opencode-worktree` plugin via `ocx` installeren
|
||||||
|
- Parallel agents via Sessions sidebar
|
||||||
|
- Live: Next.js 16 + GSAP + Lenis scroll-site opzetten
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lesflow
|
||||||
|
|
||||||
|
**Geen heen-en-weer switchen.** De les is opgedeeld in:
|
||||||
|
- **Theorie 1** — uninterrupted uitleg (slides 4-6)
|
||||||
|
- **Live Demo 1** — alle features tonen achter elkaar (slide 7)
|
||||||
|
- **Theorie 2** — uninterrupted uitleg (slides 8-12)
|
||||||
|
- **Live Demo 2** — setup + bouw SmoothScroll (slide 13)
|
||||||
|
- Pauze
|
||||||
|
- Lesopdracht
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# DEEL 1 — Docenthandleiding (volg dit live tijdens de les)
|
||||||
|
|
||||||
|
## VÓÓR DE LES — Setup (30 min)
|
||||||
|
|
||||||
|
### 1. OpenCode Desktop
|
||||||
|
|
||||||
|
- Download van https://opencode.ai/download
|
||||||
|
- Installeer
|
||||||
|
- Log in met OpenAI key (uit Brightspace)
|
||||||
|
|
||||||
|
### 2. `ocx` + worktree plugin
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://kdco.dev/ocx/install.sh | sh
|
||||||
|
ocx add kdco/worktree --from https://registry.kdco.dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Sluit en open OpenCode opnieuw zodat plugin geladen wordt.
|
||||||
|
|
||||||
|
### 3. Demo-repo aanmaken
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~
|
||||||
|
npx create-next-app@latest scroll-demo \
|
||||||
|
--typescript --tailwind --app --eslint --no-src-dir --turbopack
|
||||||
|
cd scroll-demo
|
||||||
|
npm install gsap @gsap/react lenis
|
||||||
|
git init
|
||||||
|
git add .
|
||||||
|
git commit -m "init: next 16 + gsap + lenis"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Test je setup
|
||||||
|
|
||||||
|
- Open OpenCode Desktop → File → Open Folder → `~/scroll-demo`
|
||||||
|
- Type in chat: `Wat is de stack?` → moet Next.js 16 + Tailwind herkennen
|
||||||
|
- Type `/init` en abort (Esc) — alleen testen dat 't werkt
|
||||||
|
- Maak test-worktree om plugin te valideren:
|
||||||
|
```
|
||||||
|
Maak een testworktree feature-test
|
||||||
|
```
|
||||||
|
- Klik **+ New Session** linksboven, open folder van die worktree
|
||||||
|
- Sluit Session, verwijder worktree:
|
||||||
|
```bash
|
||||||
|
git worktree remove ~/.local/share/opencode/worktree/scroll-demo/feature-test
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Browser tabs open
|
||||||
|
|
||||||
|
- https://opencode.ai/download
|
||||||
|
- https://opencode.ai/docs/rules/
|
||||||
|
- https://gsap.com/resources/React/
|
||||||
|
- https://github.com/kdcokenny/opencode-worktree
|
||||||
|
|
||||||
|
### 6. Backup plan
|
||||||
|
|
||||||
|
Als plugin live faalt:
|
||||||
|
```bash
|
||||||
|
git worktree add ../scroll-demo-hero -b feature-hero
|
||||||
|
```
|
||||||
|
Dan handmatig nieuwe Session → Open Folder.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TIJDENS DE LES
|
||||||
|
|
||||||
|
### Blok 1 — Welkom + Terugblik (10 min)
|
||||||
|
|
||||||
|
**Slides 1, 2, 3.**
|
||||||
|
|
||||||
|
- Start meeting
|
||||||
|
- Slide 2: vraag in chat: "Wie heeft tot nu toe alleen met chat (ChatGPT/Claude) gewerkt?"
|
||||||
|
- Slide 3: planning langslopen. **Benadruk** dat we eerst theorie geven, dan demo, dan weer theorie, dan demo. Geen heen-en-weer.
|
||||||
|
|
||||||
|
**Geen demo nodig in dit blok.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Blok 2 — THEORIE 1: Waarom OpenCode + Kern features (20 min)
|
||||||
|
|
||||||
|
**Slides 4, 5, 6. Achter elkaar, zonder switchen.**
|
||||||
|
|
||||||
|
#### Slide 4 — Waarom OpenCode (en niet Cursor) — 6 min
|
||||||
|
|
||||||
|
**Vertel:**
|
||||||
|
"Iedereen kent Cursor. Sommigen gebruiken het al. Goede tool. Waarom beginnen we dan met OpenCode?
|
||||||
|
|
||||||
|
Drie redenen.
|
||||||
|
|
||||||
|
**Eén — alternatieven kennen is professioneel.** Wie alleen Cursor kent, zit vast aan één tool. Een goede dev kent meerdere coding-assistenten en kiest per project.
|
||||||
|
|
||||||
|
**Twee — provider-keuze.** Cursor heeft eigen routing — jij hebt niet vol overzicht welk model wanneer wordt gebruikt. OpenCode is provider-agnostisch: OpenAI vandaag, Anthropic morgen, lokaal met Ollama als je dat wilt. Jij beslist.
|
||||||
|
|
||||||
|
**Drie — open source = geen lock-in.** Voor je eindopdracht en je carrière is dit relevant. Tools veranderen, abonnementen veranderen. Open source blijft beschikbaar.
|
||||||
|
|
||||||
|
Belangrijk: dit is **geen Cursor-bashing**. Cursor is uitstekend. We komen er later in de leerlijn op terug. Vandaag de open variant — dan kun je daarna zelf kiezen."
|
||||||
|
|
||||||
|
Loop tabel langs.
|
||||||
|
|
||||||
|
#### Slide 5 — Wat is OpenCode — 7 min
|
||||||
|
|
||||||
|
**Vertel:**
|
||||||
|
"OpenCode is een AI coding-IDE. 60.000+ GitHub stars. Gemaakt door SST. Werkt met elke provider — OpenAI, Anthropic, Google, Groq, of lokaal met Ollama.
|
||||||
|
|
||||||
|
Twee smaken: Desktop en TUI. Wij gebruiken Desktop. Waarom?
|
||||||
|
- Visuele diff-viewer (klik accept/reject)
|
||||||
|
- File tree links, Sessions sidebar
|
||||||
|
- Multiple sessies naast elkaar
|
||||||
|
- Sneller leren als je begint
|
||||||
|
|
||||||
|
De TUI bestaat ook. Goed voor SSH-servers, scripts, CI/CD. Ik laat 'm 1 minuut zien in de demo — daarna 100% Desktop."
|
||||||
|
|
||||||
|
Loop tabel langs.
|
||||||
|
|
||||||
|
#### Slide 6 — Plan/Build/@explore + /init — 7 min
|
||||||
|
|
||||||
|
**Vertel:**
|
||||||
|
"Vier dingen die je echt moet kennen.
|
||||||
|
|
||||||
|
**Modes** — twee modes, Tab om te wisselen:
|
||||||
|
- **plan** is read-only. Denkt mee, leest files, wijzigt niks. Goed voor verkenning en brainstorm.
|
||||||
|
- **build** is default. Schrijft code, voert commands uit.
|
||||||
|
|
||||||
|
**Sub-agents** — drie ingebouwde:
|
||||||
|
- `@explore` is read-only verkenning. Eigen context, spaart tokens.
|
||||||
|
- `@general` is brede taak.
|
||||||
|
- `@scout` is gerichte zoek.
|
||||||
|
|
||||||
|
**`/init` commando** — eerste actie in elk nieuw project. Scant je repo, stelt vragen, schrijft je `AGENTS.md`.
|
||||||
|
|
||||||
|
**Best practice:** plan eerst, lees mee, geef feedback, dan Tab → build. Dit voorkomt rommel.
|
||||||
|
|
||||||
|
Dat was de theorie. Nu zien jullie het live."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Blok 3 — LIVE DEMO 1: Desktop Tour (10 min)
|
||||||
|
|
||||||
|
**Slide 7.**
|
||||||
|
|
||||||
|
**Setup vooraf:** OpenCode Desktop open op `~/scroll-demo`. Systeem-terminal open naast OpenCode voor de TUI-demo.
|
||||||
|
|
||||||
|
#### Stap 1 — TUI in 1 minuut (1 min)
|
||||||
|
|
||||||
|
- Switch naar systeem-terminal
|
||||||
|
- Type: `opencode`
|
||||||
|
- Toon kort de TUI met chat onderaan
|
||||||
|
- Type: `wat is de stack van dit project?` → krijg antwoord
|
||||||
|
- Druk **Tab** → switch naar plan mode → tab terug
|
||||||
|
- **Ctrl+D** om te sluiten
|
||||||
|
|
||||||
|
**Zeg:** "Dat was de TUI. Werkt prima. Vandaag verder met Desktop."
|
||||||
|
|
||||||
|
#### Stap 2 — Desktop UI tour (2 min)
|
||||||
|
|
||||||
|
- Switch naar Desktop
|
||||||
|
- Wijs aan:
|
||||||
|
- **File tree** links (klik op `app/page.tsx` om te tonen)
|
||||||
|
- **Chat panel** onderaan
|
||||||
|
- **Diff viewer** in midden
|
||||||
|
- **Sessions sidebar** (toon dat 't er is, leeg op één session na)
|
||||||
|
- **Model selector** + **mode indicator** bovenin
|
||||||
|
|
||||||
|
**Zeg:** "Alles op één scherm. File tree, chat, diff. Veel makkelijker dan switchen tussen terminals."
|
||||||
|
|
||||||
|
#### Stap 3 — Plan mode demo (2 min)
|
||||||
|
|
||||||
|
- Onder in chat, check dat mode-badge op `build` staat
|
||||||
|
- Druk **Tab** → wisselt naar `plan`
|
||||||
|
- Type in chat: `analyseer dit project en stel verbeteringen voor`
|
||||||
|
- Wacht op antwoord
|
||||||
|
- **Zeg:** "Zie? Concrete voorstellen. Geen file wijzigingen. Veilig om los te laten."
|
||||||
|
|
||||||
|
#### Stap 4 — Build mode demo (2 min)
|
||||||
|
|
||||||
|
- Druk **Tab** → terug naar `build`
|
||||||
|
- Type: `voeg een comment bovenaan app/page.tsx toe met de tekst "scroll demo"`
|
||||||
|
- Toon diff in viewer — klik **Accept**
|
||||||
|
- Open `app/page.tsx` in file tree — comment staat er
|
||||||
|
|
||||||
|
**Zeg:** "Plan is denken, build is doen."
|
||||||
|
|
||||||
|
#### Stap 5 — @explore demo (1.5 min)
|
||||||
|
|
||||||
|
- Type in chat: `@explore wat is de folder structuur van dit project?`
|
||||||
|
- Toon dat het in eigen context werkt
|
||||||
|
- **Zeg:** "Read-only sub-agent. Spaart tokens, kan niks kapot maken."
|
||||||
|
|
||||||
|
#### Stap 6 — /init demo (1.5 min)
|
||||||
|
|
||||||
|
- Type: `/init`
|
||||||
|
- Beantwoord de vragen die OpenCode stelt (Next.js 16, GSAP, scroll-animaties)
|
||||||
|
- Wacht tot AGENTS.md gegenereerd is
|
||||||
|
- Open `AGENTS.md` in file tree — toon wat 't gegenereerd heeft
|
||||||
|
- **Zeg:** "Dit is een goede basis. Volgende blok: hoe we 'm aanvullen met onze regels."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Blok 4 — THEORIE 2: AGENTS.md + opencode.json + plugin + stack (15 min)
|
||||||
|
|
||||||
|
**Slides 8, 9, 10, 11, 12. Achter elkaar, zonder switchen.**
|
||||||
|
|
||||||
|
#### Slide 8 — AGENTS.md — 3 min
|
||||||
|
|
||||||
|
**Vertel:**
|
||||||
|
"Belangrijkste concept van vandaag. `AGENTS.md` is **dé** manier om OpenCode jouw regels te geven. Officieel format, automatisch in elke context.
|
||||||
|
|
||||||
|
Twee locaties:
|
||||||
|
- `./AGENTS.md` in je repo — versioned, deelt met team
|
||||||
|
- `~/.config/opencode/AGENTS.md` — globaal, jouw persoonlijke voorkeuren
|
||||||
|
|
||||||
|
Externe regels mag je referencen met `@rules/styling.md` — agent laadt 'm lazy.
|
||||||
|
|
||||||
|
Tip: schrijf je AGENTS.md zoals je 'm aan een junior dev zou geven. Concreet, controleerbaar."
|
||||||
|
|
||||||
|
#### Slide 9 — opencode.json — 3 min
|
||||||
|
|
||||||
|
**Vertel:**
|
||||||
|
"Naast regels heb je config. Welk model, welke permissies, welke plugins.
|
||||||
|
|
||||||
|
`$schema` geeft autocomplete in je editor.
|
||||||
|
`model` is `provider/model-id`.
|
||||||
|
|
||||||
|
Belangrijkste is **permissions**. Drie levels: `allow`, `ask`, `deny`. Glob patterns voor bash én files.
|
||||||
|
|
||||||
|
Voor student-project: `bash.*` op `ask` is veilig — je reviewed elke shell command. Productie: alleen specifieke folders editable."
|
||||||
|
|
||||||
|
#### Slide 10 — Worktree plugin — 3 min
|
||||||
|
|
||||||
|
**Vertel:**
|
||||||
|
"Plugin van **kdcokenny** — community lid, ook achter `ocx` extension manager. Twee tools voor de agent:
|
||||||
|
- `worktree_create` — branch + worktree
|
||||||
|
- `worktree_delete` — commit + cleanup
|
||||||
|
|
||||||
|
Installatie via `ocx`. Restart na install.
|
||||||
|
|
||||||
|
Verschil TUI vs Desktop:
|
||||||
|
- TUI: plugin spawnt automatisch nieuw terminal venster
|
||||||
|
- Desktop: plugin maakt de worktree, jij opent 'm in nieuwe Sessions tab
|
||||||
|
|
||||||
|
Klein verschil, zelfde resultaat: parallel agents."
|
||||||
|
|
||||||
|
#### Slide 11 — Demo stack — 3 min
|
||||||
|
|
||||||
|
**Vertel:**
|
||||||
|
"De stack waarmee we vandaag bouwen — en waarom dit dé combinatie is voor scroll storytelling.
|
||||||
|
|
||||||
|
**Next.js 16** — uit oktober 2025. Belangrijkste verandering t.o.v. 15: `cookies()`, `headers()`, `params`, `searchParams` zijn allemaal async. Altijd `await`. Turbopack is default — snellere builds.
|
||||||
|
|
||||||
|
**GSAP 3.15** — sinds januari 2025 100% gratis, incl. ScrollTrigger en SplitText. Hét animatie-pakket op pro-niveau. Apple product pages, Stripe homepage, OpenAI marketing — allemaal GSAP. Award-winning sites op Awwwards en FWA: vrijwel altijd GSAP.
|
||||||
|
|
||||||
|
**Lenis 1.3** — door **Darkroom Engineering** (voorheen Studio Freight, een award-winning studio uit Brooklyn die zelf onder andere voor Studio Freight, Activision en Riot werkt). Beste smooth scroll lib. Integreert naadloos met GSAP ScrollTrigger.
|
||||||
|
|
||||||
|
**`@gsap/react`** — geeft je de officiele `useGSAP` hook. Drop-in voor useEffect met auto cleanup.
|
||||||
|
|
||||||
|
**Waarom niet Framer Motion?**
|
||||||
|
Framer Motion is uitstekend — voor app UI. Modals, page transitions, micro-interacties. Maar voor scroll storytelling (zoals jij gaat bouwen) wil je timing-precisie en GPU-optimalisaties die GSAP biedt en Framer Motion niet matcht. Pro-studios zoals **Active Theory**, **Locomotive**, **Resn**, **Darkroom Engineering** — allemaal GSAP-based.
|
||||||
|
|
||||||
|
Daarom staat in onze AGENTS.md: 'Geen Framer Motion'. Het is geen anti-Framer, het is pro-GSAP voor dit type werk."
|
||||||
|
|
||||||
|
#### Slide 12 — Onze AGENTS.md — 3 min
|
||||||
|
|
||||||
|
**Vertel:**
|
||||||
|
"Hier zie je onze concrete regels voor dit project. Let op de structuur:
|
||||||
|
- Stack — versies expliciet
|
||||||
|
- Hard rules — niet onderhandelbaar
|
||||||
|
- Patterns — hoe we organiseren
|
||||||
|
- Done — wat klaar betekent
|
||||||
|
|
||||||
|
Regels die opvallen:
|
||||||
|
- 'Geen Framer Motion' — voorkomt dat AI default naar 't bekendere
|
||||||
|
- 'useGSAP, nooit useEffect' — werkt met Strict Mode
|
||||||
|
- 'Lenis sync via gsap.ticker.add' — voorkomt jank
|
||||||
|
- 'await params in Next 16' — anders runtime error
|
||||||
|
|
||||||
|
Deze regels heb ik uit ervaring. In de volgende demo zet ik dit in, en zie je dat de AI ze volgt."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Blok 5 — LIVE DEMO 2: Setup + Worktree + SmoothScroll (15 min)
|
||||||
|
|
||||||
|
**Slide 13.**
|
||||||
|
|
||||||
|
**Setup vooraf:** OpenCode Desktop nog open op `~/scroll-demo`. Plugin al geïnstalleerd.
|
||||||
|
|
||||||
|
#### Stap 1 — AGENTS.md vervangen (3 min)
|
||||||
|
|
||||||
|
- Open `AGENTS.md` in Desktop file tree
|
||||||
|
- Selecteer alles → vervang met content uit slide 12:
|
||||||
|
|
||||||
|
```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 · GSAP 3.15+ (incl. ScrollTrigger, SplitText)
|
||||||
|
- Lenis 1.3+ (`lenis/react`)
|
||||||
|
- @gsap/react voor de useGSAP hook
|
||||||
|
|
||||||
|
## Hard rules
|
||||||
|
- Geen Framer Motion, react-spring, AOS
|
||||||
|
- Animaties altijd in Client Components (`"use client"`)
|
||||||
|
- Animatie-code in useGSAP(() => {}, { scope: ref })
|
||||||
|
- Nooit useEffect voor GSAP code
|
||||||
|
- Lenis sync: gsap.ticker.add met autoRaf: false
|
||||||
|
- Next 16: await params, await cookies(), await headers()
|
||||||
|
|
||||||
|
## Patterns
|
||||||
|
- Eén <SmoothScroll> wrapper in app/layout.tsx
|
||||||
|
- Tailwind voor layout; GSAP voor transform/opacity
|
||||||
|
|
||||||
|
## Done =
|
||||||
|
- Geen hydration warnings
|
||||||
|
- ScrollTrigger.refresh() na dynamische content
|
||||||
|
```
|
||||||
|
|
||||||
|
- Cmd+S
|
||||||
|
- Type in chat: `Lees AGENTS.md. Welke regels ga jij volgen, en waarom kiezen we deze stack?`
|
||||||
|
- Toon dat het ook de **why** uitlegt — niet alleen de regels napapegaait
|
||||||
|
|
||||||
|
#### Stap 2 — opencode.json maken (3 min)
|
||||||
|
|
||||||
|
- Right-click in file tree → New File → `opencode.json`
|
||||||
|
- Plak:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"$schema": "https://opencode.ai/config.json",
|
||||||
|
"model": "openai/gpt-4o-mini",
|
||||||
|
"permission": {
|
||||||
|
"bash": {
|
||||||
|
"*": "ask",
|
||||||
|
"git *": "allow",
|
||||||
|
"npm *": "allow",
|
||||||
|
"rm *": "deny"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Cmd+S
|
||||||
|
- Restart OpenCode (File → Reload Window)
|
||||||
|
- Type: `rm -rf node_modules` → toon dat 't blokkeert
|
||||||
|
- Type: `git status` → toon dat 't direct werkt
|
||||||
|
- **Zeg:** "Geen surprises meer."
|
||||||
|
|
||||||
|
#### Stap 3 — Worktree plugin in actie (3 min)
|
||||||
|
|
||||||
|
- Type: `Welke tools heb je beschikbaar?`
|
||||||
|
- Wijs aan: `worktree_create`, `worktree_delete` in lijst
|
||||||
|
- Type: `Maak een worktree feature-hero voor een hero-sectie.`
|
||||||
|
- Wacht tot plugin klaar is
|
||||||
|
- Klik **+ New Session** linksboven
|
||||||
|
- **Open Folder** → navigeer naar `~/.local/share/opencode/worktree/scroll-demo/feature-hero/`
|
||||||
|
- Nieuwe Session opent — toon dat 't naast main staat in sidebar
|
||||||
|
|
||||||
|
#### Stap 4 — SmoothScroll laten bouwen (5 min)
|
||||||
|
|
||||||
|
- In de **feature-hero** Session, type:
|
||||||
|
```
|
||||||
|
Bouw een SmoothScroll wrapper component volgens AGENTS.md.
|
||||||
|
Plaats in components/SmoothScroll.tsx en wrap children in app/layout.tsx.
|
||||||
|
```
|
||||||
|
- Wacht op diff
|
||||||
|
- **Wijs aan wat de regels volgen:**
|
||||||
|
- `"use client"` bovenaan
|
||||||
|
- `useGSAP` import (niet useEffect)
|
||||||
|
- `gsap.ticker.add` met `autoRaf: false`
|
||||||
|
- Geen Framer Motion of andere libs
|
||||||
|
- Klik **Accept**
|
||||||
|
|
||||||
|
#### Stap 5 — Bewijs van regels (1 min)
|
||||||
|
|
||||||
|
**Zeg:** "Zie je? Met goede AGENTS.md krijg je consistente output. Zonder zou de AI waarschijnlijk Framer Motion pakken of useEffect gebruiken. Schrijf je regels op, krijg je betrouwbare resultaten."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Blok 6 — Pauze (15 min)
|
||||||
|
|
||||||
|
**Slide 14.**
|
||||||
|
|
||||||
|
Stuur in chat: "Terug over 15 minuten." Camera mag uit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Blok 7 — Lesopdracht (35 min)
|
||||||
|
|
||||||
|
**Slide 15.**
|
||||||
|
|
||||||
|
#### Briefing (3 min):
|
||||||
|
|
||||||
|
"Eigen worktree maken, sectie kiezen, bouwen. Plan eerst, dan Build."
|
||||||
|
|
||||||
|
Loop checklist op slide 15 langs.
|
||||||
|
|
||||||
|
#### Tijdens 30 min werken:
|
||||||
|
|
||||||
|
- Tim blijft in main meeting-room
|
||||||
|
- Breakout-rooms op verzoek
|
||||||
|
- Check in chat: "Wie heeft worktree? Type W." → "Wie ziet animatie? Type A."
|
||||||
|
|
||||||
|
#### Veelvoorkomende problemen:
|
||||||
|
|
||||||
|
| Probleem | Oplossing |
|
||||||
|
|----------|-----------|
|
||||||
|
| Plugin niet beschikbaar | `ocx list` om te checken |
|
||||||
|
| Worktree-tool onbekend | Desktop herstarten na ocx add |
|
||||||
|
| Sessions sidebar leeg | Klik `+ New Session` |
|
||||||
|
| `useGSAP is not a function` | `npm install @gsap/react` |
|
||||||
|
| Hydration mismatch | `"use client"` mist of `useEffect` ipv `useGSAP` |
|
||||||
|
| Lenis import error | Niet `@studio-freight/lenis`, maar `lenis` |
|
||||||
|
| ScrollTrigger niets | `gsap.registerPlugin(ScrollTrigger)` mist |
|
||||||
|
| Async params error Next 16 | `await params` toevoegen |
|
||||||
|
|
||||||
|
#### Check-in (~25 min in):
|
||||||
|
|
||||||
|
"Wie heeft werkende animatie? Type A in chat." Bij <50%: 5 min klassikaal debug.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Blok 8 — Huiswerk + Afsluiting
|
||||||
|
|
||||||
|
**Slides 16, 17.**
|
||||||
|
|
||||||
|
- Loop huiswerk eisen langs
|
||||||
|
- "Volgende keer: **Introductie Cursor** — de commerciele tegenhanger. Cursor rules vs AGENTS.md, Composer, wanneer welke tool."
|
||||||
|
- Vragen + feedback
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# DEEL 2 — Docenttekst (referentie per slide)
|
||||||
|
|
||||||
|
## Slide 4 — Waarom OpenCode
|
||||||
|
|
||||||
|
Vertel waarom **niet** Cursor:
|
||||||
|
- Cursor is goed maar commercieel ($20/mnd), eigen routing
|
||||||
|
- OpenCode is gratis (alleen API-kosten), open source, jij kiest model
|
||||||
|
- Voor je carriere: meerdere tools kennen > vasthangen aan één
|
||||||
|
- We komen later in leerlijn terug op Cursor — vandaag de open variant
|
||||||
|
|
||||||
|
## Slide 5 — Wat is OpenCode
|
||||||
|
|
||||||
|
Provider-agnostisch, scriptable, multi-instance. Twee smaken: Desktop (vandaag), TUI (kort tonen).
|
||||||
|
|
||||||
|
## Slide 6 — Plan/Build/@explore + /init
|
||||||
|
|
||||||
|
Tab voor mode switch. `@explore` voor verkenning. `/init` voor eerste AGENTS.md.
|
||||||
|
|
||||||
|
## Slide 8 — AGENTS.md
|
||||||
|
|
||||||
|
Officieel format. Automatisch in context. Concrete regels werken, vage regels niet.
|
||||||
|
|
||||||
|
## Slide 9 — opencode.json
|
||||||
|
|
||||||
|
Schema voor autocomplete. Model. Permissions (allow/ask/deny). Plugins.
|
||||||
|
|
||||||
|
## Slide 10 — Worktree plugin
|
||||||
|
|
||||||
|
Via ocx installeren. Twee tools voor agent. Desktop: nieuwe Session tab; TUI: auto terminal.
|
||||||
|
|
||||||
|
## Slide 11 — Stack
|
||||||
|
|
||||||
|
Next.js 16 (async params, Turbopack). GSAP gratis. Lenis door darkroomengineering. useGSAP hook.
|
||||||
|
|
||||||
|
## Slide 12 — Onze AGENTS.md
|
||||||
|
|
||||||
|
Concrete regels die voorkomen dat AI default naar bekende-maar-verkeerde keuzes (Framer Motion, useEffect).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bronnen voor studenten
|
||||||
|
|
||||||
|
**OpenCode:**
|
||||||
|
- Docs: https://opencode.ai/docs/
|
||||||
|
- Download: https://opencode.ai/download
|
||||||
|
- Rules: https://opencode.ai/docs/rules/
|
||||||
|
- Config: https://opencode.ai/docs/config/
|
||||||
|
- GitHub: https://github.com/sst/opencode
|
||||||
|
|
||||||
|
**Plugin:**
|
||||||
|
- opencode-worktree: https://github.com/kdcokenny/opencode-worktree
|
||||||
|
- ocx: https://github.com/kdcokenny/ocx
|
||||||
|
|
||||||
|
**Stack:**
|
||||||
|
- Next.js 16: https://nextjs.org/blog/next-16
|
||||||
|
- GSAP: https://gsap.com/docs/v3/
|
||||||
|
- GSAP React: https://gsap.com/resources/React/
|
||||||
|
- Lenis: https://github.com/darkroomengineering/lenis
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Backup-onderwerpen (als tijd over)
|
||||||
|
|
||||||
|
1. **Custom sub-agents** in `~/.config/opencode/`
|
||||||
|
2. **MCP servers** — context7 voor up-to-date library docs
|
||||||
|
3. **opencode-workspace plugin** (uitgebreidere variant)
|
||||||
|
4. **Cursor live laten zien** — vergelijken
|
||||||
|
5. **Ollama setup** voor lokale models (privacy)
|
||||||
153
v2-klasB/Les02-OpenCode/Les02-Huiswerk.md
Normal file
153
v2-klasB/Les02-OpenCode/Les02-Huiswerk.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# Les 2 — Huiswerk
|
||||||
|
## Bouw je eigen scroll-animatie landing page
|
||||||
|
|
||||||
|
**Vak:** AI-Assisted Development
|
||||||
|
**Opleiding:** NOVI Hogeschool Utrecht
|
||||||
|
**Deadline:** Voor de volgende les (Les 3)
|
||||||
|
**Inleveren:** GitHub repo URL + Vercel deploy URL + `WORKFLOW.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Doel
|
||||||
|
|
||||||
|
Bouw een **kleine scroll-animatie landing page** met OpenCode, gebruikmakend van AGENTS.md, opencode.json en worktrees. Deploy hem op Vercel.
|
||||||
|
|
||||||
|
Dit is geen design-opdracht — focus is op de **workflow** en de **technologie**. Een simpele maar werkende site is genoeg.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Voorbeeld-thema (kies zelf!)
|
||||||
|
|
||||||
|
Suggesties:
|
||||||
|
- **Mini portfolio** (over jou — projects, contact)
|
||||||
|
- **Restaurant landing** (menu, story, reserveer)
|
||||||
|
- **Product launch** (features, prijs, signup)
|
||||||
|
- **Conferentie / event** (speakers, schedule, register)
|
||||||
|
- **Fitness app marketing** (hero, features, testimonials)
|
||||||
|
|
||||||
|
Eigen idee mag ook — even checken met Tim als 't iets totaal anders is.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Eisen (verplicht)
|
||||||
|
|
||||||
|
### Code
|
||||||
|
- [ ] Next.js 16 (App Router, TypeScript, Turbopack)
|
||||||
|
- [ ] Eigen **`AGENTS.md`** (mag onze als basis)
|
||||||
|
- [ ] Eigen **`opencode.json`** met permissions + (optioneel) plugin config
|
||||||
|
- [ ] **Minimaal 3 secties** met scroll-animaties
|
||||||
|
- [ ] **Minimaal 3 verschillende animatie-technieken** (bv. fade-in, parallax, SplitText, horizontaal, stagger)
|
||||||
|
- [ ] **Lenis** smooth scroll werkt (geen "harde" scroll)
|
||||||
|
- [ ] TailwindCSS voor styling
|
||||||
|
- [ ] Werkt zonder console-errors of hydration warnings
|
||||||
|
|
||||||
|
### Workflow
|
||||||
|
- [ ] **Minstens 2 worktrees** gebruikt (mag via plugin of handmatig)
|
||||||
|
- [ ] Branches gemerged naar `main`
|
||||||
|
- [ ] Worktrees opgeruimd
|
||||||
|
- [ ] Code op GitHub gepushed
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
- [ ] **Vercel deploy** werkend, URL in README
|
||||||
|
- [ ] Geen broken pages / 500's
|
||||||
|
|
||||||
|
### Documentatie
|
||||||
|
- [ ] **`WORKFLOW.md`** in repo-root met:
|
||||||
|
- Welke prompts werkten goed?
|
||||||
|
- Welke regels heb je later toegevoegd aan AGENTS.md (en waarom)?
|
||||||
|
- Hoe heb je worktrees georganiseerd?
|
||||||
|
- Wat zou je anders doen volgende keer?
|
||||||
|
- Screenshot van `git worktree list` tijdens het werk
|
||||||
|
- Max 400 woorden — concreet, geen fluff
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bonus (optioneel, geen extra punten — wel meer leren)
|
||||||
|
|
||||||
|
- **Eigen sub-agent** definieren in `~/.config/opencode/` (bv. een "animation-reviewer")
|
||||||
|
- **MCP server** toevoegen (bv. context7 voor up-to-date docs in agent context)
|
||||||
|
- **GSAP advanced**: horizontale scroll met pin + scrub, of SplitText met stagger
|
||||||
|
- **Custom Lenis options** experimenteren (`lerp`, `duration`, etc.)
|
||||||
|
- **Lighthouse score** > 90 op alle 4 metrics
|
||||||
|
- **Reduced motion respecteren** (`prefers-reduced-motion` media query)
|
||||||
|
- **Eigen `ocx` plugin** schrijven (zie kdcokenny/ocx docs)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tijd-indicatie
|
||||||
|
|
||||||
|
- Setup (Next.js + deps + AGENTS.md + opencode.json): 30 min
|
||||||
|
- 3 scroll-secties bouwen via opencode (3× ~30 min): ~90 min
|
||||||
|
- Polish + responsiveness: 30 min
|
||||||
|
- Deploy op Vercel: 15 min
|
||||||
|
- `WORKFLOW.md`: 15 min
|
||||||
|
|
||||||
|
**Totaal: ~3 uur.** Loop je vast? Vraag in Brightspace of plan een korte 1-op-1 met Tim.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
### Workflow tips
|
||||||
|
|
||||||
|
- **Begin met een werkende `SmoothScroll` wrapper** — zonder dat doet niks goed.
|
||||||
|
- **Eén sectie per worktree** — niet alles in main mengen.
|
||||||
|
- **Plan-mode eerst** voor elke nieuwe sectie. Krijg een plan, geef feedback, dan pas Build.
|
||||||
|
- **AGENTS.md update tijdens werk** — loop je tegen iets aan dat de agent steeds verkeerd doet? Voeg een regel toe.
|
||||||
|
|
||||||
|
### Technische tips
|
||||||
|
|
||||||
|
- **`useGSAP` heeft een `scope` prop** — gebruik 'm met `useRef` zodat je `gsap.from(".class")` selectors scoped zijn aan je component.
|
||||||
|
- **`ScrollTrigger.refresh()`** als je dynamisch content laadt — anders triggert het niet.
|
||||||
|
- **`prefers-reduced-motion`** kun je checken met een media query in CSS én in JS (`window.matchMedia('(prefers-reduced-motion: reduce)')`).
|
||||||
|
- **Lenis `lerp`** is "hoe smooth" — lager = soepeler maar trager. Default `0.1` is goed.
|
||||||
|
- **Pin-secties** mogen niet inside flex/grid die hun height anders berekenen — pas op met layout.
|
||||||
|
|
||||||
|
### Deploy tips
|
||||||
|
|
||||||
|
- Vercel pakt je Next.js automatisch op
|
||||||
|
- `npm run build` lokaal eerst om te checken of er geen TS errors zijn
|
||||||
|
- Environment vars (als je ze hebt) in Vercel dashboard zetten
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inleveren
|
||||||
|
|
||||||
|
1. **GitHub repo** — push alle code naar `main`
|
||||||
|
2. **Vercel deploy URL** in README van je repo
|
||||||
|
3. **`WORKFLOW.md`** in root
|
||||||
|
4. **Brightspace inlevering**:
|
||||||
|
- GitHub URL
|
||||||
|
- Vercel URL
|
||||||
|
- Korte note (1-2 zinnen): wat is je trots-punt?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Beoordeling
|
||||||
|
|
||||||
|
| Criterium | Punten |
|
||||||
|
|-----------|--------|
|
||||||
|
| 3+ scroll-animaties, verschillend qua techniek | 3 |
|
||||||
|
| `AGENTS.md` aanwezig + concreet | 1 |
|
||||||
|
| `opencode.json` met permissions/plugin | 1 |
|
||||||
|
| Minstens 2 worktrees gebruikt (zichtbaar in git log) | 1 |
|
||||||
|
| Vercel deploy werkt | 1 |
|
||||||
|
| `WORKFLOW.md` concreet + screenshot | 2 |
|
||||||
|
| Geen console errors / hydration warnings | 1 |
|
||||||
|
| **Totaal** | **10** |
|
||||||
|
|
||||||
|
Voldoende = 6+. Bonus telt mee bij twijfelgevallen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Veelvoorkomende valkuilen (uit eerdere groepen)
|
||||||
|
|
||||||
|
- **AGENTS.md te vaag** — "gebruik clean code" werkt niet. Concrete regels werken.
|
||||||
|
- **Te veel willen** — beter 3 secties goed dan 7 half. Schaal omlaag bij twijfel.
|
||||||
|
- **Worktrees na merge laten staan** — opruimen, anders chaos.
|
||||||
|
- **`Lenis` van oude package importeren** — `@studio-freight/lenis` werkt niet meer. Gebruik `lenis`.
|
||||||
|
- **`useEffect` voor GSAP code** — gebruik `useGSAP` van `@gsap/react`. Anders Strict Mode bugs.
|
||||||
|
- **Next.js 16 async params vergeten** — `cookies()`, `headers()`, `params`, `searchParams` zijn nu async. Altijd `await`.
|
||||||
|
- **Geen Vercel deploy testen vóór deadline** — minstens 1 dag van tevoren deployen.
|
||||||
|
|
||||||
|
Succes!
|
||||||
143
v2-klasB/Les02-OpenCode/Les02-Huiswerk.pdf
Normal file
143
v2-klasB/Les02-OpenCode/Les02-Huiswerk.pdf
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
%PDF-1.4
|
||||||
|
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R /F3 5 0 R /F4 6 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 13 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 14 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 15 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
9 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
10 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 12 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
11 0 obj
|
||||||
|
<<
|
||||||
|
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260518122502+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260518122502+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||||
|
/Subject (\(unspecified\)) /Title (Les 2 Huiswerk) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
12 0 obj
|
||||||
|
<<
|
||||||
|
/Count 4 /Kids [ 4 0 R 7 0 R 8 0 R 9 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
13 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1631
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
GauHL939k-']/^ggg+VAW0[@EB@iG>3FtfU;n?Dt3_CT*>HTQql+`i@^Crp>9Gs"W+BeR/rU(UQf_D36B:K%9T>K=r$C&AK%b)dW9[D[BCAkFDo3(!t5TFZ'+Ti?<jp-ctQ%A*35@bo@D?kh"0"@Dac9i'Mmf`_$TF`f,@o4A"D[5&$_Pu^>s5&0Zpl(n[Q[$4dDVf=)j$p_DpoS_<B(JJG4@*1L4f[NTRsKVjdhE9U?X0/<8$rn>]MpA3n%')#;StA%!PCKUHrlW>e7&VPi`7<S:IV-f_t4/1DiCb0^?^GCQ3ZaNkFr(`+"LLNM.5#NIYegqMh$h,^7n=`+J6'!q@4f;kW.jbSHcQN]U)f>i&+QD+i-T<R-g@j,O>6^@DgfSf]j9;3lL_SC@2RY5&gWB6B=TMfUV5\ofKE9HCS*>Y^XV6d-O&#CtYaVJtMH+p<2f3$sH:3h+T6[bX(Y*6cH$WL8-X**-^NfU_E5PG8:aZgE%HHZ`lUC$gW!FpO:M2ms"+!boVQ:BC5uJ,9E\O%`DVh4;q\3F=Cg.9d[M95oIC.((;bFB$2TS0uI_`0F%YYdC+[H'Z"qMG%&%T!-O-kFbt'\_M0=He0ojGmo=K82ZeY;L^_G9:e>[EAMT7P'Tb`99P+[RUP3qL9+X<A<<fd?I%\f0cXm'+?^=t^mL4^$fsTtD05]Nn)\JMh8?-s=(DMf\6cE08"f^hJ_,[l=HVNb0<Zq[2Z,+0,F<18KMR5"]#)>F$`'p7'BmfD0Q$jrp:jJ`)m\%G`B2LZ%d4CEJGaumi!]HEN.94/W^o^3_R.6LG;s(Yd*2cAuZV20M<lHDo5?((NMX/m+Ld$a[=dEG`'I):akd,N*9)Z$k$/[D^i@h\R74aUFn`/X"e&hF)&!G6+ao8lF6_Ck02G1uo[V[;XDucqCGMrJ!E-[>1GBFXB+U-I.gB%WeI+o.pnurAS3Q%p9_sa^5%iVO/.OC5_m6!r3S2H-6f\7Ne0mHtL"kL^/-=\BGQ:XW$L5T;I*u%3&OXO:7jV(aPT1(&-BsbauK\Io-GGiKRVr,j"P>;&YL"BeH7W(h`!Qr#Q`<t'kPQ[->7/_k:83u@>f?#)P)''=H6FNRI:`e9oN@Qm-&sYsmAtkNJlqlfM,3gP^\VdH9*'p-WDQV6H&-k])H(s`\rD(?5e9L_JCFhT99%61bbo6eG9n/=?/eYO2'GY":TLnb3I&5>e;)_E_Z%m<=mesCM1r\XU&BX98UQ;-Njb)RiL<+Tn'#/WXjO!SHI5TkfVlj_F4K'N#-I"g)agr#871S&f3WI/o6EUYY=,BoNr-s-fYXH?fWgYoi$[!\'>tuMCR>taiUFu.8dscTASZF40^D*N)WZoT-<una%!(VcY!i8r:mg79rV'p58f[Z/[W6)e:ohO'OWIJVc/FosLGe&P%>XZ.i\eB1t]YQ7"=K6`rmpRJdH/>*n-h@80ZFO]HVB`_W*!+c=E1MBE$g[nJ@3%#?X@e.crPFMV]04L>7ftl3s,#6n-qfBe*"+USB"^@mQ_I:i(kP"_WlS.N1.o\@(3je9@=G^^:Z"?'*S5f0aI+a,A-#<1rt@)("*@4qXefps;jd\:#-Y6E$=/6a3f4QcS44l8\(PRR@/UJlcQC[~>endstream
|
||||||
|
endobj
|
||||||
|
14 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1724
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gb"/'>BA7S&:XAWfXFeHe6);?]UUEI-prPQ)sBq$<*QW`.$B^XQLa@fg5b!r\M.I;\9*HPPGGLkg2AX:G"'3_(MQ's3P`fm]Qceo:`)uZGd[k;;`Gh&h^k6$2"Z1"h8jSG$?kdeJ"SSjJfiW29Oe-d'A?=IJJSn[MW+miXp[T0K'"b8D@s+j^^24rm"kF&'WeE\m=8*ig9^`#L``d,l5/"9`HJK8%b5CQ-k'aM-)b.Mle)d<6Qa<h3;E:5lT7(')6]3..03e7k"0Gu6>6]qmgbDYWi->%iAJC46BuUEbqg2D_>&;hf8=t%N=ft@hNr`7/"gje.&n5hB<Bg9=]S&tF@FJfZtUm9TM%^@-aI%0$.0PN%;r^iR)nq%07^T%ICoI2NsU`![c;V[ar$,(ZTO_1!F6`9]/b_uO5UT^&Q4PPLCgU-qp<N08NWhOTGpEu_="e:#X0PY&"R$ge*iH%cCG^Ps65eR0(*/L+A])oC1=2l[B>#LVN.2oGQU$2L<#1pLh"ni:_sD[FX'+c>Xhcl@[#Be&&23,#EAZ6VX*e9CAT9r\@j9i\>ZoR,N4n[q3EGm_po:14po#,:@l!M^4t!N:]&B&ejh\:[;0s(cAJo@j]]>%;_,4HpO`bY_g=GIC5H9h$2SI\1MGZMUm(](5P"9_^8bp(:(E<,'$f"DE'8gCD9:*;?'GPC0D)(j=YcI/gStS>--h$c]?SnQ[W:etY#qKCIYQ-djPT?PE:il!j7qE$Voo>$dK;>KS7SAS%h;94E643%g=Rib,4&'fgF]qVDo(KoV_Vqh2/s@,9YkqA&IgXc't_0Y(F,rCb6/Ic_b%s-jE#43jEb,TTds:50E<.rK,L?:CV'W2-3JWDA2.^j+TJhjXZ#1@'!6gHAG,#4dUpjT0HB:oY?qN_br)*EKb.LdQl&JDLB`fW=n!;9GQ6`3b#3[ja:XY11EkEF&Y,2^0OnXd&`cP#5EmuQIoPT+Q>o']Nk[AMg]7_igM9T[ST7l7#=gXQb2gb@J@[Kj4(-J;H1c'Y]oJ40/&Y.*doY_qE35?o(Z($9B"LkK#jRa1^#_e*$$):Dr/b]rF9QCdq/*,dg6I=1VBo\V:[?=;'^7,?T4/sM(Kc.oaoMlB3a=srU%E.NeBQ<s9$`F-5hN-7HlC$.2Jf[:]5Gt6f["Co*A`/D(WFTLl`3o7YU+(jMoi=i9X6$6r#9FIQ^Z#Aa6kbDF07=c?mT<o/"4,r&p%*pVbR++SWc@)G\AafAJP/3=heh\&IH*%bfSiW]iQhdS?G<6b42&:gA((7+o+DqhAqX;?h70ogBTZ7)en.<8KS=enbcnXrLQ.OQ0X)28/l'?&U[m5@WO5T05%38.`9s0dH_=`:RN&gEpusWKS;!OL4&^sI)l%uO7LW9<,&L2s%pUpeDLd,%4YN1`)*q\5J(6F;;3]Ap<LC1:M9.RS:8'%FD$<lVKo-N2)^lq4iH5^;kbWh&k=I`lp4U3EEfhhJ\oBb6`JVK1f`:HUUr;#dslhQ>Gtm1VKp0M"Za>N.h7.KY/)M+]Z-!H(mE<RDdp9%lb8XX0db4i_1.D5@o)kIMKc#r7K_s6V)'GQ,Iu[qhoBCRp@U'pn3\dBJCkTV>sYL;IFh)%c+Vj?1%'YgHPI,3];5$$]dBd"M<^PO[I,Fn9^c0s7:k&[c4j>oh/)6/1o^G<.uY#*4*D,E,$$bl:6\/gg.#\-ToEP\Z'\:q<#f<E#COFtk5~>endstream
|
||||||
|
endobj
|
||||||
|
15 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1334
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
GauHK9j?@A&AJ$CbgB#B79Y,AEbHOcJ>@==J4_H.#\blo.r1DUaj;+(m@BMQ@r,Z,Zk"!-fJE!?]^ohV/:?*pmplWA'#Dt`%5roR%(8f6Lk]jeomZN=okE?15TFAr+U&K>jpP/>/&:b5+4AL?Ad*hk0"B+PN.hZgl32_ZJDr83hm7k:^(i=<#dZ[dq&B/?nL6oU0(F<R>hAHBA&c3DpmlWmB)@Qq-t.<c/Q!OT=LK#j&C$ktEI%Er^;u9!A0PRpIoM:QP6sdD#&sK_E3-Io'i3dETCZ<R1L=&L+IYXhhUl#JGF]:tA\iHc+kK!<9.fd!=+@Z_=)fRE(n;>2Doh/EaJYT(!VHcj//NB4S+7:I/F\YTUGHG_iIs0]l^u7mehHC4Z4aJ$4<M7`Aq&9],u\,@<ueH5[p*oJ=]eC$ct-'*oGQ;iFdUYGdchOSFa@R'_2DV\2XtUQfh]UG&R1bQ>XH&@PsPFLA@qnJh[SR]Ok$A>qN19Q.)a3s*//F-JB&mtaC6^+,?aR]OXWM@d5qOLm@-tWY]V&j^ONfrc./>bNSl>/kE6d97fBqZ!=ZX#%oiUN.2C@oTTXpaXuN44d5u*"6#^61rYHUk[LVBWr9!b]icH4X#u<d'E&!JIr/L6e3<u*'RHH9a'pMf55FE>Q]+6%)E)YnnMNFXr?!YEPee,Nb(sd[n@MZB^,j&%-.li5*08,('FQa0[pd</g0S>LgVI";Gaq'Tb.Q.VqMo/tAa2,XDJK,(e2Q8%/egC2jnW!<nL<r8-+O75U>a'O]'"oN'qM)nM^2>i8o<cMDJ=/5C`-&+RSi$9!#_1>W'd%Ln#HCcBZq<FOre@cLFec3I%Pi<[19Y\'DhO,EJeHOX8'%\8hpsnmmW6_Os7U^`VWg>[WCX88q#4:]>40/3>o5_Kj^oI)`PoB"*X`jeX=Z1Q1j>Glld),&kjJZbkUUUX[MP:uNi>$Rkk\/_OpN4;A^*qnS5`rM.P>&;"J#P=<TJ;%E,Mi%\AE)c@G4bHek`;bLN0@X-uX?1Qe6Br\7ir_is&,$BqC@2:G8F]1/%0+p.Tb_JQr*=0HCO5U=_*b"85P9eEsu$`^q<BXM'hj4ncs%`3?b,p=S\m*lFQB]V(CuP.ApQ%)r\tgcGRaNGH5J7&R[Z,-5l2oU2&Vr6(&e>HSU1mt'o6Ci:,3fZ8HT]`.;7Gkp0+A)![/"s7_Q2nf,>r_.[WArJe'ZkP_Z3R)1aL2@@Nk<7h@rN[qd:N^RSc/IgHOlV0ZEEqBW@puu7^m5$,&(*pKEL_N37gJ<_Oc:5>PfWff_`ZN#06!uO3&>dPM)$S_QZ9mag15im59UqYmJ~>endstream
|
||||||
|
endobj
|
||||||
|
16 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1876
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gatm;=``=U&:W67fU%Pf___DNSa!M)i](YCUQ,u%p][C"$8Mo9+D'+!oj**D7+#K*]!8>h_o9+Z[n?cT^52_]$\6\\*5<db.#`(ppl5mF$TK)d^5j6Pd`;s7nRC*C-od&rr]k*@#smd.#u(]DDWJ`u%t73B3)3qUGV4kE"Id6QM\,t;$Jd-(_21_p`o2RASeG"ZWdQ6#_k_drYqJ#t,u3)pLM#-;#_itfEGCKuq2S+"."H:<LEAa/HOoRE`liJ$<"<7cc-of!f9AaDo)@jK/4E_3.D4V`4BIGmbN_*Hk:h?nFER)$00s72BH-u'QU'Nc;Nr]7Den"O//+1thnf*rA(h!<ZnXD3Tb@[6O1G&[OE[dF+Z+M+hdY)O>c:BNi@.i#:O+R'[\^F5GTEKnV2nP+nJik6-G`3NY0F(o2)5;qm>u<#PB7?3hsIBshN.%#:I1lG?K>Xp>C1mqSUPJ8qE(8%K1gE7\]2%:J/NQJUXH"O3b8m)F^845YI1==(<^0[MVHXint28Sij'fq>00eoJRhk1M'@l:]nA/k.aO0C'EtN?042O9f@Y-gcafR_pEbG!)c$fi]>q-5k\`E1)L,<@jS\B)pkr'EJMF^p5=>]/+]U;JS7@0n$CU#d>g;\t8tMbOf?a2*DLfj%Asug&[GWf?;sqk&-)!S@$a'kg<2*oK]Z?Gls8-mq:rBm"RUA;bM>SV.bH-rB7J]?janS7W`NA\$LHmni0W%-,a@$3Bb4^29J.HCUM7rqKl]gQdjbmC"K4285Ebpl-K7gs*S_U8AQ[c`_piL)Q[n`?n,*'C_e35`!$lr7+eX8Ni1kT/8S-.AHkn9"bG!FMZUmS_.dh3P)gnW-K;\sR+a/WT"hZMD>h<g"9K)Pl0o8uE"R!Qil'PF:UVe:tD%%$-%-\0a9C5WO(R*-J`=Jjt9AGjAi4?j5_fC'K2_R4n3##P?oa,XMf*R^*I4a+Q=I&aEe3W'6C9*\4W>aF%,H%g+O@3Xi1Xi1-lk8D$EL'sNfn[,PL,`_1[8`/URKVuXii;;`kKO_b_`?ps_SF.,f\QG4^"&BZ_58u'g"6E%_7g*-,mafhGF_1XYU(^kW6JfEJ0IQi(L7"1,!csL`H1RRcYi`F,53H+b'Yaa7E#Y5Ae$\nH0S?DB+@j`dD>&CpP"6c8p^&QPVG];SYNs#e\Z.#JT?MWqA.r0V.&i6i<n`CG)nJeRSO(1:32GCCqVO=iUquXagdZ0]@4MHOI_-;]H=X'&&esN=W1\F(<ZHt'+Y.&nDkT*)#c:?TAfk?Kfs%1Kb$_QW?FgUb:;fD;At"1k%r0)c*'0>eY:\!u-Cbt"97*io8#)tO+!W,d%kB`OC?PtqdbmDS7Z`$5mYb"C'#BOg2gpL_2,3*D=E'gNa;Il8PfO@EUfsFn(nOgE0LWuSl&;UIO*&47.+(NkC5ILHYk45)ROAqDUIhS9Xlfr"O[&')/5(G8F(8t+A-L8nS:%d(ffk?mp5[PoHWIGkZ0!U>qHtE@h\D/7gtdLGpG,141b20Sm5&(V(9tLbF.CE(-6=:3:>R$C'fR?Im]O7M1N/73fG&P_`^Za@R,NQDg0$s#r0]FMice#`@[05GoE[X&KS_WYLbt"?!rmHrIkPkjY0^A\f"b0YihW@Cd>])4p`D*\f9UTJS.$(;mkt\=Xepkm*I_u)9mh1<WcuVmp>&';>J9:b3kpSa3<M&XlFN3lRjj^A%N;M&5K.@5#cIX!3PA_W?S=&R\;iB2o'GG^LGN/UF1qt-DO9T`ES5\lbOfL$GF#gGc>'bpf(Ikr.Gjl]nEt#9SSF;3WY.</$+TEgp0##fk:b0r4!sl*bB!;8nf'T`n3]a'57^er!p"OKHDM@ni`"KJ#6Q4UUON9L,Y1Q~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 17
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000061 00000 n
|
||||||
|
0000000122 00000 n
|
||||||
|
0000000229 00000 n
|
||||||
|
0000000341 00000 n
|
||||||
|
0000000546 00000 n
|
||||||
|
0000000661 00000 n
|
||||||
|
0000000766 00000 n
|
||||||
|
0000000971 00000 n
|
||||||
|
0000001176 00000 n
|
||||||
|
0000001381 00000 n
|
||||||
|
0000001451 00000 n
|
||||||
|
0000001743 00000 n
|
||||||
|
0000001821 00000 n
|
||||||
|
0000003544 00000 n
|
||||||
|
0000005360 00000 n
|
||||||
|
0000006786 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<51c9ef4a08589d21f13f527085c33787><51c9ef4a08589d21f13f527085c33787>]
|
||||||
|
% ReportLab generated PDF document -- digest (opensource)
|
||||||
|
|
||||||
|
/Info 11 0 R
|
||||||
|
/Root 10 0 R
|
||||||
|
/Size 17
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
8754
|
||||||
|
%%EOF
|
||||||
188
v2-klasB/Les02-OpenCode/Les02-Lesopdracht.md
Normal file
188
v2-klasB/Les02-OpenCode/Les02-Lesopdracht.md
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
# Les 2 — Lesopdracht
|
||||||
|
## Bouw een scroll-animatie sectie in een worktree
|
||||||
|
|
||||||
|
**Vak:** AI-Assisted Development
|
||||||
|
**Opleiding:** NOVI Hogeschool Utrecht
|
||||||
|
**Duur:** 35 minuten (in de les)
|
||||||
|
**Inleveren:** niet — je code uit deze opdracht is je basis voor het huiswerk
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Doel
|
||||||
|
|
||||||
|
Bouw één scroll-animatie sectie in een Next.js 16 project, met:
|
||||||
|
- OpenCode **Desktop** (met onze AGENTS.md geladen)
|
||||||
|
- Een eigen worktree (via plugin of handmatig)
|
||||||
|
- Een nieuwe Sessions tab voor die worktree
|
||||||
|
- GSAP + Lenis
|
||||||
|
- TailwindCSS voor styling
|
||||||
|
|
||||||
|
Het hoeft niet groot — een werkende sectie van 1-2 schermen is genoeg.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Vereisten (al opgezet vóór de les)
|
||||||
|
|
||||||
|
In je `scroll-demo` repo staat al:
|
||||||
|
- Next.js 15 starter (App Router, TypeScript, Tailwind)
|
||||||
|
- `AGENTS.md` met onze regels
|
||||||
|
- `opencode.json` met permissions
|
||||||
|
- `npm install`-ed: `gsap`, `@gsap/react`, `lenis`
|
||||||
|
- `components/SmoothScroll.tsx` wrapper (klassikaal gebouwd)
|
||||||
|
|
||||||
|
Geen scroll-demo repo? Vraag in chat, of clone: `git clone <link uit Brightspace>`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wat moet er staan?
|
||||||
|
|
||||||
|
- [ ] Eigen **worktree** + branch voor jouw sectie
|
||||||
|
- [ ] OpenCode draait in die worktree
|
||||||
|
- [ ] Een **werkende scroll-animatie sectie** (kies één type — zie suggesties)
|
||||||
|
- [ ] Volgt de regels uit `AGENTS.md` (geen Framer Motion, `useGSAP`, scope, etc.)
|
||||||
|
- [ ] **Commit + push** naar je branch
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stappenplan
|
||||||
|
|
||||||
|
### Stap 1 — Worktree aanmaken (3 min)
|
||||||
|
|
||||||
|
**Met opencode-worktree plugin** (in main Session):
|
||||||
|
|
||||||
|
```
|
||||||
|
Maak een worktree voor feature-mijn-sectie (kies een naam, bv. feature-hero).
|
||||||
|
```
|
||||||
|
|
||||||
|
De agent roept `worktree_create` aan. De worktree-folder wordt gemaakt op `~/.local/share/opencode/worktree/scroll-demo/feature-hero/`.
|
||||||
|
|
||||||
|
**Daarna in Desktop:**
|
||||||
|
1. Klik **+ New Session** linksboven in de Sessions sidebar
|
||||||
|
2. Kies **Open Folder** → navigeer naar de worktree-folder
|
||||||
|
3. Nieuwe Session opent met eigen chat-context — main blijft beschikbaar in sidebar
|
||||||
|
|
||||||
|
**Of handmatig** (als plugin niet werkt):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git worktree add ../scroll-demo-hero -b feature-hero
|
||||||
|
```
|
||||||
|
Dan in Desktop: **+ New Session → Open Folder → ../scroll-demo-hero**.
|
||||||
|
|
||||||
|
### Stap 2 — Sectie kiezen (2 min)
|
||||||
|
|
||||||
|
Kies één van deze:
|
||||||
|
|
||||||
|
| Type | Wat | Moeilijkheid |
|
||||||
|
|------|-----|--------------|
|
||||||
|
| **Hero met SplitText reveal** | Tekst die letter-voor-letter verschijnt op scroll | ⭐⭐ |
|
||||||
|
| **Features grid stagger** | 3-koloms grid die in-fade'd, staggered | ⭐ |
|
||||||
|
| **Testimonials horizontaal** | Horizontale scroll-sectie met cards (pin) | ⭐⭐⭐ |
|
||||||
|
| **Gallery met parallax** | Afbeeldingen die parallax-en bij scroll | ⭐⭐ |
|
||||||
|
| **Stats counter** | Cijfers die optellen wanneer in beeld | ⭐⭐ |
|
||||||
|
|
||||||
|
### Stap 3 — Plan-mode (5 min)
|
||||||
|
|
||||||
|
In opencode (start in plan-mode of `Tab` om te wisselen):
|
||||||
|
|
||||||
|
> Plan een [type sectie] component die voldoet aan de regels in AGENTS.md. Toon me het plan: welke files maak je, welke GSAP API gebruik je, hoe sync je met Lenis?
|
||||||
|
|
||||||
|
Lees het plan. Stel vragen / geef feedback. Niet meteen op Tab naar build.
|
||||||
|
|
||||||
|
### Stap 4 — Build-mode (15 min)
|
||||||
|
|
||||||
|
`Tab` → build. Geef commando:
|
||||||
|
|
||||||
|
> Bouw de geplande sectie. Plaats hem in components/ en importeer in app/page.tsx zodat ik 'm direct kan testen.
|
||||||
|
|
||||||
|
Laat het bouwen. Lees mee. Stel correcties als iets ingaat tegen AGENTS.md.
|
||||||
|
|
||||||
|
### Stap 5 — Testen (5 min)
|
||||||
|
|
||||||
|
In de worktree:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open `http://localhost:3000`. Scroll. Check:
|
||||||
|
- Smooth scroll werkt (Lenis)
|
||||||
|
- Jouw animatie triggered op het juiste moment
|
||||||
|
- Geen console errors
|
||||||
|
- Geen hydration mismatch
|
||||||
|
|
||||||
|
Werkt het niet? Vraag opencode om te debuggen.
|
||||||
|
|
||||||
|
### Stap 6 — Commit + push (3 min)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: [jouw sectie]"
|
||||||
|
git push origin [jouw branch]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stap 7 — (Optioneel) Cleanup
|
||||||
|
|
||||||
|
Klaar met deze worktree? In de main Session:
|
||||||
|
|
||||||
|
> Sluit de feature-X worktree en merge naar main.
|
||||||
|
|
||||||
|
Of handmatig:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git worktree remove ~/.local/share/opencode/worktree/scroll-demo/feature-hero
|
||||||
|
cd ~/scroll-demo
|
||||||
|
git merge feature-hero
|
||||||
|
```
|
||||||
|
|
||||||
|
Sluit ook de feature-Session in Desktop (right-click → Close).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Veelvoorkomende problemen
|
||||||
|
|
||||||
|
| Probleem | Oplossing |
|
||||||
|
|----------|-----------|
|
||||||
|
| `useGSAP is not a function` | `npm install @gsap/react` |
|
||||||
|
| Hydration mismatch warning | `"use client"` mist of `useEffect` voor GSAP code |
|
||||||
|
| Lenis import error | Niet `@studio-freight/lenis` — gebruik `lenis` package |
|
||||||
|
| ScrollTrigger niks doet | `gsap.registerPlugin(ScrollTrigger)` boven in file |
|
||||||
|
| Geen smooth scroll | `SmoothScroll` wrapper mist in `app/layout.tsx` |
|
||||||
|
| Plugin niet beschikbaar | `ocx list` om te checken, evt. `ocx add` opnieuw |
|
||||||
|
| Worktree-tool niet bekend | Plugin niet correct geïnstalleerd of opencode niet herstart |
|
||||||
|
| `gsap.context is not a function` | Oude versie — `npm i gsap@latest @gsap/react@latest` |
|
||||||
|
| `params is not iterable` / `Cannot read params` | Next.js 16: gebruik `const { id } = await params` (async!) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Klaar zijn = je hebt:
|
||||||
|
|
||||||
|
1. Een werkende **scroll-animatie sectie** in je app
|
||||||
|
2. Gebruik gemaakt van **OpenCode + worktrees**
|
||||||
|
3. De **regels uit AGENTS.md** gevolgd
|
||||||
|
4. **Smooth scroll** werkend via Lenis
|
||||||
|
|
||||||
|
Deze code is je basis voor het huiswerk — daar bouw je 'm uit naar een complete landing page.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Voorbeelden van prompts die werken
|
||||||
|
|
||||||
|
**Goed:**
|
||||||
|
- "Plan een hero sectie met SplitText reveal. 1 lange koptekst, 1 paragraaf. Lees AGENTS.md eerst."
|
||||||
|
- "Bouw een features grid van 3 cards die fade-in'en met stagger 0.15 wanneer de sectie 80% in beeld is."
|
||||||
|
- "Voeg een horizontale scroll sectie toe met 5 cards. Gebruik pin: true en scrub: 1."
|
||||||
|
|
||||||
|
**Te vaag (krijg je rommel):**
|
||||||
|
- "Maak iets met scroll."
|
||||||
|
- "Voeg animaties toe."
|
||||||
|
- "Maak het mooi."
|
||||||
|
|
||||||
|
**Tip:** wees specifiek over wat én volg de patterns uit AGENTS.md. Hoe specifieker, hoe beter.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reflectievragen (1 min, niet inleveren)
|
||||||
|
|
||||||
|
- Werkt OpenCode anders met goede AGENTS.md dan zonder?
|
||||||
|
- Voelde plan-mode → build flow natuurlijker?
|
||||||
|
- Waar zou je worktrees morgen gebruiken op je eigen project?
|
||||||
149
v2-klasB/Les02-OpenCode/Les02-Lesopdracht.pdf
Normal file
149
v2-klasB/Les02-OpenCode/Les02-Lesopdracht.pdf
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
%PDF-1.4
|
||||||
|
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 6 0 R /F5 7 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 14 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /ZapfDingbats /Name /F5 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 15 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
9 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
10 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
11 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 13 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
12 0 obj
|
||||||
|
<<
|
||||||
|
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260518122502+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260518122502+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||||
|
/Subject (\(unspecified\)) /Title (Les 2 Lesopdracht) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
13 0 obj
|
||||||
|
<<
|
||||||
|
/Count 4 /Kids [ 5 0 R 8 0 R 9 0 R 10 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
14 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1679
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gb!;c>BcPr&:WeDbbNq&$5,;FQeaKb2Wo2:[.^@MISm>,M#gJhFgo,77t:V%[c;VemV2%GK90^-S'*_m"VX,-\crJVX"g,N;4n?;T7P_7L@JKX*#i5n_Hc6V%M4PfQHt*VQMuM!1fA9tiqgls^eKl/cN]k;_R\!DiAo5Z*omqt5;su%cS[k'"6%aL\bk<t79mi/[7qXmof(2Up2Or@:Y`rN1pd1U0\er5:p!^?-73jt#K@&YhS$\;L,UTH75.XiL;1o:#."phN-TAcrSjn,U8!lN\<('/XKk6kjYIb2_t^dneWXo-:-9IkXiZ&C$XeKdPtc>I9"kmGPR='H;'4/e.p4K?Ciq=%4Q!Ct*.**O\9KV\CsT($D*j1?5%1=hTC`3CEf5)7/d+Xj6`ELJa.`?G\)n=HUHZ'5..un3Xg3*r0RAdiUJ]UFR%6(?;\g2sRM"Sfg#)_k<D5biAmhD@jd]J0SRJs/<Sh]e`fJ$_//2fD]T8V/`8mf547(10G.#KH'ofo?BsG,tAgbjiPl57]>*qYs8ic9hfn;B8a)Y<_RJt^TE-d4!>[9"M=KEs=?4pb1;pSngG\EgcH@@N(X2OC:np20Q6pW>tYkC]_M9i-/!<p59M^:o^64r9.NaEJU-mK$q=tM@,50%].Ntr&Ep,(*'On:T>(%9eVh=/B;X2c`?TOh_H2/C<NFl#Lmoaq=+J(H+QP=rg?:2PY`$otg4o9X5^pT=!@QSe\/A^beTO)ra\3YO&n'SuKd/>HpDL6"\^<5Sp)*Se73$8[`pEj8a-O/"[6p]_),bTods,pqthJ=/Ka&BePRC`eV2:gBnQ`]KOO!Dnf77jOStF>"e6#UCnX:11BD=/Br)iT&T8.[Di^5;;'6L+-t^3nOr\7k\^YB=@mZCpi6\7.B_(/hSZOZQTA(oc''H(e36`g>$TMmN#<YI,_S0YN?/BUlLW.:3Un#*G\C0%_$5q>Pqg4i5BZ7rbo>DUer<m)m5Ca48H!(pB=A0Z<Z5G1Is2Pmk^B'l]>Dn@U?'N=Da@$f]1B<$HPIs9-^uL8f1-1'9s>0MRt%E*hD-&$*nps'dt8[Z&%CNPYTOp,BA;V/E[R/Ceqf)3k^dU>\__[#]li2FKCo3-Cmi.XZO7S'^,pZhO;P+),TKGJlOQg^eW)QE>`eT-)p-2QbS>BAYK$^k$toY;WO[upJ=.7PFAjkd(p`[_lB[VMIATS9W7.A1_M0iHGJ`d4cNLRN,:\/SiY%Mpo'93o-'(malFkkUT>HDq6n=X][o2o53QM2o]s\Eit4k[<HY>6]>SD7P]<r5<nBfj5-,u5[R-G1SH7cMdL'04eJHaMZ3ORb>CSiD,Q%7q#j)2$Od?Up!r;F`rH"E#&R\e^RLo5Pqh=NS<=e3A;GOEs7VWGu$j)]).`F]Y3#s;9XKtdSAOosOX&O91(r.mC=]SPe4;Jdf\NjI/jW1e/D0<Cqo/#"o@4_:I@%UAbDeKrmLe.PjS5cKRrB@$g4.^Ou4>3b\hLodCGd-n]e.:dMguT^hB([9jY6U*!O8duegJ0p,7Ok.4ktZ4V=LeGg\3Jj:m4&&?q*$OqT2m2`B%XRgN5%:lhl8XeS"9ooN,@0D-\G5kKNG]TO:D1e,mJT"MaH^nFbg\SG,`0[rq1++7.B@h8J(G!A;an$W=ZUh-*'[`#QKDG0=[&<XT~>endstream
|
||||||
|
endobj
|
||||||
|
15 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1751
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gb"/'94Q^7%)2%/i95=t6W0.:mFJC4gTB^Mn^^>cN'uEXp$a4QC&@3$l9WO8&uAmC;rbfZ-j';HHj%5=T_Ms_GFSd5]S)JI#)pH?"\]I.bLc7LdeVW@4Q)q&JU!?(&I/qojp.oo;h,sO+Q<t88OF[h!CAOcAL)i%>SsaX.LiGV%Kd=J1mA&tA:>YR,C,=QSE&%Lpd#H3b4k\,JJXHA7u&e1?W;b9=DsGSl3TeF+8W4c@I`LI?a&C!\^ko9.E`/!CapHD)S"]fKP.LDB6BcrNDAEB^<p)obB;2pJ`RUtT:3/7q?<32'I^Aes0]"\"+HTKUf(7b41.fk"am'04h>d_(%<8[81!dg)IbZIoXX"UDkn`^&O>c'T6.Pc/9?&,-l$bXL3U<L6!+unl%hRJM&e[42bYu=<8!rNk=%R:h&bnE=9-6(Mu\Y1b[L:4NA%827-uJ/6Uqh.5$3o[YVfp"H0f@;Q<*.s7K;Gud&5uD5\/3&8^nS'>Vb^J6bT)`AK*KbM$ma_Rh)\9rB[JK,5bQXi5B7?;Kkq:LU,VXd537OjD(`RNYNVrBe`,7+JP/7Ag9Y:]2*VBQW^9C]sQP-#2A-22c/pa&XS>tD[-ugll,*o(CU/`'n2]hUjZBN4S`\%c/!V45]@6X'P.u<`GKIq*E?=$@NHZ)F%5SR0^M\h*QoEGW=^,*Cu2rB":_7REgRM%G0K!KP2Q_t0MGc)<Y($N/F"+U#]h_2%&IcqW0O&GQ_C&ldErOp0/DN,DssKp#>lEBH5?Z.&oknnHSt^\;ec[YBjjAN;jJ0"Ztc`omH3Y5iRU&-;GCcfJid]QcPP'l>t9hniA;=.].1-T<s5*F<FHNX$.!b-D9C]5CpD+6&&\S\D-mfkZAWd.B*NX'[Pq<-D\g"/+MMb*,POM=ZqoGo9#p3X,pUcn2du6'Q>WDH5-DKl!T*%p@6=-8#O)D&BsFcnb8UjH3\f%"`#@ntd?glE(G(m#DrM<,#_2?IoLFe8n'E.p1&&ItbF^"toE/PEi<At.K;neg.+Cu&f"/^;<>kNO0_>D7I1tdhO)U]b<Vu2YWip=m*SQJ.5`WBZUVR,P)qDH<=Z#tbEs1J#I>Q[u=u=>(&!jU8TP$u3'7b"&YYdiPX!V+^h,%6;'TjS.R(!t9nYk^r,#$*@OPd+Z\#US9FA18YOou%NWT1#&1,mU+l#(TCJpV4TM0Y[C,JqKeNeZnI,Po/5UAR5n7*jU7!k,*-4>`c0JL5J$6Q%I=*G/'!e/[AcXlj_5:Og'%g,Y\[22=T^=GXC,>^NFuQrP-sYL"f\XBtn19g_>B)k'>\O?^C9_=H&MhgM;2!@&3LI67+S]'&SI"oY-&R!D`t1eY$\)kA;hOi)o(H2o#R:9ZBG[P5,PI$^\S&k`_gHD=IuLUiaYl>>?BJh5)ee*+q3XfU:5_i:hgi/R-jXBhC*P>csgGu9MpeR\GG9`U?a?r"=u=2VUA';ukX?LROnG8\heHLA5cb.JDd&K<WPV6K.HFm*AUJ549"r^Xj"_qp`&PNHG=RY&.#X7S2+!GXM,^%BK6+@Fde4m3@fD0TPj-2!3/SYG-e4OsqEm3WT%<0le6;nMBk<VW@RcBusO5$M<-SL%uYg*";46/9HBbOhgDCW6e/qc@$[]%#E3VM;Un`\qXn6Cl%Jl.$.:hVp/3NCG;R#u;:il!^i>C/(1K*doJXPIuC_^FQB-;K<;S1_6GPgAeiXbhMX-$]"LrCX[5d-8tI__0Op:K(BLp>aIM~>endstream
|
||||||
|
endobj
|
||||||
|
16 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1729
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gb"/'968iG&AIa;m,V%lD'6IsK"c>s1i_<m,gKNZ--h&g@>Qm6-m\1:rUjHX,"O/+ChG*;Toh/U\H)=(I/%kN"r+hRqbKk8B60HRAAC1Kc[eY3@K%0Ob_(rWiJL,\"<oZ;0aA=!pORW&<"LOR@NI>P1a4uD+>kBI`u6ptM]rp&D;b=`^jnh17Tol@/6#f$0jYF13LZ6Z<%?`G^\1GbpL9lJhP$G;&!^Q6[LUGq'p;B/7NouKfR*5`mj!'g(T'cjee[aV>FT`f_C=X[*#q+)BUZSJ9a6*7CK&kcBr^k]bV*B'`7^UCQX#_Fii!=bY>#*=nDCCS3q8Z"P=8e(+==,FiNs*+'OU_U;,)_:&MD+*k<';82d/`u'pJ_08Up&;7DL-7WRMS!qV0mu_BQssP&TWK#%!$C9Jbg1Gu9P!iXib?_>6@PJO,BlK>W*L0Pk<1,P?qm[upr;oV0,+n)Sf!%q?5t)D$LN<pn_Grp6J6:PW:GoGSm:<F_84c+!b.HA)iO[qaB7+fq<umH[0TlL`,MJ#Qdq'!`@J]:o878?/SabtO1Q&B_Ys$OSA\*XZce6N>dC3R3gEd-Y#jmono'hGFH"AZE*n\_"2[h*PGab55Vn@@j!?/YP&k.;p,'R-O>6re=K5qo/G<fg1j"$l6=[^\1Lk+Gr9HGX!'W+JYm5">;8,WMpgrMEGf*67%Vg&j>kY""t#o0T8lcW>]<9:lZV7P_\e?PP;jc:t>@!:`=%2Br7X\3neU>eRK#0oQ<<GN+T`9&Z>cjDT1g63/pMR)+V%A&dciR(kFCV]Pg$<$oB;JF7TE1>HVdr6j6_2i7\s72(^*+(DjY@$WAl@;qPK2j5b>UlAQiZ%LujYR@fQr,;?U8K$qFI2*1Br_^AAf+rf\K10p:nQZ-A^l\/\)10gB0_io^_3&j*RKfQ3;nm9Ab@S!,l'Hb\2M^2Kfc0ojo'.Q-b+1t<S)[p0]NPJ,$$Fm7&"]"RrI5C&*DG55>UmL01N=gmW-3X:2\p$d&niKeEZ`Ca[-JZl67Ga_o#:qtSP`D(lrNhi2ZfRF,C>H0Q#0ra.":cGaOUoU1b3V:4>\ZRAR&V6(k#.;.L*<%L\Q"5:'erMH10Sl?4W#H)bl*/AF"a5^1-4.C0putLlna"]aV"0^3:b/q3[]G/T<sWE8schH\Ml;uebppTa'j++9^S&iX4;$?Zprd3+8FH"$!%.pn4STE"3]R;/hpG7#4(-'gkBPn)5.Y%J(!+IBeK>/1cOl(rrM5\U^2+?iucSe@\WqAdhl_6XT*qla[2qd-A39D!q3*16_1A#F2E%F<iZku.p'/bh_k@!F$KUFDoaDV?5W:P,R;0B><Ef4.7UC#ln-t8[6L,q2GK(*D;'D(.G`-)HWVMh[4M^ec^,ul]KO/kVf/R^Nmb(UQlr$>\:;m[N5mta%GC>RP.<$0nu\.uU?GW*EP$u72tt8AK/3*kBl1J8VOJ4"Ja5rkmdG:@lfmG6XWm!$mQqTE<eUD8Z;XZ_AV)oKg,`Rl9PlOI<He'+`KbdC!i=_!5I):YVn7k/[.U(_&)Ddd[8g]E"/`5<h0^fI*QI^<i@I3+2(kC\]&aAR@ClBRgq2<56EZF#igBa>n2jA6l8pBgkBJDr>PJq6=3\%soAVrZSn"AT6Lc.ikPob0HPX+t8X9C&^tTee-LI/rBaKjG:"&IIq[:I,ldnRdmXKt1au[%7jF99]oQngJUe6sq2LknGJ#`<@$3~>endstream
|
||||||
|
endobj
|
||||||
|
17 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1412
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gat=*gN)%,&:N/3lsqG!Ei+Qtn-2'&DX0:(A8F2*m2*H$'L^=Q!=#@$\6n+s8DS)RmaRCGP/<eR]@]7S$3@l>s3*!Dha_YZR0$qRRK8C="JbF)0cKs0&=0OWMLgFC#VuZ1$f)oW@\=l>8<U6:!Y82Gdg.-m$0N02L3@9';m6mH*sNEMRKP(#J8cDS4F(K[P(YQ3*K`<QZBt8J5OR`H,jEu*c0gR!\:XE?X\lul">ik`(f`9&]"\%K?VDW4Hu=mp^KW5[Gme-%;E4]&HJUJie&j-;.A*CkFX;0W!i#u;I;lp/n0>qE)PP[krcd#q"8k"Ke;?-SN@7CN+PMGD$e)](8m'CsAI7=8&E.dPch\E>!#"Jkln^!6VhY"q)r=/cSrBq8#(r:8W3)I9M:Xg7[V;gA(B7GSg=bG[oo>Z=o@7Hbf4n$spT5U,X+CmhI]oiIk\XiGr"%j>GnW0n)q>n;dG?R$E7scKI#[/]#/1=F?fPAFSH)C_L(A5#L<=7\IF9Yh/8"4uf<mA9gq)-A*r*,nY8"8e:?0^=//ieZH[Z'."5:+)@(+F->8mGEMr%^j'pQ:DKi7E>BLI8\V8s1S(j]b]2uE0)h;l46<Ap+Uo/S@Ue[s5qF5,Ha6e[X&'"dt1K4r*F!2!Q@Ahn:uXIl-rll_L"e_h?50<<gZ(8S@X^;6JO]..A"T:0pX/^<P(b-IDDB?GjPKdc$#0$6]RNt.<1e77=segND]APku+\pQVJYi=$!\TAK8$R]oe7P.H"`k,@5':>.7A8kp8'8TQtFXa/AVD>$>6fSc=1[*)$]g_)sQ<)Kmo(Um9C;@G;-(`AU-#N8>&:q'dUO1KJP\td#3YaT"+s0\CNg&[$]>u^D\06Q*@Z$je2-ea2s'\_Or=<s`Yt48u_X,G1]Qr'geA@*Cl&#MEjKB?\mPpE3:L^fp@O]I.8(k1h])3$;*sRC=c9`4QL9i].;j=%&_iMtAM.*qqfP704mT.0+(\k\--Dl$QU<'%Hn!sJV\68<Bn9uQedTV3ZK9CpOKABM=iJgn%2bc?J!IB`'*6rQF+kSd]KNjla6b^+IdAaSB;@G54JFHs!Nn6;FEp'8djGnA$&ic[,^DpS,0BbS%cSL>:gj];eG`T9'.Me0N)98.815:RJ%)9DofBY?PShkW?l1RaRIA,Db][FkaosrkGh3"$/l:89!Id-nCO'EP$O>DTd9DN*eJ[IQ\;X>S*>?A>2<d8Yi;NFV$/NH^+#MHj(_c>?Dm;PbJ'^d8je><TV*Z8brQ"q!Wn\P%_`RX1<<)].k%K@:>qa^+lTlh2r7OiW1:dUdT%]-'7Xn'o29ZAVYf&V"'J]XWc;j]#?">/?H_Q*1cn[5-=+Y7Y9^k7;O0*Ont=I5+U8mPZQD?4K(?K:S=!Rpc4e`iuI&K(ER,O`Gq~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 18
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000061 00000 n
|
||||||
|
0000000132 00000 n
|
||||||
|
0000000239 00000 n
|
||||||
|
0000000351 00000 n
|
||||||
|
0000000456 00000 n
|
||||||
|
0000000661 00000 n
|
||||||
|
0000000738 00000 n
|
||||||
|
0000000821 00000 n
|
||||||
|
0000001026 00000 n
|
||||||
|
0000001231 00000 n
|
||||||
|
0000001437 00000 n
|
||||||
|
0000001507 00000 n
|
||||||
|
0000001802 00000 n
|
||||||
|
0000001881 00000 n
|
||||||
|
0000003652 00000 n
|
||||||
|
0000005495 00000 n
|
||||||
|
0000007316 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<de44488731e8e5bd8c7e304038250f1a><de44488731e8e5bd8c7e304038250f1a>]
|
||||||
|
% ReportLab generated PDF document -- digest (opensource)
|
||||||
|
|
||||||
|
/Info 12 0 R
|
||||||
|
/Root 11 0 R
|
||||||
|
/Size 18
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
8820
|
||||||
|
%%EOF
|
||||||
619
v2-klasB/Les02-OpenCode/Les02-Lesstof.md
Normal file
619
v2-klasB/Les02-OpenCode/Les02-Lesstof.md
Normal file
@@ -0,0 +1,619 @@
|
|||||||
|
# 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. [Project setup van A tot Z](#8-project-setup-van-a-tot-z)
|
||||||
|
9. [Workflow patterns](#9-workflow-patterns)
|
||||||
|
10. [Bronnen](#10-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. 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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 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/
|
||||||
|
|
||||||
|
### 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?
|
||||||
277
v2-klasB/Les02-OpenCode/Les02-Lesstof.pdf
Normal file
277
v2-klasB/Les02-OpenCode/Les02-Lesstof.pdf
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
%PDF-1.4
|
||||||
|
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R /F3 5 0 R /F4 8 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
9 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
10 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
11 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
12 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 26 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
13 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 27 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
14 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
15 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
16 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 30 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 19 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
17 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 19 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
18 0 obj
|
||||||
|
<<
|
||||||
|
/Author (NOVI Hogeschool Utrecht) /CreationDate (D:20260518122502+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260518122502+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||||
|
/Subject (\(unspecified\)) /Title (Les 2 Lesstof) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
19 0 obj
|
||||||
|
<<
|
||||||
|
/Count 11 /Kids [ 4 0 R 6 0 R 7 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R
|
||||||
|
16 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
20 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1817
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gatm<>B?8n'Ro4HS<rZ>m7,J,K\2XIUt<h6g9bkSR@Uu%/3>+4EWF.Nrq\bZ$okC1f'>;J,GB2S`;.+l_LUX$<S(acE&N<3[gX+/d0,h4Hl.9^2^@eJ,@'fd%tFpS7DsaF_Yl_`oeHduOV*Wk-lN^5qVWknP_p/oZjT5:6EXbf_IGht8OMSA;(Rf$DV,=@3QKK1$)EM$gGepWQX3'jP9$N's.V;S_&?.P=5ah8JhV`&%$!N#qK<A;m8OnDNO8u)QFTb.9"<kCK[]PQe"TBk;NKeEIaH*[B0%Q8_rqk*03kTMJ)?S<$N4r"rs)g0#J:hKS^^t!ib=k#^j9l^j-HkG8D`DV"X@Fi#^d=JpY1mF2tQr$W&L,r_*LIKQ0qCco;*)4)bW`7G/0If1^KJTmH,Z++cE#d``Q3DC4ioMM:]@V]I$`B6T]4n$^Q#OdkH#`ei-rR(/*#dnaIt@VA'i&SR\LPWb)t5`o4.CJM'BiqUg'aW1nk.Yk+ereHTf%*;4R&@W,mmkDaZ$r\o#`/0Ft'MKQ^^_?1Ps<E9NLT:-$5D_Zug>f";:%9[u\N!*dehuZ5=OjYrK'l[0_TB81]A]G]AEkBVJ8gRT9&n7d)Ld[cD,gc.LKgFTtaCt?do/e5SCA:82:aES/juCZ7=^7gBMR:lPD&5j94\6V%(HUA<iq+%o$5!!F?#]8[lLntR0NhQ[iN:b7lm[7Z9b:h5].Pg?E"8;jkf-2jQq-&n]0Fl0mUm8CICUpIlC4pQITiMt_bgt[0+ac<7]59'Rm%9mBS8lP[V51@.%K]/j_keK:SSclS8C<B1UoKOR7T4540iM(aKM3(K!F28ai6AKl?kbqb$IVB^;&7<?"rIZ3D\PGq)Gr2ZZ/-5Y#G)Njlsb+#G%^17T,j#-.h]F^lHMOWn\i5Fph.0<XUh3$t%lMjKd3$"Z,XZ<(eB,0jO]]!/-55L\KZ3CQ0>Pb4s\(eBOeB`2%Hu&95quoj5)OV.p5j&8JnhE$;h:HL1nF7GIHi:B(4;%<Ii9!,dmk^&'^I>PC'nm:bT8EDhH?BX=SMdOO,WDW(C"aLl.H)fK+.&WILD]gEYIYY1(V5#4$6K_9=)]2@BR#"p4B%Vpr=XhYcbY/KVBW[bRE(>Fm-Y4:_'Cpe!LhM(W<S$n-heQ8*`d1m$V37H>=]uAERAK9lV##!cpY.I[5`&fE9P6V/m(3s?[b.[CGgL$=-4#pN@AdgJ.K$42B5N]uF<YUJXG`(bnC%bJlAWp;1gMm<A%'t1D@haO:,Y_1=%8:Suh5o"UcHKaD$-"0uL!:aFfd*-*9U@Hbq(+sW[oouTjESX.R%&f1i\W1.fGL/hk_Cu!S,@L>0[AJU!u7&p>'6h1.+i.PqDs)<-Qi#B&sEDEiFPGtr2N<%C=?1,[e&@Q$t?pV6PB3D[$CI(BC1;AD]NWD-<n0b?4D-2BBRs-?&Z7-ALe7NCL,0#V2t7KikOUNCL(R`CQ:Sq?7gJsp60U"'Mbnh<!U$H>[jgF^"mF6$U2Bk[q:.=jZu`6+XlH$-q@XjiM#JC/Vd2m]8HUlU>1UO56sG-"J<FN^.tCt>%r9h-Y\la5:ds3ILood&7BlM@/[D85-l1Za]^g16m/L!2V$qnUV^TsM2Y!i6'):<OKLoeqHGhh'uk^_3a.mJ$>lR8^U:)F2pY;@`kuJL)urk'L[_&'7g7o*kZ']P*Ca;N!O2:IQIgHSe[1:!47)QEQeZT7a&hnc5Z@h.mOKs$]lb^B6C3Tj4N&,-6>9*fB*YBQBM1/^e=P+Jrl$QGFp[aWcR=(IMd(sNj)b9grNMgR2TrP#ZbZGSrgWN;~>endstream
|
||||||
|
endobj
|
||||||
|
21 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1814
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gb!;d>>s99'Roe[3;^(i9nXhMj?>.'D932bg*,k/m-l2=`JDT5C-,k5^OD71fJ-*nd+Mh387Gf3Nm@ImSXV)'peRC:X8r$:$A\(!:^5B/d#`o74bIrWn!cgLb`XX]&o^'+)3?[oIo,:!JLDjbb#/T%:C'`_#WX3$V]6Q!9+m[Y.:N50UHk!p:O!.udjXAKcMW42N8`2.M;gMnEW/ElmaOm$][75>Cd0<VT:d-uHDs2$Hl=:C9FEiTGlDgeV`'lAG&=@906J_MlP_An9AjJ=5,p)4eT(jAE\4\)(=L^9@!Vq(f5@^Ar%O($RY8dgq.Hu7#5DEQG2>ji,][H!Y^r1f#\bY6AfElHT9CDe'ASHMnb*%&Ka2$+`_^n2,40)/VEL4Vh[fNjN:G.k+e_KOL*KRi9]l"XGX=Ee:/jHBicAf:^$L9Xch%Qd!uWT@SSO;G?+R`6pO`<lQ-Aj/>%kS4Q/#($bnsQSH.Q@i.JM`fr8DumSVFa2i>ZqKG)Z9NEQS?U-o^&rDg%'Lp4^j/jr]Wdq/IWD-#?Y3a@J]tV!T2uk=]NLm7`*e^jHptN!=87pG?iL#OU\,\aeEFDqrl]h:3r2=KMWR%9U7a=*@SU''TjnSLKb`-R\?g`'3UbrrtZcqK-i`<@u@N^^"!JZ)D)CD$_!p;psoWn>Wd123[-(jMk6.64[f;IOe']:rjR1l:7$M*1?Z7ZqH[Di.JGJQ?XtJ[h3;c&6_DO)JY8sXd+EXX[OC&J<ttS-+O-)IY]3I(l6&B#^qtL0"&8n>R=7O+=<;q)MG9OGZ@dX2#?UE(+[>M!BC5"UO7El;LOph3#a:-2n(m*oI@(/U3?,g9'GWOfB;mr`U91;8X&4A-.2T6MS@ZF[4AHrZP>Pe[:L)[/8Ebg>'/+h+Eq'p9/As5[*9@rAaWQQ6bo>?ibkkG>25<i+]mRi1"n%Or*!(@*b!t^LoC1hQU\.=XAh.M#;BQbo3p"JogB3@Z;N:?n[_]0Z&Qrna'gF?\]bTl(G`q/[Y:ZF2'Y)P*$1`2@&[4p!NV!kGXa65$&[uLPY`*(+jJa^&5HcDW9k3M&&(^i?b&-SrA)3i>*]>(IXV$,8$1,3KsiB:LS=+OI'aEG2Z5MTn"A.qB^'VC$SrG?#A_%HBNVr<Y?cR.nCL%p8*%KiK#%$uDA49V^DOdo$KK'A21dVq<rW^jZ+!2,0l+(G93@RX,SB<\[^kpaPRu54A^11"Sr%sa$>[G0>[,DZ\7(GSpEBFQG`N%!Za%2Jl\T_5Y:rOXA\8uWZndQ>Fo*\G,m+>U")hRb2$Q_/dSf2Yof1DM>AW:b<\+!-n%XDFGG=5@,cARIB*XMbbo?iq,&:2\UstKm<gpqSg0%>h/[S]?7HWlo_c#?!W-m:/nb?;;YS9Rl*Af><U"j14dMC$;!oqES/>bga\!;8r#nboQ9PbGC=;kG$>qui$_j.N`Kg_S+J[I+ZTQ9Y/6,[0t>iXCEh2G*0rUrK%IK@Q1@WHa*=1>]]?-:o/-oC;+>%rXehGji%_k9M2`ZY6[1?21%oBtm0N(n$5!(<cHD'"DuZ/(P>3=iBAASiAgG[ZcB01,Lim=j>>'=U@-gQIs!Tq;``GkXnooj_Dq;Ep%P,H;\Mj_10Wcq\hkH"a6E2j-09P?nG>$0Qrqr`5E$?-BY>Hu"ALe[:n(>I-KKgS+q72B1WDld/Rn1<Qi[8%[QGT;I/tb5rB:o=d$u$h]8j25[#EDe;$Zh9cPnk5MIZ%Ogf?q8mcthbqeJ$)GCX(E:E`m:Bmf!qW5d^$:A2'esmd<mKD]H#[gbJuYf[X%h^RA(^t@Ig>D0OT~>endstream
|
||||||
|
endobj
|
||||||
|
22 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1690
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
GauHK>BcPr&:WeDbfcTAp=+sF,UAt)HeE;ce'lL[:%oea(s<Bu"q'!sqs/HZ!+X'&[L\?<DP$[d)pL&m@R0J$RU`u2GW(?KQOF^dq$NK3!p4FZn%&23,<XmV80GXDI`R(n^AW\)m:@CB&qiAXTW',=#nWO;X[<O;oornm8cu-7*Wr,<WjDc#R1+1V:Z!N#k@e$1)$Jp'I`kMkH6ESuG"C)1&I]sflVrr1$UU7\'':,mHi*6r!aau(;oL\@T#/OZ2"=9Lf:4@9H80bM<Cp2[-+konPNKj(AG%17Itmc/CMSGR6pO'be04f1;ZR+c<cu,sW:-L(P"":>?p<M3FuTM@Gq,hNmo+q6G]:>Z+4isY+qOck4>)K&m%:*q=+jJF#LBntV$(3Vi56qJPDR!P).##AR"afIKd[a0kcoQuA9n=5K,=o<f;Zg[=18-kp-?!o&pn`H,/p%CA?4Lt1%7=!DS.<mm)MQor2!,Y-?fQdg[#bFN)@GLj$#08osN:D`:tH-KXkYX4qI.8#!XC25/,rCZ4PLY!.Y"<!d5=@;fu=-`CLX6aXWF!QNRu**U;UYr`u"5dD';\RPZdN4s`Q_qu3:E8*<W?LhUBpIfVP<-@s]=Y9n5-8N.0!q85C=&Z/9U:W+(@;$BZfT2pZ&8*U/NP&SG8_O(>$-+Q@aOSQTNr>_MjBLe(Kp]*8;[hZuKn[@5@.=/,oASmU[Pce%UBo3(1QUGe.^+JoS>Y\.7;6J@2p9m?A-.US6oX$)Ok+QiT=fj@`]>WK!EG[SiVbrUCD8+S_A8.3dppatgl<ROZWIZ@!S6:39*$n*\+b,p4Pus:H?"L;jHEGI-Y1m<id]?,VZIi,Tlis<eqiHBt$21)^'TKEIbf("f97lenW3d-U=m;MbX#8dN^VW!!W)]TY;f8fmV,Jq#-M+<j.Tr4Z3('[8puO"_F^q-l0&qbESmSPi3gu_ib.TYWEQ8:BZLLk"hDP`[D<lRM("(i:#[>8>$EY:GJEsP2-sLS`3a(KX7Z6S&A#roJ?H-PSf[8[gfr\.GX9hY\O&9q,cV.col%,r'0!FgF1U]0C\W:T\j6Ykd;jbSE!rr8[&IEZ0T@iMrUV0C\&t@C+e'j2]ZQ;UcCfDbcKU0<eQ\j#A.8soG[jf5=%AC5[SUHC$%*KRER1ulqrcujZ:\IXO_h%L@13up[p\Gd?-<op>@F5ac"2`Y`WDSg<$V?)::N,P_TS(q8ijds]jgo`HApK\kK?@Si03oL`h)]UGG\p+Ys5>_Fq(c*6P0r4RhreullR+iEIW>Ab"VaO:Csa>E\E_qS,hqE8^6T!-pt0@WJ"P>`Xe56sWRn1!)tCCn.bb0d1KGSJ=daS?4QQ$NFSM4#mAkDm@tU@iX3o^?b'M[T>^_B5PeduTdk,IHmSQ*LA,G)U<.dO-a24qFKFof?-0*:TL,_m7]15:A/<;9"jcO"l'FOT-dap_p2SB#s^m,K"DfDbE%dlZb_I=$"q&UQ[A(8Irg*5N&m8U#QMX_t^BA*^&,Ah\FE!)^R6g">UZK45VYl'969+g/1gieC#JsO<Z)fOMVr55?E6d&6DSZ/C"2hc[m+2HRAm(:+0F,S(ESsL9o]X$!'(,V4cbIgrC&IqE]DM[=PZCr?c9flDi\BIW]BAM;$iJdKKNN.7%";V1Tar0QcWYq\m/K2%gnF?ED7T'Z-rrLYKr6>~>endstream
|
||||||
|
endobj
|
||||||
|
23 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1726
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gatm;bBDVu&Dcq.As6^`[:'%<5qneXDA"<[3I+b%]#Y)M+Ghuu$45C&^V0g>+\J&poX'oX'&[0[%WLSS"r';G?df)7C'#3T(bcG`3A<`%9]!Y08an;S>k1ub5XIoWKEFe4pBU@8-m=aA-9P_0BM;AV5U]*d8ec5L(WS(]g;*W#^js@d`_$5./<WUh=s"C!3LU^/Ott]rhr.KD?:&1X%UleQ</)$eF)'&?$:7l07kcCMo\KDjDr>cG0MT-[WZ6Js[7Q]#^2b:4jdYkbVTB`lB(3[mS%Mo>VR/S(j;'(<SZS$'+XBWg&T?ubCDu,]f>^k_<pL"(a@ZnNUuin>Bs1%t%VJHM#t#Wk;1*T&K+RcGKgH+Q7DL.r4q;XZ^gf^1:np%R3[m?s/GXN;l=JCOR)90+(iu^3W<D=G#R9*.CLm\MrBuMCqr^(Lpm,c'dQnHcXJ>mQTZD+,JF"$^DN$\RK4WsijZ`(R?bCF/n_BBtFmKs9(o)a7`^=.42cPq1-Ph`fKs5`iGOHdTdd'[7J#m!r'!VRR];>NpY02a(FdC?+IPH>Tnd;r*1L+I%AreZ5.QT9CgC\C@Lh5PhNqU?YKSKU&%<s-p<&:jlID:3@AKPXM^BY1Y%;li72u%i5b$WO)/<-'%YRe`uZV;AR'0V&L!,LL9CDrD+P5G;&Y"!rM5VTt-X_mO>a"kNeD8G0+#4O'P%;$G?40Qg)0*2e\%*^RmEs@QVXRMZ[dkc5&e%)aJP/+I[-(%hI)gph?S#+5JS?FVhgfIJbdopB1-@m)EVK_D!hUHbH/@0Be,L/&jaB<N4f:?F.EHYsVHC\7AQ[*Ja3e'H]P/'f'XKu+nXqXs/TdQ^\cUFPN=Te!6*l^A(gF*[ZgeXdOdiV[T78'"`;-fcq>h6qq"c-9hV1M$o"3g%-kQ^&['$AHQJoifajI;3"$!%kI;%iDYG'm&)/`-%n,<jP)$$D\7]LDUaFoq&rHCQE8iQG.JK.!Od4n=:P1f4r[:r9K;-$X?l[P)OJj6/4hj.NMce8JQ`=GGJe6cg@SQ>j0W#TrMsJ@-X^<&fsQVQmA*F_\7)6OU0B*I#(>^0LL*e%*_@B7Nc.N1tA`/-9at[M[lP&L05m"ieAG2fl0,8S"<OQ9!0KR8%gM8$F*["7_XL!?DTRSNFRV8FGuUHNR2:m)L[TGUSFn0)rC#HF'37C\6%5a.kn=Z'@Dcdm$]#7LVNE@VD+>g?(e4^/'D-Y)Pb4G4+01ToSF"ik$C_g"U-%BWi\)D/Ep^Fg8\[8f0jl_ml'2U(=V14QOGiH\5^/)H2]MGG?KF$nLo=ESB%",LAL9:ONt.9r^C/[9IqI7I(j1lU'Tlk9kdilVhY4T:bIOJc/9p@RNtZ>3AC0G1'I"_5`BImTM@e_:Pf8dAHiM38s_N?oDt=d*"fGOqq>e<pKig#&LF*[AbtKV@EH/RCd2k_d'N1L9Fm.ni=V3Wa.X%[%V?sF,@%++lhC"JbC&^hdRi]`C#S4NkZr.s3!`;N5;FXJ4/nRa%WaHGO1Lmc/D>>(cJ'm.Mo@:"[Wq7!rk-Cq#7J#XOZiQ+I$BjLRS=QY8MR`\e@l+g-4g9DV3.kiULTgN?X=+,5e`@O*X&EJYC2$;I*J9F_,PmSREKTa0jV5oF14?4i9"?mDXB/e&W(7]tAgiDK8+%4mDmLs&c9kHiNP<d2/'fEJX7%!&6Ii]-:on3A^IOPaPZ=?tHEWZ)6uAJ`%X4Z'"D~>endstream
|
||||||
|
endobj
|
||||||
|
24 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2485
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gau`T>BAQ-&q8H9fGRJ_:*RLS#_JjbEi*a6>WQTYA*Gg'IXt']U.pb$8QenOm;MFp]ZQA5SE\6XQ6h,*G-T]up-o6#5Ks+].tF7)E;#"ej"Qr)'1BY&"'j,@^Q/Yeg_2:Oa/;\JJHV#/K46Q-_3ICm4CI)GO8,:HiA9KjJI`ab4HFbaBUD"+0d*'`ShGWhba#p?L>F):F50q1=3BGUI3YA&`!_B;UdHm&Iq49a=ECF$X!7m]Y33Z<"fEG,rUq;hAIDdub:H<E5?4DpAHb#_HZ8M(E`&-B=m62ulN`tkq+@R81RR"7m((eb^g@@=!`+'Qr'0BX38e^XAb2AVQ!2,*!dDHBhl+thO5u:j*qbBM:_-9?:u<K&p#8&"$43aFG=asak)p>N#c5B[b]1C#,ma)f+3qC`RW-d$iIL`_)-5QmJEm7Q3o1@If5q)$'-R_8Nft'mVlYA=4%?U3,ok<=M?IiY+WKG/(k\$-UZKQ`b'[sIT=lu+Z.P>[DpU5C(o)c]N'"h:YN*7/[?qf`Ks4b*O08ZbdddnSs-CFX`+8tdG)-+:gWPYa.9T(s)O@sdCd*otpr7<E6mK&T3k<dPV:+QE7&21lL`!%CqL9=VppE1f=/NAU)dru7`$MKaE?Ab]']Khp1uq)KVo*7IA6B(5XPm*\doT\J6*72(V5b@Q`iR_4]nS46/,c;r7&d+/nB%7ll_KgGFIj4<6f@N.SsW"_4QljmWUI7N&c"n!Lf3/p=6lU)MB>J6TcFm67$hFS(&O7>r1PkUR]b8%W)_:i`T#s#[a?"V/AuVpo#\#GOQ(S.`sr?+,6a/&!HGtF(CM2?RO,i.[tFl27cI8d>oOt?%e=H;>9dMd>g`5@7Hg"op4kV&0aDZa[gPF$1tB/S/>dT%],QC\l-3$JL'Ka)@!H52L>YZ?/NVkQ'X:U#4<)0>j)\);R1UjYH+'?31]eh]^Wm*OFri<^15'e+Yl8MhC'JU?lrL(g*jVjIPpDp<k]B(.OR`d.mgtJmcQ.ZAa)'qk]]UM1i;2hs\?K\,^?R;+G6pqpi:`o$Q+2oKh`u)Z!lsO@r)7gLr)2c'D.6G#Qan_FD```&6;A[E4KN&3+H0bl`7&q^g-KNj6hD!ta33"(G[@/"FtOX=T,PRqWmd4Y<)@Kmj0rg@;)dZI:19*%bGq-)$0Cpe/TWja(3L731WZT20o=-GrP<!t1SanT-C=Q,)/([=6f4N5+7@Bb:?,#i?RcFS^_o(+76H@s3n'V7Zr5jGfDrK)eh%oO@.HEQpQHm_/$!M"Vi)p.U8;_16W/o;40H$([/9A:g^YD2;OH++_7HFQ'+\];Y@dQP$P0LoY<Sn'X]73W9OVRtD6?L`e3OI.SEL3C<o9$B"S7@'rZbM@%3rkEVT,Qp*G&>`8MX.WCiX8,7ZP[1:iD_@f`0j438u!sUGqfq/h%CV%6D8@PZTU(,j8j!?Ze;u?Ze03B1Dd3rl9K,*D'FnT>4HjI]gH'YrM0sWGMhL\K<1/X#l'"'DT5q6FFb+X>Kp'A-7_3Tn*C%l+;2FSEMeE@"n5UZ)r+Wr"tXZ`FcGR79#klq0W3Wr1MU:jr$2'*toH1&P[E%RpK@9$Z'HR'^hdu/(cm_+kNT&b4A#^1%5lsN`Y86([oC7[_OBD%K-&.(L`#L_/-)JoJ(a7_JGL*WA2'*&f'`['jRWg6(ngYk]DKc'\6V$X.QpB60!f&s3p"CB*.V_ZW\popk[HR\LUB9J83AN\B`Zm1<2*'k'@r?1+F9IMq]dQek_PY*HUS#!`+].q+ScL-;L=;djZbLH=5"U&E^^*mq[8XPO[W<?]8LEUW9`-?,EDlC#ba=mW[`R^d12#brC9`)GBrdKj%odr=poOV.5Ip$@@Xc2jPE#`M_s/NYkJ1=#>'W"P0D--bh[\cSKhA0DOSR1&QT)a!0s,'IE5rc<D-_=Vb(ni,V$=%B"Q]OT?$qla(2m>+=V3%F8H[Wgm%.GcqLLU<*$UV?+8/o5g;"Ust0&],i[3?iuc=7a=;:'Zuam<)5Mlm_UNea)8d7mP%Rur6k-5_cGQp"A[l4<lXY"^Sh2P$SJncToAXuE>C"Wm2-07e\D<b2@duhGd0LCU594_0!4qI"jo5./(7!H%:iX*;(Qg;Q5>pYLB+c>pkN(5E<%J2CYNG0aC,_EjolAq@4@1E`F^$GQ*`eSkrQP\Zhq4/NpL[i#R@>i)5?QEe?GZ[,%](@a!&mj-##?uOL?FaE!f<.LlZ8VT`1cgc4H<2q)P7G+&(I=Hkm@A^o%6m;I.LS,j7%riB7a%Ji@hqpUCNVeFN9Y`PMajXY+fIQQ!&MNF`J7Af*Ydf#$ZeD3EHQlTS7cT_jD]3fL=2Z5,;aLmgb6hHB(9dUDFh`<r+&10(laj?P:.&-t<s@)Usd]"#B(l`]$TX>')PC/6cA'2/Y.%72Rs-""2X.]'.d=N5QPT6*ssQ?TMVFM+jH*9&G+("XEea2``<h&OJ455VcJX;`o3r=-(@%0u~>endstream
|
||||||
|
endobj
|
||||||
|
25 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1620
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gau`T95iQS&AIa;%#goWK4q[]?2Bj0:"ge.h+#X<(Rh(03M\'eXFm6<IsYgpjH>fTYtb:#OsP**o?I.u1SFMRr]Mh5?7o[VRK;HQ]E0F:K]QG5IMps2KPPJ$![9010aA=!pOI!!D*_m1@idG1e.?C@8BZgsYm$/8`\7Kp#$9+p#/k1iX9<"#dT/Tj(IW>)U*WZ?a8>e*Ib(J7'A[AXC:5bu6OMB^'i9T0PUWA8=hsBj?f1kh5EtK8:9VhrLHh4W9<T<0^q#"45L*WcoqlW4'th]WZFns-fs^\dQ8c$qk%'J@V:6bKdbMlmS(5:Ths7/PC/HXIok'\D*l7c/0(!X8n+8Hd&g=3i:n70%,g\2F81c\5&Qbe,)U@o0)a^O2UGHdL.S6#TI!hZ7RPY@apk;kj*)nnTOY0ZGYQ\fVJcbm:M@0(7o8)A/D"s+s+<%&O&KS7"nKKC70aBL(QD`,QjAX2agW2$S]@?A]X,65L@h^Xe$+Gj$@#->7Z9D`4'GnVi2t)6Vn?p;t$%Iaa3Dh?I[(V6%m]p\5Xtk#rQeODCdW0]B=i7_QbGo$()4/lPae:9qa`0D9-OXK;SH^=JGc/dBQ>+e6b8a.aV5#I]90Lf.-l>,^rg_/.o3HkdM6r%/8F1X'>-[hT0l_IO[gro?(*3_hVRZ>^\4BYU9:8`FF^4I.n6Lo;)j+#of?7V7*uBY!E!Tuo0C0?]4/Rq;JmDC5AEf5BURbp@r+A=L'FI_Z-*@DsPF%V-P)j9^!rR_$2jdt'Ee0A8fW9dFgD490^V>V]JkpeGM]jd!Q,>\U7gJWe`I_3pXimNX"Bkt\Y>+MQ#rZe5/'I35bOX324:f<*7I?<S^@a7=7>s-[cSjO+lbugK]Ii[uP/_U`pLeasYtgF$3!p_TKM$"!-aopEUOgQ!_mGRJW]uD5b`/6q/\#40;:$GU+OkAh]!&A^oJ7N'kTJ&+?p!"+#@0Fj_4'?K_$2I%g7X5tYER0ic6,Q_0Pu%3qf&_3Ud>V;3,`L3cG%-"SJB9"3LjA6c)s6;%%3`((2[(H)E<(m)OWCJDT;=i"[_8[fARn&HIpAP3A3;Fc.Qg,rmLmrT'G@aV0SDA[g-rAq45]I@D8GoS7u?\)J22q*T=$"MBlo]_96j_Db4To475#-XBKjQk*o@@cst<+]^KV[gR_3MIpqB"ZMRpHYN$,jf(IFiM/f>M>>4L=f`u-5;'g4U:^ks2Of[K?KAc)[pqnd-'kPc):M7urlc\ZU@1&o.B?D@_;5PVnk.3$dRrjeTae,VMNodpud&p;Z4eYk_ACS1?D\m\j'ZjSk0fS`FI[=%l/n0,"5j$HK.Pr)EjO[,JMo3a$6+NNGqWVnBrq?H8n-4P=ai4FGiB;lo8q[5e0NanpBFmqoJ.*6&5_]q5JC-[6'+[W'(%HqP5>4W'X14%hm,qK#97[cG*%#pXImV7pqZM;:>pf7;1`u,s;W<EJplP*8S"3.LEGFnk6_$\*k$;mDB_h84r%s*]?6;4YWbD3JXSk"2XnO^\JBs;1'.0Y"[0pqtGL[GYUN_8jeL#q(rKErcRm>lVB&8UGe,T52ZMNT<On7hT7DdkD^b0>iXP1+`2RqOn%mmNQ>[^R3a^/2&k[-:j#h/~>endstream
|
||||||
|
endobj
|
||||||
|
26 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2009
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
GauHK=c_;q&:W67(na.S,W./O'M0m6(296pS#2[u8RE5]'U_/9ZKOib2Z\g8p'u4lII;Zh]p;%qLNCd#'O:R_i\t$@r%`rA$OW-7E"%sE%`?ofI->rt#STmP+,Hh"047$Hci-3kE>%aE&HN7f-s%$-3H.ED;Lnn(qkU##;@VY6%L"&1.hr;`W%XCfg@#Wi(`pqY019c#IjL_miWV_Ld\3&i(RZEMXd!S1HCVLpQTbfod(=Poko=#uM9_ip0en(";]SSR\7A:MZh+1&/=U4]*l2c@X^e\BkTkWd_^cQfZ"J4SF"U!+\_Q9G>%bVNJ$[ph9<N3NaXd`aG1aGpPLb*aX5oMJ,+dsiFN$Om4!**EH!G:h$]"PR]PZ5/LIpL:>]nVbWi.nN;R#SH?dhD<Z\CD<;/05k9**HE4uBo8>1,5/e-ciq=Pq./`OE4&kr+LUk*3r,>:F$/BS<HF2emFkO.<1JKTuG"SfbVLTi8n4+KC<ZNlS(kR%he,ML7SKX28A@itk$T1Z,igpks`R5hIuEcA56u%,26jDrVT/5D/F@/9MSnOmZSGFH1@=O%"^-ga45ZFAG4:=l-MVcm!%,.i&IlIa^l:0!)qnMK9-h$aSW:'UcL,P&Jm/H@HGXH]_G^<llom#)dH'diZAm3J<bD3X$1F"eBJpOY+IA?ToeU]'S!;W/`ck:#.;a=[`_OBj$_&b.YR,*(EE\0\-!FH]N&:J7.3.h;WSEdoq%>RVGpm`rbC(ddGH%D7?m<Y,&b,;XP841W-,X#L-EKrQKH\\IPLOUK!#ZhKGm#6&RFekE*p[l<;*g1eaVm4GA)sIr+,,:A9X%G5*0(E'Gk3FKG4>_8c1"LM.SQfDs7u;67ZG[G2D[h;0!GpW1FjC3.EB$M0ZLWtWs_`VapFm(7M(9uBp@l9lT@g'roK]cYG@1,W,o.bdnjVt.,b;0mNn_8/P4'tZi-[QZ?;E)D.4k=LtpEGX0ZodmHrjL>1p.DgL1G!bJ'9h"-i>g(JE3[$g!_TJ=ZE4D,Yl=eaXLF^toCmQ&R,)FEJfj.H4:#n-H19c;Ioa=eX*F:miq+rkK?:E@7d&\@jp;&XSWDr&ggG3j)ZYVj*XU]5!CULq-VS1g=%m:1*?b!`%@6al`)$0e0I-u9ekZ6TWF.Fl!GW%Q4b5JF6T2'O7)[=ht\5.c*bE`sHdMVi@m)*V+k4pbo)[pQ++X=ZA+O`WqP[m_f#I<T&`h#\ra&p0'58?OI>-(gT;)Q,DkdAg%A$X]f]@SMQN^dC[DXn;6rGcQfNAdc-+A,>BO]nksSX`?^M.g*_S#W\KLZi@+I':q&Bb#'c*;k]U!"_lU-9NH>&=.Eu^/m4BdOF2<=cDQ(S*+AilO8Lic]:"mO)O<5@%)$X&8b>=)/k7b.^CX_A@kB'@##(glGg6c`77`!N#s=E6/X(tkSR(Q$r_i,ZNr)<m\lmcg5,H;dS0ge#T6X\%rb^P#V2ZoLi4K*@)#rqR2S$2!eb!F)SOpm+cWSRp/g2b;30)WF=useb"[^_!0Q@E#G`3f)M<><L?t)!@W5;0MXEh"EJ(LHZ32I%MG03!YB^.dO'3cAF>tI48bb&77LO$`'?&KEE&=(&S-Q@Q8:M,ubJtV=2KN3`rtX[q;U!#m@5old`SdgOC#JsY%e8Mh:4bnRY4r^KL],R'.m2qreko,Wh#o]cf*(h"'Gftm@rmWP$F[iq:Q[nefFd$W.%Rs+6f:nS^RAX-.VJ\AW*<`Go)tr1N(<ihs(>P'fqUbDUP$S^Wp)Q[@o=.RSutuITBapf7gC`ZH4V=*'9(;0FK7T+2<Aio3IUT4&#,D7JmRGS^AT:Jc*uL('JB#8<8QIM8'hZErZ=t,5D\=s"NC16`HMet(6H=iepgs7Ws*r^"D#6V6!Crf:pZ`fCeIC;0Ejj)\!To4`)-F>L15@br/2:`ok1e_38J1),]NTbL8b@-EBTt)83G^!p&bXdLq_jOIIF%NOV%=<b:l%nFV-d3Dm*f`(iT&um_fR[It$K5?i~>endstream
|
||||||
|
endobj
|
||||||
|
27 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1975
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gb!;d>BA7Q'Roe[3%m@hd&<+TPBh^5"h$3`b*$XLqP)\YU;f-.VZD8F*r-R!Bj/Y5h4a)cQ>D!4IZYIDr3?):-3.t]E:f.kj"S.Njq%cp+5lP9qJ$W1ESkbefRhfX#85\O%uQd?K'O"%huNpGI3O%D*5RFBJH1_rI%U42.(F_D0d+2#IGk/<bk6XuZed#Mk=F;MY3,uClWa@A@4ra0b8mnAr$*&-_-3OY<8/R\\\8I#"@f;]r]PhIZ^E;\H'ZEg?54r[=)c9l&!N4IUb$XkW<eO7XbsGI;/(.Qdi4Z<2m`eaNoQ8;GPk25&#oaBGV,u_\j8KC1S%,L".7E5dLO=X/Y>3A`3uY+VRT^bQAp2&[c9@h,SkSqo@VC.(AA-3NYou[d=10gk'MJ8j*'=5<^2?M9JC(OqPaJ0$XDo#D:X*`1XJjLaC+`^>7BDpoh4!@d@NsDd5;^p%XKJV`P!)ja[9i]eLkE^NTH5X):tj9f-@$_Ne,.d-!W-A"%-<t\>$F!5HkN(NLI?F"+7;l%g_(3G;sSFJ8VuMJ#o:OM_'n/1=_5_1la((/fo$<:XIr=^-9=MlN>fp1^Ao:eM'$ah^WYF)X]7KM:00gpFZt7=Lah,DhA@<`;4ro<MSP#FjsC:FZ!*U$pt<+7?q/X_U*E3]IB(Mk]@$f>c&?q:mk,M*uZA$_6$C^\M*\4f*A`7S,m]<Ibe/,B8-(?XBR=hTp',-PjM?5:qTH`qg4`!Is2cVG>DujY^orp%^ZV=8bkLY@<-P^XFseXjK[*,UQ`*),7(VlTiH@u\i_s*\WW()g-I>!R?WJ'.TqGrZ[)a=oM#\W&nHu.B."QuqBc9SP.K?tN<!0FS]WusO&XeS=^5Mu7M\DW=t\iM7pEH*<oD/*5^0hDl8Z@F?r!=hi&.Y6j(f#bd8:UYPq3WK8nb&D[M[r*f=opA%=+(aqi32q;o045i0S8/RRP@E2GQj5@b9J::fttdLk"9JmTdsf^FSJR86KI0]`0`IK,</PUq1sHE5Ha7n(/6@Z*$?Y&7+!BCPkgGnkK)!RB60iWAlf82p70_N)P/*jH@<X<Y[_q.Xd%i9T?'96WD[;1dY%`ne95'nHe9dguJNncI>k!e;FYX?0t]o?N;)FMZj*-e0f>(Nn.\J5b?#2a.mFNT\Z>R=CI(G[51+d[1,TV4faOHGn%*eg2($',Pr!"JR>EDkBg/^a0*:8D_h-C3r\IYp*j)-jCCdA6l$/1RAbO)`rDfK4k?l>.kFh##tOLQ@KJ'NVO1]4]BsuMkaRip].V&Jdm'X5Z+FO2.l'esb=H:-9@t`;UIeQr15>$u@@BB5%p>8GR@-*hIoMgW_D/VfO^Ut0S)TH+W<,6B_:gg""qQpZ?WRRhTTWB]_VI)(:DiEQCrUHp!fl_,4*V)e%WJcAg1E%og"YA0kX)d#i)VfYN-sFQ4)5BnfBDuLi`]ch1l0"fh(GB*.E%^lU[8<2Q.C>;0SbSLOBR.51tn(GU#CFf3WU?XDS,:M"g'fK\/XJ$3F)@DnpqQgGFIFFnpOQnIr?"J[g8t4^$i0k`spHe[!7nNlD)2Kp*!r46'uI>1W=jCX0PV2UQE(\b<1ROP9u`]/<VaU$*$=hV)BjHVQ(T^d7<80J%r591#+1UFFp9-Nb[.AY4M,ZZh&1>MX(;mE@ohd9qcl^`[b%?%\(aW5d-d9m5"AnCGu'<c.X'/9)#46SgsI`TtY28Bc+hf55JE3D\>fn8qS`lG]Opf=:Voam;Mr.CcT#Aa+`iYhC1TS*U4/J7/'DholE$p6+RZF0_ENueO4%?e2G>nNk(SL(gi)FMY:ha_(qoB@a,p!F3uUCo=9=_o+]3!TN3YXlOYBc!GC3Rn)fEObnJGQG+.W:ZVorTg0B[G,r(]qdlBX7=MeA#>NO6Il&CR33l=Rrf\KruEe1&'\(5e<?eX>Z2.mkNCK/>qK)'\)`TnlHO0<P117M?8G9U95C^0uCrrIjK#,_~>endstream
|
||||||
|
endobj
|
||||||
|
28 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1636
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gb!#[gMYb*&:N/3%#dX&D.B"nO]7q+7@S1GU@"]3I9>Q!OVqA_DO$GmYirjj:m*7fbsi!NUh^p4392&#EXkTL"r+hR]-]PRDeiIG0OPmOkJ/@*Y^Q[-f>4A8E5f3nJI"V3`.:=nIA#F$"b_c3Ldqj^e\l,-dP,-(A:UGIekAGJiVZ9_J7qBZO['<_Pu0d@$_fW$W?hk9MQZddr/@Be&N-d[Rf*c5E!.*qj\^^WP_D/OFUjJi^AI4Rr*F8XPO-FIK0S,E-G($g3S3cup%!CWUePV`nA9X_=]sjpBRba/7p%uqF%u/#<$]mi+6(&?%<0*ue!B/[lMGgq(,82jQp5O_pGe$@4>eua#c]Tn2stl4E*nQc8h.ma*g6NMgTl?F6E)dT)`PY_8XNP+C'jWEP/,iAJJlHIPW)#j/dfF)$eCC/"SRQQ$1=FlJ71)M4/iIZI[27P,DusLT&ehrQSDWg''t3F;XW:0IWaYGdqMkq1T4dr0h)I.N!j$L.njWfLm^h>#j\tql@"8f3rFg'+7UX)+cB1*#PdcRntSo_BP`#u_<8=YkKoMHr&pq_AZ44uV\s6nT4I15Sa8bR&!&r^EJ<5>*oG\T/c"&/V,TUe"")W@EI3I2Z-t%p\4Sm,rn_Ftdj?,b_Y[W["0$F8#J;Vr,d%Ip8!?^aMGQn;e7/,]P/,g=<!m-"G>NXU+dD!lp>B@9%.Xh>"eiqjPG^<NdS34c3mQh$C;r-XOmCpiY%E'o<hTSh/hHWUJOUpEN2+T#d=Usr5=P5[P1mpX>o"9fAR&6]12JfrWMD/QCtYVdL""N:e'oG&j'Hj?FI3'OAc&UH,ZpsElPac3I7]>+4sE0sD3LfMlRBtf;^]a_>.\40oiYG:ai2MGmI+qmA2C&BVtn\YYHrT'4RY0-_H++tfHNn(1U$LKW%OqHI'nk7S`?2o1H*B\W);J>Fj_%?'K&'QmmA,H"7(33K;-L3/XeTC1>"K%R:ks!6=FAAb\WD"ZeE4hj$"seU(,Lcj&OeWZh,#9:eFCpTb0Lr(K-?NL*<%d"7$Q=P\+5C;@eCL#()8lMJmaUGRGP.kW%/rX61U8D1;uBN8U3r]\*:97utGCOttAR[`i1=OH./R;th&Tg'dIc0>kc!%](C.W8M!(.#7*Ze]YGf%j^$t*#EmJ@>e><OreSY6F$Fda5jB+l:_"lo(Q:7!B]&QkH_28XN`YBM&V+jnbK%r0/([(/LIj/;3tiek%P,RmWXT+IZ$hBi^p\c=MC$/fH&6dOeMUnjDcLj_ITI>kESUi',<D(]J;T`h&t%Z>MOMs%=_]tKoTP_SEkaP.qAA+5guYnIK/)M:`0]K;kY22Oi9!KGKf4>iYWHC[]Q"Ye]Pon:01"iS>Y*olAMF*'Hh?@On$LQ6=^SXi??^ZC6u52k*Q54TJ01dPUP#^Wj6c=ir;@kE==W2<"Y8@(d@_hpK?;<k5@V@gm$%[U$!(Z5Ai(h8$HrhXD_`Sq.4FI1*fJ*1Bhjgi@+aXlG8#4dC7*>GR&r%KDU+qU2sr=1ja_EbJGgirbUIbMG\eZH&".pRI5cG0&!TlK)2d'ea;W(V@PZB/K:=XR>#O=eVQET3p!%RHEK7#FAL%qA*^`g:C;.EY7!mE0tnF8`El:0&GupW-3P[~>endstream
|
||||||
|
endobj
|
||||||
|
29 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1324
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gatm:gN)%,&:N_Cm%`Ul0EL%Gb]MQ`C+#Eh*Of)/(V`5r8qKJD$33YgIXRP!1UQ163/K5H%"dEsm+J]Mj:Kap\%fldi+rUq(EBr8f`HEB@[LH<q(2:\0Th5D:4PbgN,eqMO.&;;bFjS8ASEc;%Pl7qb[QASB2[k)"?i)_49LMG3"@pP/.FBQ"-Yi=AbssK&PIhNX^dZmC&[c#*hR9,jXffH&^9Z9_.X#@P8^/b0ai8i,r")hdFF"Jn)9g?U+99a<:J:>/63h[KZN)rqi`taC$2aS5B2aLfl"%fY@)MaZf>Z$;>`Bh/0T8!j'SM_!VG]j=`dNEePb!+GW:TP2f\[*-l"nl/<h]C_Mi7"9u;O=LlkQ)`[P^*Og&^_bZ058=;]%u1achK.V:e9`HW_T=Ao@?*"BF=]EpGhjg6X9@#,inDTr1>@A4lp&*#.tFI.Kf)%M57@@&/D^S%Oh@K>(G4JX^S]EhP(X/Y71Q2^EMd7u4KPf[5QUQY//$->U=SDm!nO_r52;-b%-BR]f-'L-Hpk=g7D^JP-[8[jc?h\s+5<9=0bjZV>OI8:*t(kW;^Ig6T.=u^7TCD$-?I2dQ(fA3%*U=3SJC-]/OrsC%]cZZlL+5qJd;%ep%OW<-E;[?WO(`K8A(s\3]!*&(QI0haa&r;a2.?VHC;BAF5[A6!=Sb<dNBa=s4?D3.flB['G%,N0\@"DG*<O$/c=0BeVVWQ7&E-`*\hY9hkBn,;#,YIcDhPAFDj;s-oYD28@EIJ]MS<>1LO:<@Ld8GG9mjq5L`@'1]I^UN2B\-'r@TZVF=Vb"KUNFc=SB1.B^i-$5&\@CNDH0uD)#U5]CTR1,RUg9)+;Of@2SI^eTN-?@i;0&PlmDPOZQ&RTrq?8)G/H3ai8.Ep;SA]Q-i7ma:I<&i(cE083XLbu_EELk7aOQ2"%?rV8_J4$@-M&p73GPU/?'#+LJJ,@i!m-<#4N&X;3eM(afjo)W_4a7Z"jiHJ`!]bnJb%G02HWDOo,I`]<)KuAT*Op19,+q0./G*_Op=^.uh.C6:!4Z<t9ck>M=I]^,6F442RP,R2nPQS8V'g6#Qa]ntbju?2o\E)7@9)QC]1oEo[\+j<dDXcK0tjSFj7LG,+<H`70hDe/'XXP,)ZsdtO3?9MV>YH)kW7]-cOGf%aco?NUnS@`Lb)<j(t$CW]rA24bedr3'<p+ae0cKjJFte#St;8dYQ#C9Qb7:*DE=Gr!j/bT#o:FLi'F-"@lFXN=iO\G.HHlqP5b6(8fdolT%?:E=P$e6DJ!.gEJrof?:,fJ%<di59fMo=LP>7JD"7DQ#)NVu/mN5Mb5ei;~>endstream
|
||||||
|
endobj
|
||||||
|
30 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1582
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gb!;d8T3?E&AII3bbYhFdEj-b;,g=E9imuY2n/7=MaGgO&t*i13D'8L)c=$h-ZM$Y!Gi^@\BW5V)i%rhn]UjFRKL3j_"^%p`aLV+(6JkLTAeTOp`0nuGS7t\6:o(Z"%gDm"4\qV&.9[[ShcBa+YnlsP)Mr"9&R338QZ%ZL?Zm3!D*DgA-><+=@dFAI7OM(a>tNM&F&l\/,<^#?:r..3Y\q!+YfM'<hMLR@72N%P8GWf(`e&#oa*h9R<IlFg(JkcPuae?*-7^e_5I56k6b;V*8]rg?/!8&RsGSlB/"Van/BZ7,#2S]Dj105m=5<<]@p"aWaE)8@5;5,5j'*OFA5<qQ(SGK,ReC=[^]8p6&:D\@3d#to74lWII6mRJ1$#u8.PL+>g8-39*?@1`9TE5kkae&8]DZH>uupTdMP%!+`$7_!j"Ht$FkO<",<SP+/Bo#g2TsjmA259d0[?egqagM=2AV/IB*+OVB<QkI)e=P+EHQb"-X&@B$.YP>G.^%/A9.B*>jO8<mTBi!sZUu8.!&QTQ(:(U>p,FGZ.aT[(4N\6IO0W^[DbfFcdV#/-`mQm*V/R2MX3BE'1GTBqYm9bN$8F$&13WZ%>h3OFd8e20@>(odk?S(=qdtTSp6fDti!<@^e1BWYlh`,hXXmH;Mi4?O"09rG<_'2Mo2Vb.S";RSg"$Oqm!sHcB:c8\e=!CnQ)\Ns'T>8t4qoJ[N18@#N"q@I&2%$JY;dM:qNGFR\8FdGtP#kJqqYfWT%%h.=Q%4s/4Ef;"EK=u.aB[t%D+i%B,A4s.A-f;$]@/XNsLhA1HrG2uDGcNru2kWT^Ra5tEYQkf;Ynq8DQ+62KJ?=U[bp=hIu?2fmPq:G1eX)cS0\j'<BbjWmU;'MWuq0*sof!a5G[+./PI!W\6kIIn]g6b+b)tS57m]<u$I8t(C$>X%@R;Ab$D:$h`/dL?ijkM%Y%l1D^q!\9CikJQf*MHo_RDWe1!MN)W(n*PEUMib_qjp)jS2k&Zg%Y\3`_Cg[%b9or8,cc;WXK:)fs8]l#"$)rAW+O[&%V5YcRd:VI%dSf<,Y.<eLACq;o;>G>(>l:DnFc`<qbS3/,Y$t=&ZX+h(kf(Bl:H`V5Mp5mLK^^QS!RtnTMMMGJ)GtaM-t6eQ>s-SSm.U?/<>u['RqJTk!q%4'm8[\=X._Rp^:S`^m-<#Hfbk6]sRgJF;^HjB7c:QgKB1c9FLK2`<riG$\<5f*4l8XfEf/PdcDDojlO*4:d5!"#!Dk;e4J48ZAE3kY\?2(<qOSY*rih.G@uk$7.T.,-\q$j;m"cL8&V+T_aCNc(_?UP!h]$&KuJcpo\Qf50=U/I&6-T[%X;b&`YQN9kaR+QW(^Lr:^gtn3WWB"r<BM<72'>b#p8nI("4lpQj=PZ'KAO)soNEK2Wq^MXam`GK>0oNk3HZI-0;NCG>Trb8JI+TfFh\.Xb1X95iC9J"-1ZpOU?:]jUib140P'9O6>!WTlgfiNdL4C@<g<._<r2=/sWGS6@/8e')2O8_3M2)&t7KF@Z"*E+nDBlZDf7m9ZQ;pFADW'c(32]n4GO1gUHS\i`K_es9j),=:la%t-!i~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 31
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000061 00000 n
|
||||||
|
0000000122 00000 n
|
||||||
|
0000000229 00000 n
|
||||||
|
0000000341 00000 n
|
||||||
|
0000000546 00000 n
|
||||||
|
0000000651 00000 n
|
||||||
|
0000000856 00000 n
|
||||||
|
0000001061 00000 n
|
||||||
|
0000001138 00000 n
|
||||||
|
0000001343 00000 n
|
||||||
|
0000001549 00000 n
|
||||||
|
0000001755 00000 n
|
||||||
|
0000001961 00000 n
|
||||||
|
0000002167 00000 n
|
||||||
|
0000002373 00000 n
|
||||||
|
0000002579 00000 n
|
||||||
|
0000002785 00000 n
|
||||||
|
0000002855 00000 n
|
||||||
|
0000003146 00000 n
|
||||||
|
0000003277 00000 n
|
||||||
|
0000005186 00000 n
|
||||||
|
0000007092 00000 n
|
||||||
|
0000008874 00000 n
|
||||||
|
0000010692 00000 n
|
||||||
|
0000013269 00000 n
|
||||||
|
0000014981 00000 n
|
||||||
|
0000017082 00000 n
|
||||||
|
0000019149 00000 n
|
||||||
|
0000020877 00000 n
|
||||||
|
0000022293 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<a6147630729a0aa699ee753548d84bc4><a6147630729a0aa699ee753548d84bc4>]
|
||||||
|
% ReportLab generated PDF document -- digest (opensource)
|
||||||
|
|
||||||
|
/Info 18 0 R
|
||||||
|
/Root 17 0 R
|
||||||
|
/Size 31
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
23967
|
||||||
|
%%EOF
|
||||||
441
v2-klasB/Les02-OpenCode/Les02-Slide-Overzicht.md
Normal file
441
v2-klasB/Les02-OpenCode/Les02-Slide-Overzicht.md
Normal file
@@ -0,0 +1,441 @@
|
|||||||
|
# Les 2 — OpenCode Pro: Rules, Worktrees & Scroll Animations
|
||||||
|
## Slide Overzicht (Klas B — 2 uur, online)
|
||||||
|
|
||||||
|
**Bronnen-overzicht onderaan dit document.**
|
||||||
|
|
||||||
|
**Lesflow:** Theorie eerst in blokken, dan dedicated **Live Demo** momenten. Geen heen-en-weer geswitch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 1: Title
|
||||||
|
### Les 2 — OpenCode Pro
|
||||||
|
|
||||||
|
**Visual:**
|
||||||
|
- Background: CREAM
|
||||||
|
- "Les 2" in BLUE
|
||||||
|
- "OpenCode Pro" in BLACK
|
||||||
|
- Subtitle: "Rules · Worktrees · Een scroll-animatie site bouwen"
|
||||||
|
|
||||||
|
**Bronnen:** [1]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 2: Terugblik
|
||||||
|
### Waar staan we?
|
||||||
|
|
||||||
|
**Content:**
|
||||||
|
- Les 1: kennismaking + leerlijn-opzet
|
||||||
|
- Iedereen kent ChatGPT en/of Claude (als chat)
|
||||||
|
- Eindopdracht: AI-app met Next.js + Supabase + Vercel AI SDK
|
||||||
|
|
||||||
|
**Vandaag:**
|
||||||
|
"Van AI als chat naar AI als coding-IDE. Met regels, config en parallel worktrees."
|
||||||
|
|
||||||
|
**Visual:** Chat-bubble → IDE icoon
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 3: Planning
|
||||||
|
### Vandaag — 120 minuten
|
||||||
|
|
||||||
|
| Onderwerp | Duur |
|
||||||
|
|-----------|------|
|
||||||
|
| Welkom + Terugblik | 10 min |
|
||||||
|
| **Theorie 1** — Waarom OpenCode + kern features | 20 min |
|
||||||
|
| **Live Demo 1** — Desktop tour | 10 min |
|
||||||
|
| **Theorie 2** — AGENTS.md + opencode.json + plugin + stack | 15 min |
|
||||||
|
| **Live Demo 2** — Setup + worktree + bouw SmoothScroll | 15 min |
|
||||||
|
| **Pauze** | 15 min |
|
||||||
|
| Lesopdracht: bouw scroll-sectie | 35 min |
|
||||||
|
| Huiswerk + Afsluiting | (eind) |
|
||||||
|
|
||||||
|
**Visual:** Timeline met YELLOW pauze-rij + PINK demo-rijen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 4: Waarom OpenCode (en niet Cursor)?
|
||||||
|
### Alternatieven kennen is professioneel
|
||||||
|
|
||||||
|
**Iedereen kent Cursor. Wij beginnen bewust met OpenCode. Waarom?**
|
||||||
|
|
||||||
|
| | Cursor | OpenCode |
|
||||||
|
|---|--------|----------|
|
||||||
|
| Licentie | Commercieel ($20/mnd) | Open source (gratis) |
|
||||||
|
| Models | Eigen routing | Direct: OpenAI, Anthropic, Google, Groq, Ollama |
|
||||||
|
| Lock-in | Hoog | Geen |
|
||||||
|
| Scriptable | Beperkt | Volledig (CLI + plugins) |
|
||||||
|
| Lokale AI | ❌ | ✅ (via Ollama) |
|
||||||
|
|
||||||
|
**Belangrijke punten:**
|
||||||
|
- **Provider-keuze** — jij beslist welk model, niet de tool
|
||||||
|
- **Geen vendor lock-in** — past in een pro-toolchain
|
||||||
|
- **Concept is hetzelfde** — leer OpenCode goed, dan begrijp je Cursor + Claude Code ook
|
||||||
|
- **Onderdeel van leerlijn** — later kijken we naar Cursor; nu de open variant
|
||||||
|
|
||||||
|
**Belangrijk:** dit is **geen Cursor-bashing**. Cursor is uitstekend. We kiezen voor breedte: meerdere tools kennen > vasthangen aan één.
|
||||||
|
|
||||||
|
**Bronnen:** [1] [4]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 5: Wat is OpenCode?
|
||||||
|
### Een AI coding-IDE in twee smaken
|
||||||
|
|
||||||
|
**Content:**
|
||||||
|
- Open source · 60.000+ GitHub stars · door SST
|
||||||
|
- Werkt met elke provider: OpenAI, Anthropic, Google, Groq, Ollama
|
||||||
|
- Lokaal — code blijft op jouw machine
|
||||||
|
|
||||||
|
**Twee smaken:**
|
||||||
|
|
||||||
|
| Desktop (vandaag) | TUI (terminal) |
|
||||||
|
|-------------------|----------------|
|
||||||
|
| Visuele diff-viewer | Snel met keyboard |
|
||||||
|
| File tree + Sessions sidebar | Werkt over SSH |
|
||||||
|
| Multi-session parallel | Goed voor scripts / CI/CD |
|
||||||
|
| Sneller leren als je begint | Worktree plugin spawnt auto terminal |
|
||||||
|
|
||||||
|
**Vandaag:** Desktop. We tonen TUI **1 minuut** in Live Demo zodat je weet dat 't bestaat.
|
||||||
|
|
||||||
|
**Voor jouw eindopdracht: Desktop.**
|
||||||
|
|
||||||
|
**Bronnen:** [1] [2] [3] [5]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 6: Plan/Build/@explore + /init
|
||||||
|
### De vier dingen die je echt moet kennen
|
||||||
|
|
||||||
|
**Twee modes** (Tab om te wisselen):
|
||||||
|
- **plan** — read-only, denkt mee, wijzigt niks
|
||||||
|
- **build** — default, schrijft code, voert commands uit
|
||||||
|
|
||||||
|
**Sub-agents:**
|
||||||
|
- `@explore` — read-only verkenning (spaart tokens)
|
||||||
|
- `@general` — brede taak
|
||||||
|
- `@scout` — gerichte zoekopdracht
|
||||||
|
|
||||||
|
**`/init` commando** — eerste actie in elk nieuw project:
|
||||||
|
- Scant je repo
|
||||||
|
- Stelt vragen
|
||||||
|
- Schrijft/update je `AGENTS.md`
|
||||||
|
|
||||||
|
**Best practice:**
|
||||||
|
> Plan eerst. Lees mee. Geef feedback. Tab → Build.
|
||||||
|
|
||||||
|
**Bronnen:** [6] [7] [8]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 7: LIVE DEMO 1 — Desktop Tour
|
||||||
|
### Wat je nu gaat zien (~10 min)
|
||||||
|
|
||||||
|
**Setup:** OpenCode Desktop open op een leeg Next.js project.
|
||||||
|
|
||||||
|
**Wat ik laat zien:**
|
||||||
|
1. **TUI 1 minuut** — `opencode` in terminal, snelle Tab/exit. "Hetzelfde, maar terminal-only."
|
||||||
|
2. **Desktop UI tour** — file tree, chat panel, diff viewer, Sessions sidebar
|
||||||
|
3. **Plan mode** — vraag `analyseer dit project`, zie dat niks wijzigt
|
||||||
|
4. **Tab → Build mode** — vraag iets simpels, zie diff
|
||||||
|
5. **`@explore`** — `@explore wat zit er in deze repo?` — aparte context
|
||||||
|
6. **`/init`** — laat AGENTS.md genereren
|
||||||
|
|
||||||
|
**Visual:** Mockup van Desktop layout met annotaties. PINK badge "LIVE DEMO".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 8: AGENTS.md — Projectregels
|
||||||
|
### De officiële OpenCode standaard
|
||||||
|
|
||||||
|
**Wat is AGENTS.md?**
|
||||||
|
Markdown in project-root dat OpenCode automatisch in elke context laadt. Officieel format — alternatief voor Cursor's `.cursorrules`.
|
||||||
|
|
||||||
|
**Twee locaties:**
|
||||||
|
- `./AGENTS.md` — per project (in repo)
|
||||||
|
- `~/.config/opencode/AGENTS.md` — globaal voor alle projecten
|
||||||
|
|
||||||
|
**Externe regels referencen:**
|
||||||
|
```
|
||||||
|
@rules/styling.md
|
||||||
|
@rules/security.md
|
||||||
|
```
|
||||||
|
|
||||||
|
**Hoe te maken:**
|
||||||
|
- Handmatig schrijven, OF
|
||||||
|
- `/init` in OpenCode — scant repo, stelt vragen, genereert
|
||||||
|
|
||||||
|
**Tip:** schrijf concrete regels die je AI kan controleren. "Gebruik clean code" werkt niet. "useGSAP alleen, geen useEffect" wel.
|
||||||
|
|
||||||
|
**Bronnen:** [9]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 9: opencode.json — Config
|
||||||
|
### Model · Permissies · Plugins
|
||||||
|
|
||||||
|
**Locaties:**
|
||||||
|
- `./opencode.json` — per project
|
||||||
|
- `~/.config/opencode/opencode.json` — globaal
|
||||||
|
|
||||||
|
**Basis:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"$schema": "https://opencode.ai/config.json",
|
||||||
|
"model": "openai/gpt-4o-mini"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Permissies (uit officiele docs):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"permission": {
|
||||||
|
"bash": { "*": "ask", "git *": "allow", "rm *": "deny" },
|
||||||
|
"edit": { "*": "deny", "app/**/*.tsx": "allow" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Drie levels: `allow` · `ask` · `deny`. Glob patterns voor bash én files.
|
||||||
|
|
||||||
|
**Bronnen:** [10] [11]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 10: opencode-worktree Plugin
|
||||||
|
### Auto-magisch worktrees aanmaken
|
||||||
|
|
||||||
|
**Wat doet het?**
|
||||||
|
Plugin van **kdcokenny**. Geeft de agent twee tools:
|
||||||
|
- `worktree_create` — branch + worktree
|
||||||
|
- `worktree_delete` — commit + cleanup
|
||||||
|
|
||||||
|
**Installatie via `ocx`:**
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://kdco.dev/ocx/install.sh | sh
|
||||||
|
ocx add kdco/worktree --from https://registry.kdco.dev
|
||||||
|
```
|
||||||
|
|
||||||
|
**Desktop workflow:**
|
||||||
|
1. In main session: "Maak worktree feature-hero"
|
||||||
|
2. Plugin maakt worktree-folder
|
||||||
|
3. Klik **+ New Session** → **Open Folder** → kies worktree
|
||||||
|
4. Parallel agents in sidebar
|
||||||
|
|
||||||
|
**Bronnen:** [12] [13]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 11: Demo Stack — Next.js 16 + GSAP + Lenis
|
||||||
|
### De stack voor high-end scroll storytelling
|
||||||
|
|
||||||
|
**Stack:**
|
||||||
|
- **Next.js 16** App Router + TypeScript (Turbopack default)
|
||||||
|
- **TailwindCSS**
|
||||||
|
- **GSAP 3.15** + `@gsap/react` — sinds 2025 100% gratis (ScrollTrigger, SplitText)
|
||||||
|
- **Lenis 1.3** (`lenis/react`) — door Darkroom Engineering
|
||||||
|
|
||||||
|
**Waarom deze combinatie?**
|
||||||
|
|
||||||
|
Dit is dé stack waarmee award-winning scroll-storytelling sites gebouwd worden.
|
||||||
|
Niet "een" optie — **de** standaard op pro-niveau.
|
||||||
|
|
||||||
|
**Wie gebruikt dit?**
|
||||||
|
- Apple product pages (GSAP scroll animaties)
|
||||||
|
- Stripe, OpenAI marketing — beide GSAP-based
|
||||||
|
- Awwwards / FWA winnaars — bijna altijd GSAP
|
||||||
|
- Studios: **Active Theory**, **Locomotive**, **Resn**, **Darkroom Engineering** (makers van Lenis zelf)
|
||||||
|
|
||||||
|
**Waarom niet Framer Motion?**
|
||||||
|
- Framer Motion is uitstekend voor **app UI** (modals, transities, micro-interacties)
|
||||||
|
- GSAP heeft betere timing-precisie en GPU-optimalisaties voor **scroll storytelling**
|
||||||
|
- Voor jouw eindopdracht (een site die "wow" doet bij scrollen): GSAP
|
||||||
|
|
||||||
|
**Next.js 16 detail:**
|
||||||
|
- `cookies()`, `headers()`, `params`, `searchParams` zijn **async** — altijd `await`
|
||||||
|
|
||||||
|
**Bronnen:** [14] [15] [16] [17] [18] [19]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 12: Onze AGENTS.md
|
||||||
|
### Regels voor het 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 · GSAP 3.15+ (incl. ScrollTrigger, SplitText)
|
||||||
|
- Lenis 1.3+ (`lenis/react`)
|
||||||
|
- @gsap/react voor de useGSAP hook
|
||||||
|
|
||||||
|
## Hard rules
|
||||||
|
- Geen Framer Motion, react-spring, AOS
|
||||||
|
- Animaties altijd in Client Components (`"use client"`)
|
||||||
|
- useGSAP(() => {}, { scope: ref }) — nooit useEffect voor GSAP
|
||||||
|
- Lenis sync: gsap.ticker.add met autoRaf: false
|
||||||
|
- Next 16: await params, await cookies(), await headers()
|
||||||
|
|
||||||
|
## Patterns
|
||||||
|
- Eén <SmoothScroll> wrapper in app/layout.tsx
|
||||||
|
- Tailwind voor layout; GSAP voor transform/opacity
|
||||||
|
|
||||||
|
## Done =
|
||||||
|
- Geen hydration warnings
|
||||||
|
- ScrollTrigger.refresh() na dynamische content
|
||||||
|
```
|
||||||
|
|
||||||
|
**De `## Why this stack` sectie** geeft de agent context. Hij snapt nu
|
||||||
|
*waarom* deze keuzes — en stelt voor dezelfde redenen geen Framer Motion voor.
|
||||||
|
|
||||||
|
**Bronnen:** [14] [15] [19]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 13: LIVE DEMO 2 — Setup + Worktree + SmoothScroll
|
||||||
|
### Wat je nu gaat zien (~15 min)
|
||||||
|
|
||||||
|
**Wat ik laat zien:**
|
||||||
|
1. **AGENTS.md** invullen met onze projectregels
|
||||||
|
2. **opencode.json** maken met permissions
|
||||||
|
3. Tonen dat `rm -rf` geblokkeerd wordt
|
||||||
|
4. **`ocx` + worktree plugin** installeren (was al klaar — kort tonen)
|
||||||
|
5. Via prompt: **worktree feature-hero** aanmaken
|
||||||
|
6. **+ New Session** → openen op worktree-folder
|
||||||
|
7. In feature-hero: **SmoothScroll wrapper** laten bouwen
|
||||||
|
8. Bewijs dat **AGENTS.md regels gevolgd worden** (useGSAP, geen Framer Motion, etc.)
|
||||||
|
|
||||||
|
**Visual:** Mockup Sessions sidebar + diff-viewer. PINK badge "LIVE DEMO".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 14: Pauze
|
||||||
|
### Pauze!
|
||||||
|
|
||||||
|
**Visual:** "Pauze" groot, "15 minuten"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 15: Lesopdracht
|
||||||
|
### Bouw een scroll-sectie — 35 minuten
|
||||||
|
|
||||||
|
**Setup (al klaar in starter):**
|
||||||
|
- Next.js 16 starter
|
||||||
|
- AGENTS.md, opencode.json, plugin
|
||||||
|
- GSAP + Lenis geïnstalleerd
|
||||||
|
- SmoothScroll wrapper bestaat al
|
||||||
|
|
||||||
|
**Jouw taak:**
|
||||||
|
1. `/init` runnen — check AGENTS.md
|
||||||
|
2. Vraag agent: maak worktree voor jouw feature
|
||||||
|
3. Open de worktree in nieuwe Sessions tab
|
||||||
|
4. Plan-mode → review → Tab → Build
|
||||||
|
5. Test op `npm run dev`
|
||||||
|
6. Commit + push
|
||||||
|
|
||||||
|
**Sectie keuze:** hero (SplitText) · features-grid (stagger) · testimonials (horizontaal) · gallery (parallax)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 16: Huiswerk
|
||||||
|
### Bouw je eigen scroll-animatie site
|
||||||
|
|
||||||
|
**Voor volgende week:**
|
||||||
|
Bouw een **kleine landing page** met 3-4 scroll secties.
|
||||||
|
|
||||||
|
**Eisen:**
|
||||||
|
- [ ] Eigen `AGENTS.md` (onze mag als basis)
|
||||||
|
- [ ] `opencode.json` met permissions
|
||||||
|
- [ ] **2+ worktrees** gebruikt (Sessions sidebar)
|
||||||
|
- [ ] **3 verschillende scroll-animaties**
|
||||||
|
- [ ] Lenis smooth scroll
|
||||||
|
- [ ] Deploy op Vercel
|
||||||
|
- [ ] `WORKFLOW.md` reflectie (max 400 woorden)
|
||||||
|
|
||||||
|
**Lever in:** GitHub URL + Vercel URL + screenshot van `git worktree list`
|
||||||
|
|
||||||
|
**Bonus:** Eigen sub-agent · MCP server (context7) · Lighthouse 90+
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 17: Afsluiting
|
||||||
|
### Volgende les — Introductie Cursor
|
||||||
|
|
||||||
|
**Vandaag gedaan:**
|
||||||
|
- Waarom OpenCode (vs Cursor)
|
||||||
|
- Plan/Build/@explore/`/init`
|
||||||
|
- AGENTS.md + opencode.json
|
||||||
|
- opencode-worktree plugin via ocx
|
||||||
|
- Live: Next.js 16 + GSAP + Lenis scroll-site
|
||||||
|
- Parallel agents via Sessions sidebar
|
||||||
|
|
||||||
|
**Volgende keer — Cursor:**
|
||||||
|
- De commerciele tegenhanger van OpenCode
|
||||||
|
- Cursor rules vs AGENTS.md
|
||||||
|
- Composer, Tab-completion, @-references
|
||||||
|
- Wanneer kies je welke tool?
|
||||||
|
|
||||||
|
**Vragen? Feedback?**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide Summary
|
||||||
|
|
||||||
|
| # | Title | Type | Bronnen |
|
||||||
|
|---|-------|------|---------|
|
||||||
|
| 1 | Title | Opening | [1] |
|
||||||
|
| 2 | Terugblik | Intro | — |
|
||||||
|
| 3 | Plan | Intro | — |
|
||||||
|
| 4 | Waarom OpenCode | Theorie | [1] [4] |
|
||||||
|
| 5 | Wat is OpenCode | Theorie | [1] [2] [3] [5] |
|
||||||
|
| 6 | Plan/Build/@explore | Theorie | [6] [7] [8] |
|
||||||
|
| 7 | **LIVE DEMO 1** | Demo | — |
|
||||||
|
| 8 | AGENTS.md | Theorie | [9] |
|
||||||
|
| 9 | opencode.json | Theorie | [10] [11] |
|
||||||
|
| 10 | Worktree plugin | Theorie | [12] [13] |
|
||||||
|
| 11 | Demo stack | Theorie | [14]–[18] |
|
||||||
|
| 12 | Onze AGENTS.md | Theorie | [14] [15] [19] |
|
||||||
|
| 13 | **LIVE DEMO 2** | Demo | — |
|
||||||
|
| 14 | Pauze | Break | — |
|
||||||
|
| 15 | Lesopdracht | Praktijk | alle |
|
||||||
|
| 16 | Huiswerk | Praktijk | alle |
|
||||||
|
| 17 | Afsluiting | Closing | — |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bronnen
|
||||||
|
|
||||||
|
**OpenCode (officieel):**
|
||||||
|
- [1] OpenCode hoofdsite — https://opencode.ai
|
||||||
|
- [2] OpenCode Download (Desktop) — https://opencode.ai/download
|
||||||
|
- [3] OpenCode docs — https://opencode.ai/docs/
|
||||||
|
- [4] OpenCode GitHub (sst) — https://github.com/sst/opencode
|
||||||
|
- [5] DeepWiki: Desktop Applications — https://deepwiki.com/sst/opencode/6.7-desktop-applications
|
||||||
|
- [6] Modes (plan/build) — https://opencode.ai/docs/modes/
|
||||||
|
- [7] Agents (sub-agents) — https://opencode.ai/docs/agents/
|
||||||
|
- [8] Commands (slash) — https://opencode.ai/docs/commands/
|
||||||
|
- [9] Rules (AGENTS.md) — https://opencode.ai/docs/rules/
|
||||||
|
- [10] Config — https://opencode.ai/docs/config/
|
||||||
|
- [11] Permissions — https://opencode.ai/docs/permissions/
|
||||||
|
|
||||||
|
**Worktree plugin:**
|
||||||
|
- [12] opencode-worktree — https://github.com/kdcokenny/opencode-worktree
|
||||||
|
- [13] ocx (extension manager) — https://github.com/kdcokenny/ocx
|
||||||
|
|
||||||
|
**Next.js 16:**
|
||||||
|
- [14] Next.js 16 blog — https://nextjs.org/blog/next-16
|
||||||
|
- [15] Upgrading to v16 — https://nextjs.org/docs/app/guides/upgrading/version-16
|
||||||
|
|
||||||
|
**GSAP:**
|
||||||
|
- [16] GSAP docs v3 — https://gsap.com/docs/v3/
|
||||||
|
- [17] GSAP React (useGSAP) — https://gsap.com/resources/React/
|
||||||
|
- [18] GSAP License (gratis sinds 2025) — https://gsap.com/standard-license
|
||||||
|
|
||||||
|
**Lenis:**
|
||||||
|
- [19] Lenis GitHub — https://github.com/darkroomengineering/lenis
|
||||||
BIN
v2-klasB/Les02-OpenCode/Les02-Slides.pdf
Normal file
BIN
v2-klasB/Les02-OpenCode/Les02-Slides.pdf
Normal file
Binary file not shown.
BIN
v2-klasB/Les02-OpenCode/Les02-Slides.pptx
Normal file
BIN
v2-klasB/Les02-OpenCode/Les02-Slides.pptx
Normal file
Binary file not shown.
Reference in New Issue
Block a user