Agency-Watch Apps Personalizados
Agora com o AgencyOS27: uma atualização grátis para quem já tem o relógio.

⌚ Criar a tua própria app para o Agency-Watch
O relógio está aberto. Um dono de servidor pode adicionar uma app com o aspeto e o comportamento de uma integrada, usando os mesmos componentes, as mesmas cores e as mesmas traduções.
Requisito: a edição Pro. As apps próprias só existem quando o Agency-Phone corre no servidor e o jogador o tem. Sem Pro são registadas mas nunca entregues: a interface nunca sabe delas, não aparecem na App Store e o servidor recusa todas as ações que enviam. Isto é verificado em três sítios diferentes e não pode ser desligado.
| Ficheiro | Obrigatório | O que faz |
|---|---|---|
apps/<id>/app.lua | sim | Regista a app: nome, ícone, cor, categoria. |
apps/<id>/app.js | sim | O ecrã: o que desenha e como reage. |
apps/<id>/app.css | não | O teu próprio estilo. Só é carregado com style = true. |
apps/<id>/server.lua | não | Lógica de servidor que a tua app pode chamar. |
A pasta tem exatamente o nome do id da app. É assim que o relógio encontra app.js e app.css sem o caminho ser escrito duas vezes, e caminhos escritos duas vezes acabam por divergir mais cedo ou mais tarde.
Tudo o que está em apps/ está em escrow_ignore: continua legível e editável no teu disco, e uma atualização do relógio nunca o substitui.
1 Registar a app
apps/hello/app.lua
AgencyWatchApp({
id = 'hello', -- lowercase, digits and _, must match the folder
name = 'Hello',
icon = 'raster', -- one of the built-in icons, see below
color = '#5ac8fa', -- #rrggbb
category = 'tools', -- tools | games | driving | style | connected
style = true, -- also load app.css
texts = { en = 'Hello', de = 'Hallo' }, -- optional, name per language
})
Uma app com um id mal formado, sem nome, com uma categoria desconhecida ou uma cor que não seja #rrggbb é recusada na consola do servidor, claramente e com o motivo. Não existe registo a meio: esse tipo de erro só apareceria quando um jogador tocasse na app.
Corre refresh e restart Agency-Watch depois de adicionares ficheiros. Ao arrancar, o relógio indica o que foi registado.
2 Desenhar o ecrã
apps/hello/app.js
AgencyWatch.app('hello', {
render: function (w) { // required, returns HTML
var d = w.data();
return w.card('Hello, ' + w.esc(d.name)) +
w.section('Steps') +
w.row({ icon: 'schritte', static: true,
top: String(d.steps || 0) }) +
w.button('Roll a die', ' data-roll');
},
bind: function (w) { // optional, runs right after
w.click('[data-roll]', function () {
w.toServer('roll', { sides: 6 }).then(function (a) {
if (a.ok) w.notify('Hello', 'You rolled ' + a.data.value);
});
});
},
});
render corre sempre que o ecrã é construído, por isso não guarda estado entre chamadas. O que tiver de sobreviver a um redesenho vai para uma variável fora do objeto da app.
As duas funções correm dentro de uma rede de segurança. Se o teu código lançar um erro, a tua app mostra uma linha de erro e o relógio continua a funcionar; o erro real vai para a consola F8.
3 A caixa de ferramentas
w tem tudo o que uma app num relógio precisa, e nada mais. Uma interface que faz tudo nunca mais pode ser alterada, por isso esta é pequena de propósito.
| Chamada | O que te dá |
|---|---|
w.data() | Um instantâneo simples: time, hour, minute, date, weekday, name, job, health, armour, pulse, steps, distance, calories, speed, heading, weather, pro. |
w.row({icon, top, bottom, end, attrs, static}) | Uma linha de lista no estilo do relógio. |
w.section(text) | Um título de secção. |
w.card(html) | Uma superfície. |
w.button(text, attrs) | Um botão. attrs é uma string de atributos em bruto, por exemplo ' data-roll'. |
w.toggle(on) | Um interruptor ligar/desligar. |
w.center(html) | Centrado, para um único valor grande. |
w.icon(name) | Um dos ícones integrados. |
w.esc(text) | Escapa texto. Usa-o para tudo o que não seja teu. |
w.text(key, fallback) | Uma tradução do relógio. |
w.click(selector, fn) | Associa um listener. Só dentro de bind. |
w.notify(title, text, icon, colour) | Uma notificação no relógio. |
w.refresh() | Redesenha, sem a animação de entrada. |
w.close() | Volta atrás, como a seta do cabeçalho. |
w.toServer(action, data) | Pergunta ao servidor. Devolve uma promise. |
w.id, w.version | O id da tua app e a versão do AgencyOS. |
O instantâneo é uma cópia, não uma referência. O relógio também guarda contactos, mensagens e dados de cartões; nada disso está lá.
4 O lado do servidor
apps/hello/server.lua
AgencyWatchAction('hello', 'roll', function(src, data)
local sides = tonumber(data and data.sides) or 6
if sides < 2 then sides = 2 end
if sides > 100 then sides = 100 end
return { value = math.random(1, math.floor(sides)) }
end)
w.toServer resolve sempre, com { ok: true, data: … } ou { ok: false, reason: '…' }, mesmo quando o servidor nunca respondeu. A tua app nunca fica presa à espera, e o motivo está sempre no nível de topo, seja qual for o lado que recusou.
reason | Significado |
|---|---|
no_pro | Sem edição Pro. Sem ela não existem apps próprias. |
unknown | Não existe essa app nem essa ação registada. |
too_fast | Limite de pedidos: no máximo dez pedidos por cada cinco segundos por jogador. |
error | O teu handler lançou um erro. Os detalhes estão na consola do servidor. |
timeout | Sem resposta em doze segundos. |
data | O pedido não era uma tabela. |
O que chega em data vem do cliente e é um desejo, não um facto. Verifica cada valor antes de o usares. Tudo o que conta (dinheiro, itens, resultados) pertence ao servidor e a mais lado nenhum.
5 Estilo
As cores do relógio estão disponíveis como variáveis CSS e seguem o que o utilizador escolheu no Studio. Cores fixas dão uma app que continua azul num relógio verde.
var(--text) var(--text-2) var(--leise)
var(--akzent) var(--gruen) var(--rot) var(--gelb)
var(--karte) var(--karte-hoch) var(--linie)
var(--grund)
Dá um prefixo às tuas próprias classes. O ecrã é partilhado com todas as outras apps, e uma classe chamada .large vai encontrar companhia.
6 Ícones integrados
Passa qualquer um destes a icon em app.lua ou a w.icon():
akku auto blitz brief einkauf farben flugzeug gewitter glocke haken helligkeit herz hoch hupe karte karte-pin kein-signal kino kompass kreuz krone lampe laufen lautlos links loeschen minus mobil mond nebel neuladen pause personen pin plus qr raster rechts regen regler runter sanduhr schild schloss schloss-auf schnee schritte signal sonne sp-fall sp-flug sp-ring sp-turm sprechen stoppuhr telefon telefon-aus tempo ton uhr verboten wiedergabe wlan wolke zahnrad
Os nomes dos ícones ficam como estão de propósito. São ids, não rótulos: um jogador nunca os lê, e mudar o nome de um id estraga todas as apps que já o usam.
📦 O relógio traz um exemplo que funciona
apps/example/ dentro do resource é uma app completa e executável: componentes, uma chamada ao servidor, uma notificação e CSS próprio. Copia a pasta, muda-lhe o nome e tens um ponto de partida que já funciona.
Há uma versão curta desta página ao lado, em apps/README.md.