Scènes — le cahier des charges du film
Fiche d'entité. Respecte le contrat de
README.md:ContentBase/InstanceBase, argent entier suffixé_eur,Tick= demi-journée, durée écran en secondes, stats 0–100, probabilités suffixées_p, événementsdomaine.sujet.verbe_au_passé.Écart assumé.
BreakdownItemn'est pas une entité de premier niveau (pas deContentBase, absent deEntityKind) : c'est un enregistrement embarqué dansSceneDef, avec son propre ULID. Un item de dépouillement n'existe pas hors de sa scène, ne se réutilise jamais, et le sortir obligerait à versionner deux objets pour une seule correction éditoriale.
Exemple filé. La Nuit des hérons, long métrage, devis 1,9 M€, 34 jours. Scène 47 : la jument s'emballe au crépuscule, la mère tombe, l'enfant accourt pieds nus dans la boue. Elle coûte cher, elle est magnifique, et le monteur la coupera peut-être.
1. Rôle dans le jeu
Le joueur est directeur de production. Il ne tourne jamais une scène. Il fait trois choses, et ce sont trois écrans :
| verbe | écran | produit |
|---|---|---|
| découper | dépouillement (surlignage au stabilo) | la liste des besoins — §3 |
| doter | arbitrage budgétaire | des Assignment : qui, quoi, combien — §4 |
| planifier | plan de travail | des Day, des regroupements — §7 |
La scène est le pont entre le texte et la logistique. C'est la première information consultée d'une partie — on ne recrute pas sans savoir ce qu'on tourne — et le seul objet du modèle qui contienne de la prose. Tout le reste est du tableur ; la scène est du récit. La friction du jeu naît de la traduction d'un texte ambigu en lignes de devis non ambiguës. Dans le pipeline canonique (README §7), elle est en entrée :
SceneDef.breakdown ──► SceneDef.requirements ──► Assignment ──► résolution ──► Shot[]
▲ ▲ │
surlignage joueur normalisation moteur SceneState.qualite / couverture
│ │
besoins manqués ────────────► SurpriseLatente ──► Event le jour du tournage ────┘
Elle consomme temps, argent, personnes, éléments ; elle produit des Shot (shots.md), une note par critère, et — dépouillement bâclé — des Event (events.md).
2. SceneDef — l'en-tête de scène
Le schéma reprend la continuité dramatique française.
type SceneDef = ContentBase & {
kind: 'scene'
numero: string // "47", "47A", "47bis" — TOUJOURS string : une réécriture
ordreScenario: number // insère des scènes lettrées. ordreScenario = tri.
sequenceId?: string
interieurExterieur: 'INT.' | 'EXT.' | 'INT./EXT.'
decorId: string // -> production-elements.md (sous-type décor)
decorLibelle: string // "FERME DES ARDOISES — CHEMIN DE TERRE"
moment: Moment // régime de lumière : pilote le REGROUPEMENT
effet?: Effet // fenêtre étroite : pilote la PRESSION
personnages: PersonnageDansScene[]
figuration: Figuration
longueur: Longueur
synopsis: string // 1–2 phrases : ce qui se passe
intention: string // ce que le réalisateur veut OBTENIR — nourrit le critère
// `intention` (§5) et le brief de plateau
texte: string // le texte de la scène, NFC : support du dépouillement
texteHash: string // sha256(texte NFC) — invalide les spans (§3)
breakdown: BreakdownItem[] // §3 — la VÉRITÉ, jamais envoyée au client
requirements: SceneRequirements // §4
ponderation: Ponderation // §5
poidsNarratif: PoidsNarratif // §6
positionRealisateur: PositionRealisateur
regroupement: CleRegroupement // §7
raccordAvec: string[] // sceneIds : continuité HMC / costume / lumière
contraintesOrdre: ContrainteOrdre[]
}
type Moment = 'JOUR' | 'NUIT'
type Effet = 'aube' | 'crepuscule' | 'magic-hour' | 'heure-bleue' | 'nuit-americaine'
type PersonnageDansScene = {
roleId: string // le PERSONNAGE, pas le comédien : le lien est un Deal (people.md)
presence: 'joue' | 'silhouette' | 'voix-off' | 'mentionne'
repliques: number
doublureRequise?: ('cascade' | 'lumiere' | 'nu' | 'enfant' | 'main')[]
}
type Figuration = { silhouettes: number; figurants: number; descriptif: string }
type Longueur = {
pages: number; huitiemes: number // 0..7 — la grille de 8 tracée sur la page imprimée
dureeEcranEstimee_s: number // SECONDES : l'unité que lit le moteur (contrat §3)
densite: 'dialogue' | 'mixte' | 'action'
}
moment et effet sont séparés parce qu'ils servent deux calculs opposés. moment est binaire : c'est ce qui structure une journée d'équipe. effet est la fenêtre réelle — une magic hour, c'est 25 minutes exploitables, donc deux scènes en magic hour ne se regroupent pas, elles se répartissent sur deux soirs. Fusionner les deux champs supprimerait cette leçon.
Pages → durée écran, défaut moteur écrasable par l'auteur : dureeEcranEstimee_s = round((pages + huitiemes/8) × k), k = 45 s (dialogue), 55 s (mixte — la règle du pouce « 1 page ≈ 1 min »), 90 s (action : trois lignes de didascalie = une demi-journée de plateau). Le piège pédagogique est là : la longueur écran ne prédit pas la durée de tournage. La 47 fait 2 p. 4/8 → 206 s à l'écran, et 2 jours de plateau. C'est requirements.dureeTournageEstimee_ticks qui entre au plan de travail, et il est indépendant.
Scène 47 — EXT. · FERME DES ARDOISES — CHEMIN DE TERRE · JOUR / magic-hour · Nadia (joue, 3 répliques, doublures cascade + lumiere), Théo 11 ans (joue, 1 réplique, doublure enfant) · 2 silhouettes + 10 figurants « villageois, fin d'automne » · 2 p. 4/8, action, 206 s · intention : « La nature reprend la ferme. Nadia perd le contrôle en un plan, devant témoins, et personne ne bouge. »
47. EXT. FERME DES ARDOISES — CHEMIN DE TERRE — CRÉPUSCULE
Le ciel vire à l'orange sale. NADIA (43), bottes et ciré, tire par la bride OTTOKAR,
un hongre bai qui refuse d'avancer. Plus bas, sur la route, une dizaine de VILLAGEOIS
regardent sans bouger.
NADIA
Avance. Avance, bon sang.
Un coup de tonnerre. Ottokar se cabre, arrache la bride et part au galop. Nadia tombe
lourdement dans l'ornière. Son arcade s'ouvre.
THÉO (11) surgit de derrière le tracteur en panne et court vers elle, pieds nus dans
la boue.
THÉO
Maman !
La pluie commence. Derrière eux, la ligne à haute tension barre le ciel.
3. Le dépouillement, modélisé
Le minigame central de la pré-production. Le joueur reçoit ce texte et un stabilo par Poste (couleurs dans content/reference/postes.json, contrat §5). Il surligne, rattache, quantifie.
/** Offsets en code units UTF-16 sur `SceneDef.texte` normalisé NFC. */
type TextSpan = { start: number; end: number }
type Criticite = 'bloquant' | 'degradant' | 'optionnel'
type BreakdownItem = {
id: string // ULID
spans: TextSpan[] // PLUSIEURS : "OTTOKAR" l.2 et "Ottokar" l.7 = un seul besoin
poste: Poste
besoin: Besoin
quantite: number
unite: 'unite' | 'jour' | 'demi-journee' | 'personne' | 'metre' | 'litre' | 'plan'
criticite: Criticite
note?: string // la phrase pédagogique montrée en correction
difficulte: number // 0..100 — complexité de mise en œuvre (coût, risque)
evident_p: number // 0..1 — proba qu'un joueur moyen le repère (équilibrage, §3.3)
origine: 'auteur' | 'llm-valide' | 'llm-propose'
}
type Besoin =
| { type: 'element'; elementId: string }
| { type: 'personne'; roleId?: string; profil: ProfilRequis }
| { type: 'prestation'; prestationId: string } // journée de dresseur, plan VFX
| { type: 'autorisation'; autorisationId: string }
| { type: 'consequence'; cible: Poste; libelle: string } // "pluie -> son direct perdu"
| { type: 'libre'; libelle: string } // brouillon d'auteur non résolu
texteHash est le garde-fou. Le scénario est réécrit pendant la partie — c'est un événement de production, pas un bug. À chaque modification de texte on recalcule le hash ; tout item dont les spans n'ont pas été réancrés retombe en llm-propose et sort de la vérité jusqu'à revalidation. Le réancrage littéral réussit ~85 % du temps ; le reste est un écran de conflits.
3.1 La vérité, pré-remplie par l'auteur
SceneDef.breakdown est la liste exhaustive des besoins réels de la scène. Elle n'est jamais envoyée au client avant soumission du dépouillement, exactement comme un Rated.actual. Le moteur s'en sert pour composer requirements (§4), budgéter la scène telle qu'elle devrait l'être, et savoir ce qui manque. Vérité de la scène 47 — 16 items :
| # | span | poste | besoin | qté | crit. | evident_p |
|---|---|---|---|---|---|---|
| 1 | « CRÉPUSCULE » | image | fenêtre magic hour, 25 min utiles/soir | 2 soirs | bloq. | 0.55 |
| 2 | « bottes et ciré » | costumes | costume Nadia ×3 (doublure + rechange boue) | 3 | dégr. | 0.70 |
| 3 | « OTTOKAR, un hongre bai » | animaux | cheval + dresseur | 2 j | bloq. | 0.95 |
| 4 | « une dizaine de VILLAGEOIS » | casting | 12 figurants | 12 | dégr. | 0.85 |
| 5 | (même span) | costumes | 12 costumes villageois | 12 | dégr. | 0.45 |
| 6 | « Un coup de tonnerre » | post | effet sonore, pas de captation | 1 | opt. | 0.15 |
| 7 | « se cabre… part au galop » | cascades | coordinateur équin + cheval dressé au cabré | 2 j | bloq. | 0.60 |
| 8 | « Nadia tombe lourdement » | cascades | doublure cascade, gabarit Nadia | 1 | bloq. | 0.50 |
| 9 | « dans l'ornière » | deco | ornière creusée + tapis de chute enterré | 1 | dégr. | 0.25 |
| 10 | « Son arcade s'ouvre » | hmc | maquillage FX arcade + sang, 2 états | 2 | bloq. | 0.75 |
| 11 | « THÉO (11) » | enfants | autorisation préfectorale + coach + 4 h de plateau max | 1 | bloq. | 0.40 |
| 12 | « le tracteur en panne » | deco | tracteur Renault D22, location + chauffeur | 2 j | bloq. | 0.90 |
| 13 | « pieds nus dans la boue » | regie | chaufferettes, serviettes, présence médicale, 8 °C | 1 | dégr. | 0.10 |
| 14 | « La pluie commence » | sfx | rampe de pluie, citerne 10 000 L, 2 techniciens | 2 j | bloq. | 0.80 |
| 15 | (même span) | son | son direct perdu → post-synchro Nadia + Théo | 1 | dégr. | 0.20 |
| 16 | « la ligne à haute tension » | vfx | effacement HT + effacement du câble de cascade | 6 plans | dégr. | 0.35 |
Les trois items en gras sont les pièges de conception, et exactement ce que le jeu enseigne : on voit les figurants, on oublie de les habiller ; on lit « pieds nus », on n'entend pas « 8 °C, un enfant, vingt minutes avant que le coach arrête tout » ; on lit « la pluie », on n'entend pas « plus un mot de son direct ».
3.2 Ce que le joueur doit retrouver
type BreakdownAttempt = {
id: string; sceneId: string
passage: number // 1er, 2e… — un second passage coûte du temps (§3.5)
items: PlayerBreakdownItem[]
soumisAuTick?: Tick
score?: BreakdownScore
}
type PlayerBreakdownItem = {
id: string
span: TextSpan // UN seul : le joueur surligne, il ne fusionne pas
poste: Poste // la couleur de stabilo choisie
besoinDeclare: { libelle: string; elementId?: string; roleId?: string }
quantite: number
}
Un item joueur apparie un item de vérité si son span chevauche d'au moins un caractère l'un des spans de la vérité.
| verdict | condition | compte comme |
|---|---|---|
exact | chevauchement + même poste + besoin compatible + quantité à ±20 % | trouvé, plein poids |
partiel | chevauchement + même poste, élément ou quantité faux | trouvé à 50 %, et budgété faux |
mauvais-poste | chevauchement, poste différent | manqué, mais la correction est plus douce |
manque | aucun chevauchement | manqué, plein effet (§3.4) |
invente | item joueur sans vérité en face | faux positif |
Un même span porte parfois deux items (4/5, 14/15) : il faut le surligner deux fois avec deux stabilos. C'est l'exercice le plus difficile du minigame, et le plus fidèle au métier.
3.3 Le barème
type BreakdownScore = {
trouves: number; partiels: number; mauvaisPoste: number; manques: number; inventes: number
couverture_p: number // pondérée par criticité
precision_p: number // trouvés / (trouvés + inventés)
note: number // 0..100
coutFauxPositifs_eur: number
manquesCritiques: string[] // itemIds bloquants ratés -> SurpriseLatente
}
Poids : bloquant 3, degradant 2, optionnel 1.
couverture_p = (Σ poids(trouvés) + 0.5 · Σ poids(partiels)) / Σ poids(tous)
note = round(100 · couverture_p^1.2 · (0.6 + 0.4 · precision_p))
L'exposant 1.2 rend les derniers 20 % de couverture disproportionnellement payants : dépouiller à 80 %, ce n'est pas 80 % du travail, c'est un tournage qui déraille. La précision ne pèse que 40 % : on veut que le joueur surligne large au début. evident_p n'entre pas dans la note — il alimente l'écran de correction (« 90 % des directeurs de prod ratent celui-ci ») et l'équilibrage en atelier. Punir au barème pour un besoin objectivement invisible serait injuste ; punir dans la fiction ne l'est pas, parce que c'est ce qui arrive.
3.4 Un besoin manqué — le générateur d'aléas
C'est la meilleure idée du jeu : il n'a presque pas besoin de dés. Un besoin manqué n'est pas budgété, pas commandé, personne ne l'attend. Il reste latent jusqu'au jour du tournage.
type SurpriseLatente = InstanceBase & {
sceneId: string; itemId: string // itemId -> la vérité manquée
poste: Poste
declencheur: 'preparation-decor' | 'veille' | 'jour-de-tournage' | 'post'
gravite: 'gene' | 'retard' | 'blocage'
detecte: boolean // rattrapée en amont ? (§3.5)
eventDefId: string
}
gravite se dérive de criticite — aucun tirage :
| criticité ratée | gravité | jour J |
|---|---|---|
optionnel | gene | −5 à −15 sur un critère. Invisible sur le plateau, visible au montage. |
degradant | retard | 1 tick à improviser, ou dégradation acceptée. Un tick de plateau = 12 000–25 000 €. |
bloquant | blocage | la scène ne se tourne pas aujourd'hui → report, cascade sur tout le plan de travail (§7). |
Trois portes, toujours les mêmes — jamais de défaite sèche : payer en urgence (prix × 2,5, imputé aux imprévus, chapitre 10), dégrader (0 €, malus sur les critères nourris par ce poste, Shot marqué compromis), reporter (1 tick + coûts de retour au décor, §7). Événements : depouillement.scene.soumis, depouillement.besoin.manque, tournage.besoin.surgi, budget.ligne.non_prevue, production.imprevus.entames. depouillement.besoin.manque est émis mais non notifié : il entre au journal, le joueur ne le voit pas. C'est la seule information volontairement cachée hors des Rated, et elle l'est pour une raison narrative — l'angoisse du directeur de production, c'est de ne pas savoir ce qu'il a oublié.
Le cas d'école. Le joueur a raté l'item 13 (evident_p: 0.10, degradant). Jour de tournage :
17h40 L'enfant entre dans la boue. 8 °C.
17h48 Le coach arrête la prise. Pas de chaufferette, pas de serviette.
-> tournage.besoin.surgi { gravite: 'retard' }
18h02 Le joueur reporte. La magic hour est perdue.
18h05 Cheval et dresseur loués à la journée -> 1 400 € refacturés. Le coordinateur
cascade part sur un autre film à J+9 : la fenêtre de report se referme.
18h10 La rampe de pluie est réservée demain sur la 62 -> décaler 62 (déco montée) ou 47 ?
Un besoin à 400 € produit 20 000 € de dégâts et trois décisions, sans une ligne d'aléatoire : l'aléa, c'est l'attention du joueur, et il est parfaitement reproductible d'une partie à l'autre.
3.5 Les soupapes
Second passage : 1 tick de pré-production ; révèle les items dont evident_p > 0.3 + 0.1 × passage. On ne repart jamais de zéro. — Le 1er assistant réalisateur relit à J−3 : chaque SurpriseLatente a une probabilité vigilance_actual / 200 d'être détectée et payée au prix normal. Un bon 1er assistant à 80 rattrape 40 % des oublis : c'est pourquoi il coûte cher, et le joueur ne le comprend qu'après en avoir engagé un mauvais. — Les imprévus (chapitre 10, ~10 %) : leur épuisement est la courbe de tension de la partie.
Les faux positifs, eux, sont chers mais visibles : la machine à fumée à 1 200 € apparaît au budget. L'asymétrie est le cœur du design — un oubli est gratuit et invisible aujourd'hui, ruineux et incontrôlable dans trois semaines ; un excès est cher et visible tout de suite. Le joueur apprend à préférer la seconde erreur, ce qui est exactement le réflexe du métier.
4. requirements — le cahier des charges résolu
breakdown est de la prose annotée ; requirements est ce que le moteur consomme. Généré depuis breakdown, puis éditable : une scène peut exiger une grue que le texte ne mentionne pas — c'est une décision de mise en scène, pas un besoin du texte.
type SceneRequirements = {
parPoste: ExigencePoste[]
personnes: ExigencePersonne[]
elements: ExigenceElement[]
prestations: ExigencePrestation[]
dureeTournageEstimee_ticks: number
plansPrevus: number // découpage prévisionnel -> shots.md
fenetre: FenetreDeTournage
contraintesLegales: ContrainteLegale[]
seuilCritique: Partial<Record<Critere, number>> // §5 : sous ce seuil, à retourner
}
type ExigencePoste = {
poste: Poste
niveauAttendu: number // 0..100 — un NOMBRE NU : la barre est honnête
effectifMin: number
criticite: Criticite
justification: string // affichée : "cheval + chute -> chef op qui cadre l'imprévu"
}
type ExigenceElement = { elementId: string; quantite: number; criticite: Criticite
substituts: { elementId: string; malusQualite: number }[] }
type ExigencePersonne = { roleId: string; criticite: Criticite; doublurePossible_p: number }
type ExigencePrestation = { prestationId: string; quantite: number; criticite: Criticite
unite: 'jour' | 'demi-journee' | 'plan' | 'unite' }
type FenetreDeTournage = {
moment: Moment; effet?: Effet
dureeUtile_min?: number // magic hour = 25 : contrainte DURE
meteoRequise: 'sec' | 'pluie' | 'couvert' | 'soleil' | 'indifferent'
meteoAcceptable: string[]
saison?: 'printemps' | 'ete' | 'automne' | 'hiver' // feuillage, lumière
plageHoraire?: { debut_h: number; fin_h: number }
}
type ContrainteLegale = {
code: 'enfant-horaires' | 'enfant-autorisation' | 'animal-veterinaire' | 'arme-armurier'
| 'cascade-coordinateur' | 'nuit-majoration' | 'voie-publique-autorisation'
| 'drone-dgac' | 'feu-pompier' | 'monument-historique'
criticite: Criticite // en pratique toujours 'bloquant'
effet: string
emetteur?: Poste
contournable: boolean // le joueur PEUT tourner sans
risqueControle_p: number // 0..1 par tick -> juridique.controle.subi
}
Le pari central du jeu tient dans une asymétrie de type.
niveauAttenduest unnumbernu : la barre est connue. La compétence de la personne affectée est unRated: sonclaimedest sur le CV, sonactualse découvre au tournage. Le joueur compare une exigence certaine à une promesse incertaine, cent vingt fois de suite. C'est tout le « engager le pas cher, le payer plus tard ».
| niveau | définition opératoire | test moteur |
|---|---|---|
| bloquant | sans ça, tournage.scene.ouverte est refusé | précondition |
| dégradant | on tourne, mais un ou plusieurs critères plafonnent | plafond de qualité |
| optionnel | on tourne pareil, mieux si présent | bonus additif |
Les contraintes légales sont bloquantes mais contournables. Le joueur peut tourner un enfant hors horaires, une rue sans autorisation ; il gagne un tick et tire risqueControle_p à chaque tick. Un contrôle, c'est l'arrêt, l'amende, et surtout la nouvelle qui circule : malus de réputation qui renchérit tous les cachets restants. Seule mécanique du jeu où la triche est explicitement offerte — elle doit l'être, ça se fait.
Scène 47 — image 65 + magic hour 2 soirs (bloq.) · cascades 70, coordinateur équin + doublure (bloq.) · animaux 75, 2 j (bloq.) · sfx 55, rampe + citerne (bloq.) · hmc 60, arcade 2 états (bloq.) · enfants autorisation + coach 4 h (bloq., contournable, risqueControle_p: 0.15) · deco 50, tracteur (bloq.) / ornière (dégr.) · vfx 45 (dégr.) · costumes 40 (dégr.) · son 50 + post-synchro (dégr.) · regie 35 (dégr.). dureeTournageEstimee_ticks: 4, plansPrevus: 11, meteoRequise: 'sec' — parce que la pluie est fabriquée, et qu'une vraie pluie par-dessus une fausse pluie ne raccorde pas.
5. criteria — ce sur quoi la scène est jugée
Liste fermée, cinq critères — fermée parce qu'un critère ouvert rend l'UI de comparaison inécrivable, et parce que cinq axes suffisent à distinguer toutes les scènes qu'on veut écrire.
type Critere = 'jeu' | 'image' | 'son' | 'credibilite' | 'intention'
/** Entiers, somme obligatoirement = 100. Vérifié par le lint (§10). */
type Ponderation = Record<Critere, number>
Arbitrages. emotion est fusionné dans intention : l'émotion n'est pas mesurable sur un plateau, l'écart entre ce que le réalisateur voulait et ce qui a été tourné l'est. rythme est retiré du niveau scène et calculé au niveau film (§9) : une scène n'a pas de rythme, un montage en a un ; une scène tournée en 3 plans au lieu de 11 ne « manque pas de rythme », elle prive le monteur d'options — ce que couverture_p mesure déjà. (Contre-argument sérieux en §11.6.)
| critère | nourri par | agrégation | plafonné par |
|---|---|---|---|
jeu | talent actual des comédiens, moral, prises accordées, direction d'acteurs, coach enfant | min pondéré par les répliques | le plus faible comédien à l'image |
image | chef op, optiques et caméra, électro + machinerie, respect de la fenêtre, décor | moyenne pondérée | la fenêtre : magic hour ratée = plafond 45 |
son | ingé son, perchman, nuisances du lieu, SFX bruyants, post-synchro budgétée ou non | moyenne pondérée | pluie non compensée = plafond 30 |
credibilite | déco, costumes, HMC, SFX, VFX, animaux, cascades, figuration, accessoires | min strict sur les postes engagés | le maillon le plus faible |
intention | couverture vs plansPrevus, temps passé vs estimé, présence et énergie du réalisateur, découpage respecté | moyenne × facteur d'épuisement | l'état du réalisateur (people.md) |
Pourquoi credibilite est un min. Un tracteur d'époque parfait à côté d'un costume en polyester ne donne pas une scène « moyennement crédible » : le costume est tout ce qu'on voit. Ce choix interdit d'acheter sa crédibilité en surinvestissant un seul poste — la leçon la plus utile du jeu sur la répartition d'un budget.
| type de scène | jeu | image | son | credibilite | intention |
|---|---|---|---|---|---|
| dialogue intime, 2 personnes, cuisine | 45 | 15 | 20 | 5 | 15 |
| scène de foule d'époque | 10 | 25 | 5 | 45 | 15 |
| poursuite / cascade | 10 | 30 | 5 | 40 | 15 |
| plan de coupe / raccord | 0 | 50 | 10 | 30 | 10 |
| scène 47 | 25 | 25 | 10 | 25 | 15 |
Le son à 10 alors que la pluie détruit le son direct est délibéré : la pondération dit ce qui compte à l'écran, pas ce qui est difficile — qui surinvestit le son ici gaspille. seuilCritique de la 47 : { credibilite: 45, image: 40 }.
6. L'importance narrative — et le désaccord avec le réalisateur
type ImportanceNarrative =
| 'indispensable' // sans elle, le film est incompréhensible
| 'structurante' // sans elle, le film est plus faible mais tient
| 'confortable' // elle enrichit, elle ne porte rien
| 'coupable' // le monteur la coupera de toute façon
type PoidsNarratif = {
importance: ImportanceNarrative
poidsFilm: number // 0..100, contribution à la note finale
arcs: string[] // "deuil-nadia", "theo-grandit"
scenesDependantes: string[] // sceneIds incompréhensibles sans elle
sauvetages: TypeRattrapage[] // §9
}
type PositionRealisateur = {
attachement: Rated // MENT : claimed = ce qu'il dit en réunion,
// actual = ce qu'il défendra vraiment
argument: string // sa phrase, affichée au joueur
scenePreferee: boolean // seulement s'il l'a dit publiquement
reactionSiCoupee: { moralDelta: number; confianceDelta: number; eventDefId?: string }
monnaieDechange: boolean // il la brandit pour obtenir autre chose
}
Décision : le poids narratif est honnête et visible. Ce n'est pas un Rated. Le joueur voit si une scène est indispensable ou coupable — dans la vraie vie, le scénariste et le monteur le savent. Mettre l'incertitude là transformerait chaque arbitrage en pile ou face. L'incertitude est ailleurs, chez le réalisateur : le désaccord EST le jeu.
il y tient (actual haut) | il s'en fiche (actual bas) | |
|---|---|---|
| indispensable / structurante | Pas un choix, un coût. On la tourne, on trouve l'argent ailleurs. Contrainte dure, repère. | Le piège. Il te laisse la couper d'un haussement d'épaules. Le film s'effondre au montage, et il t'en tiendra rigueur : un réalisateur ne se souvient jamais d'avoir dit oui. |
| confortable / coupable | Le choix cornélien, la scène du jeu. 90 000 € pour trois minutes que personne ne regrettera — sauf lui, qui a fait le film pour ça. Négociable contre quoi ? | Le cadeau. Rare, placé après un enchaînement de catastrophes. Le joueur coupe, gagne 2 jours, personne ne dit rien. Récompense, pas remplissage. |
Le mensonge fonctionne dans les deux sens : claimed 25 / actual 90 — « fais comme tu veux », puis il claque la porte trois jours plus tard (moralDelta: -40, et l'équipe le voit) ; claimed 95 / actual 30 — il hurle en réunion pour une scène dont il se fiche (monnaieDechange: true) afin d'obtenir la grue sur la 62, et qui cède ici paie deux fois. confidence_p est nourri par ce que le joueur sait de lui (négociations passées, indiscrétions du scripte, filmographie) ; la révélation est un événement — realisation.attachement.revele — jamais un changement de champ.
7. Le regroupement — pourquoi on ne tourne pas dans l'ordre
Quatre logiques, par poids économique décroissant : par décor (montage/démontage et location repayés à chaque retour) · par comédien (le cachet est journalier : faire venir Marion pour une réplique coûte une journée pleine + transport + défraiement) · par effet jour/nuit (mélanger casse le rythme de l'équipe et déclenche les majorations) · par matériel exceptionnel (grue, groupe, rampe de pluie, cheval : loués à la journée).
type CleRegroupement = {
decorId: string
lieuId: string // le même décor peut exister en studio ET en réel
moment: Moment; effet?: Effet
rolesPresents: string[] // -> coût de journée comédien
materielLourd: string[] // elementIds loués à la journée
postesExceptionnels: Poste[] // 'cascades' | 'animaux' | 'sfx' | 'enfants'
zoneGeo: string // frais de déplacement, temps de route
}
type CoutsDeRegroupement = {
montageDecor_eur: number // payé À CHAQUE arrivée dans le décor
montageDecor_ticks: number; demontage_ticks: number
retourLieu_eur: number // transport équipe + matériel
penaliteRaccord: number // 0..100 retirés à `credibilite`
fenetreRaccord_ticks: number // au-delà : risque de faux raccord
}
type ContrainteOrdre = {
cible: string // sceneId
relation: 'avant' | 'apres' | 'meme-jour' | 'jamais-meme-jour'
raison: string // "la ferme brûle scène 71"
dur: boolean // false = pénalité, true = interdit
}
Le raccord rend le regroupement non trivial. raccordAvec liste les scènes dont la continuité doit tenir : costume, état de maquillage, météo, feuillage, barbe. Au-delà de fenetreRaccord_ticks d'écart, le moteur émet continuite.raccord.risque et applique penaliteRaccord à credibilite. La 47 est en raccord avec la 46 et la 48 (Nadia rentre, arcade ouverte) : les trois doivent tenir dans la même semaine, boue comprise. L'écran de plan de travail affiche pour chaque regroupement candidat :
gain_eur = Σ montageDecor_eur évités
+ Σ (journées comédien économisées × tarif journalier)
+ Σ (journées matériel économisées × tarif)
− Σ penaliteRaccord convertie en coût de retournage attendu
− coût des reports en cascade
Le moteur propose, il ne décide pas. Un mauvais regroupement n'est jamais interdit : il est cher, et la facture arrive plus tard. Même signature de design que le dépouillement.
8. SceneState — l'état runtime
type StatutScene =
| 'non-depouillee' | 'depouillee' | 'budgetee' | 'planifiee' | 'en-cours'
| 'tournee' | 'a-retourner'
| 'coupee' // décision assumée : budget libéré, trou géré en amont
| 'abandonnee' // JAMAIS tournée faute de moyens : trou subi, argent déjà dépensé
type SceneState = InstanceBase & {
statut: StatutScene
depouillement: {
attemptIds: string[]; score?: BreakdownScore
surprisesLatentes: string[] // NON exposé au client
surprisesSurvenues: string[]
}
budget: {
alloue_eur: number; engage_eur: number; depense_eur: number
parChapitre: Record<number, number> // chapitres 1..10, contrat §6
depassement_eur: number // peut être négatif
}
planification: { dayIds: string[]; ticksAlloues: number; ticksConsommes: number
reports: number }
couverture: {
shotIds: string[]; plansPrevus: number; plansTournes: number
couverture_p: number // pondérée par l'importance des plans
manquants: string[] // "gros plan Théo", "raccord chute"
}
qualite: {
parCritere: Partial<Record<Critere, number>>
note: number // Σ critère × pondération / 100
calculeeAuTick?: Tick
plafonds: { critere: Critere; cause: string; valeur: number }[]
}
incidents: string[] // eventIds
}
coupee et abandonnee ne sont pas cosmétiquement distincts : coupee libère le budget engagé et ouvre les rattrapages en amont ; abandonnee survient en fin de tournage, l'argent est parti, le rattrapage se paiera en post, plus cher (§9).
| événement | transition | effet |
|---|---|---|
depouillement.scene.soumis | non-depouillee → depouillee | crée les SurpriseLatente |
budget.scene.arbitree | → budgetee | engage alloue_eur par chapitre |
planning.scene.calee | → planifiee | rattache des dayIds |
planning.scene.reportee | planifiee → planifiee | reports++, recalcule les raccords |
tournage.scene.ouverte | → en-cours | vérifie les exigences bloquant |
tournage.plan.tourne | — | pousse un shotId, recalcule couverture_p |
tournage.besoin.surgi | — | pousse dans surprisesSurvenues |
tournage.scene.bouclee | → tournee | fige qualite |
montage.scene.rejetee | tournee → a-retourner | ouvre un devis de retournage |
production.scene.coupee | * → coupee | libère alloue_eur − engage_eur |
tournage.scene.abandonnee | → abandonnee | crée un TrouNarratif |
9. Scène → film
noteFilm = Σ (scene.qualite.note × poidsFilm) / Σ poidsFilm − Σ gravite(trous non rattrapés) + termeRythme
termeRythme est le critère écarté du §5, remis à son juste niveau : il se calcule sur la distribution de couverture_p. Un film dont toutes les scènes sont couvertes se monte bien ; un film où 30 % des scènes ont 4 plans au lieu de 11 est mou, quelle que soit la qualité des plans. Formule de travail : termeRythme = 15 × (moyenne(couverture_p) − 0.75), borné à ±10.
type TrouNarratif = {
sceneId: string
cause: 'coupee' | 'abandonnee' | 'inutilisable'
gravite: number // 0..100, dérivé de poidsFilm + scenesDependantes
rattrapages: Rattrapage[]; comble_p: number
}
type TypeRattrapage = 'ellipse-assumee' | 'plan-de-coupe' | 'carton' | 'voix-off'
| 'replique-ajoutee' | 'remontage' | 'reshoot'
type Rattrapage = {
type: TypeRattrapage
cout_eur: number; cout_ticks: number
efficacite_p: number // fraction du trou comblée
effetsSecondaires: string[]
prerequis?: string[] // "comédiens disponibles", "avant le mixage"
}
| rattrapage | coût | efficacité | effet secondaire |
|---|---|---|---|
ellipse-assumee | 0 € | 1.0 si gravite < 30, sinon 0.1 | +3 intention si la scène était coupable : le film est plus serré |
plan-de-coupe | 800 € | 0.25 | aucun |
carton | 300 € | 0.4 | −5 intention sur le film |
voix-off | 4 000 € (1 j studio + réécriture) | 0.6 | −15 intention : « le film s'explique ». Le réalisateur s'y oppose (moralDelta: -25) |
replique-ajoutee | 2 500 € (post-synchro) | 0.35 | exige le comédien disponible |
remontage | 6 000 € + 4 ticks | 0.5 | peut dégrader d'autres scènes |
reshoot | 25 000–80 000 € | 0.95 | comédiens + décor + avant le mixage. Souvent impossible — et c'est le sens du jeu |
C'est un vrai sous-jeu de fin de partie : trois trous, 18 000 € d'imprévus restants. La voix off sauve le film et abîme l'œuvre. L'ellipse est gratuite et ne marche que si la scène était vraiment coupable — c'est-à-dire si le joueur a coupé la bonne. Une partie où l'on a sacrifié les scènes coupable finit sur un film plus court et meilleur ; une partie où l'on a sacrifié une scène indispensable que le réalisateur laissait partir finit sur une voix off.
10. Édition dans le backoffice
Import. Trois entrées, une sortie : des SceneDef en authoring.status: 'draft'. .fountain (format canonique : sluglines, personnages, didascalies) · .fdx (idem, via les types d'éléments XML) · .pdf (couche texte ; la pagination réelle rend pages/huitiemes fiables ; personnages par heuristique de centrage). Le parser de slugline est une regex unique qui doit échouer bruyamment :
^(?<numero>\d+[A-Za-z]*)\.?\s+(?<ie>INT\.|EXT\.|INT\.?/EXT\.)\s+
(?<decor>.+?)\s+[—–-]\s+(?<moment>JOUR|NUIT|AUBE|CRÉPUSCULE|MAGIC HOUR|…)$
decor est ensuite rapproché du catalogue d'éléments par distance de chaîne ; l'auteur valide ou crée. C'est le seul écran d'import qui demande une décision humaine — une par décor, pas une par scène.
L'écran de dépouillement de l'auteur est exactement le même composant que celui du joueur, avec un mode :
type ModeDepouillement =
| 'verite' // l'auteur pose les BreakdownItem : quantité, criticité, note pédagogique
| 'joueur' // partie : surlignage à l'aveugle
| 'diff' // correction ET playtest : vérité en aplat, tentative en contour,
// manques clignotants
Le mode diff rend l'atelier viable : l'auteur rejoue sa scène en joueur, voit ce qu'il rate lui-même, corrige evident_p. Dès que la télémétrie de parties réelles existe, evident_p est remplacé par la mesure et la valeur d'auteur redevient une simple amorce.
Génération assistée. Une passe LLM propose des BreakdownItem (spans, poste, quantité). Règle non négociable : un item proposé naît en llm-propose et n'entre pas dans la vérité avant acceptation (llm-valide). Le modèle est bon sur les besoins littéraux (tracteur, cheval, figurants) et mauvais sur exactement ce qui fait l'intérêt du jeu (« pieds nus dans la boue » → chaufferettes et médecin). Le taux d'acceptation par poste est affiché : il dit à l'auteur où travailler à la main.
Lint (scene.lint), à chaque sauvegarde : Σ ponderation ≠ 100 · un personnage jamais nommé dans texte (ou l'inverse) · un nom propre en capitales sans item ni personnage · une ExigenceElement pointant un elementId absent du catalogue · un bloquant sans exigence de poste correspondante · texteHash périmé · effet: 'magic-hour' avec plus d'un tick estimé sans dureeUtile_min · une scène indispensable avec sauvetages: [] (c'est peut-être voulu, il faut le dire).
11. Questions ouvertes
- Réancrage des spans après réécriture. Le scénario réécrit en cours de partie (
realisation.scenario.reecrit) est un excellent événement et un cauchemar de modèle. Offsets + réancrage littéral, ou ancres floues (contexte gauche/droite + empreinte), plus robustes et plus lourdes ? Et fait-on repayer au joueur le dépouillement des scènes modifiées — réaliste, peut-être insupportable ? - Dépouiller 120 scènes : jeu ou corvée ? (a) tout dépouiller ; (b) l'auteur marque ~25 scènes « à enjeu », le reste est auto-dépouillé ; (c) délégation au 1er assistant contre du temps et une couverture plafonnée à 70 %. Préférence pour (c) — une décision de jeu plutôt qu'une amputation de contenu — mais non testé.
evident_pdoit-il entrer dans le barème ? Tranché non (§3.3). L'argument inverse tient : ne pas pondérer, c'est noter durement un joueur sur des pièges volontaires, et la note est ce qu'il regarde.- Le faux positif coûte-t-il autre chose que de l'argent ? Commander trois chevaux pour une scène à un cheval devrait entamer la confiance de la régie — mais un malus de réputation risque de tuer le surlignage large, qui est le bon réflexe d'apprentissage.
- Le poids narratif doit-il rester honnête ? Tranché oui (§6). Une variante « avis du monteur » en
Rated— le monteur se trompe — serait plus cruelle et plus fidèle au métier ; à prototyper en mode difficile, pas en défaut. rythmeau niveau scène : vraiment inexistant ? Une scène peut être molle en soi (trop de prises, comédiens fatigués, découpage paresseux) sans que la couverture le dise. Le réintroduire oblige à retirer autre chose : cinq critères est un maximum ergonomique.- Tick vs scènes courtes. Un tick = une demi-journée, mais on tourne parfois six scènes courtes dedans. Répartir qualité, incidents et dépassement comment ? Sous-diviser le tick trahit le contrat ; imputer au prorata de
dureeEcranEstimee_sest faux — une scène courte peut manger la matinée. - La scène est-elle une unité de budget, ou seulement de besoin ? Le devis est par chapitre (contrat §6).
SceneState.budgetest-il une donnée de premier ordre, ou une vue calculée par imputation desBudgetLine? La vue est plus juste comptablement, la donnée infiniment plus lisible pour un joueur qui veut savoir « combien m'a coûté la 47 ». À trancher avant d'écrire le réducteur budgétaire.