arrow_back Voltar para o SeeB

Documentação Oficial do Widget

Guia completo de integração do widget de acessibilidade SeeB — da instalação básica em HTML estático até frameworks modernos com SSR. Inclui causas, soluções e exemplos de código prontos para produção.

Introdução

O que é o SeeB Widget

O SeeB Widget é um painel de acessibilidade client-side que você adiciona a qualquer site com uma única tag <script>. Ele injeta um Custom Element (<seeb-widget>) no DOM, expondo controles de acessibilidade aos usuários finais: ajuste de tamanho de fonte, contraste, filtros de daltonismo, modo de foco e espaçamento de texto.

Tudo acontece no navegador. O widget não faz chamadas externas durante o uso, não coleta dados e não depende de nenhum backend. As preferências do usuário são salvas em localStorage.

Quando usar

O widget é adequado para qualquer projeto que renderize HTML no browser sem restrições severas sobre manipulação do DOM global. Funciona bem em:

  • Sites estáticos, blogs e landing pages
  • SPAs com React, Vue ou Svelte via Vite ou CRA
  • Next.js App Router — com os dois ajustes documentados neste guia
  • Aplicações Angular — com as ressalvas desta documentação
  • Qualquer projeto onde você controla o index.html

Quando não usar

Cenários com risco real de conflito
  • Projetos que manipulam diretamente os filhos imediatos do <body> por fora do framework — o widget cria um wrapper em torno deles e pode desorganizar referências DOM
  • Ambientes com CSP (Content Security Policy) restritivo que bloqueia scripts de domínios externos sem allowlist explícita
  • Microfrontends com múltiplos runtimes independentes gerenciando o mesmo <body>
  • Projetos que já possuem outro widget de acessibilidade que também manipula o DOM global do body

Instalação Básica

Para a maioria dos projetos, adicionar o script é suficiente. O widget se auto-inicializa quando o DOM estiver pronto.

html index.html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <title>Meu Site</title>

  <!-- Funciona no <head> com defer ou antes de </body> -->
  <script
    src="https://seeb-widget.pages.dev/widget.js"
    defer
  ></script>
</head>
<body>
  <!-- Seu conteúdo aqui -->
</body>
</html>
Por que usar defer
O atributo defer faz o browser baixar o script em paralelo com o HTML, mas executa apenas após o parsing completo do documento. Isso evita bloqueio de render e garante que o DOM está disponível quando o widget inicializa. Colocar o script antes de </body> sem defer tem efeito equivalente em HTML estático — mas defer no <head> é preferível porque permite que o download comece mais cedo.

Como funciona internamente

Entender o que o widget faz ao inicializar é essencial para prever e evitar conflitos em ambientes mais complexos.

1
Aguarda o DOMContentLoaded

O widget registra um listener para o evento DOMContentLoaded. Quando dispara, ele verifica se um <seeb-widget> já existe no DOM. Se não existir, cria e injeta no <body>. Em HTML estático e SPAs com Vite, esse evento sempre dispara antes da execução do widget — não há problema. Em Next.js com SSR e carregamento tardio do script, o evento pode já ter disparado quando o script é finalmente executado.

2
Cria o wrapper #seeb-content-wrapper

O widget chama wrapContent(), que verifica se existe um <div id="seeb-content-wrapper"> no body. Se não existir, ele cria esse div e move todos os filhos atuais do <body> para dentro dele. Isso isola o conteúdo da página para que estilos de acessibilidade possam ser aplicados de forma controlada. O problema surge quando os nós movidos são gerenciados por um framework — o React ou Angular ainda referencia as posições originais e falha ao tentar operá-los depois.

3
Injeta o elemento <seeb-widget>

O Custom Element é adicionado diretamente ao <body> — fora do wrapper. Ele contém o painel de controles via Shadow DOM e toda a lógica de persistência de preferências em localStorage. Opera como overlay independente e não interfere com o conteúdo da página.

O ponto crítico de todos os conflitos
A maioria dos problemas de integração vem do passo 2. A solução universal é pré-criar o <div id="seeb-content-wrapper"> antes que o widget inicialize. Com o div já existente, o widget encontra a condição if (!wrapper) como false e não move nenhum nó do DOM.

Compatibilidade por ambiente

Ambiente Funciona? Observação
HTML Estático ✓ Sim Adicione o <script defer> no <head>
React + Vite / CRA ✓ Sim Adicione no index.html da raiz
Vue + Vite ✓ Sim Adicione no index.html; atenção se usar Teleport to="body"
Astro ✓ Sim Adicione no layout base com is:inline
Next.js Pages Router ~ Com ajuste Pre-criar o #seeb-content-wrapper no _document.tsx
Next.js App Router ~ Com ajuste Requer componente Client + wrapper no layout — veja o guia completo abaixo
Angular ~ Com ajuste Funciona na maioria dos casos; com SSR requer guard de plataforma
SvelteKit (SSR) ~ Com ajuste Use browser guard do SvelteKit antes de injetar o script

Funcionalidades

O widget expõe um painel completo de acessibilidade com controles agrupados em cinco categorias. Todas as preferências são salvas automaticamente em localStorage e restauradas na próxima visita. Cada funcionalidade tem um atalho de teclado próprio com o modificador Alt +.

Daltonismo

Aplica filtros SVG feColorMatrix combinados com outros filtros ativos via inline style. Os filtros de daltonismo, contraste, inverter e modo escuro são sempre compostos numa única propriedade filter, eliminando conflitos de especificidade CSS.

Opção Atalho
NormalAlt + 1
ProtanopiaAlt + 2
DeuteranopiaAlt + 3
TritanopiaAlt + 4
MonocromáticoAlt + 5

Contraste

Ativa alto contraste via contrast(1.5) saturate(1.5). Mutuamente combinável com os demais filtros na mesma propriedade filter.

Opção Atalho
Normal
Alto contrasteAlt + C

Ampliação e Leitura

Conjunto de controles que melhoram a legibilidade do conteúdo sem alterar o layout da página.

Funcionalidade Atalho Descrição
Ampliar Texto Alt + T Alterna font-size entre 100% e 125% no <html>
Espaçamento Alt + E word-spacing: 2px, letter-spacing: 0.12em, line-height: 1.8
Negrito Alt + B font-weight: 700 em todos os elementos do conteúdo
Sublinhar Links Alt + U text-decoration: underline com thickness: 2px em todos os <a>
Guia de Leitura Alt + G Régua horizontal que segue o mouse, com throttle via requestAnimationFrame. Altura configurável via slider (10px a 200px)
Linha de Foco Alt + F Destaca o elemento sob o cursor com cor de fundo configurável via color picker

Visibilidade

Controles que alteram a aparência visual da página inteira. Imagens e vídeos são re-invertidos automaticamente nos modos que aplicam inversão, para manter sua aparência natural.

Funcionalidade Atalho Descrição
Inverter Cores Alt + I filter: invert(1) no wrapper de conteúdo. Imagens e vídeos são re-invertidos para manter aparência natural
Modo Escuro Alt + D filter: invert(0.9) hue-rotate(180deg). Imagens e vídeos re-invertidos. Mutuamente exclusivo com Inverter Cores
Ocultar Imagens Alt + H visibility: hidden em img, video e picture
Parar Animações Alt + P animation-play-state: paused e transition-duration: 0ms em todos os elementos

Interação

Recursos que modificam como o usuário interage com a página, facilitando a navegação por teclado e mouse.

Funcionalidade Atalho Descrição
Cursor Grande Alt + M Substitui o cursor por um SVG de 32×32px via CSS custom cursor
Links Destacados Alt + K Adiciona outline, background e underline em todos os <a>

Configuração

Aparência

As cores do widget são configuráveis diretamente no painel pelo usuário final e salvas no localStorage. As variáveis CSS internas do widget também podem ser sobrescritas via tema.

Campo CSS Variable Padrão
Cor do Ícone e Cabeçalho --cor-principal, --cor-fundo-icone #003667
Cor do Fundo do Painel --cor-fundo-panel #E6EDF3

Posição do Widget

O ícone flutuante pode ser reposicionado de duas formas: arrastando livremente ou escolhendo um preset na grade 3×3 dentro do painel.

Arrastar

Clique e arraste o ícone para qualquer lugar da tela. O drag usa throttle com requestAnimationFrame para performance. Se o usuário soltar sem mover mais de 5px, o painel abre normalmente — o clique e o drag coexistem sem conflito.

Presets (grade 3×3)

Oito posições predefinidas acessíveis pelo painel. O preset padrão é right-center.

Preset Posição
top-leftSuperior Esquerdo
top-centerSuperior Centro
top-rightSuperior Direito
left-centerEsquerdo Centro
right-centerDireito Centro padrão
bottom-leftInferior Esquerdo
bottom-centerInferior Centro
bottom-rightInferior Direito

Atalhos de Teclado

Todos os controles do widget têm atalho de teclado usando Alt + como modificador. Os atalhos funcionam globalmente na página, independentemente do foco atual.

Atalho Ação
Alt + AAbrir/Fechar painel
Alt + TAmpliar texto
Alt + EEspaçamento de texto
Alt + BNegrito
Alt + USublinhar links
Alt + GGuia de leitura
Alt + FLinha de foco
Alt + CAlternar contraste alto/normal
Alt + IInverter cores
Alt + DModo escuro
Alt + HOcultar imagens
Alt + MCursor grande
Alt + KLinks destacados
Alt + PParar animações
Alt + RRedefinir tudo
Alt + 1Daltonismo: Normal
Alt + 2Daltonismo: Protanopia
Alt + 3Daltonismo: Deuteranopia
Alt + 4Daltonismo: Tritanopia
Alt + 5Daltonismo: Monocromático

Persistência

Todas as configurações são salvas em localStorage na chave seeb.settings. O objeto completo de estado persistido:

js localStorage — chave: seeb.settings
{
  fontSize: 100,
  fontSizeIncreased: false,
  textSpacing: false,
  boldText: false,
  underlineLinks: false,
  readingGuide: false,
  rulerHeight: 50,
  focusLine: false,
  focusLineColor: '#AED5F2',
  colorBlindness: 'normal',
  contrast: 'normal',
  invertColors: false,
  darkMode: false,
  hideImages: false,
  bigCursor: false,
  highlightLinks: false,
  pauseAnimations: false,
  widgetIconColor: '#003667',
  widgetPanelColor: '#E6EDF3',
  widgetPositionPreset: 'right-center',
  widgetPositionX: null,
  widgetPositionY: null,
}
Redefinir Tudo
O atalho Alt + R remove a chave seeb.settings do localStorage e restaura todos os valores para o estado padrão listado acima. Nenhum outro dado do localStorage da aplicação é afetado.

CSS Variables

As variáveis CSS internas do widget operam dentro do Shadow DOM. Elas controlam a aparência do painel e do ícone flutuante e podem ser alteradas programaticamente via JavaScript após a criação do elemento <seeb-widget>.

css Variáveis internas do widget
:root {
  --cor-principal: #003667;
  --cor-destaque: #014C83;
  --cor-neutra-clara: #E6EDF3;
  --cor-neutra-escura: #1A4975;
  --cor-fundo-panel: var(--cor-neutra-clara);
  --cor-fundo-icone: var(--cor-principal);
  --cor-texto-claro: #FFFFFF;
  --cor-borda-padrao: #C3D2E0;
  --cor-borda-foco: #315A81;
  --cor-fundo-hover: #D6E6F2;
  --fonte-principal: 'Atkinson Hyperlegible', sans-serif;
}

Guia por Framework

5.1 — HTML Puro

O caso mais simples. Adicione a tag <script defer> no <head>. Sem passos adicionais — o widget inicializa automaticamente quando o DOM estiver pronto e aparece no canto inferior da tela.

html index.html
<head>
  <!-- Demais tags meta, CSS, etc. -->
  <script
    src="https://seeb-widget.pages.dev/widget.js"
    defer
  ></script>
</head>

5.2 — Vite (React, Vue, Svelte)

Projetos Vite têm um index.html na raiz que serve como ponto de entrada. Adicione o script diretamente nele — o Vite não processa essa tag, ela vai ao browser exatamente como está.

html index.html (raiz do projeto)
<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <title>Meu App</title>
  <script src="https://seeb-widget.pages.dev/widget.js" defer></script>
</head>
<body>
  <div id="root"></div>
  <script type="module" src="/src/main.tsx"></script>
</body>
</html>
Por que funciona sem problemas
Scripts com defer e scripts type="module" são diferidos pelo browser. O widget inicializa no DOMContentLoaded — que em projetos Vite dispara antes do bundle do framework executar. Na prática, o wrapper é criado antes que o React ou Vue montem, então não há nós gerenciados pelo framework para o widget mover.

5.3 — Next.js (App Router)

O App Router do Next.js tem um ciclo de vida que entra em conflito com a forma como o widget inicializa. São três problemas independentes — cada um com uma causa clara e uma solução pontual.

1
DOMContentLoaded não dispara para o widget

Com strategy="afterInteractive" do componente <Script> do Next.js, o script só carrega depois da hydration do React. O evento DOMContentLoaded já disparou quando o script chega — o listener do widget nunca executa e o <seeb-widget> nunca é criado.

js widget.js (interno — não edite)
document.addEventListener("DOMContentLoaded", () => {
  if (!document.querySelector("seeb-widget")) {
    const widget = document.createElement("seeb-widget")
    document.body.appendChild(widget)
  }
})
2
Widget move nós gerenciados pelo React

Quando o widget chama wrapContent(), ele move todos os filhos do <body> para dentro de um novo <div id="seeb-content-wrapper">. Esses nós incluem o que o React criou e ainda referencia internamente. Quando o React tenta operar nesses nós (por exemplo, ao navegar entre rotas), não os encontra mais onde esperava:

js widget.js (interno — não edite)
wrapContent() {
  let wrapper = document.getElementById("seeb-content-wrapper")
  if (!wrapper) {
    wrapper = document.createElement("div")
    wrapper.id = "seeb-content-wrapper"
    Array.from(document.body.childNodes).forEach(node => {
      wrapper.appendChild(node) // move nós gerenciados pelo React
    })
    document.body.appendChild(wrapper)
  }
}
3
Hydration mismatch de atributos

O componente <Script> do Next.js injeta atributos como data-nscript no HTML do servidor. Com a prop onLoad (executada apenas no cliente), esses atributos divergem entre server e client durante a hydration:

Solução: dois ajustes pontuais que resolvem os três problemas acima.

1 Criar um Client Component com useEffect

Em vez do componente <Script> do Next.js, crie um Client Component que retorna null no servidor (zero HTML gerado) e injeta o script via useEffect no cliente. O callback onload do script cria o <seeb-widget> manualmente — contornando o DOMContentLoaded que não disparou.

Resolve os problemas: 1 e 3

tsx src/components/accessibility-widget.tsx
'use client'

import { useEffect } from 'react'

export function AccessibilityWidget() {
  useEffect(() => {
    if (document.querySelector('seeb-widget')) return

    const script = document.createElement('script')
    script.src = 'https://seeb-widget.pages.dev/widget.js'
    script.defer = true
    script.onload = () => {
      if (!document.querySelector('seeb-widget')) {
        const widget = document.createElement('seeb-widget')
        document.body.appendChild(widget)
      }
    }
    document.body.appendChild(script)
  }, [])

  return null
}
Por que funciona
  • return null → servidor não renderiza nada, cliente também não → zero hydration mismatch
  • useEffect só roda no cliente, após a montagem → sem conflito com SSR
  • script.onload cria o widget manualmente, contornando o DOMContentLoaded que não disparou
  • Guard querySelector('seeb-widget') evita duplicação no React StrictMode
2 Pre-criar o seeb-content-wrapper no layout

Adicione o <div id="seeb-content-wrapper"> diretamente no layout do servidor. Quando o widget inicializar no cliente e chamar wrapContent(), o div já existe — a condição if (!wrapper) é false e nenhum nó é movido.

Resolve o problema: 2

tsx src/app/layout.tsx
import type { Metadata } from 'next'
import { AccessibilityWidget } from '@/components/accessibility-widget'

export const metadata: Metadata = {
  title: 'Minha Aplicação',
}

export default function RootLayout({
  children,
}: { children: React.ReactNode }) {
  return (
    <html lang="pt-BR">
      <body>
        {/* O wrapper deve existir ANTES do widget inicializar */}
        <div id="seeb-content-wrapper">
          {children}
        </div>
        <AccessibilityWidget />
      </body>
    </html>
  )
}
Por que funciona
  • O seeb-content-wrapper já existe no HTML quando o widget inicializa no cliente
  • O widget encontra o div, entra na condição if (!wrapper) como false e não move nenhum nó
  • O React mantém todas as referências DOM intactas durante a navegação
Problema Causa Solução
Widget não aparece DOMContentLoaded já disparou quando o script carrega Criar <seeb-widget> manualmente no onload
removeChild — node is not a child Widget move nós gerenciados pelo React para dentro do wrapper Pre-criar <div id="seeb-content-wrapper"> no layout
Hydration mismatch de atributos <Script> do Next.js gera data-nscript no servidor useEffect + createElement em vez do componente Script

5.4 — Vue

A maioria dos projetos Vue usa Vite. Nesses casos, a abordagem mais simples e confiável é adicionar o script diretamente no index.html da raiz.

html index.html
<head>
  <script src="https://seeb-widget.pages.dev/widget.js" defer></script>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>

Se preferir injetar programaticamente após a montagem do app — para garantir que o Vue já assumiu o DOM antes do widget inicializar:

js src/main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)
app.mount('#app')

// Injetar após mount — Vue já controla o DOM nesse ponto
const script = document.createElement('script')
script.src = 'https://seeb-widget.pages.dev/widget.js'
script.defer = true
document.body.appendChild(script)
Cuidado com Teleport to="body"
Se sua aplicação usa <Teleport to="body"> para modais ou overlays, esses elementos são filhos imediatos do <body> — e o widget pode movê-los para dentro do wrapper, causando conflitos. A solução é pré-criar o <div id="seeb-content-wrapper"> no index.html e usar <Teleport to="#seeb-content-wrapper"> como destino em vez do body diretamente.

5.5 — Angular

A abordagem com menor risco é adicionar o script diretamente no src/index.html do projeto Angular. O widget inicializa antes do bootstrap do framework, o que evita conflitos com o ciclo de vida do Angular.

html src/index.html
<head>
  <script
    src="https://seeb-widget.pages.dev/widget.js"
    defer
  ></script>
</head>
<body>
  <app-root></app-root>
</body>

Para controlar o carregamento via TypeScript — por exemplo, para evitar injeção em ambientes de teste ou aplicar condições específicas:

ts src/app/app.component.ts
import { Component, OnInit } from '@angular/core'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
  ngOnInit(): void {
    if (document.querySelector('seeb-widget')) return

    const script = document.createElement('script')
    script.src = 'https://seeb-widget.pages.dev/widget.js'
    script.defer = true
    document.body.appendChild(script)
  }
}

Se o projeto usa Angular Universal (SSR), adicione um guard de plataforma antes de qualquer operação de DOM:

ts app.component.ts (com guard SSR)
import { Component, OnInit, Inject, PLATFORM_ID } from '@angular/core'
import { isPlatformBrowser } from '@angular/common'

@Component({ selector: 'app-root', templateUrl: './app.component.html' })
export class AppComponent implements OnInit {
  constructor(@Inject(PLATFORM_ID) private platformId: object) {}

  ngOnInit(): void {
    // Nunca executar operações de DOM no servidor (Node.js)
    if (!isPlatformBrowser(this.platformId)) return
    if (document.querySelector('seeb-widget')) return

    const script = document.createElement('script')
    script.src = 'https://seeb-widget.pages.dev/widget.js'
    script.defer = true
    document.body.appendChild(script)
  }
}
Ressalvas específicas do Angular
  • Zone.js: scripts injetados via createElement fora do contexto do Angular não são interceptados pelo zone.js. O widget não dispara detecção de mudanças do Angular — isso é esperado e inofensivo, pois o widget opera de forma completamente independente.
  • CSP restritivo: se o projeto Angular usa Content Security Policy, adicione https://seeb-widget.pages.dev à diretiva script-src.
  • Angular Universal / SSR: sempre use o guard isPlatformBrowser antes de qualquer operação com document ou window. O código do widget não deve executar no contexto Node.js.

Problemas Conhecidos

Referência rápida para os erros mais frequentes durante a integração.

Widget não aparece na tela

Causa: O evento DOMContentLoaded já disparou quando o script foi carregado. Comum em Next.js App Router com strategy="afterInteractive" e em situações de lazy loading tardio.

Solução: Crie o elemento <seeb-widget> manualmente no callback onload do script, como demonstrado no guia do Next.js. O padrão de criação manual funciona em qualquer framework.

removeChild — The node is not a child of this node

Causa: O widget chamou wrapContent() e moveu nós DOM que o framework (React, Angular) ainda referencia internamente. Quando o framework tentou operar nesses nós, não os encontrou mais no <body>.

Solução: Pré-crie o <div id="seeb-content-wrapper"> antes que o widget inicialize. Com o div existente, o widget não move nenhum nó.

Hydration mismatch no Next.js

Causa: O componente <Script> do Next.js com onLoad gera atributos distintos no HTML do servidor e no cliente, causando divergência na hydration do React.

Solução: Use o padrão useEffect + createElement. O componente retorna null no servidor, eliminando qualquer possibilidade de mismatch de atributos.

Widget aparece duplicado

Causa: O script foi injetado ou o widget foi criado mais de uma vez. Acontece quando hooks de ciclo de vida executam múltiplas vezes (React StrictMode executa os efeitos duas vezes em desenvolvimento), ou quando o componente que inicia o widget é montado e desmontado durante a navegação.

Solução: Sempre verifique antes de criar: if (document.querySelector('seeb-widget')) return. Todos os exemplos nesta documentação já incluem esse guard.

Script bloqueado por CSP

Causa: O projeto tem uma Content Security Policy que não permite carregar scripts de domínios externos não listados.

Solução: Adicione https://seeb-widget.pages.dev à diretiva script-src do seu CSP. Como alternativa, faça o self-hosting do widget.js a partir do repositório público.

Widget não funciona em páginas específicas

Causa: Algumas páginas usam tecnologias proprietárias ou estruturas de DOM não convencionais que impedem o widget de aplicar seus estilos corretamente. É um comportamento esperado para casos extremos — não um bug.

Solução: Reporte a página no repositório via issue com o domínio e uma descrição do problema. A equipe avalia caso a caso.

Boas Práticas

  • Sempre use defer. Evita bloqueio de render e garante que o DOM está disponível quando o widget executa.
  • Em projetos com SSR, pré-crie o #seeb-content-wrapper. Isso previne a movimentação de nós DOM gerenciados pelo framework — o ajuste mais importante para Next.js, SvelteKit e Angular Universal.
  • Aplique sempre o guard de verificação antes de criar: if (document.querySelector('seeb-widget')) return. Previne duplicações em hot reload, StrictMode e navegações em SPA.
  • Carregue o widget uma única vez no ponto de entrada. Em SPAs, não coloque a lógica de injeção em componentes que montam e desmontam durante a navegação. Use o layout raiz ou o arquivo de bootstrap.
  • Não manipule os filhos imediatos do <body> manualmente ao mesmo tempo que o widget está ativo. Se o código da aplicação move, clona ou remove nós do body por fora do framework, pode conflitar com o wrapper do widget.
  • Valide em produção. O comportamento com SSR, hydration e carregamento assíncrono pode diferir entre desenvolvimento e produção. Teste que o widget aparece corretamente após o build, incluindo em rotas com SSR.
  • Em projetos com CSP, configure o allowlist antes de implantar em produção. Um CSP que bloqueia scripts externos silencia o widget sem gerar erros visíveis ao usuário.

Filosofia do Projeto

O SeeB Widget existe porque acreditamos que acessibilidade não deveria ser um projeto paralelo — ela já deveria estar lá, embutida na experiência padrão da web.

100% Gratuito, Para Sempre

Não existe plano pago, tier premium, limite de uso ou intenção de monetização. O widget é gratuito para qualquer projeto — pessoal, comercial ou educacional. Não há roadmap de cobrança.

Zero Coleta de Dados

O widget não faz nenhuma chamada externa durante o uso do usuário. Sem analytics, telemetria, rastreamento ou envio de informações a servidores. As preferências de acessibilidade são salvas apenas em localStorage — no dispositivo do próprio usuário. Nenhum dado sai do navegador.

Client-Side Only

Todo o processamento acontece no navegador. Não há backend, não há dependência de infraestrutura externa além do carregamento inicial do widget.js. Uma vez carregado, funciona offline. Falhas de rede após o carregamento inicial não afetam o funcionamento.

Open Source e Auditável

O código-fonte está disponível publicamente. Qualquer desenvolvedor pode auditar o que o widget faz, propor melhorias ou reportar problemas. Não há código ofuscado ou comportamento escondido. O que está documentado aqui reflete exatamente o que o código faz.

Contribua com o projeto
O SeeB é desenvolvido por alunos da ETEC Parque Belém como projeto open source. Contribuições são bem-vindas: correções de bugs, novas funcionalidades, melhoria de compatibilidade com frameworks ou aprimoramentos desta documentação. Acesse o repositório em github.com/devrafcks/seeb-widget.