Make semester progress fun!
  • Svelte 53.3%
  • TypeScript 43.8%
  • CSS 1.7%
  • Nix 0.7%
  • HTML 0.4%
  • Other 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
yuuhikaze 29972128ad feat(ui): use the dragon emoji as favicon
Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 09:32:52 -05:00
docs chore(build): replace pnpm with bun 2026-08-23 19:31:20 -05:00
public feat(ui): use the dragon emoji as favicon 2026-08-24 09:32:52 -05:00
scripts chore(build): replace pnpm with bun 2026-08-23 19:31:20 -05:00
src docs: document progress tracking and grade medals 2026-08-23 11:00:57 -05:00
.envrc build: add nix flake devshell 2026-08-18 10:29:05 -05:00
.gitignore chore: scaffold vite + svelte + ts project 2026-08-18 10:27:53 -05:00
bun.lock chore(build): replace pnpm with bun 2026-08-23 19:31:20 -05:00
flake.lock build: add nix flake devshell 2026-08-18 10:29:05 -05:00
flake.nix chore(build): replace pnpm with bun 2026-08-23 19:31:20 -05:00
index.html feat(ui): replace the favicon with a hannya mask 2026-08-24 09:24:54 -05:00
package.json chore(build): replace pnpm with bun 2026-08-23 19:31:20 -05:00
README.md feat(ui): use the dragon emoji as favicon 2026-08-24 09:32:52 -05:00
svelte.config.js chore: scaffold vite + svelte + ts project 2026-08-18 10:27:53 -05:00
tsconfig.json feat(timeline): render course lanes, grid and high-load overlay 2026-08-18 10:40:37 -05:00
vite.config.ts test: exclude .direnv copy from vitest discovery 2026-08-18 11:06:40 -05:00

title
Línea de tiempo de entregables

Aplicación web que muestra los entregables de un semestre en carriles apilados, uno por materia, sobre un eje temporal desplazable, y resalta automáticamente los períodos de alta carga.

Construida con Vite, Svelte 5 y TypeScript, sin librerías de gráficos. Los datos se sirven como JSON estático desde public/data/ y se cargan en runtime: añadir un semestre no requiere recompilar.

Puesta en marcha

El flake provee Bun y miniserve, de modo que no hace falta instalar nada en el sistema.

nix develop
bun install
bun dev

Sin Nix basta con Bun 1.2 o superior.

Scripts disponibles:

bun dev          # servidor de desarrollo
bun run build    # svelte-check + bundle de producción en dist/
bun run preview  # sirve dist/
bun run check    # sólo verificación de tipos
bun run test     # tests de la detección de carga
bun run migrate  # regenera public/data/ desde el data.json original

Despliegue

bun run build produce en dist/ un sitio completamente estático: HTML, un bundle JS, una hoja de estilos y la copia de public/data/. No hay servidor de aplicación ni API detrás, así que publicar consiste en copiar esa carpeta a cualquier servidor de archivos.

El bundle es reubicable. vite.config.ts fija base: "./" y los datos se piden con rutas relativas, de modo que el mismo dist/ sirve tanto en la raíz de un dominio como en un subdirectorio, sin reconstruir por destino. La única condición es que la URL del subdirectorio termine en barra, para que el navegador resuelva data/index.json dentro de él y no un nivel más arriba.

dist/ no se versiona: se regenera en cada despliegue. Un contenedor de dos etapas basta para construirlo y servirlo sin dejar la cadena de herramientas en la imagen final.

FROM oven/bun:1-alpine AS build
WORKDIR /src
COPY . .
RUN bun install --frozen-lockfile && bun run build

FROM nginx:alpine
COPY --from=build /src/dist /usr/share/nginx/html

Antes de publicar conviene probar el bundle tal como quedará servido, con bun run preview o con miniserve --index index.html dist. Para reproducir una publicación en subdirectorio, copiarlo bajo una carpeta y servir el nivel superior:

mkdir -p /tmp/pub/timeline && cp -r dist/* /tmp/pub/timeline/ && miniserve /tmp/pub

Uso

La barra superior controla toda la vista y su estado se guarda en localStorage; el semestre, el zoom, el umbral y la ventana viajan además en la query string, así que un enlace reproduce la vista exacta.

Eje temporal — el lienzo mide días × px/día y nunca se comprime al ancho de la pantalla: se recorre con scroll horizontal. La rejilla marca los meses en la banda superior y las semanas naturales (S1, S2, …) en la inferior. La línea punteada señala el día de hoy y el botón Ir a hoy centra la vista en él.

Carriles — cada materia ocupa una fila con su color. El fondo son las semanas del sílabo: al pasar el cursor muestran el temario y, cuando existe, los temas de laboratorio. Los entregables que se solapan se apilan en sub-filas, de modo que ninguno queda oculto.

Entregables — un hito puntual se dibuja como marcador y un entregable con rango como barra de date a end. La forma distingue el tipo (rombo para exámenes y parciales, cuadrado para talleres y defensas, círculo para el resto) porque el color queda reservado a la materia. Un contorno punteado indica una fecha aproximada, inferida del número de semana. El lienzo no lleva texto: el título y el detalle aparecen al pasar el cursor y, al hacer clic, en el panel derecho junto al temario de esa semana.

Avance — cada entregable puede marcarse como hecho, y una vez llega la calificación se le asigna una nota. Lo entregado se apaga a gris; una nota A, B o C convierte el marcador en oro, plata o bronce, mientras que D y F quedan grises y muestran su letra en el panel. El resumen de la barra superior lleva la cuenta de entregas y de cada medalla sobre lo que está visible.

Con un entregable seleccionado el teclado basta: d alterna hecho, a b c x f asignan la nota (x es la D, porque d ya está tomada), ← y → saltan al entregable anterior o siguiente de la misma materia y Escape cierra el panel.

Alta carga — las cajas rojas cubren verticalmente todos los carriles sobre los rangos de fechas donde se acumulan los entregables. La etiqueta superior indica cuántos hay y abre la lista completa en el panel derecho.

Detección de alta carga

La carga de un día es la suma de los pesos de los entregables visibles desde una ventana centrada en él. Cada entregable cuenta una sola vez por ventana, así que un proyecto de tres semanas no se comporta como veinte entregas. Los días que alcanzan el umbral forman intervalos contiguos, y los intervalos cercanos se fusionan.

Los controles de la barra ajustan la métrica en vivo:

  • Umbral — carga mínima para marcar un día. Por defecto 5.
  • Ventana — radio en días de la ventana. Por defecto ±2.
  • Fusionar — separación máxima entre intervalos que se unen en uno. Por defecto 1 día.
  • Ponderar por tipo — usa el weight de types.json (un parcial pesa 2, un deber 1) en lugar de contar 1 por entregable.
  • Rangos completos — un entregable con rango ocupa todos sus días en vez de sólo el de entrega.
  • Ignorar lo hecho — lo ya entregado deja de pesar, de modo que las cajas miden carga pendiente. Apagarlo devuelve la carga planificada del semestre. Activo por defecto.

Los filtros de materia y de tipo se aplican antes de la detección: ocultar una materia recalcula los períodos con las restantes.

La implementación vive en src/lib/burst.ts como función pura y está cubierta por src/lib/burst.test.ts.

Datos

Los archivos de public/data/ son la única fuente de entregables de la aplicación; el avance del usuario es el único dato que ella produce y vive en el navegador. Para añadir un semestre nuevo basta con dejar su JSON en esa carpeta y registrarlo en index.json. Los botones Exportar e Importar de la barra superior mueven el avance entre navegadores como un archivo JSON. Reference el formato de datos para ambos esquemas.