Skip to content

Commit 30eb08b

Browse files
committed
feat(catalog): add comedic meme metadata
1 parent f9898b6 commit 30eb08b

6 files changed

Lines changed: 270 additions & 83 deletions

File tree

docs/reference/src/cli/flags.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ mac --catalog=layouts,style_presets,allowed_names
6060

6161
Output runtime catalog metadata as JSON. `mac --catalog` returns the full catalog; `--catalog=<selector>` returns one or more comma-separated subsets. Supported selectors include `templates`, `assets`, `assets:<category>`, `effects`, `effect_definitions`, `layouts`, `style_presets`, `limits`, and `allowed_names`.
6262

63-
Asset entries include stable IDs such as `meme.distracted_boyfriend` and relative asset paths such as `assets/templates/meme/distracted_boyfriend.jpg`. Image bytes are not embedded.
63+
Asset entries include stable IDs such as `meme.distracted_boyfriend`, display names, relative asset paths such as `assets/templates/meme/distracted_boyfriend.jpg`, searchable tags, moods, subjects, aliases, caption guidance, and optional comedy metadata such as `comedicName`, `comedicRead`, and `antiPatterns`. Image bytes are not embedded.
6464

6565
### Version
6666

include/MacCatalog.h

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ namespace mac_catalog {
4141
std::vector<std::string> subjects;
4242
std::vector<std::string> aliases;
4343
std::string captionGuidance;
44+
std::string comedicName;
45+
std::string comedicRead;
46+
std::vector<std::string> antiPatterns;
4447
};
4548

4649
struct TemplateMetadata {
@@ -51,6 +54,9 @@ namespace mac_catalog {
5154
std::vector<std::string> subjects;
5255
std::vector<std::string> aliases;
5356
std::string captionGuidance;
57+
std::string comedicName;
58+
std::string comedicRead;
59+
std::vector<std::string> antiPatterns;
5460
};
5561

5662
inline std::string lower(std::string value) {
@@ -156,6 +162,7 @@ namespace mac_catalog {
156162
std::string description = "Reaction meme asset showing " + titleizeStem(stem) + ".";
157163
std::string bestFor = "Readable reaction beats, labels, and short punchlines.";
158164
std::string captionGuidance = "Prefer top or bottom captions; keep center text very short and avoid covering faces or the primary subject.";
165+
std::string comedicRead = "A flexible reaction image; make the caption specific enough to supply the joke.";
159166
return {
160167
description,
161168
bestFor,
@@ -164,6 +171,9 @@ namespace mac_catalog {
164171
uniqueValues(subjects),
165172
uniqueValues(aliases),
166173
captionGuidance,
174+
"",
175+
comedicRead,
176+
{"generic labels without a situation", "center text covering the subject"},
167177
};
168178
}
169179

@@ -177,6 +187,33 @@ namespace mac_catalog {
177187
{"alarm", "clock"},
178188
{"alarm clock", "angry alarm", "morning alarm"},
179189
"Use bottom captions for the complaint; avoid center text over the clock face.",
190+
"The 7 AM Betrayal",
191+
"A tiny plastic tyrant announcing that your previous self made bad choices.",
192+
{"generic Monday bad text", "center captions over the clock face"},
193+
}},
194+
{"meme.barbie_car_fire", {
195+
"Pink toy car scene consumed by very unserious-looking fire.",
196+
"Cute aesthetics colliding with total crisis, overdramatic errands, and glamorous disaster.",
197+
{"meme", "reaction", "barbie", "car", "fire", "cute", "crisis"},
198+
{"panic", "chaos", "meltdown", "absurd"},
199+
{"car", "fire"},
200+
{"barbie car", "pink car fire", "cute disaster"},
201+
"Use bottom captions; keep the fire and car readable.",
202+
"Cute Car, Total Crisis",
203+
"The visual joke is that everything is on fire but the branding stayed adorable.",
204+
{"flat disaster labels", "effects so heavy the pink car disappears"},
205+
}},
206+
{"meme.bathroom_throne", {
207+
"Bathroom scene with absurd throne energy.",
208+
"Private revelations, fake luxury, shower thoughts, and decisions made with unearned authority.",
209+
{"meme", "reaction", "bathroom", "throne", "privacy", "decision"},
210+
{"deadpan", "absurd", "smug"},
211+
{"bathroom", "throne"},
212+
{"bathroom throne", "toilet throne", "private kingdom"},
213+
"Prefer a short bottom caption; avoid making the scene feel too literal.",
214+
"Executive Bathroom Decision",
215+
"Someone has clearly mistaken solitude for leadership experience.",
216+
{"gross-out captions as the whole joke", "long centered captions"},
180217
}},
181218
{"meme.beach_dog_sitting", {
182219
"Dog sitting alone on a beach with peaceful resigned energy.",
@@ -186,6 +223,21 @@ namespace mac_catalog {
186223
{"dog", "beach"},
187224
{"beach dog", "resigned dog", "calm dog"},
188225
"Use bottom captions; keep text short so the quiet beach mood stays visible.",
226+
"Vacation Brain Has Left The Chat",
227+
"A dog quietly accepting a situation it absolutely does not understand.",
228+
{"busy captions that ruin the quiet", "loud chaos effects"},
229+
}},
230+
{"meme.bliss_ferret_stare", {
231+
"Small ferret staring with serene, empty-headed bliss.",
232+
"No-thoughts moments, tiny victories, harmless delusion, and being weirdly pleased.",
233+
{"meme", "reaction", "ferret", "bliss", "stare", "empty headed"},
234+
{"calm", "joy", "deadpan", "weird"},
235+
{"ferret", "stare"},
236+
{"bliss ferret", "ferret stare", "no thoughts ferret"},
237+
"Bottom captions work best; let the blank stare do half the joke.",
238+
"No Thoughts, Premium Bliss",
239+
"The joke lands when the caption reveals why this tiny creature is so peacefully wrong.",
240+
{"mean animal captions", "overexplaining the blank stare"},
189241
}},
190242
{"meme.cat_explosion", {
191243
"Cat in a chaotic explosion scene with maximum meltdown energy.",
@@ -195,6 +247,9 @@ namespace mac_catalog {
195247
{"cat", "explosion", "fire"},
196248
{"exploding cat", "chaos cat", "meltdown cat"},
197249
"Use short top or bottom captions; heavy effects are appropriate, but keep the cat readable.",
250+
"Tiny Problem, Biblical Consequences",
251+
"The correct asset when a minor inconvenience deserves an operatic disaster response.",
252+
{"using it for mild reactions", "deepfry so strong the cat vanishes"},
198253
}},
199254
{"meme.distracted_boyfriend", {
200255
"Classic distracted boyfriend scene with three clear role positions.",
@@ -204,6 +259,21 @@ namespace mac_catalog {
204259
{"boyfriend", "girlfriend", "street"},
205260
{"distracted boyfriend", "temptation trio", "boyfriend looking back"},
206261
"Use short labels near each role; avoid generic ME/MY RESPONSIBILITIES unless requested.",
262+
"Bad Priorities Walk By",
263+
"A three-role temptation machine: stable choice, doomed observer, shiny mistake.",
264+
{"ME/MY RESPONSIBILITIES defaults", "long labels that need reading twice"},
265+
}},
266+
{"meme.dog_earbuds_bliss", {
267+
"Dog wearing earbuds in pure private-concert bliss.",
268+
"Ignoring problems, main-character errands, tiny joy, and pretending the world is fine.",
269+
{"meme", "reaction", "dog", "earbuds", "music", "bliss"},
270+
{"joy", "calm", "smug"},
271+
{"dog", "earbuds"},
272+
{"earbuds dog", "music dog", "bliss dog"},
273+
"Use bottom captions; avoid covering the face or earbuds.",
274+
"Main Character Errand Walk",
275+
"The mood is delusional confidence powered by one good song.",
276+
{"generic happy dog text", "sad captions that fight the image"},
207277
}},
208278
{"meme.evil_cat_throne", {
209279
"Cat seated like a tiny villain on a throne.",
@@ -213,6 +283,9 @@ namespace mac_catalog {
213283
{"cat", "throne"},
214284
{"evil cat", "cat throne", "villain cat"},
215285
"Bottom captions work best; one concise royal decree or consequence.",
286+
"The Snack Crime Overlord",
287+
"A tiny monarch preparing a household policy nobody voted for.",
288+
{"generic evil laugh captions", "overcrowding the throne area"},
216289
}},
217290
{"meme.girl_side_eye", {
218291
"Girl giving a strong side-eye reaction.",
@@ -222,6 +295,9 @@ namespace mac_catalog {
222295
{"girl", "face"},
223296
{"side eye girl", "judgment stare", "suspicious girl"},
224297
"Use top or bottom captions; never cover the eyes with center text.",
298+
"The Receipt Has Been Noticed",
299+
"For the exact second someone hears a detail that changes the whole story.",
300+
{"covering the eyes", "generic 'sus' captions with no situation"},
225301
}},
226302
{"meme.lonely_desk_worker", {
227303
"Person alone at a desk with a monitor, quiet office mood.",
@@ -231,6 +307,9 @@ namespace mac_catalog {
231307
{"desk", "worker", "computer"},
232308
{"desk worker", "lonely desk", "alone at computer"},
233309
"Use bottom captions or terminal-style text; keep the monitor and person visible.",
310+
"One Last Thing At 11:47 PM",
311+
"The setup frame for any bad idea that starts calmly and becomes everyone else's problem.",
312+
{"only developer jokes by default", "covering the desk/monitor subject"},
234313
}},
235314
{"meme.spongebob_group_stare", {
236315
"Group stare reaction with multiple characters looking toward the viewer.",
@@ -240,6 +319,9 @@ namespace mac_catalog {
240319
{"group", "faces"},
241320
{"group stare", "everyone staring", "spongebob group"},
242321
"Use bottom captions; avoid covering faces with centered text.",
322+
"The Group Chat Goes Silent",
323+
"Everyone has read the message; nobody wants to be the first to answer.",
324+
{"covering faces", "too much caption for a reaction beat"},
243325
}},
244326
{"meme.spongebob_war_room", {
245327
"Chaotic SpongeBob war-room scene with planning-board energy.",
@@ -249,6 +331,9 @@ namespace mac_catalog {
249331
{"spongebob", "room", "board"},
250332
{"war room", "planning board", "spongebob war room"},
251333
"Use bottom captions; pair with mild desaturation or contrast for tense middle beats.",
334+
"The Plan Is Mostly Panic",
335+
"A room full of confidence that is technically just anxiety with stationery.",
336+
{"starting GIF arcs at maximum chaos", "covering the board/faces"},
252337
}},
253338
{"meme.squidward_window_stare", {
254339
"Squidward staring through a window with quiet longing and resignation.",
@@ -258,6 +343,9 @@ namespace mac_catalog {
258343
{"squidward", "window"},
259344
{"squidward window", "window stare", "outside looking in"},
260345
"Use bottom captions with muted styling; avoid loud effects unless ironic.",
346+
"Watching Joy Happen Elsewhere",
347+
"A quiet little window into being technically fine and spiritually outside.",
348+
{"loud panic styling", "captioning over the face/window read"},
261349
}},
262350
{"meme.thousand_yard_stare", {
263351
"Blank thousand-yard stare with exhausted existential energy.",
@@ -267,6 +355,9 @@ namespace mac_catalog {
267355
{"face", "stare"},
268356
{"thousand yard stare", "blank stare", "haunted stare"},
269357
"Use bottom captions; keep text short and let the stare carry the joke.",
358+
"The Lights Are On But Nobody Saved",
359+
"The face of someone whose brain has opened too many tabs and lost the original one.",
360+
{"giant centered captions over the eyes", "using it for high-energy jokes"},
270361
}},
271362
};
272363
return metadata;
@@ -277,14 +368,18 @@ namespace mac_catalog {
277368
if (!override.description.empty()) result.description = override.description;
278369
if (!override.bestFor.empty()) result.bestFor = override.bestFor;
279370
if (!override.captionGuidance.empty()) result.captionGuidance = override.captionGuidance;
371+
if (!override.comedicName.empty()) result.comedicName = override.comedicName;
372+
if (!override.comedicRead.empty()) result.comedicRead = override.comedicRead;
280373
addAllUnique(result.tags, override.tags);
281374
addAllUnique(result.moods, override.moods);
282375
addAllUnique(result.subjects, override.subjects);
283376
addAllUnique(result.aliases, override.aliases);
377+
addAllUnique(result.antiPatterns, override.antiPatterns);
284378
result.tags = uniqueValues(result.tags);
285379
result.moods = uniqueValues(result.moods);
286380
result.subjects = uniqueValues(result.subjects);
287381
result.aliases = uniqueValues(result.aliases);
382+
result.antiPatterns = uniqueValues(result.antiPatterns);
288383
return result;
289384
}
290385

@@ -336,6 +431,9 @@ namespace mac_catalog {
336431
item["subjects"] = entry.subjects;
337432
item["aliases"] = entry.aliases;
338433
item["captionGuidance"] = entry.captionGuidance;
434+
if (!entry.comedicName.empty()) item["comedicName"] = entry.comedicName;
435+
if (!entry.comedicRead.empty()) item["comedicRead"] = entry.comedicRead;
436+
if (!entry.antiPatterns.empty()) item["antiPatterns"] = entry.antiPatterns;
339437
return item;
340438
}
341439

@@ -365,9 +463,11 @@ namespace mac_catalog {
365463
auto filename = image.filename().string();
366464
auto id = category + "." + stem;
367465
auto metadata = metadataForAsset(id, stem, category);
466+
auto canonicalName = titleizeStem(stem);
467+
addUnique(metadata.aliases, canonicalName);
368468
out.push_back({
369469
id,
370-
titleizeStem(stem),
470+
metadata.comedicName.empty() ? canonicalName : metadata.comedicName,
371471
category,
372472
metadata.description,
373473
metadata.bestFor,
@@ -379,6 +479,9 @@ namespace mac_catalog {
379479
metadata.subjects,
380480
metadata.aliases,
381481
metadata.captionGuidance,
482+
metadata.comedicName,
483+
metadata.comedicRead,
484+
metadata.antiPatterns,
382485
});
383486
}
384487
}
@@ -404,6 +507,9 @@ namespace mac_catalog {
404507
metadata.subjects,
405508
metadata.aliases,
406509
metadata.captionGuidance,
510+
metadata.comedicName,
511+
metadata.comedicRead,
512+
metadata.antiPatterns,
407513
});
408514
}
409515
auto assets = assetTemplateEntries(binaryDir);
@@ -672,7 +778,7 @@ namespace mac_catalog {
672778
: splitSelectors(selectorText);
673779

674780
json out = {
675-
{"schema_version", 2},
781+
{"schema_version", 3},
676782
{"mac_version", MAC_VERSION},
677783
{"catalog_fingerprint", catalogFingerprint(binaryDir)},
678784
{"included", json::array()},

tests/analyzer/run_analyzer_tests.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ def catalog_full_registered():
658658
"layouts", "style_presets", "limits", "allowed_names",
659659
):
660660
assert_true(key in data, f"catalog should include {key}")
661-
assert_eq(data["schema_version"], 2)
661+
assert_eq(data["schema_version"], 3)
662662

663663

664664
@test
@@ -680,11 +680,14 @@ def catalog_asset_selector_registered():
680680
assert_true(find(assets, id="meme.distracted_boyfriend") is not None)
681681
template = find(assets, id="meme.distracted_boyfriend")
682682
assert_true(template["assetPath"].endswith("assets/templates/meme/distracted_boyfriend.jpg"))
683-
for key in ("tags", "moods", "subjects", "aliases", "captionGuidance"):
683+
for key in ("tags", "moods", "subjects", "aliases", "captionGuidance", "comedicName", "comedicRead", "antiPatterns"):
684684
assert_true(key in template, f"asset metadata should include {key}")
685685
assert_true("temptation" in template["tags"])
686686
assert_true("boyfriend" in template["subjects"])
687687
assert_true("ME/MY RESPONSIBILITIES" in template["captionGuidance"])
688+
assert_eq(template["name"], "Bad Priorities Walk By")
689+
assert_true("shiny mistake" in template["comedicRead"])
690+
assert_true("ME/MY RESPONSIBILITIES defaults" in template["antiPatterns"])
688691

689692

690693
@test

0 commit comments

Comments
 (0)