Personal site for Matthew Ginzburg. Quantitative Finance @ Stevens, class of 2028.
One page, laid out as a node graph: the intro, an "off the clock" hobbies panel, each project, awards, skills, and contact are nodes on a dot-grid canvas, wired together with jagged zigzag connectors that carry a travelling current. No framework, no build step, no dependencies.
python3 -m http.server 4321
Then open http://127.0.0.1:4321. Any static server works: npx serve,
php -S, etc. Opening index.html straight off the filesystem mostly works,
but file:// is not a secure context, so the copy-email button falls back
silently if the Clipboard API is unavailable. Use a server.
| Path | What it is |
|---|---|
index.html |
All content. Each node is a <section class="node" data-node>. |
css/site.css |
Design tokens (light + dark, both token sets on :root / [data-theme]) and layout. |
js/site.js |
Wire routing, scroll reveal, the left-hand rail, keyboard nav, theme persistence. |
js/hobbies.js |
The hobbies panel: ski skyline, Chelsea / Knicks plays, shared animation helpers. |
js/poker.js |
The poker table in the hobbies panel. |
assets/resume.pdf |
Résumé, linked from the header and the contact node. |
js/site.js walks [data-node] in document order and draws one jagged
zigzag connector per consecutive pair, measuring real
getBoundingClientRect() geometry rather than hardcoded coordinates — so the
graph re-routes correctly on resize. A short bright segment animates along
each connector's path on a continuous loop (an SVG <animate> on
stroke-dashoffset); the underlying wire lights up once on reveal and
settles to a dim resting glow rather than flickering forever.
Below 900px the left-hand rail hides and cards stop alternating left/right, since everything stacks into one column.
Add or reorder a node by moving its <section class="node" data-node> in
index.html. Wires and the left-hand rail redraw from DOM order on every
resize, so nothing else needs updating. Give a project card side-l or
side-r to alternate which side of the canvas it sits on.
The hobbies node (#n-hobbies) lives in js/hobbies.js, kept apart from the
page wiring in js/site.js:
- Ski skyline. Five hand-drawn SVG peaks, roughly to relative height, not
to scale. Hovering, focusing or clicking a peak or its legend row highlights
both (they share a
data-peakkey); otherwise it tours through them. - Chelsea / Knicks plays. Players are
<g class="player" data-name>in the SVG. They pass 3–10 times at random, then shoot and always score, and the scorer's name flashes. Hover or tap a player to see who it is. - Poker table (
js/poker.js). Five top-down players (shoulders, head, two hands) play Hold'em by the rules, one action every 5 seconds: blinds, hole cards dealt from the small blind, preflop action from left of the big blind, a burn before each street, showdown with no winner. Checks are a knock on the table, bets are pushed in by hand, folds slide to the muck. Idle players do real chip tricks: the two-stack riffle, the thumb flip and the knuckle roll, and they peek at their cards.
Every animation only runs while it's on screen and the tab is visible, and
everything is static under prefers-reduced-motion. Team and table colours
are the --chelsea*, --knicks*, --felt and --rail tokens in
css/site.css.
| Key | Action |
|---|---|
J / K |
Step to next / previous node |
T |
Toggle theme |
C |
Copy email |
Respects prefers-color-scheme on first visit, then remembers the choice via
localStorage. Honors prefers-reduced-motion (no travelling current, no
reveal animation, no connector draw-in).