Escoffier Labs · Course 11 (l’ardoise)

Mise en Scène: staging the explainer

A Vite + React 19 studio that turns raw source material into a self-contained, audience-tuned technical explainer rendered as a dark editorial SVG scene — exported as one standalone HTML file. An honest early spike, scoped without overclaiming.

v0.1.0 spikeReact 19 + Vitelocal studioMIT
01

The Chalkboard Out Front

Mise en Scène is "the studio": paste a repo, an OpenAPI spec, a README, an incident report, a transcript, or architecture notes, and it produces a polished, editable technical explainer rendered as a dark editorial HTML/SVG scene. Pick an audience and a mode, click the cards, then export the whole thing as one standalone HTML artifact you can hand to anyone.

It solves the editorial-diagram problem: producing a legible, audience-tuned architecture picture from raw notes without hand-drawing it, and shipping it as a portable file. On escoffierlabs.dev it is course 11 — station "l’ardoise", the chalkboard out front — the fleet’s front-of-house explainer surface.

02

Mise en Scène vs Mise en Place

The name is a deliberate counterpart to Brigade’s mise en place. Mise en place is prep — everything in its place before you cook. Mise en scène is stagecraft — the arrangement of a scene so it reads. This tool’s job is composing extracted elements into a legible scene. Being honest about the current spike matters as much as the pitch.

What it is

  • A staging surfaceArranges extracted facts, terms, and blocks into a composed, audience-tuned scene.
  • A single-file exporterEmits a standalone HTML artifact (styles included) plus a JSON export.
  • Honestly scopedThe README calls it "an early working spike". v0.1.0, private package, published MIT.

What it is not (yet)

  • A generic graph editorThe diagram is a fixed 8-block pipeline self-portrait today, not a graph synthesized from arbitrary input.
  • Model-driven extractionIngestion is local text heuristics (regex sentences + frequency terms) — no model calls yet.
  • Wired to BrigadeBrigade appears only as a depicted block in the demo scene; there is no Brigade code dependency.
03

The Data Model: One Scene Object

Everything an author touches is one plain Scene object. Blocks are absolutely-positioned cards; edges are directed connectors keyed to the four explainer modes. No backing store — just a typed value.

src/App.tsxtypescript
type SceneBlock = {
  id: string; label: string; kicker: string; detail: string;
  x: number; y: number; w: number; h: number;   // absolute layout
};

type SceneEdge = {
  from: string; to: string; label: string;
  modes: Array<ExplainerMode>;  // which modes light this edge up
  dashed?: boolean;
};

type Scene = {
  title: string; subtitle: string; summary: string;
  facts: string[]; terms: string[];
  blocks: SceneBlock[]; edges: SceneEdge[];
};
  • x / y / w / h on every blockCards are absolutely positioned in a fixed 1280x780 viewBox — layout is data, not CSS flow.
  • modes: Array<ExplainerMode>An edge belongs to one or more of the 4 modes; switching mode filters what lights up.
  • facts / terms: string[]These (plus title and card detail) are the parts actually extracted from pasted source.
04

Source → Scene: the Heuristic Pipeline

createScene is the transform. Today it is pure local heuristics: it extracts text, then merges it into a fixed block/edge template. Knowing exactly which parts are dynamic vs templated is the key to reading the tool honestly.

  1. Paste sourceRepo text, OpenAPI spec, README, incident report, transcript, or notes go into the studio textarea.
  2. splitFacts()A sentence-splitting regex pulls candidate facts from the source.
  3. extractTerms()Stopword-filtered frequency analysis surfaces the key terms.
  4. titleFromSource()Derives a title for the chosen mode.
  5. createScene()Merges extracted title/facts/terms/detail into a fixed 8-block pipeline template with mode-keyed edges.
  6. Render SceneSvgThe scene draws as an interactive SVG; click cards, switch audience and mode.
05

The foreignObject Card Trick

SVG <text> cannot wrap or clamp, so early cards overflowed when detail ran long (character-width estimation never holds). The fix: draw the border as a <rect>, then put real HTML inside a <foreignObject> and let CSS line-clamp do the work.

src/App.tsx · src/sceneStyles.tstsx
<rect x={block.x} y={block.y} width={block.w} height={block.h} rx="10" className="card-rect" />
<foreignObject x={block.x} y={block.y} width={block.w} height={block.h}>
  <div className="card">
    <h3>{block.label}</h3>
    <p>{block.detail}</p>
  </div>
</foreignObject>

/* sceneStyles.ts — the clamp that keeps text in bounds */
.card p {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}
  • <rect ... /> then <foreignObject>The rect is the visible border; the foreignObject hosts real, wrappable HTML.
  • -webkit-line-clamp: 3CSS clamps detail to 3 lines — the overflow fix that replaced fragile SVG text measuring.
  • styles live in sceneStyles.ts as literalsToken literals (not CSS vars) so the styles can be inlined into the exported SVG.
06

One Component, Two Outputs (No Drift)

The live studio and the exported file render the same SceneSvg, and the scene’s CSS is injected inside the SVG — so styles travel with the artifact and the export can never visually drift from the app. standaloneHtml serializes a full document with React 19’s renderToStaticMarkup.

src/App.tsxtsx
function StandalonePage({ scene, mode }) {
  return (
    <html lang="en">
      <head><style>{standaloneCss}</style></head>
      <body>
        <main>
          <section className="scene">
            <SceneSvg scene={scene} activeMode={mode} staticExport />
          </section>
        </main>
      </body>
    </html>
  );
}

// standaloneHtml(scene, mode):
//   "<!doctype html>" + renderToStaticMarkup(<StandalonePage scene mode/>)
  • the same <SceneSvg> in both pathsLive app and export share one renderer — a single source of truth, so they cannot diverge.
  • styles injected inside the SVGThe scene’s CSS lives in the SVG, so a saved file looks identical with no external stylesheet.
  • renderToStaticMarkup(<StandalonePage/>)react-dom/server is bundled client-side (≈ a deliberate +bundle tradeoff) to serialize the artifact.
07

An Honest Spike: Shipped vs Planned

The repo does not oversell. Here is the real line between what works today and what is aspirational — the kind of scoping the fleet values.

Studio app
Source paste, title override, 4 audiences, 4 modes, click-to-select cards, persistent state.
shipped
SVG renderer
SceneSvg with zones, bezier edges, and the foreignObject line-clamp cards.
shipped
HTML + JSON export
Standalone single-file HTML via renderToStaticMarkup, plus a JSON scene export.
shipped
Model ingestion
Real model-driven extraction beyond local regex heuristics.
planned
Generic graph synthesis
Building the diagram from arbitrary pasted structure (today it is a fixed template).
planned
Screenshot / walkthrough export
Image and recorded-walkthrough export targets.
planned
08

Where It Sits in the Kitchen

Mise en Scène is independent of Brigade in code, but its demo scene depicts a future where "Brigade runtime" is the backend that runs grounding, model routing, tool calls, and artifact export once the pipeline grows past local heuristics.

Escoffier Labs Academy. Generated from the deep-dive source of record.