Add 13 new grammar notes with 1010 exercises from video extraction

Scraped a 4h Spanish fundamentals YouTube video (transcript + OCR on
14810 frames), extracted structured content across 52 chapters, and
generated fill-in-the-blank quizzes for every grammar topic.

- 13 new GrammarNote entries (articles, possessives, demonstratives,
  greetings, poder, al/del, prepositional pronouns, irregular yo,
  stem-changing, stressed possessives, present/future perfect, present
  indicative conjugation)
- 1010 generated exercises across all 36 grammar notes (new + existing)
- Fix tense guide parser to handle unnumbered *Usages* blocks
- Rewrite 6 broken tense guide bodies (imperative, subj pluperfect,
  subj future) with numbered usage format
- Bump courseDataVersion 5→6 with TenseGuide refresh on upgrade
- Add docs/spanish-fundamentals/ with raw transcripts, polished notes,
  structured JSON, and exercise data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-04-16 08:40:05 -05:00
parent ff4f906128
commit 47a7871c38
297 changed files with 114661 additions and 14 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1274,4 +1274,445 @@ struct GrammarNote: Identifiable {
**Tip:** Use the Irregularity Drills in the Practice tab to focus on each type separately — spelling changes, stem changes, or unique irregulars.
"""
)
// MARK: - BEGIN generated notes (do not edit regenerate via scrape/work/generate_swift.py)
static let generatedNotes: [GrammarNote] = [
GrammarNote(
id: "present-indicative-conjugation",
title: "Present Indicative Conjugation",
category: "Core Concepts",
body: """
The present indicative describes what someone **does** or **is doing** right now, habitually, or as a general truth. To conjugate a regular verb, drop the infinitive ending (-ar, -er, -ir) and add the person-ending that matches the subject.
**-ar verbs** (hablar — to speak):
*hablo, hablas, habla, hablamos, habláis, hablan*
**-er verbs** (comer — to eat):
*como, comes, come, comemos, coméis, comen*
**-ir verbs** (vivir — to live):
*vivo, vives, vive, vivimos, vivís, viven*
Notice -er and -ir verbs share the same endings EXCEPT in the nosotros and vosotros forms (-emos/-éis vs -imos/-ís).
*Yo hablo español todos los días.* — I speak Spanish every day.
*¿Tú comes carne?* — Do you eat meat?
*Ellos viven en Madrid.* — They live in Madrid.
**Key tip:** Since the verb ending already tells you the subject, Spanish often drops subject pronouns: *Hablo español* already means *I speak Spanish.*
"""
),
GrammarNote(
id: "articles-and-gender",
title: "Articles & Gender",
category: "Core Concepts",
body: """
Every Spanish noun has a grammatical gender (masculine or feminine) and a number (singular or plural). The article must agree with both.
**Definite articles** (the):
*el* (m. sing.), *la* (f. sing.), *los* (m. pl.), *las* (f. pl.)
**Indefinite articles** (a/an/some):
*un* (m. sing.), *una* (f. sing.), *unos* (m. pl.), *unas* (f. pl.)
*el libro / los libros* — the book(s)
*la mesa / las mesas* — the table(s)
*un amigo / unos amigos* — a friend / some friends
**General rules:**
- Nouns ending in -o are usually masculine: *el carro, el vino.*
- Nouns ending in -a are usually feminine: *la casa, la silla.*
- Nouns ending in -ción, -sión, -dad, -tad are feminine: *la canción, la ciudad.*
- Nouns ending in -ma, -pa, -ta from Greek are often masculine: *el problema, el mapa, el planeta.*
**Common exceptions to memorize:**
*la mano, la foto, la moto, la radio* (feminine but end in -o)
*el día, el clima, el tema, el idioma, el sofá* (masculine but end in -a)
**Tip:** Always learn a new noun together with its article — *la mano*, not just *mano*.
"""
),
GrammarNote(
id: "possessive-adjectives",
title: "Possessive Adjectives",
category: "Adjectives",
body: """
Spanish possessive adjectives go **before** the noun and agree in number with the item possessed (not with the possessor). Only *nuestro* and *vuestro* also agree in gender.
| | Singular | Plural |
|---|---|---|
| my | mi | mis |
| your (tú) | tu | tus |
| his/her/your(Ud.) | su | sus |
| our | nuestro/a | nuestros/as |
| your (vosotros) | vuestro/a | vuestros/as |
| their/your(Uds.) | su | sus |
*mi libro / mis libros* — my book(s)
*tu casa / tus casas* — your house(s)
*nuestra familia / nuestros amigos* — our family / our friends
**Note:** *tu* (your) has no accent; *tú* (you) does.
**Ambiguity of *su*:** *su* can mean his, her, its, your (Ud./Uds.), or their. Context or *de + pronoun* clarifies: *la casa de él* (his house), *la casa de ella* (her house).
*Su coche es rojo* — His / Her / Their / Your car is red.
*El coche de ella es rojo.* — Her car is red.
"""
),
GrammarNote(
id: "demonstrative-adjectives",
title: "Demonstrative Adjectives",
category: "Adjectives",
body: """
Demonstratives point to something and agree with the noun in gender and number. Spanish has three levels of distance:
**este/esta/estos/estas** — this/these (near the speaker)
**ese/esa/esos/esas** — that/those (near the listener)
**aquel/aquella/aquellos/aquellas** — that/those over there (far from both)
*este libro* — this book
*esta mesa* — this table
*esos zapatos* — those shoes (near you)
*aquellas montañas* — those mountains (in the distance)
**Neuter pronouns** — use *esto, eso, aquello* when pointing to something unidentified or to an abstract idea. They don't change form.
*¿Qué es esto?* — What is this?
*Eso no me gusta.* — I don't like that.
*Aquello fue un desastre.* — That was a disaster.
**Tip:** *este/ese/aquel* follow the distance triangle — speaker → listener → beyond. The *-ese* forms (ese/esos) sit in the middle.
"""
),
GrammarNote(
id: "greetings-farewells",
title: "Greetings & Farewells",
category: "Core Concepts",
body: """
Spanish greetings are highly time-of-day aware. Using the wrong one sounds jarring.
**Greetings**
*hola* — hi (anytime)
*buenos días* — good morning (until ~noon)
*buenas tardes* — good afternoon (noon until sunset)
*buenas noches* — good evening / good night (after dark, also used when leaving)
**Common questions**
*¿cómo estás?* — how are you? (tú)
*¿cómo está usted?* — how are you? (formal)
*¿qué tal?* — what's up?
*¿qué hay?* — what's new?
*¿cómo te va?* — how's it going?
**Responses**
*bien, gracias* — fine, thanks
*muy bien* — very well
*más o menos* — so-so
*todo bien* — all good
**Introductions**
*mucho gusto* — nice to meet you
*encantado / encantada* — delighted (m./f.)
*igualmente* — likewise
**Farewells**
*adiós* — goodbye
*hasta luego* — see you later
*hasta pronto* — see you soon
*hasta mañana* — see you tomorrow
*nos vemos* — see you (around)
*chau / chao* — bye (informal)
**Tip:** *buenas noches* works for both *good evening* (hello) and *good night* (goodbye) — context tells which.
"""
),
GrammarNote(
id: "poder-infinitive",
title: "Poder + Infinitive",
category: "Irregular Verbs",
body: """
*Poder* means "to be able to / can" and is one of the most-used verbs in Spanish. It's an o→ue stem-changer in the present tense (all forms except nosotros and vosotros) and takes an infinitive directly — no preposition.
**Present indicative:**
*puedo, puedes, puede, podemos, podéis, pueden*
**Preterite (irregular stem pud-):**
*pude, pudiste, pudo, pudimos, pudisteis, pudieron*
**Future / Conditional stem:** *podr-*
*podré, podrás, podrá...* (future)
*podría, podrías, podría...* (conditional — often softens a request)
*Puedo hablar tres idiomas.* — I can speak three languages.
*¿Puedes ayudarme?* — Can you help me?
*No pudimos ir al concierto.* — We couldn't go to the concert.
*¿Podrías pasar la sal?* — Could you pass the salt? (polite request)
**Pattern:** poder + infinitive. Never *poder a* or *poder de*.
**Nuance:** The preterite *pude* often carries the meaning "managed to / succeeded in"; *no pude* means "I failed to / couldn't."
"""
),
GrammarNote(
id: "al-del-contractions",
title: "al & del Contractions",
category: "Core Concepts",
body: """
Spanish has only **two mandatory contractions**, and they both collapse the redundant vowel between a preposition and the article *el*.
**a + el = al** (to the)
**de + el = del** (of the / from the)
*Voy al mercado.* — I'm going to the market. (NOT *a el*)
*La puerta del coche está abierta.* — The door of the car is open. (NOT *de el*)
No other preposition + article pair contracts:
*en el parque, por el camino, con el amigo* — all uncontracted.
None of the other articles contract either:
*a la escuela, a los niños, a las chicas, de la casa, de los libros* — all separate.
**Exception — proper names:** Don't contract with *Él* (the pronoun *he*) or when *El* is part of a name (*El Salvador*, *El Paso*).
*Le doy el regalo a él.* — I give the gift to him. (NOT *al*)
*Vuelvo de El Salvador.* — I'm coming back from El Salvador. (NOT *del*)
**Tip:** Think of al/del as a pronunciation shortcut — Spanish hates two vowels smashed together (a-el, de-el).
"""
),
GrammarNote(
id: "prepositional-pronouns",
title: "Prepositional Pronouns",
category: "Pronouns",
body: """
After most prepositions (a, de, en, para, por, sin, sobre, etc.) Spanish uses a special set of object-of-preposition pronouns. Only *yo* and *tú* change form.
| Subject | After preposition |
|---|---|
| yo | **mí** |
| tú | **ti** |
| él / ella / usted | él / ella / usted |
| nosotros/as | nosotros/as |
| vosotros/as | vosotros/as |
| ellos/as / ustedes | ellos/as / ustedes |
*Este regalo es para mí.* — This gift is for me.
*No puedo ir sin ti.* — I can't go without you.
*Hablan de nosotros.* — They're talking about us.
*Pienso en ella.* — I'm thinking about her.
**Note the accent:** *mí* (me) has an accent, *mi* (my) doesn't. *ti* never has an accent.
**Special: con + mí/ti**
The preposition *con* fuses with *mí* and *ti* into single words:
*conmigo* — with me
*contigo* — with you
*consigo* — with himself/herself/yourself (reflexive, less common)
*¿Quieres venir conmigo?* — Do you want to come with me?
*Iré contigo.* — I'll go with you.
**Exceptions:** After *entre, según, incluso, excepto, menos* use subject pronouns: *entre tú y yo* — between you and me.
"""
),
GrammarNote(
id: "irregular-yo-verbs",
title: "Irregular Yo Verbs",
category: "Irregular Verbs",
body: """
A group of Spanish verbs conjugates regularly in every present-tense form **except yo**, which takes a special irregular ending. Once you learn these yo forms, the rest of the conjugation behaves normally.
**-go endings (very common):**
*hacer → hago* (I do/make)
*poner → pongo* (I put)
*salir → salgo* (I leave)
*tener → tengo* (I have) — also stem-changes in tú/él forms
*venir → vengo* (I come) — also stem-changes
*decir → digo* (I say) — also stem-changes
*traer → traigo* (I bring)
*oír → oigo* (I hear)
*caer → caigo* (I fall)
**-zco endings** (verbs ending in -cer or -cir after a vowel):
*conocer → conozco* (I know)
*conducir → conduzco* (I drive)
*traducir → traduzco* (I translate)
*ofrecer → ofrezco* (I offer)
*parecer → parezco* (I seem)
**-oy endings:**
*dar → doy* (I give)
*estar → estoy* (I am)
*ir → voy* (I go)
*ser → soy* (I am)
**Standalone irregulars:**
*ver → veo* (I see)
*saber → sé* (I know — has an accent)
*caber → quepo* (I fit)
*Yo tengo dos hermanos.* — I have two brothers.
*Hago la tarea cada día.* — I do homework every day.
*Conozco a tu padre.* — I know your father.
"""
),
GrammarNote(
id: "stem-changing-verbs",
title: "Stem-Changing Verbs",
category: "Irregular Verbs",
body: """
Stem-changing verbs modify the vowel inside their stem in **all present-tense forms except nosotros and vosotros**. The affected forms map out like a boot on a conjugation chart — hence *boot verbs*.
**Four categories:**
**1. e → ie** (pensar — to think):
*pienso, piensas, piensa, pensamos, pensáis, piensan*
Also: cerrar, empezar, querer, entender, preferir, sentir.
**2. o → ue** (poder — to be able):
*puedo, puedes, puede, podemos, podéis, pueden*
Also: dormir, contar, volver, encontrar, recordar, morir.
**3. e → i** (only -ir verbs) (pedir — to ask for):
*pido, pides, pide, pedimos, pedís, piden*
Also: servir, repetir, seguir, vestirse.
**4. u → ue** (*jugar* — to play — the ONLY one):
*juego, juegas, juega, jugamos, jugáis, juegan*
**Why nosotros/vosotros are spared:** the stress falls on the ending in those forms, so the stem vowel stays unstressed and unchanged.
*Yo quiero un café.* — I want a coffee.
*Nosotros queremos café.* — We want coffee. (no change)
*Ella duerme ocho horas.* — She sleeps eight hours.
*Nosotros dormimos poco.* — We sleep little. (no change)
*Pido la cuenta.* — I ask for the check.
**Tip:** Stem changes carry through into the present subjunctive and sometimes affect the gerund (*durmiendo, pidiendo*) and 3rd-person preterite (*durmió, pidió*) — but only for -ir verbs.
"""
),
GrammarNote(
id: "stressed-possessives",
title: "Stressed Possessive Adjectives",
category: "Adjectives",
body: """
Stressed possessives are the "long-form" possessives used for emphasis, after the noun, or after *ser*. Unlike the short forms (mi, tu, su…), they agree in BOTH gender and number with the item possessed.
| | Singular m. / f. | Plural m. / f. |
|---|---|---|
| mine | mío / mía | míos / mías |
| yours (tú) | tuyo / tuya | tuyos / tuyas |
| his/hers/yours (Ud.) | suyo / suya | suyos / suyas |
| ours | nuestro / nuestra | nuestros / nuestras |
| yours (vosotros) | vuestro / vuestra | vuestros / vuestras |
| theirs/yours (Uds.) | suyo / suya | suyos / suyas |
**Used three ways:**
1. **After a noun** (emphatic, often with *un/una*):
*un amigo mío* — a friend of mine
*una idea tuya* — an idea of yours
*unos primos nuestros* — some cousins of ours
2. **After ser** (ownership):
*El libro es mío.* — The book is mine.
*Esta casa es nuestra.* — This house is ours.
*¿Son tuyas estas llaves?* — Are these keys yours?
3. **As a pronoun** with *el / la / los / las*:
*Mi coche es rojo; el tuyo es azul.* — My car is red; yours is blue.
*Tus hijos y los míos juegan juntos.* — Your kids and mine play together.
**Ambiguity of *suyo***: Like short *su*, stressed *suyo/a* can mean his, hers, yours (Ud./Uds.), or theirs. Use *de él / de ella* if ambiguous.
"""
),
GrammarNote(
id: "present-perfect-tense",
title: "Present Perfect",
category: "Verb Tenses",
body: """
The present perfect (*pretérito perfecto*) describes what someone **has done** — an action completed in the recent past or within an unfinished time frame that extends to now (today, this week, this year, ever).
**Formula:** *haber* (present) + past participle
| | haber |
|---|---|
| yo | he |
| tú | has |
| él/ella/Ud. | ha |
| nosotros | hemos |
| vosotros | habéis |
| ellos/Uds. | han |
**Regular participles:**
-ar verbs → -ado: *hablar → hablado*
-er/-ir verbs → -ido: *comer → comido, vivir → vivido*
**Common irregular participles:**
*abrir → abierto* (opened)
*decir → dicho* (said)
*escribir → escrito* (written)
*hacer → hecho* (done/made)
*morir → muerto* (died)
*poner → puesto* (put)
*romper → roto* (broken)
*ver → visto* (seen)
*volver → vuelto* (returned)
*cubrir → cubierto* (covered)
*resolver → resuelto* (solved)
*He comido demasiado hoy.* — I have eaten too much today.
*¿Has visto la nueva película?* — Have you seen the new movie?
*Todavía no han llegado.* — They haven't arrived yet.
*Este año hemos viajado mucho.* — This year we've traveled a lot.
**Key rule:** *Haber* and the participle must stay together. Never put a pronoun between them: *Lo he comido*, NOT *He lo comido*.
**Tip:** The participle never changes in this tense — always ends in -o. (It only agrees in gender/number when used as an adjective with *ser/estar*.)
"""
),
GrammarNote(
id: "future-perfect-tense",
title: "Future Perfect",
category: "Verb Tenses",
body: """
The future perfect (*futuro perfecto*) describes what **will have happened** by some point in the future. It's also used to speculate about the recent past ("they must have").
**Formula:** *haber* (future) + past participle
| | haber |
|---|---|
| yo | habré |
| tú | habrás |
| él/ella/Ud. | habrá |
| nosotros | habremos |
| vosotros | habréis |
| ellos/Uds. | habrán |
**Two main uses:**
1. **Will-have-happened before a future point:**
*Para las ocho, habré terminado el trabajo.* — By eight, I will have finished the work.
*Cuando lleguen, ya habremos cenado.* — By the time they arrive, we'll have eaten.
*En un año, habrás aprendido mucho español.* — In a year, you'll have learned a lot of Spanish.
2. **Speculation / guess about recent past** (like English "must have"):
*Habrá olvidado la cita.* — He must have forgotten the appointment.
*Se habrán ido ya.* — They must have left already.
*¿Habrás dejado las llaves en casa?* — Could you have left the keys at home?
**Pattern reminder:** Same irregular participles as present perfect (dicho, hecho, visto, escrito, puesto, abierto, etc.).
**Tip:** When preceded by a time clause with *cuando/antes de que/para cuando*, Spanish usually puts a subjunctive in the time clause and future perfect in the main clause: *Cuando vengas, ya habré salido.*
"""
),
]
/// Combined list used by the UI: 24 hand-authored notes + generated ones.
static let allNotesIncludingGenerated: [GrammarNote] = allNotes + generatedNotes
// MARK: - END generated notes
}

View File

@@ -3,7 +3,7 @@ import SharedModels
import Foundation
actor DataLoader {
static let courseDataVersion = 5
static let courseDataVersion = 6
static let courseDataKey = "courseDataVersion"
/// Quick check: does the DB need seeding or course data refresh?
@@ -145,12 +145,29 @@ actor DataLoader {
print("Course data version outdated — re-seeding...")
let context = ModelContext(container)
// Delete existing course data
// Delete existing course data + tense guides so they can be re-seeded
// with updated bodies from the bundled conjuga_data.json.
try? context.delete(model: VocabCard.self)
try? context.delete(model: CourseDeck.self)
try? context.delete(model: TenseGuide.self)
try? context.save()
// Re-seed
// Re-seed tense guides from the bundled JSON
if let url = Bundle.main.url(forResource: "conjuga_data", withExtension: "json"),
let data = try? Data(contentsOf: url),
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let guides = json["tenseGuides"] as? [[String: Any]] {
for g in guides {
guard let tenseId = g["tenseId"] as? String,
let title = g["title"] as? String,
let body = g["body"] as? String else { continue }
context.insert(TenseGuide(tenseId: tenseId, title: title, body: body))
}
try? context.save()
print("Re-seeded \(guides.count) tense guides")
}
// Re-seed course data
seedCourseData(context: context)
shared.set(courseDataVersion, forKey: courseDataKey)

View File

@@ -19,9 +19,9 @@ struct GrammarNotesListView: View {
@Binding var selectedNote: GrammarNote?
private var groupedNotes: [(String, [GrammarNote])] {
let grouped = Dictionary(grouping: GrammarNote.allNotes, by: \.category)
let grouped = Dictionary(grouping: GrammarNote.allNotesIncludingGenerated, by: \.category)
var seen: [String] = []
for note in GrammarNote.allNotes {
for note in GrammarNote.allNotesIncludingGenerated {
if !seen.contains(note.category) {
seen.append(note.category)
}

View File

@@ -450,14 +450,17 @@ struct GuideContent {
var spanishLine: String?
func flushUsage() {
if currentUsageNumber > 0 {
// Only emit a usage if it has at least one example. This suppresses
// the implicit "Usage 1" seeded when we enter an unnumbered
// *Usages* block but the body actually has numbered headers below.
if currentUsageNumber > 0 && !currentExamples.isEmpty {
usages.append(GuideUsage(
number: currentUsageNumber,
title: currentUsageTitle,
examples: currentExamples
))
currentExamples = []
}
currentExamples = []
}
for line in lines {
@@ -491,6 +494,11 @@ struct GuideContent {
let title = String(match.1).replacingOccurrences(of: "*", with: "")
if title.lowercased().contains("usage") {
inUsages = true
// Seed an implicit Usage 1 so content that follows without a
// numbered "*1 Title*" header still gets captured. Any numbered
// header below will replace this via flushUsage().
currentUsageNumber = 1
currentUsageTitle = "Usage"
continue
}
}

File diff suppressed because one or more lines are too long