Plugin Flutter para exibir traduções de texto para LIBRAS usando o avatar 3D do VLibras (iniciativa UFPB/RNP do governo brasileiro para acessibilidade digital).
| Plataforma | Suporte |
|---|---|
| Flutter Web | ✓ (estável) |
| Android | ✓ (via WebView) |
| iOS | Planejado |
O pacote ainda não está publicado no pub.dev. Use uma das três formas abaixo.
No pubspec.yaml do app consumidor:
dependencies:
vlibras_flutter:
git:
url: https://github.com/luizpaulobarroca/vlibras-flutter.git
ref: mainOpcional — fixar uma tag ou commit específico:
dependencies:
vlibras_flutter:
git:
url: https://github.com/luizpaulobarroca/vlibras-flutter.git
ref: v0.1.0 # ou um SHA de commitDepois rode:
flutter pub getClone o repositório ao lado do seu app e aponte para a pasta:
dependencies:
vlibras_flutter:
path: ../vlibras-flutterdependencies:
vlibras_flutter: ^0.1.0(disponível quando a primeira versão for publicada)
O avatar é carregado por um player Unity WebGL servido a partir do diretório web/ do seu app. Você precisa de dois conjuntos de arquivos:
a) O loader JS em web/vlibras/vlibras.js
b) Os assets Unity em web/vlibras/target/:
web/vlibras/target/UnityLoader.js
web/vlibras/target/playerweb.json
web/vlibras/target/playerweb.data.unityweb
web/vlibras/target/playerweb.wasm.code.unityweb
web/vlibras/target/playerweb.wasm.framework.unityweb
A forma mais prática é copiar a pasta web/vlibras/ do próprio repositório do plugin:
# a partir da raiz do seu app
git clone --depth 1 https://github.com/luizpaulobarroca/vlibras-flutter.git /tmp/vlibras
cp -r /tmp/vlibras/web/vlibras ./web/vlibrasDepois, referencie o loader no seu web/index.html, antes do </body>:
<script src="vlibras/vlibras.js"></script>Se você servir a partir de um path customizado, passe-o ao controller:
VLibrasController(targetPath: '/meu-app/vlibras/target');Zero setup. A permissão INTERNET e a configuração de cleartext traffic para 127.0.0.1 são contribuídas automaticamente pelo AndroidManifest.xml do plugin e mescladas no manifest do seu app pelo Gradle. Os assets Unity são empacotados no pacote e servidos para o WebView via um HttpServer loopback em tempo de execução — nada para copiar.
Requisitos mínimos: minSdk 21 (padrão do Flutter).
Se o seu app já declara o próprio
android:networkSecurityConfignoAndroidManifest.xml, o manifest merger vai parar com um erro de conflito. Nesse caso, copie as regras deandroid/src/main/res/xml/vlibras_network_security_config.xml(permitir cleartext em127.0.0.1) para o seu config e adicionetools:replace="android:networkSecurityConfig"no elemento<application>.
Plugue no builder do seu MaterialApp e pronto: um botão flutuante à direita abre o avatar, e qualquer Text do app pode ser tocado para ser traduzido.
import 'package:flutter/material.dart';
import 'package:vlibras_flutter/vlibras_flutter.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) =>
VLibrasAccessibilityWidget(child: child!),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Minha aplicação')),
body: const Padding(
padding: EdgeInsets.all(24),
child: Text('Toque no botão azul e depois neste texto.'),
),
);
}
}
VLibrasAccessibilityWidgetprecisa estar dentro deMaterialApp(por isso usamosbuilder), para queDirectionality,MediaQueryeThemeestejam disponíveis.
Quando você quer integrar o avatar em um layout específico e controlar traduções manualmente:
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late final VLibrasController _controller;
@override
void initState() {
super.initState();
_controller = VLibrasController();
_controller.initialize();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
width: 400,
height: 300,
child: VLibrasView(controller: _controller),
),
ValueListenableBuilder<VLibrasValue>(
valueListenable: _controller,
builder: (_, value, __) => Text('Status: ${value.status.name}'),
),
ElevatedButton(
onPressed: () => _controller.translate('Olá mundo'),
child: const Text('Traduzir'),
),
],
);
}
}| Status | Descrição |
|---|---|
idle |
Criado mas não inicializado |
initializing |
initialize() em andamento |
ready |
Pronto para traduzir |
translating |
Aguardando resposta do player |
playing |
Avatar animando a tradução |
error |
Erro — veja VLibrasValue.error |
Métodos do controller:
initialize()— prepara a plataformatranslate(String)— traduz um textopause()/resume()/stop()/repeat()— controles do playersetSpeed(VLibrasSpeed)— preset de velocidade (slow/normal/fast)setAvatar(VLibrasAvatar)— troca o avatar (ícaro/hosana/guga)setSubtitles(bool)— liga/desliga legendas
O controller não traz backend de persistência. Para salvar velocidade, avatar e legendas entre execuções, use os parâmetros opcionais do construtor com o pacote que preferir (ex.: shared_preferences):
Future<VLibrasSettings> _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
final raw = prefs.getString('vlibras_settings');
if (raw == null) return const VLibrasSettings();
return VLibrasSettings.fromJson(jsonDecode(raw) as Map<String, dynamic>);
}
Future<void> _saveSettings(VLibrasSettings settings) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('vlibras_settings', jsonEncode(settings.toJson()));
}
final controller = VLibrasController(
initialSettings: await _loadSettings(),
onSettingsChanged: _saveSettings,
);
await controller.initialize();onSettingsChanged é chamado apenas depois que o player aceita a mudança, então o callback nunca persiste um estado intermediário ou rejeitado. initialSettings é aplicado antes do primeiro ready.
VLibrasAccessibilityWidget(
avatarWidth: 280,
avatarHeight: 320,
buttonSize: 56,
showSettingsButton: true,
settingsLabels: const VLibrasSettingsLabels(
title: 'Configurações',
speed: 'Velocidade',
avatar: 'Avatar',
subtitles: 'Legendas',
close: 'Fechar',
),
child: child!,
)git clone https://github.com/luizpaulobarroca/vlibras-flutter.git
cd vlibras-flutter/example
flutter pub get
flutter run -d chromeMIT — veja LICENSE.