diff --git a/ISSUES.md b/ISSUES.md index a26c98b..be5e186 100644 --- a/ISSUES.md +++ b/ISSUES.md @@ -12,7 +12,7 @@ Each issue is formatted as `- [ ] [-]`. When resolved it becomes -` - [x] [MP-100] Replaced the sketch-based hero with the inline hero video (muted by default with an audio toggle) and refreshed the favicon using the provided JPEG source. - [x] [MP-101] Changed the global theme to dark turquoise with golden typography, updating hero/sections/cards/buttons accordingly. - [x] [MP-102] Integrated the declarative `` from mpr-ui (non-sticky, no theme switch) plus lab-wide quick links. -- [ ] [MP-103] Restructure landing page into four product bands +- [x] [MP-103] Restructure landing page into four product bands Summary - Rebuild the entire landing page information architecture (below the hero) around four top-level sections: Research, Tools, Platform, Products. @@ -59,16 +59,37 @@ Each issue is formatted as `- [ ] [-]`. When resolved it becomes -` - Presence of section headings “Research”, “Tools”, “Platform”, “Products”. - At least one project card rendered under each of those headings, driven by the JSON catalog. - Every rendered card shows a name, description, and status badge, and either a working link or an explicit “coming soon” style when configured. + Outcome + - Created `data/projects.json`, rebuilt the four section bands to render cards from the catalog (status-sorted with static visuals), and added Playwright assertions for headings, cards, and link behavior. + +- [x] [MP-104] add an ability to visually flip the card and show the back of the card. we will embed a form from LoppAware to subscribe tio the news there later, but I want the cards with BETA and WIP status to flip when clicked on + - Implemented flippable card markup/CSS and JS so Beta and WIP cards toggle an `is-flipped` state on click/keyboard while Production cards remain static, and extended Playwright coverage to assert the behavior. +- [ ] [MP-105] LoopAware-powered feedback widget + - Integrate a LoopAware widget that lets visitors send structured feedback (text + contact details) straight from the landing page footer without jumping to another product surface. + - Current difficulties: the LoopAware embed we ship today is hard-coded for “subscribe” flows (email-only, no free-form message fields), and the script instance assumes each card maps to a LoopAware property, so there is no single endpoint or schema for a global “site feedback” inbox. We need a LoopAware template that supports multi-field submissions plus a consolidated destination before wiring it into the footer drop-up. ## Improvements (200–299) - [x] [MP-200] Hero text/CTA now lives below the video with refreshed cyberpunk styling so the motion stays unobstructed. - [x] [MP-201] Swapped in the new hero video (web-optimized MP4) and refreshed fonts (Orbitron + Space Grotesk) to match the cyberpunk aesthetic. - [ ] [MP-202] LoopAware-powered subscriptions for WIP cards - - On project cards with status WIP, make the WIP badge clickable so the card visually flips as if turned over and reveals a “subscribe to updates” surface. + - On project cards with status WIP, make the WIP badge clickable so the card visually flips as if turned over and reveals a "subscribe to updates" surface. - Embed the subscribe form from the LoopAware project (widget or inline form) so visitors can subscribe to news about that specific project without leaving the page. - - Decide whether each project maps to its own LoopAware site identifier or whether all WIP cards share a single “lab updates” subscription list, and document that mapping. + - Decide whether each project maps to its own LoopAware site identifier or whether all WIP cards share a single "lab updates" subscription list, and document that mapping. - Extend Playwright coverage to assert that WIP cards expose a working subscription surface and that Production/Beta cards continue to behave as in MP-103. +- [x] [MP-203] Band order in HTML does not match SECTION_ORDER constant in JavaScript — Fixed by reordering `` elements in `index.html` to match MP-103 canonical order: Research → Tools → Platform → Products. + - `index.html` declares bands in visual order: Tools → Platform → Products → Research + - `script.js:28-33` defines `SECTION_ORDER = ["Research", "Tools", "Platform", "Products"]` + - The mismatch causes no functional bug (cards render correctly because JS iterates bands by `data-band-category` attribute), but it creates maintainability confusion when reasoning about section ordering. + - Fix option A: Reorder `` elements in `index.html` to match `SECTION_ORDER` (Research → Tools → Platform → Products). + - Fix option B: Reorder `SECTION_ORDER` in `script.js` to match the intended visual order (Tools → Platform → Products → Research). + - Decide which order is canonical per MP-103 requirements ("Research → Tools → Platform → Products") and align both files. +- [x] [MP-204] Subscribe iframe uses `tabindex="-1"`, potentially blocking keyboard-only users from interacting with the LoopAware form — Fixed by toggling iframe tabindex in the `toggleFlip` handler: `tabindex="0"` when flipped, `tabindex="-1"` when unflipped. Added Playwright assertions to verify the behavior. + - Location: `script.js:159` sets `subscribeFrame.setAttribute("tabindex", "-1")` + - Current behavior: The iframe cannot receive focus via Tab navigation, which may prevent keyboard users from entering email or submitting the subscribe form. + - Rationale for current code: Likely added to prevent focus from jumping into the iframe during card flip animation or while card is not flipped. + - Fix: Conditionally set `tabindex="0"` on the iframe when the card enters the flipped state (`is-flipped` class added) and restore `tabindex="-1"` when unflipped. Update the `toggleFlip` handler in `script.js:207-225` to toggle the iframe's tabindex alongside the flip state. + - Extend Playwright test `subscribe-enabled cards render LoopAware forms after flipping` to assert that the iframe is focusable (`tabindex="0"`) when the card is flipped. ## BugFixes (300–399) @@ -79,6 +100,14 @@ Each issue is formatted as `- [ ] [-]`. When resolved it becomes -` sticky="false" ``` +- [x] [MP-301] Footer host element has `position: relative` instead of `position: static`, causing Playwright test `footer respects non-sticky configuration` to fail — Fixed by adding `position: static !important` to override mpr-ui CDN defaults in `styles.css:538`. + - Test location: `tests/hero.spec.js:109` + - Expected: `position: static` on `mpr-footer` host element + - Actual: `position: relative` + - Root cause: The mpr-ui CDN stylesheet likely sets `position: relative` on the `mpr-footer` custom element, and our local `styles.css:536-541` does not explicitly override it to `static`. + - Fix: Add `position: static;` to the `mpr-footer { ... }` rule block in `styles.css` at line 536 to ensure the host element is not positioned, regardless of CDN defaults. + - Verify fix passes: `npx playwright test --grep "footer respects non-sticky"`. + ## Maintenance (400–499) - [x] [MP-400] Added `docker-compose.yml` + `.env.ghttp` to run the site through `ghcr.io/temirov/ghttp` and documented the workflow in README. @@ -98,6 +127,29 @@ Each issue is formatted as `- [ ] [-]`. When resolved it becomes -` - Final status (WIP, Beta, Production). - Short, approved description text (one to two sentences, consistent tone). - Populate @projects.yml to the best of your abilities +- [ ] [MP-404] I am using bands in the design of @index.html. I want to add bands web components to mpr-ui (symlinked under @tools/mpr-ui) and use these components from mpr-ui CDN. +Deliverables: +1. web component added to mpr-ui. A PR is open in mpr-ui repo +2. web component provides sufficient cuastimization options using declarative syntax +3. mpr-ui is loaded from the CDN in @index.html +- [x] [MP-405] Consolidated all imagery, videos, and favicons under a canonical `assets/` tree: created `assets/site/` for hero media, fonts, favicons, and brand imagery, standardized project icons as `assets/projects//icon.(svg|png)` while keeping raw files in per-project `brand/` subfolders, and refreshed `index.html`/README references accordingly. +- [x] [MP-406] Rebranded Product Scanner to **Poodle Scanner**, refreshed its description in `data/projects.(json|yml)`, and shipped the ProductScanner repo’s Poodle mark at `assets/projects/product-scanner/icon.png`. +- [x] [MP-407] Normalized every raster project logo to 64×64 (storing the original favicons inside each `brand/` folder), resized the new Poodle icon from the 2048px source, and published `docs/assets-report.md` to document sizes + sources. +- [x] [MP-408] Embedded the LoopAware subscribe widget on the LoopAware project card back face, restyled it to match the lab palette, and wired the flipping logic/tests so beta-style cards can host future LoopAware subscribe mounts. +- [ ] [MP-409] PLAN.md is tracked in git history, violating AGENTS.GIT.md workflow rules + - AGENTS.GIT.md line 47 states: "PLAN.md is intentionally ignored in .gitignore; ensure it never appears in commits." + - Current state: `PLAN.md` was committed in branch `feature/MP-104-flippable-cards` and is visible in `git diff master...HEAD -- PLAN.md`. + - Root cause: `.gitignore` is missing the `PLAN.md` entry. + - Fix steps: + 1. Add `PLAN.md` to `.gitignore` (append at end of file). + 2. Remove PLAN.md from git tracking: `git rm --cached PLAN.md`. + 3. Commit the `.gitignore` update and removal. + 4. If PLAN.md must be purged from history (per AGENTS.GIT.md guidance), run: `git filter-repo --path PLAN.md --invert-paths` — but note this rewrites history and is forbidden by AGENTS.GIT.md ("Never use git push --force, git rebase..."). Safer alternative: leave the historical commit as-is and ensure future commits exclude PLAN.md. + - Verify: `git status` should show PLAN.md as untracked after fix. +- [x] [MP-410] Double blank line before DOMContentLoaded listener in script.js — Removed extra blank line at `script.js:476`. + - Location: `script.js:469-470` has two consecutive blank lines before `document.addEventListener("DOMContentLoaded", ...)`. + - AGENTS.FRONTEND.md requires tidy code without dead code or duplicate logic; while not a functional issue, the extra blank line is a style inconsistency. + - Fix: Remove one of the two blank lines at `script.js:469` so only a single blank line separates the `setupHeroAudioToggle` function from the `DOMContentLoaded` listener. -## Planning +## Planning **Do not work on these, not ready** diff --git a/Makefile b/Makefile index d51f0b0..48f7fac 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install lint test ci projects-json +.PHONY: install lint test ci install: npm install @@ -11,6 +11,3 @@ test: ci: npm run ci - -projects-json: - npx js-yaml data/projects.yml > data/projects.json diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..27b4900 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,5 @@ +# LoopAware subscribe plan + +- Load the hosted LoopAware subscribe widget (`subscribe.js`) so the site can post email submissions against the production service. +- Update flippable cards to host a subscribe mount (starting with LoopAware) and restyle the widget so it blends into the existing beta/alpha back face. +- Wait for the widget to render, move it into the card mount, and extend the Playwright suite to assert the mount exists. diff --git a/README.md b/README.md index 571cae1..2d1706c 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,19 @@ Landing page for Marco Polo Research Lab. -The home page features an animated hero section, an about overview and a gallery of our public apps. - -This repository hosts the static website built with HTML, CSS and JavaScript. [Three.js](https://threejs.org/) is used to draw and animate the lab's logo and project icons. +The site ships a data-driven hero and project gallery built with semantic HTML, web components from `mpr-ui`, vanilla CSS, and Alpine-powered behaviors in `script.js`. Static assets now live under a consistent `assets/` hierarchy so projects, site chrome, and favicons pull from predictable locations. You can open `index.html` directly in your browser or serve the site through GitHub Pages. ## Structure -- `index.html` – main page with hero section, about information and a gallery of apps -- `script.js` – initializes Three.js and animates the SVG assets -- `assets/` – fonts and SVG illustrations +- `index.html` – main page with the hero video, CTA, `` project sections, and the lab footer. +- `script.js` – fetches `data/projects.json`, renders the project cards, and wires up interactive affordances such as the LoopAware-ready flip state. +- `styles.css` – layout, typography, and per-band styling. +- `data/projects.json` – canonical catalog that drives the landing page and tests. +- `assets/` – canonical home for static assets: + - `assets/site/` – hero video, fonts, favicon bundle, and Marco Polo brand imagery + - `assets/projects//icon.(png|svg)` – project card icons plus any extra brand files under `assets/projects//brand/` ## Local Development with Docker Compose @@ -50,11 +52,11 @@ Playwright downloads Chromium automatically during `npm install`; the tests load ## Adding a New App -Each entry in the project gallery consists of an SVG logo, a `` element and a call to `initProjectAnimation()` in `script.js`. To add a new app: +Each entry in the project gallery is powered by `data/projects.json`: -1. create a new SVG logo in the `assets/` folder -2. add a project card in `index.html` following existing examples -3. reference the SVG from `script.js` +1. create a new `assets/projects//icon.(png|svg)` and keep any supporting references in `assets/projects//brand/` +2. add the project metadata to `data/projects.json` +3. open `index.html` locally or run `npm test` to ensure the Playwright suite exercises the new entry cleanly Vectorizing images or text to SVG can be done using the tools available in the [svg_tools](https://github.com/tyemirov/svg_tools) repository. diff --git a/assets/allergy/Gemini_Generated_Image_1576gn1576gn1576.png b/assets/projects/allergy-wheel/brand/Gemini_Generated_Image_1576gn1576gn1576.png similarity index 100% rename from assets/allergy/Gemini_Generated_Image_1576gn1576gn1576.png rename to assets/projects/allergy-wheel/brand/Gemini_Generated_Image_1576gn1576gn1576.png diff --git a/assets/allergy/Gemini_Generated_Image_1576gn1576gn1576_outline.svg b/assets/projects/allergy-wheel/brand/Gemini_Generated_Image_1576gn1576gn1576_outline.svg similarity index 100% rename from assets/allergy/Gemini_Generated_Image_1576gn1576gn1576_outline.svg rename to assets/projects/allergy-wheel/brand/Gemini_Generated_Image_1576gn1576gn1576_outline.svg diff --git a/assets/allergy/Gemini_Generated_Image_b7dfs3b7dfs3b7df.png b/assets/projects/allergy-wheel/brand/Gemini_Generated_Image_b7dfs3b7dfs3b7df.png similarity index 100% rename from assets/allergy/Gemini_Generated_Image_b7dfs3b7dfs3b7df.png rename to assets/projects/allergy-wheel/brand/Gemini_Generated_Image_b7dfs3b7dfs3b7df.png diff --git a/assets/allergy/Gemini_Generated_Image_s90m3os90m3os90m.png b/assets/projects/allergy-wheel/brand/Gemini_Generated_Image_s90m3os90m3os90m.png similarity index 100% rename from assets/allergy/Gemini_Generated_Image_s90m3os90m3os90m.png rename to assets/projects/allergy-wheel/brand/Gemini_Generated_Image_s90m3os90m3os90m.png diff --git a/assets/allergy/adventurous_boy.png b/assets/projects/allergy-wheel/brand/adventurous_boy.png similarity index 100% rename from assets/allergy/adventurous_boy.png rename to assets/projects/allergy-wheel/brand/adventurous_boy.png diff --git a/assets/allergy/adventurous_boy1.png b/assets/projects/allergy-wheel/brand/adventurous_boy1.png similarity index 100% rename from assets/allergy/adventurous_boy1.png rename to assets/projects/allergy-wheel/brand/adventurous_boy1.png diff --git a/assets/allergy/adventurous_boy1_vectorized.svg b/assets/projects/allergy-wheel/brand/adventurous_boy1_vectorized.svg similarity index 100% rename from assets/allergy/adventurous_boy1_vectorized.svg rename to assets/projects/allergy-wheel/brand/adventurous_boy1_vectorized.svg diff --git a/assets/allergy/creative boy.png b/assets/projects/allergy-wheel/brand/creative boy.png similarity index 100% rename from assets/allergy/creative boy.png rename to assets/projects/allergy-wheel/brand/creative boy.png diff --git a/assets/allergy/creative boy1.png b/assets/projects/allergy-wheel/brand/creative boy1.png similarity index 100% rename from assets/allergy/creative boy1.png rename to assets/projects/allergy-wheel/brand/creative boy1.png diff --git a/assets/allergy/creative boy1_vectorized.svg b/assets/projects/allergy-wheel/brand/creative boy1_vectorized.svg similarity index 100% rename from assets/allergy/creative boy1_vectorized.svg rename to assets/projects/allergy-wheel/brand/creative boy1_vectorized.svg diff --git a/assets/allergy/curious girl.png b/assets/projects/allergy-wheel/brand/curious girl.png similarity index 100% rename from assets/allergy/curious girl.png rename to assets/projects/allergy-wheel/brand/curious girl.png diff --git a/assets/allergy/curious girl_vectorized.svg b/assets/projects/allergy-wheel/brand/curious girl_vectorized.svg similarity index 100% rename from assets/allergy/curious girl_vectorized.svg rename to assets/projects/allergy-wheel/brand/curious girl_vectorized.svg diff --git a/assets/allergy/spinning-wheel.svg b/assets/projects/allergy-wheel/brand/spinning-wheel.svg similarity index 100% rename from assets/allergy/spinning-wheel.svg rename to assets/projects/allergy-wheel/brand/spinning-wheel.svg diff --git a/assets/allergy/sunny girl.png b/assets/projects/allergy-wheel/brand/sunny girl.png similarity index 100% rename from assets/allergy/sunny girl.png rename to assets/projects/allergy-wheel/brand/sunny girl.png diff --git a/assets/allergy/sunny girl.xcf b/assets/projects/allergy-wheel/brand/sunny girl.xcf similarity index 100% rename from assets/allergy/sunny girl.xcf rename to assets/projects/allergy-wheel/brand/sunny girl.xcf diff --git a/assets/allergy/sunny girl_vectorized.svg b/assets/projects/allergy-wheel/brand/sunny girl_vectorized.svg similarity index 100% rename from assets/allergy/sunny girl_vectorized.svg rename to assets/projects/allergy-wheel/brand/sunny girl_vectorized.svg diff --git a/assets/allergy/sunny_girl_full.png b/assets/projects/allergy-wheel/brand/sunny_girl_full.png similarity index 100% rename from assets/allergy/sunny_girl_full.png rename to assets/projects/allergy-wheel/brand/sunny_girl_full.png diff --git a/assets/allergy/tricerotops.png b/assets/projects/allergy-wheel/brand/tricerotops.png similarity index 100% rename from assets/allergy/tricerotops.png rename to assets/projects/allergy-wheel/brand/tricerotops.png diff --git a/assets/allergy_wheel.svg b/assets/projects/allergy-wheel/icon.svg similarity index 100% rename from assets/allergy_wheel.svg rename to assets/projects/allergy-wheel/icon.svg diff --git a/assets/city_finder.svg b/assets/projects/city-finder/icon.svg similarity index 100% rename from assets/city_finder.svg rename to assets/projects/city-finder/icon.svg diff --git a/assets/countdown/Calendar Icon with Checkmark on Blue.png b/assets/projects/countdown/brand/Calendar Icon with Checkmark on Blue.png similarity index 100% rename from assets/countdown/Calendar Icon with Checkmark on Blue.png rename to assets/projects/countdown/brand/Calendar Icon with Checkmark on Blue.png diff --git a/assets/countdown_calendar.svg b/assets/projects/countdown/icon.svg similarity index 100% rename from assets/countdown_calendar.svg rename to assets/projects/countdown/icon.svg diff --git a/assets/projects/ctx/brand/icon-source.png b/assets/projects/ctx/brand/icon-source.png new file mode 100644 index 0000000..a59308e Binary files /dev/null and b/assets/projects/ctx/brand/icon-source.png differ diff --git a/assets/projects/ctx/icon.png b/assets/projects/ctx/icon.png new file mode 100644 index 0000000..a02d1bc Binary files /dev/null and b/assets/projects/ctx/icon.png differ diff --git a/assets/projects/ets/icon.svg b/assets/projects/ets/icon.svg new file mode 100644 index 0000000..3177af0 --- /dev/null +++ b/assets/projects/ets/icon.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/assets/projects/ghttp/brand/icon-source.png b/assets/projects/ghttp/brand/icon-source.png new file mode 100644 index 0000000..a59308e Binary files /dev/null and b/assets/projects/ghttp/brand/icon-source.png differ diff --git a/assets/projects/ghttp/icon.png b/assets/projects/ghttp/icon.png new file mode 100644 index 0000000..a02d1bc Binary files /dev/null and b/assets/projects/ghttp/icon.png differ diff --git a/assets/projects/gix/brand/icon-source.png b/assets/projects/gix/brand/icon-source.png new file mode 100644 index 0000000..a59308e Binary files /dev/null and b/assets/projects/gix/brand/icon-source.png differ diff --git a/assets/projects/gix/icon.png b/assets/projects/gix/icon.png new file mode 100644 index 0000000..a02d1bc Binary files /dev/null and b/assets/projects/gix/icon.png differ diff --git a/assets/gravity/favicon64_final.png b/assets/projects/gravity-notes/brand/favicon64_final.png similarity index 100% rename from assets/gravity/favicon64_final.png rename to assets/projects/gravity-notes/brand/favicon64_final.png diff --git a/assets/projects/gravity-notes/brand/icon-32.png b/assets/projects/gravity-notes/brand/icon-32.png new file mode 100644 index 0000000..063f1d8 Binary files /dev/null and b/assets/projects/gravity-notes/brand/icon-32.png differ diff --git a/assets/projects/gravity-notes/brand/turquoise_bg_diag_64.png b/assets/projects/gravity-notes/brand/turquoise_bg_diag_64.png new file mode 100644 index 0000000..c510bbd Binary files /dev/null and b/assets/projects/gravity-notes/brand/turquoise_bg_diag_64.png differ diff --git a/assets/projects/gravity-notes/brand/turquoise_bg_diag_match_64.png b/assets/projects/gravity-notes/brand/turquoise_bg_diag_match_64.png new file mode 100644 index 0000000..e7b8086 Binary files /dev/null and b/assets/projects/gravity-notes/brand/turquoise_bg_diag_match_64.png differ diff --git a/assets/projects/gravity-notes/icon.png b/assets/projects/gravity-notes/icon.png new file mode 100644 index 0000000..0e6ac55 Binary files /dev/null and b/assets/projects/gravity-notes/icon.png differ diff --git a/assets/projects/issues-md/brand/icon-source.png b/assets/projects/issues-md/brand/icon-source.png new file mode 100644 index 0000000..a59308e Binary files /dev/null and b/assets/projects/issues-md/brand/icon-source.png differ diff --git a/assets/projects/issues-md/icon.png b/assets/projects/issues-md/icon.png new file mode 100644 index 0000000..a02d1bc Binary files /dev/null and b/assets/projects/issues-md/icon.png differ diff --git a/assets/projects/ledger/brand/icon-source.png b/assets/projects/ledger/brand/icon-source.png new file mode 100644 index 0000000..a59308e Binary files /dev/null and b/assets/projects/ledger/brand/icon-source.png differ diff --git a/assets/projects/ledger/icon.png b/assets/projects/ledger/icon.png new file mode 100644 index 0000000..a02d1bc Binary files /dev/null and b/assets/projects/ledger/icon.png differ diff --git a/assets/llm_crossword.svg b/assets/projects/llm-crossword/icon.svg similarity index 100% rename from assets/llm_crossword.svg rename to assets/projects/llm-crossword/icon.svg diff --git a/assets/projects/loopaware/icon.svg b/assets/projects/loopaware/icon.svg new file mode 100644 index 0000000..a48af6f --- /dev/null +++ b/assets/projects/loopaware/icon.svg @@ -0,0 +1,30 @@ + + + + + + + diff --git a/assets/old_millionaire.svg b/assets/projects/old-millionaire/icon.svg similarity index 100% rename from assets/old_millionaire.svg rename to assets/projects/old-millionaire/icon.svg diff --git a/assets/projects/photolab/icon.svg b/assets/projects/photolab/icon.svg new file mode 100644 index 0000000..78b159a --- /dev/null +++ b/assets/projects/photolab/icon.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/assets/projects/pinguin/brand/ChatGPT Image Nov 21, 2025, 11_54_19 PM.png b/assets/projects/pinguin/brand/ChatGPT Image Nov 21, 2025, 11_54_19 PM.png new file mode 100644 index 0000000..fae1972 Binary files /dev/null and b/assets/projects/pinguin/brand/ChatGPT Image Nov 21, 2025, 11_54_19 PM.png differ diff --git a/assets/projects/pinguin/brand/Gemini_Generated_Image_4mjlzi4mjlzi4mjl.png b/assets/projects/pinguin/brand/Gemini_Generated_Image_4mjlzi4mjlzi4mjl.png new file mode 100644 index 0000000..94639be Binary files /dev/null and b/assets/projects/pinguin/brand/Gemini_Generated_Image_4mjlzi4mjlzi4mjl.png differ diff --git a/assets/projects/pinguin/brand/favicon(1).ico b/assets/projects/pinguin/brand/favicon(1).ico new file mode 100644 index 0000000..8a2dd15 Binary files /dev/null and b/assets/projects/pinguin/brand/favicon(1).ico differ diff --git a/assets/projects/pinguin/brand/favicon-16x16.png b/assets/projects/pinguin/brand/favicon-16x16.png new file mode 100644 index 0000000..2fabe05 Binary files /dev/null and b/assets/projects/pinguin/brand/favicon-16x16.png differ diff --git a/assets/projects/pinguin/brand/favicon-32x32.png b/assets/projects/pinguin/brand/favicon-32x32.png new file mode 100644 index 0000000..aee020d Binary files /dev/null and b/assets/projects/pinguin/brand/favicon-32x32.png differ diff --git a/assets/projects/pinguin/brand/favicon.svg b/assets/projects/pinguin/brand/favicon.svg new file mode 100644 index 0000000..db6423f --- /dev/null +++ b/assets/projects/pinguin/brand/favicon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/projects/pinguin/brand/favicon64_pinguin_turquoise.png b/assets/projects/pinguin/brand/favicon64_pinguin_turquoise.png new file mode 100644 index 0000000..cc97ddc Binary files /dev/null and b/assets/projects/pinguin/brand/favicon64_pinguin_turquoise.png differ diff --git a/assets/projects/pinguin/brand/favicon64_pinguin_turquoise_large.png b/assets/projects/pinguin/brand/favicon64_pinguin_turquoise_large.png new file mode 100644 index 0000000..a9b4d61 Binary files /dev/null and b/assets/projects/pinguin/brand/favicon64_pinguin_turquoise_large.png differ diff --git a/assets/projects/pinguin/icon.png b/assets/projects/pinguin/icon.png new file mode 100644 index 0000000..a9b4d61 Binary files /dev/null and b/assets/projects/pinguin/icon.png differ diff --git a/assets/projects/product-scanner/brand/poodle-scanner-logo.png b/assets/projects/product-scanner/brand/poodle-scanner-logo.png new file mode 100644 index 0000000..53f41c6 Binary files /dev/null and b/assets/projects/product-scanner/brand/poodle-scanner-logo.png differ diff --git a/assets/projects/product-scanner/icon.png b/assets/projects/product-scanner/icon.png new file mode 100644 index 0000000..49ca858 Binary files /dev/null and b/assets/projects/product-scanner/icon.png differ diff --git a/assets/projects/prompt-bubbles/icon.svg b/assets/projects/prompt-bubbles/icon.svg new file mode 100644 index 0000000..e34fc9c --- /dev/null +++ b/assets/projects/prompt-bubbles/icon.svg @@ -0,0 +1,17 @@ + + Prompt Bubbles Icon + + + + + + + + + + + + + + + diff --git a/assets/projects/rsvp/brand/icon-source.png b/assets/projects/rsvp/brand/icon-source.png new file mode 100644 index 0000000..98dd839 Binary files /dev/null and b/assets/projects/rsvp/brand/icon-source.png differ diff --git a/assets/rsvp.svg b/assets/projects/rsvp/brand/logo.svg similarity index 100% rename from assets/rsvp.svg rename to assets/projects/rsvp/brand/logo.svg diff --git a/assets/projects/rsvp/icon.png b/assets/projects/rsvp/icon.png new file mode 100644 index 0000000..74542d2 Binary files /dev/null and b/assets/projects/rsvp/icon.png differ diff --git a/assets/projects/sheet2tube/icon.svg b/assets/projects/sheet2tube/icon.svg new file mode 100644 index 0000000..97eee48 --- /dev/null +++ b/assets/projects/sheet2tube/icon.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + diff --git a/assets/social_threader/favicon.svg b/assets/projects/social-threader/brand/favicon.svg similarity index 100% rename from assets/social_threader/favicon.svg rename to assets/projects/social-threader/brand/favicon.svg diff --git a/assets/social_threader.svg b/assets/projects/social-threader/icon.svg similarity index 100% rename from assets/social_threader.svg rename to assets/projects/social-threader/icon.svg diff --git a/assets/projects/tauth/icon.svg b/assets/projects/tauth/icon.svg new file mode 100644 index 0000000..ff89303 --- /dev/null +++ b/assets/projects/tauth/icon.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/assets/marko_polo_portrait.jpg b/assets/site/brand/marco-polo/marko_polo_portrait.jpg similarity index 100% rename from assets/marko_polo_portrait.jpg rename to assets/site/brand/marco-polo/marko_polo_portrait.jpg diff --git a/assets/marko_polo_portrait.svg b/assets/site/brand/marco-polo/marko_polo_portrait.svg similarity index 100% rename from assets/marko_polo_portrait.svg rename to assets/site/brand/marco-polo/marko_polo_portrait.svg diff --git a/assets/marcopolo/89F88663-2153-488C-AFF7-075941844FC2_1_201_a.jpeg b/assets/site/brand/marco-polo/reference/89F88663-2153-488C-AFF7-075941844FC2_1_201_a.jpeg similarity index 100% rename from assets/marcopolo/89F88663-2153-488C-AFF7-075941844FC2_1_201_a.jpeg rename to assets/site/brand/marco-polo/reference/89F88663-2153-488C-AFF7-075941844FC2_1_201_a.jpeg diff --git a/assets/marcopolo/8E6BA567-3D3A-44A6-917D-6BC9DFF45581_1_201_a.jpeg b/assets/site/brand/marco-polo/reference/8E6BA567-3D3A-44A6-917D-6BC9DFF45581_1_201_a.jpeg similarity index 100% rename from assets/marcopolo/8E6BA567-3D3A-44A6-917D-6BC9DFF45581_1_201_a.jpeg rename to assets/site/brand/marco-polo/reference/8E6BA567-3D3A-44A6-917D-6BC9DFF45581_1_201_a.jpeg diff --git a/assets/marcopolo/94B15A83-B12A-4E40-9308-A21679BB5283_1_201_a.jpeg b/assets/site/brand/marco-polo/reference/94B15A83-B12A-4E40-9308-A21679BB5283_1_201_a.jpeg similarity index 100% rename from assets/marcopolo/94B15A83-B12A-4E40-9308-A21679BB5283_1_201_a.jpeg rename to assets/site/brand/marco-polo/reference/94B15A83-B12A-4E40-9308-A21679BB5283_1_201_a.jpeg diff --git a/assets/marcopolo/favicon_marcopolo_outline64_new.png b/assets/site/brand/marco-polo/reference/favicon_marcopolo_outline64_new.png similarity index 100% rename from assets/marcopolo/favicon_marcopolo_outline64_new.png rename to assets/site/brand/marco-polo/reference/favicon_marcopolo_outline64_new.png diff --git a/assets/marcopolo/marco_polo_portrait.jpg b/assets/site/brand/marco-polo/reference/marco_polo_portrait.jpg similarity index 100% rename from assets/marcopolo/marco_polo_portrait.jpg rename to assets/site/brand/marco-polo/reference/marco_polo_portrait.jpg diff --git a/assets/marcopolo/marco_polo_portrait_outline.svg b/assets/site/brand/marco-polo/reference/marco_polo_portrait_outline.svg similarity index 100% rename from assets/marcopolo/marco_polo_portrait_outline.svg rename to assets/site/brand/marco-polo/reference/marco_polo_portrait_outline.svg diff --git a/assets/title.svg b/assets/site/brand/marco-polo/title.svg similarity index 100% rename from assets/title.svg rename to assets/site/brand/marco-polo/title.svg diff --git a/assets/site/favicons/HEAD-snippet.html b/assets/site/favicons/HEAD-snippet.html new file mode 100644 index 0000000..1b2ff1f --- /dev/null +++ b/assets/site/favicons/HEAD-snippet.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/site/favicons/android-chrome-192x192.png b/assets/site/favicons/android-chrome-192x192.png new file mode 100644 index 0000000..f058398 Binary files /dev/null and b/assets/site/favicons/android-chrome-192x192.png differ diff --git a/assets/site/favicons/android-chrome-512x512.png b/assets/site/favicons/android-chrome-512x512.png new file mode 100644 index 0000000..7b5f505 Binary files /dev/null and b/assets/site/favicons/android-chrome-512x512.png differ diff --git a/assets/site/favicons/apple-touch-icon.png b/assets/site/favicons/apple-touch-icon.png new file mode 100644 index 0000000..3151e52 Binary files /dev/null and b/assets/site/favicons/apple-touch-icon.png differ diff --git a/assets/site/favicons/favicon-16x16.png b/assets/site/favicons/favicon-16x16.png new file mode 100644 index 0000000..2fabe05 Binary files /dev/null and b/assets/site/favicons/favicon-16x16.png differ diff --git a/assets/site/favicons/favicon-32x32.png b/assets/site/favicons/favicon-32x32.png new file mode 100644 index 0000000..fd53b36 Binary files /dev/null and b/assets/site/favicons/favicon-32x32.png differ diff --git a/assets/site/favicons/favicon.ico b/assets/site/favicons/favicon.ico new file mode 100644 index 0000000..4f7fc36 Binary files /dev/null and b/assets/site/favicons/favicon.ico differ diff --git a/assets/site/favicons/favicon.svg b/assets/site/favicons/favicon.svg new file mode 100644 index 0000000..db6423f --- /dev/null +++ b/assets/site/favicons/favicon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/site/favicons/safari-pinned-tab.svg b/assets/site/favicons/safari-pinned-tab.svg new file mode 100644 index 0000000..db6423f --- /dev/null +++ b/assets/site/favicons/safari-pinned-tab.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/site/favicons/site.webmanifest b/assets/site/favicons/site.webmanifest new file mode 100644 index 0000000..1e52fc8 --- /dev/null +++ b/assets/site/favicons/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Pinguin", + "short_name": "Pinguin", + "icons": [ + { + "src": "android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#0076c3", + "background_color": "#0076c3", + "display": "standalone" +} diff --git a/assets/GreatVibes-Regular.ttf b/assets/site/fonts/GreatVibes-Regular.ttf similarity index 100% rename from assets/GreatVibes-Regular.ttf rename to assets/site/fonts/GreatVibes-Regular.ttf diff --git a/assets/hero-loop.mp4 b/assets/site/hero/hero-loop.mp4 similarity index 100% rename from assets/hero-loop.mp4 rename to assets/site/hero/hero-loop.mp4 diff --git a/assets/hero-loop.webm b/assets/site/hero/hero-loop.webm similarity index 100% rename from assets/hero-loop.webm rename to assets/site/hero/hero-loop.webm diff --git a/assets/Generated Image September 25, 2025 - 4_19PM.jpeg b/assets/site/imagery/Generated Image September 25, 2025 - 4_19PM.jpeg similarity index 100% rename from assets/Generated Image September 25, 2025 - 4_19PM.jpeg rename to assets/site/imagery/Generated Image September 25, 2025 - 4_19PM.jpeg diff --git a/assets/turquoise_golden_16x9.png b/assets/site/imagery/turquoise_golden_16x9.png similarity index 100% rename from assets/turquoise_golden_16x9.png rename to assets/site/imagery/turquoise_golden_16x9.png diff --git a/data/projects.json b/data/projects.json new file mode 100644 index 0000000..da7ce50 --- /dev/null +++ b/data/projects.json @@ -0,0 +1,225 @@ +{ + "projects": [ + { + "id": "issues-md", + "name": "ISSUES.md", + "description": "Append-only lab worklog that tracks features, improvements, and maintenance activity across Marco Polo Research Lab projects.", + "status": "WIP", + "category": "Research", + "repo": "github.com/MarcoPoloResearchLab/marcopolo.github.io", + "app": "https://github.com/MarcoPoloResearchLab/marcopolo.github.io/blob/main/ISSUES.md", + "docs": "https://github.com/MarcoPoloResearchLab/marcopolo.github.io/blob/main/ISSUES.md", + "launchEnabled": false, + "docsEnabled": false, + "subscribeEnabled": false, + "icon": "assets/projects/issues-md/icon.png" + }, + { + "id": "photolab", + "name": "Photolab", + "description": "Local photo library classifier and search UI that writes high-confidence labels into EXIF, indexes metadata into SQLite, and serves a minimal browser-based search grid.", + "status": "WIP", + "category": "Research", + "repo": null, + "app": null, + "docs": null, + "launchEnabled": false, + "docsEnabled": false, + "subscribeEnabled": false, + "icon": "assets/projects/photolab/icon.svg" + }, + { + "id": "ctx", + "name": "ctx", + "description": "Terminal-first project explorer for browsing trees, reading files with embedded docs, analysing call chains, and fetching upstream docs from GitHub via one CLI.", + "status": "Production", + "category": "Tools", + "repo": "github.com/tyemirov/ctx", + "app": "https://ctx.mprlab.com", + "docs": "https://github.com/tyemirov/ctx#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/ctx/icon.png" + }, + { + "id": "gix", + "name": "gix", + "description": "Git and GitHub maintenance CLI for keeping large fleets of repositories healthy by normalising folder names, aligning remotes, and automating audit/release workflows.", + "status": "Production", + "category": "Tools", + "repo": "github.com/tyemirov/gix", + "app": "https://gix.mprlab.com", + "docs": "https://github.com/tyemirov/gix#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/gix/icon.png" + }, + { + "id": "ghttp", + "name": "gHTTP", + "description": "Go-powered static file server that mirrors python -m http.server while adding Markdown rendering, structured logging, and easy HTTPS provisioning for local work or containers.", + "status": "Production", + "category": "Tools", + "repo": "github.com/temirov/ghttp", + "app": "https://github.com/temirov/ghttp", + "docs": "https://github.com/temirov/ghttp#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/ghttp/icon.png" + }, + { + "id": "loopaware", + "name": "LoopAware", + "description": "Customer feedback platform with an embeddable widget, Google-authenticated dashboard, and APIs for collecting, triaging, and responding to product messages.", + "status": "Production", + "category": "Platform", + "repo": "github.com/tyemirov/loopaware", + "app": "https://loopaware.mprlab.com", + "docs": "https://github.com/tyemirov/loopaware#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": true, + "icon": "assets/projects/loopaware/icon.svg", + "subscribe": { + "script": "https://loopaware.mprlab.com/subscribe.js?site_id=a3222433-92ec-473a-9255-0797226c2273&mode=inline&accent=%23ffd369&cta=Subscribe&success=Thanks%20for%20subscribing&name_field=false", + "title": "Get LoopAware release updates", + "copy": "Drop your email to hear when LoopAware ships fresh drops, integrations, and subscriber tooling." + } + }, + { + "id": "pinguin", + "name": "Pinguin", + "description": "Production-ready notification service that exposes a gRPC API for email and SMS, persists jobs in SQLite, and retries failures with an exponential-backoff scheduler.", + "status": "Production", + "category": "Platform", + "repo": "github.com/temirov/pinguin", + "app": "https://github.com/temirov/pinguin", + "docs": "https://github.com/temirov/pinguin#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/pinguin/icon.png" + }, + { + "id": "ets", + "name": "Ephemeral Token Service (ETS)", + "description": "JWT + DPoP gateway that mints short-lived, browser-bound access tokens and reverse-proxies requests so front-end apps never handle provider secrets directly.", + "status": "Beta", + "category": "Platform", + "repo": "github.com/tyemirov/ETS", + "app": "https://ets.mprlab.com", + "docs": "https://github.com/tyemirov/ETS#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/ets/icon.svg" + }, + { + "id": "tauth", + "name": "TAuth", + "description": "Google Sign-In and session service that verifies ID tokens, issues short-lived JWT cookies, and ships a tiny auth-client.js helper for same-origin apps.", + "status": "Production", + "category": "Platform", + "repo": "github.com/tyemirov/TAuth", + "app": "https://tauth.mprlab.com", + "docs": "https://github.com/tyemirov/TAuth#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/tauth/icon.svg" + }, + { + "id": "ledger", + "name": "Ledger Service", + "description": "Standalone gRPC-based virtual credits ledger that tracks grants, reservations, captures, and releases in an append-only store backed by SQL with full auditability.", + "status": "Beta", + "category": "Platform", + "repo": "github.com/tyemirov/ledger", + "app": "https://github.com/tyemirov/ledger", + "docs": "https://github.com/tyemirov/ledger#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/ledger/icon.png" + }, + { + "id": "product-scanner", + "name": "Poodle Scanner", + "description": "AI-assisted storefront auditor nicknamed “Poodle” that sniffs out PDP gaps, evaluates results against configurable rule packs, and reports issues through a CLI and authenticated dashboard.", + "status": "Beta", + "category": "Products", + "repo": "github.com/MarcoPoloResearchLab/ProductScanner", + "app": "https://ps.mprlab.com", + "docs": "https://github.com/MarcoPoloResearchLab/ProductScanner#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/product-scanner/icon.png" + }, + { + "id": "sheet2tube", + "name": "Sheet2Tube", + "description": "CSV and web toolkit that round-trips YouTube channel metadata between spreadsheets and your account plus a GPT-powered helper for expanding scripted placeholders.", + "status": "Beta", + "category": "Products", + "repo": "github.com/MarcoPoloResearchLab/Sheet2Tube", + "app": "https://sheet2tube.mprlab.com", + "docs": "https://github.com/MarcoPoloResearchLab/Sheet2Tube#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/sheet2tube/icon.svg" + }, + { + "id": "gravity-notes", + "name": "Gravity Notes", + "description": "Single-page Markdown notebook with an inline card grid, offline-first storage, and Google-backed sync so ideas flow without modal dialogs or context switches.", + "status": "Production", + "category": "Products", + "repo": "github.com/MarcoPoloResearchLab/gravity", + "app": "https://gravity.mprlab.com", + "docs": "https://github.com/MarcoPoloResearchLab/gravity#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": true, + "icon": "assets/projects/gravity-notes/icon.png", + "subscribe": { + "script": "https://loopaware.mprlab.com/subscribe.js?site_id=d8c3d1c8-7968-43d0-8026-ee827ada7666&mode=inline&accent=%23ffd369&cta=Subscribe&success=Thanks%20for%20subscribing&name_field=false", + "title": "Get Gravity Notes release updates", + "copy": "Drop your email to hear when Gravity Notes ships fresh features, AI integrations, and new plugins.", + "height": 320 + } + }, + { + "id": "rsvp", + "name": "RSVP", + "description": "Event invitation platform that generates QR-code-powered invites, tracks responses, and supports both local and production TLS setups for secure guest flows.", + "status": "Production", + "category": "Products", + "repo": "github.com/MarcoPoloResearchLab/RSVP", + "app": "https://rsvp.mprlab.com", + "docs": "https://github.com/MarcoPoloResearchLab/RSVP#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/rsvp/icon.png" + }, + { + "id": "prompt-bubbles", + "name": "Prompt Bubbles", + "description": "Browser-first prompt library with inline editing, deep-linkable cards, local likes, and a Bootstrap/Alpine interface tuned for fast search and keyboard-friendly navigation.", + "status": "Production", + "category": "Products", + "repo": "github.com/MarcoPoloResearchLab/prompts", + "app": "https://prompts.mprlab.com", + "docs": "https://github.com/MarcoPoloResearchLab/prompts#readme", + "launchEnabled": true, + "docsEnabled": true, + "subscribeEnabled": false, + "icon": "assets/projects/prompt-bubbles/icon.svg" + } + ] +} diff --git a/data/projects.yml b/data/projects.yml deleted file mode 100644 index 46e90b9..0000000 --- a/data/projects.yml +++ /dev/null @@ -1,182 +0,0 @@ -projects: - - id: issues-md - repo: github.com/MarcoPoloResearchLab/marcopolo.github.io - display_name: "ISSUES.md" - urls: - app: https://github.com/MarcoPoloResearchLab/marcopolo.github.io/blob/main/ISSUES.md - docs: https://github.com/MarcoPoloResearchLab/marcopolo.github.io/blob/main/ISSUES.md - github: https://github.com/MarcoPoloResearchLab/marcopolo.github.io - public: true # or false for “not yet public” - category: Research # Research | Tools | Platform | Products - status: WIP # WIP | Beta | Production - description: > - Append-only lab worklog that tracks features, improvements, and maintenance activity across Marco Polo Research Lab projects. - - - id: photolab - repo: - display_name: "Photolab" - urls: - app: - docs: - github: - public: false # or false for “not yet public” - category: Research - status: WIP - description: > - Local photo library classifier and search UI that scans image folders, writes high-confidence labels into EXIF, indexes metadata into SQLite, and serves a minimal browser-based search grid. - - - id: ctx - repo: github.com/tyemirov/ctx - display_name: "ctx" - urls: - app: https://github.com/tyemirov/ctx - docs: https://github.com/tyemirov/ctx#readme - github: https://github.com/tyemirov/ctx - public: true - category: Tools - status: Production - description: > - Terminal-first project explorer for browsing trees, reading files with optional embedded documentation, analysing call chains, and fetching upstream docs from GitHub using one CLI. - - - id: gix - repo: github.com/tyemirov/gix - display_name: "gix" - urls: - app: https://github.com/tyemirov/gix - docs: https://github.com/tyemirov/gix#readme - github: https://github.com/tyemirov/gix - public: true - category: Tools - status: Production - description: > - Git and GitHub maintenance CLI for keeping large fleets of repositories healthy by normalising folder names, aligning remotes, pruning stale branches, and automating audit and release workflows. - - - id: ghttp - repo: github.com/temirov/ghttp - display_name: "gHTTP" - urls: - app: https://github.com/temirov/ghttp - docs: https://github.com/temirov/ghttp#readme - github: https://github.com/temirov/ghttp - public: true - category: Tools - status: Production - description: > - Go-powered static file server that mirrors python -m http.server while adding Markdown rendering, structured logging, and easy HTTPS provisioning for local or containerised environments. - - - id: loopaware - repo: github.com/tyemirov/loopaware - display_name: "LoopAware" - urls: - app: https://loopaware.mprlab.com - docs: https://github.com/tyemirov/loopaware#readme - github: https://github.com/tyemirov/loopaware - public: true - category: Platform - status: Production - description: > - Customer feedback platform with an embeddable widget, Google-authenticated dashboard, and APIs for collecting, triaging, and responding to messages across sites. - - - id: pinguin - repo: github.com/temirov/pinguin - display_name: "Pinguin" - urls: - app: https://github.com/temirov/pinguin - docs: https://github.com/temirov/pinguin#readme - github: https://github.com/temirov/pinguin - public: true - category: Platform - status: Production - description: > - Production-quality notification service that exposes a gRPC API for email and SMS, persists jobs in SQLite, and retries failures with an exponential-backoff scheduler and structured logging. - - - id: ets - repo: github.com/tyemirov/ETS - display_name: "Ephemeral Token Service (ETS)" - urls: - app: https://ets.mprlab.com - docs: https://github.com/tyemirov/ETS#readme - github: https://github.com/tyemirov/ETS - public: true - category: Platform - status: Beta - description: > - JWT + DPoP gateway that mints short-lived, browser-bound access tokens and reverse-proxies requests to upstream APIs so front-end apps never handle provider secrets directly. - - - id: tauth - repo: github.com/tyemirov/TAuth - display_name: "TAuth" - urls: - app: https://tauth.mprlab.com - docs: https://github.com/tyemirov/TAuth#readme - github: https://github.com/tyemirov/TAuth - public: true - category: Platform - status: Production - description: > - Google Sign-In and session service that verifies ID tokens, issues short-lived JWT cookies, and ships a tiny auth-client.js helper so single-origin apps avoid storing tokens in JavaScript. - - - id: ledger - repo: github.com/tyemirov/ledger - display_name: "Ledger Service" - urls: - app: https://github.com/tyemirov/ledger - docs: https://github.com/tyemirov/ledger#readme - github: https://github.com/tyemirov/ledger - public: true - category: Platform - status: Beta - description: > - Standalone gRPC-based virtual credits ledger that tracks grants, reservations, captures, and releases in an append-only store backed by SQL with full auditability and idempotency. - - - id: product-scanner - repo: github.com/MarcoPoloResearchLab/ProductScanner - display_name: "Product Scanner" - urls: - app: https://ps.mprlab.com - docs: https://github.com/MarcoPoloResearchLab/ProductScanner#readme - github: https://github.com/MarcoPoloResearchLab/ProductScanner - public: true - category: Products - status: Beta - description: > - Product detail page auditor that crawls listings, evaluates them against configurable rule packs, and reports gaps through a CLI and authenticated web dashboard. - - - id: sheet2tube - repo: github.com/MarcoPoloResearchLab/Sheet2Tube - display_name: "Sheet2Tube" - urls: - app: https://sheet2tube.mprlab.com - docs: https://github.com/MarcoPoloResearchLab/Sheet2Tube#readme - github: https://github.com/MarcoPoloResearchLab/Sheet2Tube - public: true - category: Products - status: Beta - description: > - CSV and web toolkit that round-trips YouTube channel metadata between spreadsheets and your account while also offering a GPT-powered helper for expanding GPT(…) placeholders in CSV files. - - - id: gravity-notes - repo: github.com/MarcoPoloResearchLab/gravity - display_name: "Gravity Notes" - urls: - app: https://gravity.mprlab.com - docs: https://github.com/MarcoPoloResearchLab/gravity#readme - github: https://github.com/MarcoPoloResearchLab/gravity - public: true - category: Products - status: Production - description: > - Single-page Markdown notebook with an inline card grid, offline-first storage, and Google-backed sync designed to keep ideas flowing without modal dialogs or context switches. - - - id: rsvp - repo: github.com/MarcoPoloResearchLab/RSVP - display_name: "RSVP" - urls: - app: https://rsvp.mprlab.com - docs: https://github.com/MarcoPoloResearchLab/RSVP#readme - github: https://github.com/MarcoPoloResearchLab/RSVP - public: true - category: Products - status: Production - description: > - Event invitation platform that generates QR-code-powered invites, tracks responses, and supports both local and production TLS setups for secure guest flows. diff --git a/docker-compose.yml b/docker-compose.yml index 08235a6..27b8f59 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: site: - image: ghcr.io/temirov/ghttp:latest + image: ghcr.io/tyemirov/ghttp:latest container_name: mprlab-site restart: unless-stopped env_file: diff --git a/docs/assets-report.md b/docs/assets-report.md new file mode 100644 index 0000000..4257fa5 --- /dev/null +++ b/docs/assets-report.md @@ -0,0 +1,44 @@ +## Asset Inventory (generated 2025-02-14) + +### Project card icons (logos) + +All raster logos have been normalized to **64×64**; SVG icons remain vector-based. + +| Project | Path | Format | Size (KB) | Dimensions | Notes | +| --- | --- | --- | --- | --- | --- | +| allergy-wheel | `assets/projects/allergy-wheel/icon.svg` | SVG | 29.4 | vector | Inline gradient illustration. | +| city-finder | `assets/projects/city-finder/icon.svg` | SVG | 37.5 | vector | SVG skyline. | +| countdown | `assets/projects/countdown/icon.svg` | SVG | 35.8 | vector | SVG calendar. | +| ctx | `assets/projects/ctx/icon.png` | PNG | 17.1 | 64×64 | Upscaled from the original 32px favicon; original lives in `brand/icon-source.png`. | +| ets | `assets/projects/ets/icon.svg` | SVG | 0.8 | vector | Minimal SVG lock. | +| ghttp | `assets/projects/ghttp/icon.png` | PNG | 17.1 | 64×64 | Upscaled from the 32px favicon; source retained in `brand/`. | +| gix | `assets/projects/gix/icon.png` | PNG | 17.1 | 64×64 | Upscaled from the 32px favicon; source retained in `brand/`. | +| gravity-notes | `assets/projects/gravity-notes/icon.png` | PNG | 4.5 | 64×64 | Uses existing 64px turquoise badge. | +| issues-md | `assets/projects/issues-md/icon.png` | PNG | 17.1 | 64×64 | Upscaled from the 32px favicon; source retained in `brand/`. | +| ledger | `assets/projects/ledger/icon.png` | PNG | 17.1 | 64×64 | Upscaled from the 32px favicon; source retained in `brand/`. | +| llm-crossword | `assets/projects/llm-crossword/icon.svg` | SVG | 33.9 | vector | SVG crossword grid. | +| loopaware | `assets/projects/loopaware/icon.svg` | SVG | 0.7 | vector | Minimal SVG arcs. | +| old-millionaire | `assets/projects/old-millionaire/icon.svg` | SVG | 30.5 | vector | SVG portrait. | +| photolab | `assets/projects/photolab/icon.svg` | SVG | 0.8 | vector | SVG aperture. | +| pinguin | `assets/projects/pinguin/icon.png` | PNG | 6.3 | 64×64 | Native 64px logo. | +| product-scanner | `assets/projects/product-scanner/icon.png` | PNG | 6.7 | 64×64 | Downscaled from 2048px “Poodle” artwork; master copy parked in `brand/poodle-scanner-logo.png`. | +| rsvp | `assets/projects/rsvp/icon.png` | PNG | 4.4 | 64×64 | Upscaled from 32px source; source retained in `brand/`. | +| sheet2tube | `assets/projects/sheet2tube/icon.svg` | SVG | 0.7 | vector | SVG sheet icon. | +| social-threader | `assets/projects/social-threader/icon.svg` | SVG | 29.0 | vector | SVG weave. | +| tauth | `assets/projects/tauth/icon.svg` | SVG | 0.6 | vector | SVG badge. | + +### Notable raster assets (reference/brand only) + +| Path | Size (KB) | Dimensions | Notes | +| --- | --- | --- | --- | +| `assets/projects/product-scanner/brand/poodle-scanner-logo.png` | 4206 | 2048×2080 | Canonical artwork for future exports. | +| `assets/projects/pinguin/brand/Gemini_Generated_Image_4mjlzi4mjlzi4mjl.png` | 4286 | 1920×2208 | Key art for marketing; not served on landing page. | +| `assets/projects/countdown/brand/Calendar Icon with Checkmark on Blue.png` | 1117 | 1024×1024 | Poster-style source. | +| `assets/projects/allergy-wheel/brand/*.png` | 180–1000 | 544–1120 | Character renders for future assets. | +| `assets/site/imagery/turquoise_golden_16x9.png` | 6.4 | 1600×900 | Background/wallpaper asset. | + +### Takeaways + +- Every PNG logo in `assets/projects/*/icon.png` is now 64×64, which matches how cards render them and keeps payloads predictable (~4–17 KB each). +- Original 32px favicons and oversized illustrations have been preserved under each project’s `brand/` folder so we can re-export higher fidelity versions later without digging through git history. +- SVG icons already scale without intervention; no changes were needed there. Large reference art stays sandboxed in `brand/` so it never bloats the production bundle. diff --git a/index.html b/index.html index b96340c..5201dd5 100644 --- a/index.html +++ b/index.html @@ -23,17 +23,36 @@ href="https://cdn.jsdelivr.net/gh/MarcoPoloResearchLab/mpr-ui@latest/mpr-ui.css" /> + + + + + + + Marco Polo Research Lab @@ -57,209 +76,102 @@ -
-
- - -
+ Toggle sound + + + + -
-

Marco Polo Research Lab

+
+

Marco Polo Research Lab

-

The new platform you can stand on.

+

The new platform you can stand on.

- -
-
- - -
- -
-

Our Mission

-

- At Marco Polo Research Lab, we build exceptional products that are - simple, reliable, and help people get things done. We create - intuitive, productive tools, avoiding unnecessary complexity. We - listen to user feedback and never stop tweaking and tuning. -

+ - -
-

Discoveries & Creations

-
-
-
- -
-
-

Social Threader

-

- A web-based tool that intelligently breaks long text into - smaller chunks for social media platforms. -

- Launch App -
-
-
-
- -
-
-

Countdown Calendar

-

A sleek calendar tool that counts down to designated dates.

- Launch App -
-
-
-
- -
-
-

Nearest City Finder

-

- CLI and web application that finds the closest city by driving - distance. -

- View on GitHub -
-
-
-
- -
-
-

RSVP

-

- An events invitation platform that relies on physical QR Codes - and allows printing, sending, and tracking invitations to - events. -

- Launch App -
+ +
+ +
+
+

Research

-
-
- -
-
-

LLM Crossword

-

- Dynamically built crosswords. Enter the topic and get a - crossword created just for you. -

- Launch App -
-
-
-
- -
-
-

Old Millionaire

-

- How much money you’d need **today** to match the purchasing - power of \$1,000,000 in your birth year. -

- Launch App -
+
+
+ + + +
+
+

Tools

-
-
- -
-
-

Allergy Wheel

-

- Interactive allergy-learning game where kids pick food - allergens, spin the wheel to win hearts, and discover dishes - that match their choices. -

- Launch App -
+
+
+ + + +
+
+

Platform

+
-
+ - -
-

Chart Your Course With Us

-

- Ready to embark on your next project or have a question? Reach out and - let's explore the possibilities. -

-

Email: contact@mprlab.com

-
-
+ +
+
+

Products

+
+
+
+
+ { + await page.goto("/index.html"); + + for (const project of catalog.projects) { + const card = page + .locator(".project-card") + .filter({has: page.getByRole("heading", {name: project.name})}); + + await expect(card).toContainText(project.description); + await expect(card.locator(".status-badge").first()).toHaveText(project.status); + + const action = card.locator("a.card-action").first(); + const expectLaunchVisible = + project.status !== "WIP" && + Boolean(project.app) && + (project.launchEnabled !== false); + + await expect(action).toHaveCount(expectLaunchVisible ? 1 : 0); + if (expectLaunchVisible) { + await expect(action).toHaveAttribute("href", project.app); + } + } + }); + + test("beta and WIP cards flip while production cards remain static", async ({page}) => { + await page.goto("/index.html"); + + for (const project of catalog.projects) { + const card = page + .locator(".project-card") + .filter({has: page.getByRole("heading", {name: project.name})}); + + await expect(card).toBeVisible(); + + const initialClasses = await card.getAttribute("class"); + expect(initialClasses || "").not.toMatch(/is-flipped/); + + const badge = card.locator(".status-badge").first(); + await badge.click(); + + const classesAfterClick = await card.getAttribute("class"); + + const shouldFlip = + project.status === "Beta" || + project.status === "WIP" || + Boolean(project.subscribe); + + if (shouldFlip) { + expect(classesAfterClick || "").toMatch(/is-flipped/); + + await badge.click(); + const classesAfterSecondClick = await card.getAttribute("class"); + expect(classesAfterSecondClick || "").not.toMatch(/is-flipped/); + } else { + expect(classesAfterClick || "").not.toMatch(/is-flipped/); + } + } + }); + test("footer respects non-sticky configuration", async ({page}) => { await page.goto("/index.html"); @@ -58,4 +124,109 @@ test.describe("Marco Polo Research Lab landing page", () => { expect(topAtTop).toBeGreaterThan(viewportHeight); expect(topAtBottom).toBeLessThanOrEqual(viewportHeight); }); + + test("footer adheres to the site color palette", async ({page}) => { + await page.goto("/index.html"); + + const footerRoot = page.locator('mpr-footer footer[data-mpr-footer="root"]'); + await expect(footerRoot).toBeVisible(); + + const palette = await page.evaluate(() => { + const footer = document.querySelector("mpr-footer footer[data-mpr-footer='root']"); + const host = document.querySelector("mpr-footer"); + if (!footer) { + throw new Error("Footer root not found"); + } + if (!host) { + throw new Error("Footer host not found"); + } + + const hexToRgb = value => { + const trimmed = value.trim(); + if (!trimmed) return ""; + if (trimmed.startsWith("rgb")) return trimmed; + const hex = trimmed.replace("#", ""); + const normalized = hex.length === 3 ? hex.split("").map(char => char + char).join("") : hex; + const num = parseInt(normalized, 16); + const r = (num >> 16) & 255; + const g = (num >> 8) & 255; + const b = num & 255; + return `rgb(${r}, ${g}, ${b})`; + }; + + const documentStyles = window.getComputedStyle(document.documentElement); + const footerStyles = window.getComputedStyle(footer); + const hostStyles = window.getComputedStyle(host); + + const expectedBackground = hexToRgb(documentStyles.getPropertyValue("--bg-panel")); + const expectedText = hexToRgb(documentStyles.getPropertyValue("--text-gold-strong")); + const expectedAccent = documentStyles.getPropertyValue("--accent-gold").trim(); + const expectedBorder = documentStyles.getPropertyValue("--accent-outline").trim(); + + return { + expectedBackground, + actualBackground: footerStyles.backgroundColor, + expectedText, + actualText: footerStyles.color, + expectedAccent, + hostAccent: hostStyles.getPropertyValue("--mpr-color-accent").trim(), + expectedBorder, + hostBorder: hostStyles.getPropertyValue("--mpr-color-border").trim() + }; + }); + + expect(palette.actualBackground).toBe(palette.expectedBackground); + expect(palette.actualText).toBe(palette.expectedText); + expect(palette.hostAccent).toBe(palette.expectedAccent); + expect(palette.hostBorder).toBe(palette.expectedBorder); + }); + + test("subscribe-enabled cards render LoopAware forms after flipping", async ({page}) => { + const subscribeProjects = catalog.projects.filter( + project => + project.subscribe && + project.subscribe.script && + project.subscribeEnabled !== false, + ); + await page.goto("/index.html"); + + for (const project of subscribeProjects) { + const card = page + .locator(".project-card") + .filter({has: page.getByRole("heading", {name: project.name})}); + + const badge = card.locator(".status-badge").first(); + const overlay = card.locator(".project-card-subscribe-overlay"); + const iframeElement = card.locator(".subscribe-widget-frame"); + await expect(overlay).toHaveAttribute("data-subscribe-loaded", "false"); + await expect( + iframeElement, + `${project.name} iframe should be unfocusable before flip`, + ).toHaveAttribute("tabindex", "-1"); + + await badge.click(); + + const cardBack = card.locator(".project-card-face.project-card-back"); + const frame = cardBack.frameLocator(".subscribe-widget-frame"); + const loopAwareForm = frame.locator("#mp-subscribe-form"); + await expect(loopAwareForm, `${project.name} LoopAware form should render inside iframe`).toBeVisible(); + await expect(frame.locator("input[type='email']")).toBeVisible(); + await expect( + frame.locator("button"), + `${project.name} LoopAware widget should expose a CTA button`, + ).toContainText(/subscribe|notify/i); + + await expect(overlay).toHaveAttribute("data-subscribe-loaded", "true"); + await expect( + iframeElement, + `${project.name} iframe should be focusable after flip`, + ).toHaveAttribute("tabindex", "0"); + + await badge.click(); + await expect( + iframeElement, + `${project.name} iframe should be unfocusable after unflip`, + ).toHaveAttribute("tabindex", "-1"); + } + }); });