Un lenguaje.
Un binario.
Toda la web.
SpaceFive es un framework web escrito solo en Five y con todo incluido. HTTP, WebSocket, PostgreSQL, bcrypt, AES, idiomas: el propio runtime se encarga de todo. Sin Node, sin FFI, sin servidor ORM. Un único binario estático que habla directamente con Postgres, con tres aplicaciones reales funcionando encima ahora mismo.
Tres aplicaciones, un mismo framework,
una misma estética.
Cada clic lo atiende un handler de Five: actualizaciones parciales hipermedia, formularios renderizados en el servidor, exportación a CSV, subida de fotos y eventos en tiempo real.
Gestor de activos
Galería, lista y ficha de detalle; búsqueda y filtros por estado y categoría; importes en varias monedas; exportación a CSV con un clic.
Personal / RR. HH.
Un directorio de empleados con puesto, departamento, salario y foto, hecho con la misma carcasa, los mismos chips y las mismas tarjetas que el gestor de activos.
Ventas / ERP
Clientes, productos y pedidos de venta con control de crédito, stock, envíos, facturación, cobros y antigüedad de saldos. Panel, documentos imprimibles e informes.
Este lenguaje ya lo sabes.
Solo ha cambiado la pantalla.
Si has programado en Clipper, FoxPro o Harbour, una página de SpaceFive se lee como un diálogo que has escrito cien veces. Todos los ejemplos de abajo son reales: el widget de la derecha lo acaba de dibujar el código de la izquierda, en esta misma petición.
MENU hMenu MENUBAR MENUITEM "Assets" ACTION "/assets" MENUITEM "People" ACTION "/people" MENUITEM "+ New asset" ACTION "/assets/new" GOLD ENDMENU cHtml := MENU_HTML( hMenu )
hStat := DB_ONE( cAssetStats, {} ) DASHBOARD hDash STAT "Total assets" VALUE hStat[ "n" ] GOLD STAT "Total value" VALUE Money( hStat[ "total" ], "USD" ) GOLD STAT "Active" VALUE hStat[ "active" ] OK STAT "In maintenance" VALUE hStat[ "maint" ] WARN ENDDASHBOARD cHtml := DASH_HTML( hDash )
aRows := DB_QUERY( cFirstEmployees, {} ) TABLE hList OF aRows LINK "/people/:id" COLUMN "name" HEADER "Employee" THUMB "photo" SUB "emp_no" COLUMN "position" HEADER "Position" COLUMN "status" HEADER "Status" BADGE COLUMN "salary" HEADER "Salary" MONEY CURRENCY "currency" RIGHT ENDTABLE cHtml := TABLE_HTML( hList )
GALLERY hCards OF aRows LINK "/people/:id" CARD PHOTO "photo" INITIALS "name" CARD BADGE "status" CARD TAG "position" CARD TITLE "name" CARD META "department" CARD VALUE "salary" CURRENCY "currency" ENDGALLERY cHtml := GALLERY_HTML( hCards )
FORM hForm ACTION "/people" OF hReq GET "emp_no" LABEL "Employee no." VALUE "E-2001" GET "name" LABEL "Name" COMBO "status" LABEL "Status" VALUE "active" ITEMS aStatuses GET "salary" LABEL "Salary (annual)" VALUE 90000 BUTTON "Save" GOLD LINK "Cancel" ACTION "/" ENDFORM cHtml := FORM_HTML( hForm )
De la pantalla DOS al navegador
| Antes escribías | Ahora escribes | Qué hace |
|---|---|---|
| @ 10, 5 SAY "Name" GET cName | GET "name" LABEL "Name" VALUE cName | Un campo de texto con su etiqueta. |
| MENU oMenu … MENUITEM … ENDMENU | MENU hMenu MENUBAR … MENUITEM … ENDMENU | Botones de cabecera, chips laterales y pestañas con una sola sintaxis. |
| TBrowse / dbEdit() | TABLE hList OF aRows … COLUMN … ENDTABLE | Una lista clicable con miniaturas, badges y columnas de importes. |
| USE customers INDEX ON name | aRows := DB_QUERY( cSql, { cName } ) | PostgreSQL con parámetros ligados, sin servidor ORM de por medio. |
| SET COLOR TO W+/B | public/skins/<skin>/skin.css | El aspecto es cosa del skin: CSS y pequeñas plantillas HTML que un diseñador puede tocar. |
| ACTIVATE WINDOW oWnd | FV_SERVE( nPort, "public", {| hReq | APP_DISPATCH( hReq ) } ) | El servidor web entero cabe en una línea de main.prg. |
Runtime nativo, sin pegamento.
Cada capa es una llamada a la librería del runtime de Five. Aparte de PostgreSQL, no hay nada que instalar.
FV_SERVEHTTP de principio a fin
Entran cabeceras y cookies; salen el estado y el set-cookie. Cada petición corre en su propio hilo de la VM.
WsServe · WsSendTiempo real
Un servidor WebSocket sin dependencias. El feed al pie de esta página lo está escuchando.
PG_OPEN · PG_QUERYPostgreSQL, sin intermediarios
Consultas con parámetros ligados sobre pgx. Las migraciones se ejecutan al arrancar y son idempotentes.
PWHASH · ENCRYPT · SECEQSeguro por defecto
Contraseñas con bcrypt, sesiones AES-256-GCM, comparaciones en tiempo constante y CSRF double-submit.
T()Idiomas de serie
Traducciones por catálogo con el idioma decidido en cada petición. Esta misma página se sirve en seis idiomas desde locales/*.json.
hx.jsUI hipermedia
Un shim de 54 líneas al estilo HTMX: swaps parciales y cabeceras CSRF, sin paso de build ni framework.
La petición es un hash. La respuesta, otro.
El handler es un bloque.
La tabla de rutas y un handler reales de la aplicación que está en marcha.
// asset manager — gallery, list, detail, CRUD, export ROUTE( "GET", "/assets", {| hReq | ASSET_DASHBOARD( hReq ) } ) ROUTE( "GET", "/assets/cards", {| hReq | ASSET_CARDS( hReq ) } ) ROUTE( "POST", "/assets", {| hReq | ASSET_CREATE( hReq ) } ) ROUTE( "GET", "/assets/export.csv", {| hReq | ASSET_EXPORT( hReq ) } ) // main.prg — the whole server FV_SERVE( hCfg[ "port" ], "public", {| hReq | APP_DISPATCH( hReq ) } ) // a handler: query → hash → JSON. The result lives in a variable; RETURN returns it. FUNCTION ASSET_LIST( hReq ) LOCAL aRows := Rows( hReq, 1000, 0 ) LOCAL hRes := RES_JSON( { "ok" => .T., "assets" => aRows, "count" => Len( aRows ) } ) RETURN hRes






