diff --git a/group_vars/all/09_networks.yml b/group_vars/all/09_networks.yml index 7e889504..940fc03b 100644 --- a/group_vars/all/09_networks.yml +++ b/group_vars/all/09_networks.yml @@ -120,6 +120,8 @@ defaults_networks: subnet: 192.168.104.96/28 web-app-suitecrm: subnet: 192.168.104.112/28 + web-app-littlejs: + subnet: 192.168.104.128/28 # /24 Networks / 254 Usable Clients web-app-bigbluebutton: diff --git a/group_vars/all/10_ports.yml b/group_vars/all/10_ports.yml index 8cf87b04..957a28a0 100644 --- a/group_vars/all/10_ports.yml +++ b/group_vars/all/10_ports.yml @@ -85,6 +85,7 @@ ports: web-app-shopware: 8060 web-svc-onlyoffice: 8061 web-app-suitecrm: 8062 + web-app-littlejs: 8063 web-app-bigbluebutton: 48087 # This port is predefined by bbb. @todo Try to change this to a 8XXX port public: # The following ports should be changed to 22 on the subdomain via stream mapping diff --git a/roles/web-app-littlejs/README.md b/roles/web-app-littlejs/README.md new file mode 100644 index 00000000..2491d120 --- /dev/null +++ b/roles/web-app-littlejs/README.md @@ -0,0 +1,33 @@ +# LittleJS Playground + +## Description + +**LittleJS Playground** is a self-hosted web application that bundles the LittleJS engine, its official examples, and a minimal Infinito.Nexus launcher UI. +It provides a simple, tile-based overview of demos and games, allowing you to quickly explore LittleJS examples directly in your browser. + +## Overview + +LittleJS Playground is designed as a lightweight HTML5 game sandbox for education, prototyping, and fun. +It exposes the original LittleJS `examples/` browser and adds a Bootstrap-based landing page that lists all examples as clickable tiles and offers quick links to popular games such as platformers and arcade-style demos. +The app runs as a single Docker container and requires no additional database or backend services. + +## Features + +- **Self-hosted LittleJS environment** — run LittleJS demos and games under your own domain. +- **Example browser integration** — direct access to the original LittleJS example browser. +- **Tile-based launcher UI** — dynamically renders a catalog from the `exampleList` definition. +- **Quick links for games** — navbar entries for selected games (e.g. platformer, pong, space shooter). +- **Bootstrap-styled interface** — clean, minimalistic, and responsive layout. +- **Docker-ready** — fully integrated into the Infinito.Nexus Docker stack. + +## Further Resources + +- 🕹 Upstream engine & examples: [KilledByAPixel/LittleJS](https://github.com/KilledByAPixel/LittleJS) +- 📚 LittleJS README & docs: [GitHub – LittleJS](https://github.com/KilledByAPixel/LittleJS#readme) + +## Credits + +LittleJS is developed and maintained by **KilledByAPixel** and contributors. +This integration and role are developed and maintained by **Kevin Veen-Birkenbach**. +Learn more at [veen.world](https://www.veen.world). +Licensed under the [Infinito.Nexus NonCommercial License](https://s.infinito.nexus/license). diff --git a/roles/web-app-littlejs/config/main.yml b/roles/web-app-littlejs/config/main.yml new file mode 100644 index 00000000..bc481686 --- /dev/null +++ b/roles/web-app-littlejs/config/main.yml @@ -0,0 +1,33 @@ +features: + matomo: true + css: true + desktop: true + logout: false + +server: + csp: + whitelist: + script-src-elem: + - "https://cdnjs.cloudflare.com" + - "https://cdn.jsdelivr.net" + style-src-elem: + - "https://cdn.jsdelivr.net" + - "https://cdnjs.cloudflare.com" + font-src: + - "https://cdnjs.cloudflare.com" + - "data:" + connect-src: + - "https://cdn.jsdelivr.net" + frame-src: + - "https://littlejs.{{ PRIMARY_DOMAIN }}" + flags: + style-src-attr: + unsafe-inline: true + script-src-elem: + unsafe-inline: true + script-src-attr: + unsafe-inline: true + domains: + canonical: + - "littlejs.{{ PRIMARY_DOMAIN }}" + aliases: [] diff --git a/roles/web-app-littlejs/files/style.css b/roles/web-app-littlejs/files/style.css new file mode 100644 index 00000000..2d91c01b --- /dev/null +++ b/roles/web-app-littlejs/files/style.css @@ -0,0 +1,55 @@ +/* Global Base Styling */ +body { + /* Use Infinito.Nexus color scheme variables */ + background-color: var(--color-01-90); + color: var(--color-01-05); + min-height: 100vh; + padding-bottom: 4rem; /* Space for footer bar */ +} + +/* Card Styling (Infinito.Nexus Homepage Style) */ +.app-card { + border-radius: 1rem; + background: radial-gradient( + circle at top left, + rgba(var(--color-rgb-01-10), 0.95), + rgba(var(--color-rgb-01-20), 0.90) + ); + border: 1px solid rgba(var(--color-rgb-01-40), 0.35); + box-shadow: 0 18px 45px rgba(var(--color-rgb-01-90), 0.65); + transition: transform .12s ease-out, box-shadow .12s ease-out, border-color .12s ease-out; +} + +.app-card:hover { + transform: translateY(-3px); + box-shadow: 0 22px 60px rgba(var(--color-rgb-01-90), 0.90); + border-color: rgba(var(--color-rgb-01-30), 0.70); +} + +.app-icon { + font-size: 2.6rem; +} + +.app-badge { + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: .12em; +} + +/* Footer Bar */ +.footer-bar { + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: 1030; +} + +.footer-bar .btn-link { + text-decoration: none; + font-size: 0.8rem; +} + +.footer-bar .btn-link:hover { + text-decoration: underline; +} diff --git a/roles/web-app-littlejs/meta/main.yml b/roles/web-app-littlejs/meta/main.yml new file mode 100644 index 00000000..c9b6087c --- /dev/null +++ b/roles/web-app-littlejs/meta/main.yml @@ -0,0 +1,28 @@ +# roles/web-app-littlejs/meta/main.yml +galaxy_info: + author: "Kevin Veen-Birkenbach" + description: > + LittleJS Playground – self-hosted LittleJS example browser and + collection of HTML5 games and demos, wrapped as a Dockerized web app. + license: "Infinito.Nexus NonCommercial License" + license_url: "https://s.infinito.nexus/license" + company: | + Kevin Veen-Birkenbach + Consulting & Coaching Solutions + https://www.veen.world + galaxy_tags: + - infinito + - docker + - webapp + - game + - html5 + - littlejs + repository: "https://s.infinito.nexus/code" + issue_tracker_url: "https://s.infinito.nexus/issues" + documentation: "https://docs.infinito.nexus" + logo: + class: "fa-solid fa-gamepad" + run_after: + - web-app-matomo + +dependencies: [] diff --git a/roles/web-app-littlejs/tasks/01_core.yml b/roles/web-app-littlejs/tasks/01_core.yml new file mode 100644 index 00000000..b80bcd06 --- /dev/null +++ b/roles/web-app-littlejs/tasks/01_core.yml @@ -0,0 +1,23 @@ +- name: "load docker, proxy for '{{ application_id }}'" + include_role: + name: sys-stk-full-stateless + vars: + docker_compose_flush_handlers: false + +- name: "Load LittleJS example metadata" + include_vars: + file: "examples.yml" + +- name: "Render LittleJS index.html" + template: + src: "html/index.html.j2" + dest: "{{ LITTLEJS_INDEX_HOST_ABS }}" + mode: "0644" + notify: + - docker compose build + - docker compose up + +- name: "flush docker compose for '{{ application_id }}'" + meta: flush_handlers + +- include_tasks: utils/run_once.yml diff --git a/roles/web-app-littlejs/tasks/main.yml b/roles/web-app-littlejs/tasks/main.yml new file mode 100644 index 00000000..4204121d --- /dev/null +++ b/roles/web-app-littlejs/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- include_tasks: 01_core.yml + when: run_once_web_app_littlejs is not defined diff --git a/roles/web-app-littlejs/templates/Dockerfile.j2 b/roles/web-app-littlejs/templates/Dockerfile.j2 new file mode 100644 index 00000000..f1abfbee --- /dev/null +++ b/roles/web-app-littlejs/templates/Dockerfile.j2 @@ -0,0 +1,9 @@ +# roles/web-app-littlejs/templates/Dockerfile.j2 +FROM nginx:alpine + +# Static LittleJS assets – engine builds + examples +COPY ./{{ LITTLEJS_APP_REL }}/examples /usr/share/nginx/html/examples +COPY ./{{ LITTLEJS_APP_REL }}/dist /usr/share/nginx/html/dist + +# Custom Infinito.Nexus landing page with Bootstrap menu and tiles +COPY ./{{ LITTLEJS_INDEX_HOST_REL }} /usr/share/nginx/html/index.html diff --git a/roles/web-app-littlejs/templates/docker-compose.yml.j2 b/roles/web-app-littlejs/templates/docker-compose.yml.j2 new file mode 100644 index 00000000..0c078a0b --- /dev/null +++ b/roles/web-app-littlejs/templates/docker-compose.yml.j2 @@ -0,0 +1,10 @@ +--- +{% include 'roles/docker-compose/templates/base.yml.j2' %} + {{ LITTLEJS_SERVICE }}: + container_name: {{ LITTLEJS_CONTAINER }} + {{ lookup('template', 'roles/docker-container/templates/build.yml.j2') | indent(4) }} + ports: + - 127.0.0.1:{{ ports.localhost.http[application_id] }}:80 +{% include 'roles/docker-container/templates/base.yml.j2' %} + +{% include 'roles/docker-compose/templates/networks.yml.j2' %} diff --git a/roles/web-app-littlejs/templates/html/index.html.j2 b/roles/web-app-littlejs/templates/html/index.html.j2 new file mode 100644 index 00000000..40073814 --- /dev/null +++ b/roles/web-app-littlejs/templates/html/index.html.j2 @@ -0,0 +1,32 @@ + + + + + {{ LITTLEJS_TITLE }} + + + + + + + + + + + {% include "nav_top.html.j2" %} + + {% include "main.html.j2" %} + + {% include "nav_bottom.html.j2" %} + + + + \ No newline at end of file diff --git a/roles/web-app-littlejs/templates/html/main.html.j2 b/roles/web-app-littlejs/templates/html/main.html.j2 new file mode 100644 index 00000000..b7a5da57 --- /dev/null +++ b/roles/web-app-littlejs/templates/html/main.html.j2 @@ -0,0 +1,58 @@ +
+
+

LittleJS Examples & Games

+

+ Browse and launch LittleJS demos rendered dynamically through Infinito.Nexus. +

+
+ +
+
+ + {% for key, cat in littlejs_examples|dictsort %} + {% for ex in cat['items'] %} + {% if ex.is_project %} + {% set href = "/examples/" ~ ex.file ~ "/" %} + {% else %} + {% set href = "/examples/shorts/base.html?file=" ~ ex.file %} + {% endif %} + +
+
+
+ +
+
+ +
+ + {{ cat.label|replace('---','')|trim }} + +
+ +

{{ ex.name }}

+ + {% if ex.description %} +

{{ ex.description }}

+ {% endif %} + + {% if ex.tags %} +

{{ ex.tags }}

+ {% endif %} + + + +
+
+
+ + {% endfor %} + {% endfor %} + +
+
+
diff --git a/roles/web-app-littlejs/templates/html/nav_bottom.html.j2 b/roles/web-app-littlejs/templates/html/nav_bottom.html.j2 new file mode 100644 index 00000000..709d70be --- /dev/null +++ b/roles/web-app-littlejs/templates/html/nav_bottom.html.j2 @@ -0,0 +1,23 @@ + + + diff --git a/roles/web-app-littlejs/templates/html/nav_top.html.j2 b/roles/web-app-littlejs/templates/html/nav_top.html.j2 new file mode 100644 index 00000000..fe9d07f5 --- /dev/null +++ b/roles/web-app-littlejs/templates/html/nav_top.html.j2 @@ -0,0 +1,68 @@ + + diff --git a/roles/web-app-littlejs/vars/examples.yml b/roles/web-app-littlejs/vars/examples.yml new file mode 100644 index 00000000..9c914e13 --- /dev/null +++ b/roles/web-app-littlejs/vars/examples.yml @@ -0,0 +1,401 @@ +# roles/web-app-littlejs/vars/examples.yml +# LittleJS examples for launcher UI (used to generate example tiles and menu) + +littlejs_examples: + basic: + label: "--- BASIC ---" + icon: "fa-solid fa-shapes" + items: + - name: "Hello World" + file: "helloWorld.js" + description: "Simple starter example" + is_project: false + tags: "beginner, gradient, text, tiles" + icon: "fa-solid fa-seedling" + + - name: "Empty" + file: "empty.js" + description: "Empty example template" + is_project: false + tags: "beginner, text" + icon: "fa-regular fa-file" + + - name: "Texture" + file: "texture.js" + description: "Texture display and manipulation" + is_project: false + tags: "sprites, loading, tiles" + icon: "fa-regular fa-image" + + - name: "Animation" + file: "animation.js" + description: "Sprite animation system" + is_project: false + tags: "frames, loop, tiles, sprites" + icon: "fa-solid fa-film" + + - name: "Shapes" + file: "shapes.js" + description: "Draw geometric shapes and primitives" + is_project: false + tags: "circle, ellipse, rectangle, polygon, lines" + icon: "fa-solid fa-draw-polygon" + + - name: "Colors" + file: "colors.js" + description: "Color manipulation and HSL" + is_project: false + tags: "hue, saturation, blending, rectangle" + icon: "fa-solid fa-palette" + + - name: "Sprite Atlas" + file: "spriteAtlas.js" + description: "Sprite atlas and tile rendering" + is_project: false + tags: "sheet, frames, tiles" + icon: "fa-solid fa-table-cells-large" + + - name: "Blending" + file: "blending.js" + description: "Additive blending and transparency" + is_project: false + tags: "alpha, color, tiles, smooth" + icon: "fa-solid fa-droplet" + + - name: "Tile Layer" + file: "tileLayer.js" + description: "Tile layer rendering system" + is_project: false + tags: "level, map, grid, particles" + icon: "fa-solid fa-border-all" + + - name: "Particles" + file: "particles.js" + description: "Particle system" + is_project: false + tags: "effects, emitter, physics, fire, smoke" + icon: "fa-solid fa-burst" + + - name: "Input" + file: "input.js" + description: "Input system demo for keyboard, mouse, touch, and gamepad." + is_project: false + tags: "input, control" + icon: "fa-regular fa-keyboard" + + - name: "Timers" + file: "timers.js" + description: "Timer objects and UI" + is_project: false + tags: "delay, interval, slider" + icon: "fa-regular fa-clock" + + - name: "Sound Effects" + file: "sound.js" + description: "ZzFX sound effect generator" + is_project: false + tags: "audio, volume, ui" + icon: "fa-solid fa-bell" + + - name: "Music" + file: "music.js" + description: "Basic load, play, pause, and stop" + is_project: false + tags: "music, sound, audio, streaming, volume, ui" + icon: "fa-solid fa-headphones-simple" + + - name: "Video" + file: "videoPlayer.js" + description: "Basic video play, pause, and stop" + is_project: false + tags: "movie, sound, audio, streaming, volume, ui" + icon: "fa-solid fa-video" + + - name: "Font Image" + file: "fontImage.js" + description: "Bitmap font system with built-in system font" + is_project: false + tags: "text, characters" + icon: "fa-solid fa-font" + + - name: "Medals" + file: "medals.js" + description: "Achievement system" + is_project: false + tags: "unlock, progress, newgrounds" + icon: "fa-solid fa-medal" + + - name: "Tile Raycast" + file: "tileRaycast.js" + description: "Example of the tile layer raycast collision" + is_project: false + tags: "level, map, grid" + icon: "fa-solid fa-crosshairs" + + - name: "Camera Mouse Drag" + file: "cameraDrag.js" + description: "Example of how to control camera with mouse" + is_project: false + tags: "ui, input, control" + icon: "fa-solid fa-arrows-up-down-left-right" + + - name: "Debug Drawing" + file: "debugDraw.js" + description: "Debug drawing system" + is_project: false + tags: "debug, circle, line, rectangle" + icon: "fa-solid fa-bug" + + advanced: + label: "--- ADVANCED ---" + icon: "fa-solid fa-rocket" + items: + - name: "Clock" + file: "clock.js" + description: "Animated analog clock" + is_project: false + tags: "time, rotation, lines, rectangle" + icon: "fa-regular fa-clock" + + - name: "Starfield" + file: "starfield.js" + description: "Animated parallax starfield" + is_project: false + tags: "space, movement, depth, rectangle" + icon: "fa-solid fa-star" + + - name: "Parallax" + file: "parallax.js" + description: "Parallax scrolling mountains" + is_project: false + tags: "generative, canvas, background" + icon: "fa-solid fa-mountain-sun" + + - name: "Maze Generator" + file: "maze.js" + description: "Procedural maze generation" + is_project: false + tags: "generative, level, tiles, map, grid" + icon: "fa-solid fa-border-style" + + - name: "Piano" + file: "piano.js" + description: "Interactive piano keyboard" + is_project: false + tags: "music, sound, audio, notes, ui, instrument" + icon: "fa-solid fa-music" + + - name: "Step Sequencer" + file: "sequencer.js" + description: "Simple music loop creation tool" + is_project: false + tags: "music, sound, audio, notes, ui, instrument" + icon: "fa-solid fa-sliders" + + - name: "Music Player" + file: "musicPlayer.js" + description: "Music player with audio seeking and drag and drop" + is_project: false + tags: "sound, loading, audio, ui" + icon: "fa-solid fa-compact-disc" + + games: + label: "--- GAMES ---" + icon: "fa-solid fa-gamepad" + items: + - name: "Pong Game" + file: "pongGame.js" + description: "Classic paddle ball bouncing" + is_project: false + tags: "objects, collision" + icon: "fa-solid fa-table-tennis-paddle-ball" + + - name: "Platformer Game" + file: "platformer.js" + description: "Jump and run side view" + is_project: false + tags: "objects, gravity, level, tiles, camera" + icon: "fa-solid fa-person-running" + + - name: "Top Down Game" + file: "topDown.js" + description: "Top-down style camera" + is_project: false + tags: "objects, movement, exploration" + icon: "fa-solid fa-up-down-left-right" + + - name: "Tilted View Game" + file: "tiltedView.js" + description: "Pseudo-3D oblique view" + is_project: false + tags: "isometric, depth" + icon: "fa-solid fa-cube" + + - name: "Flappy Game" + file: "flappyGame.js" + description: "Flappy bird style game" + is_project: false + tags: "objects, obstacles" + icon: "fa-solid fa-dove" + + - name: "Lander Game" + file: "landerGame.js" + description: "Lunar lander style game" + is_project: false + tags: "objects, physics" + icon: "fa-solid fa-rocket" + + - name: "Hill Glide Game" + file: "hillGlideGame.js" + description: "Tiny wings style sliding game" + is_project: false + tags: "objects, physics, speed" + icon: "fa-solid fa-mountain" + + - name: "Sliding Puzzle" + file: "slidingPuzzle.js" + description: "15 tile sliding puzzle" + is_project: false + tags: "objects, numbers, ui" + icon: "fa-solid fa-grip" + + - name: "Space Game" + file: "spaceGame.js" + description: "Spaceship shooter with parallax" + is_project: false + tags: "objects, weapons, stars, camera, rotation" + icon: "fa-solid fa-meteor" + + - name: "3D FPS Game" + file: "fps.js" + description: "Pseudo 3D raycasting demo" + is_project: false + tags: "3D, FPS, maze, camera" + icon: "fa-solid fa-bullseye" + + plugins: + label: "--- PLUGINS ---" + icon: "fa-solid fa-puzzle-piece" + items: + - name: "Box2d Demo" + file: "box2d.js" + description: "Box2D physics plugin" + is_project: false + tags: "objects, mouse" + icon: "fa-solid fa-cubes" + + - name: "Box2d Car" + file: "box2dCar.js" + description: "Drivable car with Box2D physics" + is_project: false + tags: "objects, vehicle, suspension, wheels" + icon: "fa-solid fa-car" + + - name: "Box2d Pool" + file: "box2dPool.js" + description: "Billiard table pool game with Box2d physics" + is_project: false + tags: "objects, game" + icon: "fa-solid fa-pool-8-ball" + + - name: "Box2d Tile Layer" + file: "box2dTileLayer.js" + description: "Tile layer with Box2d physics" + is_project: false + tags: "objects, level, map, grid" + icon: "fa-solid fa-border-all" + + - name: "WebGL Shader" + file: "shader.js" + description: "Full canvas webgl shader" + is_project: false + tags: "webgl, visual, effect" + icon: "fa-solid fa-wand-magic-sparkles" + + - name: "Post Processing" + file: "postProcess.js" + description: "Shader effects and filters" + is_project: false + tags: "webgl, visual, effect" + icon: "fa-solid fa-sparkles" + + - name: "UI System" + file: "uiSystem.js" + description: "Buttons, sliders, and checkboxes" + is_project: false + tags: "objects, widgets, interactive" + icon: "fa-solid fa-sliders" + + - name: "Nine Slice" + file: "nineSlice.js" + description: "Scalable UI panels" + is_project: false + tags: "three slice, stretch, corners, text, tiles" + icon: "fa-solid fa-vector-square" + + full_examples: + label: "--- FULL EXAMPLES ---" + icon: "fa-solid fa-box-open" + items: + - name: "Starter" + file: "starter" + description: "Clean project template" + is_project: true + tags: "base, empty, particles" + icon: "fa-solid fa-seedling" + + - name: "Breakout Tutorial" + file: "breakoutTutorial" + description: "Step-by-step breakout game tutorial" + is_project: true + tags: "objects, physics, score" + icon: "fa-solid fa-graduation-cap" + + - name: "Breakout Game" + file: "breakout" + description: "Complete breakout game" + is_project: true + tags: "objects, physics, score" + icon: "fa-solid fa-table-tennis-paddle-ball" + + - name: "Platforming Game" + file: "platformer" + description: "Platformer with level loading" + is_project: true + tags: "jump, world, tiles, pixel art, sprites" + icon: "fa-solid fa-person-running" + + - name: "Puzzle Game" + file: "puzzle" + description: "Match 3 style puzzle game" + is_project: true + tags: "match, swap, sprites" + icon: "fa-solid fa-puzzle-piece" + + - name: "Stress Test" + file: "stress" + description: "Performance and music test" + is_project: true + tags: "optimization, tiles, sprites" + icon: "fa-solid fa-gauge-high" + + - name: "Box2D Plugin" + file: "box2d" + description: "Full Box2D physics demo" + is_project: true + tags: "objects, bodies, joints" + icon: "fa-solid fa-cubes" + + - name: "HTML Menus" + file: "htmlMenu" + description: "HTML UI integration" + is_project: true + tags: "web, browser, overlay, button, slider, textbox" + icon: "fa-solid fa-code" + + - name: "UI System Plugin Demo" + file: "uiSystem" + description: "Complete UI system demo" + is_project: true + tags: "menu, overlay, button, slider, checkbox" + icon: "fa-solid fa-sliders" diff --git a/roles/web-app-littlejs/vars/main.yml b/roles/web-app-littlejs/vars/main.yml new file mode 100644 index 00000000..8ef145e7 --- /dev/null +++ b/roles/web-app-littlejs/vars/main.yml @@ -0,0 +1,30 @@ +# General +application_id: "web-app-littlejs" +entity_name: "{{ application_id | get_entity_name }}" + +# Features +features: + css: true + matomo: true + desktop: true + +LITTLEJS_HEADLINE: "" + +LITTLEJS_TITLE: "LittleJS Playground – {{ PRIMARY_DOMAIN | upper }}" + +# Base repository URL for LittleJS +LITTLEJS_REPOSITORY_BASE: "https://github.com/KilledByAPixel/LittleJS" + +# Git repository for LittleJS engine + examples +docker_repository_address: "{{ LITTLEJS_REPOSITORY_BASE }}.git" +docker_pull_git_repository: true +docker_repository_branch: "main" + +# Relative path where sys-stk-full-stateless checks out the repo +LITTLEJS_APP_REL: "services/repository" +LITTLEJS_INDEX_HOST_ABS: "{{ [ docker_compose.directories.volumes, 'index.html' ] | path_join }}" +LITTLEJS_INDEX_HOST_REL: "volumes/index.html" + +# Helper variables +LITTLEJS_CONTAINER: "{{ entity_name }}" +LITTLEJS_SERVICE: "{{ entity_name }}"