Back Office · office.temerarii.xyz
CALENDAR_CELL_SPEC.md

← all docs

Calendar Cell Spec — the parity bar for every cell

Status: binding · Owner: Temerarii Media · Source of truth: brands/temerarii-media/content/_context/calendar/*.yaml (authored content) + GOAL.yaml (schedule) + remotion/src/storyboard-registry.json (produced video cells).

Every cell on /calendar (office.temerarii.xyz) opens a modal. This doc is the bar each modal must clear — the iamdream-v3 reference at parity or above. "Finish the calendar" = author each cell's composition to this bar. Rendered video masters and audio are downstream (the Remotion/audio pipeline, gated separately); a cell whose composition is complete but unrendered legitimately reads "render pending" — that is not a gap.

The discipline (from the content-engine deep-dive): one source per fact · derive production from the schedule · gate every bug class · render-and-eyeball (a clean exit code is not proof). The renderer (apps/office/render_calendar.py) already surfaces every field below; the work is authoring the content, not rebuilding the renderer.


The 7 cell types

1. Campaign anchor cell (the week's Sunday cell)

Drives every other cell that week. Authored in the campaign/pillar YAML under weeks.<wk>.

  • name (objective) · tagline (this-cell line) · anchor (one-sentence north star) · theme (pillar arc)
  • description.strategic_intent · description.brand_rails · description.visual_treatment · description.vo_music
  • Counted publish-volume map (rendered automatically by _week_volume): Blog 1/wk → site + syndicate; Video 1/wk → YouTube; Email 7/wk; SMS 2/wk (Tue+Fri); Social 35/wk → ×9 Blotato fan-out; Total assets → channel-posts.
  • Pillar must match the GOAL.yaml rotation for that week.

2. Blog cell (Sunday)

  • blog = title (in the week YAML). Pillar weeks also carry blog2 = a second sub-service spotlight title.
  • The full article = 2500+ words, authored to docs/strategy/BLOG_EDITORIAL_STANDARD.md (E-E-A-T first, Texas/SA–ATX-aware SEO (home market; global reach), HTML hierarchy, internal links, CTA, zero banned words). The article lives in content/blog/<date>-<slug>.md (one file per blog; blog2 → its own <date>-<slug2>.md).
  • The renderer loads the .md from disk for the cell body (falling back to inline blog_body, then to "Authored at production").
  • Source path surfaced: content/blog/<date>-<slug>.md.

3. Video cell (Sunday) — the deepest

Authored as a storyboard md + a storyboard-registry.json entry (+ enrichment). The cell must carry:

  • composition (Remotion comp) · cut spec (duration / frames @ fps) · render set (per-aspect masters 9:16 / 1:1 / 16:9 + 4K + Social GIF, per governance/asset_specs.yaml) · per-platform map · music · anchor · publishes-to (9 Blotato) · cover.
  • Full scene-by-scene table (#/frames/time/what/motion/audio) · timecoded VO script.
  • "Optimized scene (live registry)" enrichment: synthesized VO + VO-coverage % (target 70–98%) · goal · CTA · per-channel caption variants (tiktok/instagram/x/linkedin/…) · audio master note (VO + ducked music, −16 LUFS) · per-day per-channel post copy.
  • Each WEEK has a video SET: 1 hero/educational long-form (YouTube) + daily social-video comps (ReelDaily / BoundaryStatement / FounderPullQuote / SymbolLoop / ScriptureWalk-equivalents, Temerarii-themed).
  • Source: content/storyboards/W##/<slug>.md. Render status is read from disk — unrendered = "render pending" (legitimate).

4. Email cell (daily)

Authored under weeks.<wk>.days.<Day>:

  • email = the day brief / subject line (always present).
  • email_subject (optional, overrides) · email_preheader (optional) · email_body = the full letter.
  • Template + spec/ratio — surfaced automatically from governance/asset_specs.yaml slots.email.formats (Primary 600×600, Primary V2 600×900, Secondary 600×400, Tertiary 600×250, Quaternary 600×300, Header 600×150, Story 600×1400). One source — do not hand-type dimensions into the cell.
  • Channel = Resend (owned list) · Source content/email/<date>.md · Cadence = daily 7am ET.

5. SMS cell (Tue + Fri)

  • sms = the full body (≤160 chars, plain text, no exclamation/emoji).
  • Template + spec — from asset_specs.yaml slots.sms.formats (Static 600×600, GIF 720×720). One source.
  • Channel = Twilio (owned list) · Source content/sms/<date>.txt · Cadence = Tue + Fri 7am local.

6. Social cells (social[5], daily)

  • 5 daily lines, themed to that week's pillar + the Insights-repurposing arc, at the W34 standard.
  • Hero/reel posts also carry the per-channel caption variants (from the video cell enrichment).
  • Each fans to all 9 Blotato channels.

7. Off-weeks

Pre-launch and post-campaign weeks collapse to a label row by default (no daily grid) — intentional, not a gap.


Renderer contract (apps/office/render_calendar.py)

  • _campaign_panel → campaign cell + counted publish map. _blog_panel → full blog_body. _panel_html → produced video cell (registry + render status + scene beats + VO + captions + outputs).
  • _email_panel / _sms_panel → full copy + template + spec (via lib.asset_specs.slot()), source, cadence. Wired per-day as panel ids e-W{wk}-{di} / s-W{wk}-{di}.
  • _spec_row(slot_key, label) is the single helper that reads asset_specs.slot(key).formats — the one source for email/SMS template + ratio. Never duplicate dimensions in cell YAML.

Completeness gate (engine/gates/check_calendar_completeness.py)

A cell fails the bar (flagged, not silently passed) when, for an authored campaign week:

  1. a blog title exists but blog_body is empty;
  2. a video is scheduled (video field or registry entry) but no storyboard exists;
  3. a day in the daily grid is entirely blank (no email, no sms-on-Tue/Fri, no social).

Graceful: weeks the schedule never frames, and unrendered-but-composed video cells, do not fail — only real composition gaps do.