Site feito para o agrinho, sobre agricultura sustentável, desenvolvido em 2026 com HTML, CSS e JavaScript.
- Sobre o projeto
- O concurso e o que o regulamento exige
- A regra que guia todo o projeto: sem servidor, sem biblioteca, sem nada
- Tecnologias e APIs do navegador
- Como abrir e usar o site
- Estrutura de pastas
- Como o front-end está organizado
- Componentes globais
- Design system
- Acessibilidade
- Modo escuro
- Página inicial
- Aprender
- Quizzes
- Analisar e Capturar
- Resultados — o simulador de talhão
- Jogo — Lavoura em Equilíbrio
- Glossário
- Agrinho
- Dados salvos no navegador
- Escopo educativo e limitações
- Privacidade e segurança
- Guia de manutenção
- Roteiro de testes
- Créditos e fontes
O Terra Roxa é um site educativo que criei, que apresenta de forma interativa a ideia de uma agricultura que mostra cuidados sobre produção e meio ambiente, criando um agro forte, que por sua vez, gera uma cultura sustentável. Ele reúne conteúdos de leituras, quizzes, análise visual automática de folhas de feijão e milho, um simulador do seu próprio campo em pixel art e um mini-game.
Todos esses pensados para explicar conceitos de campo de um jeito educativo e simples!
O objetivo é organizar esse conteúdo em um site estático, que funciona só com o navegador, sem servidor, banco de dados ou etapa de instalação. A proposta não é representar um sistema agrícola real nem substituir orientação técnica... É oferecer um material de estudo e demonstração construído inteiramente com tecnologias de front-end. E claro, para o agrinho! :)
Eu desenvolvi o Terra Roxa para o Concurso Agrinho 2026, promovido pelo SENAR-PR e pela SEED-PR, na categoria de Programação — mais precisamente na Subcategoria 3: Programação Front-End (HTML, CSS e JavaScript), voltada a estudantes do Ensino Médio da rede pública do Paraná.
O tema proposto pelo concurso é:
Agro forte, futuro sustentável: equilíbrio entre produção e meio ambiente.
Todo o conteúdo do site gira em torno desse tema. As trilhas de estudo, os quizzes, a análise de folhas, o simulador e o jogo abordam aspectos do equilíbrio entre produzir alimentos e preservar solo, água e biodiversidade, sempre com linguagem voltada ao público escolar.
O regulamento da Subcategoria 3 traz regras técnicas bem específicas, e elas guiaram boa parte das minhas decisões. Por isso, deixei registrado abaixo cada uma delas e como procurei atendê-la:
| Exigência do regulamento | Como o Terra Roxa atende |
|---|---|
| Usar somente HTML, CSS e JavaScript | O site inteiro usa apenas essas três linguagens, sem nenhuma outra. |
| Não utilizar frameworks | Não há React, Vue, jQuery, Bootstrap nem qualquer biblioteca. Tudo é escrito à mão. |
| Sem CSS ou JavaScript embutido (inline) no HTML | Estilos e scripts ficam em arquivos .css e .js, sempre declarados nos HTML. |
| Repositório público com todos os arquivos para rodar | Todo o HTML, CSS, JS e as mídias estão versionados no repositório. |
| README com instruções de uso, lista de tecnologias e o objetivo do tema | Estão nas seções 5, 4 e 1–2 deste documento, respectivamente. |
| Código identado, com comentários breves nas funções JS | O código segue indentação consistente e comenta os trechos centrais. |
| Mídias organizadas em pastas próprias | Imagens em public/images/, ícones em icons/, fontes em public/fonts/. |
| Sem erros no console e com todos os caminhos funcionando | Os caminhos são relativos e resolvidos com cuidado (ver seção 8). |
Há ainda duas exigências que pertencem à configuração do repositório, e não ao código
em si, mas que valem o registro porque a rubrica as pontua: a etiqueta (topic) oficial
agrinho precisa estar configurada nos topics do repositório no GitHub, e o link do
GitHub Pages (ou Vercel) onde o site está publicado deve estar declarado e funcional no
campo About.
Mais do que uma regra a cumprir, fazer tudo sem dependências virou o princípio que guiou o projeto inteiro. Como quase toda decisão que tomei nasce daqui, vale explicar o que isso significa na prática.
Não há servidor nem back-end. Nenhuma parte do site precisa de um processo rodando do
outro lado. Não existe API própria, rota, endpoint ou camada de servidor. Abrir o
index.html é suficiente para o site funcionar por inteiro.
Não há banco de dados. Nada é gravado em um banco externo. Quando o site precisa
lembrar de alguma coisa — o progresso de uma trilha, a melhor pontuação do jogo, as
preferências de acessibilidade —, ele usa o localStorage do próprio navegador, que vive
na máquina de quem está usando. Os dados ficam ali e não saem dali (ver seção 20).
Não há framework nem biblioteca. Não usei React, Vue, Angular, jQuery, Bootstrap, Tailwind, D3 nem nenhum outro pacote. Tudo o que normalmente a gente joga para uma biblioteca, resolvi com os próprios recursos do navegador: componentes reusáveis viraram Web Components, os gráficos e o mapa do simulador são desenhados na Canvas API, as animações usam CSS e a Web Animations API, e a leitura por voz usa a Web Speech API. Não foi por purismo: o regulamento veda frameworks, e o resultado acabou sendo um projeto leve, sem etapa de build e sem código de terceiros para auditar.
Não há etapa de instalação ou compilação. Não existe package.json, node_modules,
bundler, transpilador ou comando obrigatório. O que está no repositório é exatamente o
que roda no navegador. Isso torna o projeto fácil de publicar (basta servir os arquivos) e
fácil de inspecionar (o código não é minificado nem gerado).
Não há dependência de CDN. Fontes e ícones são servidos localmente, a partir das pastas
do próprio projeto. Não há <link> ou <script> apontando para servidores externos. Em
consequência, o site funciona mesmo offline, depois de aberto.
O quadro abaixo resume as escolhas que substituíram as dependências usuais:
| No lugar de… | O Terra Roxa usa… |
|---|---|
| Um framework de componentes | Web Components nativos (<terra-header>, <terra-accessibility>) |
| Um banco de dados / login | localStorage no navegador |
| Uma biblioteca de gráficos | Desenho manual na Canvas API |
| Uma CDN de fontes/ícones | Arquivos locais em public/ e icons/ |
| Um bundler e cache de build | Páginas separadas e cache busting por query string |
Tudo o que usei é nativo do navegador — não há nada para instalar.
- HTML5 — a estrutura semântica de cada página, com tags como
header,nav,main,section,articleefooter. - CSS3 — layout (Flexbox e Grid), responsividade com media queries, tema, animações e o design system inteiro baseado em variáveis (custom properties).
- JavaScript (ES) puro — toda a interatividade e a lógica das páginas, organizada em um arquivo por página mais dois componentes compartilhados.
- Web Components / Custom Elements — o cabeçalho e o painel de acessibilidade são
elementos customizados (
<terra-header>e<terra-accessibility>), reaproveitados em todas as páginas sem repetição de HTML. - Canvas API — usada para ler os pixels da imagem na análise de folhas e para desenhar o mapa em pixel art do simulador de talhão, seu minimapa e os efeitos do jogo.
- Web Animations API — anima aberturas e transições (como o acordeão do FAQ) de um jeito que respeita a opção de reduzir movimento.
- Web Speech API (SpeechSynthesis) — lê em voz alta o conteúdo apontado, quando o navegador oferece suporte.
- MediaDevices / getUserMedia — acessa a câmera na página de captura, quando o usuário autoriza.
- localStorage — guarda progresso, preferências e históricos no próprio navegador.
- IntersectionObserver — dispara animações (como os contadores da home) só quando o elemento entra na tela.
- Fontes WOFF2 e ícones SVG locais — incluindo a fonte OpenDyslexic, carregada da pasta do projeto.
Uma observação que o regulamento cobra explicitamente: scripts e folhas de estilo são
sempre declarados nos arquivos HTML por meio de <link> e <script>. Não há CSS em
atributos style nem JavaScript embutido nas páginas.
Por ser um site estático, não há instalação, dependências ou build. Há duas formas de abrir.
Forma mais simples — abrir o arquivo:
1. baixe ou clone a pasta do projeto
2. dê um duplo clique em index.html (ou arraste-o para o navegador)
3. navegue pelas páginas usando o menu no topo
Forma recomendada — servir por um servidor estático local. Abrir via file://
funciona para quase tudo, mas alguns recursos do navegador (como o acesso à câmera) só são
liberados em http:// ou https://. Se você tiver o Python instalado, um servidor local
resolve, sem instalar nada além disso:
# dentro da pasta do projeto
python -m http.server 8000
# depois acesse http://localhost:8000 no navegadorO site também funciona publicado em qualquer hospedagem de arquivos estáticos, como o GitHub Pages ou a Vercel — que são, aliás, as opções previstas pelo regulamento.
Sobre a câmera: na página de análise, a captura por câmera só é ativada quando o navegador autoriza o acesso. Se a câmera estiver bloqueada ou indisponível, a própria página oferece o envio de uma foto como alternativa, de modo que nada se perde e tudo continua dentro do escopo estático.
terra-roxa/
├── index.html página inicial
├── README.md este documento
│
├── agrinho/ página sobre o programa Agrinho
│ └── index.html
├── analisar/ entrada da análise visual
│ ├── index.html
│ └── capturar/ captura, upload e resultado da análise
│ └── index.html
├── aprendizado/ trilhas de estudo
│ └── index.html
├── glossario/ consulta de termos técnicos
│ └── index.html
├── jogo/ mini-game "Lavoura em Equilíbrio"
│ └── index.html
├── quizzes/ quizzes de revisão
│ └── index.html
├── resultados/ simulador de talhão
│ └── index.html
│
├── css/
│ ├── style.css base visual e componentes globais
│ ├── theme-dark.css ajustes do modo escuro
│ ├── pages/ um arquivo de estilo por página
│ │ ├── agrinho.css
│ │ ├── analisar.css
│ │ ├── aprendizado.css
│ │ ├── glossario.css
│ │ ├── jogo.css
│ │ ├── quizzes.css
│ │ └── resultados.css
│ └── sections/ seções reutilizadas (FAQ, rodapé, próximos passos)
│ ├── faq.css
│ ├── footer.css
│ └── next-actions.css
│
├── js/
│ ├── components/ Web Components globais
│ │ ├── site-header.js
│ │ └── accessibility-dock.js
│ ├── main.js interações da página inicial
│ ├── courses.js dados das trilhas de estudo
│ ├── aprendizado.js interface e progresso das trilhas
│ ├── quizzes.js lógica dos quizzes
│ ├── analisar.js entrada e histórico da análise
│ ├── detector.js fluxo de captura, upload e resultado
│ ├── leaf-vision.js classificador de cores da folha
│ ├── diagnostics-data.js textos das condições da folha
│ ├── analise-historico.js histórico local das análises
│ ├── resultados.js simulador de talhão
│ ├── jogo.js motor do mini-game
│ ├── glossario-data.js base de 1.200 termos do glossário
│ ├── glossario.js busca e lista virtualizada
│ └── agrinho.js interações da página Agrinho
│
├── icons/ 76 ícones em SVG
└── public/
├── fonts/ fontes locais (inclui a OpenDyslexic e sua licença)
└── images/ 60 imagens, organizadas por seção
Em números redondos, são 9 páginas HTML, 12 arquivos CSS, 16 arquivos JavaScript, 60 imagens e 76 ícones. As mídias ficam sempre separadas em pastas próprias, como o regulamento pede.
Organizei tudo seguindo uma ideia simples, repetida em todas as páginas: um HTML por página, estilos globais separados dos estilos específicos, e um script dedicado para cada página, somados a dois componentes que aparecem em todas elas.
Separação de responsabilidades. Cada página carrega a base (style.css), os ajustes de
tema (theme-dark.css) e, quando precisa, seu CSS específico em css/pages/. No
JavaScript, a regra é a mesma: o que é global vem dos componentes em js/components/, e o
resto fica no script daquela página.
Dados fora da lógica. Os conteúdos mais volumosos não ficam embutidos no HTML nem
misturados ao código que os exibe. As trilhas de estudo vivem em courses.js, os 1.200
termos do glossário em glossario-data.js e os textos das condições da folha em
diagnostics-data.js. Cada um desses arquivos publica seus dados em um objeto global
(window.TerraRoxaCourses, window.TerraDiagnostics, etc.), que o script da página
consome. Assim, atualizar conteúdo é mexer em dados, não em lógica.
Relação entre páginas, scripts e estilos:
| Página | Caminho | Script(s) principal(is) | CSS específico |
|---|---|---|---|
| Início | index.html |
main.js |
seções faq, next-actions, footer |
| Aprender | aprendizado/index.html |
courses.js, aprendizado.js |
pages/aprendizado.css |
| Quizzes | quizzes/index.html |
courses.js, quizzes.js |
pages/quizzes.css |
| Analisar | analisar/index.html |
(componentes globais) | pages/analisar.css |
| Capturar | analisar/capturar/index.html |
leaf-vision.js, diagnostics-data.js, analise-historico.js, detector.js, analisar.js |
pages/analisar.css |
| Resultados | resultados/index.html |
resultados.js |
pages/resultados.css |
| Jogo | jogo/index.html |
jogo.js |
pages/jogo.css |
| Glossário | glossario/index.html |
glossario-data.js, glossario.js |
pages/glossario.css |
| Agrinho | agrinho/index.html |
agrinho.js |
pages/agrinho.css |
Em todas as páginas estão presentes os dois scripts globais — site-header.js e
accessibility-dock.js — e as folhas de estilo base.
Cache busting. Para garantir que o navegador não reutilize uma versão antiga de um
arquivo do cache, os CSS e JS são carregados com uma query string de versão, como
style.css?v=... ou quizzes.js?v=.... Quando um arquivo importante muda, basta atualizar
esse número no HTML correspondente para forçar o recarregamento. É uma técnica manual e
sem ferramentas — coerente com a proposta sem build.
Para não copiar o mesmo cabeçalho e o mesmo painel de acessibilidade em nove páginas, escrevi essas duas partes como Web Components — elementos HTML customizados, recurso nativo do navegador. Cada página só declara a tag; o componente cuida do resto.
Este componente monta o cabeçalho e o menu de navegação. Ele tem duas particularidades que resolvem problemas comuns de um site com páginas em subpastas:
- Caminhos relativos corretos. Como as páginas vivem em subpastas de profundidades
diferentes (
quizzes/está um nível abaixo da raiz;analisar/capturar/está dois), um link fixo quebraria em algumas delas. O componente descobre a raiz do site a partir da própria URL do script e resolve cada link a partir dela, então o menu funciona igual em qualquer página. - Página ativa em destaque. Cada página declara qual item está ativo, e o componente
marca esse item com
aria-current="page", o que ajuda tanto visualmente quanto para leitores de tela.
O uso na página é direto:
<terra-header active="home"></terra-header>O atributo active aceita um destes valores, conforme a página: home, aprendizado,
quizzes, ia (Analisar), resultados, jogo, glossario ou agrinho. O componente
ainda cuida do menu sanfona no mobile, fechando-o ao clicar fora ou ao escolher um link.
Este componente desenha o painel lateral de acessibilidade e aplica as preferências escolhidas. Um detalhe de implementação importante: o estado salvo é lido e aplicado antes de a tela aparecer, ainda no carregamento do script, para que a página não "pisque" no tema claro antes de trocar para o escuro, por exemplo.
As preferências são guardadas no localStorage, sob a chave terra-roxa-accessibility, e
cada uma aplica uma classe no documento que o CSS usa para ajustar a aparência. A seção 10
detalha os recursos. O uso na página é igualmente simples:
<terra-accessibility></terra-accessibility>A base visual fica em css/style.css, e montei tudo sobre variáveis CSS declaradas em
:root. Centralizar cores, espaçamentos, tipografia e tempos de animação em um só lugar
mantém o site consistente e facilita ajustes — inclusive o modo escuro, que só precisa
redefinir algumas dessas variáveis.
:root {
/* cores */
--color-primary: #43215c; /* roxo principal */
--color-primary-light: #68417f; /* roxo claro */
--color-accent-yellow: #d99b37; /* dourado de destaque */
--color-accent-green: #748b58; /* verde principal */
--color-accent-dark-green: #4e6544;
--color-accent-clay: #b96b50; /* tom terroso */
/* fundos e textos */
--color-bg-main: #f7f0e8;
--color-bg-card: #fff9ef;
--color-bg-soft: #efe4d9;
--color-text-main: #43215c;
--color-text-muted: #725e77;
--color-text-light: #ffffff;
}Os tokens estão agrupados por finalidade:
Cores. Roxo principal e sua variação clara, dourado de destaque, dois tons de verde, um
tom terroso (clay), três fundos (principal, cards e secundário) e três cores de texto
(principal, secundário e claro sobre fundo escuro). Há também versões -rgb de algumas
cores, usadas quando o CSS precisa aplicar transparência via rgba().
Ícones. Os ícones são SVGs monocromáticos coloridos por filter de CSS — há filtros
prontos para tingi-los de roxo (--icon-filter-primary), verde (--icon-filter-green) ou
branco (--icon-filter-light). Isso permite reaproveitar o mesmo arquivo de ícone em
contextos de cores diferentes, inclusive no modo escuro.
Tipografia.
| Token | Uso |
|---|---|
--font-family |
texto geral (Trebuchet MS / Segoe UI / Arial) |
--font-family-display |
títulos (Georgia / Cambria, serifada) |
--font-family-dyslexic |
fonte OpenDyslexic, usada no modo dislexia |
--a11y-content-font-size |
tamanho do texto, controlado pela acessibilidade |
--a11y-content-line-height |
altura de linha do conteúdo |
--a11y-heading-line-height |
altura de linha dos títulos |
--a11y-word-spacing |
espaçamento entre palavras |
As variáveis com prefixo --a11y- são reescritas em tempo real pelo painel de
acessibilidade, o que faz o site inteiro responder ao aumento de fonte e de espaçamento sem
quebrar o layout.
Espaçamento, bordas e movimento.
| Espaçamento | Valor | Bordas | Valor | Movimento | Uso | ||
|---|---|---|---|---|---|---|---|
--spacing-xs |
0.5rem | --radius-sm |
8px | --transition-fast |
transições rápidas (0.2s) | ||
--spacing-sm |
1rem | --radius-md |
16px | --transition-micro |
microinterações (0.16s) | ||
--spacing-md |
1.5rem | --radius-lg |
24px | --transition-normal |
transições padrão (0.3s) | ||
--spacing-lg |
2rem | --radius-xl |
40px | ||||
--spacing-xl |
3rem | --radius-full |
9999px | ||||
--spacing-xxl |
5rem |
Sombras. O projeto opta por um visual mais "chapado": as variáveis de sombra
(--shadow-sm, --shadow-md, etc.) ficam em none por padrão, e a separação entre
elementos é feita com cor, borda e espaçamento em vez de sombras pesadas.
A fonte para dislexia é carregada localmente via @font-face, apontando para os arquivos
OpenDyslexic-Regular.woff2 e OpenDyslexic-Bold.woff2 em public/fonts/ — sem CDN.
Não quis tratar a acessibilidade como um extra: ela faz parte do componente que acompanha
todas as páginas. O painel <terra-accessibility> reúne os ajustes abaixo, todos aplicados
no front-end e lembrados entre visitas:
- Fonte maior — quatro níveis de tamanho (Normal, Maior, Grande, Extra), independentes do zoom geral do navegador.
- Espaçamento — três níveis que ampliam, juntos, a altura de linha e o espaçamento entre palavras, ajudando na leitura.
- Velocidade da narração — Normal, Lenta ou Rápida, para a leitura por voz.
- Modo escuro — alterna o tema do site (ver seção 11).
- Reduzir animações — minimiza ou desliga transições e efeitos, respeitando também a
preferência
prefers-reduced-motiondo sistema. - Alto contraste — reforça o contraste de texto e elementos.
- Fonte para dislexia — troca a tipografia pela OpenDyslexic.
- Sublinhar clicáveis — marca links e botões com sublinhado, tornando-os mais fáceis de identificar.
- Clique direito para ouvir — quando ativo, o clique com o botão direito sobre um texto faz o navegador lê-lo em voz alta (usando a Web Speech API, se houver suporte).
Cada opção liga uma classe no documento, que o CSS usa para mudar a aparência:
| Recurso | Classe / efeito |
|---|---|
| Reduzir animações | a11y-reduced-motion |
| Modo escuro | theme-dark |
| Alto contraste | a11y-contrast |
| Fonte para dislexia | a11y-dyslexic |
| Sublinhar clicáveis | a11y-underline |
| Tamanho e espaçamento | variáveis --a11y-* reescritas em tempo real |
Como o estado é guardado. Tudo fica na chave terra-roxa-accessibility do
localStorage, em um objeto com os campos fontIndex, lineIndex, speechRateIndex,
dark, reduceMotion, contrast, dyslexic, underline e speech. Na leitura, os
valores são validados (índices fora da faixa são corrigidos), de modo que um dado corrompido
nunca quebra a página. Há ainda um botão Redefinir, que volta tudo ao padrão.
Se o navegador não oferecer suporte à Web Speech API, as opções de narração aparecem desativadas e rotuladas como indisponíveis, em vez de simplesmente falharem.
O modo escuro vive em css/theme-dark.css e é ativado quando a classe theme-dark está
presente no elemento html. Como o site é construído sobre variáveis, o tema escuro em
boa parte apenas redefine essas variáveis de cor — e tudo que as consome se ajusta
junto.
Algumas áreas têm elementos mais delicados (gradientes, brilhos, ícones que poderiam sumir no escuro) e por isso recebem ajustes pontuais: a timeline da página Agrinho, o glossário, o analisador, o simulador, o jogo e o próprio painel de acessibilidade. A intenção desses ajustes é sempre a mesma — garantir que texto, ícones, cards e botões continuem legíveis e com contraste suficiente quando o fundo escurece.
A página inicial (index.html, com js/main.js) apresenta o projeto e encaminha o
visitante para as demais áreas. Além do hero de abertura, ela reúne uma explicação da
proposta, situações do campo, uma área de métricas, depoimentos, uma seção de perguntas
frequentes e chamadas para as próximas páginas.
A interatividade da home, concentrada em main.js, é toda feita à mão:
- Contadores animados. Os números das métricas sobem do zero até o valor final com uma
animação suave. Para não animar fora da tela, um
IntersectionObserversó dispara a contagem quando o número aparece; e, se o usuário pediu para reduzir animações, o valor final é mostrado direto. - Carrossel de depoimentos. Os cards giram em uma disposição em "órbita" (ativo ao centro, vizinhos nas laterais), com avanço automático a cada poucos segundos. O avanço pausa quando o ponteiro está sobre o carrossel ou quando ele recebe foco pelo teclado, e não roda se o modo de reduzir animações estiver ligado.
- FAQ em acordeão. Abrir uma pergunta fecha as demais. A altura é animada com a Web Animations API, e a animação é descartada quando o usuário prefere menos movimento.
- Dica que segue o cursor. Em telas com ponteiro fino (mouse), alguns elementos exibem uma pequena dica que acompanha o cursor; em telas de toque, ela simplesmente não aparece.
A página Aprender (aprendizado/index.html, com js/aprendizado.js) organiza o conteúdo
teórico em trilhas de estudo. Os dados de cada trilha vêm de js/courses.js, no objeto
global window.TerraRoxaCourses.
As trilhas disponíveis:
| Trilha | Duração | Lições |
|---|---|---|
| Agro forte, futuro sustentável | 35 min | 7 |
| Solo vivo | 18 min | 3 |
| Água no campo | 16 min | 3 |
| Biodiversidade que trabalha | 15 min | 3 |
| Manejo Integrado de Pragas | 20 min | 3 |
| Plantio direto e rotação | 19 min | 3 |
| Tecnologia com propósito | 17 min | 3 |
| Clima e resiliência | 18 min | 3 |
| Gestão e renda sustentável | 17 min | 3 |
| Campo e cidade conectados | 15 min | 3 |
Cada trilha é um objeto com slug, número, título, descrição, categoria, duração, número
de lições e os capítulos. Cada capítulo traz parágrafos e, quando faz sentido, um destaque
(callout), uma lista ou uma imagem de apoio. Muitas trilhas terminam com uma pergunta de
verificação e uma atividade prática sugerida.
O que a página guarda no navegador:
| Chave | Uso |
|---|---|
terra-roxa-course-progress |
progresso (em %) de cada trilha |
terra-roxa-course-notes |
anotações do usuário |
terra-roxa-course-seen |
trilhas já abertas |
terra-roxa-last-course |
última trilha aberta |
terra-roxa-course-completion-celebrated |
se a conclusão geral já foi comemorada |
O progresso é calculado conforme a rolagem dentro da trilha e fica salvo, de modo que ao
voltar a página reabre no ponto certo. Quando todas as trilhas são concluídas, uma
animação de comemoração (um confete desenhado na Canvas) aparece uma única vez — o registro
em localStorage evita repeti-la a cada visita.
A página Quizzes (quizzes/index.html, com js/quizzes.js) revisa o conteúdo das trilhas.
Como as perguntas derivam dos cursos, ela também carrega courses.js.
O fluxo cobre o ciclo completo de um quiz: listar os quizzes disponíveis, iniciar um, responder pergunta a pergunta, calcular o resultado e registrar a pontuação. Dois recursos de conforto se destacam:
- Rascunho automático. Se o usuário sai no meio de um quiz, as respostas já dadas ficam salvas como rascunho. Ao voltar, ele pode retomar de onde parou.
- Pontuação e retomada. O melhor resultado de cada quiz fica registrado, e a interface mostra um rótulo de progresso com base nele.
O que a página guarda:
| Chave | Uso |
|---|---|
terraRoxaQuizScores |
melhores pontuações por quiz |
terraRoxaQuizDrafts |
rascunhos de quizzes em andamento |
Um detalhe de implementação: a resposta correta de cada pergunta não fica gravada de forma óbvia no estado salvo. A verificação usa uma pequena assinatura, em vez de expor o índice da alternativa certa, para que não seja trivial "espiar" o gabarito pelo armazenamento do navegador. As transições de altura entre perguntas são animadas manualmente, para que o card não "salte" quando o tamanho do conteúdo muda.
Essa é a parte mais elaborada do projeto em termos de processamento, e também a que eu mais tomo cuidado ao descrever — por isso a seção 21 reforça seus limites.
A página Analisar (analisar/index.html) é a porta de entrada: ela apresenta a
ferramenta, explica o uso educativo e encaminha para a captura. Ela não executa a análise.
A página Capturar (analisar/capturar/index.html) é onde a análise acontece, e tudo se
passa dentro do navegador — nenhuma imagem é enviada para qualquer servidor. Os scripts
envolvidos dividem bem as tarefas:
detector.jscuida do fluxo de interface: escolher a cultura (milho ou feijão), enviar uma foto ou abrir a câmera, preparar a imagem em um<canvas>, mostrar o resultado e salvar no histórico.leaf-vision.jsé o "motor" da leitura de cores.diagnostics-data.jsguarda os textos de cada condição.analise-historico.jsadministra o histórico local.
Como a leitura funciona. A imagem é desenhada em um <canvas> e seus pixels são
percorridos (em uma amostragem, para manter tudo leve). Cada pixel é convertido de RGB para
o espaço de cor HSV, que separa melhor matiz, saturação e brilho. A partir daí, o
leaf-vision.js classifica a cor em uma de quatro faixas — verde, amarelo, laranja ou
marrom —, descartando antes o fundo branco e os tons frios (azuis), que não fazem parte da
folha. As faixas são definidas por limites simples de matiz, saturação e brilho.
Com a contagem de cada cor, o motor estima a cobertura (quanto da imagem é folha) e calcula uma pontuação para quatro condições, aplicando pesos diferentes para cada sinal:
| Condição | Sinal de cor associado |
|---|---|
| Folha saudável | predomínio de verde |
| Ferrugem | manchas alaranjadas |
| Mancha foliar | áreas marrons/secas |
| Amarelecimento (clorose) | amarelo difuso |
A condição mais provável é a de maior pontuação. O motor também mede a "indecisão" do resultado: se a cobertura de folha for baixa demais, ou se as condições ficarem muito empatadas (calculado por uma entropia normalizada), o resultado é marcado como de baixa confiança, e a interface comunica isso em vez de cravar um veredito. A barra de progresso que aparece durante a análise é uma animação de interface — a leitura em si é praticamente instantânea sobre a amostra de pixels.
Os textos do resultado vêm de diagnostics-data.js, que para cada condição traz um
resumo, sinais a observar, ações sugeridas, medidas de prevenção e uma nota específica por
cultura (feijão e milho). São textos educativos, escritos para ajudar o estudante a
entender o que aquele padrão de cor costuma indicar — sempre lembrando que observar não é
diagnosticar.
Histórico. Cada análise pode ser guardada localmente (analise-historico.js), na chave
terra-roxa:analises, limitada às 24 entradas mais recentes. Se o armazenamento do
navegador estiver cheio, o código reduz a lista pela metade em vez de falhar. A chave
terra-roxa-history-seen-count controla quantas análises já foram vistas, para sinalizar
novidades.
A página Resultados (resultados/index.html, com js/resultados.js) é um simulador
educativo de talhão, desenhado em pixel art. É o maior arquivo de JavaScript que escrevi
no projeto, e tudo nele — inclusive o desenho do mapa — é feito sem bibliotecas.
O mapa. O talhão é uma grade de células, desenhada célula a célula em um <canvas>. O
"terreno" inicial não é aleatório de qualquer jeito: ele é gerado por uma função de ruído
(value noise combinado em várias frequências, técnica conhecida como fbm) a partir de
uma semente, o que produz manchas de fertilidade e relevo com aparência orgânica e
reproduzível. O usuário navega com câmera e zoom, e um minimapa mostra a visão geral.
As decisões e os indicadores. O usuário aplica ações sobre as células — escolher culturas, ajustar fertilidade, etc. — e o simulador recalcula camadas e indicadores como crescimento, saúde da planta, pressão de pragas e risco de geada. A ideia é tornar visível a relação entre o que se decide e como o sistema responde. Há também uma checagem de conflitos (combinações que não fazem sentido) e um modo para daltonismo, que troca as cores das culturas por uma paleta mais distinguível.
Histórico, presets e persistência. O simulador mantém um registro das alterações que
permite desfazer e refazer (comparando "fotos" do estado antes e depois de cada
mudança). O estado é salvo automaticamente no localStorage, e o usuário pode guardar
configurações como presets para recarregar depois.
| Chave | Uso |
|---|---|
terraRoxaFieldMap |
estado atual do talhão |
terraRoxaFieldMap:presets |
configurações salvas pelo usuário |
Exportação. O talhão pode ser exportado em vários formatos, todos gerados pelo próprio navegador (sem servidor):
- JSON — o estado completo, para reabrir depois;
- CSV — uma planilha das células;
- GeoJSON — os polígonos das células como uma
FeatureCollection; - ISOXML — um arquivo no padrão ISO 11783, usado em maquinário agrícola;
- PNG — uma imagem do mapa, a partir do canvas.
O simulador também importa de volta um arquivo JSON exportado. Vale frisar (ver seção 21) que os dados são simulados: o talhão não representa nenhuma propriedade real e os indicadores são ilustrativos.
A página Jogo (jogo/index.html, com js/jogo.js) traz o mini-game "Lavoura em
Equilíbrio", que mostra de um jeito lúdico a tensão entre produzir e cuidar do ambiente. O
motor do jogo — laço de animação, pontuação, efeitos, áudio — também escrevi do zero.
Os principais elementos:
- Pontuação com combo. Acertos seguidos aumentam um multiplicador (até 3×), e erros quebram o combo. Pequenos números e estouros de partículas dão o retorno visual.
- Dificuldade. O jogador escolhe o nível, e a escolha fica salva.
- Eventos e estações. O jogo aplica eventos (incluindo climáticos) que mudam o ritmo da partida.
- Melhorias e problemas. Ao longo do jogo surgem boas práticas a aproveitar e problemas a evitar, cada um com efeito sobre produção e ambiente.
- Selos, ranking e desafio diário. Conquistas são desbloqueadas, há um ranking local e um desafio do dia, gerado a partir da data por uma semente — todos os jogadores do mesmo dia enfrentam o mesmo desafio.
- Áudio sob controle. Os efeitos sonoros são sintetizados na Web Audio API e podem ser ligados/desligados; a preferência é lembrada.
O que o jogo guarda:
| Chave | Uso |
|---|---|
terraRoxaJogoBest |
melhor pontuação |
terraRoxaJogoSom |
som ligado/desligado |
terraRoxaJogoSelos |
conquistas desbloqueadas |
terraRoxaJogoRanking |
ranking local |
terraRoxaJogoDesafio |
progresso do desafio diário |
terraRoxaJogoDificuldade |
dificuldade escolhida |
terraRoxaJogoPartidas |
número de partidas jogadas |
A página Glossário (glossario/index.html, com js/glossario.js) permite consultar
1.200 termos técnicos, divididos em 54 categorias, definidos em
js/glossario-data.js. Cada termo é um objeto simples:
{
id: "agronegocio",
termo: "Agronegócio",
categoria: "Geral",
definicao: "..."
}Exibir 1.200 itens de uma vez deixaria a página pesada, então a lista é virtualizada: apenas os itens visíveis na tela existem no DOM a cada momento, e o script calcula a altura total e as colunas para que a rolagem continue natural. Sobre essa base há busca, filtro por categoria e paginação.
A busca ignora acentos: o texto digitado e os termos são normalizados (removendo acentuação) antes da comparação, de modo que procurar por "agua" encontra "água". Clicar em um termo abre sua definição em um popup, e o layout muda para uma única coluna no celular.
A página Agrinho (agrinho/index.html, com js/agrinho.js) contextualiza o programa que dá
nome ao concurso: o que é o Agrinho, sua metodologia, casos de sucesso, quem pode
participar, como participar, a relação com os Objetivos de Desenvolvimento Sustentável
(ODS) e as etapas do concurso.
As interações da página são ligadas à rolagem e a pequenos widgets, todos feitos à mão:
- Timeline das etapas. No desktop, a seção de etapas "fixa" enquanto o usuário rola, avançando a linha do tempo conforme a posição da página; no mobile, ela usa um layout simplificado. A animação respeita a opção de reduzir movimento.
- Slider de casos. Os casos de sucesso passam em um carrossel navegável.
- Painel das ODS. Clicar em um objetivo destaca o card correspondente.
- FAQ e um pequeno assistente que monta um texto a partir das escolhas do usuário.
Por tratar de um programa real, esta página tem um cuidado editorial extra: quando uma seção fala do Agrinho, o texto é sobre o Agrinho, sem misturá-lo com o Terra Roxa.
Não há login nem servidor: tudo o que o site guarda fica no localStorage do próprio
navegador, na máquina do usuário, e nada é sincronizado entre dispositivos. Reunindo as
chaves citadas ao longo do documento:
| Chave | Origem | Uso |
|---|---|---|
terra-roxa-accessibility |
accessibility-dock.js |
preferências de acessibilidade |
terra-roxa-course-progress |
aprendizado.js |
progresso das trilhas |
terra-roxa-course-notes |
aprendizado.js |
anotações |
terra-roxa-course-seen |
aprendizado.js |
trilhas já vistas |
terra-roxa-last-course |
aprendizado.js |
última trilha aberta |
terra-roxa-course-completion-celebrated |
aprendizado.js |
controle da comemoração de conclusão |
terraRoxaQuizScores |
quizzes.js |
melhores pontuações dos quizzes |
terraRoxaQuizDrafts |
quizzes.js |
rascunhos de quizzes |
terra-roxa:analises |
analise-historico.js |
histórico de análises (até 24) |
terra-roxa-history-seen-count |
analisar.js |
contador de histórico visto |
terraRoxaFieldMap |
resultados.js |
estado do simulador |
terraRoxaFieldMap:presets |
resultados.js |
presets do simulador |
terraRoxaJogoBest |
jogo.js |
melhor pontuação |
terraRoxaJogoSom |
jogo.js |
som ligado/desligado |
terraRoxaJogoSelos |
jogo.js |
conquistas |
terraRoxaJogoRanking |
jogo.js |
ranking local |
terraRoxaJogoDesafio |
jogo.js |
desafio diário |
terraRoxaJogoDificuldade |
jogo.js |
dificuldade |
terraRoxaJogoPartidas |
jogo.js |
partidas jogadas |
Como reiniciar o estado. Durante os testes, é comum querer voltar tudo ao zero. Isso se faz pelo próprio navegador, em DevTools → Application → Local Storage, apagando as chaves do Terra Roxa. Convém fazer isso depois de testar muitos quizzes ou análises, de mexer no simulador, de validar o ranking do jogo, ou quando o painel de acessibilidade ficar com um estado antigo.
Para que ninguém leia mais do que está escrito, vale deixar claro o alcance de cada recurso:
- A análise visual é uma leitura de cores com finalidade educativa. Ela não é um diagnóstico agronômico e não substitui laboratório, visita técnica ou a avaliação de um profissional. Ela aponta o que um padrão de cor costuma sugerir, não o que a planta realmente tem.
- O simulador trabalha com dados simulados. Ele não representa uma propriedade real, não usa dados reais de solo ou clima e não calcula recomendações agronômicas. Serve para demonstrar relações entre decisões e estado do sistema.
- O jogo é uma representação simplificada. Não reproduz manejo, economia ou clima reais.
- O glossário é material de consulta e pode receber revisão técnica e novos termos.
Esse cuidado é também uma exigência implícita do projeto: os textos devem sempre tratar a análise como educativa, nunca como diagnóstico profissional.
A ausência de servidor tem uma consequência direta e positiva para a privacidade: nada
sai do navegador do usuário. Não há login, não há envio de fotos para nenhum lugar, e a
imagem analisada é processada localmente e descartada. Históricos, progresso, ranking e
preferências vivem apenas no localStorage da máquina.
Dois pontos de atenção decorrem disso, e estão documentados de propósito:
- Os dados em
localStoragepodem ser apagados pelo próprio navegador (ao limpar dados de navegação, por exemplo) e não são privados entre usuários do mesmo perfil do navegador. Quem usa o mesmo perfil vê os mesmos dados. - Justamente por isso, o simulador não deve receber informações reais e sensíveis: ele é um ambiente de demonstração.
Concentrei a maior parte do conteúdo em poucos arquivos, o que torna as atualizações previsíveis. Em qualquer uma delas, vale manter os princípios do projeto: nada de framework ou back-end, nada de CSS/JS embutido no HTML, preservar a acessibilidade e conferir o modo escuro e o mobile depois de cada mudança.
Trilhas de estudo — js/courses.js. Os dados estão em window.TerraRoxaCourses. Para
alterar uma trilha, localize seu slug e ajuste título, descrição, introdução, objetivos
ou capítulos. Mantenha o slug único, revise o quiz correspondente e teste as páginas
Aprender e Quizzes, no desktop e no mobile.
Quizzes — js/quizzes.js. As perguntas dependem do conteúdo das trilhas. Ao editar,
confira a alternativa correta e a explicação, e evite respostas ambíguas, alternativas
duplicadas ou perguntas que dependam de conteúdo que não existe na trilha.
Análise visual. As faixas de cor ficam em leaf-vision.js; o fluxo de upload e câmera,
em detector.js; os textos das condições, em diagnostics-data.js. Ao calibrar as cores,
teste com imagens claras, escuras, com fundo branco e com arquivos inválidos, além do caso
sem câmera. O texto deve continuar tratando a análise como educativa.
Glossário — js/glossario-data.js. Cada termo é um objeto com id, termo,
categoria e definicao. Para adicionar um termo, inclua o objeto mantendo o id único,
sem deixar a definição vazia, e teste a busca (inclusive sem acento), o filtro por categoria
e a paginação.
Simulador e jogo — js/resultados.js e js/jogo.js. São os arquivos mais extensos e
mudanças neles pedem teste manual: no simulador, verifique grade, ferramentas, indicadores,
undo/redo, exportação, importação e o estado salvo; no jogo, verifique início de partida,
combo, dificuldade, ranking e som. Em ambos, confira o modo escuro e o mobile.
Estilos. Ajustes globais vão em css/style.css; o que é de uma página fica em
css/pages/. Ao mexer em um arquivo importante, lembre de atualizar o ?v= no HTML para
furar o cache (ver seção 7).
O projeto não tem testes automatizados — coerente com a proposta sem ferramentas de build. A verificação é manual, e o roteiro abaixo cobre os pontos principais.
Navegação e estrutura
- abrir todas as páginas pelo menu e confirmar que carregam, sem erros no console;
- conferir se o item ativo do cabeçalho corresponde à página atual, em todas elas (inclusive nas subpastas, onde os caminhos relativos são mais sensíveis).
Acessibilidade
- abrir o painel e ativar, um a um, todos os recursos (fonte, espaçamento, narração, modo escuro, alto contraste, dislexia, sublinhado, reduzir animações);
- confirmar que as preferências persistem após recarregar a página e que o botão Redefinir zera tudo.
Funcionalidades por página
- Aprender: abrir uma trilha, avançar o progresso, escrever uma anotação e reabrir para ver se o estado volta;
- Quizzes: responder um quiz, sair no meio (rascunho salvo) e retomar; finalizar e ver o resultado;
- Capturar: enviar uma imagem, conferir o resultado e o histórico; testar com a câmera bloqueada (deve cair no upload);
- Resultados: aplicar uma ferramenta, trocar camada, desfazer/refazer, exportar (JSON e PNG) e recarregar para confirmar o estado salvo;
- Jogo: jogar um ciclo até a tela de fim, conferir o ranking e trocar a dificuldade;
- Glossário: buscar um termo com e sem acento, filtrar por categoria, paginar e abrir um termo;
- Agrinho: passar os casos do slider e rolar a timeline de etapas.
Modo escuro e responsividade
- repetir os testes acima no modo escuro, observando contraste, ícones e cards;
- abrir as páginas em larguras pequenas (360–430px), procurando rolagem horizontal, sobreposições e texto cortado — com atenção especial a Aprender, Quizzes, Capturar, Resultados, Glossário e Agrinho.
Conteúdos e referências citados no projeto:
- Caso "Eu Amo... Eu Cuido!" — https://nregoioere.educacao.pr.gov.br/Noticia/PROGRAMA-AGRINHO-E-O-PROJETO-EU-AMO-EU-CUIDO
- Redação de Ana Lyvia Bidoia — https://douradina.portaldacidade.com/noticias/educacao/aluna-do-ccm-douradina-e-destaque-regional-no-programa-agrinho-redacao-3419
- Jogo David's Farm (Scratch) — https://scratch.mit.edu/projects/1005715087/
A fonte tipográfica OpenDyslexic, usada no recurso de leitura para dislexia, é
distribuída sob a licença incluída em public/fonts/OpenDyslexic-LICENSE.txt.