Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ on:
jobs:
lighthouse:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -39,3 +42,70 @@ jobs:
name: lighthouse-results
path: .lighthouseci/
retention-days: 30

- name: Comment PR with Lighthouse results
uses: actions/github-script@v7
if: github.event_name == 'pull_request'
with:
script: |
const fs = require('fs');
const path = require('path');

// Find the latest manifest file
const lhciDir = '.lighthouseci';
const files = fs.readdirSync(lhciDir);
const manifestFile = files.find(f => f.startsWith('manifest') && f.endsWith('.json'));

if (!manifestFile) {
console.log('No manifest file found');
return;
}

const manifest = JSON.parse(fs.readFileSync(path.join(lhciDir, manifestFile), 'utf8'));
const lhr = JSON.parse(fs.readFileSync(manifest[0].jsonPath, 'utf8'));

const scores = {
performance: Math.round(lhr.categories.performance.score * 100),
accessibility: Math.round(lhr.categories.accessibility.score * 100),
bestPractices: Math.round(lhr.categories['best-practices'].score * 100),
seo: Math.round(lhr.categories.seo.score * 100)
};

const vitals = {
lcp: lhr.audits['largest-contentful-paint'].numericValue,
cls: lhr.audits['cumulative-layout-shift'].numericValue,
ttfb: lhr.audits['server-response-time'].numericValue
};

const body = `## 🚦 Lighthouse CI Results

| Category | Score |
|----------|-------|
| 🎨 Performance | ${scores.performance}% |
| ♿ Accessibility | ${scores.accessibility}% |
| ✅ Best Practices | ${scores.bestPractices}% |
| 🔍 SEO | ${scores.seo}% |

### Core Web Vitals

| Metric | Value | Threshold |
|--------|-------|-----------|
| LCP | ${(vitals.lcp / 1000).toFixed(2)}s | < 2.5s |
| CLS | ${vitals.cls.toFixed(3)} | < 0.10 |
| TTFB | ${vitals.ttfb.toFixed(0)}ms | < 600ms |

${scores.performance >= 90 && scores.accessibility >= 95 && scores.bestPractices >= 95 && scores.seo >= 90 ? '✅ All thresholds passed!' : '❌ Some thresholds failed. Please review and fix.'}
`;

github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});

- name: Notify Pages deployment
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
echo "✅ Merged to master! GitHub Pages will serve the demo from /docs at:"
echo " https://hutoczky.github.io/FormatX/scifi-ui/"
66 changes: 45 additions & 21 deletions docs/scifi-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,26 @@ npx lighthouse http://localhost:8000/scifi-ui/ --view

### Lighthouse Thresholds (CI)

- Performance: ≥ 90%
- Accessibility: ≥ 95%
- Best Practices: ≥ 95%
- SEO: ≥ 90%
The CI workflow enforces these thresholds:
- **Performance**: ≥ 90%
- **Accessibility**: ≥ 95%
- **Best Practices**: ≥ 95%
- **SEO**: ≥ 90%

Run Lighthouse CI:
**Core Web Vitals:**
- LCP (Largest Contentful Paint): < 2.5s
- CLS (Cumulative Layout Shift): < 0.10
- TTFB (Time to First Byte): < 600ms

Run Lighthouse CI locally:

```bash
npm install -g @lhci/cli
lhci autorun
```

View results in `.lighthouseci/` directory after running.

## 🔧 JavaScript Modules

### theme-switcher.js
Expand Down Expand Up @@ -189,28 +197,44 @@ document.addEventListener('theme:changed', (e) => {

## 📄 Assets & Licenses

### Created Assets
### Asset Inventory

All assets in `docs/scifi-ui/assets/`:

**SVG Files:**
- `svgs/hud-grid.svg` — Star Wars-style HUD grid overlay (original work)
- `svgs/lcars-panels.svg` — LCARS-style panel decorations (original work)
- `svgs/hologram-activation.svg` — Holographic activation effect (original work)

**Placeholder Directories (with .gitkeep):**
- `images/` — Reserved for WebP/AVIF optimized images
- `fonts/` — Reserved for licensed fonts (currently using system stacks)
- `audio/` — Reserved for optional ambient sounds

All visual assets are created with CSS and SVG:
### License Status

- **hud-grid.svg**: Minimal Star Wars-style HUD grid (original work)
- **CSS animations**: All effects implemented in pure CSS
- **Fonts**: System font stacks used (no external fonts loaded)
**All assets are original placeholders** created specifically for this demo
**No unlicensed IP used** — No trademarked logos, copyrighted imagery, or proprietary content
**System font stacks** — No external fonts loaded; commented preload examples in index.html

### Fonts Used
**Fonts:**
- LCARS: `"Eurostile", "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif`
- Star Wars: `"Orbitron", "Roboto Mono", ui-monospace, system-ui, monospace`
- Cyberpunk: `"OCR-A", "VT323", ui-monospace, monospace`

System fallbacks (no licensing required):
- LCARS: `"Eurostile", "Microgramma", "Orbitron", "Exo 2", system-ui`
- Star Wars: `"Share Tech Mono", "Orbitron", ui-monospace`
- Cyberpunk: `"OCR A", "Audiowide", "Exo 2", system-ui`
**Font Setup Instructions:**
When licensed fonts are available:
1. Add woff2 files to `assets/fonts/`
2. Uncomment preload tags in `index.html` `<head>`
3. Add `@font-face` declarations in respective theme CSS files
4. Update README with font licenses

### No Unlicensed IP
### What This Demo Does NOT Include

This demo does **NOT** include:
- Trademarked logos or symbols
- Copyrighted imagery from films/shows
- Licensed sound effects or music
- Proprietary typefaces
- ❌ Trademarked logos or symbols
- ❌ Copyrighted imagery from films/shows
- ❌ Licensed sound effects or music
- ❌ Proprietary typefaces

All designs are inspired aesthetics created from scratch.

Expand Down
24 changes: 24 additions & 0 deletions docs/scifi-ui/assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Assets

All assets are original placeholders created for this demo. No unlicensed IP is used.

## Structure

- `images/` - WebP/AVIF optimized images (empty, .gitkeep maintained)
- `svgs/` - Animated SVG assets:
- `hud-grid.svg` - Star Wars-style HUD grid overlay
- `lcars-panels.svg` - LCARS-style panel placeholder
- `hologram-activation.svg` - Holographic activation effect
- `fonts/` - Font files (empty, .gitkeep maintained, system fallbacks used)
- `audio/` - Optional ambient sounds (empty, .gitkeep maintained)

## License

All SVG files are original works created specifically for this demo. They are inspired by sci-fi aesthetics but contain no trademarked logos, copyrighted imagery, or unlicensed IP.

System font stacks are used throughout:
- LCARS: "Eurostile", "Segoe UI", system-ui
- Star Wars: "Orbitron", "Roboto Mono", ui-monospace
- Cyberpunk: "OCR-A", "VT323", ui-monospace

When licensed fonts are added, update the commented preload tags in `index.html`.
17 changes: 17 additions & 0 deletions docs/scifi-ui/assets/svgs/hologram-activation.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions docs/scifi-ui/assets/svgs/lcars-panels.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/scifi-ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
content="default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'; font-src 'self' data:; media-src 'self'; connect-src 'self'">
<link rel="preload" as="style" href="styles/base.css" />
<link rel="preload" as="style" href="styles/themes.css" />
<!-- Font preload examples (uncomment when licensed fonts are added):
<link rel="preload" as="font" type="font/woff2" href="assets/fonts/eurostile-bold.woff2" crossorigin />
<link rel="preload" as="font" type="font/woff2" href="assets/fonts/orbitron-medium.woff2" crossorigin />
<link rel="preload" as="font" type="font/woff2" href="assets/fonts/vt323-regular.woff2" crossorigin />
-->
<link rel="stylesheet" href="styles/base.css" />
<link rel="stylesheet" href="styles/themes.css" />
<link id="theme-css" rel="stylesheet" href="styles/lcars.css" />
Expand Down
35 changes: 33 additions & 2 deletions docs/scifi-ui/scripts/anim-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,39 @@
cyberpunk:`<svg class="fx glitch-overlay" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true"><defs><filter id="noise"><feTurbulence type="fractalNoise" baseFrequency="1.2" numOctaves="2" stitchTiles="stitch"/></filter></defs><rect width="100%" height="100%" filter="url(#noise)" fill="#FF2EC0" opacity=".06"/></svg>`,
lcars:''
};
function activate(theme){clearLayers(); if(SVGS[theme]) layersHost.appendChild(elFrom(SVGS[theme]));}
function activateThemeAnimations(theme){
const bars=document.querySelectorAll('.progress .bar');
bars.forEach(bar=>{
if(theme==='lcars'){
bar.style.transition='width 1.6s cubic-bezier(.2,.9,.2,1)';
}else if(theme==='starwars'){
bar.style.transition='width 1.8s ease-in-out';
layersHost.classList.add('hud-active');
}else if(theme==='cyberpunk'){
bar.style.transition='width 1.2s steps(6,end)';
bar.classList.add('glitch');
}
});
}
function activate(theme){clearLayers(); if(SVGS[theme]) layersHost.appendChild(elFrom(SVGS[theme])); activateThemeAnimations(theme);}
activate(document.documentElement.getAttribute('data-theme')||'lcars');
document.addEventListener('theme:changed',e=>{activate(e.detail.theme)});
document.addEventListener('preloader:done',()=>{ if(prefersReduced) return; let raf=0; const onMove=(ev)=>{cancelAnimationFrame(raf); raf=requestAnimationFrame(()=>{const x=(ev.clientX/innerWidth-.5)*4; const y=(ev.clientY/innerHeight-.5)*4; layersHost.style.transform=`translate(${x}px, ${y}px)`;});}; window.addEventListener('pointermove',onMove,{passive:true});});
document.addEventListener('preloader:done',()=>{
const bars=document.querySelectorAll('.loader-sample .bar');
bars.forEach(bar=>{
bar.style.width='100%';
bar.classList.add('active');
});
if(prefersReduced) return;
let raf=0;
const onMove=(ev)=>{
cancelAnimationFrame(raf);
raf=requestAnimationFrame(()=>{
const x=(ev.clientX/innerWidth-.5)*4;
const y=(ev.clientY/innerHeight-.5)*4;
layersHost.style.transform=`translate(${x}px, ${y}px)`;
});
};
window.addEventListener('pointermove',onMove,{passive:true});
});
})();
25 changes: 23 additions & 2 deletions docs/scifi-ui/scripts/preloader.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
(function(){
const pre=document.getElementById('preloader'); if(!pre) return;
pre.setAttribute('role','status');
pre.setAttribute('aria-live','polite');
const prefersReduced=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const assets=['styles/base.css','styles/themes.css','styles/lcars.css','styles/starwars.css','styles/cyberpunk.css','assets/svgs/hud-grid.svg'];
let done=0; function tick(){done++; const now=Math.min(100,Math.round(done/assets.length*100)); pre.setAttribute('aria-valuenow',String(now));}
Promise.all(assets.map(u=>fetch(u,{cache:'force-cache'}).then(r=>{tick();return r.ok;}).catch(()=>{tick();}))).then(()=>new Promise(res=>setTimeout(res,prefersReduced?100:600))).finally(()=>{pre.hidden=true; document.dispatchEvent(new CustomEvent('preloader:done'));});
let progress=0;
function setProgress(val){progress=val; pre.setAttribute('aria-valuenow',String(Math.min(100,val)));}
function tick(n){setProgress(progress+n);}
if(prefersReduced){
setProgress(100);
setTimeout(()=>{pre.style.display='none';pre.setAttribute('aria-hidden','true');document.dispatchEvent(new CustomEvent('preloader:done'));},100);
}else{
Promise.all(assets.map(u=>fetch(u,{cache:'force-cache'}).then(r=>r.ok).catch(()=>false))).then(()=>{
const theme=document.documentElement.getAttribute('data-theme')||'lcars';
const jitter=()=>60+Math.random()*30;
const step=()=>{
if(progress>=100){
setTimeout(()=>{pre.style.display='none';pre.setAttribute('aria-hidden','true');document.dispatchEvent(new CustomEvent('preloader:done'));},200);
}else{
tick(theme==='lcars'?6:theme==='starwars'?5:8);
setTimeout(step,jitter());
}
};
step();
});
}
})();
4 changes: 3 additions & 1 deletion docs/scifi-ui/scripts/theme-switcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
const brand=document.getElementById('brand');
function setPressed(btn,on){btn.setAttribute('aria-pressed',String(on));btn.setAttribute('aria-selected',String(on));}
function toggleGlitch(theme){if(!brand)return; if(theme==='cyberpunk'){brand.setAttribute('data-glitch','on');}else{brand.removeAttribute('data-glitch');}}
function setTheme(name){if(!THEMES[name])return; linkEl.setAttribute('href',THEMES[name]); root.setAttribute('data-theme',name); try{localStorage.setItem(STORAGE_KEY,name);}catch(e){}; toggleGlitch(name); document.querySelectorAll('.switcher .theme').forEach(b=>setPressed(b,b.dataset.theme===name)); document.dispatchEvent(new CustomEvent('theme:changed',{detail:{theme:name}}));}
function toggleLoaderSamples(theme){document.querySelectorAll('.loader-sample').forEach(el=>{if(el.dataset.themeSample===theme){el.style.display='block';}else{el.style.display='none';}});}
function setTheme(name){if(!THEMES[name])return; linkEl.setAttribute('href',THEMES[name]); root.setAttribute('data-theme',name); try{localStorage.setItem(STORAGE_KEY,name);}catch(e){}; toggleGlitch(name); toggleLoaderSamples(name); document.querySelectorAll('.switcher .theme').forEach(b=>setPressed(b,b.dataset.theme===name)); document.dispatchEvent(new CustomEvent('theme:changed',{detail:{theme:name}}));}
let start='lcars'; try{const saved=localStorage.getItem(STORAGE_KEY); if(saved&&THEMES[saved]) start=saved;}catch(e){}; setTheme(start);
document.querySelectorAll('.switcher .theme').forEach(btn=>{btn.addEventListener('click',()=>setTheme(btn.dataset.theme)); btn.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();setTheme(btn.dataset.theme);}})});
window.setTheme=setTheme;
})();
5 changes: 3 additions & 2 deletions docs/scifi-ui/styles/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ body{min-height:100%;background:radial-gradient(1200px 600px at 50% -10%,#121622
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
img{max-width:100%;height:auto}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.fx{position:fixed;inset:0;pointer-events:none;z-index:0}
.fx-scanlines{background-image:repeating-linear-gradient(180deg,transparent 0 2px,rgba(255,255,255,.05) 2px 3px);mix-blend-mode:soft-light;opacity:.25}
.fx-noise{background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2' stitchTiles='stitch'/></filter><rect width='120' height='120' filter='url(%23n)' opacity='.06'/></svg>");
Expand All @@ -24,7 +25,7 @@ img{max-width:100%;height:auto}
.switcher .theme[aria-pressed="true"]{background:linear-gradient(180deg,var(--accent),color-mix(in oklab,var(--accent),black 30%));color:#141518}
.hero{max-width:var(--max);margin:40px auto 12px;padding:0 20px;text-align:center}
.progress{position:relative;height:44px;max-width:620px;margin:0 auto 18px;border-radius:24px;background:#0b0d10;box-shadow:inset 0 0 0 2px rgba(0,0,0,.55);overflow:hidden}
.progress .bar{position:absolute;inset:2px 52px 2px 2px;border-radius:22px 0 0 22px;background:linear-gradient(90deg,#ffa726,#cc6f00);animation:fill var(--progress-dur) cubic-bezier(.2,.9,.2,1) infinite}
.progress .bar{position:absolute;inset:2px 52px 2px 2px;border-radius:22px 0 0 22px;background:linear-gradient(90deg,#ffa726,#cc6f00);transition:none;width:0;animation:fill var(--progress-dur) cubic-bezier(.2,.9,.2,1) infinite}
.progress .cap{position:absolute;top:2px;right:2px;bottom:2px;width:50px;border-radius:0 22px 22px 0;background:linear-gradient(180deg,#181a1e,#0f1216);}
@keyframes fill{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}
.brand{margin:0 0 12px;font:900 clamp(34px,6.5vw,66px)/1.05 "Segoe UI",system-ui,Roboto,Arial,sans-serif;letter-spacing:.1em;color:var(--accent-2);text-shadow:0 0 12px #ff9d00aa,0 0 1px #000}
Expand Down Expand Up @@ -58,4 +59,4 @@ img{max-width:100%;height:auto}
.preloader__lcars .preloader__cap{position:absolute;top:2px;right:2px;bottom:2px;width:50px;border-radius:0 22px 22px 0;background:linear-gradient(180deg,#181a1e,#0f1216)}
.preloader__label{margin-top:16px;color:#ffd089;text-align:center}
@keyframes fill{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}
@media (prefers-reduced-motion:reduce){.fx-noise,.fx-scanlines{animation:none}.preloader__lcars .preloader__bar,.progress .bar{animation:none}}
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:0.01ms!important;animation-iteration-count:1!important;transition-duration:0.01ms!important}.fx-noise,.fx-scanlines{animation:none}.preloader__lcars .preloader__bar,.progress .bar{animation:none}}
Loading