sul and beans
-sweet treat -> claire dropping the most insane piece of information ever -> hti the yap
+sweet treat -> claire dropping the most insane piece of information ever -> hti the yap
diff --git a/README.md b/README.md
index d64a125..67ee295 100644
--- a/README.md
+++ b/README.md
@@ -7,19 +7,23 @@ The site is based on the HTML5 UP Lens template and currently ships as a plain s
## Repo Layout
- `templates/index.html`: source template for the main gallery page
+- `templates/rankings.html`: source template for the rankings page
- `index.html`: generated static gallery page
+- `rankings.html`: generated static rankings page
- `assets/`: site CSS, JavaScript, fonts, and audio
- `images/fulls/`: full-size gallery images
- `images/thumbs/`: gallery thumbnails
- `data/meals.json`: source of truth for gallery entries
+- `data/elo.json`: Elo ratings, record totals, and ranking settings
- `scripts/build.js`: renders static pages from templates and data
- `scripts/generate-thumbnails.js`: regenerates thumbnails from the full-size images
- `scripts/ingest-meal.js`: ingests a new meal image and metadata in one command
+- `scripts/lib/elo.js`: validates and syncs Elo data against the meal list
- `package.json`: minimal Node build entrypoint
## Content Workflow
-Gallery entries live in `data/meals.json`, and `index.html` is generated from `templates/index.html`.
+Gallery entries live in `data/meals.json`, and the build generates both `index.html` and `rankings.html` from the template and data files.
After editing content or templates, rebuild the site with:
@@ -27,7 +31,7 @@ After editing content or templates, rebuild the site with:
npm run build
```
-The build currently renders the main page without changing the existing Lens gallery structure, so the current client-side viewer code continues to work.
+The gallery build keeps the existing Lens thumbnail markup intact, so the current client-side viewer code continues to work.
To ingest a new meal image and update the site in one command, run:
@@ -52,6 +56,11 @@ To force a full thumbnail rebuild, run:
npm run build:thumbs:force
```
+## Rankings Data
+
+`data/elo.json` stores the seed rating, Elo `kFactor`, and a win-loss record for each meal.
+The page build keeps this file aligned with `data/meals.json`, so new meals automatically appear in `rankings.html` with the default seed rating.
+
## Image Conventions
- Full-size images and thumbnails share the same numeric ID
@@ -85,5 +94,5 @@ The `x` and `y` values are normalized from `0` to `1`, where `0.5, 0.5` is the c
## Planned Features
-1. An Elo-style ranking page that shows two food images at a time and updates rankings automatically based on the selected winner.
+1. A pairwise voting page that shows two food images at a time and updates Elo rankings based on the selected winner.
2. General cleanup and history cleanup once the bigger structural changes are in place.
diff --git a/assets/css/nyaa.css b/assets/css/nyaa.css
index 8802db9..dbd7783 100755
--- a/assets/css/nyaa.css
+++ b/assets/css/nyaa.css
@@ -3,6 +3,7 @@
width: 100px;
height: auto;
}
+
#giftwo {
position: fixed;
bottom: 0;
@@ -11,3 +12,24 @@
width: 100px;
height: auto;
}
+
+.page-links {
+ font-size: 0.8rem;
+ letter-spacing: 0.1em;
+ margin-top: 1rem;
+ text-transform: uppercase;
+}
+
+.page-links a {
+ border-bottom: 0;
+}
+
+.page-links a[aria-current="page"] {
+ color: #00d3b7;
+}
+
+.page-links__separator {
+ color: #d0d0d0;
+ display: inline-block;
+ margin: 0 0.5rem;
+}
diff --git a/assets/css/rankings.css b/assets/css/rankings.css
new file mode 100644
index 0000000..fa262e0
--- /dev/null
+++ b/assets/css/rankings.css
@@ -0,0 +1,160 @@
+html.rankings-html,
+body.rankings-page {
+ background:
+ radial-gradient(circle at top, rgba(0, 211, 183, 0.18), transparent 28rem),
+ linear-gradient(180deg, #f5f7fb 0%, #ffffff 100%);
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+body.rankings-page {
+ color: #7a7a7a;
+}
+
+body.rankings-page #main {
+ height: auto;
+ left: auto;
+ margin: 2rem auto;
+ max-width: 72rem;
+ overflow: visible;
+ position: relative;
+ text-align: left;
+ width: min(72rem, calc(100% - 3rem));
+}
+
+body.rankings-page #header,
+body.rankings-page #footer {
+ text-align: left;
+}
+
+body.rankings-page #header {
+ padding-bottom: 1.25rem;
+}
+
+body.rankings-page #gifone {
+ display: block;
+ margin-bottom: 1rem;
+}
+
+body.rankings-page #giftwo {
+ left: auto;
+ position: static;
+ transform: none;
+}
+
+#rankings-summary {
+ padding: 0 2.25rem 1.25rem 2.25rem;
+}
+
+.ranking-summary {
+ color: #666;
+ font-size: 0.95rem;
+ letter-spacing: 0.04em;
+ margin: 0;
+ text-transform: uppercase;
+}
+
+#rankings {
+ display: grid;
+ gap: 1.25rem;
+ padding: 0 2.25rem 2.25rem 2.25rem;
+}
+
+.ranking-card {
+ background: #f9fbfd;
+ border: 1px solid rgba(16, 16, 16, 0.08);
+ border-radius: 1rem;
+ box-shadow: 0 1.5rem 3rem rgba(16, 16, 16, 0.08);
+ display: grid;
+ gap: 1.25rem;
+ grid-template-columns: minmax(10rem, 14rem) minmax(0, 1fr);
+ overflow: hidden;
+ position: relative;
+}
+
+.ranking-card__placement {
+ background: #101010;
+ border-radius: 999px;
+ color: #ffffff;
+ font-size: 0.8rem;
+ left: 1rem;
+ letter-spacing: 0.08em;
+ margin: 0;
+ padding: 0.45rem 0.8rem;
+ position: absolute;
+ text-transform: uppercase;
+ top: 1rem;
+ z-index: 1;
+}
+
+.ranking-card__thumbnail {
+ border-bottom: 0;
+ display: block;
+}
+
+.ranking-card__thumbnail img {
+ display: block;
+ height: 100%;
+ object-fit: cover;
+ width: 100%;
+}
+
+.ranking-card__body {
+ display: flex;
+ flex-direction: column;
+ gap: 0.85rem;
+ justify-content: center;
+ min-width: 0;
+ padding: 1.5rem 1.5rem 1.5rem 0;
+}
+
+.ranking-card__body h2,
+.ranking-card__body p {
+ margin: 0;
+}
+
+.ranking-card__body h2 {
+ color: #333;
+ font-size: 1.5rem;
+}
+
+.ranking-card__meta {
+ color: #00a892;
+ font-size: 0.8rem;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+}
+
+@media screen and (max-width: 980px) {
+ body.rankings-page #main {
+ background: rgba(255, 255, 255, 0.96);
+ }
+}
+
+@media screen and (max-width: 736px) {
+ body.rankings-page #main {
+ margin: 0.75rem auto;
+ width: calc(100% - 1.5rem);
+ }
+
+ #rankings-summary,
+ #rankings,
+ body.rankings-page #header,
+ body.rankings-page #footer {
+ padding-left: 1.25rem;
+ padding-right: 1.25rem;
+ }
+
+ .ranking-card {
+ grid-template-columns: 1fr;
+ }
+
+ .ranking-card__placement {
+ left: auto;
+ right: 1rem;
+ }
+
+ .ranking-card__body {
+ padding: 0 1.25rem 1.25rem 1.25rem;
+ }
+}
diff --git a/data/elo.json b/data/elo.json
new file mode 100644
index 0000000..833cdfb
--- /dev/null
+++ b/data/elo.json
@@ -0,0 +1,204 @@
+{
+ "defaultRating": 1000,
+ "kFactor": 32,
+ "entries": [
+ {
+ "id": "01",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "02",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "03",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "04",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "05",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "06",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "07",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "08",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "09",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "10",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "11",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "12",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "13",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "14",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "15",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "16",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "17",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "18",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "19",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "20",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "21",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "22",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "23",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "24",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "25",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "26",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "27",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "28",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "29",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "30",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "31",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "32",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ },
+ {
+ "id": "33",
+ "rating": 1000,
+ "wins": 0,
+ "losses": 0
+ }
+ ]
+}
diff --git a/index.html b/index.html
index 2557b15..06b05b6 100755
--- a/index.html
+++ b/index.html
@@ -29,6 +29,11 @@
Please enable javascript >.<
+ @@ -131,7 +136,7 @@sweet treat -> claire dropping the most insane piece of information ever -> hti the yap
+sweet treat -> claire dropping the most insane piece of information ever -> hti the yap
+ static Elo seeds for every meal before the head-to-head voting page exists.
+ +33 meals seeded at Elo 1,000 until head-to-head voting starts.
+#1
+this was so not real i can't believe technically u paid for our first meal back. calmluh 3 years after. first hang !!!! pork buns were yummy 7/10
+#2
+the first thing you cooked for me ! so yum 10/10
+#3
+we fucking love this place 10/10 i love poke i should have never quit pokehouse
+#4
+for our santa cruz hang! u in my city now. so so good but lwk so so tax 9/10
+#5
+better than pepper lunch. server was being a little bitchy but i would be too if i was the only one working the front. 8/10
+#6
+omfg this is my favorite thing uve made 100/10
+#7
+and then we played bananagrams. sushi 8/10 thanks for paying mommy
+#8
+main street tino nothing special 7/10
+#9
+my peoples food. 9/10
+#10
+insane safeway hang 9/10
+#11
+this fuckass blue drink
+#12
+one of many.. 100/10
+#13
+this is the plaza where i used to go to all the time before school 9/10
+#14
+mac and cheese was gas. 10/10. you know its my fav comfort food. free the girl crying in the corner tho
+#15
+spartan tacos
+#16
+okay damn no way we got this b2b
+#17
+this is lowkey the spot poke always hits so fucking good
+#18
+hobags ughgmmfmfm im such a fucking ho for hobags 100/10
+#19
+carmel by the sea! we love sushi but tax 8/10
+#20
+sweet treat -> claire dropping the most insane piece of information ever -> hti the yap
+#21
+so good and soooo filling 10/10. also my peoples food.
+#22
+even when its rich white people breakfast im getting salmon nox 10/10
+#23
+1k cal meal 0 protein 10/10
+#24
+i dont want to talk about this. 9/10
+#25
+i can't believe u didnt eat ur leftovers. 10/10
+#26
+for my birthday!! i love eating meat and i love you so perfect combination 1000/10
+#27
+why was the store so nice. i wonder about the 4 sisters
+#28
+her boyfriend is so not real hes so stupid and funny. porridge was gas too i love eating free at julias 10/10
+#29
+spartan tacos. i was moody lol.
+#30
+i helped wrap the wontons w/ u !!! super fun and super yummy 10/10
+#31
+marry me? yes. 100/10 best valentines day ever
+#32
+poke house 3 years later 9/10 but +1 point bc its basically free
+#33
+mochi yinje black milk tea ts was actually so buss 10/10 only boba i've ever wanted to get again myself
+${meals.length} ${mealLabel} seeded at Elo ${formatRating( + eloData.defaultRating + )} until head-to-head voting starts.
`; +} + +function renderRankingMeta(rankedMeal) { + const ratingText = `Elo ${formatRating(rankedMeal.rating)}`; + + if (rankedMeal.matches === 0) { + return `${ratingText} | no votes yet`; + } + + const matchLabel = rankedMeal.matches === 1 ? "match" : "matches"; + return `${ratingText} | ${rankedMeal.wins}-${rankedMeal.losses} record across ${ + rankedMeal.matches + } ${matchLabel}`; +} + +function renderRankingItem(rankedMeal, placement, eol) { + return [ + '\t\t\t\t#${placement}
`, + `\t\t\t\t\t${escapeHtml(rankedMeal.description)}
`, + "\t\t\t\t\t
Please enable javascript >.<
+ diff --git a/templates/rankings.html b/templates/rankings.html new file mode 100644 index 0000000..9c756d8 --- /dev/null +++ b/templates/rankings.html @@ -0,0 +1,59 @@ + + + + +