← back to Crazy News Channel Shadowman

cartoons/20260924-row-by-row-only.html

175 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Row by Row Only — P24 Political Cartoon Desk</title>
<meta name="description" content="An original invented-satire cartoon: Kansas legislates the one true way to eat corn on the cob, deputizes Corn Marshals, and bans the cheating devices known as cob holders." />
<link rel="stylesheet" href="../assets/style.css" />
</head>
<body data-mood="politics" class="cartoon-page">
<header>
  <div>
    <div class="kicker">P24 Political Cartoon Desk &middot; Invented Satire &middot; Topeka, KS</div>
    <h1>Row by Row Only</h1>
    <p class="dek">Kansas lawmakers are considering legislation that would establish a single official method for eating corn on the cob at state-funded events, citing years of inconsistent technique.</p>
  </div>
  <div class="header-actions">
    <a class="back" href="index.html">&larr; Cartoon Desk</a>
  </div>
</header>
<main>
  <figure>
    <div class="phead"><span>House Bill, Agriculture Etiquette</span><span id="stamp"></span></div>
    <svg class="art" id="art" viewBox="0 0 480 320" role="img" tabindex="0" aria-label="Editorial cartoon about Kansas regulating corn-on-the-cob eating technique"></svg>
    <figcaption id="cap"></figcaption>
  </figure>
  <div class="dock">
    <button class="twist" id="twistBtn" type="button">Plot Twist!</button>
    <div id="status" role="status" aria-live="polite"></div>
  </div>
  <p class="hint">Keys: N / &rarr; advance the story &middot; Enter/Space on the art also advances</p>
</main>
<footer>All officials, marshals, and cobs are invented. No actual corn was disciplined. Part of PANDEMONIUM-24.</footer>

<script>
(function(){
  const NS = 'http://www.w3.org/2000/svg';
  function el(tag, attrs, parent){
    const n = document.createElementNS(NS, tag);
    for (const k in attrs) n.setAttribute(k, attrs[k]);
    if (parent) parent.appendChild(n);
    return n;
  }
  function txt(svg, x, y, size, weight, fill, content, anchor){
    const t = el('text', { x, y, 'text-anchor': anchor||'middle', 'font-family':'-apple-system,sans-serif', 'font-size':size, 'font-weight':weight||'400', fill: fill||'currentColor' }, svg);
    t.textContent = content;
    return t;
  }

  function official(svg, cx, cy, r, color, label){
    const g = el('g', {}, svg);
    el('circle', { cx, cy, r, fill: color, 'fill-opacity': '0.15', stroke: color, 'stroke-width': 3 }, g);
    el('circle', { cx, cy: cy - r*0.35, r: r*0.28, fill: color }, g);
    el('path', { d: `M ${cx - r*0.5} ${cy + r*0.5} Q ${cx} ${cy + r*0.1} ${cx + r*0.5} ${cy + r*0.5}`, fill: 'none', stroke: color, 'stroke-width': r*0.22, 'stroke-linecap':'round' }, g);
    if (label) txt(svg, cx, cy + r + 16, 11, '400', 'var(--ink-dim)', label);
    return g;
  }

  function corn(svg, cx, cy, s, color, bites){
    const g = el('g', {}, svg);
    el('ellipse', { cx, cy, rx: s*0.24, ry: s*0.62, fill: color }, g);
    const rows = 9;
    for (let i=0;i<rows;i++){
      const y = cy - s*0.55 + (i*(s*1.1/rows));
      el('ellipse', { cx: cx - s*0.13, cy: y, rx: s*0.05, ry: s*0.045, fill: 'var(--panel)', opacity: .8 }, g);
      el('ellipse', { cx: cx + s*0.13, cy: y, rx: s*0.05, ry: s*0.045, fill: 'var(--panel)', opacity: .8 }, g);
    }
    el('rect', { x: cx-6, y: cy+s*0.6, width: 12, height: s*0.22, fill: '#6b5f4d' }, g);
    if (bites === 'freestyle') {
      for (let i=0;i<5;i++){
        const y = cy - s*0.3 + i*(s*0.28);
        el('circle', { cx: cx + (i%2===0?-s*0.1:s*0.16), cy: y, r: s*0.09, fill: 'var(--bg)' }, g);
      }
    } else if (bites === 'row') {
      el('rect', { x: cx-s*0.28, y: cy-s*0.1, width: s*0.56, height: s*0.16, fill: 'var(--bg)' }, g);
    }
    return g;
  }

  const HEADLINES = [
    'Kansas Lawmakers Weigh Bill Setting Official Corn-on-the-Cob Eating Method',
    "Corn Etiquette Bill Advances, Adds Fines for 'Freestyle Gnawing'",
    'State to Certify Corn Marshals to Monitor Eating Technique at Public Events',
    'Corn Marshals Granted Authority to Confiscate Improperly Eaten Cobs',
    "Kansas Declares Statewide 'Row-by-Row Only' Zone, Bans Cob Holders as 'Cheating Devices'"
  ];
  const STAMPS = ['PROPOSED', 'FINED', 'CERTIFIED', 'CONFISCATED', 'BANNED'];

  const state = { stage: 0 };

  function scene(svg, stage){
    svg.innerHTML = '';
    if (stage === 0) {
      el('rect', { x: 170, y: 250, width: 140, height: 12, fill: 'currentColor', opacity: .4, rx: 3 }, svg);
      corn(svg, 240, 190, 140, '#c9a227', null);
      official(svg, 100, 240, 28, '#0f6b52', 'State Rep. Calloway');
      official(svg, 380, 240, 28, '#b5302f', 'State Rep. Deeks');
      txt(svg, 240, 60, 14, '700', 'currentColor', '"One method. For everyone. Forever."');
    } else if (stage === 1) {
      corn(svg, 200, 190, 150, '#c9a227', 'freestyle');
      el('g', { transform: 'translate(340,140) rotate(-14)' }, svg);
      const stamp = el('g', { transform: 'translate(340,150) rotate(-14)' }, svg);
      el('rect', { x: -46, y: -20, width: 92, height: 40, rx: 4, fill: 'none', stroke: 'var(--accent)', 'stroke-width': 5 }, stamp);
      txt(svg, 340, 156, 15, '800', 'var(--accent)', 'FINED');
      txt(svg, 200, 300, 11, '700', 'currentColor', 'Freestyle gnawing: $40 civil penalty.');
    } else if (stage === 2) {
      corn(svg, 340, 190, 130, '#c9a227', 'row');
      official(svg, 150, 200, 40, '#0f6b52', null);
      const badge = el('g', {}, svg);
      el('rect', { x: 118, y: 150, width: 64, height: 30, rx: 4, fill: 'var(--seal)', stroke: 'var(--rule)', 'stroke-width': 2 }, badge);
      txt(svg, 150, 170, 10.5, '800', '#241c14', 'CORN');
      txt(svg, 150, 182, 8, '800', '#241c14', 'MARSHAL');
      txt(svg, 150, 265, 11, '400', 'var(--ink-dim)', 'Certified, first graduating class.');
    } else if (stage === 3) {
      official(svg, 130, 190, 38, '#0f6b52', 'Corn Marshal');
      corn(svg, 320, 210, 120, '#c9a227', 'freestyle');
      el('path', { d: 'M 170 190 L 280 210', stroke: 'currentColor', 'stroke-width': 3, 'stroke-dasharray':'2 4', opacity:.6 }, svg);
      el('g', { transform: 'translate(320,90)' }, svg);
      const cuff = el('g', { transform: 'translate(320,90)' }, svg);
      el('circle', { cx: -14, cy: 0, r: 12, fill: 'none', stroke: 'var(--accent)', 'stroke-width': 4 }, cuff);
      el('circle', { cx: 14, cy: 0, r: 12, fill: 'none', stroke: 'var(--accent)', 'stroke-width': 4 }, cuff);
      el('line', { x1: -2, y1: 0, x2: 2, y2: 0, stroke: 'var(--accent)', 'stroke-width': 4 }, cuff);
      txt(svg, 320, 260, 11, '700', 'currentColor', 'Evidence, Improperly Eaten, Exhibit C');
    } else if (stage === 4) {
      corn(svg, 200, 190, 150, '#c9a227', 'row');
      const banned = el('g', { transform: 'translate(370,150)' }, svg);
      el('rect', { x: -34, y: -8, width: 68, height: 16, rx: 6, fill: '#8a7a52' }, banned);
      el('rect', { x: -30, y: -8, width: 8, height: 34, fill: '#8a7a52' }, banned);
      el('rect', { x: 22, y: -8, width: 8, height: 34, fill: '#8a7a52' }, banned);
      el('circle', { cx: 0, cy: 8, r: 34, fill: 'none', stroke: 'var(--accent)', 'stroke-width': 5 }, banned);
      el('line', { x1: -24, y1: -16, x2: 24, y2: 32, stroke: 'var(--accent)', 'stroke-width': 5 }, banned);
      txt(svg, 370, 215, 11, '700', 'var(--accent)', 'COB HOLDERS: CHEATING DEVICE');
      txt(svg, 200, 300, 12, '700', 'currentColor', 'Statewide Row-by-Row-Only Zone now in effect.');
    }
  }

  function say(kind, msg){ const s = document.getElementById('status'); s.className = kind; s.textContent = msg; }

  function paint(){
    scene(document.getElementById('art'), state.stage);
    document.getElementById('cap').textContent = HEADLINES[state.stage];
    document.getElementById('stamp').textContent = STAMPS[state.stage];
    const btn = document.getElementById('twistBtn');
    if (state.stage >= HEADLINES.length - 1) { btn.textContent = 'Story Concluded'; btn.disabled = true; }
    else { btn.textContent = 'Plot Twist!'; btn.disabled = false; }
  }

  function advance(){
    if (state.stage >= HEADLINES.length - 1) { say('info', 'The story has concluded. Row-by-row is now the law of the land.'); return; }
    state.stage++;
    paint();
    say('ok', `Stage ${state.stage + 1} of ${HEADLINES.length}.`);
  }

  document.getElementById('twistBtn').addEventListener('click', advance);
  const art = document.getElementById('art');
  art.addEventListener('click', advance);
  art.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); advance(); } });

  document.addEventListener('keydown', (e) => {
    if (e.metaKey || e.ctrlKey || e.altKey) return;
    const tag = (e.target.tagName || '').toLowerCase();
    if (tag === 'input' || tag === 'textarea') return;
    const k = e.key.toLowerCase();
    if (k === 'n' || e.key === 'ArrowRight') { e.preventDefault(); advance(); }
  });


  paint();
  say('info', 'Case file open. Press N, click the art, or hit Plot Twist to advance the story.');
})();
</script>
</body>
</html>