OrganiLAB 1.6.1: organizador, actualizador, interfaz 1.6 y publicación

Primer commit del proyecto. Incluye el rediseño 1.6 (riel de pasos en la barra
lateral), el actualizador con reintentos y respaldo, publicar.sh y la nueva
opción de desconectar carpetas (1.6.1).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Este commit está contenido en:
Labstream
2026-09-15 14:26:02 -05:00
commit 8c5153e8ed
Se han modificado 20 ficheros con 6481 adiciones y 0 borrados

71
hacer_icono.py Archivo normal
Ver fichero

@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
"""Genera static/organilab.png (256 px) y static/organilab.ico (256/48/32/16) sin dependencias:
el logo OrganiLAB, cuadrado azul redondeado con tres barras blancas."""
import os
import zlib
import struct
AQUI = os.path.dirname(os.path.abspath(__file__))
AZUL = (0x1F, 0x57, 0xD6)
def pinta(n):
"""devuelve filas RGBA del logo a n×n"""
r = n * 7 / 32 # radio de las esquinas (7/32 como el SVG)
barras = [(8, 18, 1.0), (14, 13, .85), (20, 8, .65)] # (y, ancho, opacidad) en unidades de 32
filas = []
for y in range(n):
fila = bytearray()
for x in range(n):
# cuadrado redondeado con antialias sencillo (4 muestras)
dentro = 0
for sx, sy in ((.25, .25), (.75, .25), (.25, .75), (.75, .75)):
px, py = x + sx, y + sy
cx = min(max(px, r), n - r)
cy = min(max(py, r), n - r)
if (px - cx) ** 2 + (py - cy) ** 2 <= r * r:
dentro += 1
a = dentro / 4
if a == 0:
fila += bytes((0, 0, 0, 0))
continue
col = list(AZUL)
for by, bw, op in barras:
y0, y1 = by * n / 32, (by + 4) * n / 32
x0, x1 = 7 * n / 32, (7 + bw) * n / 32
rb = 2 * n / 32
if y0 <= y + .5 < y1 and x0 <= x + .5 < x1:
# esquinas de la barra redondeadas
cx = min(max(x + .5, x0 + rb), x1 - rb)
cy = min(max(y + .5, y0 + rb), y1 - rb)
if (x + .5 - cx) ** 2 + (y + .5 - cy) ** 2 <= rb * rb:
col = [int(c + (255 - c) * op) for c in AZUL]
fila += bytes((col[0], col[1], col[2], int(255 * a)))
filas.append(bytes(fila))
return filas
def png(n):
filas = pinta(n)
raw = b"".join(b"\x00" + f for f in filas)
def chunk(t, d):
return struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
return (b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", n, n, 8, 6, 0, 0, 0))
+ chunk(b"IDAT", zlib.compress(raw, 9)) + chunk(b"IEND", b""))
tamanos = (256, 48, 32, 16)
imgs = [png(t) for t in tamanos]
with open(os.path.join(AQUI, "static", "organilab.png"), "wb") as fh:
fh.write(imgs[0])
# ICO con PNG incrustados (válido desde Windows Vista)
cab = struct.pack("<HHH", 0, 1, len(tamanos))
off = 6 + 16 * len(tamanos)
entradas = b""
for t, im in zip(tamanos, imgs):
entradas += struct.pack("<BBBBHHII", t % 256, t % 256, 0, 0, 1, 32, len(im), off)
off += len(im)
with open(os.path.join(AQUI, "static", "organilab.ico"), "wb") as fh:
fh.write(cab + entradas + b"".join(imgs))
print("icono listo:", [len(i) for i in imgs])