Agency-Watch Apps Personalizadas
Ahora con AgencyOS27: una actualización gratuita para quien ya tenga el reloj.

⌚ Crea tu propia app para el Agency-Watch
El reloj está abierto. Un dueño de servidor puede añadir una app que se ve y se comporta como una integrada, con los mismos componentes, los mismos colores y las mismas traducciones.
Requisito: la edición Pro. Las apps propias solo existen si el Agency-Phone funciona en el servidor y el jugador lo tiene. Sin Pro se registran pero nunca se entregan: la interfaz nunca sabe de ellas, no aparecen en la App Store y el servidor rechaza cada acción que envían. Se comprueba en tres sitios distintos y no se puede desactivar.
| Archivo | Obligatorio | Qué hace |
|---|---|---|
apps/<id>/app.lua | sí | Registra la app: nombre, icono, color, categoría. |
apps/<id>/app.js | sí | La pantalla: qué dibuja y cómo reacciona. |
apps/<id>/app.css | no | Tu propio estilo. Solo se carga con style = true. |
apps/<id>/server.lua | no | Lógica de servidor a la que tu app puede llamar. |
La carpeta se llama exactamente igual que el id de la app. Así el reloj encuentra app.js y app.css sin escribir la ruta dos veces, y las rutas escritas dos veces acaban separándose tarde o temprano.
Todo lo que hay bajo apps/ está en escrow_ignore: sigue siendo legible y editable en tu disco, y una actualización del reloj nunca lo sobrescribe.
1 Registrar la 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
})
Una app con un id mal formado, sin nombre, con una categoría desconocida o con un color que no sea #rrggbb se rechaza en la consola del servidor, claramente y con el motivo. No existe el registro a medias: ese tipo de error solo se vería cuando un jugador tocara la app.
Ejecuta refresh y restart Agency-Watch después de añadir archivos. Al arrancar, el reloj indica qué se ha registrado.
2 Dibujar la pantalla
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 se ejecuta cada vez que se construye la pantalla, así que no guarda estado entre llamadas. Lo que tenga que sobrevivir a un redibujado va en una variable fuera del objeto de la app.
Ambas funciones se ejecutan dentro de una red de seguridad. Si tu código lanza un error, tu app muestra una línea de error y el reloj sigue funcionando; el error real va a la consola F8.
3 La caja de herramientas
w contiene todo lo que necesita una app en un reloj y nada más. Una interfaz que lo hace todo ya no se puede cambiar nunca, por eso esta es pequeña a propósito.
| Llamada | Qué te da |
|---|---|
w.data() | Una instantánea plana: 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}) | Una fila de lista con el estilo propio del reloj. |
w.section(text) | Un título de sección. |
w.card(html) | Una superficie. |
w.button(text, attrs) | Un botón. attrs es una cadena de atributos en bruto, por ejemplo ' data-roll'. |
w.toggle(on) | Un interruptor de encendido/apagado. |
w.center(html) | Centrado, para un único valor grande. |
w.icon(name) | Uno de los iconos integrados. |
w.esc(text) | Escapa texto. Úsalo para todo lo que no sea tuyo. |
w.text(key, fallback) | Una traducción del reloj. |
w.click(selector, fn) | Añade un listener. Solo dentro de bind. |
w.notify(title, text, icon, colour) | Una notificación en el reloj. |
w.refresh() | Redibuja, sin la animación de entrada. |
w.close() | Vuelve atrás, como la flecha de la cabecera. |
w.toServer(action, data) | Pregunta al servidor. Devuelve una promesa. |
w.id, w.version | El id de tu app y la versión de AgencyOS. |
La instantánea es una copia, no una referencia. El reloj también lleva contactos, mensajes y datos de tarjetas; nada de eso está ahí.
4 El lado del 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 siempre se resuelve, con { ok: true, data: … } o { ok: false, reason: '…' }, incluso si el servidor nunca respondió. Tu app nunca puede quedarse colgada esperando, y el motivo siempre está en el nivel superior, sea cual sea el lado que rechazó.
reason | Significado |
|---|---|
no_pro | Sin edición Pro. Sin ella no existen las apps propias. |
unknown | No hay ninguna app ni acción registrada con ese nombre. |
too_fast | Límite de frecuencia: como mucho diez peticiones cada cinco segundos por jugador. |
error | Tu handler lanzó un error. Los detalles están en la consola del servidor. |
timeout | Sin respuesta en doce segundos. |
data | La petición no era una tabla. |
Lo que llega en data viene del cliente y es un deseo, no un hecho. Comprueba cada valor antes de usarlo. Todo lo que cuenta (dinero, objetos, resultados) va en el servidor y en ningún otro sitio.
5 Estilo
Los colores del reloj están disponibles como variables CSS y siguen lo que el usuario eligió en Studio. Con colores fijos tendrás una app que sigue azul en un reloj 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)
Pon un prefijo a tus propias clases. La pantalla se comparte con todas las demás apps, y una clase llamada .large encontrará compañía.
6 Iconos integrados
Pasa cualquiera de estos a icon en app.lua o 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
Los nombres de los iconos se quedan como están a propósito. Son ids, no etiquetas: un jugador nunca los lee, y renombrar un id rompe todas las apps que ya lo usan.
📦 El reloj trae un ejemplo que funciona
apps/example/ dentro del resource es una app completa y ejecutable: componentes, una llamada al servidor, una notificación y su propio CSS. Copia la carpeta, cámbiale el nombre y tendrás un punto de partida que ya funciona.
Hay una versión corta de esta página al lado, en apps/README.md.