Matemarketing 2026 Programme — a static replica preview
Situation
A conference programme page is a Vue SPA: the data lives in an API and the layout in a bundle, so «make it the same» usually means «make it look similar»
Task
Take a third-party interface apart down to measurable quantities and rebuild it with no build step and no backend
Action
Pulled the programme from the public API, measured the grid on the rendered DOM, rebuilt it in plain HTML/CSS/JS, then ran four independent passes: code review, security audit, browser tests, visual audit
Result
The grid matches the original to the pixel: 99 px time column, 420 px hall column, 391 px card, 550 px row, grid top at y = 414; tests catch data and layout drift
Stack
HTMLCSSJavaScriptPython
Source View on GitHub → Updated: Nov 3, 2026
On this page
  1. Situation
  2. Task
  3. Actions
  4. Result
  5. Limitations
  6. Documentation

Matemarketing 2026 Programme — a static replica

▶ Live replica — runs on any static host, no build, no install. Code: NikitaBoyarkin/mm-program-page.

Situation

A conference programme page is a typical SPA: the HTML ships an empty <div id="app">, the programme arrives from an API and the browser draws it. You cannot copy such a page by saving the rendered markup — the saved file has neither the talks nor the grid. The usual answer to this task is «I made it look similar», and there is no way to check that claim.

Task

Take the interface apart into measurable quantities — column widths, insets, row height, type sizes — and rebuild it with no build step, no backend and no npm. More importantly, replace «looks similar» with something checkable: measurements, tests and an explicit list of deviations.

Actions

  1. Reconnaissance. Established that the page is a Vue app and the programme comes from GET /api/event-program/event/6/: 335 KB of JSON, 3 days, 91 talks, 11 tracks, 9 halls. Design tokens (borders #E5E7EB, grid surface #F9FAFB, brand #5C34F6) came from the visual config and the shipped CSS rather than from picking colours by eye.
  2. Data. tools/fetch_program.py downloads the payload, strips HTML from descriptions, falls back to the first paragraph when short_description is empty, and writes window.MM_PROGRAM. Modes: --fetch, --check (detects drift between snapshot and API) and --dry-run.
  3. Layout. An index.html skeleton plus curated CSS (an extract of the shipped CSS with data-v-* stripped and Vuetify internals dropped) and a dependency-free app.js: the time × hall grid, multi-slot cards, day tabs, 11 track chips, localStorage favourites, a modal with a focus trap, and per-day .ics export.
  4. Verification. Four independent passes: code review (15 findings, 2 high), security audit (0 blocking), browser tests in headless Chrome, and a visual audit with pixel measurements. The findings added URL validation for images, fallbacks for broken banners and avatars, .ics line folding, tab/ARIA wiring and a CSP.

Result

The grid is replicated by measurement, not by feel:

Metric (1440 px) Original Replica
Time column 99 px 99–100 px
Hall column 420 px 420 px
Card and radius 391 px, 16 391 px, 16
Banner 4:3, 291 px 4:3, 291 px
Row height 550 px 550 px
Grid top y = 414 y = 414
Heading (ink box) 638×22 650×22
Document height 6605 px 6589 px

Verification: tests/test_data.py — 9 tests, 2,370 data-invariant assertions; tests/test_page.py — 7 tests against real rendering (per-day counts, grid-area integrity, screenshots at 1440 and 390 px, graceful degradation without data). Both suites are mutation-checked: a broken counter, a shifted grid and an empty title each fail the matching test.

Limitations

  • No backend: no auth, no personal cabinet, no server-side favourites, no chat or player.
  • Images and the commercial heading typeface are not redistributed — they load from the original CDN. Because of CORS the original Loos Wide does not load, so the heading is drawn by the free Unbounded, fitted to the ink box (650×22 against 638×22).
  • The header counter shows the number of talks that day, not a fake «people online»: presence in a static page cannot be invented.
  • The data is a snapshot. python3 tools/fetch_program.py --check reports when the original programme changes.

Documentation

Need this reasoning applied to your data?

Tell me the task — I'll come back with a plan: what data it needs, what we test, and how long it takes. I reply within a day.

Discuss a task →