159 lines
14 KiB
JavaScript
159 lines
14 KiB
JavaScript
// Complete 64-Card Creative Whack Pack Catalog (Roger von Oech)
|
||
// Mapped to the 4 Creative Roles: Explorer (1-16), Artist (17-32), Judge (33-48), Warrior (49-64)
|
||
|
||
export const SUIT_META = {
|
||
explorer: {
|
||
id: "explorer",
|
||
label: "Explorer",
|
||
range: "1–16",
|
||
color: "#2b7ec1",
|
||
roleDescription: "For discovering new territory, gathering raw information, and looking in unexpected places.",
|
||
stageAffinity: ["spark", "exploring"]
|
||
},
|
||
artist: {
|
||
id: "artist",
|
||
label: "Artist",
|
||
range: "17–32",
|
||
color: "#d95f3b",
|
||
roleDescription: "For transforming raw material into new ideas through play, reversal, metaphor, and combination.",
|
||
stageAffinity: ["spark", "exploring"]
|
||
},
|
||
judge: {
|
||
id: "judge",
|
||
label: "Judge",
|
||
range: "33–48",
|
||
color: "#2a9158",
|
||
roleDescription: "For evaluating ideas critically, testing hidden assumptions, and deciding what is worth building.",
|
||
stageAffinity: ["exploring", "building"]
|
||
},
|
||
warrior: {
|
||
id: "warrior",
|
||
label: "Warrior",
|
||
range: "49–64",
|
||
color: "#b8335a",
|
||
roleDescription: "For overcoming excuses, slaying obstacles, and carrying your idea into shipped reality.",
|
||
stageAffinity: ["building", "shipped"]
|
||
}
|
||
};
|
||
|
||
const RAW_CARDS = [
|
||
// EXPLORER (1-16)
|
||
{ number: 1, file: "1.give_yourself_a_whack_on_the_side_of_the_head.jpg", title: "Give Yourself a Whack on the Side of the Head", promptQuestion: "How can you whack your thinking and break out of habitual routines?" },
|
||
{ number: 2, file: "2.ask_why.jpg", title: "Ask Why", promptQuestion: "Why does this problem exist, and what happens if you ask 'Why?' five times in a row?" },
|
||
{ number: 3, file: "3.get_out_of_your_box.jpg", title: "Get Out of Your Box", promptQuestion: "What other fields or disciplines outside your specialty can you draw on for this idea?" },
|
||
{ number: 4, file: "4.look_somewhere_else.jpg", title: "Look Somewhere Else", promptQuestion: "Where else could you look for inspiration that nobody in this space usually checks?" },
|
||
{ number: 5, file: "5.dig_deeper.jpg", title: "Dig Deeper", promptQuestion: "What overlooked details or root mechanics lie beneath the surface of this idea?" },
|
||
{ number: 6, file: "6.change_viewpoints.jpg", title: "Change Viewpoints", promptQuestion: "How does this idea look from the perspective of a beginner, a skeptic, or the end user?" },
|
||
{ number: 7, file: "7.see_the_big_picture.jpg", title: "See the Big Picture", promptQuestion: "If you zoom out 10x, what larger system or story is this idea really part of?" },
|
||
{ number: 8, file: "8.try_a_random_idea.jpg", title: "Try a Random Idea", promptQuestion: "Pick a random object or concept nearby—how can it force a fresh connection to your idea?" },
|
||
{ number: 9, file: "9.drop_an_assumption.jpg", title: "Drop an Assumption", promptQuestion: "What unnecessary boundary or assumption are you taking for granted—and what if you dropped it?" },
|
||
{ number: 10, file: "10.find_a_pattern.jpg", title: "Find a Pattern", promptQuestion: "What recurring theme, rhythm, or pattern connects this idea to other things that work?" },
|
||
{ number: 11, file: "11.see_hear_tast_feel_smell.jpg", title: "See, Hear, Taste, Feel, Smell", promptQuestion: "How can you engage more physical senses, textures, or tactile qualities in this concept?" },
|
||
{ number: 12, file: "12.listen_to_your_dreams.jpg", title: "Listen to Your Dreams", promptQuestion: "What subconscious hunch, daydream, or wild wish is trying to surface here?" },
|
||
{ number: 13, file: "13.look_to_nature.jpg", title: "Look to Nature", promptQuestion: "How has nature or biology already solved a problem similar to yours?" },
|
||
{ number: 14, file: "14.look_to_the_past.jpg", title: "Look to the Past", promptQuestion: "What vintage craft, historical design, or classic wisdom can you revive or remix here?" },
|
||
{ number: 15, file: "15.let_your_mind_wander.jpg", title: "Let Your Mind Wander", promptQuestion: "If you stop forcing a direct path and let your thoughts drift, what tangent excites you most?" },
|
||
{ number: 16, file: "16.see_the_obvious.jpg", title: "See the Obvious", promptQuestion: "What simple, right-in-front-of-your-nose truth are you overcomplicating?" },
|
||
|
||
// ARTIST (17-32)
|
||
{ number: 17, file: "17.think_like_a_kid.jpg", title: "Think Like a Kid", promptQuestion: "What would a six-year-old see, ask, or play with if they looked at your project?" },
|
||
{ number: 18, file: "18.ask_what_if.jpg", title: "Ask What If", promptQuestion: "What if the rules of gravity, cost, or convention didn't apply—what 'What if?' unlocks this?" },
|
||
{ number: 19, file: "19.challenge_the_rules.jpg", title: "Challenge the Rules", promptQuestion: "Which sacred rule in this category is ripe to be broken or inverted?" },
|
||
{ number: 20, file: "20.be_whacky.jpg", title: "Be Whacky", promptQuestion: "What is the most absurd, playful, or outrageous version of this idea?" },
|
||
{ number: 21, file: "21.simplify.jpg", title: "Simplify", promptQuestion: "What can you strip away so only the purest, most essential core remains?" },
|
||
{ number: 22, file: "22.exaggerate.jpg", title: "Exaggerate", promptQuestion: "What happens if you magnify one feature 100x or shrink it to miniature scale?" },
|
||
{ number: 23, file: "23.rearrange.jpg", title: "Rearrange", promptQuestion: "How can you swap the order, layout, or hierarchy of the components?" },
|
||
{ number: 24, file: "24.substitute.jpg", title: "Substitute", promptQuestion: "What material, medium, setting, or ingredient could you swap in for a surprising twist?" },
|
||
{ number: 25, file: "25.combine_ideas.jpg", title: "Combine Ideas", promptQuestion: "What two unrelated concepts or sparks can you fuse together into a hybrid?" },
|
||
{ number: 26, file: "26.make_a_metaphor.jpg", title: "Make a Metaphor", promptQuestion: "If this idea were a physical object, ritual, or creature, what metaphor captures it best?" },
|
||
{ number: 27, file: "27.reverse.jpg", title: "Reverse", promptQuestion: "What happens if you flip this idea inside-out, upside-down, or backwards?" },
|
||
{ number: 28, file: "28.imagine_how_others_woud_do_it.jpg", title: "Imagine How Others Would Do It", promptQuestion: "How would your favorite artist, designer, or historical figure tackle this idea?" },
|
||
{ number: 29, file: "29.imagine_youre_the_idea.jpg", title: "Imagine You're the Idea", promptQuestion: "If you were this idea personified, what would you want to become next?" },
|
||
{ number: 30, file: "30.change_its_name.jpg", title: "Change Its Name", promptQuestion: "What new name, title, or slogan would completely reframe how people experience this?" },
|
||
{ number: 31, file: "31.dont_force_it.jpg", title: "Don't Force It", promptQuestion: "Where are you pushing too hard, and how can you let the natural form of the idea emerge?" },
|
||
{ number: 32, file: "32.pause_for_a_bit.jpg", title: "Pause for a Bit", promptQuestion: "What part of this idea needs a brief incubation period so a better angle can click?" },
|
||
|
||
// JUDGE (33-48)
|
||
{ number: 33, file: "33.see_the_positive.jpg", title: "See the Positive", promptQuestion: "What is genuinely strong, exciting, and worth protecting about this idea right now?" },
|
||
{ number: 34, file: "34.find_out_whats_out_of_whack.jpg", title: "Find Out What's Out of Whack", promptQuestion: "What feels slightly off-balance, awkward, or friction-heavy in the current concept?" },
|
||
{ number: 35, file: "35.solve_the_right_problem.jpg", title: "Solve the Right Problem", promptQuestion: "Are you solving the real core problem, or just polishing a symptom?" },
|
||
{ number: 36, file: "36.conform.jpg", title: "Conform", promptQuestion: "Where should you actually follow familiar standards so users immediately understand it?" },
|
||
{ number: 37, file: "37.ask_a_fool.jpg", title: "Ask a Fool", promptQuestion: "What naive or blunt question would an outsider ask that exposes a blind spot?" },
|
||
{ number: 38, file: "38.focus_on_the_real_truth.jpg", title: "Focus on the Real Truth", promptQuestion: "Strip away wishful thinking—what do the real constraints and facts say?" },
|
||
{ number: 39, file: "39.slay_a_sacred_cow.jpg", title: "Slay a Sacred Cow", promptQuestion: "What darling feature or habit are you keeping out of nostalgia that should be cut?" },
|
||
{ number: 40, file: "40.loosen_up.jpg", title: "Loosen Up", promptQuestion: "Are you judging this idea too harshly before giving it room to breathe?" },
|
||
{ number: 41, file: "41.check_your_timing.jpg", title: "Check Your Timing", promptQuestion: "Why is right now (or later) the right moment to bring this idea to life?" },
|
||
{ number: 42, file: "42.beware_the_unintended.jpg", title: "Beware the Unintended", promptQuestion: "What second-order side effects or unintended consequences could this create?" },
|
||
{ number: 43, file: "43.get_out_of_the_dogma_house.jpg", title: "Get Out of the Dogma House", promptQuestion: "Where is rigid ideology getting in the way of a practical, creative solution?" },
|
||
{ number: 44, file: "44.be_dissatisfied.jpg", title: "Be Dissatisfied", promptQuestion: "What 'good enough' part of this idea deserves to be pushed from decent to remarkable?" },
|
||
{ number: 45, file: "45.dont_fall_in_love_with_ideas.jpg", title: "Don't Fall in Love with Ideas", promptQuestion: "If you had to pivot 50% of this concept today, what would you willingly let go of?" },
|
||
{ number: 46, file: "46.avoid_arrogance.jpg", title: "Avoid Arrogance", promptQuestion: "Where might your assumptions be wrong, and how can you test them cheaply?" },
|
||
{ number: 47, file: "47.listen_to_that_hunch.jpg", title: "Listen to That Hunch", promptQuestion: "What quiet gut instinct do you have about this idea that logic hasn't caught up to yet?" },
|
||
{ number: 48, file: "48.hear_the_knock_of_opportunity.jpg", title: "Hear the Knock of Opportunity", promptQuestion: "What unexpected side-benefit or spin-off opportunity is hiding inside this idea?" },
|
||
|
||
// WARRIOR (49-64)
|
||
{ number: 49, file: "49.take_a_whack_at_it.jpg", title: "Take a Whack at It", promptQuestion: "How can you take a concrete whack at your idea in the next 30 minutes?" },
|
||
{ number: 50, file: "50.believe_in_yourself.jpg", title: "Believe in Yourself", promptQuestion: "Why are you uniquely equipped to bring this specific idea into the world?" },
|
||
{ number: 51, file: "51.put_a_lion_in_your_heart.jpg", title: "Put a Lion in Your Heart", promptQuestion: "What bold move would you make on this project if you weren't worried about criticism?" },
|
||
{ number: 52, file: "52.fight_for_it.jpg", title: "Fight for It", promptQuestion: "What is the #1 obstacle blocking this idea, and how will you push through it?" },
|
||
{ number: 53, file: "53.flex_your_risk_muscle.jpg", title: "Flex Your Risk Muscle", promptQuestion: "What calculated risk or experiment can you run right now to move this forward?" },
|
||
{ number: 54, file: "54.get_support.jpg", title: "Get Support", promptQuestion: "Who could you show this mockup or prototype to for feedback or collaboration?" },
|
||
{ number: 55, file: "55.get_rid_of_excuses.jpg", title: "Get Rid of Excuses", promptQuestion: "What excuse has kept this idea sitting on the shelf—and how can you eliminate it today?" },
|
||
{ number: 56, file: "56.slay_a_dragon.jpg", title: "Slay a Dragon", promptQuestion: "What is the hardest, scariest task on this idea's checklist that you should tackle first?" },
|
||
{ number: 57, file: "57.have_something_at_stake.jpg", title: "Have Something at Stake", promptQuestion: "How can you put real skin in the game so you're committed to shipping this?" },
|
||
{ number: 58, file: "58.use_your_shield.jpg", title: "Use Your Shield", promptQuestion: "How can you protect this fledgling idea from premature naysayers while you build v1?" },
|
||
{ number: 59, file: "59.do_the_unexpected.jpg", title: "Do the Unexpected", promptQuestion: "How can you launch, present, or prototype this in a way that surprises everyone?" },
|
||
{ number: 60, file: "60.sell_sell_sell.jpg", title: "Sell, Sell, Sell", promptQuestion: "How can you pitch the core value of this idea in one irresistible sentence or visual?" },
|
||
{ number: 61, file: "61.set_a_deadline.jpg", title: "Set a Deadline", promptQuestion: "By what exact date and time will you ship a tangible prototype or mockup of this idea?" },
|
||
{ number: 62, file: "62.be_persistent.jpg", title: "Be Persistent", promptQuestion: "What small daily or weekly step will keep momentum alive until this crosses the finish line?" },
|
||
{ number: 63, file: "63.learn_from_mistakes.jpg", title: "Learn from Mistakes", promptQuestion: "What past stumble or failed attempt can you turn into fuel for this version?" },
|
||
{ number: 64, file: "64.give_yourself_a_pat_on_the_back.jpg", title: "Give Yourself a Pat on the Back", promptQuestion: "What progress have you already made on this idea that deserves recognition?" }
|
||
];
|
||
|
||
export const WHACK_CARDS = RAW_CARDS.map((card) => {
|
||
let suitKey = "explorer";
|
||
if (card.number >= 17 && card.number <= 32) suitKey = "artist";
|
||
else if (card.number >= 33 && card.number <= 48) suitKey = "judge";
|
||
else if (card.number >= 49) suitKey = "warrior";
|
||
|
||
const suit = SUIT_META[suitKey];
|
||
return {
|
||
...card,
|
||
suit: suit.id,
|
||
suitLabel: suit.label,
|
||
color: suit.color,
|
||
roleDescription: suit.roleDescription,
|
||
stageAffinity: suit.stageAffinity,
|
||
imageUrl: `/whack_pack/${card.file}`
|
||
};
|
||
});
|
||
|
||
export function getCardByNumber(num) {
|
||
return WHACK_CARDS.find((c) => c.number === Number(num)) || null;
|
||
}
|
||
|
||
export function drawCards({ suit, status, count = 1, excludeNumbers = [] } = {}) {
|
||
let pool = WHACK_CARDS.filter((c) => !excludeNumbers.includes(c.number));
|
||
if (suit && SUIT_META[suit]) {
|
||
pool = pool.filter((c) => c.suit === suit);
|
||
} else if (status) {
|
||
if (status === "spark") {
|
||
pool = pool.filter((c) => c.suit === "explorer" || c.suit === "artist");
|
||
} else if (status === "exploring") {
|
||
pool = pool.filter((c) => c.suit === "artist" || c.suit === "judge");
|
||
} else if (status === "building") {
|
||
pool = pool.filter((c) => c.suit === "judge" || c.suit === "warrior");
|
||
} else if (status === "shipped") {
|
||
pool = pool.filter((c) => c.suit === "warrior");
|
||
}
|
||
}
|
||
if (pool.length === 0) pool = [...WHACK_CARDS];
|
||
|
||
const shuffled = [...pool].sort(() => Math.random() - 0.5);
|
||
return shuffled.slice(0, Math.max(1, Math.min(count, shuffled.length)));
|
||
}
|
||
|
||
export function drawFourRoleSpread() {
|
||
return ["explorer", "artist", "judge", "warrior"].map((suit) => drawCards({ suit, count: 1 })[0]);
|
||
}
|