Subsecties van Python sessies
Sessie 1: Catch the Stars
In deze sessie bouw je een mini-spel: een ster valt naar beneden en jij vangt hem op met een basket. Aan het einde van de sessie beweegt alles, houdt het spel bij hoeveel sterren je vangt, en heb je je eerste eigen game.
Wat je vandaag leert
- Variabelen gebruiken om objecten te positioneren
- De
draw() functie: wat je elke frame tekent - De
update() functie: wat er elke frame verandert - Toetsenbord-input: bewegen met pijltjestoetsen
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py in Thonny. - Klik op de groene Run-knop. Je ziet een donkerblauw venster met een basket onderaan en een ster bovenaan, maar niks beweegt nog.
- Problemen? Kijk bij Thonny instellen.
Stap 1: Laat de ster vallen
De update() functie draait 60 keer per seconde. Alles wat je daarin zet, wordt dus 60 keer per seconde uitgevoerd. Dat is hoe beweging werkt in een game.
Op dit moment staat er alleen pass in update(). Dat betekent “doe niks”. Verwijder pass en voeg dit toe:
def update():
star.y = star.y + 3
Klik op Run. De ster valt nu van boven naar beneden. Als hij het scherm uit valt, verdwijnt hij. Dat lossen we zo op.
Wat gebeurt hier? star.y is de verticale positie van de ster. Hoe groter y, hoe lager op het scherm. Door elke frame + 3 toe te voegen, zakt de ster steeds een beetje.
Het coördinatenstelsel: (0, 0) zit linksboven, niet linksonder zoals in wiskunde. x loopt naar rechts, y loopt naar beneden. De ster begint op y = 30 (bijna helemaal boven), de basket staat op y = 370 (bijna helemaal onder).

Beweeg je muis over het scherm hieronder om de coördinaten te zien:
Beweeg je muis over het scherm om de coördinaten te zien.
Wil je meer weten over hoe het scherm werkt? → Coördinaten uitgelegd
Pas de schuifbalken aan en kijk hoe actor.x en actor.y veranderen als de actor beweegt:
Stap 2: ✅ Basic: laat de basket bewegen
Tijd om de basket te besturen. Pygame Zero heeft een handige keyboard-variabele die bijhoudt welke toetsen ingedrukt zijn.
Voeg dit toe aan update(), na de regel over de ster:
def update():
star.y = star.y + 3
if keyboard.left:
basket.x = basket.x - 5
if keyboard.right:
basket.x = basket.x + 5
Klik op Run en gebruik de pijltjestoetsen. De basket beweegt nu mee!
Tip (optioneel, telt als Stretch): Als je de basket te ver naar links of rechts beweegt, verdwijnt hij van het scherm. Kun jij een check toevoegen die dat voorkomt? Hint: gebruik WIDTH en vergelijk met basket.x.
Stap 3: ⭐ Stretch: vang de ster
Nu wil je dat er iets gebeurt als de basket de ster raakt. Daarvoor gebruik je colliderect. Die controleert of twee rechthoeken elkaar overlappen.
Voeg dit toe aan update():
if star.colliderect(basket):
star.y = 0
De ster springt terug naar boven als je hem vangt. Maar wat als je hem mist? Voeg ook dit toe:
if star.y > HEIGHT:
star.y = 0
Bonus: Laat de ster elke keer op een willekeurige plek terug verschijnen. Voeg bovenaan het bestand toe:
Vervang dan star.y = 0 (op beide plekken) door:
star.x = random.randint(20, WIDTH - 20)
star.y = 0
Nu valt de ster steeds op een andere plek. Veel moeilijker te vangen!
Stap 4: 🔥 Expert: voeg een score toe
Een echte game houdt bij wat je scoort. Daarvoor heb je een variabele nodig die buiten de functies leeft: een globale variabele.

Klik op de knop hieronder om te zien hoe score verandert elke keer dat je een ster vangt:
Voeg dit toe bovenaan, buiten alle functies (na de regels over basket en star):
In draw(), voeg toe:
screen.draw.text(f"Score: {score}", topleft=(10, 10), color="white")
In update(), pas de catch-code aan zodat de score omhoog gaat:
if star.colliderect(basket):
global score
score = score + 1
star.x = random.randint(20, WIDTH - 20)
star.y = 0
global score vertelt Python: “ik bedoel de score van buiten deze functie, niet een nieuwe lokale variabele.” Zonder die regel krijg je een foutmelding.
Klik op Run. De score staat linksboven en telt op elke keer dat je een ster vangt!
Showcase
Laat je spel zien aan een coach en een buddy. Vertel wat je gemaakt hebt: wat werkt, en wat je nog extra hebt toegevoegd.
Tot de volgende keer!
“Volgende keer: dingen die TERUGSLAAN. En ze gaan BOEM, met echt geluid.”
Neem mee naar huis
Probeer thuis één van deze uitbreidingen. Bij elke staat een code-hint om je op weg te helpen.
Beperk levens — Voeg levens = 3 toe. Bij een misser (star.y > HEIGHT): levens -= 1. Stop het spel als levens == 0 met game_over = True en toon “Game Over” in draw().
Willekeurige ster-kleur — Bij elke vangst: geef de ster een nieuwe kleur met random.randint(50, 255) voor rood, groen en blauw. Begin bij 50, niet bij 0 — anders is de ster soms zwart en onzichtbaar.
Achtergrond — Teken vaste sterren op de achtergrond in draw() voor de score. Gebruik screen.draw.filled_circle(x, y, 2, "white") op 20 willekeurige posities. Zaai random.seed(42) zodat ze niet flikkeren.
Tweede ster — Maak sterren = [star, Actor("star")]. Geef elke ster een eigen x. Werk ze allebei bij in update() en teken ze in draw().
Hoge score — Houd high_score bij. Als score > high_score: high_score = score. Toon f"Beste: {high_score}" naast de score.
Basket kleiner — Na elke 5 punten: basket.width = max(30, basket.width - 5). Zet basket.width terug bij herstart.
Bom — Voeg een rode cirkel toe die af en toe valt. Gebruik een timer bom_timer en random.randint om te bepalen wanneer hij verschijnt. Als de basket de bom raakt: score -= 2.
Moeilijkheidsgraad — Na elke 5 sterren: verhoog de valsnelheid met 1. Bouw een maximum in: max(3, star_snelheid).
Vastgelopen? Vraag het volgende dojo aan een coach, of probeer gewoon iets anders. Programmeren is doen.
Bekijk de cheatsheet voor deze sessie
Sessie 2: Dodge Meteors
Je ruimteschip zweeft in de donkere ruimte terwijl meteoren van boven naar beneden komen. Ontwijk ze, of verlies een leven. Hoe langer je overleeft, hoe sneller ze gaan. En deze keer bouw je ook Dojo Defender: het grotere project dat elke sessie groeit.
Wat je vandaag leert
- Lijsten gebruiken om meerdere objecten bij te houden
- Objecten spawnen (aanmaken) en verwijderen
- Levens bijhouden en een game-over scherm tonen
- Dojo Defender: je eigen ruimteschip toevoegen aan het grotere project
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py. - Klik op Run. Je ziet je ruimteschip onderaan, maar er vallen nog geen meteoren.
- Problemen? Kijk bij Thonny instellen.
Stap 1: Laat meteoren spawnen
Vul de functie spawn_meteor() in. Een meteoor is een Actor die bovenaan het scherm begint op een willekeurige x-positie:
import random
def spawn_meteor():
rock = Actor('meteor')
rock.x = random.randint(30, WIDTH - 30)
rock.y = 0
meteors.append(rock)
Roep de functie aan in update(), maar niet élke frame, anders wordt het scherm meteen volgestort. De update() functie draait 60 keer per seconde. Gebruik dat om een teller bij te houden:
Zie hieronder hoe snel een meteoor beweegt bij verschillende snelheden en hoeveel pixels dat per seconde is:
Gebruik een teller:
# bovenaan, buiten de functies:
timer = 0
def update():
global timer
timer += 1
if timer % 60 == 0: # elke seconde (60 frames)
spawn_meteor()
Klik op Run. Na een seconde verschijnt de eerste meteoor, maar hij beweegt nog niet.
Stap 2: ✅ Basic: meteoren laten vallen en verdwijnen
Laat alle meteoren in de lijst zakken, en verwijder ze als ze het scherm uit vallen:
def update():
global timer
timer += 1
if timer % 60 == 0:
spawn_meteor()
for rock in meteors[:]: # [:] = kopie zodat je veilig kunt verwijderen
rock.y += 4
if rock.y > HEIGHT + 30:
meteors.remove(rock)
Collision detecteren: Als een meteoor het schip raakt, verlies je een leven. Voeg dit toe in de loop:
if rock.colliderect(ship):
meteors.remove(rock)
global lives
lives -= 1
if lives <= 0:
# TODO: game over (stap 3)
pass
Stap 3: ⭐ Stretch: game over en snelheid opvoeren
Game over: Voeg een variabele game_over = False toe bovenaan. Als lives == 0, zet game_over = True. In draw(), toon een tekst als game_over True is:
if game_over:
screen.draw.text(
"GAME OVER",
center=(WIDTH / 2, HEIGHT / 2),
color="red",
fontsize=60,
)
Stop het bewegen in update() als game_over True is:
def update():
if game_over:
return
...
Snelheid verhogen: Laat meteoren sneller gaan naarmate de score stijgt:
snelheid = 3 + score // 5 # elke 5 punten +1 snelheid
rock.y += snelheid
Stap 4: 🔥 Expert: score en meerdere meteoorgroottes
Score: Elke seconde dat je overleeft, +1 punt. Voeg global score toe en verhoog in update():
if timer % 60 == 0:
global score
score += 1
spawn_meteor()
Meerdere groottes: Maak kleine, middel en grote meteoren. Gebruik een schaal-variabele en pas de hitbox aan:
def spawn_meteor():
rock = Actor('meteor')
rock.x = random.randint(30, WIDTH - 30)
rock.y = 0
rock.schaal = random.choice([0.5, 1.0, 1.5])
meteors.append(rock)
Kleinere meteoren bewegen sneller; grotere zijn moeilijker te ontwijken maar geven meer punten.
Dojo Defender
Download de Dojo Defender starter voor vandaag.
Dit is de basis van het project dat elke sessie groeit. Voeg vandaag je ruimteschip toe en laat het bewegen met de pijltjestoetsen.
Was je er vorige keer niet bij? Geen probleem — download de oplossing van vorige keer en je kan meteen mee.
Het volledige Dojo Defender werkblad vind je op de Dojo Defender pagina.
Showcase
Laat je spel zien aan een coach en een buddy. Hoe lang overleef jij? Wie haalt de hoogste score?
Tot de volgende keer!
“Volgende keer: je eigen ruimteschip SCHIET TERUG. Vijanden in formatie, en jij blast ze weg.”
Neem mee naar huis
- Makkelijk: verander de achtergrondkleur naar dieppaars of donkergroen.
- Middel: voeg een geluid toe als een meteoor het schip raakt (
sounds/hit.wav). - Lastig: maak meteoren sneller naarmate er meer op het scherm zijn (niet alleen de score).
- Erg lastig: voeg power-ups toe: een gouden ster die je een extra leven geeft als je hem aanraakt.
Bekijk de cheatsheet voor deze sessie
Sessie 3: Space Blaster
Vijanden staan in formatie bovenaan het scherm. Jij staat onderaan met een ruimteschip en één doel: ze allemaal uitschakelen voordat ze de bodem bereiken. Druk op SPATIE om te schieten, en mis niet.
Wat je vandaag leert
- Kogels bijhouden in een lijst
- Een kogel aanmaken als je op SPATIE drukt
- Collision tussen kogels en vijanden
- Game over als een vijand de bodem raakt
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py. - Klik op Run. Je ziet het schip onderaan en 12 vijanden in een raster, maar niks beweegt en je kunt nog niet schieten.
Stap 1: Laat het schip bewegen
Het schip beweegt al met de pijltjestoetsen. Controleer de code in update(). Zorg dat het schip niet buiten het scherm gaat:
if keyboard.left and ship.x > 30:
ship.x -= 5
if keyboard.right and ship.x < WIDTH - 30:
ship.x += 5
Stap 2: ✅ Basic: schieten met SPATIE
Vul de functie shoot() in. Een kogel is een Actor die begint op de positie van het schip:
def shoot():
kogel = Actor('bullet')
kogel.x = ship.x
kogel.y = ship.y - 20
bullets.append(kogel)
Roep shoot() aan als de spatiebalk wordt ingedrukt. Gebruik on_key_down (Pgzero-stijl):
def on_key_down(key):
if key == keys.SPACE:
shoot()
Laat de kogels omhoog bewegen in update() en verwijder ze als ze het scherm uit gaan:
for kogel in bullets[:]:
kogel.y -= 8
if kogel.y < -10:
bullets.remove(kogel)
Stap 3: ⭐ Stretch: vijanden raken
colliderect controleert of de rechthoekige hitbox van twee actors overlapt. Beweeg je muis over het scherm hieronder om te zien wanneer dat gebeurt:
Controleer in update() of een kogel een vijand raakt:
for kogel in bullets[:]:
kogel.y -= 8
if kogel.y < -10:
bullets.remove(kogel)
continue
for vijand in enemies[:]:
if kogel.colliderect(vijand):
bullets.remove(kogel)
enemies.remove(vijand)
global score
score += 10
break
Win-conditie: Als enemies leeg is, heb je gewonnen:
if not enemies:
screen.draw.text("JE WINT!", center=(WIDTH/2, HEIGHT/2), color="yellow", fontsize=60)
Stap 4: 🔥 Expert: vijanden bewegen en game over
Laat de vijanden langzaam naar beneden komen. Gebruik een timer:
vijand_timer = 0
def update():
global vijand_timer
vijand_timer += 1
if vijand_timer % 90 == 0: # elke 1,5 seconde
for vijand in enemies:
vijand.y += 20
Game over als een vijand de bodem bereikt:
for vijand in enemies:
if vijand.y > HEIGHT - 30:
global game_over
game_over = True
Snellere schietfrequentie: Bouw een cooldown in zodat de ninja niet oneindig snel kan schieten:
shoot_cooldown = 0
def update():
global shoot_cooldown
if shoot_cooldown > 0:
shoot_cooldown -= 1
def on_key_down(key):
global shoot_cooldown
if key == keys.SPACE and shoot_cooldown == 0:
shoot()
shoot_cooldown = 15
Showcase
Laat je spel zien aan een coach. Hoe snel maak jij alle vijanden weg? Vergelijk scores met een buddy.
Tot de volgende keer!
“Volgende keer: twee spelers, één bal: PONG. En je leert echte pygame zonder pgzrun.”
Neem mee naar huis
- Makkelijk: verander de kleur van de kogels of de vijanden.
- Middel: laat vijanden links en rechts bewegen (één richting per stap, keer om aan de rand).
- Lastig: voeg een second wave toe: als alle vijanden weg zijn, spawn een nieuwe rij die sneller daalt.
- Erg lastig: laat vijanden ook terugschieten: willekeurig een kogel omlaag sturen elke N frames.
Bekijk de cheatsheet voor deze sessie
Dojo Defender
Download de Dojo Defender starter voor vandaag.
Was je er vorige keer niet bij? Download de oplossing van sessie 1 en begin daarmee.
Het volledige werkblad: Dojo Defender Sessie 2.
Sessie 4: Pong
Twee paddles, één bal: het klassieke Pong-spel. Maar er is een verrassing: deze sessie schrijf je het spel in echte pygame, zonder pgzrun. Je leert de game loop zelf Installeren. Dat is hoe de meeste echte games werken.
Wat je vandaag leert
- De pygame game loop: events, update, draw
pygame.Rect voor rechthoeken en botsingen- Bal laten stuiteren (snelheid omkeren)
- Score bijhouden voor twee spelers
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py. - Klik op Run. Je ziet twee paddles en een gele bal in het midden, maar de bal beweegt nog niet.
Verschil met pgzrun: Er zijn geen draw() en update() functies meer. Alles zit in één while running: loop.
Stap 1: Laat de bal bewegen
Zoek de regels:
# bal.x += ball_dx # zet dit aan als je klaar bent
# ball.y += ball_dy
Verwijder de # voor beide regels. Maar stel eerst een startsnelheid in. Zoek ball_dx, ball_dy = 0, 0 en verander naar:
Klik op Run. De bal beweegt nu, maar verdwijnt door de rand. Dat lossen we op in stap 2.
Stap 2: ✅ Basic: bal stuitert op muren en paddles
Voeg na ball.x += ball_dx en ball.y += ball_dy het volgende toe:
# Stuiteren op boven- en onderrand
if ball.top <= 0 or ball.bottom >= HEIGHT:
ball_dy = -ball_dy
# Stuiteren op paddles
if ball.colliderect(left_paddle) or ball.colliderect(right_paddle):
ball_dx = -ball_dx
De bal stuitert nu oneindig. Voeg ook grenzen toe voor de paddles zodat ze niet buiten het scherm gaan. Kijk naar de code die al in de starter staat.
Stap 3: ⭐ Stretch: score bijhouden
Als de bal links het scherm uitvalt, scoort de rechter speler. Als hij rechts uitvalt, scoort de linker:
# Bal uit links → rechts scoort
if ball.left <= 0:
score_right += 1
ball.center = (WIDTH // 2, HEIGHT // 2)
ball_dx = 4
# Bal uit rechts → links scoort
if ball.right >= WIDTH:
score_left += 1
ball.center = (WIDTH // 2, HEIGHT // 2)
ball_dx = -4
De score staat al in draw(). Controleer dat de variabelen kloppen.
Stap 4: 🔥 Expert: win-conditie en snelheid verhogen
Win bij 5 punten: Voeg een variabele won toe. Als een speler 5 bereikt, stop dan het spel:
if score_left >= 5:
won = "Links wint!"
if score_right >= 5:
won = "Rechts wint!"
Toon de winnaar op het scherm en stop de beweging.
Snelheid verhogen: Na elke rally wordt de bal een beetje sneller:
if ball.colliderect(left_paddle) or ball.colliderect(right_paddle):
ball_dx = -ball_dx * 1.05 # 5% sneller
ball_dy = ball_dy * 1.05
Bouw een maximum in: ball_dx = max(-12, min(12, ball_dx)).
Showcase
Speel een potje tegen een buddy. Eerste naar 5 punten wint. Laat het zien aan een coach.
Tot de volgende keer!
“Volgende keer: Breakout: de bal beukt stenen kapot. En er is GELUID.”
Neem mee naar huis
- Makkelijk: verander de kleur van de bal of de paddles.
- Middel: maak één paddle groter naarmate die speler verliest (handicap).
- Lastig: voeg een AI-tegenstander toe: de rechter paddle volgt automatisch de bal.
- Erg lastig: voeg power-ups toe: een item dat de bal verdubbelt of de paddle groter maakt.
Dojo Defender
Vandaag verhuist Dojo Defender naar echte Pygame!
Download de starter.
Was je er niet bij? Download de oplossing van sessie 2.
Werkblad: Dojo Defender Sessie 3.
Bekijk de cheatsheet voor deze sessie
Sessie 5: Breakout
Een bal kaatst heen en weer en beukt rijen gekleurde stenen kapot. Jij bestuurt de paddle om de bal in de lucht te houden. En deze keer hoor je het ook: er zijn geluidseffecten bij elke botsing.
Wat je vandaag leert
- Geluid laden en afspelen met
pygame.mixer - Botsingen met meerdere objecten (lijst van stenen)
- De bal laten stuiteren in de juiste richting
- Win- en verlies-scherm bouwen
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py. - Klik op Run. Je ziet de paddle, de bal en de stenen. De bal beweegt al horizontaal maar niet verticaal. Dat ga jij aanpassen.
Stap 1: Laat de bal verticaal bewegen
Zoek deze regel in de starter:
ball_dx, ball_dy = 4, 0
# ball_dy = -4 ← verwijder de # om de bal te laten bewegen!
Verwijder de # voor ball_dy = -4. Nu heeft de bal een verticale snelheid. Voeg beweging toe in de game loop (zoek de update-sectie):
ball.x += ball_dx
ball.y += ball_dy
Klik op Run. De bal beweegt diagonaal maar verdwijnt door de randen.
Stap 2: ✅ Basic: bal stuitert op muren en paddle
Voeg stuiteren toe:
# Boven-, links- en rechtsrand
if ball.left <= 0 or ball.right >= WIDTH:
ball_dx = -ball_dx
if ball.top <= 0:
ball_dy = -ball_dy
# Paddle
if ball.colliderect(paddle):
ball_dy = -ball_dy
if snd_hit:
snd_hit.play()
Levens: Als de bal de onderkant bereikt, verlies je een leven:
if ball.top > HEIGHT:
levens -= 1
# Reset bal bovenop de paddle
ball.center = (paddle.centerx, paddle.top - BALL_SIZE)
ball_dy = -4
Stap 3: ⭐ Stretch: stenen breken
Controleer collision met elke steen in de loop:
for steen in stenen[:]:
if ball.colliderect(steen['rect']):
stenen.remove(steen)
ball_dy = -ball_dy
score += 10
if snd_hit:
snd_hit.play()
break # slechts één steen per frame breken
Win-conditie: Als alle stenen weg zijn, heeft de ninja gewonnen. Toon een bericht:
if not stenen:
# toon win-scherm
Stap 4: 🔥 Expert: levens, explosiegeluid en snelheid
Explosiegeluid als een steen breekt (gebruik snd_explode uit de starter):
if snd_explode:
snd_explode.play()
Game over bij 0 levens: toon een scherm en stop de bal.
Snelheid verhogen naarmate er minder stenen overblijven:
snelheid_factor = 1 + (1 - len(stenen) / totaal_stenen) * 0.5
ball_dx_huidig = ball_dx * snelheid_factor
Nieuwe rij stenen als alles weg is: roep stenen = maak_stenen() opnieuw aan en verhoog de moeilijkheidsgraad.
Showcase
Wie haalt de meeste stenen weg? Vergelijk scores en laat je coach de hoogste streak zien.
Tot de volgende keer!
“Volgende keer: zwaartekracht. Jouw karakter valt, en jij moet hem laten springen op platforms.”
Neem mee naar huis
- Makkelijk: verander de kleuren van de stenen naar jouw favoriete kleuren.
- Middel: maak sommige stenen twee keer zo sterk (ze moeten tweemaal geraakt worden).
- Lastig: voeg een power-up toe die de paddle tijdelijk breder maakt.
- Erg lastig: voeg een tweede bal toe die spawnt als score > 50.
Bekijk de cheatsheet voor deze sessie
Dojo Defender
Dojo Defender krijgt een menu en nieuwe vijandtypes!
Download de starter.
Was je er niet bij? Download de oplossing van sessie 3.
Werkblad: Dojo Defender Sessie 4.
In deze sessie bouw je een micro-platformer. Je speler heeft zwaartekracht, kan springen, en verzamelt sterren op platforms. Je gebruikt voor het eerst pygame direct, zonder pgzrun, en voegt geluidseffecten toe met pygame.mixer.
Wat je vandaag leert
- Zwaartekracht simuleren met een
vel_y variabele - Springen door
vel_y negatief te maken - Platformbotsingen detecteren met
pygame.Rect - Items verzamelen (collision met sterren)
- Geluiden afspelen met
pygame.mixer
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py in Thonny. - Klik op de groene Run-knop. Je ziet een venster met een speler, platforms en sterren, maar de speler valt nog niet.
- Problemen? Vraag een coach.
Stap 1: Zwaartekracht
In een platformer valt de speler continu naar beneden, tenzij hij op een platform staat. We simuleren dat met vel_y: een verticale snelheid die elke frame groter wordt door zwaartekracht.
Zoek de # STAP 1 comment in main.py en vervang de pass door:
# Zwaartekracht toepassen
vel_y += GRAVITY
player_rect.y += vel_y
# Controleer of speler op een platform staat
on_ground = False
for platform in platforms:
if (player_rect.colliderect(platform) and vel_y > 0):
player_rect.bottom = platform.top
vel_y = 0
on_ground = True
GRAVITY = 0.5 staat al bovenaan het bestand. Klik Run. De speler valt nu naar het dichtstbijzijnde platform en blijft daar staan.
Wat gebeurt hier? Elke frame wordt vel_y iets groter (de speler versnelt naar beneden). Als de speler een platform raakt terwijl hij naar beneden valt (vel_y > 0), zet je zijn onderkant (bottom) precies op de bovenkant van het platform en stop je de val (vel_y = 0).
Stap 2: ✅ Basic: springen
Een platformer zonder springen is maar half af. Druk op SPATIE om te springen: dat is niets anders dan vel_y plotseling negatief maken.
Zoek de # STAP 2 comment en voeg toe:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player_rect.x -= SPEED
if keys[pygame.K_RIGHT]:
player_rect.x += SPEED
# Springen — alleen als je op de grond staat
if keys[pygame.K_SPACE] and on_ground:
vel_y = -12
Klik Run en test:
- Pijltjestoetsen: beweeg links/rechts
- SPATIE: spring omhoog
Tip: Als de speling te hoog of te laag voelt, verander dan -12 in -10 (lager springen) of -15 (hoger springen).
Stap 3: ⭐ Stretch: sterren verzamelen
Laten we iets te verzamelen toevoegen. De starter heeft al een lijst stars met pygame.Rect-objecten. Jij schrijft de botsingsdetectie.
Zoek de # STAP 3 comment:
for star in stars[:]: # [:] zodat je veilig kunt verwijderen tijdens het loopen
if player_rect.colliderect(star):
stars.remove(star)
score += 1
En in de tekenfunctie (zoek # TEKEN STERREN):
for star in stars:
pygame.draw.polygon(screen, YELLOW, star_points(star.centerx, star.centery, 12, 5))
star_points() is al gedefinieerd in de starter. Die berekent de punten van een 5-puntige ster.
Bovenaan het spel staat score = 0. Teken de score op het scherm (zoek # TEKEN SCORE):
score_surf = font.render(f"Sterren: {score}", True, WHITE)
screen.blit(score_surf, (10, 10))
Stap 4: 🔥 Expert: geluid en win-scherm
Nu voeg je een springgeluid toe en een win-scherm als alle sterren verzameld zijn.
Geluid laden (dit staat al klaar in de starter; controleer dat jump.wav in de sounds/ map zit):
pygame.mixer.init()
jump_snd = pygame.mixer.Sound("sounds/jump.wav")
Geluid afspelen bij springen: voeg toe aan de sprong-code:
if keys[pygame.K_SPACE] and on_ground:
vel_y = -12
jump_snd.play()
Win-scherm: voeg toe na de ster-loop:
if len(stars) == 0:
win_surf = font.render("Gewonnen! Alle sterren verzameld!", True, YELLOW)
screen.blit(win_surf, (WIDTH // 2 - win_surf.get_width() // 2, HEIGHT // 2))
pygame.display.flip()
pygame.time.wait(3000)
running = False
Showcase
Laat je spel zien aan een coach en een buddy. Kun je alle sterren verzamelen voor de tijd om is?
Dojo Defender
De Dojo Defender snapshot van vandaag bouwt verder op sessie 5:
- Parallax sterrenachtergrond — drie lagen sterren met eigen snelheid
- Particle effects — uitlaatgassen, explosiepuin, vonkjes
- Vernietigbare asteroïden — big → med → small → weg
Download de Dojo Defender starter of oplossing.
Tot de volgende keer!
“Volgende keer: klik op bugs en ZAP ze weg, met je eigen klassen.”
Neem mee naar huis
Probeer thuis één van deze uitbreidingen:
- Makkelijk: verander de kleur van de speler als hij in de lucht is.
- Middel: voeg een timer toe. De speler heeft 30 seconden om alle sterren te verzamelen.
- Lastig: voeg een vijand toe die heen en weer loopt op een platform; als de speler hem raakt, herstart het spel.
- Erg lastig: laat de speler dubbel springen (twee keer SPATIE voor een tweede sprong in de lucht).
Vastgelopen? Vraag het volgende dojo aan een coach, of probeer gewoon iets anders. Programmeren is doen.
Bekijk de cheatsheet voor deze sessie
Sessie 7: Bug Zapper
Bugs vallen van boven naar beneden. Jij schiet omhoog om ze te raken. In deze sessie leer je OOP: je schrijft je eerste eigen klasse (Bug), en daarna twee subklassen: een die slingert en een die op je duikt. Klassen zijn de bouwstenen van bijna alle grote programma’s.
Wat je vandaag leert
- Een klasse schrijven met
__init__ en eigen methoden - Overerving: een subklasse die een bestaande klasse uitbreidt
- Bullets (kogels) bijhouden in een lijst
- Botsingsdetectie tussen kogels en bugs
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py in Thonny. - Klik op Run. Je ziet een scherm met een speler onderaan, maar nog geen bugs en geen kogels.
- Problemen? Vraag een coach.
Stap 1: Bugs spawnen en schieten
De Bug-klasse
Zoek de # STAP 1 — BUG KLASSE comment en schrijf:
class Bug:
def __init__(self, x, y):
self.x = x
self.y = y
self.alive = True
def update(self):
self.y += 2 # valt naar beneden
def draw(self, screen):
pygame.draw.circle(screen, GREEN, (int(self.x), int(self.y)), 15)
# Ogen
pygame.draw.circle(screen, BLACK, (int(self.x) - 5, int(self.y) - 4), 3)
pygame.draw.circle(screen, BLACK, (int(self.x) + 5, int(self.y) - 4), 3)
Bugs laten spawnen: de starter heeft al een timer. Zoek # SPAWN BUG:
bugs.append(Bug(random.randint(30, WIDTH - 30), -20))
Schieten: zoek # SCHIET (dit staat in de event-loop bij K_SPACE):
bullets.append(pygame.Rect(player_x - 3, player_y - 20, 6, 12))
Update bullets elke frame (zoek # UPDATE BULLETS):
for b in bullets[:]:
b.y -= 10
if b.y < 0:
bullets.remove(b)
pygame.draw.rect(screen, YELLOW, b) # dit staat al klaar
Stap 2: ✅ Basic: bugs raken
Nu schrijf je de botsingsdetectie: als een kogel een bug raakt, sterft de bug.
Zoek # STAP 2 — BOTSING:
for bug in bugs[:]:
bug.update()
bug.draw(screen)
if bug.y > HEIGHT + 20:
bugs.remove(bug)
continue
bug_rect = pygame.Rect(bug.x - 15, bug.y - 15, 30, 30)
for bullet in bullets[:]:
if bullet.colliderect(bug_rect):
bug.alive = False
bullets.remove(bullet)
score += 1
break
if not bug.alive:
bugs.remove(bug)
Klik Run. Schiet op de bugs: ze verdwijnen bij een treffer!
Stap 3: ⭐ Stretch: SlingerBug
Nu maak je een subklasse: een Bug die heen en weer slingert.
import math
class SlingerBug(Bug):
def __init__(self, x, y):
super().__init__(x, y)
self.start_x = x
self.timer = 0
def update(self):
self.timer += 0.05
self.x = self.start_x + math.sin(self.timer) * 60
self.y += 1.5 # iets langzamer, maar moeilijker te raken
def draw(self, screen):
super().draw(screen)
# Oranje cirkel eromheen als visuele aanwijzing
pygame.draw.circle(screen, ORANGE, (int(self.x), int(self.y)), 18, 2)
Spawnen van SlingerBugs: voeg toe aan de spawn-code (bijv. elke 3e bug):
if random.random() < 0.3:
bugs.append(SlingerBug(random.randint(30, WIDTH - 30), -20))
else:
bugs.append(Bug(random.randint(30, WIDTH - 30), -20))
super().__init__(x, y) roept de __init__ van de ouderklas (Bug) aan, dus je hoeft self.x, self.y en self.alive niet opnieuw te schrijven.
Stap 4: 🔥 Expert: DuikBug
De DuikBug detecteert de positie van de speler en duikt er recht op af.
class DuikBug(Bug):
def __init__(self, x, y, player_x_ref):
super().__init__(x, y)
self.player_x_ref = player_x_ref # functie die huidige speler-x geeft
self.speed_x = 0
self.speed_y = 1
def update(self):
target_x = self.player_x_ref()
dx = target_x - self.x
dist = max(abs(dx), 1)
self.x += dx / dist * 2
self.y += 2.5
def draw(self, screen):
super().draw(screen)
pygame.draw.circle(screen, RED, (int(self.x), int(self.y)), 18, 2)
Spawnen: gebruik een lambda om de speler-x door te geven:
bugs.append(DuikBug(random.randint(30, WIDTH - 30), -20, lambda: player_x))
Bonus: Teken een HP-balk. Start met lives = 3 en trek er één af als een bug de onderkant haalt.
Showcase
Laat je spel zien aan een coach en een buddy. Hoeveel bugs kun je neerzappen voor je levens op zijn?
Tot de volgende keer!
“Volgende keer: een oneindige weg in de lucht, en alles SCROLT voorbij.”
Neem mee naar huis
Probeer thuis één van deze uitbreidingen:
- Makkelijk: maak bugs groter of sneller naarmate de score oploopt.
- Middel: voeg een
lives-systeem toe met 3 levens, en als een bug de onderkant haalt, verlies je er één. - Lastig: schrijf een
PantserbBug die 3 treffers nodig heeft voor hij sterft (gebruik een hp-attribuut). - Erg lastig: voeg muisbesturing toe: de speler beweegt naar de muispositie en schiet automatisch elke 0,5 seconde.
Vastgelopen? Vraag het volgende dojo aan een coach, of probeer gewoon iets anders. Programmeren is doen.
Dojo Defender: Eindbaas
Deze sessie bouw je ook verder aan Dojo Defender. Je voegt een eindbaas (boss) toe die om de 5 waves verschijnt met 3 fases.
Bekijk de Dojo Defender sessie 6 voor de instructies.
De starter en oplossing staan klaar.
Bekijk de cheatsheet voor deze sessie
Sessie 8: Sky Highway
Je schip vliegt door een eindeloze luchtweg. De achtergrond scrolt langs je heen, rode obstakels komen van rechts, en sterren geven punten. Hoe langer je overleeft, hoe sneller het wordt!
Wat je vandaag leert
- Een scrollende achtergrond maken met een
scroll_x variabele - Objecten spawnen die van rechts naar links bewegen
- Botsingsdetectie met levens
- Moeilijkheidsscaling: snelheid verhogen naarmate de score stijgt
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py in Thonny. - Klik op Run. Je ziet een statisch scherm met een schip en een luchtachtergrond, maar niks beweegt nog.
- Problemen? Vraag een coach.
Een scrollende achtergrond geeft de illusie van beweging. We tekenen de achtergrond twee keer naast elkaar en schuiven de positie elke frame op.
Zoek # STAP 1 en voeg toe:
# Beweeg achtergrond naar links
scroll_x -= speed
if scroll_x <= -WIDTH:
scroll_x = 0
# Teken achtergrond twee keer
screen.blit(bg_image, (int(scroll_x), 0))
screen.blit(bg_image, (int(scroll_x) + WIDTH, 0))
scroll_x begint op 0 en wordt elke frame kleiner. Als het -WIDTH bereikt, springen we terug naar 0: een naadloze loop.
Klik Run. De lucht scrolt nu voorbij je schip!
Stap 2: ✅ Basic: obstakels en levens
Obstakels komen van rechts en bewegen naar links. Als je ze raakt, verlies je een leven.
Obstakels updaten (zoek # STAP 2):
for obs in obstacles[:]:
obs.x -= speed
if obs.x < -obs.width:
obstacles.remove(obs)
pygame.draw.rect(screen, RED, obs)
# Botsing
if ship_rect.colliderect(obs):
obstacles.remove(obs)
lives -= 1
if lives <= 0:
running = False
Levens tekenen:
for i in range(lives):
pygame.draw.rect(screen, RED, (10 + i * 25, 10, 18, 18))
Obstakels spawnen (in de spawn-timer-event):
h = random.randint(40, 120)
obstacles.append(pygame.Rect(WIDTH, random.randint(50, HEIGHT - h - 50), 30, h))
Stap 3: ⭐ Stretch: sterren verzamelen
Sterren geven punten en verdwijnen als je ze raakt.
Zoek # STAP 3:
for star in stars[:]:
star.x -= speed
if star.x < -20:
stars.remove(star)
continue
pygame.draw.circle(screen, YELLOW, star.center, 10)
if ship_rect.colliderect(star):
stars.remove(star)
score += 1
# Score tekenen:
score_surf = font.render(f"Score: {score}", True, WHITE)
screen.blit(score_surf, (WIDTH - 120, 10))
Spawnen van sterren (in dezelfde spawn-timer, maar minder vaak):
if random.random() < 0.4:
stars.append(pygame.Rect(WIDTH, random.randint(40, HEIGHT - 40), 20, 20))
Stap 4: 🔥 Expert: spawnen en snelheid schalen
Nu maak je de game steeds moeilijker naarmate de score stijgt.
Snelheid schalen (zoek # STAP 4):
speed = BASE_SPEED + score * 0.1
BASE_SPEED = 4 staat al bovenaan. Bij score 20 gaat alles dubbel zo snel!
Spawn-interval aanpassen: hoe hoger de score, hoe vaker nieuwe obstakels komen:
spawn_interval = max(500, 1800 - score * 30) # min. 500ms
pygame.time.set_timer(SPAWN_EVENT, spawn_interval)
Game over scherm:
if not running:
go_surf = font.render("GAME OVER", True, RED)
screen.blit(go_surf, (WIDTH // 2 - go_surf.get_width() // 2, HEIGHT // 2 - 30))
sc_surf = font.render(f"Score: {score}", True, WHITE)
screen.blit(sc_surf, (WIDTH // 2 - sc_surf.get_width() // 2, HEIGHT // 2 + 10))
pygame.display.flip()
pygame.time.wait(3000)
Showcase
Laat je spel zien aan een coach en een buddy. Wie haalt de hoogste score?
Tot de volgende keer!
“Volgende keer: een baas die terugvecht, in DRIE fases.”
Neem mee naar huis
Probeer thuis één van deze uitbreidingen:
- Makkelijk: voeg een tweede soort obstakel toe (bijv. een blauw obstakel dat hoger of lager vliegt).
- Middel: voeg power-ups toe. Vang een groene capsule voor een tijdelijk schild (het schip kan 1 keer geraakt worden).
- Lastig: laat het schip omhoog en omlaag bewegen met de pijltjestoetsen én begrens het scherm zodat het schip er niet uit vliegt.
- Erg lastig: voeg parallax-scrolling toe: een tweede laag achtergrond (wolken) die langzamer scrolt dan de eerste laag.
Vastgelopen? Vraag het volgende dojo aan een coach, of probeer gewoon iets anders. Programmeren is doen.
Dojo Defender: Jouw eigen versie
Vandaag werk je ook verder aan Dojo Defender — maar niet met stap-voor-stap instructies. Jij kiest wat je bouwt.
Download de Dojo Defender starter — dit is de complete game met alles erop en eraan (schip, vijanden, asteroïden, waves, boss). Kies een feature uit de lijst, plan hem kort met een coach, en ga aan de slag.
👉 Alles over Dojo Defender vind je op de Dojo Defender pagina.
Bekijk de cheatsheet voor deze sessie
Sessie 9: Boss Battle
De eindbaas wacht op je. Hij beweegt heen en weer, schiet kogels en wordt steeds gevaarlijker naarmate zijn HP daalt. Jij schiet terug, houdt zijn HP bij op een balk, en overleeft drie fasen. Dit is de moeilijkste sessie, en de meest bevredigende als je hem haalt.
Wat je vandaag leert
- Een HP-balk tekenen op het scherm
- Een state machine: de baas gedraagt zich anders per fase
- De baas laten schieten met een kogeltimer
- Fasen activeren op HP-drempelwaarden
Stap 0: Installeren
- Open Thonny.
- Download de starter via deze link, pak de ZIP uit en open
main.py in Thonny. - Klik op Run. Je ziet de baas bovenaan, jouw schip onderaan. Geen movement, geen kogels nog.
- Problemen? Vraag een coach.
Stap 1: Baas laten bewegen
De baas beweegt heen en weer over het scherm. Als hij de rand raakt, keert hij om.
Zoek # STAP 1 en voeg toe:
boss_rect.x += boss_speed
# Omdraaien bij de rand
if boss_rect.right >= WIDTH or boss_rect.left <= 0:
boss_speed = -boss_speed
boss_speed = 3 staat al bovenaan. Klik Run: de baas dendert van links naar rechts!
Speler bewegen en schieten (zoek # SPELER):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player_rect.left > 0:
player_rect.x -= PLAYER_SPEED
if keys[pygame.K_RIGHT] and player_rect.right < WIDTH:
player_rect.x += PLAYER_SPEED
# Schiet (zoek # SCHIET in event-loop):
player_bullets.append(pygame.Rect(player_rect.centerx - 3, player_rect.top - 15, 6, 15))
Stap 2: ✅ Basic: baas raken en HP-balk
Botsing speler-kogel met baas:
Zoek # STAP 2:
for b in player_bullets[:]:
b.y -= 8
if b.y < 0:
player_bullets.remove(b)
continue
pygame.draw.rect(screen, YELLOW, b)
if b.colliderect(boss_rect):
player_bullets.remove(b)
boss_hp -= 1
if boss_hp <= 0:
running = False # speler wint!
HP-balk tekenen (zoek # HP BALK):
# Achtergrond van de balk
pygame.draw.rect(screen, DARK_RED, (10, 10, 300, 20))
# Gevulde balk op basis van huidige HP
breedte = int(300 * boss_hp / BOSS_MAX_HP)
pygame.draw.rect(screen, RED, (10, 10, breedte, 20))
# Label
hp_surf = font.render(f"Baas HP: {boss_hp}", True, WHITE)
screen.blit(hp_surf, (320, 10))
Klik Run. Schiet op de baas: de HP-balk slinkt!
Stap 3: ⭐ Stretch: baas schiet terug
De baas schiet elke N frames een kogel naar beneden.
Zoek # STAP 3:
boss_shoot_timer += 1
if boss_shoot_timer >= boss_shoot_interval:
boss_shoot_timer = 0
boss_bullets.append(pygame.Rect(boss_rect.centerx - 4, boss_rect.bottom, 8, 16))
Baas-kogels updaten:
for b in boss_bullets[:]:
b.y += 6
if b.y > HEIGHT:
boss_bullets.remove(b)
continue
pygame.draw.rect(screen, ORANGE, b)
if b.colliderect(player_rect):
boss_bullets.remove(b)
player_lives -= 1
if player_lives <= 0:
running = False
Teken player_lives als hartjes of rode blokjes onderaan het scherm.
Stap 4: 🔥 Expert: drie fases
Nu reageert de baas op zijn HP:
- Fase 1 (HP 100 tot 50): normaal gedrag
- Fase 2 (HP 50 tot 25): sneller bewegen, vaker schieten
- Fase 3 (HP < 25): maximale snelheid, dubbele kogels
Zoek # STAP 4:
if boss_hp > 50:
boss_phase = 1
boss_speed_abs = 3
boss_shoot_interval = 60
elif boss_hp > 25:
boss_phase = 2
boss_speed_abs = 5
boss_shoot_interval = 35
else:
boss_phase = 3
boss_speed_abs = 7
boss_shoot_interval = 20
# Pas de snelheid aan zonder de richting te wisselen:
boss_speed = boss_speed_abs * (1 if boss_speed > 0 else -1)
Fase 3: dubbele kogels (voeg toe in de shoot-code):
if boss_phase == 3:
boss_bullets.append(pygame.Rect(boss_rect.left + 10, boss_rect.bottom, 8, 16))
boss_bullets.append(pygame.Rect(boss_rect.right - 18, boss_rect.bottom, 8, 16))
else:
boss_bullets.append(pygame.Rect(boss_rect.centerx - 4, boss_rect.bottom, 8, 16))
Win-scherm bij boss_hp <= 0:
screen.fill(BLACK)
win = font.render("BAAS VERSLAGEN!", True, YELLOW)
screen.blit(win, (WIDTH // 2 - win.get_width() // 2, HEIGHT // 2))
pygame.display.flip()
pygame.time.wait(3000)
Showcase
Laat je spel zien aan een coach en een buddy. Wie haalt fase 3 en overleeft?
Tot de volgende keer!
“Volgende keer: jouw eigen spel, van nul, helemaal jouw idee.”
Neem mee naar huis
Probeer thuis één van deze uitbreidingen:
- Makkelijk: verander de kleur van de baas per fase (groen → oranje → rood).
- Middel: voeg een score toe: hoe sneller je de baas verslaat, hoe meer punten.
- Lastig: laat de baas in fase 2 ook diagonale kogels schieten (schuin links en rechts).
- Erg lastig: voeg een tweede speler toe die mee kan doen met WASD-toetsen.
Vastgelopen? Vraag het volgende dojo aan een coach, of probeer gewoon iets anders. Programmeren is doen.
Bekijk de cheatsheet voor deze sessie
Sessie 10: Mijn Spel
Dit is jouw sessie. Geen vaste stappen, geen verplichte mechanics. Jij beslist wat je bouwt, en vandaag maak je het.
Jouw spel, jouw regels
In negen sessies heb je geleerd:
- Variabelen, functies en game loops
- Toetsenbord- en muisinput
- Sprites, collision detection en score
- Geluid en animatie
- Klassen en overerving
- Scrollende achtergronden, spawnen en moeilijkheidsscaling
- HP-balken, state machines en baas-AI
Al die bouwstenen liggen klaar. Vandaag combineer je ze in je eigen spel.
Kies je concept
Nog geen idee? Hier zijn wat genres om van te starten:
Dodge-game: wijk objecten uit die steeds sneller komen. Simpel maar verslavend.
Platformer: spring van platform naar platform, verzamel items, vermijd vijanden.
Shooter: schiet vijanden neer die van boven of van de zijkant komen.
Puzzelgame: schuif blokjes, verbind punten, of los een patroon op.
Racegame: ontwerp een parcours en beweeg zo snel mogelijk naar de finish.
Vertel een verhaal: geen score, geen levens. Laat de speler klikken en keuzes maken.
Je mag ook iets combineren: een shooter met puzzelelementen, een platformer met een baas aan het einde. Alles mag.
Plan je spel
Vóór je code schrijft, beantwoord deze drie vragen:
- Wat doet de speler? (bewegen, schieten, springen, klikken, …)
- Wat is het doel? (score halen, de baas verslaan, het einde bereiken, …)
- Wat maakt het moeilijk? (vijanden, obstakels, een timer, …)
Schrijf je antwoorden op een papiertje of in een comment bovenaan je code. Dit helpt je gefocust te blijven als je vastloopt.
Animatie: sprite wisselen per frame
Wil je een loopanimatie, een explosie of een knipperend object? Maak een lijst met afbeeldingsnamen en wissel actor.image elke N milliseconden. De demo hieronder laat zien hoe dat werkt: gebruik de schuifbalk om de snelheid aan te passen en de knop om te pauzeren:
In Python gebruik je dan een lijst met afbeeldingsnamen en een timer:
frames = ['lopen_1', 'lopen_2', 'lopen_3', 'lopen_4']
anim_timer = 0
FRAME_DUUR = 10 # frames (bij 60 fps = ~167 ms)
def update():
global anim_timer
anim_timer += 1
speler.image = frames[(anim_timer // FRAME_DUUR) % len(frames)]
Aan de slag
Download de starter via deze link. De starter heeft:
- Een werkende pygame game loop
- Een lege
draw()- en update()-sectie - Kleur-constanten en een lettertypevariabele klaar
- Comments die aangeven waar je wat kunt plaatsen
Open main.py en begin met Stap 1 van je eigen plan. De cheatsheet op deze pagina heeft alle patronen van de vorige sessies bij de hand.
Vastgelopen? Vraag een coach. Beschrijf wat je wilt bereiken, niet alleen wat niet werkt. Dan kunnen we samen de beste aanpak bedenken.
Te snel klaar? Voeg geluid toe, maak een start-scherm, of voeg een tweede speler toe.
Showcase
Aan het einde van de sessie presenteert iedereen zijn spel. Je hoeft het niet af te hebben. Laat zien wat je gemaakt hebt en vertel:
- Wat is het concept van je spel?
- Welke techniek uit een vorige sessie heb je gebruikt?
- Wat zou je nog willen toevoegen als je meer tijd had?
Wat nu?
CoderDojo stopt na tien sessies. Zelf bouwen stopt niet.
Blijf bouwen. Kleine projectjes leren je meer dan grote cursussen. Maak een spel voor je broer of zus, je huisdier, of gewoon voor jezelf.
Inspiratie nodig?
CoderDojo komt terug. Jij ook?
Blijf bouwen!
Bekijk de cheatsheet voor deze sessie
Subsecties van Git sessies
Sessie 11: Git: Jouw code-geschiedenisboek
Stel je voor: je werkt drie uur aan je game. Je voegt een cool nieuw wapen toe. Maar… nu doet de rest van je game het niet meer. En je weet niet meer wat je precies veranderd hebt. Weg drie uur werk.
Git is de oplossing. Git onthoudt élke versie van je bestanden. Als een oneindige “undo”-knop die nooit vergeet wat je gedaan hebt.
In deze sessie installeer je Git, maak je je eerste repository en leg je voor altijd vast wat je doet: stap voor stap, versie voor versie. En het leuke: Git werkt niet alleen voor code. Ook voor notities, schoolverslagen en verhalen.
Wat is Git?
Git is een versiebeheersysteem. Het houdt bij wat jij verandert in je bestanden, wanneer je dat deed, en waarom. Elke keer dat je een stukje werk af hebt, maak je een commit: een foto van al je bestanden op dat moment.
Wat Git bijzonder maakt:
- Elke versie is bewaard. Je kunt altijd terug naar een vorige commit als iets kapot gaat.
- Je werkt lokaal. Git draait op jouw computer. Geen internet nodig.
- Git is snel. Zelfs projecten met duizenden bestanden controleren in milliseconden.
Git is gemaakt door Linus Torvalds, dezelfde persoon die Linux bouwde. Hij had iets nodig om met duizenden programmeurs tegelijk aan de Linux-kernel te werken. In 2005 bouwde hij Git in een weekend. Vandaag gebruikt bijna elke ontwikkelaar ter wereld het.
Git is niet alleen voor code
Git is gebouwd voor broncode, maar het werkt met alle tekstbestanden. Een tekstbestand is elk bestand dat je met Kladblok of een simpele editor kunt openen en lezen: .py, .html, .css, .json, .txt, .csv, .md (Markdown), .yml, .toml, noem maar op.
Wat Git níet goed kan: binaire bestanden. Dat zijn bestanden die niet uit leesbare tekst bestaan: afbeeldingen (.png, .jpg), video’s (.mp4), gecompileerde programma’s (.exe), Word-documenten (.docx). Git kan ze wél bijhouden, maar het is trager en je kunt niet zien wát er precies veranderd is. Bij tekstbestanden toont git diff elke letter die je toevoegde of weghaalde. Bij een .png zegt Git alleen “dit bestand is gewijzigd”, maar niet wát er aan de afbeelding veranderde.
Markdown en notities
Veel notitie-apps van tegenwoordig gebruiken Markdown (.md-bestanden) om je documenten op te slaan. Denk aan:
- Obsidian: je notities zijn gewoon
.md-bestanden in een map op je computer - Notion: exporteert naar Markdown
- Joplin: slaat alles op als Markdown
- Typora, Zettlr, Logseq: allemaal Markdown-gebaseerd
Omdat Markdown-bestanden gewone tekstbestanden zijn, kun je er Git op loslaten. Je houdt de geschiedenis van je notities bij, je kunt terug naar een vorige versie van een document, en je kunt je notities delen via GitHub, precies zoals je met code doet.
Een map met Markdown-notities onder Git zetten is even simpel als een Python-project:
mkdir mijn-notities
cd mijn-notities
git init
echo "# Mijn Notities" > start.md
git add start.md
git commit -m "Eerste notitie: startpagina"
Vanaf dat moment bewaart Git elke wijziging aan je notities. Schrijf je een verslag voor school in Markdown? Commit elke paragraaf. Werk je aan wereldbouw voor een verhaal? Git onthoudt elke versie van je plot.
Wanneer Git wél en níet voor notities gebruiken
| Wél Git gebruiken | Beter iets anders |
|---|
Notities in Markdown (.md) | Notities in Word (.docx) |
Configuratiebestanden (.json, .yml) | Grote afbeeldingen of video’s bij je notities |
| Schrijfwerk: verslagen, verhalen, blogs | Realtime samenwerking zoals Google Docs (daar is Git te traag voor) |
| Je CoderDojo-cheatsheets | Wachtwoorden of persoonlijke dagboeken (tenzij private repo) |
Kortom: alles wat tekst is, kun je in Git stoppen. Alles wat binair is, beter niet.
Waarom versiebeheer?
Zonder Git ziet je workflow er zo uit:
game.py
game_backup.py
game_backup2.py
game_final.py
game_final_echt.py
game_final_echt_nieuwe_wapens.py
Herkenbaar? Met Git heb je maar één bestand nodig: game.py. Git onthoudt de rest.
Wat versiebeheer je oplevert:
- Nooit meer werk kwijt. Alles wat je commit, blijft bestaan. Altijd.
- Begrijpen wat er gebeurd is. Je ziet exact welke regels je wanneer veranderde.
- Experimenteren zonder risico. Maak een aparte kopie van je code (een branch), probeer iets geks, en gooi het weg als het niet werkt. Je originele code blijft intact.
- Samenwerken. Meerdere mensen kunnen tegelijk aan hetzelfde project werken, zonder elkaars code te overschrijven.
Wat stop je NIET in Git?
Git is gemaakt voor tekstbestanden: bestanden die jij zelf schrijft: code, notities, configuratie. Er zijn dingen die je beter buiten Git houdt:
| Stop wél in Git | Stop NIET in Git |
|---|
Je Python-bestanden (.py) | Wachtwoorden, API-sleutels, tokens |
| Afbeeldingen die je game gebruikt | Bestanden die je programma zelf maakt (.exe, .pyc) |
Geluidsbestanden (.wav, .mp3) | De __pycache__ map |
| Tekstbestanden, configuratie | Grote bestanden (>50 MB) zoals video’s |
Je README.md | Instellingen van jouw specifieke computer |
Waarom geen wachtwoorden in Git? Omdat Git álles onthoudt, voor altijd. Zelfs als je later een wachtwoord verwijdert, zit het nog in de geschiedenis. Iedereen die jouw code ooit ziet, kan terugscrollen naar die commit. En als je code ooit op GitHub komt, staat je wachtwoord op het internet. Voor eeuwig.
Gebruik een .gitignore-bestand om Git te vertellen welke bestanden het moet negeren. Daar kom je zo meteen achter.
Stap 0: Git installeren
Windows
- Ga naar git-scm.com en download de Windows-installer.
- Dubbelklik het gedownloade bestand.
- Klik door de installatie. De standaardopties zijn prima.
- Belangrijk: kies bij het kiezen van de teksteditor Nano of Notepad++ (niet Vim, tenzij je Vim al kent).
- Open na de installatie Git Bash (zoek ernaar in het startmenu).
Mac
Open de Terminal (zoek naar “Terminal” in Spotlight) en typ:
Als Git niet geïnstalleerd is, vraagt macOS je om de developer tools te installeren. Klik op “Install”. Klaar.
Linux (Ubuntu/Debian)
Controleren of het werkt
Open een terminal (Git Bash op Windows) en typ:
Je ziet iets als git version 2.47.0. Dat betekent: Git staat klaar.
Stap 1: Vertel Git wie je bent
Git wil weten wie jij bent, zodat het jouw naam bij elke commit kan zetten. Dit doe je één keer, daarna onthoudt Git het.
git config --global user.name "Jouw Naam"
git config --global user.email "jouw@email.com"
Gebruik hetzelfde e-mailadres dat je straks voor GitHub gebruikt. Dat maakt koppelen makkelijker.
Tip: --global betekent: deze instelling geldt voor ál je Git-projecten. Je hoeft dit maar één keer te doen.
Stap 2: Je eerste repository maken
Een repository (of “repo”) is een map waar Git de versies bijhoudt. Laten we er één maken.
Maak eerst een nieuwe map voor je project:
mkdir mijn-eerste-git-project
cd mijn-eerste-git-project
Nu vertel je Git: “Deze map is een repository.”
Je ziet: Initialized empty Git repository in .../mijn-eerste-git-project/.git/
Git heeft een verborgen map .git aangemaakt. Daar bewaart het álles: de geschiedenis, de commits, de configuratie. Raak die map nooit met de hand aan, want Git beheert hem zelf.
Stap 3: Je eerste bestand committen
Maak een bestand aan. Bijvoorbeeld een Python-bestand met één regel:
echo 'print("Hallo Git!")' > hallo.py
Nu vertel je Git: “Let op dit bestand.”
Met git add zet je bestanden in de staging area: een tussenstation. Je zegt tegen Git: “Deze wijzigingen wil ik in mijn volgende commit.”
Controleer wat er klaarstaat:
Git toont:
On branch master
Changes to be committed:
new file: hallo.py
Nu komt de commit zelf:
git commit -m "Mijn eerste commit: hallo.py toegevoegd"
Wat gebeurt hier? -m staat voor “message”. De tekst tussen aanhalingstekens is je commit message: een korte uitleg van wat je veranderd hebt. Git heeft nu een permanente foto van je project gemaakt.
Goede commit messages: Schrijf in het Engels (dat is de afspraak in bijna alle projecten). Begin met een werkwoord: “Add”, “Fix”, “Update”. Hou het kort: maximaal 72 karakters.
Stap 4: Veranderingen bijhouden
Open hallo.py in een teksteditor. Verander de regel naar:
print("Hallo Git! Jij onthoudt mijn code.")
Sla het bestand op. Kijk nu wat Git ziet:
Git weet dat hallo.py gewijzigd is. Maar wát is er precies veranderd?
git diff toont exact welke regels je toegevoegd (groen met +) en verwijderd (rood met -) hebt. Dit is één van de krachtigste dingen van Git: je ziet letterlijk wat er veranderd is, karakter voor karakter, sinds je laatste commit.
Commit de wijziging:
git add hallo.py
git commit -m "Update: begroeting uitgebreid"
Stap 5: Terug in de tijd
Dit is waar Git magisch wordt. Stel: je hebt spijt van je laatste wijziging. Je wilt terug naar de eerste versie.
Toon eerst alle commits:
Je ziet zoiets:
a1b2c3d Update: begroeting uitgebreid
e4f5g6h Mijn eerste commit: hallo.py toegevoegd
Elke commit heeft een unieke code, een hash. Die lange code (verkort tot 7 karakters) identificeert exact die ene versie van je project.
Om te zien hoe hallo.py eruitzag in de eerste commit:
git show e4f5g6h:hallo.py
Daar is je originele print("Hallo Git!") weer.
Wil je écht terug in de tijd? Dat kan:
git checkout e4f5g6h -- hallo.py
Nu staat hallo.py weer zoals in je eerste commit. Controleer met cat hallo.py. Je ziet de oude versie. Maar maak je geen zorgen: je tweede commit is niet weg. Met git checkout master -- hallo.py ga je weer naar de nieuwste versie.
Stap 6: Wat níet in Git: .gitignore
Maak een bestand aan dat Git moet negeren:
echo "GEHEIM_WACHTWOORD=12345" > geheimen.txt
git status toont dit bestand nu als “untracked”. Git heeft het gezien, maar weet niet of je het wilt bijhouden. Je kunt het negeren met een .gitignore-bestand:
echo "geheimen.txt" > .gitignore
Nu git status opnieuw en geheimen.txt is verdwenen uit de lijst. Git negeert het. (Voeg .gitignore zelf wél toe aan Git met git add .gitignore en git commit, zodat anderen ook weten wat er genegeerd moet worden.)
Een goed .gitignore voor een Python-project:
# Python
__pycache__/
*.pyc
*.pyo
# Geheimen
*.env
secrets.txt
# Jouw editor
.vscode/
.idea/
Showcase
Laat aan een coach en een buddy zien:
- Je repository met minstens 3 commits.
- Het resultaat van
git log --oneline: jouw commit-geschiedenis. - Een
git diff die toont wat je veranderd hebt. - Je
.gitignore-bestand.
Tot de volgende keer!
“Volgende keer: twee versies van je code tegelijk. Je werkt aan een nieuwe feature terwijl de oude versie gewoon blijft werken. Dat heet branches, en het is wat Git écht krachtig maakt.”
Neem mee naar huis
- Makkelijk: Maak een repository voor je notities. Zet een Markdown-bestand met wat je vandaag geleerd hebt in Git, en commit het.
- Middel: Verander iets in je code of notities, gebruik
git diff om de wijziging te bekijken, en commit hem met een goede message. - Lastig: Maak drie commits met verschillende wijzigingen. Gebruik
git show om elke versie te bekijken. Gebruik git checkout om terug te gaan naar de eerste commit, en daarna weer naar de laatste. - Erg lastig: Maak een Python-project met een goede
.gitignore. Zorg dat __pycache__/ en .pyc-bestanden écht genegeerd worden (check met git status).
Vastgelopen? Vraag het volgende dojo aan een coach, of probeer gewoon iets anders. Programmeren is doen. Git leren is doen.
Sessie 12: Git Branches: Parallelle universums voor je code
Vorige sessie leerde je commits maken: foto’s van je code op één tijdlijn. Alles netjes achter elkaar.
Maar wat als je een nieuw idee wil uitproberen? Een lasergun toevoegen aan je game, bijvoorbeeld. Je weet niet of het gaat werken. Je wil je werkende code niet kapot maken.
Daar zijn branches voor.
Een branch is een kopie van je code waar je vrij kunt experimenteren. Je hoofdcode (de master-branch) blijft veilig. Als je experiment werkt, plak je het terug in master. Werkt het niet? Je gooit de branch weg. Je master-branch heeft er nooit iets van gemerkt.
Noot: Op GitHub en in veel nieuwe projecten heet de hoofdbranch main in plaats van master. Dat is exact hetzelfde, alleen de naam is anders. In deze cursus gebruiken we master, maar als je online main tegenkomt, weet je dat het hetzelfde betekent.
Wat je vandaag leert
- Wat een branch is en hoe Git branches intern opslaat
- Branches aanmaken, wisselen en samenvoegen
- Wat een merge conflict is en hoe je het oplost
- Wanneer je wél en níet een branch moet gebruiken
Stap 0: Herhaling: waar sta je nu?
Open je terminal in het project van vorige sessie. Check waar je bent:
git status
git log --oneline
Je hebt een paar commits op master. Dit is je stabiele basis: hier ga je straks vanaf splitsen.
Stap 1: Je eerste branch
Je gaat een nieuwe feature toevoegen: een highscore.txt-bestand dat de hoogste score bijhoudt. Maar eerst maak je een branch:
git branch highscore-feature
Git heeft nu een nieuwe branch aangemaakt. Maar je staat nog steeds op master. Check welke branches er zijn:
Je ziet:
highscore-feature
* master
Het sterretje bij master betekent: “hier sta je nu.” Wissel naar je nieuwe branch:
git switch highscore-feature
(Oudere Git-versies gebruiken git checkout highscore-feature. Beide werken.)
Nog een keer git branch: het sterretje staat nu bij highscore-feature. Alles wat je nu commit, gebeurt op deze branch. master blijft onaangeroerd.
Tip: Je kunt een branch aanmaken en er meteen naartoe switchen in één commando:
git switch -c mijn-nieuwe-branch
-c staat voor “create”. Dit is sneller en je vergeet nooit te switchen.
Stap 2: Werk doen op een branch
Maak een nieuw bestand aan:
echo "HIGHSCORE: 0" > highscore.txt
Commit je werk:
git add highscore.txt
git commit -m "Add highscore.txt met beginwaarde 0"
Voeg nog een bestand toe dat de highscore leest:
echo 'def lees_highscore():' > highscore_manager.py
echo ' with open("highscore.txt") as f:' >> highscore_manager.py
echo ' return int(f.read().split(": ")[1])' >> highscore_manager.py
Commit opnieuw:
git add highscore_manager.py
git commit -m "Add highscore_manager: functie om highscore te lezen"
Kijk nu naar je log:
Je ziet al je commits van master, plus de twee nieuwe. Git onthoudt de hele keten.
Stap 3: Twee werelden tegelijk
Switch terug naar master:
Kijk wat er hier is:
highscore.txt en highscore_manager.py zijn… weg. Ze bestaan alleen op de highscore-feature-branch. Op master is alles nog precies zoals je het achterliet.
Dit is de magie van branches: twee (of meer) versies van je project, tegelijk op je computer, zonder dat ze elkaar in de weg zitten.
Switch nog eens heen en weer om het te voelen:
git switch highscore-feature # bestanden zijn terug
git switch master # bestanden zijn weer weg
Stap 4: Samenvoegen met git merge
Je highscore-feature werkt. Tijd om hem terug in master te zetten. Dit heet mergen.
Zorg dat je op master staat:
Voeg de branch samen:
git merge highscore-feature
Git toont iets als Updating a1b2c3d..e4f5g6h en Fast-forward. Je highscore-feature-commits zijn nu onderdeel van master. Controleer:
highscore.txt en highscore_manager.py staan nu op master. Alle commits van de feature-branch zijn opgenomen in de geschiedenis.
Stap 5: Wat zijn merge conflicts?
Stel: je hebt op master iets veranderd in highscore.txt, bijvoorbeeld “HIGHSCORE: 100” in plaats van “HIGHSCORE: 0”. En tegelijkertijd heb je op een andere branch highscore.txt ook veranderd, naar “HIGHSCORE: 500”.
Als je nu probeert te mergen, weet Git niet welke versie de juiste is. Dat is een merge conflict. Git vraagt jóu om te beslissen.
Laten we het expres uitlokken.
Op master:
echo "HIGHSCORE: 100" > highscore.txt
git add highscore.txt
git commit -m "Update highscore naar 100 op master"
Maak een nieuwe branch en verander daar hetzelfde bestand:
git switch -c andere-highscore
echo "HIGHSCORE: 500" > highscore.txt
git add highscore.txt
git commit -m "Update highscore naar 500"
Switch terug naar master en probeer te mergen:
git switch master
git merge andere-highscore
Git zegt: CONFLICT (content): Merge conflict in highscore.txt. Open highscore.txt in je editor. Je ziet:
<<<<<<< HEAD
HIGHSCORE: 100
=======
HIGHSCORE: 500
>>>>>>> andere-highscore
Dit zijn de twee versies. HEAD is jouw master-versie. Daaronder staat de versie van andere-highscore. Jij kiest welke je houdt, of je combineert ze.
Verwijder de markers en kies één versie:
Sla het bestand op. Vertel Git dat het conflict is opgelost:
git add highscore.txt
git commit -m "Merge: highscore van andere-highscore gekozen"
Conflict opgelost. Git kan weer verder.
Stap 6: Branches opruimen
Je feature is gemerged. De branch heb je niet meer nodig:
git branch -d highscore-feature
git branch -d andere-highscore
-d staat voor “delete”. Git weigert een branch te verwijderen die nog niet gemerged is: dat is een veiligheidsklep. Als je écht weg wil gooien zonder mergen, gebruik je -D (hoofdletter). Maar wees daar voorzichtig mee.
Wanneer wél een branch, wanneer niet?
| Wél een branch | Géén branch |
|---|
| Nieuwe feature die tijd kost | Typo in een comment fixen |
| Experiment waarvan je niet weet of het werkt | Kleine bugfix van één regel |
| Iets dat je werkende code kan breken | Je werkt alleen en je wijziging is duidelijk |
| Je werkt samen met anderen | (bij solo-werk is master vaak genoeg) |
Vuistregel: Als je twijfelt, maak een branch. Een branch kost niks. Code kwijtraken wel.
Tips om vlot te werken met branches
- Houd branches kort. Een branch van 3 uur is prima. Een branch van 3 weken wordt een merge-nachtmerrie: hoe langer je wacht met mergen, hoe meer er intussen op
master verandert, en hoe groter de kans op conflicts. - Eén ding per branch. “Highscore toevoegen” is een goede branch. “Highscore, menu, en nieuwe levels toevoegen” is te veel: split het op.
- Merge vaak. Werk je feature af, merge hem meteen terug naar
master. Kleine, frequente merges zijn makkelijker dan één groot monster-merge. - Geef branches duidelijke namen.
highscore-feature is goed. test123 of branch2 zijn slecht. Over een week weet je niet meer wat er in test123 zat. - Check waar je bent voor je begint.
git branch of git status vertelt je op welke branch je staat. Maak hier een gewoonte van, zodat je voorkomt dat je per ongeluk op master code schrijft die eigenlijk op een feature-branch hoort.
Showcase
Laat aan een coach en een buddy zien:
git branch met minstens twee branches (waaronder master).- Op elke branch een ander bestand of andere code.
- Switch heen en weer: de bestanden verschijnen en verdwijnen.
- Een succesvolle merge van een feature-branch in
master.
Tot de volgende keer!
“Tot nu toe leeft al je code alleen op jouw laptop. Volgende keer zetten we hem online. Je maakt een GitHub-account, pusht je repository naar het internet, en je game is overal ter wereld te bekijken. En: je kunt samenwerken met anderen. GitHub: je code de wereld in.”
Neem mee naar huis
- Makkelijk: Maak een branch voor een kleine feature in een bestaand project. Commit je werk en merge hem terug.
- Middel: Creëer expres een merge conflict (twee branches die hetzelfde bestand wijzigen) en los het op.
- Lastig: Werk met drie branches tegelijk op hetzelfde project. Merge ze één voor één terug in
master. Check na elke merge of alles nog werkt. - Erg lastig: Maak een branch, commit drie wijzigingen, switch terug naar
master, maak daar óók een wijziging in hetzelfde bestand, en merge de branch. Los het conflict zorgvuldig op en check met git log --graph hoe de geschiedenis eruitziet.
Sessie 13: GitHub: Je code online, voor iedereen
Tot nu toe leeft al je code op jouw laptop. Handig voor jou, maar niemand anders kan erbij. En als je laptop crasht, ben je alles kwijt.
GitHub is een website waar je Git-repositories online zet. Het is een back-up, een portfolio, en een samenwerkingsplatform in één. Vandaag zet je jouw code op GitHub. Aan het einde van deze sessie kan iedereen met een internetverbinding jouw projecten bekijken, en jij die van hen.
Wat is GitHub?
GitHub is niet hetzelfde als Git. Git is het versiebeheersysteem dat op jouw computer draait. GitHub is een website (github.com) die Git-repositories host: een soort Google Drive voor code, maar dan met Git eronder.
Wat GitHub toevoegt aan Git:
- Back-up in de cloud. Je code staat niet alleen lokaal. Laptop kapot? Je code overleeft.
- Samenwerken. Meerdere mensen kunnen aan dezelfde repo werken. GitHub regelt wie wat mag.
- Pull requests. Je vraagt toestemming om jouw wijzigingen in iemands project te stoppen, met discussie en review.
- Issues. Bugs melden, features voorstellen, taken bijhouden: allemaal in je repo.
- Portfolio. Je GitHub-profiel is je visitekaartje. Werkgevers kijken ernaar.
GitHub is niet de enige optie; er zijn alternatieven zoals GitLab en Bitbucket. Maar GitHub is de grootste, met meer dan 100 miljoen gebruikers. In deze sessies gebruiken we GitHub.
Stap 0: Een GitHub-account maken
- Open github.com in je browser.
- Klik op Sign up.
- Vul je e-mailadres in. Gebruik hetzelfde adres dat je in sessie 11 bij
git config hebt ingesteld: dat scheelt gedoe. - Kies een username. Dit wordt jouw identiteit op GitHub. Kies iets dat je over 5 jaar nog steeds leuk vindt. Je kunt je username later veranderen, maar oude links naar jouw profiel werken dan niet meer.
- Verifieer je account via de e-mail die GitHub stuurt.
- Kies het Free-abonnement. Alles wat je nodig hebt is gratis: onbeperkt publieke en private repositories.
Tip voor coaches: check of de ninjas toegang hebben tot hun e-mail tijdens de sessie. Sommige laptops staan niet ingelogd op webmail. Zorg voor een plan B: als e-mailverificatie niet lukt, kunnen ninjas GitHub later thuis verifiëren. De rest van de sessie werkt ook zonder verificatie.
Stap 1: Je eerste repository op GitHub
Je hebt een lokaal project op je computer (van sessie 11). Die ga je nu online zetten.
Op GitHub, klik rechtsboven op het + icoontje → New repository.
Vul in:
| Veld | Wat je invult |
|---|
| Repository name | mijn-eerste-git-project (zelfde als je lokale map) |
| Description | “Mijn eerste Git-project (CoderDojo sessie 11)” |
| Public / Private | Kies Public: anderen mogen je code zien |
| Initialize with README | NIET aanvinken: je hebt al een lokaal project |
Klik Create repository.
GitHub toont nu instructies. Kies het blok onder "…or push an existing repository from the command line". Kopieer die drie commando’s: die heb je zo nodig.
Stap 2: Je lokale repo koppelen aan GitHub
In je terminal (in je projectmap):
git remote add origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git
Wat gebeurt hier? remote is een externe locatie waar jouw repo ook staat. origin is de naam die je die locatie geeft. “origin” is de standaardnaam voor je belangrijkste remote. Je kunt meerdere remotes hebben (bijvoorbeeld origin voor GitHub, backup voor GitLab), maar één is meestal genoeg.
Controleer of het gelukt is:
Je ziet:
origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git (fetch)
origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git (push)
fetch = hier haal je code vandaan. push = hier stuur je code naartoe. Meestal zijn die hetzelfde.
Stap 3: Je code online zetten met git push
Nu komt het moment: je lokale commits naar GitHub sturen.
git push -u origin master
push = stuur mijn commits naar de remote. -u origin master = “onthoud dat master op mijn computer hoort bij master op origin.” De volgende keer kun je gewoon git push typen, want Git onthoudt de koppeling.
GitHub vraagt om in te loggen. Dat kan op twee manieren:
- Via de browser: GitHub opent een browservenster, je klikt op “Authorize”. Klaar.
- Met een Personal Access Token: maak je aan via GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic). Geef de token een naam, vink
repo aan, kopieer de token, en plak hem als wachtwoord in de terminal.
Voor ninjas: methode 1 (browser) is het makkelijkst. Als dat niet werkt, help dan met een token.
Na een succesvolle push, ververs je GitHub-pagina. Je bestanden staan er! Je hallo.py, je commit-geschiedenis: alles.
Stap 4: Wijzigingen pushen
Maak een wijziging lokaal:
echo 'print("GitHub is cool!")' >> hallo.py
git add hallo.py
git commit -m "Add GitHub enthusiasm"
Push naar GitHub:
Je hoeft nu geen -u origin master meer, want Git weet de weg. Ververs GitHub: je nieuwe commit staat erbij.
Stap 5: Een nieuw project starten via GitHub
Dit is de omgekeerde route: je begint op GitHub en haalt het naar je computer.
Op GitHub: New repository. Noem hem python-spelletje. Vink dit keer wél Add a README file aan; GitHub maakt dan een repo met één bestand erin. Klik Create repository.
Nu haal je deze repo naar je computer. Dit heet clonen:
cd ~ # ga naar je home-map
git clone https://github.com/JOUW_USERNAME/python-spelletje.git
GitHub maakt een map python-spelletje aan met de README erin. En het is meteen een volwaardige Git-repository: de .git-map zit er al in. Je hoeft geen git init te doen.
cd python-spelletje
git log --oneline # je ziet de eerste commit die GitHub voor je maakte
Nu kun je hier lokaal verder werken en je commits pushen naar GitHub, precies zoals in Stap 3 tot 4.
Stap 6: Wat als iemand anders ook wijzigingen maakt?
Stel: je hebt thuis aan python-spelletje gewerkt en gepusht. Nu ben je op de dojo-laptop en wil je verder. Je hebt de nieuwste versie nog niet.
git pull haalt de nieuwste commits van GitHub naar jouw computer. Het is twee acties in één: git fetch (ophalen) + git merge (samenvoegen met jouw lokale code).
Altijd git pull doen voor je begint met werken, anders loop je achter en krijg je merge conflicts.
Samenvatting van de workflow:
| Commando | Wat het doet |
|---|
git pull | Haal nieuwste versie op van GitHub |
Werk aan je code, maak commits (git add, git commit) | |
git push | Stuur jouw commits naar GitHub |
Onthoud: pull voor je begint, push als je klaar bent.
Showcase
Laat aan een coach en een buddy zien:
- Je GitHub-profiel met minstens één repository.
- De commit-geschiedenis van je repo op GitHub (klik op “X commits” boven de bestandslijst).
- Een verse
git push die net op GitHub is aangekomen.
Tot de volgende keer!
“Nu staat je code online. Maar wat zet je in een commit message? Hoe schrijf je een bericht dat over drie maanden nog steeds duidelijk is? En hoe werk je met een team zonder de boel te breken? Volgende keer: de professionele kant van Git: best practices die elke developer gebruikt.”
Neem mee naar huis
- Makkelijk: Push een bestaand lokaal project naar een nieuwe GitHub-repository.
- Middel: Maak 3 commits lokaal, push ze, en check op GitHub of ze allemaal zichtbaar zijn.
- Lastig: Clone een repo van GitHub, maak een wijziging, commit, en push terug.
- Erg lastig: Simuleer werken op twee computers: clone een repo, maak een commit en push. Ga naar een andere map, clone dezelfde repo opnieuw (alsof het een andere computer is), maak een andere commit, en probeer te pushen. Wat gebeurt er? Los het op met
git pull.
Sessie 14: Git Best Practices: Schrijf commits die je later nog snapt
Je kunt Git-commando’s typen. Je code staat op GitHub. Maar er is een verschil tussen “Git gebruiken” en “Git goed gebruiken.”
Deze sessie gaat over de gewoontes die ervaren developers elke dag toepassen. Geen nieuwe commando’s, wel scherpere regels. Aan het einde schrijf je commit messages waar je over een jaar nog iets aan hebt, en werk je met een branching-strategie die je project overzichtelijk houdt.
Wat je vandaag leert
- Hoe je een commit message schrijft die iets zegt
- Drie simpele regels voor branching
- Wat
git stash is en wanneer je het gebruikt - De pull-voor-je-pusht regel
Deel 1: Commit messages die iets zeggen
Een slechte commit message ziet er zo uit:
git commit -m "fix"
git commit -m "update"
git commit -m "dingen veranderd"
Over drie maanden kijk je terug. Wat was “fix”? Welke “dingen”? Je weet het niet meer. Je moet door de code spitten om te achterhalen wat er gebeurd is. Dat is tijdverspilling.
De goede commit message: 3 delen
Een professionele commit message heeft drie onderdelen:
1. Een korte samenvatting (max 72 karakters)
Schrijf in het Engels. Begin met een werkwoord in de tegenwoordige tijd. Dit heet “imperative mood”: alsof je een bevel geeft aan de codebase. Denk: “Add”, “Fix”, “Remove”, “Update”, “Refactor”.
Add highscore tracking
Fix star spawning off-screen
Remove unused collision code
2. Een lege regel
3. Een langere uitleg (optioneel, als het nodig is)
Add highscore tracking
Slaat de hoogste score op in highscore.txt. De score wordt
bijgewerkt na elke game-over. Het bestand wordt aangemaakt als
het nog niet bestaat.
Dit vervangt de oude methode waarbij de score alleen in het
geheugen stond en verloren ging bij afsluiten.
De uitgebreide uitleg vertelt waarom je iets veranderd hebt, niet alleen wát. De code zelf laat het “wat” al zien. Het “waarom” is wat je over drie maanden nodig hebt.
Commit message regels op een rij
| Doe dit | Niet dit |
|---|
| “Add player health bar” | “added health bar thing” |
| “Fix collision detection on left wall” | “fix” |
| “Remove debug print statements” | “cleanup” |
| Max 72 karakters voor de titel | Een heel verhaal in de titel |
| Tegenwoordige tijd, Engels | Verleden tijd (“added”, “fixed”) |
Waarom Engels? Omdat bijna alle open source-projecten Engels gebruiken. Code is internationaal. Ook je Python-code schrijf je in het Engels (def calculate_score). Je commit messages volgen diezelfde taal.
Waarom tegenwoordige tijd? Een commit beschrijft wat deze wijziging dóet, niet wat jij gedaan hébt. “Add feature” (deze commit voegt een feature toe), niet “Added feature” (ik heb ooit een feature toegevoegd). Git zelf gebruikt ook tegenwoordige tijd: Merge branch 'feature', niet Merged.
Multi-line commits in de terminal
Je kunt een commit message over meerdere regels schrijven door de aanhalingstekens niet te sluiten:
git commit -m "Add highscore tracking
Slaat de hoogste score op in highscore.txt. Het bestand wordt
automatisch aangemaakt bij de eerste game-over."
Let op: je typt het sluitende aanhalingsteken pas op de laatste regel. Alles ertussen is onderdeel van je message.
Wanneer commit je?
Commit vaak. Commit klein.
Niet: drie uur werken, één enorme commit met 47 gewijzigde bestanden.
Wel: elke 15 tot 30 minuten een commit, telkens als één logisch stukje af is.
Een vuistregel: als je commit message “en” bevat, is je commit te groot. “Add highscore tracking en fix menu bug en update sprites” → dit moeten drie aparte commits zijn.
Kleine commits maken het makkelijker om:
- Te begrijpen wat er wanneer veranderd is
- Eén specifieke wijziging terug te draaien zonder andere dingen kapot te maken
- Merge conflicts op te lossen (kleine brokjes = minder conflicten)
Deel 2: Branching: drie simpele regels
Je weet al hóe je branches maakt (sessie 12). Nu: wannéér en waaróm.
Regel 1: master is altijd werkend
De master-branch is je etalage. Iemand die je repo cloned, moet je code kunnen runnen zonder foutmeldingen. master bevat nooit half-af werk.
Niet oké op master: code met # TODO: dit moet nog af, uitgecommentarieerde functies, experimenten die je “later nog fixet.”
Wel oké op master: werkende code. Punt.
Regel 2: Eén feature, één branch
Een branch doet precies één ding. Niet meer.
- Goed:
feature/player-health-bar - Slecht:
feature/health-bar-and-menu-and-sound-effects
Als je tijdens het werken aan een feature denkt: “Oh, ik kan ook even die menu-bug fixen”: stop. Maak een nieuwe branch voor de bugfix. Merge die eerst. Ga dan verder met je feature.
Regel 3: Branches hebben een korte levensduur
Een branch die langer dan een paar dagen bestaat, wordt een probleem. master verandert intussen, en jouw branch raakt achterop. Hoe langer je wacht met mergen, hoe groter de kans op merge conflicts.
Merge je branch zodra de feature klaar is. Voor kleine dingen (een bugfix van 10 minuten): misschien heb je niet eens een aparte branch nodig.
Branch-naamgeving
Geef branches namen die je over een week nog begrijpt:
feature/highscore-tracking
bugfix/star-spawn-offscreen
experiment/particle-effects
De prefix (feature/, bugfix/, experiment/) vertelt meteen wat voor soort werk er in deze branch zit. Dit is een conventie, geen technische vereiste, maar het helpt.
Deel 3: Handige workflow-commando’s
git stash: werk opzij zetten
Stel: je bent bezig op een feature-branch. Je code is half af. Je wil even switchen naar master voor een snelle bugfix, maar je wil je half-affe werk niet committen. Daar is git stash voor:
Git bewaart al je wijzigingen tijdelijk en zet je working directory terug naar de laatste commit. Je kunt nu switchen, de bugfix doen, committen, en terugkomen:
git switch master
# ... bugfix doen, committen ...
git switch feature-branch
git stash pop
git stash pop haalt je opgeslagen wijzigingen terug. Alles staat weer zoals je het achterliet: half af, maar veilig bewaard.
git pull --rebase: een schonere geschiedenis
Normaal doet git pull een merge. Dat maakt een extra merge-commit aan. Soms wil je dat niet; je wil een rechte lijn van commits zonder vertakkingen.
Dit haalt de nieuwste commits op en zet jouw lokale commits erbovenop, alsof je ze ná de remote-commits gemaakt hebt. Het resultaat is een lineaire geschiedenis: geen merge-commits die alleen maar “Merge branch ‘master’” zeggen.
Let op: gebruik --rebase alleen op branches die jij alleen gebruikt. Bij gedeelde branches is gewoon git pull (merge) veiliger.
De pull-voor-je-pusht regel
Voordat je git push doet:
Altijd. Ook al denk je dat niemand anders gepusht heeft. Het kost één seconde en voorkomt dat GitHub je push weigert met “Updates were rejected because the remote contains work that you do not have locally.”
Deze regel geldt vooral als je samenwerkt. Als jij de enige bent die aan een repo werkt, is het risico kleiner, maar de gewoonte is goud waard.
Deel 4: De .gitignore die je altijd moet hebben
Elk project heeft bestanden die niet in Git horen. Je .gitignore is je eerste verdedigingslinie tegen per ongeluk wachtwoorden committen.
Minimale .gitignore voor een Python-project:
# Python
__pycache__/
*.pyc
*.pyo
# Virtual environment
venv/
.venv/
# Environment variables (bevat vaak wachtwoorden/keys)
.env
# Jouw editor
.vscode/
.idea/
*.swp
*.swo
# OS-bestanden
.DS_Store
Thumbs.db
Waarom __pycache__/ negeren? Dit zijn gecompileerde Python-bestanden die je programma automatisch aanmaakt. Ze zijn verschillend per Python-versie en per computer. Ze in Git stoppen geeft alleen maar ruis.
Waarom .env negeren? .env-bestanden bevatten vaak geheime sleutels, API-keys, database-wachtwoorden. Die mogen nooit, maar dan ook nooit in Git.
Showcase
Laat aan een coach en een buddy zien:
- Je laatste 5 commits, met goeie commit messages.
- Je
.gitignore-bestand. - Een branch-naam die de feature/prefix-conventie volgt.
Tot de volgende keer!
“Nu werk je professioneel met Git. Maar er is nog één concept dat élk team gebruikt: de pull request. Je code is klaar, maar voor hij in master komt, moet iemand anders hem goedkeuren. Hoe werkt dat? Volgende keer: pull requests, de review-muur waar élke wijziging doorheen moet.”
Neem mee naar huis
- Makkelijk: Herschrijf de commit messages van je laatste 5 commits. Gebruik de regels uit deze sessie.
- Middel: Maak een branch met de
feature/-prefix, werk erin, merge hem terug, en verwijder hem. Doe hetzelfde voor een bugfix/-branch. - Lastig: Gebruik
git stash om half werk op te slaan, switch naar master, maak een snelle fix, push, en kom terug naar je feature met git stash pop. - Erg lastig: Maak een situatie waar
git pull faalt (clone je repo in twee mappen, maak in beide een andere commit, push de eerste, en probeer de tweede te pushen). Los het op: git pull, merge conflict fixen, en dan pas pushen.
Sessie 15: Pull Requests: De voordeur van je project
Je hebt een feature gebouwd op een branch. Goeie commit messages, netjes gewerkt. Nu wil je je code in master zetten.
Je zou git merge kunnen doen en klaar. Maar in een team werkt dat niet. Iemand anders moet je code eerst bekijken: checken op fouten, op stijl, op dingen die je gemist hebt. Dát is een pull request.
Een pull request (PR) is een verzoek: “Haal mijn wijzigingen binnen.” Je opent hem op GitHub. Je teamgenoten bekijken je code, geven feedback. Jij past dingen aan. Pas als iedereen tevreden is, gaat de code naar master.
In deze sessie maak je je eerste pull request. Je reviewt die van een buddy. En je ervaart hoe écht teamwerk met Git voelt.
Wat je vandaag leert
- Wat een pull request is en waarom teams het gebruiken
- Een PR openen op GitHub
- Je PR updaten na feedback
- Een PR van iemand anders reviewen
- Een PR mergen en de branch opruimen
Stap 0: Voorbereiding: werken in duo’s
Vandaag werk je samen met een buddy. Spreek af wie de auteur is (die de feature bouwt) en wie de reviewer is (die de PR bekijkt). Halverwege wissel je om.
De auteur heeft een GitHub-repo nodig waar de reviewer toegang toe heeft. De makkelijkste manier:
- De auteur maakt een repo aan op GitHub (public).
- De auteur gaat naar Settings → Collaborators → Add people.
- De auteur nodigt de reviewer uit met diens GitHub-username.
- De reviewer accepteert de uitnodiging (via e-mail of GitHub-notificaties).
Nu kunnen jullie allebei pushen naar dezelfde repo.
Alternatief (zonder collaborator-toegang): de reviewer forkt de repo van de auteur en opent een PR vanaf de fork naar het origineel. Maar vandaag houden we het simpel: directe collaborator-toegang.
Stap 1: Een feature-branch maken en pushen (auteur)
De auteur cloned de repo (als dat nog niet gebeurd is) en maakt een feature-branch:
git clone https://github.com/AUTEUR_USERNAME/ons-samenwerk-project.git
cd ons-samenwerk-project
git switch -c feature/groet-functie
Maak een nieuw bestand:
echo 'def groet(naam):' > groet.py
echo ' return f"Hallo {naam}!"' >> groet.py
Commit en push:
git add groet.py
git commit -m "Add groet functie
Retourneert een begroeting voor de opgegeven naam."
git push -u origin feature/groet-functie
Stap 2: Een pull request openen (auteur)
- Ga naar je repo op GitHub.
- GitHub toont nu een gele balk: “feature/groet-functie had recent pushes”: klik op Compare & pull request. (Als je de balk niet ziet: klik op het Pull requests-tabblad, dan New pull request, kies
base: master ← compare: feature/groet-functie.) - Schrijf een duidelijke titel: “Add groet functie”
- Schrijf een beschrijving. Een goede PR-beschrijving heeft drie delen:
## Wat
Een functie `groet(naam)` die een begroeting retourneert.
## Waarom
We hebben een herbruikbare begroeting nodig voor de
gebruikersinterface. Dit voorkomt dat we op meerdere plekken
dezelfde string moeten schrijven.
## Hoe testen
```python
from groet import groet
print(groet("CoderDojo")) # "Hallo CoderDojo!"
5. Klik **Create pull request**.
Je PR staat nu open. Iedereen met toegang tot de repo kan hem zien. GitHub toont de diff: exact welke regels je hebt toegevoegd (groen) en verwijderd (rood).
## Stap 3: Een PR reviewen (reviewer)
De reviewer opent de PR op GitHub. Dit zijn de stappen van een review:
### 1. Lees de beschrijving
Begrijp je wat deze PR doet? Zo niet, vraag om verduidelijking.
### 2. Bekijk de diff
Klik op het **Files changed**-tabblad. GitHub toont elke gewijzigde regel. Kijk naar:
- **Werkt de code?** Zou je het zelf runnen als je het cloned?
- **Is de stijl consistent?** Dezelfde naamgevingsconventies als de rest van het project?
- **Zijn er fouten?** Typo's, ontbrekende imports, logische fouten?
- **Staan er geen geheimen in?** Wachtwoorden, API-keys, tokens?
- **Is het te begrijpen?** Kan iemand die deze code voor het eerst ziet, volgen wat er gebeurt?
### 3. Geef feedback
Klik op een regel om een comment toe te voegen. Wees specifiek:
**Goeie feedback:**
> In `groet.py` regel 2: wat gebeurt er als `naam` leeg is? Misschien een default-waarde toevoegen?
**Slechte feedback:**
> Dit is niet goed.
### 4. Dien je review in
Klik op **Review changes**. Je hebt drie opties:
- **Comment**: gewoon feedback, geen beslissing.
- **Approve**: de code is goed, mag gemerged worden.
- **Request changes**: er moet iets aangepast worden voor de PR gemerged kan worden.
Bij je eerste review: kies **Approve** als alles er goed uitziet, of **Request changes** als je iets wilt laten aanpassen.
## Stap 4: Feedback verwerken (auteur)
De reviewer heeft een comment achtergelaten. De auteur past de code aan:
```bash
# Zorg dat je op je feature-branch zit
git switch feature/groet-functie
Pas groet.py aan op basis van de feedback. Bijvoorbeeld:
def groet(naam="wereld"):
return f"Hallo {naam}!"
Commit en push:
git add groet.py
git commit -m "Add default parameter to groet functie"
git push
De nieuwe commit verschijnt automatisch in de PR. De reviewer ziet de update en kan opnieuw kijken.
Stap 5: Mergen en opruimen
Als de reviewer Approved heeft, is het tijd om te mergen.
Op GitHub, in de PR, klik je op Merge pull request. Kies Create a merge commit (de standaardoptie). Klik Confirm merge.
De feature-branch is nu samengevoegd met master. Op GitHub kun je de branch verwijderen met de Delete branch-knop die verschijnt na het mergen.
Lokaal moet je ook opruimen:
git switch master
git pull # haal de merge op die net op GitHub gebeurd is
git branch -d feature/groet-functie # verwijder de lokale branch
Je master is nu up-to-date. Je feature-branch is weg, lokaal én op GitHub. Klaar voor het volgende stuk werk.
De volledige PR-workflow op een rij
1. git switch -c feature/iets ← Maak een feature-branch
2. Werk, commit, werk, commit
3. git push -u origin feature/iets ← Push naar GitHub
4. Open een PR op GitHub ← Vraag om review
5. Reviewer bekijkt, geeft feedback
6. Pas code aan, commit, push ← Feedback verwerken
7. Reviewer approved
8. Merge de PR op GitHub ← Code naar master
9. git switch master && git pull ← Haal master lokaal bij
10. git branch -d feature/iets ← Ruim de branch op
Een PR van iemand anders reviewen: hoe doe je dat goed?
Een review is niet: “Ziet er goed uit.” Een goeie review is specifiek, constructief en respectvol.
Vragen die je jezelf stelt tijdens een review:
- Snap ik wat deze code doet? (Zo nee: vraag om betere comments of een duidelijkere beschrijving.)
- Doet de code wat de PR-beschrijving belooft?
- Kan dit simpeler?
- Mist er iets? (Foutafhandeling, edge cases, documentatie)
- Staan er geheimen, wachtwoorden of persoonlijke data in?
- Volgt de code de stijl van de rest van het project?
Hoe geef je feedback:
Begin met wat goed is. Wees dan specifiek over wat beter kan. Eindig met een duidelijke conclusie.
Voorbeeld:
De functie werkt precies zoals beschreven. Twee suggesties:
- In regel 2: een default-waarde voor
naam zou handig zijn. - Overweeg een docstring toe te voegen die uitlegt wat de functie retourneert.
Verder ziet het er goed uit. Als je deze twee dingen aanpast, approve ik hem graag.
Showcase
Wissel van rol met je buddy en doe de hele workflow nog een keer: nu ben jij de reviewer.
Laat aan een coach zien:
- Een open pull request op GitHub met een beschrijving.
- Minstens één review-comment op een PR van je buddy.
- Een succesvol gemergede PR: de feature-code staat nu op
master.
Tot de volgende keer!
Dit was de laatste Git-sessie. Wat je nu kunt:
- Je code versiebeheren met Git (
init, add, commit, log, diff) - Experimenteren op branches zonder
master kapot te maken (branch, switch, merge) - Je code online delen via GitHub (
push, pull, clone) - Professionele commit messages schrijven
- Samenwerken via pull requests: openen én reviewen
Dit is niet “extra”. Dit is hoe developers élke dag werken. Of je nu games maakt, websites bouwt, of AI traint: Git en GitHub zijn de gereedschappen die je project beheersbaar houden. Gebruik ze.
Neem mee naar huis
- Makkelijk: Open een pull request voor een wijziging in een van je eigen projecten.
- Middel: Vraag een vriend of familielid om een GitHub-account te maken. Nodig ze uit als collaborator en laat ze een PR reviewen.
- Lastig: Draag bij aan een echt open source-project. Zoek op GitHub naar issues met het label
good first issue. Fork de repo, maak een fix, en open een PR. - Erg lastig: Bouw een klein project met twee anderen. Gebruik branches, pull requests en reviews. Werk alsof je in een professioneel team zit.
Sessie 16: Markdown: Schrijf notities die eruitzien als het web
Je kent HTML misschien van het internet: <h1>, <p>, <a>. Maar voor notities en documentatie is HTML veel te veel typwerk. Daar is Markdown voor.
Markdown is een mini-taal die je in gewone tekst schrijft. Het ziet er leesbaar uit zónder dat je het eerst moet omzetten. En met één druk op de knop wordt het nette HTML: koppen, lijsten, links, tabellen.
In deze sessie leer je de hele basis van Markdown. Aan het einde schrijf je notities die er professioneel uitzien, op GitHub, in Obsidian, of in elk ander programma dat Markdown begrijpt.
Wat je vandaag leert
- Koppen en alinea’s maken
- Tekst opmaken: vet, cursief, doorstreept
- Lijsten en opsommingen
- Links naar andere pagina’s en websites
- Afbeeldingen invoegen
- Tabellen maken
- Horizontale lijnen en codeblokken
Waarom Markdown?
Markdown is overal:
- GitHub: elke repo heeft een
README.md in Markdown. Issues, pull requests, wiki’s: allemaal Markdown. - Obsidian, Joplin, Logseq: notitie-apps die je documenten als
.md-bestanden opslaan. - Discord, Slack, Reddit: ondersteunen Markdown voor snelle opmaak in berichten.
- Hugo (deze website!): alle sessie-pagina’s die je hier ziet, zijn geschreven in Markdown.
- Jupyter Notebooks: de tekst-cellen zijn Markdown.
Het grote voordeel: je schrijft gewone tekst. Geen ingewikkelde tags. En het resultaat is altijd leesbaar, ook als platte tekst.
Stap 0: Een Markdown-bestand maken
Markdown-bestanden eindigen op .md. Maak er één:
mkdir mijn-notities
cd mijn-notities
echo "# Mijn Eerste Notitie" > test.md
Je kunt .md-bestanden openen in elke teksteditor: Kladblok, VS Code, Thonny, Obsidian. VS Code heeft een ingebouwde preview: klik rechtsboven op het icoontje met het vergrootglas en het boek.
Stap 1: Koppen en alinea’s
Koppen maak je met #. Hoe meer #, hoe kleiner de kop:
# Dit is een titel (h1)
## Dit is een subtitel (h2)
### Dit is een kleinere kop (h3)
#### Nog kleiner (h4)
Een alinea maak je door gewoon tekst te typen. Een lege regel ertussen start een nieuwe alinea:
Dit is de eerste alinea. Die loopt gewoon door.
Dit is de tweede alinea. Omdat er een lege regel tussen zit.
Tip: één # gebruik je maar één keer per document: voor de titel. De rest begint bij ##.
Stap 2: Tekst opmaken
**Dit is vetgedrukt**
*Dit is cursief*
~~Dit is doorstreept~~
Je kunt ook **vet en *cursief* combineren** in dezelfde zin.
Het resultaat:
**vet** wordt vet*cursief* wordt cursief~~doorstreept~~ wordt doorstreept
Let op: geen spaties tussen de sterretjes en de tekst. ** vet ** werkt niet. **vet** wel.
Sommige editors accepteren ook underscores: __vet__ en _cursief_. Maar sterretjes zijn de standaard: gebruik die.
Stap 3: Horizontale lijnen
Een horizontale lijn maak je met drie (of meer) streepjes:
Of met sterretjes:
Het resultaat is een lijn over de hele breedte. Gebruik het spaarzaam: één of twee per document is genoeg. Te veel lijnen maken je notities onoverzichtelijk.
Stap 4: Lijsten
Ongenummerde lijst
Gebruik -, * of +:
- Python
- Git
- Markdown
- GitHub
Je kunt lijsten nesten door in te springen (2 of 4 spaties):
- Programmeertalen
- Python
- JavaScript
- Versiebeheer
- Git
- GitHub
Genummerde lijst
1. Open Thonny
2. Schrijf je code
3. Klik op Run
Het maakt niet uit welke nummers je typt: Markdown nummert automatisch door. Dit:
1. Stap één
1. Stap twee
1. Stap drie
…geeft exact hetzelfde resultaat als 1, 2, 3. Handig als je later een stap wilt toevoegen zonder alles te hernummeren.
Checklist (GitHub-stijl)
- [x] Git installeren
- [x] Eerste commit maken
- [ ] Branches leren
- [ ] Pull request openen
[x] is afgevinkt, [ ] is open. Werkt in GitHub issues, pull requests, en veel notitie-apps.
Stap 5: Links
Externe links (naar websites)
[klik hier voor de CoderDojo-site](https://python.coderdojohasselt.be)
Het woord tussen [ ] is de klikbare tekst. De URL tussen ( ) is de bestemming.
Interne links (naar andere pagina’s in je project)
[Bekijk sessie 11](11-git-intro/)
Dit linkt naar het bestand 11-git-intro/_index.md in dezelfde map.
Snel-link (toon de URL direct)
Dit toont de URL als klikbare link, zonder aparte tekst.
Stap 6: Afbeeldingen
Een afbeelding is bijna hetzelfde als een link, maar met een ! ervoor:

De tekst tussen [ ] is de alt-tekst: die verschijnt als de afbeelding niet laadt, of wordt voorgelezen door screenreaders.
Afbeeldingen en Git: Kleine afbeeldingen (SVG, kleine PNG’s) kun je in Git zetten. Grote afbeeldingen (>1 MB) en video’s beter niet, want die maken je repo traag.
Stap 7: Tabellen
| Commando | Wat het doet |
|----------|-------------|
| `git init` | Nieuwe repository maken |
| `git add` | Bestanden klaarzetten voor commit |
| `git commit` | Wijzigingen vastleggen |
| `git push` | Commits naar GitHub sturen |
De | tekens vormen de kolommen. De --- regel scheidt de kop van de data. De : in de scheidingsregel bepaalt uitlijning:
| Links uitgelijnd | Gecentreerd | Rechts uitgelijnd |
|:-----------------|:-----------:|------------------:|
| links | midden | rechts |
Stap 8: Code en codeblokken
Inline code
Gebruik backticks voor korte stukjes code in een zin:
Gebruik `git status` om te zien wat er gewijzigd is.
Codeblokken
Voor meerdere regels code gebruik je drie backticks:
```python
def groet(naam):
return f"Hallo {naam}!"
```
De taal (python) achter de eerste backticks geeft syntax highlighting. Dit werkt voor tientallen talen: bash, html, css, javascript, json, yaml, markdown.
Codeblok zonder taal
```
Dit is gewoon tekst
zonder syntax highlighting
```
Stap 9: Blockquotes
Gebruik > voor citaten of belangrijke opmerkingen:
> Git is geen back-up. Git is een tijdmachine.
> Iemand op het internet
Meerdere > regels achter elkaar vormen één blok. Een lege > regel start een nieuwe alinea binnen het citaat.
Stap 10: Alles samen: een echte README
Een goed README.md combineert alles wat je nu kent. Hier is een voorbeeld:
# Mijn Project
Een korte beschrijving van wat dit project doet.
## Installatie
```bash
git clone https://github.com/jouw-naam/mijn-project.git
cd mijn-project
```
## Gebruik
1. Open `main.py` in Thonny.
2. Klik op **Run**.
3. Kies een level en start.
## Wat je leert
- [x] Pygame Zero basis
- [x] Collision detection
- [ ] Highscore systeem
- [ ] Geluidseffecten
## Links
- [CoderDojo Hasselt](https://coderdojohasselt.be)
- [Broncode op GitHub](https://github.com/jouw-naam/mijn-project)
Cheatsheet
| Wat | Markdown |
|---|
| Kop niveau 1 | # Titel |
| Kop niveau 2 | ## Subtitel |
| Kop niveau 3 | ### Kleinere kop |
| Vet | **vet** |
| Cursief | *cursief* |
| Doorstreept | ~~doorstreept~~ |
| Horizontale lijn | --- of *** |
| Lijst (ongeordend) | - item |
| Lijst (genummerd) | 1. item |
| Checklist | - [ ] open item |
| Link | [tekst](url) |
| Afbeelding |  |
| Inline code | `code` |
| Codeblok | ```taal |
| Citaat | > citaat |
| Tabel | | kolom | kolom | |
Showcase
Laat aan een coach en een buddy zien:
- Een Markdown-document met minstens één kop, een lijst, een link en vetgedrukte tekst.
- Een tabel met minstens twee kolommen en drie rijen.
- Een checklist met afgevinkte en open items.
Tot de volgende keer!
Markdown is simpel, maar het is overal. Je README’s op GitHub, je notities in Obsidian, je documentatie: alles wordt leesbaarder met Markdown. Gebruik het. Overdrijf niet met opmaak. Goeie notities zijn helder, niet druk.
Neem mee naar huis
- Makkelijk: Schrijf een
README.md voor je favoriete Python-project. Gebruik koppen, een lijst en een codeblok. - Middel: Maak een notitie in Obsidian (of een andere Markdown-editor) over wat je deze maand geleerd hebt. Gebruik alle opmaak uit de cheatsheet minstens één keer.
- Lastig: Bouw een “cheatsheet”-pagina in Markdown voor een onderwerp naar keuze (Git-commando’s, Python syntax, wiskunde-formules). Gebruik tabellen en geneste lijsten.
- Erg lastig: Maak een Markdown-document met een geneste lijst die minstens drie niveaus diep gaat, een tabel met uitlijning, en een codeblok met syntax highlighting.