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.

The tablero is the heart of ComuniTEA — a full-screen, landscape-oriented AAC (Augmentative and Alternative Communication) board modeled on the PECS communication system. Children navigate pictogram categories, tap individual symbols to compose a structured sentence in the frase strip at the top of the screen, and press the play button to hear the complete phrase read aloud in a warm, natural voice. Every interaction is designed for low cognitive load: navigation is always one or two taps deep, and the visual language is consistent throughout.

How the tablero works

1

Choose a category

The bottom section of the screen shows subcategory tiles organized by topic (Frutas, Comida, Emociones, Actividades, etc.). The child taps a tile to open its pictograms inline, scrolling the list into view. A category overlay drawer is also available for quick jumping between topics.
2

Tap a pictogram

Tapping a pictogram immediately plays its individual audio clip and routes it into the correct slot in the frase strip. Pictograms from the personas category go into the Persona slot; pictograms from peticiones go into the Petición slot; everything else fills the Objeto slots (up to two objects can be added).
3

Build the sentence strip

The frase strip at the top of the screen shows up to four ordered slots: [Persona] [Petición] [Objeto 1] [Objeto 2]. The strip becomes active (the play button enables) as soon as a petición has been selected. The child can tap any slot to remove that pictogram, or use the clear button to reset the entire strip.
4

Play the full sentence

Pressing the play (▶) button speaks the complete phrase aloud. The app expands short pictogram labels into natural-sounding sentences before handing them to the TTS engine — for example, "Yo" + "Quiero" + "Manzana" becomes “Yo quiero una manzana”. Each completed playback is recorded via recordSentenceSpoken() for the progress reports.

The Pictograma interface

Every symbol on the tablero is represented by a Pictograma object. The interface is defined in features/tablero/data/tablero.ts:
export interface Pictograma {
  id: string;
  emoji: string;
  label: string;
  categoria: string;
  esFavorito: boolean;
  /**
   * Key in `getAudioAssets(perfil)` from `constants/AudioAssets.ts`.
   * If omitted, `id` is used to resolve the MP3 clip (e.g. `manzana` → manzana.mp3).
   */
  audioAssetKey?: string;
  /** Child's photo or a remote image URI (personas / tablero). */
  imageUri?: string;
}
The helper getPictogramAudioKey(p) returns p.audioAssetKey ?? p.id, ensuring that pictograms with aliased MP3 names (e.g. fresafresas.mp3) resolve correctly while keeping id values clean for database logging.

Fixed rows: personas and peticiones

Two rows are always visible at the top of the vocabulary area regardless of which subcategory is active.

PERSONAS_ROW — family and caregivers

export const PERSONAS_ROW: Pictograma[] = [
  pic('mama',  '👩',    'Mamá',  'personas'),
  pic('papa',  '👨',    'Papá',  'personas'),
  pic('profe', '👩‍🏫', 'Profe', 'personas'),
  pic('nico',  '👦',    'Nico',  'personas'),
];
When a caregiver configures important_people in the child’s profile, the default row is replaced entirely by custom entries. The child’s own avatar ("Yo", audio key core-yo) is always prepended as the first persona.

PETICIONES_ROW — communicative intents

export const PETICIONES_ROW: Pictograma[] = [
  pic('quiero',   '🤲', 'Quiero',    'peticiones'),
  pic('no-quiero','🚫', 'No quiero', 'peticiones'),
  pic('me-gusta', '❤️', 'Me gusta',  'peticiones'),
  pic('me-duele', '😣', 'Me duele',  'peticiones'),
  pic('ayuda',    '🙋', 'Ayuda',     'peticiones'),
];
Peticiones map directly to PECS Phase III communicative functions: requesting, rejecting, expressing preference, reporting pain, and requesting assistance.

Subcategories (ALL_SUBCATS)

The default vocabulary is organized into seven subcategories. Each Subcategoria bundles its pictograms and carries its own emoji and nombre for display in the category tiles.
IDNombreEmojiPictograms
frutasFrutas🍎Manzana, Plátano, Naranja, Uvas, Fresa
comidaComida🍽️Jugo, Galleta, Huevo, Pan, Arroz
juguetesJuguetes🧸Auto, Pelota, Oso, Estrella
verdurasVerduras🥕Zanahoria, Tomate, Brócoli
golosinasGolosinas🍬Caramelo, Chocolate, Helado
actividadesActividades🎮Dormir, Baño, Jugar, Leer
emocionesEmociones😊Feliz, Triste, Enojado, Asustado
A dynamic “Le gusta” subcategory is generated from the child’s preferred_activities profile field and is injected at the top of the list when present.

buildMergedBoard() — merging custom pictograms

features/tablero/buildMergedBoard.ts exports two merge functions that combine the static board data with per-child personalizations stored in Supabase:
/**
 * Returns ALL_SUBCATS plus a dynamic "Le gusta" subcategory
 * built from the child's preferred_activities profile field.
 */
export function mergeAllSubcats(
  preferred: string[] | null | undefined
): Subcategoria[]

/**
 * Returns [childPicto, ...customPeople] when important_people is set,
 * or [childPicto, ...PERSONAS_ROW] as the default fallback.
 */
export function mergePersonasRow(
  importantPeople: string[] | null | undefined,
  childAvatarUrl?: string | null
): Pictograma[]
Important people are stored as "emoji|Nombre" pipe-delimited strings (e.g. "👩|Mamá"). The formatImportantPersonLine / parseImportantPersonLine helpers handle encoding and decoding. To seed the list from the defaults when a user adds their first custom person, call seedImportantPeopleFromPersonasRow().

The sentence strip (useFrase)

The useFrase hook manages the four-slot sentence buffer and all audio playback for the frase bar. The FraseState interface describes the slot layout:
export interface FraseState {
  slotPersona: Pictograma;
  slotPeticion: Pictograma | null;
  slotsObjeto: [Pictograma | null, Pictograma | null];
  /** true when a petición has been set — enables the ▶ button */
  fraseLista: boolean;
}
The hook returns the following values and methods:
Return valueTypeDescription
slotPersonaPictogramaCurrently set persona (defaults to child avatar)
slotPeticionPictograma | nullCurrently set petición
slotsObjeto[Pictograma | null, Pictograma | null]Up to two objeto slots
slots(Pictograma | null)[]All four slots as a flat array [persona, peticion, obj1, obj2]
fraseListabooleantrue when slotPeticion !== null — enables the ▶ button
puedeHablarbooleanAlias for fraseLista
agregarPersona(p)(p: Pictograma) => voidSets the persona slot directly
agregarPeticion(p)(p: Pictograma) => voidSets the petición slot directly
agregarObjeto(p)(p: Pictograma) => voidAdds to next available objeto slot
agregarPictograma(p)(p: Pictograma) => voidRoutes p to the correct slot by p.categoria
quitarPictograma(index)(index: number) => voidRemoves the pictogram at slot 0–3
limpiarFrase()() => voidResets petición and objeto slots; resets persona to the child’s avatar
leerFrase()() => Promise<void>Plays the full sentence using speakFrasePhrase()
agregarPictograma handles routing automatically: categoria === 'personas' → persona slot; categoria === 'peticiones' → petición slot; anything else → next available objeto slot (slot 2 then slot 3, overwriting slot 3 if both are full).

Voice audio system

ComuniTEA ships with bundled MP3 audio clips for both a femenina and masculina voice profile. Audio is resolved through getAudioAssets(perfil) from constants/AudioAssets.ts, which maps pictogram IDs to the correct require’d module. When a pictogram is played individually (on tap), the clip for that pictogram’s audioAssetKey (or id) is looked up in the asset map and played immediately. For full-sentence playback, speakFrasePhrase() in lib/speakFrasePhrase.ts is used. This function:
  1. Passes the phrase through expandTableroSlots() to generate a natural-language sentence (using the user’s XP level to choose expansion complexity).
  2. Checks network connectivity via useNetwork().
  3. If online, calls the ElevenLabs TTS API for higher-quality neural speech.
  4. If offline or if ElevenLabs fails, falls back to expo-speech (on-device TTS) with Spanish (es-MX) locale and the configured tts_speed from parental settings.
All individual pictogram audio clips are bundled inside the app binary. Core vocabulary (quiero, no quiero, ayuda, all food items, emotions, etc.) plays instantly even with no internet connection. ElevenLabs neural voice is used only for full-sentence playback when online.

useTablero hook

The useTablero hook is the top-level state coordinator for the tablero screen. It composes mergeAllSubcats, mergePersonasRow, useChildProfile, and useUserGroup to produce a fully resolved board state:
export function useTablero(): {
  subcategorias: Subcategoria[];        // visible subcats (sliced by maxSubcategoriasVisibles)
  categorias: CategoriaResumen[];       // deduplicated category list for the overlay
  categoriaActiva: string | null;       // currently highlighted category id
  overlayVisible: boolean;              // category picker drawer state
  openOverlay: () => void;
  closeOverlay: () => void;
  selectCategoria: (categoriaId: string) => void;  // scrolls FlatList to the selected category
  clearCategoriaActiva: () => void;
  categoriaActivaLabel: string | null;
  listRef: React.RefObject<FlatList<Subcategoria>>;
  personas: Pictograma[];               // merged personas row
  peticiones: Pictograma[];             // always PETICIONES_ROW
  favoritos: Pictograma[];              // all pictograms with esFavorito === true
  state: TableroState;
}
The maxSubcategoriasVisibles limit comes from useUserGroup() and ensures that children assigned to lower exercise groups see a simplified vocabulary set, reducing visual overload. categorias is derived by grouping all subcategories from mergeAllSubcats (the full unsliced list) via categoriasFromSubcats(), so the overlay always shows the complete category index even when subcategorias is trimmed.

Build docs developers (and LLMs) love