Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ElthonJohan/comunitea/llms.txt

Use this file to discover all available pages before exploring further.

Vocabulary in ComuniTEA is a living system managed entirely by the caregiver or therapist, never by the child. The communication board draws from three sources that are merged at runtime: the built-in pictogram catalogue (whose breadth is governed by the active VocabLevel), custom “Mi mundo en fotos” pictograms that the caregiver photographs and names, and a set of disabled-pictogram overrides that hide irrelevant items without deleting them. All of this is orchestrated from the Vocabulary Manager screen, accessible once the parental gate PIN has been entered.

Three Vocabulary Levels

VocabLevel is defined in context/AuthContext.ts and determines how much of the built-in catalogue appears on the board:
type VocabLevel = 'BASICO' | 'INTERMEDIO' | 'AVANZADO';

BASICO

Essential vocabulary — the minimum viable set for a child just starting with AAC. Covers food, emotions, bathroom, sleep, toys, and the core “Quiero / No quiero” intention buttons. Vocabulary label: “Vocabulario esencial”.

INTERMEDIO

More categories and contexts — everything in BASICO plus clothing, places, daily routine (“Mi día”), social phrases, numbers, and colours. Vocabulary label: “Más categorías y contextos”.

AVANZADO

Full vocabulary — the complete catalogue including advanced verb phrases, school items, week-day agenda, multi-turn conversation starters, and emergency help phrases. Vocabulary label: “Vocabulario completo”.
The current level is changed from Settings → Control parental → Nivel de vocabulario without any re-configuration of the child profile. The updateLevel() function from useAuth() persists the change to the profiles table.
Start the child at BASICO even if their communication level maps to INTERMEDIO. ComuniTEA’s board is intentionally limited to six pictograms per subcategory view to avoid cognitive overload. Give the child time to build familiarity with the core items before unlocking the broader vocabulary.

Built-In Pictogram Categories

The VOCABULARY object in constants/Vocabulary.ts provides the full catalogue indexed by level. The vocabulary-manager.tsx screen flattens this structure using buildSections(level) to display every individual pictogram as a toggleable row. The main categories across all levels include:
CategoryidSome items
Yo (Self)yomi nombre, tengo hambre, tengo sed, me duele, estoy cansado
Emocionesemocionesfeliz, triste, enojado, asustado, calma, aburrido, confundido
Comidacomidafrutas, verduras, bebidas, dulces, carnes, lácteos, menú
Bañobanoinodoro, papel, ducharse, lavado, dientes
Dormirdormircama, pijama, luz, osito, silencio
Jugarjugarformas, animales, gestos
Juguetesjuguetespelota, carro, legos, dinosaurio, muñeca, tren, plastilina
Roparopapolo, pantalón, zapatos, casaca, chompa, vestido, falda
Personaspersonashermano, hermana, abuela, abuelo, maestra, amigo
Socialsocialhola, adiós, gracias, por favor, sí, no
Mi díami-dialevantarse, desayunar, bañarse, vestirse, colegio, llegar a casa
Colorescoloresrojo, azul, verde, amarillo, negro, blanco
Númerosnumerosuno through diez
Lugarlugarcasa, escuela, parque, tienda, médico
Quieroquierocomer, televisión, mamá, papá
No quierono-quierono me gusta, no jugar, no dormir, me molesta
Avanzadovariousschool items, verbs, agenda days, conversation starters, help phrases
Categories are rendered in VocabularyManagerScreen using a SectionList with each section header showing the category emoji and name, and each row showing the pictogram emoji, label, optional parent-category label, and a Switch to toggle visibility.

Custom Pictograms (“Mi Mundo en Fotos”)

Caregivers can add personalised pictograms using photos taken or selected from the device gallery. These are stored in the custom_pictograms Supabase table and displayed alongside built-in pictograms in the matching category.

useCustomPictograms() Hook

// features/vocabulario/hooks/useCustomPictograms.ts

export interface CustomPictogram {
    id: string;
    user_id: string;
    category_key: string | null;
    label: string;
    /** Remote URL in Supabase Storage — always available. */
    image_url: string;
    /** Local filesystem URI — available after first offline warmup. */
    local_uri?: string;
    audio_url: string | null;
    created_at: string;
}

// Usage:
const { pictograms, loading, savePictogram, deletePictogram, reload } =
    useCustomPictograms(categoryKey);
useCustomPictograms(categoryKey) filters the table by category_key so the hook only loads the pictograms relevant to the currently open category. Pass null as categoryKey to get an empty result (useful when no category is selected yet).

Adding a Custom Pictogram

The typical flow for adding a custom pictogram:
1

Pick an image

Use expo-image-picker to open the device camera or gallery. The app requests media library permissions and crops the image to a 1:1 square at 70% quality.
2

Upload to Supabase Storage

The image is uploaded to the pictograms bucket. The returned public URL is passed to savePictogram().
3

Save the record

savePictogram(imageUrl, label) inserts a row into custom_pictograms with user_id, category_key, label, and image_url. The new pictogram is appended to the local state immediately (optimistic update).
await savePictogram(imageUrl, label.trim());
4

Pre-warm offline cache

After loading, useCustomPictograms calls prewarmCache(loaded) in the background to cache the images locally so they are available offline.

Deleting a Custom Pictogram

deletePictogram(id) removes the pictogram from local state immediately, then deletes the file from supabase.storage.from('pictograms') and the database row from custom_pictograms. The local offline cache entry is also cleared via removeCached(id).

Disabling Pictograms

Not all built-in pictograms are relevant to every child. Rather than permanently removing items, useDisabledPictograms() maintains a Set<string> of hidden pictogram IDs persisted in AsyncStorage under STORAGE_KEYS.DISABLED_PICTOGRAMS.
// features/vocabulario/hooks/useDisabledPictograms.ts

const { isDisabled, toggle, loaded } = useDisabledPictograms();

// Check if a pictogram is hidden:
if (isDisabled('pelota')) { /* ... */ }

// Toggle visibility:
await toggle('pelota');
toggle(id) flips the enabled/disabled state, persists the new set to AsyncStorage, and writes a vocabulary_pictogram_toggle entry to config_audit_log via auditLog() — so therapists can review which pictograms were hidden and when. The VocabularyManagerScreen uses isDisabled to render disabled rows at 45% opacity with a strikethrough label, and the Switch component in each row calls toggle() directly:
<Switch
    value={!isDisabled(item.id)}
    onValueChange={() => toggle(item.id)}
    trackColor={{ false: Colors.border, true: Colors.primary }}
    thumbColor={Colors.white}
/>

Vocabulary Manager Screen

app/vocabulary-manager.tsx is the main UI for all vocabulary management. It is accessible from Settings → Control parental → Gestión de vocabulario and requires the parental gate PIN. The screen shows a live count of active and hidden pictograms in the header:
Gestor de vocabulario
47 activos · 3 ocultos
It builds the section list using buildSections(level) from the current user’s profile.level, flattening subcategories with flattenItems() so that every individual leaf pictogram appears as its own row — not just the category header.

Activity Editor

app/activity-editor.tsx lets caregivers create guided activity sequences — structured sessions with a specific theme or routine the child works through with pictograms. Activities are stored in Supabase and accessed via the useActivities() hook from features/vocabulario/hooks/useActivities.ts. The Activity Editor is accessible from Settings → Control parental → Actividades guiadas.

AI Magic Expand (useMagicExpand)

The AI Magic Expand feature expands a partial sentence already on the communication bar into a fuller, contextualised utterance using the ai-expand Supabase Edge Function. It is available on the Dashboard and Category screens as a “magic wand” button.
// features/vocabulario/hooks/useMagicExpand.ts

const { handleMagicExpand, isExpanding } = useMagicExpand();
handleMagicExpand() reads the current sentence from the useSentence() context, determines the time of day and the last completed routine, and posts to the ai-expand Edge Function:
const res = await fetch(`${supabaseUrl}/functions/v1/ai-expand`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`,
    },
    body: JSON.stringify({
        pictogramLabels: labels,
        vocabularyLevel: profile?.level ?? 'INTERMEDIO',
        timeOfDay,
        lastRoutine,
    }),
});

const { expandedText } = await res.json();
if (expandedText) {
    await speakFreeText(expandedText); // Neural TTS via ElevenLabs
}
The expanded text is spoken aloud via speakFreeText() (which uses the ElevenLabs TTS path) and the event is logged via logEvent('ai_expand', { latencyMs, sentenceLength }) for usage reporting. useMagicExpand requires an active internet connection — if the Edge Function call fails, an error alert is shown without modifying the communication bar.

buildMergedBoard()

At runtime, features/tablero/buildMergedBoard.ts merges the default communication board structure with child-specific additions. Two key functions are used on every board render:
// Merge default subcategories + "Le gusta" (preferred activities)
mergeAllSubcats(preferred: string[] | null | undefined): Subcategoria[]

// Build the Personas row: child's "Yo" picto first, then custom people
mergePersonasRow(
    importantPeople: string[] | null | undefined,
    childAvatarUrl?: string | null,
): Pictograma[]
mergeAllSubcats() prepends a “Le gusta” subcategory to ALL_SUBCATS when the child profile has preferred_activities entries. mergePersonasRow() inserts the child’s own avatar as the “Yo” pictogram and replaces the default placeholder people with the custom important_people list from the child profile. Neither function modifies the stored vocabulary data — all merging happens in memory on each render.

Build docs developers (and LLMs) love