Initial commit: Couple matters documentation + PowerPoint skill
Documentation personnelle complète
- CLAUDE.md : Instructions compactes et enrichies
- personnalités/ : Profils Alexis, Tingting, Ben, Xiaoxiao + TingtingWork.md
- couple_backlog/ : Historique conflits (16-22 octobre 2025)
- conversation_topics/ : Système suivi sujets actifs
- Projects/ : Analyses techniques et projets
- ToRemember/ : Leadership socratique, suivi conversations
- Promesses_à_tenir.md, observations_patterns.md
PowerPoint skill
- .claude/skills/pptx/ : Skill officiel Anthropic (html2pptx)
- Identité visuelle Tingting : Bordeaux + Or antique + Crème
- Exemple : personnalités/Tingting_Class73_Elegant.pptx
Organisation
- planning/, stratégie/, topics/, plan_discussion/
- .gitignore : node_modules, *.pptx (sauf personnalités/), HTML/JS temp
🎯 Repo propre : 129 fichiers essentiels, 0 dependencies
This commit is contained in:
commit
f5aa93bcbd
30
.claude/skills/pptx/LICENSE.txt
Normal file
30
.claude/skills/pptx/LICENSE.txt
Normal file
@ -0,0 +1,30 @@
|
||||
© 2025 Anthropic, PBC. All rights reserved.
|
||||
|
||||
LICENSE: Use of these materials (including all code, prompts, assets, files,
|
||||
and other components of this Skill) is governed by your agreement with
|
||||
Anthropic regarding use of Anthropic's services. If no separate agreement
|
||||
exists, use is governed by Anthropic's Consumer Terms of Service or
|
||||
Commercial Terms of Service, as applicable:
|
||||
https://www.anthropic.com/legal/consumer-terms
|
||||
https://www.anthropic.com/legal/commercial-terms
|
||||
Your applicable agreement is referred to as the "Agreement." "Services" are
|
||||
as defined in the Agreement.
|
||||
|
||||
ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the
|
||||
contrary, users may not:
|
||||
|
||||
- Extract these materials from the Services or retain copies of these
|
||||
materials outside the Services
|
||||
- Reproduce or copy these materials, except for temporary copies created
|
||||
automatically during authorized use of the Services
|
||||
- Create derivative works based on these materials
|
||||
- Distribute, sublicense, or transfer these materials to any third party
|
||||
- Make, offer to sell, sell, or import any inventions embodied in these
|
||||
materials
|
||||
- Reverse engineer, decompile, or disassemble these materials
|
||||
|
||||
The receipt, viewing, or possession of these materials does not convey or
|
||||
imply any license or right beyond those expressly granted above.
|
||||
|
||||
Anthropic retains all right, title, and interest in these materials,
|
||||
including all copyrights, patents, and other intellectual property rights.
|
||||
60
.claude/skills/pptx/README.md
Normal file
60
.claude/skills/pptx/README.md
Normal file
@ -0,0 +1,60 @@
|
||||
# PowerPoint (PPTX) Skill - Installation complète
|
||||
|
||||
## Installation effectuée le 23 octobre 2025
|
||||
|
||||
### Fichiers installés
|
||||
- ✓ SKILL.md (25K) - Instructions principales
|
||||
- ✓ html2pptx.md - Documentation HTML vers PPTX
|
||||
- ✓ ooxml.md - Documentation format Office Open XML
|
||||
- ✓ scripts/ - Scripts Python et Node.js
|
||||
- ✓ ooxml/ - Schémas et scripts OOXML
|
||||
|
||||
### Dépendances Python installées
|
||||
- ✓ markitdown (0.1.3) - Conversion PPTX vers Markdown
|
||||
- ✓ Pillow - Manipulation d'images
|
||||
- ✓ lxml - Parsing XML
|
||||
- ✓ python-pptx - Bibliothèque PowerPoint
|
||||
|
||||
### Dépendances Node.js installées
|
||||
- ✓ pptxgenjs - Génération PowerPoint
|
||||
- ✓ playwright + chromium - Rendu HTML
|
||||
- ✓ sharp - Traitement d'images
|
||||
|
||||
### Utilisation
|
||||
|
||||
Le skill est automatiquement détecté par Claude Code quand tu demandes :
|
||||
- "Crée une présentation PowerPoint sur..."
|
||||
- "Modifie cette présentation..."
|
||||
- "Analyse ce fichier PPTX..."
|
||||
|
||||
Tu peux aussi l'invoquer explicitement avec `/pptx`
|
||||
|
||||
### Capacités
|
||||
|
||||
1. **Création de présentations** (3 méthodes)
|
||||
- Depuis zéro avec html2pptx
|
||||
- Depuis un template existant
|
||||
- Modification d'une présentation existante
|
||||
|
||||
2. **Analyse de présentations**
|
||||
- Extraction de texte via markitdown
|
||||
- Création de thumbnails
|
||||
- Inventaire du contenu
|
||||
|
||||
3. **Édition avancée**
|
||||
- Modification du XML OOXML brut
|
||||
- Réarrangement de slides
|
||||
- Remplacement de contenu
|
||||
|
||||
### Scripts disponibles
|
||||
|
||||
- `scripts/html2pptx.js` - Convertir HTML vers PPTX
|
||||
- `scripts/thumbnail.py` - Générer grilles de vignettes
|
||||
- `scripts/inventory.py` - Extraire inventaire de texte
|
||||
- `scripts/replace.py` - Remplacer texte dans slides
|
||||
- `scripts/rearrange.py` - Réorganiser slides
|
||||
|
||||
### License
|
||||
Proprietary - Voir LICENSE.txt
|
||||
Source-available (non open source)
|
||||
Fourni par Anthropic comme référence
|
||||
484
.claude/skills/pptx/SKILL.md
Normal file
484
.claude/skills/pptx/SKILL.md
Normal file
@ -0,0 +1,484 @@
|
||||
---
|
||||
name: pptx
|
||||
description: "Presentation creation, editing, and analysis. When Claude needs to work with presentations (.pptx files) for: (1) Creating new presentations, (2) Modifying or editing content, (3) Working with layouts, (4) Adding comments or speaker notes, or any other presentation tasks"
|
||||
license: Proprietary. LICENSE.txt has complete terms
|
||||
---
|
||||
|
||||
# PPTX creation, editing, and analysis
|
||||
|
||||
## Overview
|
||||
|
||||
A user may ask you to create, edit, or analyze the contents of a .pptx file. A .pptx file is essentially a ZIP archive containing XML files and other resources that you can read or edit. You have different tools and workflows available for different tasks.
|
||||
|
||||
## Reading and analyzing content
|
||||
|
||||
### Text extraction
|
||||
If you just need to read the text contents of a presentation, you should convert the document to markdown:
|
||||
|
||||
```bash
|
||||
# Convert document to markdown
|
||||
python -m markitdown path-to-file.pptx
|
||||
```
|
||||
|
||||
### Raw XML access
|
||||
You need raw XML access for: comments, speaker notes, slide layouts, animations, design elements, and complex formatting. For any of these features, you'll need to unpack a presentation and read its raw XML contents.
|
||||
|
||||
#### Unpacking a file
|
||||
`python ooxml/scripts/unpack.py <office_file> <output_dir>`
|
||||
|
||||
**Note**: The unpack.py script is located at `skills/pptx/ooxml/scripts/unpack.py` relative to the project root. If the script doesn't exist at this path, use `find . -name "unpack.py"` to locate it.
|
||||
|
||||
#### Key file structures
|
||||
* `ppt/presentation.xml` - Main presentation metadata and slide references
|
||||
* `ppt/slides/slide{N}.xml` - Individual slide contents (slide1.xml, slide2.xml, etc.)
|
||||
* `ppt/notesSlides/notesSlide{N}.xml` - Speaker notes for each slide
|
||||
* `ppt/comments/modernComment_*.xml` - Comments for specific slides
|
||||
* `ppt/slideLayouts/` - Layout templates for slides
|
||||
* `ppt/slideMasters/` - Master slide templates
|
||||
* `ppt/theme/` - Theme and styling information
|
||||
* `ppt/media/` - Images and other media files
|
||||
|
||||
#### Typography and color extraction
|
||||
**When given an example design to emulate**: Always analyze the presentation's typography and colors first using the methods below:
|
||||
1. **Read theme file**: Check `ppt/theme/theme1.xml` for colors (`<a:clrScheme>`) and fonts (`<a:fontScheme>`)
|
||||
2. **Sample slide content**: Examine `ppt/slides/slide1.xml` for actual font usage (`<a:rPr>`) and colors
|
||||
3. **Search for patterns**: Use grep to find color (`<a:solidFill>`, `<a:srgbClr>`) and font references across all XML files
|
||||
|
||||
## Creating a new PowerPoint presentation **without a template**
|
||||
|
||||
When creating a new PowerPoint presentation from scratch, use the **html2pptx** workflow to convert HTML slides to PowerPoint with accurate positioning.
|
||||
|
||||
### Design Principles
|
||||
|
||||
**CRITICAL**: Before creating any presentation, analyze the content and choose appropriate design elements:
|
||||
1. **Consider the subject matter**: What is this presentation about? What tone, industry, or mood does it suggest?
|
||||
2. **Check for branding**: If the user mentions a company/organization, consider their brand colors and identity
|
||||
3. **Match palette to content**: Select colors that reflect the subject
|
||||
4. **State your approach**: Explain your design choices before writing code
|
||||
|
||||
**Requirements**:
|
||||
- ✅ State your content-informed design approach BEFORE writing code
|
||||
- ✅ Use web-safe fonts only: Arial, Helvetica, Times New Roman, Georgia, Courier New, Verdana, Tahoma, Trebuchet MS, Impact
|
||||
- ✅ Create clear visual hierarchy through size, weight, and color
|
||||
- ✅ Ensure readability: strong contrast, appropriately sized text, clean alignment
|
||||
- ✅ Be consistent: repeat patterns, spacing, and visual language across slides
|
||||
|
||||
#### Color Palette Selection
|
||||
|
||||
**Choosing colors creatively**:
|
||||
- **Think beyond defaults**: What colors genuinely match this specific topic? Avoid autopilot choices.
|
||||
- **Consider multiple angles**: Topic, industry, mood, energy level, target audience, brand identity (if mentioned)
|
||||
- **Be adventurous**: Try unexpected combinations - a healthcare presentation doesn't have to be green, finance doesn't have to be navy
|
||||
- **Build your palette**: Pick 3-5 colors that work together (dominant colors + supporting tones + accent)
|
||||
- **Ensure contrast**: Text must be clearly readable on backgrounds
|
||||
|
||||
**Example color palettes** (use these to spark creativity - choose one, adapt it, or create your own):
|
||||
|
||||
1. **Classic Blue**: Deep navy (#1C2833), slate gray (#2E4053), silver (#AAB7B8), off-white (#F4F6F6)
|
||||
2. **Teal & Coral**: Teal (#5EA8A7), deep teal (#277884), coral (#FE4447), white (#FFFFFF)
|
||||
3. **Bold Red**: Red (#C0392B), bright red (#E74C3C), orange (#F39C12), yellow (#F1C40F), green (#2ECC71)
|
||||
4. **Warm Blush**: Mauve (#A49393), blush (#EED6D3), rose (#E8B4B8), cream (#FAF7F2)
|
||||
5. **Burgundy Luxury**: Burgundy (#5D1D2E), crimson (#951233), rust (#C15937), gold (#997929)
|
||||
6. **Deep Purple & Emerald**: Purple (#B165FB), dark blue (#181B24), emerald (#40695B), white (#FFFFFF)
|
||||
7. **Cream & Forest Green**: Cream (#FFE1C7), forest green (#40695B), white (#FCFCFC)
|
||||
8. **Pink & Purple**: Pink (#F8275B), coral (#FF574A), rose (#FF737D), purple (#3D2F68)
|
||||
9. **Lime & Plum**: Lime (#C5DE82), plum (#7C3A5F), coral (#FD8C6E), blue-gray (#98ACB5)
|
||||
10. **Black & Gold**: Gold (#BF9A4A), black (#000000), cream (#F4F6F6)
|
||||
11. **Sage & Terracotta**: Sage (#87A96B), terracotta (#E07A5F), cream (#F4F1DE), charcoal (#2C2C2C)
|
||||
12. **Charcoal & Red**: Charcoal (#292929), red (#E33737), light gray (#CCCBCB)
|
||||
13. **Vibrant Orange**: Orange (#F96D00), light gray (#F2F2F2), charcoal (#222831)
|
||||
14. **Forest Green**: Black (#191A19), green (#4E9F3D), dark green (#1E5128), white (#FFFFFF)
|
||||
15. **Retro Rainbow**: Purple (#722880), pink (#D72D51), orange (#EB5C18), amber (#F08800), gold (#DEB600)
|
||||
16. **Vintage Earthy**: Mustard (#E3B448), sage (#CBD18F), forest green (#3A6B35), cream (#F4F1DE)
|
||||
17. **Coastal Rose**: Old rose (#AD7670), beaver (#B49886), eggshell (#F3ECDC), ash gray (#BFD5BE)
|
||||
18. **Orange & Turquoise**: Light orange (#FC993E), grayish turquoise (#667C6F), white (#FCFCFC)
|
||||
|
||||
#### Visual Details Options
|
||||
|
||||
**Geometric Patterns**:
|
||||
- Diagonal section dividers instead of horizontal
|
||||
- Asymmetric column widths (30/70, 40/60, 25/75)
|
||||
- Rotated text headers at 90° or 270°
|
||||
- Circular/hexagonal frames for images
|
||||
- Triangular accent shapes in corners
|
||||
- Overlapping shapes for depth
|
||||
|
||||
**Border & Frame Treatments**:
|
||||
- Thick single-color borders (10-20pt) on one side only
|
||||
- Double-line borders with contrasting colors
|
||||
- Corner brackets instead of full frames
|
||||
- L-shaped borders (top+left or bottom+right)
|
||||
- Underline accents beneath headers (3-5pt thick)
|
||||
|
||||
**Typography Treatments**:
|
||||
- Extreme size contrast (72pt headlines vs 11pt body)
|
||||
- All-caps headers with wide letter spacing
|
||||
- Numbered sections in oversized display type
|
||||
- Monospace (Courier New) for data/stats/technical content
|
||||
- Condensed fonts (Arial Narrow) for dense information
|
||||
- Outlined text for emphasis
|
||||
|
||||
**Chart & Data Styling**:
|
||||
- Monochrome charts with single accent color for key data
|
||||
- Horizontal bar charts instead of vertical
|
||||
- Dot plots instead of bar charts
|
||||
- Minimal gridlines or none at all
|
||||
- Data labels directly on elements (no legends)
|
||||
- Oversized numbers for key metrics
|
||||
|
||||
**Layout Innovations**:
|
||||
- Full-bleed images with text overlays
|
||||
- Sidebar column (20-30% width) for navigation/context
|
||||
- Modular grid systems (3×3, 4×4 blocks)
|
||||
- Z-pattern or F-pattern content flow
|
||||
- Floating text boxes over colored shapes
|
||||
- Magazine-style multi-column layouts
|
||||
|
||||
**Background Treatments**:
|
||||
- Solid color blocks occupying 40-60% of slide
|
||||
- Gradient fills (vertical or diagonal only)
|
||||
- Split backgrounds (two colors, diagonal or vertical)
|
||||
- Edge-to-edge color bands
|
||||
- Negative space as a design element
|
||||
|
||||
### Layout Tips
|
||||
**When creating slides with charts or tables:**
|
||||
- **Two-column layout (PREFERRED)**: Use a header spanning the full width, then two columns below - text/bullets in one column and the featured content in the other. This provides better balance and makes charts/tables more readable. Use flexbox with unequal column widths (e.g., 40%/60% split) to optimize space for each content type.
|
||||
- **Full-slide layout**: Let the featured content (chart/table) take up the entire slide for maximum impact and readability
|
||||
- **NEVER vertically stack**: Do not place charts/tables below text in a single column - this causes poor readability and layout issues
|
||||
|
||||
### Workflow
|
||||
1. **MANDATORY - READ ENTIRE FILE**: Read [`html2pptx.md`](html2pptx.md) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for detailed syntax, critical formatting rules, and best practices before proceeding with presentation creation.
|
||||
2. Create an HTML file for each slide with proper dimensions (e.g., 720pt × 405pt for 16:9)
|
||||
- Use `<p>`, `<h1>`-`<h6>`, `<ul>`, `<ol>` for all text content
|
||||
- Use `class="placeholder"` for areas where charts/tables will be added (render with gray background for visibility)
|
||||
- **CRITICAL**: Rasterize gradients and icons as PNG images FIRST using Sharp, then reference in HTML
|
||||
- **LAYOUT**: For slides with charts/tables/images, use either full-slide layout or two-column layout for better readability
|
||||
3. Create and run a JavaScript file using the [`html2pptx.js`](scripts/html2pptx.js) library to convert HTML slides to PowerPoint and save the presentation
|
||||
- Use the `html2pptx()` function to process each HTML file
|
||||
- Add charts and tables to placeholder areas using PptxGenJS API
|
||||
- Save the presentation using `pptx.writeFile()`
|
||||
4. **Visual validation**: Generate thumbnails and inspect for layout issues
|
||||
- Create thumbnail grid: `python scripts/thumbnail.py output.pptx workspace/thumbnails --cols 4`
|
||||
- Read and carefully examine the thumbnail image for:
|
||||
- **Text cutoff**: Text being cut off by header bars, shapes, or slide edges
|
||||
- **Text overlap**: Text overlapping with other text or shapes
|
||||
- **Positioning issues**: Content too close to slide boundaries or other elements
|
||||
- **Contrast issues**: Insufficient contrast between text and backgrounds
|
||||
- If issues found, adjust HTML margins/spacing/colors and regenerate the presentation
|
||||
- Repeat until all slides are visually correct
|
||||
|
||||
## Editing an existing PowerPoint presentation
|
||||
|
||||
When edit slides in an existing PowerPoint presentation, you need to work with the raw Office Open XML (OOXML) format. This involves unpacking the .pptx file, editing the XML content, and repacking it.
|
||||
|
||||
### Workflow
|
||||
1. **MANDATORY - READ ENTIRE FILE**: Read [`ooxml.md`](ooxml.md) (~500 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for detailed guidance on OOXML structure and editing workflows before any presentation editing.
|
||||
2. Unpack the presentation: `python ooxml/scripts/unpack.py <office_file> <output_dir>`
|
||||
3. Edit the XML files (primarily `ppt/slides/slide{N}.xml` and related files)
|
||||
4. **CRITICAL**: Validate immediately after each edit and fix any validation errors before proceeding: `python ooxml/scripts/validate.py <dir> --original <file>`
|
||||
5. Pack the final presentation: `python ooxml/scripts/pack.py <input_directory> <office_file>`
|
||||
|
||||
## Creating a new PowerPoint presentation **using a template**
|
||||
|
||||
When you need to create a presentation that follows an existing template's design, you'll need to duplicate and re-arrange template slides before then replacing placeholder context.
|
||||
|
||||
### Workflow
|
||||
1. **Extract template text AND create visual thumbnail grid**:
|
||||
* Extract text: `python -m markitdown template.pptx > template-content.md`
|
||||
* Read `template-content.md`: Read the entire file to understand the contents of the template presentation. **NEVER set any range limits when reading this file.**
|
||||
* Create thumbnail grids: `python scripts/thumbnail.py template.pptx`
|
||||
* See [Creating Thumbnail Grids](#creating-thumbnail-grids) section for more details
|
||||
|
||||
2. **Analyze template and save inventory to a file**:
|
||||
* **Visual Analysis**: Review thumbnail grid(s) to understand slide layouts, design patterns, and visual structure
|
||||
* Create and save a template inventory file at `template-inventory.md` containing:
|
||||
```markdown
|
||||
# Template Inventory Analysis
|
||||
**Total Slides: [count]**
|
||||
**IMPORTANT: Slides are 0-indexed (first slide = 0, last slide = count-1)**
|
||||
|
||||
## [Category Name]
|
||||
- Slide 0: [Layout code if available] - Description/purpose
|
||||
- Slide 1: [Layout code] - Description/purpose
|
||||
- Slide 2: [Layout code] - Description/purpose
|
||||
[... EVERY slide must be listed individually with its index ...]
|
||||
```
|
||||
* **Using the thumbnail grid**: Reference the visual thumbnails to identify:
|
||||
- Layout patterns (title slides, content layouts, section dividers)
|
||||
- Image placeholder locations and counts
|
||||
- Design consistency across slide groups
|
||||
- Visual hierarchy and structure
|
||||
* This inventory file is REQUIRED for selecting appropriate templates in the next step
|
||||
|
||||
3. **Create presentation outline based on template inventory**:
|
||||
* Review available templates from step 2.
|
||||
* Choose an intro or title template for the first slide. This should be one of the first templates.
|
||||
* Choose safe, text-based layouts for the other slides.
|
||||
* **CRITICAL: Match layout structure to actual content**:
|
||||
- Single-column layouts: Use for unified narrative or single topic
|
||||
- Two-column layouts: Use ONLY when you have exactly 2 distinct items/concepts
|
||||
- Three-column layouts: Use ONLY when you have exactly 3 distinct items/concepts
|
||||
- Image + text layouts: Use ONLY when you have actual images to insert
|
||||
- Quote layouts: Use ONLY for actual quotes from people (with attribution), never for emphasis
|
||||
- Never use layouts with more placeholders than you have content
|
||||
- If you have 2 items, don't force them into a 3-column layout
|
||||
- If you have 4+ items, consider breaking into multiple slides or using a list format
|
||||
* Count your actual content pieces BEFORE selecting the layout
|
||||
* Verify each placeholder in the chosen layout will be filled with meaningful content
|
||||
* Select one option representing the **best** layout for each content section.
|
||||
* Save `outline.md` with content AND template mapping that leverages available designs
|
||||
* Example template mapping:
|
||||
```
|
||||
# Template slides to use (0-based indexing)
|
||||
# WARNING: Verify indices are within range! Template with 73 slides has indices 0-72
|
||||
# Mapping: slide numbers from outline -> template slide indices
|
||||
template_mapping = [
|
||||
0, # Use slide 0 (Title/Cover)
|
||||
34, # Use slide 34 (B1: Title and body)
|
||||
34, # Use slide 34 again (duplicate for second B1)
|
||||
50, # Use slide 50 (E1: Quote)
|
||||
54, # Use slide 54 (F2: Closing + Text)
|
||||
]
|
||||
```
|
||||
|
||||
4. **Duplicate, reorder, and delete slides using `rearrange.py`**:
|
||||
* Use the `scripts/rearrange.py` script to create a new presentation with slides in the desired order:
|
||||
```bash
|
||||
python scripts/rearrange.py template.pptx working.pptx 0,34,34,50,52
|
||||
```
|
||||
* The script handles duplicating repeated slides, deleting unused slides, and reordering automatically
|
||||
* Slide indices are 0-based (first slide is 0, second is 1, etc.)
|
||||
* The same slide index can appear multiple times to duplicate that slide
|
||||
|
||||
5. **Extract ALL text using the `inventory.py` script**:
|
||||
* **Run inventory extraction**:
|
||||
```bash
|
||||
python scripts/inventory.py working.pptx text-inventory.json
|
||||
```
|
||||
* **Read text-inventory.json**: Read the entire text-inventory.json file to understand all shapes and their properties. **NEVER set any range limits when reading this file.**
|
||||
|
||||
* The inventory JSON structure:
|
||||
```json
|
||||
{
|
||||
"slide-0": {
|
||||
"shape-0": {
|
||||
"placeholder_type": "TITLE", // or null for non-placeholders
|
||||
"left": 1.5, // position in inches
|
||||
"top": 2.0,
|
||||
"width": 7.5,
|
||||
"height": 1.2,
|
||||
"paragraphs": [
|
||||
{
|
||||
"text": "Paragraph text",
|
||||
// Optional properties (only included when non-default):
|
||||
"bullet": true, // explicit bullet detected
|
||||
"level": 0, // only included when bullet is true
|
||||
"alignment": "CENTER", // CENTER, RIGHT (not LEFT)
|
||||
"space_before": 10.0, // space before paragraph in points
|
||||
"space_after": 6.0, // space after paragraph in points
|
||||
"line_spacing": 22.4, // line spacing in points
|
||||
"font_name": "Arial", // from first run
|
||||
"font_size": 14.0, // in points
|
||||
"bold": true,
|
||||
"italic": false,
|
||||
"underline": false,
|
||||
"color": "FF0000" // RGB color
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* Key features:
|
||||
- **Slides**: Named as "slide-0", "slide-1", etc.
|
||||
- **Shapes**: Ordered by visual position (top-to-bottom, left-to-right) as "shape-0", "shape-1", etc.
|
||||
- **Placeholder types**: TITLE, CENTER_TITLE, SUBTITLE, BODY, OBJECT, or null
|
||||
- **Default font size**: `default_font_size` in points extracted from layout placeholders (when available)
|
||||
- **Slide numbers are filtered**: Shapes with SLIDE_NUMBER placeholder type are automatically excluded from inventory
|
||||
- **Bullets**: When `bullet: true`, `level` is always included (even if 0)
|
||||
- **Spacing**: `space_before`, `space_after`, and `line_spacing` in points (only included when set)
|
||||
- **Colors**: `color` for RGB (e.g., "FF0000"), `theme_color` for theme colors (e.g., "DARK_1")
|
||||
- **Properties**: Only non-default values are included in the output
|
||||
|
||||
6. **Generate replacement text and save the data to a JSON file**
|
||||
Based on the text inventory from the previous step:
|
||||
- **CRITICAL**: First verify which shapes exist in the inventory - only reference shapes that are actually present
|
||||
- **VALIDATION**: The replace.py script will validate that all shapes in your replacement JSON exist in the inventory
|
||||
- If you reference a non-existent shape, you'll get an error showing available shapes
|
||||
- If you reference a non-existent slide, you'll get an error indicating the slide doesn't exist
|
||||
- All validation errors are shown at once before the script exits
|
||||
- **IMPORTANT**: The replace.py script uses inventory.py internally to identify ALL text shapes
|
||||
- **AUTOMATIC CLEARING**: ALL text shapes from the inventory will be cleared unless you provide "paragraphs" for them
|
||||
- Add a "paragraphs" field to shapes that need content (not "replacement_paragraphs")
|
||||
- Shapes without "paragraphs" in the replacement JSON will have their text cleared automatically
|
||||
- Paragraphs with bullets will be automatically left aligned. Don't set the `alignment` property on when `"bullet": true`
|
||||
- Generate appropriate replacement content for placeholder text
|
||||
- Use shape size to determine appropriate content length
|
||||
- **CRITICAL**: Include paragraph properties from the original inventory - don't just provide text
|
||||
- **IMPORTANT**: When bullet: true, do NOT include bullet symbols (•, -, *) in text - they're added automatically
|
||||
- **ESSENTIAL FORMATTING RULES**:
|
||||
- Headers/titles should typically have `"bold": true`
|
||||
- List items should have `"bullet": true, "level": 0` (level is required when bullet is true)
|
||||
- Preserve any alignment properties (e.g., `"alignment": "CENTER"` for centered text)
|
||||
- Include font properties when different from default (e.g., `"font_size": 14.0`, `"font_name": "Lora"`)
|
||||
- Colors: Use `"color": "FF0000"` for RGB or `"theme_color": "DARK_1"` for theme colors
|
||||
- The replacement script expects **properly formatted paragraphs**, not just text strings
|
||||
- **Overlapping shapes**: Prefer shapes with larger default_font_size or more appropriate placeholder_type
|
||||
- Save the updated inventory with replacements to `replacement-text.json`
|
||||
- **WARNING**: Different template layouts have different shape counts - always check the actual inventory before creating replacements
|
||||
|
||||
Example paragraphs field showing proper formatting:
|
||||
```json
|
||||
"paragraphs": [
|
||||
{
|
||||
"text": "New presentation title text",
|
||||
"alignment": "CENTER",
|
||||
"bold": true
|
||||
},
|
||||
{
|
||||
"text": "Section Header",
|
||||
"bold": true
|
||||
},
|
||||
{
|
||||
"text": "First bullet point without bullet symbol",
|
||||
"bullet": true,
|
||||
"level": 0
|
||||
},
|
||||
{
|
||||
"text": "Red colored text",
|
||||
"color": "FF0000"
|
||||
},
|
||||
{
|
||||
"text": "Theme colored text",
|
||||
"theme_color": "DARK_1"
|
||||
},
|
||||
{
|
||||
"text": "Regular paragraph text without special formatting"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Shapes not listed in the replacement JSON are automatically cleared**:
|
||||
```json
|
||||
{
|
||||
"slide-0": {
|
||||
"shape-0": {
|
||||
"paragraphs": [...] // This shape gets new text
|
||||
}
|
||||
// shape-1 and shape-2 from inventory will be cleared automatically
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Common formatting patterns for presentations**:
|
||||
- Title slides: Bold text, sometimes centered
|
||||
- Section headers within slides: Bold text
|
||||
- Bullet lists: Each item needs `"bullet": true, "level": 0`
|
||||
- Body text: Usually no special properties needed
|
||||
- Quotes: May have special alignment or font properties
|
||||
|
||||
7. **Apply replacements using the `replace.py` script**
|
||||
```bash
|
||||
python scripts/replace.py working.pptx replacement-text.json output.pptx
|
||||
```
|
||||
|
||||
The script will:
|
||||
- First extract the inventory of ALL text shapes using functions from inventory.py
|
||||
- Validate that all shapes in the replacement JSON exist in the inventory
|
||||
- Clear text from ALL shapes identified in the inventory
|
||||
- Apply new text only to shapes with "paragraphs" defined in the replacement JSON
|
||||
- Preserve formatting by applying paragraph properties from the JSON
|
||||
- Handle bullets, alignment, font properties, and colors automatically
|
||||
- Save the updated presentation
|
||||
|
||||
Example validation errors:
|
||||
```
|
||||
ERROR: Invalid shapes in replacement JSON:
|
||||
- Shape 'shape-99' not found on 'slide-0'. Available shapes: shape-0, shape-1, shape-4
|
||||
- Slide 'slide-999' not found in inventory
|
||||
```
|
||||
|
||||
```
|
||||
ERROR: Replacement text made overflow worse in these shapes:
|
||||
- slide-0/shape-2: overflow worsened by 1.25" (was 0.00", now 1.25")
|
||||
```
|
||||
|
||||
## Creating Thumbnail Grids
|
||||
|
||||
To create visual thumbnail grids of PowerPoint slides for quick analysis and reference:
|
||||
|
||||
```bash
|
||||
python scripts/thumbnail.py template.pptx [output_prefix]
|
||||
```
|
||||
|
||||
**Features**:
|
||||
- Creates: `thumbnails.jpg` (or `thumbnails-1.jpg`, `thumbnails-2.jpg`, etc. for large decks)
|
||||
- Default: 5 columns, max 30 slides per grid (5×6)
|
||||
- Custom prefix: `python scripts/thumbnail.py template.pptx my-grid`
|
||||
- Note: The output prefix should include the path if you want output in a specific directory (e.g., `workspace/my-grid`)
|
||||
- Adjust columns: `--cols 4` (range: 3-6, affects slides per grid)
|
||||
- Grid limits: 3 cols = 12 slides/grid, 4 cols = 20, 5 cols = 30, 6 cols = 42
|
||||
- Slides are zero-indexed (Slide 0, Slide 1, etc.)
|
||||
|
||||
**Use cases**:
|
||||
- Template analysis: Quickly understand slide layouts and design patterns
|
||||
- Content review: Visual overview of entire presentation
|
||||
- Navigation reference: Find specific slides by their visual appearance
|
||||
- Quality check: Verify all slides are properly formatted
|
||||
|
||||
**Examples**:
|
||||
```bash
|
||||
# Basic usage
|
||||
python scripts/thumbnail.py presentation.pptx
|
||||
|
||||
# Combine options: custom name, columns
|
||||
python scripts/thumbnail.py template.pptx analysis --cols 4
|
||||
```
|
||||
|
||||
## Converting Slides to Images
|
||||
|
||||
To visually analyze PowerPoint slides, convert them to images using a two-step process:
|
||||
|
||||
1. **Convert PPTX to PDF**:
|
||||
```bash
|
||||
soffice --headless --convert-to pdf template.pptx
|
||||
```
|
||||
|
||||
2. **Convert PDF pages to JPEG images**:
|
||||
```bash
|
||||
pdftoppm -jpeg -r 150 template.pdf slide
|
||||
```
|
||||
This creates files like `slide-1.jpg`, `slide-2.jpg`, etc.
|
||||
|
||||
Options:
|
||||
- `-r 150`: Sets resolution to 150 DPI (adjust for quality/size balance)
|
||||
- `-jpeg`: Output JPEG format (use `-png` for PNG if preferred)
|
||||
- `-f N`: First page to convert (e.g., `-f 2` starts from page 2)
|
||||
- `-l N`: Last page to convert (e.g., `-l 5` stops at page 5)
|
||||
- `slide`: Prefix for output files
|
||||
|
||||
Example for specific range:
|
||||
```bash
|
||||
pdftoppm -jpeg -r 150 -f 2 -l 5 template.pdf slide # Converts only pages 2-5
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
**IMPORTANT**: When generating code for PPTX operations:
|
||||
- Write concise code
|
||||
- Avoid verbose variable names and redundant operations
|
||||
- Avoid unnecessary print statements
|
||||
|
||||
## Dependencies
|
||||
|
||||
Required dependencies (should already be installed):
|
||||
|
||||
- **markitdown**: `pip install "markitdown[pptx]"` (for text extraction from presentations)
|
||||
- **pptxgenjs**: `npm install -g pptxgenjs` (for creating presentations via html2pptx)
|
||||
- **playwright**: `npm install -g playwright` (for HTML rendering in html2pptx)
|
||||
- **react-icons**: `npm install -g react-icons react react-dom` (for icons)
|
||||
- **sharp**: `npm install -g sharp` (for SVG rasterization and image processing)
|
||||
- **LibreOffice**: `sudo apt-get install libreoffice` (for PDF conversion)
|
||||
- **Poppler**: `sudo apt-get install poppler-utils` (for pdftoppm to convert PDF to images)
|
||||
- **defusedxml**: `pip install defusedxml` (for secure XML parsing)
|
||||
625
.claude/skills/pptx/html2pptx.md
Normal file
625
.claude/skills/pptx/html2pptx.md
Normal file
@ -0,0 +1,625 @@
|
||||
# HTML to PowerPoint Guide
|
||||
|
||||
Convert HTML slides to PowerPoint presentations with accurate positioning using the `html2pptx.js` library.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Creating HTML Slides](#creating-html-slides)
|
||||
2. [Using the html2pptx Library](#using-the-html2pptx-library)
|
||||
3. [Using PptxGenJS](#using-pptxgenjs)
|
||||
|
||||
---
|
||||
|
||||
## Creating HTML Slides
|
||||
|
||||
Every HTML slide must include proper body dimensions:
|
||||
|
||||
### Layout Dimensions
|
||||
|
||||
- **16:9** (default): `width: 720pt; height: 405pt`
|
||||
- **4:3**: `width: 720pt; height: 540pt`
|
||||
- **16:10**: `width: 720pt; height: 450pt`
|
||||
|
||||
### Supported Elements
|
||||
|
||||
- `<p>`, `<h1>`-`<h6>` - Text with styling
|
||||
- `<ul>`, `<ol>` - Lists (never use manual bullets •, -, *)
|
||||
- `<b>`, `<strong>` - Bold text (inline formatting)
|
||||
- `<i>`, `<em>` - Italic text (inline formatting)
|
||||
- `<u>` - Underlined text (inline formatting)
|
||||
- `<span>` - Inline formatting with CSS styles (bold, italic, underline, color)
|
||||
- `<br>` - Line breaks
|
||||
- `<div>` with bg/border - Becomes shape
|
||||
- `<img>` - Images
|
||||
- `class="placeholder"` - Reserved space for charts (returns `{ id, x, y, w, h }`)
|
||||
|
||||
### Critical Text Rules
|
||||
|
||||
**ALL text MUST be inside `<p>`, `<h1>`-`<h6>`, `<ul>`, or `<ol>` tags:**
|
||||
- ✅ Correct: `<div><p>Text here</p></div>`
|
||||
- ❌ Wrong: `<div>Text here</div>` - **Text will NOT appear in PowerPoint**
|
||||
- ❌ Wrong: `<span>Text</span>` - **Text will NOT appear in PowerPoint**
|
||||
- Text in `<div>` or `<span>` without a text tag will be silently ignored
|
||||
|
||||
**NEVER use manual bullet symbols (•, -, *, etc.)** - Use `<ul>` or `<ol>` lists instead
|
||||
|
||||
**ONLY use web-safe fonts that are universally available:**
|
||||
- ✅ Web-safe fonts: `Arial`, `Helvetica`, `Times New Roman`, `Georgia`, `Courier New`, `Verdana`, `Tahoma`, `Trebuchet MS`, `Impact`, `Comic Sans MS`
|
||||
- ❌ Wrong: `'Segoe UI'`, `'SF Pro'`, `'Roboto'`, custom fonts - **Might cause rendering issues**
|
||||
|
||||
### Styling
|
||||
|
||||
- Use `display: flex` on body to prevent margin collapse from breaking overflow validation
|
||||
- Use `margin` for spacing (padding included in size)
|
||||
- Inline formatting: Use `<b>`, `<i>`, `<u>` tags OR `<span>` with CSS styles
|
||||
- `<span>` supports: `font-weight: bold`, `font-style: italic`, `text-decoration: underline`, `color: #rrggbb`
|
||||
- `<span>` does NOT support: `margin`, `padding` (not supported in PowerPoint text runs)
|
||||
- Example: `<span style="font-weight: bold; color: #667eea;">Bold blue text</span>`
|
||||
- Flexbox works - positions calculated from rendered layout
|
||||
- Use hex colors with `#` prefix in CSS
|
||||
- **Text alignment**: Use CSS `text-align` (`center`, `right`, etc.) when needed as a hint to PptxGenJS for text formatting if text lengths are slightly off
|
||||
|
||||
### Shape Styling (DIV elements only)
|
||||
|
||||
**IMPORTANT: Backgrounds, borders, and shadows only work on `<div>` elements, NOT on text elements (`<p>`, `<h1>`-`<h6>`, `<ul>`, `<ol>`)**
|
||||
|
||||
- **Backgrounds**: CSS `background` or `background-color` on `<div>` elements only
|
||||
- Example: `<div style="background: #f0f0f0;">` - Creates a shape with background
|
||||
- **Borders**: CSS `border` on `<div>` elements converts to PowerPoint shape borders
|
||||
- Supports uniform borders: `border: 2px solid #333333`
|
||||
- Supports partial borders: `border-left`, `border-right`, `border-top`, `border-bottom` (rendered as line shapes)
|
||||
- Example: `<div style="border-left: 8pt solid #E76F51;">`
|
||||
- **Border radius**: CSS `border-radius` on `<div>` elements for rounded corners
|
||||
- `border-radius: 50%` or higher creates circular shape
|
||||
- Percentages <50% calculated relative to shape's smaller dimension
|
||||
- Supports px and pt units (e.g., `border-radius: 8pt;`, `border-radius: 12px;`)
|
||||
- Example: `<div style="border-radius: 25%;">` on 100x200px box = 25% of 100px = 25px radius
|
||||
- **Box shadows**: CSS `box-shadow` on `<div>` elements converts to PowerPoint shadows
|
||||
- Supports outer shadows only (inset shadows are ignored to prevent corruption)
|
||||
- Example: `<div style="box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);">`
|
||||
- Note: Inset/inner shadows are not supported by PowerPoint and will be skipped
|
||||
|
||||
### Icons & Gradients
|
||||
|
||||
- **CRITICAL: Never use CSS gradients (`linear-gradient`, `radial-gradient`)** - They don't convert to PowerPoint
|
||||
- **ALWAYS create gradient/icon PNGs FIRST using Sharp, then reference in HTML**
|
||||
- For gradients: Rasterize SVG to PNG background images
|
||||
- For icons: Rasterize react-icons SVG to PNG images
|
||||
- All visual effects must be pre-rendered as raster images before HTML rendering
|
||||
|
||||
**Rasterizing Icons with Sharp:**
|
||||
|
||||
```javascript
|
||||
const React = require('react');
|
||||
const ReactDOMServer = require('react-dom/server');
|
||||
const sharp = require('sharp');
|
||||
const { FaHome } = require('react-icons/fa');
|
||||
|
||||
async function rasterizeIconPng(IconComponent, color, size = "256", filename) {
|
||||
const svgString = ReactDOMServer.renderToStaticMarkup(
|
||||
React.createElement(IconComponent, { color: `#${color}`, size: size })
|
||||
);
|
||||
|
||||
// Convert SVG to PNG using Sharp
|
||||
await sharp(Buffer.from(svgString))
|
||||
.png()
|
||||
.toFile(filename);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
// Usage: Rasterize icon before using in HTML
|
||||
const iconPath = await rasterizeIconPng(FaHome, "4472c4", "256", "home-icon.png");
|
||||
// Then reference in HTML: <img src="home-icon.png" style="width: 40pt; height: 40pt;">
|
||||
```
|
||||
|
||||
**Rasterizing Gradients with Sharp:**
|
||||
|
||||
```javascript
|
||||
const sharp = require('sharp');
|
||||
|
||||
async function createGradientBackground(filename) {
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="562.5">
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#COLOR1"/>
|
||||
<stop offset="100%" style="stop-color:#COLOR2"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="url(#g)"/>
|
||||
</svg>`;
|
||||
|
||||
await sharp(Buffer.from(svg))
|
||||
.png()
|
||||
.toFile(filename);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
// Usage: Create gradient background before HTML
|
||||
const bgPath = await createGradientBackground("gradient-bg.png");
|
||||
// Then in HTML: <body style="background-image: url('gradient-bg.png');">
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html { background: #ffffff; }
|
||||
body {
|
||||
width: 720pt; height: 405pt; margin: 0; padding: 0;
|
||||
background: #f5f5f5; font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
}
|
||||
.content { margin: 30pt; padding: 40pt; background: #ffffff; border-radius: 8pt; }
|
||||
h1 { color: #2d3748; font-size: 32pt; }
|
||||
.box {
|
||||
background: #70ad47; padding: 20pt; border: 3px solid #5a8f37;
|
||||
border-radius: 12pt; box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1>Recipe Title</h1>
|
||||
<ul>
|
||||
<li><b>Item:</b> Description</li>
|
||||
</ul>
|
||||
<p>Text with <b>bold</b>, <i>italic</i>, <u>underline</u>.</p>
|
||||
<div id="chart" class="placeholder" style="width: 350pt; height: 200pt;"></div>
|
||||
|
||||
<!-- Text MUST be in <p> tags -->
|
||||
<div class="box">
|
||||
<p>5</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Using the html2pptx Library
|
||||
|
||||
### Dependencies
|
||||
|
||||
These libraries have been globally installed and are available to use:
|
||||
- `pptxgenjs`
|
||||
- `playwright`
|
||||
- `sharp`
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```javascript
|
||||
const pptxgen = require('pptxgenjs');
|
||||
const html2pptx = require('./html2pptx');
|
||||
|
||||
const pptx = new pptxgen();
|
||||
pptx.layout = 'LAYOUT_16x9'; // Must match HTML body dimensions
|
||||
|
||||
const { slide, placeholders } = await html2pptx('slide1.html', pptx);
|
||||
|
||||
// Add chart to placeholder area
|
||||
if (placeholders.length > 0) {
|
||||
slide.addChart(pptx.charts.LINE, chartData, placeholders[0]);
|
||||
}
|
||||
|
||||
await pptx.writeFile('output.pptx');
|
||||
```
|
||||
|
||||
### API Reference
|
||||
|
||||
#### Function Signature
|
||||
```javascript
|
||||
await html2pptx(htmlFile, pres, options)
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
- `htmlFile` (string): Path to HTML file (absolute or relative)
|
||||
- `pres` (pptxgen): PptxGenJS presentation instance with layout already set
|
||||
- `options` (object, optional):
|
||||
- `tmpDir` (string): Temporary directory for generated files (default: `process.env.TMPDIR || '/tmp'`)
|
||||
- `slide` (object): Existing slide to reuse (default: creates new slide)
|
||||
|
||||
#### Returns
|
||||
```javascript
|
||||
{
|
||||
slide: pptxgenSlide, // The created/updated slide
|
||||
placeholders: [ // Array of placeholder positions
|
||||
{ id: string, x: number, y: number, w: number, h: number },
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Validation
|
||||
|
||||
The library automatically validates and collects all errors before throwing:
|
||||
|
||||
1. **HTML dimensions must match presentation layout** - Reports dimension mismatches
|
||||
2. **Content must not overflow body** - Reports overflow with exact measurements
|
||||
3. **CSS gradients** - Reports unsupported gradient usage
|
||||
4. **Text element styling** - Reports backgrounds/borders/shadows on text elements (only allowed on divs)
|
||||
|
||||
**All validation errors are collected and reported together** in a single error message, allowing you to fix all issues at once instead of one at a time.
|
||||
|
||||
### Working with Placeholders
|
||||
|
||||
```javascript
|
||||
const { slide, placeholders } = await html2pptx('slide.html', pptx);
|
||||
|
||||
// Use first placeholder
|
||||
slide.addChart(pptx.charts.BAR, data, placeholders[0]);
|
||||
|
||||
// Find by ID
|
||||
const chartArea = placeholders.find(p => p.id === 'chart-area');
|
||||
slide.addChart(pptx.charts.LINE, data, chartArea);
|
||||
```
|
||||
|
||||
### Complete Example
|
||||
|
||||
```javascript
|
||||
const pptxgen = require('pptxgenjs');
|
||||
const html2pptx = require('./html2pptx');
|
||||
|
||||
async function createPresentation() {
|
||||
const pptx = new pptxgen();
|
||||
pptx.layout = 'LAYOUT_16x9';
|
||||
pptx.author = 'Your Name';
|
||||
pptx.title = 'My Presentation';
|
||||
|
||||
// Slide 1: Title
|
||||
const { slide: slide1 } = await html2pptx('slides/title.html', pptx);
|
||||
|
||||
// Slide 2: Content with chart
|
||||
const { slide: slide2, placeholders } = await html2pptx('slides/data.html', pptx);
|
||||
|
||||
const chartData = [{
|
||||
name: 'Sales',
|
||||
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
||||
values: [4500, 5500, 6200, 7100]
|
||||
}];
|
||||
|
||||
slide2.addChart(pptx.charts.BAR, chartData, {
|
||||
...placeholders[0],
|
||||
showTitle: true,
|
||||
title: 'Quarterly Sales',
|
||||
showCatAxisTitle: true,
|
||||
catAxisTitle: 'Quarter',
|
||||
showValAxisTitle: true,
|
||||
valAxisTitle: 'Sales ($000s)'
|
||||
});
|
||||
|
||||
// Save
|
||||
await pptx.writeFile({ fileName: 'presentation.pptx' });
|
||||
console.log('Presentation created successfully!');
|
||||
}
|
||||
|
||||
createPresentation().catch(console.error);
|
||||
```
|
||||
|
||||
## Using PptxGenJS
|
||||
|
||||
After converting HTML to slides with `html2pptx`, you'll use PptxGenJS to add dynamic content like charts, images, and additional elements.
|
||||
|
||||
### ⚠️ Critical Rules
|
||||
|
||||
#### Colors
|
||||
- **NEVER use `#` prefix** with hex colors in PptxGenJS - causes file corruption
|
||||
- ✅ Correct: `color: "FF0000"`, `fill: { color: "0066CC" }`
|
||||
- ❌ Wrong: `color: "#FF0000"` (breaks document)
|
||||
|
||||
### Adding Images
|
||||
|
||||
Always calculate aspect ratios from actual image dimensions:
|
||||
|
||||
```javascript
|
||||
// Get image dimensions: identify image.png | grep -o '[0-9]* x [0-9]*'
|
||||
const imgWidth = 1860, imgHeight = 1519; // From actual file
|
||||
const aspectRatio = imgWidth / imgHeight;
|
||||
|
||||
const h = 3; // Max height
|
||||
const w = h * aspectRatio;
|
||||
const x = (10 - w) / 2; // Center on 16:9 slide
|
||||
|
||||
slide.addImage({ path: "chart.png", x, y: 1.5, w, h });
|
||||
```
|
||||
|
||||
### Adding Text
|
||||
|
||||
```javascript
|
||||
// Rich text with formatting
|
||||
slide.addText([
|
||||
{ text: "Bold ", options: { bold: true } },
|
||||
{ text: "Italic ", options: { italic: true } },
|
||||
{ text: "Normal" }
|
||||
], {
|
||||
x: 1, y: 2, w: 8, h: 1
|
||||
});
|
||||
```
|
||||
|
||||
### Adding Shapes
|
||||
|
||||
```javascript
|
||||
// Rectangle
|
||||
slide.addShape(pptx.shapes.RECTANGLE, {
|
||||
x: 1, y: 1, w: 3, h: 2,
|
||||
fill: { color: "4472C4" },
|
||||
line: { color: "000000", width: 2 }
|
||||
});
|
||||
|
||||
// Circle
|
||||
slide.addShape(pptx.shapes.OVAL, {
|
||||
x: 5, y: 1, w: 2, h: 2,
|
||||
fill: { color: "ED7D31" }
|
||||
});
|
||||
|
||||
// Rounded rectangle
|
||||
slide.addShape(pptx.shapes.ROUNDED_RECTANGLE, {
|
||||
x: 1, y: 4, w: 3, h: 1.5,
|
||||
fill: { color: "70AD47" },
|
||||
rectRadius: 0.2
|
||||
});
|
||||
```
|
||||
|
||||
### Adding Charts
|
||||
|
||||
**Required for most charts:** Axis labels using `catAxisTitle` (category) and `valAxisTitle` (value).
|
||||
|
||||
**Chart Data Format:**
|
||||
- Use **single series with all labels** for simple bar/line charts
|
||||
- Each series creates a separate legend entry
|
||||
- Labels array defines X-axis values
|
||||
|
||||
**Time Series Data - Choose Correct Granularity:**
|
||||
- **< 30 days**: Use daily grouping (e.g., "10-01", "10-02") - avoid monthly aggregation that creates single-point charts
|
||||
- **30-365 days**: Use monthly grouping (e.g., "2024-01", "2024-02")
|
||||
- **> 365 days**: Use yearly grouping (e.g., "2023", "2024")
|
||||
- **Validate**: Charts with only 1 data point likely indicate incorrect aggregation for the time period
|
||||
|
||||
```javascript
|
||||
const { slide, placeholders } = await html2pptx('slide.html', pptx);
|
||||
|
||||
// CORRECT: Single series with all labels
|
||||
slide.addChart(pptx.charts.BAR, [{
|
||||
name: "Sales 2024",
|
||||
labels: ["Q1", "Q2", "Q3", "Q4"],
|
||||
values: [4500, 5500, 6200, 7100]
|
||||
}], {
|
||||
...placeholders[0], // Use placeholder position
|
||||
barDir: 'col', // 'col' = vertical bars, 'bar' = horizontal
|
||||
showTitle: true,
|
||||
title: 'Quarterly Sales',
|
||||
showLegend: false, // No legend needed for single series
|
||||
// Required axis labels
|
||||
showCatAxisTitle: true,
|
||||
catAxisTitle: 'Quarter',
|
||||
showValAxisTitle: true,
|
||||
valAxisTitle: 'Sales ($000s)',
|
||||
// Optional: Control scaling (adjust min based on data range for better visualization)
|
||||
valAxisMaxVal: 8000,
|
||||
valAxisMinVal: 0, // Use 0 for counts/amounts; for clustered data (e.g., 4500-7100), consider starting closer to min value
|
||||
valAxisMajorUnit: 2000, // Control y-axis label spacing to prevent crowding
|
||||
catAxisLabelRotate: 45, // Rotate labels if crowded
|
||||
dataLabelPosition: 'outEnd',
|
||||
dataLabelColor: '000000',
|
||||
// Use single color for single-series charts
|
||||
chartColors: ["4472C4"] // All bars same color
|
||||
});
|
||||
```
|
||||
|
||||
#### Scatter Chart
|
||||
|
||||
**IMPORTANT**: Scatter chart data format is unusual - first series contains X-axis values, subsequent series contain Y-values:
|
||||
|
||||
```javascript
|
||||
// Prepare data
|
||||
const data1 = [{ x: 10, y: 20 }, { x: 15, y: 25 }, { x: 20, y: 30 }];
|
||||
const data2 = [{ x: 12, y: 18 }, { x: 18, y: 22 }];
|
||||
|
||||
const allXValues = [...data1.map(d => d.x), ...data2.map(d => d.x)];
|
||||
|
||||
slide.addChart(pptx.charts.SCATTER, [
|
||||
{ name: 'X-Axis', values: allXValues }, // First series = X values
|
||||
{ name: 'Series 1', values: data1.map(d => d.y) }, // Y values only
|
||||
{ name: 'Series 2', values: data2.map(d => d.y) } // Y values only
|
||||
], {
|
||||
x: 1, y: 1, w: 8, h: 4,
|
||||
lineSize: 0, // 0 = no connecting lines
|
||||
lineDataSymbol: 'circle',
|
||||
lineDataSymbolSize: 6,
|
||||
showCatAxisTitle: true,
|
||||
catAxisTitle: 'X Axis',
|
||||
showValAxisTitle: true,
|
||||
valAxisTitle: 'Y Axis',
|
||||
chartColors: ["4472C4", "ED7D31"]
|
||||
});
|
||||
```
|
||||
|
||||
#### Line Chart
|
||||
|
||||
```javascript
|
||||
slide.addChart(pptx.charts.LINE, [{
|
||||
name: "Temperature",
|
||||
labels: ["Jan", "Feb", "Mar", "Apr"],
|
||||
values: [32, 35, 42, 55]
|
||||
}], {
|
||||
x: 1, y: 1, w: 8, h: 4,
|
||||
lineSize: 4,
|
||||
lineSmooth: true,
|
||||
// Required axis labels
|
||||
showCatAxisTitle: true,
|
||||
catAxisTitle: 'Month',
|
||||
showValAxisTitle: true,
|
||||
valAxisTitle: 'Temperature (°F)',
|
||||
// Optional: Y-axis range (set min based on data range for better visualization)
|
||||
valAxisMinVal: 0, // For ranges starting at 0 (counts, percentages, etc.)
|
||||
valAxisMaxVal: 60,
|
||||
valAxisMajorUnit: 20, // Control y-axis label spacing to prevent crowding (e.g., 10, 20, 25)
|
||||
// valAxisMinVal: 30, // PREFERRED: For data clustered in a range (e.g., 32-55 or ratings 3-5), start axis closer to min value to show variation
|
||||
// Optional: Chart colors
|
||||
chartColors: ["4472C4", "ED7D31", "A5A5A5"]
|
||||
});
|
||||
```
|
||||
|
||||
#### Pie Chart (No Axis Labels Required)
|
||||
|
||||
**CRITICAL**: Pie charts require a **single data series** with all categories in the `labels` array and corresponding values in the `values` array.
|
||||
|
||||
```javascript
|
||||
slide.addChart(pptx.charts.PIE, [{
|
||||
name: "Market Share",
|
||||
labels: ["Product A", "Product B", "Other"], // All categories in one array
|
||||
values: [35, 45, 20] // All values in one array
|
||||
}], {
|
||||
x: 2, y: 1, w: 6, h: 4,
|
||||
showPercent: true,
|
||||
showLegend: true,
|
||||
legendPos: 'r', // right
|
||||
chartColors: ["4472C4", "ED7D31", "A5A5A5"]
|
||||
});
|
||||
```
|
||||
|
||||
#### Multiple Data Series
|
||||
|
||||
```javascript
|
||||
slide.addChart(pptx.charts.LINE, [
|
||||
{
|
||||
name: "Product A",
|
||||
labels: ["Q1", "Q2", "Q3", "Q4"],
|
||||
values: [10, 20, 30, 40]
|
||||
},
|
||||
{
|
||||
name: "Product B",
|
||||
labels: ["Q1", "Q2", "Q3", "Q4"],
|
||||
values: [15, 25, 20, 35]
|
||||
}
|
||||
], {
|
||||
x: 1, y: 1, w: 8, h: 4,
|
||||
showCatAxisTitle: true,
|
||||
catAxisTitle: 'Quarter',
|
||||
showValAxisTitle: true,
|
||||
valAxisTitle: 'Revenue ($M)'
|
||||
});
|
||||
```
|
||||
|
||||
### Chart Colors
|
||||
|
||||
**CRITICAL**: Use hex colors **without** the `#` prefix - including `#` causes file corruption.
|
||||
|
||||
**Align chart colors with your chosen design palette**, ensuring sufficient contrast and distinctiveness for data visualization. Adjust colors for:
|
||||
- Strong contrast between adjacent series
|
||||
- Readability against slide backgrounds
|
||||
- Accessibility (avoid red-green only combinations)
|
||||
|
||||
```javascript
|
||||
// Example: Ocean palette-inspired chart colors (adjusted for contrast)
|
||||
const chartColors = ["16A085", "FF6B9D", "2C3E50", "F39C12", "9B59B6"];
|
||||
|
||||
// Single-series chart: Use one color for all bars/points
|
||||
slide.addChart(pptx.charts.BAR, [{
|
||||
name: "Sales",
|
||||
labels: ["Q1", "Q2", "Q3", "Q4"],
|
||||
values: [4500, 5500, 6200, 7100]
|
||||
}], {
|
||||
...placeholders[0],
|
||||
chartColors: ["16A085"], // All bars same color
|
||||
showLegend: false
|
||||
});
|
||||
|
||||
// Multi-series chart: Each series gets a different color
|
||||
slide.addChart(pptx.charts.LINE, [
|
||||
{ name: "Product A", labels: ["Q1", "Q2", "Q3"], values: [10, 20, 30] },
|
||||
{ name: "Product B", labels: ["Q1", "Q2", "Q3"], values: [15, 25, 20] }
|
||||
], {
|
||||
...placeholders[0],
|
||||
chartColors: ["16A085", "FF6B9D"] // One color per series
|
||||
});
|
||||
```
|
||||
|
||||
### Adding Tables
|
||||
|
||||
Tables can be added with basic or advanced formatting:
|
||||
|
||||
#### Basic Table
|
||||
|
||||
```javascript
|
||||
slide.addTable([
|
||||
["Header 1", "Header 2", "Header 3"],
|
||||
["Row 1, Col 1", "Row 1, Col 2", "Row 1, Col 3"],
|
||||
["Row 2, Col 1", "Row 2, Col 2", "Row 2, Col 3"]
|
||||
], {
|
||||
x: 0.5,
|
||||
y: 1,
|
||||
w: 9,
|
||||
h: 3,
|
||||
border: { pt: 1, color: "999999" },
|
||||
fill: { color: "F1F1F1" }
|
||||
});
|
||||
```
|
||||
|
||||
#### Table with Custom Formatting
|
||||
|
||||
```javascript
|
||||
const tableData = [
|
||||
// Header row with custom styling
|
||||
[
|
||||
{ text: "Product", options: { fill: { color: "4472C4" }, color: "FFFFFF", bold: true } },
|
||||
{ text: "Revenue", options: { fill: { color: "4472C4" }, color: "FFFFFF", bold: true } },
|
||||
{ text: "Growth", options: { fill: { color: "4472C4" }, color: "FFFFFF", bold: true } }
|
||||
],
|
||||
// Data rows
|
||||
["Product A", "$50M", "+15%"],
|
||||
["Product B", "$35M", "+22%"],
|
||||
["Product C", "$28M", "+8%"]
|
||||
];
|
||||
|
||||
slide.addTable(tableData, {
|
||||
x: 1,
|
||||
y: 1.5,
|
||||
w: 8,
|
||||
h: 3,
|
||||
colW: [3, 2.5, 2.5], // Column widths
|
||||
rowH: [0.5, 0.6, 0.6, 0.6], // Row heights
|
||||
border: { pt: 1, color: "CCCCCC" },
|
||||
align: "center",
|
||||
valign: "middle",
|
||||
fontSize: 14
|
||||
});
|
||||
```
|
||||
|
||||
#### Table with Merged Cells
|
||||
|
||||
```javascript
|
||||
const mergedTableData = [
|
||||
[
|
||||
{ text: "Q1 Results", options: { colspan: 3, fill: { color: "4472C4" }, color: "FFFFFF", bold: true } }
|
||||
],
|
||||
["Product", "Sales", "Market Share"],
|
||||
["Product A", "$25M", "35%"],
|
||||
["Product B", "$18M", "25%"]
|
||||
];
|
||||
|
||||
slide.addTable(mergedTableData, {
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 8,
|
||||
h: 2.5,
|
||||
colW: [3, 2.5, 2.5],
|
||||
border: { pt: 1, color: "DDDDDD" }
|
||||
});
|
||||
```
|
||||
|
||||
### Table Options
|
||||
|
||||
Common table options:
|
||||
- `x, y, w, h` - Position and size
|
||||
- `colW` - Array of column widths (in inches)
|
||||
- `rowH` - Array of row heights (in inches)
|
||||
- `border` - Border style: `{ pt: 1, color: "999999" }`
|
||||
- `fill` - Background color (no # prefix)
|
||||
- `align` - Text alignment: "left", "center", "right"
|
||||
- `valign` - Vertical alignment: "top", "middle", "bottom"
|
||||
- `fontSize` - Text size
|
||||
- `autoPage` - Auto-create new slides if content overflows
|
||||
427
.claude/skills/pptx/ooxml.md
Normal file
427
.claude/skills/pptx/ooxml.md
Normal file
@ -0,0 +1,427 @@
|
||||
# Office Open XML Technical Reference for PowerPoint
|
||||
|
||||
**Important: Read this entire document before starting.** Critical XML schema rules and formatting requirements are covered throughout. Incorrect implementation can create invalid PPTX files that PowerPoint cannot open.
|
||||
|
||||
## Technical Guidelines
|
||||
|
||||
### Schema Compliance
|
||||
- **Element ordering in `<p:txBody>`**: `<a:bodyPr>`, `<a:lstStyle>`, `<a:p>`
|
||||
- **Whitespace**: Add `xml:space='preserve'` to `<a:t>` elements with leading/trailing spaces
|
||||
- **Unicode**: Escape characters in ASCII content: `"` becomes `“`
|
||||
- **Images**: Add to `ppt/media/`, reference in slide XML, set dimensions to fit slide bounds
|
||||
- **Relationships**: Update `ppt/slides/_rels/slideN.xml.rels` for each slide's resources
|
||||
- **Dirty attribute**: Add `dirty="0"` to `<a:rPr>` and `<a:endParaRPr>` elements to indicate clean state
|
||||
|
||||
## Presentation Structure
|
||||
|
||||
### Basic Slide Structure
|
||||
```xml
|
||||
<!-- ppt/slides/slide1.xml -->
|
||||
<p:sld>
|
||||
<p:cSld>
|
||||
<p:spTree>
|
||||
<p:nvGrpSpPr>...</p:nvGrpSpPr>
|
||||
<p:grpSpPr>...</p:grpSpPr>
|
||||
<!-- Shapes go here -->
|
||||
</p:spTree>
|
||||
</p:cSld>
|
||||
</p:sld>
|
||||
```
|
||||
|
||||
### Text Box / Shape with Text
|
||||
```xml
|
||||
<p:sp>
|
||||
<p:nvSpPr>
|
||||
<p:cNvPr id="2" name="Title"/>
|
||||
<p:cNvSpPr>
|
||||
<a:spLocks noGrp="1"/>
|
||||
</p:cNvSpPr>
|
||||
<p:nvPr>
|
||||
<p:ph type="ctrTitle"/>
|
||||
</p:nvPr>
|
||||
</p:nvSpPr>
|
||||
<p:spPr>
|
||||
<a:xfrm>
|
||||
<a:off x="838200" y="365125"/>
|
||||
<a:ext cx="7772400" cy="1470025"/>
|
||||
</a:xfrm>
|
||||
</p:spPr>
|
||||
<p:txBody>
|
||||
<a:bodyPr/>
|
||||
<a:lstStyle/>
|
||||
<a:p>
|
||||
<a:r>
|
||||
<a:t>Slide Title</a:t>
|
||||
</a:r>
|
||||
</a:p>
|
||||
</p:txBody>
|
||||
</p:sp>
|
||||
```
|
||||
|
||||
### Text Formatting
|
||||
```xml
|
||||
<!-- Bold -->
|
||||
<a:r>
|
||||
<a:rPr b="1"/>
|
||||
<a:t>Bold Text</a:t>
|
||||
</a:r>
|
||||
|
||||
<!-- Italic -->
|
||||
<a:r>
|
||||
<a:rPr i="1"/>
|
||||
<a:t>Italic Text</a:t>
|
||||
</a:r>
|
||||
|
||||
<!-- Underline -->
|
||||
<a:r>
|
||||
<a:rPr u="sng"/>
|
||||
<a:t>Underlined</a:t>
|
||||
</a:r>
|
||||
|
||||
<!-- Highlight -->
|
||||
<a:r>
|
||||
<a:rPr>
|
||||
<a:highlight>
|
||||
<a:srgbClr val="FFFF00"/>
|
||||
</a:highlight>
|
||||
</a:rPr>
|
||||
<a:t>Highlighted Text</a:t>
|
||||
</a:r>
|
||||
|
||||
<!-- Font and Size -->
|
||||
<a:r>
|
||||
<a:rPr sz="2400" typeface="Arial">
|
||||
<a:solidFill>
|
||||
<a:srgbClr val="FF0000"/>
|
||||
</a:solidFill>
|
||||
</a:rPr>
|
||||
<a:t>Colored Arial 24pt</a:t>
|
||||
</a:r>
|
||||
|
||||
<!-- Complete formatting example -->
|
||||
<a:r>
|
||||
<a:rPr lang="en-US" sz="1400" b="1" dirty="0">
|
||||
<a:solidFill>
|
||||
<a:srgbClr val="FAFAFA"/>
|
||||
</a:solidFill>
|
||||
</a:rPr>
|
||||
<a:t>Formatted text</a:t>
|
||||
</a:r>
|
||||
```
|
||||
|
||||
### Lists
|
||||
```xml
|
||||
<!-- Bullet list -->
|
||||
<a:p>
|
||||
<a:pPr lvl="0">
|
||||
<a:buChar char="•"/>
|
||||
</a:pPr>
|
||||
<a:r>
|
||||
<a:t>First bullet point</a:t>
|
||||
</a:r>
|
||||
</a:p>
|
||||
|
||||
<!-- Numbered list -->
|
||||
<a:p>
|
||||
<a:pPr lvl="0">
|
||||
<a:buAutoNum type="arabicPeriod"/>
|
||||
</a:pPr>
|
||||
<a:r>
|
||||
<a:t>First numbered item</a:t>
|
||||
</a:r>
|
||||
</a:p>
|
||||
|
||||
<!-- Second level indent -->
|
||||
<a:p>
|
||||
<a:pPr lvl="1">
|
||||
<a:buChar char="•"/>
|
||||
</a:pPr>
|
||||
<a:r>
|
||||
<a:t>Indented bullet</a:t>
|
||||
</a:r>
|
||||
</a:p>
|
||||
```
|
||||
|
||||
### Shapes
|
||||
```xml
|
||||
<!-- Rectangle -->
|
||||
<p:sp>
|
||||
<p:nvSpPr>
|
||||
<p:cNvPr id="3" name="Rectangle"/>
|
||||
<p:cNvSpPr/>
|
||||
<p:nvPr/>
|
||||
</p:nvSpPr>
|
||||
<p:spPr>
|
||||
<a:xfrm>
|
||||
<a:off x="1000000" y="1000000"/>
|
||||
<a:ext cx="3000000" cy="2000000"/>
|
||||
</a:xfrm>
|
||||
<a:prstGeom prst="rect">
|
||||
<a:avLst/>
|
||||
</a:prstGeom>
|
||||
<a:solidFill>
|
||||
<a:srgbClr val="FF0000"/>
|
||||
</a:solidFill>
|
||||
<a:ln w="25400">
|
||||
<a:solidFill>
|
||||
<a:srgbClr val="000000"/>
|
||||
</a:solidFill>
|
||||
</a:ln>
|
||||
</p:spPr>
|
||||
</p:sp>
|
||||
|
||||
<!-- Rounded Rectangle -->
|
||||
<p:sp>
|
||||
<p:spPr>
|
||||
<a:prstGeom prst="roundRect">
|
||||
<a:avLst/>
|
||||
</a:prstGeom>
|
||||
</p:spPr>
|
||||
</p:sp>
|
||||
|
||||
<!-- Circle/Ellipse -->
|
||||
<p:sp>
|
||||
<p:spPr>
|
||||
<a:prstGeom prst="ellipse">
|
||||
<a:avLst/>
|
||||
</a:prstGeom>
|
||||
</p:spPr>
|
||||
</p:sp>
|
||||
```
|
||||
|
||||
### Images
|
||||
```xml
|
||||
<p:pic>
|
||||
<p:nvPicPr>
|
||||
<p:cNvPr id="4" name="Picture">
|
||||
<a:hlinkClick r:id="" action="ppaction://media"/>
|
||||
</p:cNvPr>
|
||||
<p:cNvPicPr>
|
||||
<a:picLocks noChangeAspect="1"/>
|
||||
</p:cNvPicPr>
|
||||
<p:nvPr/>
|
||||
</p:nvPicPr>
|
||||
<p:blipFill>
|
||||
<a:blip r:embed="rId2"/>
|
||||
<a:stretch>
|
||||
<a:fillRect/>
|
||||
</a:stretch>
|
||||
</p:blipFill>
|
||||
<p:spPr>
|
||||
<a:xfrm>
|
||||
<a:off x="1000000" y="1000000"/>
|
||||
<a:ext cx="3000000" cy="2000000"/>
|
||||
</a:xfrm>
|
||||
<a:prstGeom prst="rect">
|
||||
<a:avLst/>
|
||||
</a:prstGeom>
|
||||
</p:spPr>
|
||||
</p:pic>
|
||||
```
|
||||
|
||||
### Tables
|
||||
```xml
|
||||
<p:graphicFrame>
|
||||
<p:nvGraphicFramePr>
|
||||
<p:cNvPr id="5" name="Table"/>
|
||||
<p:cNvGraphicFramePr>
|
||||
<a:graphicFrameLocks noGrp="1"/>
|
||||
</p:cNvGraphicFramePr>
|
||||
<p:nvPr/>
|
||||
</p:nvGraphicFramePr>
|
||||
<p:xfrm>
|
||||
<a:off x="1000000" y="1000000"/>
|
||||
<a:ext cx="6000000" cy="2000000"/>
|
||||
</p:xfrm>
|
||||
<a:graphic>
|
||||
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/table">
|
||||
<a:tbl>
|
||||
<a:tblGrid>
|
||||
<a:gridCol w="3000000"/>
|
||||
<a:gridCol w="3000000"/>
|
||||
</a:tblGrid>
|
||||
<a:tr h="500000">
|
||||
<a:tc>
|
||||
<a:txBody>
|
||||
<a:bodyPr/>
|
||||
<a:lstStyle/>
|
||||
<a:p>
|
||||
<a:r>
|
||||
<a:t>Cell 1</a:t>
|
||||
</a:r>
|
||||
</a:p>
|
||||
</a:txBody>
|
||||
</a:tc>
|
||||
<a:tc>
|
||||
<a:txBody>
|
||||
<a:bodyPr/>
|
||||
<a:lstStyle/>
|
||||
<a:p>
|
||||
<a:r>
|
||||
<a:t>Cell 2</a:t>
|
||||
</a:r>
|
||||
</a:p>
|
||||
</a:txBody>
|
||||
</a:tc>
|
||||
</a:tr>
|
||||
</a:tbl>
|
||||
</a:graphicData>
|
||||
</a:graphic>
|
||||
</p:graphicFrame>
|
||||
```
|
||||
|
||||
### Slide Layouts
|
||||
|
||||
```xml
|
||||
<!-- Title Slide Layout -->
|
||||
<p:sp>
|
||||
<p:nvSpPr>
|
||||
<p:nvPr>
|
||||
<p:ph type="ctrTitle"/>
|
||||
</p:nvPr>
|
||||
</p:nvSpPr>
|
||||
<!-- Title content -->
|
||||
</p:sp>
|
||||
|
||||
<p:sp>
|
||||
<p:nvSpPr>
|
||||
<p:nvPr>
|
||||
<p:ph type="subTitle" idx="1"/>
|
||||
</p:nvPr>
|
||||
</p:nvSpPr>
|
||||
<!-- Subtitle content -->
|
||||
</p:sp>
|
||||
|
||||
<!-- Content Slide Layout -->
|
||||
<p:sp>
|
||||
<p:nvSpPr>
|
||||
<p:nvPr>
|
||||
<p:ph type="title"/>
|
||||
</p:nvPr>
|
||||
</p:nvSpPr>
|
||||
<!-- Slide title -->
|
||||
</p:sp>
|
||||
|
||||
<p:sp>
|
||||
<p:nvSpPr>
|
||||
<p:nvPr>
|
||||
<p:ph type="body" idx="1"/>
|
||||
</p:nvPr>
|
||||
</p:nvSpPr>
|
||||
<!-- Content body -->
|
||||
</p:sp>
|
||||
```
|
||||
|
||||
## File Updates
|
||||
|
||||
When adding content, update these files:
|
||||
|
||||
**`ppt/_rels/presentation.xml.rels`:**
|
||||
```xml
|
||||
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide1.xml"/>
|
||||
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="slideMasters/slideMaster1.xml"/>
|
||||
```
|
||||
|
||||
**`ppt/slides/_rels/slide1.xml.rels`:**
|
||||
```xml
|
||||
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout1.xml"/>
|
||||
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image1.png"/>
|
||||
```
|
||||
|
||||
**`[Content_Types].xml`:**
|
||||
```xml
|
||||
<Default Extension="png" ContentType="image/png"/>
|
||||
<Default Extension="jpg" ContentType="image/jpeg"/>
|
||||
<Override PartName="/ppt/slides/slide1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>
|
||||
```
|
||||
|
||||
**`ppt/presentation.xml`:**
|
||||
```xml
|
||||
<p:sldIdLst>
|
||||
<p:sldId id="256" r:id="rId1"/>
|
||||
<p:sldId id="257" r:id="rId2"/>
|
||||
</p:sldIdLst>
|
||||
```
|
||||
|
||||
**`docProps/app.xml`:** Update slide count and statistics
|
||||
```xml
|
||||
<Slides>2</Slides>
|
||||
<Paragraphs>10</Paragraphs>
|
||||
<Words>50</Words>
|
||||
```
|
||||
|
||||
## Slide Operations
|
||||
|
||||
### Adding a New Slide
|
||||
When adding a slide to the end of the presentation:
|
||||
|
||||
1. **Create the slide file** (`ppt/slides/slideN.xml`)
|
||||
2. **Update `[Content_Types].xml`**: Add Override for the new slide
|
||||
3. **Update `ppt/_rels/presentation.xml.rels`**: Add relationship for the new slide
|
||||
4. **Update `ppt/presentation.xml`**: Add slide ID to `<p:sldIdLst>`
|
||||
5. **Create slide relationships** (`ppt/slides/_rels/slideN.xml.rels`) if needed
|
||||
6. **Update `docProps/app.xml`**: Increment slide count and update statistics (if present)
|
||||
|
||||
### Duplicating a Slide
|
||||
1. Copy the source slide XML file with a new name
|
||||
2. Update all IDs in the new slide to be unique
|
||||
3. Follow the "Adding a New Slide" steps above
|
||||
4. **CRITICAL**: Remove or update any notes slide references in `_rels` files
|
||||
5. Remove references to unused media files
|
||||
|
||||
### Reordering Slides
|
||||
1. **Update `ppt/presentation.xml`**: Reorder `<p:sldId>` elements in `<p:sldIdLst>`
|
||||
2. The order of `<p:sldId>` elements determines slide order
|
||||
3. Keep slide IDs and relationship IDs unchanged
|
||||
|
||||
Example:
|
||||
```xml
|
||||
<!-- Original order -->
|
||||
<p:sldIdLst>
|
||||
<p:sldId id="256" r:id="rId2"/>
|
||||
<p:sldId id="257" r:id="rId3"/>
|
||||
<p:sldId id="258" r:id="rId4"/>
|
||||
</p:sldIdLst>
|
||||
|
||||
<!-- After moving slide 3 to position 2 -->
|
||||
<p:sldIdLst>
|
||||
<p:sldId id="256" r:id="rId2"/>
|
||||
<p:sldId id="258" r:id="rId4"/>
|
||||
<p:sldId id="257" r:id="rId3"/>
|
||||
</p:sldIdLst>
|
||||
```
|
||||
|
||||
### Deleting a Slide
|
||||
1. **Remove from `ppt/presentation.xml`**: Delete the `<p:sldId>` entry
|
||||
2. **Remove from `ppt/_rels/presentation.xml.rels`**: Delete the relationship
|
||||
3. **Remove from `[Content_Types].xml`**: Delete the Override entry
|
||||
4. **Delete files**: Remove `ppt/slides/slideN.xml` and `ppt/slides/_rels/slideN.xml.rels`
|
||||
5. **Update `docProps/app.xml`**: Decrement slide count and update statistics
|
||||
6. **Clean up unused media**: Remove orphaned images from `ppt/media/`
|
||||
|
||||
Note: Don't renumber remaining slides - keep their original IDs and filenames.
|
||||
|
||||
|
||||
## Common Errors to Avoid
|
||||
|
||||
- **Encodings**: Escape unicode characters in ASCII content: `"` becomes `“`
|
||||
- **Images**: Add to `ppt/media/` and update relationship files
|
||||
- **Lists**: Omit bullets from list headers
|
||||
- **IDs**: Use valid hexadecimal values for UUIDs
|
||||
- **Themes**: Check all themes in `theme` directory for colors
|
||||
|
||||
## Validation Checklist for Template-Based Presentations
|
||||
|
||||
### Before Packing, Always:
|
||||
- **Clean unused resources**: Remove unreferenced media, fonts, and notes directories
|
||||
- **Fix Content_Types.xml**: Declare ALL slides, layouts, and themes present in the package
|
||||
- **Fix relationship IDs**:
|
||||
- Remove font embed references if not using embedded fonts
|
||||
- **Remove broken references**: Check all `_rels` files for references to deleted resources
|
||||
|
||||
### Common Template Duplication Pitfalls:
|
||||
- Multiple slides referencing the same notes slide after duplication
|
||||
- Image/media references from template slides that no longer exist
|
||||
- Font embedding references when fonts aren't included
|
||||
- Missing slideLayout declarations for layouts 12-25
|
||||
- docProps directory may not unpack - this is optional
|
||||
1499
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd
Normal file
1499
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,146 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
xmlns="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing"
|
||||
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing"
|
||||
elementFormDefault="qualified">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
schemaLocation="dml-main.xsd"/>
|
||||
<xsd:complexType name="CT_ShapeNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1"
|
||||
/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Shape">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvSpPr" type="CT_ShapeNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="textlink" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="fLocksText" type="xsd:boolean" use="optional" default="true"/>
|
||||
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ConnectorNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvCxnSpPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Connector">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvCxnSpPr" type="CT_ConnectorNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PictureNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Picture">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="macro" type="xsd:string" use="optional" default=""/>
|
||||
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GraphicFrameNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
|
||||
minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GraphicFrame">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvGraphicFramePr" type="CT_GraphicFrameNonVisual" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GroupShapeNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GroupShape">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvGrpSpPr" type="CT_GroupShapeNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="sp" type="CT_Shape"/>
|
||||
<xsd:element name="grpSp" type="CT_GroupShape"/>
|
||||
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
|
||||
<xsd:element name="cxnSp" type="CT_Connector"/>
|
||||
<xsd:element name="pic" type="CT_Picture"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_ObjectChoices">
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="sp" type="CT_Shape"/>
|
||||
<xsd:element name="grpSp" type="CT_GroupShape"/>
|
||||
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
|
||||
<xsd:element name="cxnSp" type="CT_Connector"/>
|
||||
<xsd:element name="pic" type="CT_Picture"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:group>
|
||||
<xsd:simpleType name="ST_MarkerCoordinate">
|
||||
<xsd:restriction base="xsd:double">
|
||||
<xsd:minInclusive value="0.0"/>
|
||||
<xsd:maxInclusive value="1.0"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Marker">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="x" type="ST_MarkerCoordinate" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="y" type="ST_MarkerCoordinate" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_RelSizeAnchor">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="from" type="CT_Marker"/>
|
||||
<xsd:element name="to" type="CT_Marker"/>
|
||||
<xsd:group ref="EG_ObjectChoices"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_AbsSizeAnchor">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="from" type="CT_Marker"/>
|
||||
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
|
||||
<xsd:group ref="EG_ObjectChoices"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_Anchor">
|
||||
<xsd:choice>
|
||||
<xsd:element name="relSizeAnchor" type="CT_RelSizeAnchor"/>
|
||||
<xsd:element name="absSizeAnchor" type="CT_AbsSizeAnchor"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_Drawing">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_Anchor" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"
|
||||
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
elementFormDefault="qualified"
|
||||
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
schemaLocation="dml-main.xsd"/>
|
||||
<xsd:element name="lockedCanvas" type="a:CT_GvmlGroupShape"/>
|
||||
</xsd:schema>
|
||||
3081
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd
Normal file
3081
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/drawingml/2006/picture"
|
||||
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" elementFormDefault="qualified"
|
||||
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/picture">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
schemaLocation="dml-main.xsd"/>
|
||||
<xsd:complexType name="CT_PictureNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Picture">
|
||||
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="pic" type="CT_Picture"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,185 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
xmlns="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
|
||||
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
|
||||
elementFormDefault="qualified">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
schemaLocation="dml-main.xsd"/>
|
||||
<xsd:import schemaLocation="shared-relationshipReference.xsd"
|
||||
namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>
|
||||
<xsd:element name="from" type="CT_Marker"/>
|
||||
<xsd:element name="to" type="CT_Marker"/>
|
||||
<xsd:complexType name="CT_AnchorClientData">
|
||||
<xsd:attribute name="fLocksWithSheet" type="xsd:boolean" use="optional" default="true"/>
|
||||
<xsd:attribute name="fPrintsWithSheet" type="xsd:boolean" use="optional" default="true"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ShapeNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1"
|
||||
/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Shape">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvSpPr" type="CT_ShapeNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="textlink" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="fLocksText" type="xsd:boolean" use="optional" default="true"/>
|
||||
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ConnectorNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvCxnSpPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Connector">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvCxnSpPr" type="CT_ConnectorNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PictureNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Picture">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="macro" type="xsd:string" use="optional" default=""/>
|
||||
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GraphicalObjectFrameNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
|
||||
minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GraphicalObjectFrame">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvGraphicFramePr" type="CT_GraphicalObjectFrameNonVisual" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GroupShapeNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GroupShape">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvGrpSpPr" type="CT_GroupShapeNonVisual" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="sp" type="CT_Shape"/>
|
||||
<xsd:element name="grpSp" type="CT_GroupShape"/>
|
||||
<xsd:element name="graphicFrame" type="CT_GraphicalObjectFrame"/>
|
||||
<xsd:element name="cxnSp" type="CT_Connector"/>
|
||||
<xsd:element name="pic" type="CT_Picture"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_ObjectChoices">
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="sp" type="CT_Shape"/>
|
||||
<xsd:element name="grpSp" type="CT_GroupShape"/>
|
||||
<xsd:element name="graphicFrame" type="CT_GraphicalObjectFrame"/>
|
||||
<xsd:element name="cxnSp" type="CT_Connector"/>
|
||||
<xsd:element name="pic" type="CT_Picture"/>
|
||||
<xsd:element name="contentPart" type="CT_Rel"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_Rel">
|
||||
<xsd:attribute ref="r:id" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_ColID">
|
||||
<xsd:restriction base="xsd:int">
|
||||
<xsd:minInclusive value="0"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_RowID">
|
||||
<xsd:restriction base="xsd:int">
|
||||
<xsd:minInclusive value="0"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Marker">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="col" type="ST_ColID"/>
|
||||
<xsd:element name="colOff" type="a:ST_Coordinate"/>
|
||||
<xsd:element name="row" type="ST_RowID"/>
|
||||
<xsd:element name="rowOff" type="a:ST_Coordinate"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_EditAs">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="twoCell"/>
|
||||
<xsd:enumeration value="oneCell"/>
|
||||
<xsd:enumeration value="absolute"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_TwoCellAnchor">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="from" type="CT_Marker"/>
|
||||
<xsd:element name="to" type="CT_Marker"/>
|
||||
<xsd:group ref="EG_ObjectChoices"/>
|
||||
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="editAs" type="ST_EditAs" use="optional" default="twoCell"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_OneCellAnchor">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="from" type="CT_Marker"/>
|
||||
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
|
||||
<xsd:group ref="EG_ObjectChoices"/>
|
||||
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_AbsoluteAnchor">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="pos" type="a:CT_Point2D"/>
|
||||
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
|
||||
<xsd:group ref="EG_ObjectChoices"/>
|
||||
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_Anchor">
|
||||
<xsd:choice>
|
||||
<xsd:element name="twoCellAnchor" type="CT_TwoCellAnchor"/>
|
||||
<xsd:element name="oneCellAnchor" type="CT_OneCellAnchor"/>
|
||||
<xsd:element name="absoluteAnchor" type="CT_AbsoluteAnchor"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_Drawing">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_Anchor" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="wsDr" type="CT_Drawing"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,287 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
xmlns:dpct="http://schemas.openxmlformats.org/drawingml/2006/picture"
|
||||
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
xmlns="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
||||
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
||||
elementFormDefault="qualified">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||
schemaLocation="dml-main.xsd"/>
|
||||
<xsd:import schemaLocation="wml.xsd"
|
||||
namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/picture"
|
||||
schemaLocation="dml-picture.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
schemaLocation="shared-relationshipReference.xsd"/>
|
||||
<xsd:complexType name="CT_EffectExtent">
|
||||
<xsd:attribute name="l" type="a:ST_Coordinate" use="required"/>
|
||||
<xsd:attribute name="t" type="a:ST_Coordinate" use="required"/>
|
||||
<xsd:attribute name="r" type="a:ST_Coordinate" use="required"/>
|
||||
<xsd:attribute name="b" type="a:ST_Coordinate" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_WrapDistance">
|
||||
<xsd:restriction base="xsd:unsignedInt"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Inline">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="extent" type="a:CT_PositiveSize2D"/>
|
||||
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||
<xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
|
||||
minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_WrapText">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="bothSides"/>
|
||||
<xsd:enumeration value="left"/>
|
||||
<xsd:enumeration value="right"/>
|
||||
<xsd:enumeration value="largest"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_WrapPath">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="edited" type="xsd:boolean" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WrapNone"/>
|
||||
<xsd:complexType name="CT_WrapSquare">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WrapTight">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WrapThrough">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WrapTopBottom">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_WrapType">
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="wrapNone" type="CT_WrapNone" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="wrapSquare" type="CT_WrapSquare" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="wrapTight" type="CT_WrapTight" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="wrapThrough" type="CT_WrapThrough" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="wrapTopAndBottom" type="CT_WrapTopBottom" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:group>
|
||||
<xsd:simpleType name="ST_PositionOffset">
|
||||
<xsd:restriction base="xsd:int"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_AlignH">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="left"/>
|
||||
<xsd:enumeration value="right"/>
|
||||
<xsd:enumeration value="center"/>
|
||||
<xsd:enumeration value="inside"/>
|
||||
<xsd:enumeration value="outside"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_RelFromH">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="margin"/>
|
||||
<xsd:enumeration value="page"/>
|
||||
<xsd:enumeration value="column"/>
|
||||
<xsd:enumeration value="character"/>
|
||||
<xsd:enumeration value="leftMargin"/>
|
||||
<xsd:enumeration value="rightMargin"/>
|
||||
<xsd:enumeration value="insideMargin"/>
|
||||
<xsd:enumeration value="outsideMargin"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_PosH">
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="align" type="ST_AlignH" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="relativeFrom" type="ST_RelFromH" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_AlignV">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="top"/>
|
||||
<xsd:enumeration value="bottom"/>
|
||||
<xsd:enumeration value="center"/>
|
||||
<xsd:enumeration value="inside"/>
|
||||
<xsd:enumeration value="outside"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_RelFromV">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="margin"/>
|
||||
<xsd:enumeration value="page"/>
|
||||
<xsd:enumeration value="paragraph"/>
|
||||
<xsd:enumeration value="line"/>
|
||||
<xsd:enumeration value="topMargin"/>
|
||||
<xsd:enumeration value="bottomMargin"/>
|
||||
<xsd:enumeration value="insideMargin"/>
|
||||
<xsd:enumeration value="outsideMargin"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_PosV">
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="align" type="ST_AlignV" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="relativeFrom" type="ST_RelFromV" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Anchor">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="simplePos" type="a:CT_Point2D"/>
|
||||
<xsd:element name="positionH" type="CT_PosH"/>
|
||||
<xsd:element name="positionV" type="CT_PosV"/>
|
||||
<xsd:element name="extent" type="a:CT_PositiveSize2D"/>
|
||||
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||
<xsd:group ref="EG_WrapType"/>
|
||||
<xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
|
||||
minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||
<xsd:attribute name="simplePos" type="xsd:boolean"/>
|
||||
<xsd:attribute name="relativeHeight" type="xsd:unsignedInt" use="required"/>
|
||||
<xsd:attribute name="behindDoc" type="xsd:boolean" use="required"/>
|
||||
<xsd:attribute name="locked" type="xsd:boolean" use="required"/>
|
||||
<xsd:attribute name="layoutInCell" type="xsd:boolean" use="required"/>
|
||||
<xsd:attribute name="hidden" type="xsd:boolean" use="optional"/>
|
||||
<xsd:attribute name="allowOverlap" type="xsd:boolean" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_TxbxContent">
|
||||
<xsd:group ref="w:EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_TextboxInfo">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="txbxContent" type="CT_TxbxContent" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:unsignedShort" use="optional" default="0"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_LinkedTextboxInformation">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:unsignedShort" use="required"/>
|
||||
<xsd:attribute name="seq" type="xsd:unsignedShort" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WordprocessingShape">
|
||||
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
<xsd:element name="cNvCnPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:choice>
|
||||
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||
<xsd:element name="txbx" type="CT_TextboxInfo" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="linkedTxbx" type="CT_LinkedTextboxInformation" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
</xsd:choice>
|
||||
<xsd:element name="bodyPr" type="a:CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="normalEastAsianFlow" type="xsd:boolean" use="optional" default="false"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GraphicFrame">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="cNvFrPr" type="a:CT_NonVisualGraphicFrameProperties" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WordprocessingContentPartNonVisual">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="cNvContentPartPr" type="a:CT_NonVisualContentPartProperties" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WordprocessingContentPart">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="nvContentPartPr" type="CT_WordprocessingContentPartNonVisual" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="bwMode" type="a:ST_BlackWhiteMode" use="optional"/>
|
||||
<xsd:attribute ref="r:id" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WordprocessingGroup">
|
||||
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
|
||||
maxOccurs="1"/>
|
||||
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element ref="wsp"/>
|
||||
<xsd:element name="grpSp" type="CT_WordprocessingGroup"/>
|
||||
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
|
||||
<xsd:element ref="dpct:pic"/>
|
||||
<xsd:element name="contentPart" type="CT_WordprocessingContentPart"/>
|
||||
</xsd:choice>
|
||||
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_WordprocessingCanvas">
|
||||
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||
<xsd:element name="bg" type="a:CT_BackgroundFormatting" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="whole" type="a:CT_WholeE2oFormatting" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element ref="wsp"/>
|
||||
<xsd:element ref="dpct:pic"/>
|
||||
<xsd:element name="contentPart" type="CT_WordprocessingContentPart"/>
|
||||
<xsd:element ref="wgp"/>
|
||||
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
|
||||
</xsd:choice>
|
||||
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="wpc" type="CT_WordprocessingCanvas"/>
|
||||
<xsd:element name="wgp" type="CT_WordprocessingGroup"/>
|
||||
<xsd:element name="wsp" type="CT_WordprocessingShape"/>
|
||||
<xsd:element name="inline" type="CT_Inline"/>
|
||||
<xsd:element name="anchor" type="CT_Anchor"/>
|
||||
</xsd:schema>
|
||||
1676
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd
Normal file
1676
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/characteristics"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/characteristics"
|
||||
elementFormDefault="qualified">
|
||||
<xsd:complexType name="CT_AdditionalCharacteristics">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="characteristic" type="CT_Characteristic" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Characteristic">
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="relation" type="ST_Relation" use="required"/>
|
||||
<xsd:attribute name="val" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="vocabulary" type="xsd:anyURI" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Relation">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="ge"/>
|
||||
<xsd:enumeration value="le"/>
|
||||
<xsd:enumeration value="gt"/>
|
||||
<xsd:enumeration value="lt"/>
|
||||
<xsd:enumeration value="eq"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:element name="additionalCharacteristics" type="CT_AdditionalCharacteristics"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,144 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography"
|
||||
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/bibliography"
|
||||
elementFormDefault="qualified">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:simpleType name="ST_SourceType">
|
||||
<xsd:restriction base="s:ST_String">
|
||||
<xsd:enumeration value="ArticleInAPeriodical"/>
|
||||
<xsd:enumeration value="Book"/>
|
||||
<xsd:enumeration value="BookSection"/>
|
||||
<xsd:enumeration value="JournalArticle"/>
|
||||
<xsd:enumeration value="ConferenceProceedings"/>
|
||||
<xsd:enumeration value="Report"/>
|
||||
<xsd:enumeration value="SoundRecording"/>
|
||||
<xsd:enumeration value="Performance"/>
|
||||
<xsd:enumeration value="Art"/>
|
||||
<xsd:enumeration value="DocumentFromInternetSite"/>
|
||||
<xsd:enumeration value="InternetSite"/>
|
||||
<xsd:enumeration value="Film"/>
|
||||
<xsd:enumeration value="Interview"/>
|
||||
<xsd:enumeration value="Patent"/>
|
||||
<xsd:enumeration value="ElectronicSource"/>
|
||||
<xsd:enumeration value="Case"/>
|
||||
<xsd:enumeration value="Misc"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_NameListType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="Person" type="CT_PersonType" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PersonType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="Last" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="First" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="Middle" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_NameType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="NameList" type="CT_NameListType" minOccurs="1" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_NameOrCorporateType">
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||
<xsd:element name="NameList" type="CT_NameListType" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="Corporate" minOccurs="1" maxOccurs="1" type="s:ST_String"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_AuthorType">
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="Artist" type="CT_NameType"/>
|
||||
<xsd:element name="Author" type="CT_NameOrCorporateType"/>
|
||||
<xsd:element name="BookAuthor" type="CT_NameType"/>
|
||||
<xsd:element name="Compiler" type="CT_NameType"/>
|
||||
<xsd:element name="Composer" type="CT_NameType"/>
|
||||
<xsd:element name="Conductor" type="CT_NameType"/>
|
||||
<xsd:element name="Counsel" type="CT_NameType"/>
|
||||
<xsd:element name="Director" type="CT_NameType"/>
|
||||
<xsd:element name="Editor" type="CT_NameType"/>
|
||||
<xsd:element name="Interviewee" type="CT_NameType"/>
|
||||
<xsd:element name="Interviewer" type="CT_NameType"/>
|
||||
<xsd:element name="Inventor" type="CT_NameType"/>
|
||||
<xsd:element name="Performer" type="CT_NameOrCorporateType"/>
|
||||
<xsd:element name="ProducerName" type="CT_NameType"/>
|
||||
<xsd:element name="Translator" type="CT_NameType"/>
|
||||
<xsd:element name="Writer" type="CT_NameType"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SourceType">
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="AbbreviatedCaseNumber" type="s:ST_String"/>
|
||||
<xsd:element name="AlbumTitle" type="s:ST_String"/>
|
||||
<xsd:element name="Author" type="CT_AuthorType"/>
|
||||
<xsd:element name="BookTitle" type="s:ST_String"/>
|
||||
<xsd:element name="Broadcaster" type="s:ST_String"/>
|
||||
<xsd:element name="BroadcastTitle" type="s:ST_String"/>
|
||||
<xsd:element name="CaseNumber" type="s:ST_String"/>
|
||||
<xsd:element name="ChapterNumber" type="s:ST_String"/>
|
||||
<xsd:element name="City" type="s:ST_String"/>
|
||||
<xsd:element name="Comments" type="s:ST_String"/>
|
||||
<xsd:element name="ConferenceName" type="s:ST_String"/>
|
||||
<xsd:element name="CountryRegion" type="s:ST_String"/>
|
||||
<xsd:element name="Court" type="s:ST_String"/>
|
||||
<xsd:element name="Day" type="s:ST_String"/>
|
||||
<xsd:element name="DayAccessed" type="s:ST_String"/>
|
||||
<xsd:element name="Department" type="s:ST_String"/>
|
||||
<xsd:element name="Distributor" type="s:ST_String"/>
|
||||
<xsd:element name="Edition" type="s:ST_String"/>
|
||||
<xsd:element name="Guid" type="s:ST_String"/>
|
||||
<xsd:element name="Institution" type="s:ST_String"/>
|
||||
<xsd:element name="InternetSiteTitle" type="s:ST_String"/>
|
||||
<xsd:element name="Issue" type="s:ST_String"/>
|
||||
<xsd:element name="JournalName" type="s:ST_String"/>
|
||||
<xsd:element name="LCID" type="s:ST_Lang"/>
|
||||
<xsd:element name="Medium" type="s:ST_String"/>
|
||||
<xsd:element name="Month" type="s:ST_String"/>
|
||||
<xsd:element name="MonthAccessed" type="s:ST_String"/>
|
||||
<xsd:element name="NumberVolumes" type="s:ST_String"/>
|
||||
<xsd:element name="Pages" type="s:ST_String"/>
|
||||
<xsd:element name="PatentNumber" type="s:ST_String"/>
|
||||
<xsd:element name="PeriodicalTitle" type="s:ST_String"/>
|
||||
<xsd:element name="ProductionCompany" type="s:ST_String"/>
|
||||
<xsd:element name="PublicationTitle" type="s:ST_String"/>
|
||||
<xsd:element name="Publisher" type="s:ST_String"/>
|
||||
<xsd:element name="RecordingNumber" type="s:ST_String"/>
|
||||
<xsd:element name="RefOrder" type="s:ST_String"/>
|
||||
<xsd:element name="Reporter" type="s:ST_String"/>
|
||||
<xsd:element name="SourceType" type="ST_SourceType"/>
|
||||
<xsd:element name="ShortTitle" type="s:ST_String"/>
|
||||
<xsd:element name="StandardNumber" type="s:ST_String"/>
|
||||
<xsd:element name="StateProvince" type="s:ST_String"/>
|
||||
<xsd:element name="Station" type="s:ST_String"/>
|
||||
<xsd:element name="Tag" type="s:ST_String"/>
|
||||
<xsd:element name="Theater" type="s:ST_String"/>
|
||||
<xsd:element name="ThesisType" type="s:ST_String"/>
|
||||
<xsd:element name="Title" type="s:ST_String"/>
|
||||
<xsd:element name="Type" type="s:ST_String"/>
|
||||
<xsd:element name="URL" type="s:ST_String"/>
|
||||
<xsd:element name="Version" type="s:ST_String"/>
|
||||
<xsd:element name="Volume" type="s:ST_String"/>
|
||||
<xsd:element name="Year" type="s:ST_String"/>
|
||||
<xsd:element name="YearAccessed" type="s:ST_String"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="Sources" type="CT_Sources"/>
|
||||
<xsd:complexType name="CT_Sources">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="Source" type="CT_SourceType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="SelectedStyle" type="s:ST_String"/>
|
||||
<xsd:attribute name="StyleName" type="s:ST_String"/>
|
||||
<xsd:attribute name="URI" type="s:ST_String"/>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
elementFormDefault="qualified">
|
||||
<xsd:simpleType name="ST_Lang">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_HexColorRGB">
|
||||
<xsd:restriction base="xsd:hexBinary">
|
||||
<xsd:length value="3" fixed="true"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_Panose">
|
||||
<xsd:restriction base="xsd:hexBinary">
|
||||
<xsd:length value="10"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_CalendarType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="gregorian"/>
|
||||
<xsd:enumeration value="gregorianUs"/>
|
||||
<xsd:enumeration value="gregorianMeFrench"/>
|
||||
<xsd:enumeration value="gregorianArabic"/>
|
||||
<xsd:enumeration value="hijri"/>
|
||||
<xsd:enumeration value="hebrew"/>
|
||||
<xsd:enumeration value="taiwan"/>
|
||||
<xsd:enumeration value="japan"/>
|
||||
<xsd:enumeration value="thai"/>
|
||||
<xsd:enumeration value="korea"/>
|
||||
<xsd:enumeration value="saka"/>
|
||||
<xsd:enumeration value="gregorianXlitEnglish"/>
|
||||
<xsd:enumeration value="gregorianXlitFrench"/>
|
||||
<xsd:enumeration value="none"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_AlgClass">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="hash"/>
|
||||
<xsd:enumeration value="custom"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_CryptProv">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="rsaAES"/>
|
||||
<xsd:enumeration value="rsaFull"/>
|
||||
<xsd:enumeration value="custom"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_AlgType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="typeAny"/>
|
||||
<xsd:enumeration value="custom"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ColorType">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_Guid">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:pattern value="\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_OnOff">
|
||||
<xsd:union memberTypes="xsd:boolean ST_OnOff1"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_OnOff1">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="on"/>
|
||||
<xsd:enumeration value="off"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_String">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_XmlName">
|
||||
<xsd:restriction base="xsd:NCName">
|
||||
<xsd:minLength value="1"/>
|
||||
<xsd:maxLength value="255"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_TrueFalse">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="t"/>
|
||||
<xsd:enumeration value="f"/>
|
||||
<xsd:enumeration value="true"/>
|
||||
<xsd:enumeration value="false"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_TrueFalseBlank">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="t"/>
|
||||
<xsd:enumeration value="f"/>
|
||||
<xsd:enumeration value="true"/>
|
||||
<xsd:enumeration value="false"/>
|
||||
<xsd:enumeration value=""/>
|
||||
<xsd:enumeration value="True"/>
|
||||
<xsd:enumeration value="False"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_UnsignedDecimalNumber">
|
||||
<xsd:restriction base="xsd:decimal">
|
||||
<xsd:minInclusive value="0"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_TwipsMeasure">
|
||||
<xsd:union memberTypes="ST_UnsignedDecimalNumber ST_PositiveUniversalMeasure"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_VerticalAlignRun">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="baseline"/>
|
||||
<xsd:enumeration value="superscript"/>
|
||||
<xsd:enumeration value="subscript"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_Xstring">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_XAlign">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="left"/>
|
||||
<xsd:enumeration value="center"/>
|
||||
<xsd:enumeration value="right"/>
|
||||
<xsd:enumeration value="inside"/>
|
||||
<xsd:enumeration value="outside"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_YAlign">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="inline"/>
|
||||
<xsd:enumeration value="top"/>
|
||||
<xsd:enumeration value="center"/>
|
||||
<xsd:enumeration value="bottom"/>
|
||||
<xsd:enumeration value="inside"/>
|
||||
<xsd:enumeration value="outside"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ConformanceClass">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="strict"/>
|
||||
<xsd:enumeration value="transitional"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_UniversalMeasure">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:pattern value="-?[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_PositiveUniversalMeasure">
|
||||
<xsd:restriction base="ST_UniversalMeasure">
|
||||
<xsd:pattern value="[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_Percentage">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:pattern value="-?[0-9]+(\.[0-9]+)?%"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_FixedPercentage">
|
||||
<xsd:restriction base="ST_Percentage">
|
||||
<xsd:pattern value="-?((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_PositivePercentage">
|
||||
<xsd:restriction base="ST_Percentage">
|
||||
<xsd:pattern value="[0-9]+(\.[0-9]+)?%"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_PositiveFixedPercentage">
|
||||
<xsd:restriction base="ST_Percentage">
|
||||
<xsd:pattern value="((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/customXml"
|
||||
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/customXml"
|
||||
elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:complexType name="CT_DatastoreSchemaRef">
|
||||
<xsd:attribute name="uri" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_DatastoreSchemaRefs">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="schemaRef" type="CT_DatastoreSchemaRef" minOccurs="0" maxOccurs="unbounded"
|
||||
/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_DatastoreItem">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="schemaRefs" type="CT_DatastoreSchemaRefs" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="itemID" type="s:ST_Guid" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="datastoreItem" type="CT_DatastoreItem"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/schemaLibrary/2006/main"
|
||||
targetNamespace="http://schemas.openxmlformats.org/schemaLibrary/2006/main"
|
||||
attributeFormDefault="qualified" elementFormDefault="qualified">
|
||||
<xsd:complexType name="CT_Schema">
|
||||
<xsd:attribute name="uri" type="xsd:string" default=""/>
|
||||
<xsd:attribute name="manifestLocation" type="xsd:string"/>
|
||||
<xsd:attribute name="schemaLocation" type="xsd:string"/>
|
||||
<xsd:attribute name="schemaLanguage" type="xsd:token"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SchemaLibrary">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="schema" type="CT_Schema" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="schemaLibrary" type="CT_SchemaLibrary"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"
|
||||
xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"
|
||||
blockDefault="#all" elementFormDefault="qualified">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||
schemaLocation="shared-documentPropertiesVariantTypes.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:element name="Properties" type="CT_Properties"/>
|
||||
<xsd:complexType name="CT_Properties">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="property" minOccurs="0" maxOccurs="unbounded" type="CT_Property"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Property">
|
||||
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||
<xsd:element ref="vt:vector"/>
|
||||
<xsd:element ref="vt:array"/>
|
||||
<xsd:element ref="vt:blob"/>
|
||||
<xsd:element ref="vt:oblob"/>
|
||||
<xsd:element ref="vt:empty"/>
|
||||
<xsd:element ref="vt:null"/>
|
||||
<xsd:element ref="vt:i1"/>
|
||||
<xsd:element ref="vt:i2"/>
|
||||
<xsd:element ref="vt:i4"/>
|
||||
<xsd:element ref="vt:i8"/>
|
||||
<xsd:element ref="vt:int"/>
|
||||
<xsd:element ref="vt:ui1"/>
|
||||
<xsd:element ref="vt:ui2"/>
|
||||
<xsd:element ref="vt:ui4"/>
|
||||
<xsd:element ref="vt:ui8"/>
|
||||
<xsd:element ref="vt:uint"/>
|
||||
<xsd:element ref="vt:r4"/>
|
||||
<xsd:element ref="vt:r8"/>
|
||||
<xsd:element ref="vt:decimal"/>
|
||||
<xsd:element ref="vt:lpstr"/>
|
||||
<xsd:element ref="vt:lpwstr"/>
|
||||
<xsd:element ref="vt:bstr"/>
|
||||
<xsd:element ref="vt:date"/>
|
||||
<xsd:element ref="vt:filetime"/>
|
||||
<xsd:element ref="vt:bool"/>
|
||||
<xsd:element ref="vt:cy"/>
|
||||
<xsd:element ref="vt:error"/>
|
||||
<xsd:element ref="vt:stream"/>
|
||||
<xsd:element ref="vt:ostream"/>
|
||||
<xsd:element ref="vt:storage"/>
|
||||
<xsd:element ref="vt:ostorage"/>
|
||||
<xsd:element ref="vt:vstream"/>
|
||||
<xsd:element ref="vt:clsid"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="fmtid" use="required" type="s:ST_Guid"/>
|
||||
<xsd:attribute name="pid" use="required" type="xsd:int"/>
|
||||
<xsd:attribute name="name" use="optional" type="xsd:string"/>
|
||||
<xsd:attribute name="linkTarget" use="optional" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
|
||||
xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
|
||||
elementFormDefault="qualified" blockDefault="#all">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||
schemaLocation="shared-documentPropertiesVariantTypes.xsd"/>
|
||||
<xsd:element name="Properties" type="CT_Properties"/>
|
||||
<xsd:complexType name="CT_Properties">
|
||||
<xsd:all>
|
||||
<xsd:element name="Template" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||
<xsd:element name="Manager" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||
<xsd:element name="Company" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||
<xsd:element name="Pages" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="Words" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="Characters" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="PresentationFormat" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||
<xsd:element name="Lines" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="Paragraphs" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="Slides" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="Notes" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="TotalTime" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="HiddenSlides" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="MMClips" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="ScaleCrop" minOccurs="0" maxOccurs="1" type="xsd:boolean"/>
|
||||
<xsd:element name="HeadingPairs" minOccurs="0" maxOccurs="1" type="CT_VectorVariant"/>
|
||||
<xsd:element name="TitlesOfParts" minOccurs="0" maxOccurs="1" type="CT_VectorLpstr"/>
|
||||
<xsd:element name="LinksUpToDate" minOccurs="0" maxOccurs="1" type="xsd:boolean"/>
|
||||
<xsd:element name="CharactersWithSpaces" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
<xsd:element name="SharedDoc" minOccurs="0" maxOccurs="1" type="xsd:boolean"/>
|
||||
<xsd:element name="HyperlinkBase" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||
<xsd:element name="HLinks" minOccurs="0" maxOccurs="1" type="CT_VectorVariant"/>
|
||||
<xsd:element name="HyperlinksChanged" minOccurs="0" maxOccurs="1" type="xsd:boolean"/>
|
||||
<xsd:element name="DigSig" minOccurs="0" maxOccurs="1" type="CT_DigSigBlob"/>
|
||||
<xsd:element name="Application" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||
<xsd:element name="AppVersion" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||
<xsd:element name="DocSecurity" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||
</xsd:all>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_VectorVariant">
|
||||
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||
<xsd:element ref="vt:vector"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_VectorLpstr">
|
||||
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||
<xsd:element ref="vt:vector"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_DigSigBlob">
|
||||
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||
<xsd:element ref="vt:blob"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,195 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||
blockDefault="#all" elementFormDefault="qualified">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:simpleType name="ST_VectorBaseType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="variant"/>
|
||||
<xsd:enumeration value="i1"/>
|
||||
<xsd:enumeration value="i2"/>
|
||||
<xsd:enumeration value="i4"/>
|
||||
<xsd:enumeration value="i8"/>
|
||||
<xsd:enumeration value="ui1"/>
|
||||
<xsd:enumeration value="ui2"/>
|
||||
<xsd:enumeration value="ui4"/>
|
||||
<xsd:enumeration value="ui8"/>
|
||||
<xsd:enumeration value="r4"/>
|
||||
<xsd:enumeration value="r8"/>
|
||||
<xsd:enumeration value="lpstr"/>
|
||||
<xsd:enumeration value="lpwstr"/>
|
||||
<xsd:enumeration value="bstr"/>
|
||||
<xsd:enumeration value="date"/>
|
||||
<xsd:enumeration value="filetime"/>
|
||||
<xsd:enumeration value="bool"/>
|
||||
<xsd:enumeration value="cy"/>
|
||||
<xsd:enumeration value="error"/>
|
||||
<xsd:enumeration value="clsid"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ArrayBaseType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="variant"/>
|
||||
<xsd:enumeration value="i1"/>
|
||||
<xsd:enumeration value="i2"/>
|
||||
<xsd:enumeration value="i4"/>
|
||||
<xsd:enumeration value="int"/>
|
||||
<xsd:enumeration value="ui1"/>
|
||||
<xsd:enumeration value="ui2"/>
|
||||
<xsd:enumeration value="ui4"/>
|
||||
<xsd:enumeration value="uint"/>
|
||||
<xsd:enumeration value="r4"/>
|
||||
<xsd:enumeration value="r8"/>
|
||||
<xsd:enumeration value="decimal"/>
|
||||
<xsd:enumeration value="bstr"/>
|
||||
<xsd:enumeration value="date"/>
|
||||
<xsd:enumeration value="bool"/>
|
||||
<xsd:enumeration value="cy"/>
|
||||
<xsd:enumeration value="error"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_Cy">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:pattern value="\s*[0-9]*\.[0-9]{4}\s*"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_Error">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:pattern value="\s*0x[0-9A-Za-z]{8}\s*"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Empty"/>
|
||||
<xsd:complexType name="CT_Null"/>
|
||||
<xsd:complexType name="CT_Vector">
|
||||
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xsd:element ref="variant"/>
|
||||
<xsd:element ref="i1"/>
|
||||
<xsd:element ref="i2"/>
|
||||
<xsd:element ref="i4"/>
|
||||
<xsd:element ref="i8"/>
|
||||
<xsd:element ref="ui1"/>
|
||||
<xsd:element ref="ui2"/>
|
||||
<xsd:element ref="ui4"/>
|
||||
<xsd:element ref="ui8"/>
|
||||
<xsd:element ref="r4"/>
|
||||
<xsd:element ref="r8"/>
|
||||
<xsd:element ref="lpstr"/>
|
||||
<xsd:element ref="lpwstr"/>
|
||||
<xsd:element ref="bstr"/>
|
||||
<xsd:element ref="date"/>
|
||||
<xsd:element ref="filetime"/>
|
||||
<xsd:element ref="bool"/>
|
||||
<xsd:element ref="cy"/>
|
||||
<xsd:element ref="error"/>
|
||||
<xsd:element ref="clsid"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="baseType" type="ST_VectorBaseType" use="required"/>
|
||||
<xsd:attribute name="size" type="xsd:unsignedInt" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Array">
|
||||
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xsd:element ref="variant"/>
|
||||
<xsd:element ref="i1"/>
|
||||
<xsd:element ref="i2"/>
|
||||
<xsd:element ref="i4"/>
|
||||
<xsd:element ref="int"/>
|
||||
<xsd:element ref="ui1"/>
|
||||
<xsd:element ref="ui2"/>
|
||||
<xsd:element ref="ui4"/>
|
||||
<xsd:element ref="uint"/>
|
||||
<xsd:element ref="r4"/>
|
||||
<xsd:element ref="r8"/>
|
||||
<xsd:element ref="decimal"/>
|
||||
<xsd:element ref="bstr"/>
|
||||
<xsd:element ref="date"/>
|
||||
<xsd:element ref="bool"/>
|
||||
<xsd:element ref="error"/>
|
||||
<xsd:element ref="cy"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="lBounds" type="xsd:int" use="required"/>
|
||||
<xsd:attribute name="uBounds" type="xsd:int" use="required"/>
|
||||
<xsd:attribute name="baseType" type="ST_ArrayBaseType" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Variant">
|
||||
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||
<xsd:element ref="variant"/>
|
||||
<xsd:element ref="vector"/>
|
||||
<xsd:element ref="array"/>
|
||||
<xsd:element ref="blob"/>
|
||||
<xsd:element ref="oblob"/>
|
||||
<xsd:element ref="empty"/>
|
||||
<xsd:element ref="null"/>
|
||||
<xsd:element ref="i1"/>
|
||||
<xsd:element ref="i2"/>
|
||||
<xsd:element ref="i4"/>
|
||||
<xsd:element ref="i8"/>
|
||||
<xsd:element ref="int"/>
|
||||
<xsd:element ref="ui1"/>
|
||||
<xsd:element ref="ui2"/>
|
||||
<xsd:element ref="ui4"/>
|
||||
<xsd:element ref="ui8"/>
|
||||
<xsd:element ref="uint"/>
|
||||
<xsd:element ref="r4"/>
|
||||
<xsd:element ref="r8"/>
|
||||
<xsd:element ref="decimal"/>
|
||||
<xsd:element ref="lpstr"/>
|
||||
<xsd:element ref="lpwstr"/>
|
||||
<xsd:element ref="bstr"/>
|
||||
<xsd:element ref="date"/>
|
||||
<xsd:element ref="filetime"/>
|
||||
<xsd:element ref="bool"/>
|
||||
<xsd:element ref="cy"/>
|
||||
<xsd:element ref="error"/>
|
||||
<xsd:element ref="stream"/>
|
||||
<xsd:element ref="ostream"/>
|
||||
<xsd:element ref="storage"/>
|
||||
<xsd:element ref="ostorage"/>
|
||||
<xsd:element ref="vstream"/>
|
||||
<xsd:element ref="clsid"/>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Vstream">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:base64Binary">
|
||||
<xsd:attribute name="version" type="s:ST_Guid"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="variant" type="CT_Variant"/>
|
||||
<xsd:element name="vector" type="CT_Vector"/>
|
||||
<xsd:element name="array" type="CT_Array"/>
|
||||
<xsd:element name="blob" type="xsd:base64Binary"/>
|
||||
<xsd:element name="oblob" type="xsd:base64Binary"/>
|
||||
<xsd:element name="empty" type="CT_Empty"/>
|
||||
<xsd:element name="null" type="CT_Null"/>
|
||||
<xsd:element name="i1" type="xsd:byte"/>
|
||||
<xsd:element name="i2" type="xsd:short"/>
|
||||
<xsd:element name="i4" type="xsd:int"/>
|
||||
<xsd:element name="i8" type="xsd:long"/>
|
||||
<xsd:element name="int" type="xsd:int"/>
|
||||
<xsd:element name="ui1" type="xsd:unsignedByte"/>
|
||||
<xsd:element name="ui2" type="xsd:unsignedShort"/>
|
||||
<xsd:element name="ui4" type="xsd:unsignedInt"/>
|
||||
<xsd:element name="ui8" type="xsd:unsignedLong"/>
|
||||
<xsd:element name="uint" type="xsd:unsignedInt"/>
|
||||
<xsd:element name="r4" type="xsd:float"/>
|
||||
<xsd:element name="r8" type="xsd:double"/>
|
||||
<xsd:element name="decimal" type="xsd:decimal"/>
|
||||
<xsd:element name="lpstr" type="xsd:string"/>
|
||||
<xsd:element name="lpwstr" type="xsd:string"/>
|
||||
<xsd:element name="bstr" type="xsd:string"/>
|
||||
<xsd:element name="date" type="xsd:dateTime"/>
|
||||
<xsd:element name="filetime" type="xsd:dateTime"/>
|
||||
<xsd:element name="bool" type="xsd:boolean"/>
|
||||
<xsd:element name="cy" type="ST_Cy"/>
|
||||
<xsd:element name="error" type="ST_Error"/>
|
||||
<xsd:element name="stream" type="xsd:base64Binary"/>
|
||||
<xsd:element name="ostream" type="xsd:base64Binary"/>
|
||||
<xsd:element name="storage" type="xsd:base64Binary"/>
|
||||
<xsd:element name="ostorage" type="xsd:base64Binary"/>
|
||||
<xsd:element name="vstream" type="CT_Vstream"/>
|
||||
<xsd:element name="clsid" type="s:ST_Guid"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,582 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/math"
|
||||
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
|
||||
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/math">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
schemaLocation="wml.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>
|
||||
<xsd:simpleType name="ST_Integer255">
|
||||
<xsd:restriction base="xsd:integer">
|
||||
<xsd:minInclusive value="1"/>
|
||||
<xsd:maxInclusive value="255"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Integer255">
|
||||
<xsd:attribute name="val" type="ST_Integer255" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Integer2">
|
||||
<xsd:restriction base="xsd:integer">
|
||||
<xsd:minInclusive value="-2"/>
|
||||
<xsd:maxInclusive value="2"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Integer2">
|
||||
<xsd:attribute name="val" type="ST_Integer2" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_SpacingRule">
|
||||
<xsd:restriction base="xsd:integer">
|
||||
<xsd:minInclusive value="0"/>
|
||||
<xsd:maxInclusive value="4"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_SpacingRule">
|
||||
<xsd:attribute name="val" type="ST_SpacingRule" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_UnSignedInteger">
|
||||
<xsd:restriction base="xsd:unsignedInt"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_UnSignedInteger">
|
||||
<xsd:attribute name="val" type="ST_UnSignedInteger" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Char">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:maxLength value="1"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Char">
|
||||
<xsd:attribute name="val" type="ST_Char" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_OnOff">
|
||||
<xsd:attribute name="val" type="s:ST_OnOff"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_String">
|
||||
<xsd:attribute name="val" type="s:ST_String"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_XAlign">
|
||||
<xsd:attribute name="val" type="s:ST_XAlign" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_YAlign">
|
||||
<xsd:attribute name="val" type="s:ST_YAlign" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Shp">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="centered"/>
|
||||
<xsd:enumeration value="match"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Shp">
|
||||
<xsd:attribute name="val" type="ST_Shp" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_FType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="bar"/>
|
||||
<xsd:enumeration value="skw"/>
|
||||
<xsd:enumeration value="lin"/>
|
||||
<xsd:enumeration value="noBar"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_FType">
|
||||
<xsd:attribute name="val" type="ST_FType" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_LimLoc">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="undOvr"/>
|
||||
<xsd:enumeration value="subSup"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_LimLoc">
|
||||
<xsd:attribute name="val" type="ST_LimLoc" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_TopBot">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="top"/>
|
||||
<xsd:enumeration value="bot"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_TopBot">
|
||||
<xsd:attribute name="val" type="ST_TopBot" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Script">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="roman"/>
|
||||
<xsd:enumeration value="script"/>
|
||||
<xsd:enumeration value="fraktur"/>
|
||||
<xsd:enumeration value="double-struck"/>
|
||||
<xsd:enumeration value="sans-serif"/>
|
||||
<xsd:enumeration value="monospace"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Script">
|
||||
<xsd:attribute name="val" type="ST_Script"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Style">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="p"/>
|
||||
<xsd:enumeration value="b"/>
|
||||
<xsd:enumeration value="i"/>
|
||||
<xsd:enumeration value="bi"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Style">
|
||||
<xsd:attribute name="val" type="ST_Style"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ManualBreak">
|
||||
<xsd:attribute name="alnAt" type="ST_Integer255"/>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_ScriptStyle">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="scr" minOccurs="0" type="CT_Script"/>
|
||||
<xsd:element name="sty" minOccurs="0" type="CT_Style"/>
|
||||
</xsd:sequence>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_RPR">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="lit" minOccurs="0" type="CT_OnOff"/>
|
||||
<xsd:choice>
|
||||
<xsd:element name="nor" minOccurs="0" type="CT_OnOff"/>
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ScriptStyle"/>
|
||||
</xsd:sequence>
|
||||
</xsd:choice>
|
||||
<xsd:element name="brk" minOccurs="0" type="CT_ManualBreak"/>
|
||||
<xsd:element name="aln" minOccurs="0" type="CT_OnOff"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Text">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="s:ST_String">
|
||||
<xsd:attribute ref="xml:space" use="optional"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_R">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="rPr" type="CT_RPR" minOccurs="0"/>
|
||||
<xsd:group ref="w:EG_RPr" minOccurs="0"/>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:group ref="w:EG_RunInnerContent"/>
|
||||
<xsd:element name="t" type="CT_Text" minOccurs="0"/>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_CtrlPr">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="w:EG_RPrMath" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_AccPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="chr" type="CT_Char" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Acc">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="accPr" type="CT_AccPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_BarPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="pos" type="CT_TopBot" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Bar">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="barPr" type="CT_BarPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_BoxPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="opEmu" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="noBreak" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="diff" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="brk" type="CT_ManualBreak" minOccurs="0"/>
|
||||
<xsd:element name="aln" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Box">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="boxPr" type="CT_BoxPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_BorderBoxPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="hideTop" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="hideBot" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="hideLeft" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="hideRight" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="strikeH" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="strikeV" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="strikeBLTR" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="strikeTLBR" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_BorderBox">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="borderBoxPr" type="CT_BorderBoxPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_DPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="begChr" type="CT_Char" minOccurs="0"/>
|
||||
<xsd:element name="sepChr" type="CT_Char" minOccurs="0"/>
|
||||
<xsd:element name="endChr" type="CT_Char" minOccurs="0"/>
|
||||
<xsd:element name="grow" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="shp" type="CT_Shp" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_D">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="dPr" type="CT_DPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_EqArrPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="baseJc" type="CT_YAlign" minOccurs="0"/>
|
||||
<xsd:element name="maxDist" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="objDist" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="rSpRule" type="CT_SpacingRule" minOccurs="0"/>
|
||||
<xsd:element name="rSp" type="CT_UnSignedInteger" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_EqArr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="eqArrPr" type="CT_EqArrPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_FPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="type" type="CT_FType" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_F">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="fPr" type="CT_FPr" minOccurs="0"/>
|
||||
<xsd:element name="num" type="CT_OMathArg"/>
|
||||
<xsd:element name="den" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_FuncPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Func">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="funcPr" type="CT_FuncPr" minOccurs="0"/>
|
||||
<xsd:element name="fName" type="CT_OMathArg"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GroupChrPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="chr" type="CT_Char" minOccurs="0"/>
|
||||
<xsd:element name="pos" type="CT_TopBot" minOccurs="0"/>
|
||||
<xsd:element name="vertJc" type="CT_TopBot" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GroupChr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="groupChrPr" type="CT_GroupChrPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_LimLowPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_LimLow">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="limLowPr" type="CT_LimLowPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
<xsd:element name="lim" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_LimUppPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_LimUpp">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="limUppPr" type="CT_LimUppPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
<xsd:element name="lim" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_MCPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="count" type="CT_Integer255" minOccurs="0"/>
|
||||
<xsd:element name="mcJc" type="CT_XAlign" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_MC">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="mcPr" type="CT_MCPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_MCS">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="mc" type="CT_MC" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_MPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="baseJc" type="CT_YAlign" minOccurs="0"/>
|
||||
<xsd:element name="plcHide" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="rSpRule" type="CT_SpacingRule" minOccurs="0"/>
|
||||
<xsd:element name="cGpRule" type="CT_SpacingRule" minOccurs="0"/>
|
||||
<xsd:element name="rSp" type="CT_UnSignedInteger" minOccurs="0"/>
|
||||
<xsd:element name="cSp" type="CT_UnSignedInteger" minOccurs="0"/>
|
||||
<xsd:element name="cGp" type="CT_UnSignedInteger" minOccurs="0"/>
|
||||
<xsd:element name="mcs" type="CT_MCS" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_MR">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_M">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="mPr" type="CT_MPr" minOccurs="0"/>
|
||||
<xsd:element name="mr" type="CT_MR" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_NaryPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="chr" type="CT_Char" minOccurs="0"/>
|
||||
<xsd:element name="limLoc" type="CT_LimLoc" minOccurs="0"/>
|
||||
<xsd:element name="grow" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="subHide" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="supHide" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Nary">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="naryPr" type="CT_NaryPr" minOccurs="0"/>
|
||||
<xsd:element name="sub" type="CT_OMathArg"/>
|
||||
<xsd:element name="sup" type="CT_OMathArg"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PhantPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="show" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="zeroWid" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="zeroAsc" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="zeroDesc" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="transp" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Phant">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="phantPr" type="CT_PhantPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_RadPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="degHide" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Rad">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="radPr" type="CT_RadPr" minOccurs="0"/>
|
||||
<xsd:element name="deg" type="CT_OMathArg"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SPrePr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SPre">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="sPrePr" type="CT_SPrePr" minOccurs="0"/>
|
||||
<xsd:element name="sub" type="CT_OMathArg"/>
|
||||
<xsd:element name="sup" type="CT_OMathArg"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SSubPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SSub">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="sSubPr" type="CT_SSubPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
<xsd:element name="sub" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SSubSupPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="alnScr" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SSubSup">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="sSubSupPr" type="CT_SSubSupPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
<xsd:element name="sub" type="CT_OMathArg"/>
|
||||
<xsd:element name="sup" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SSupPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SSup">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="sSupPr" type="CT_SSupPr" minOccurs="0"/>
|
||||
<xsd:element name="e" type="CT_OMathArg"/>
|
||||
<xsd:element name="sup" type="CT_OMathArg"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_OMathMathElements">
|
||||
<xsd:choice>
|
||||
<xsd:element name="acc" type="CT_Acc"/>
|
||||
<xsd:element name="bar" type="CT_Bar"/>
|
||||
<xsd:element name="box" type="CT_Box"/>
|
||||
<xsd:element name="borderBox" type="CT_BorderBox"/>
|
||||
<xsd:element name="d" type="CT_D"/>
|
||||
<xsd:element name="eqArr" type="CT_EqArr"/>
|
||||
<xsd:element name="f" type="CT_F"/>
|
||||
<xsd:element name="func" type="CT_Func"/>
|
||||
<xsd:element name="groupChr" type="CT_GroupChr"/>
|
||||
<xsd:element name="limLow" type="CT_LimLow"/>
|
||||
<xsd:element name="limUpp" type="CT_LimUpp"/>
|
||||
<xsd:element name="m" type="CT_M"/>
|
||||
<xsd:element name="nary" type="CT_Nary"/>
|
||||
<xsd:element name="phant" type="CT_Phant"/>
|
||||
<xsd:element name="rad" type="CT_Rad"/>
|
||||
<xsd:element name="sPre" type="CT_SPre"/>
|
||||
<xsd:element name="sSub" type="CT_SSub"/>
|
||||
<xsd:element name="sSubSup" type="CT_SSubSup"/>
|
||||
<xsd:element name="sSup" type="CT_SSup"/>
|
||||
<xsd:element name="r" type="CT_R"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:group name="EG_OMathElements">
|
||||
<xsd:choice>
|
||||
<xsd:group ref="EG_OMathMathElements"/>
|
||||
<xsd:group ref="w:EG_PContentMath"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_OMathArgPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="argSz" type="CT_Integer2" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_OMathArg">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="argPr" type="CT_OMathArgPr" minOccurs="0"/>
|
||||
<xsd:group ref="EG_OMathElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Jc">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="left"/>
|
||||
<xsd:enumeration value="right"/>
|
||||
<xsd:enumeration value="center"/>
|
||||
<xsd:enumeration value="centerGroup"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_OMathJc">
|
||||
<xsd:attribute name="val" type="ST_Jc"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_OMathParaPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="jc" type="CT_OMathJc" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_TwipsMeasure">
|
||||
<xsd:attribute name="val" type="s:ST_TwipsMeasure" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_BreakBin">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="before"/>
|
||||
<xsd:enumeration value="after"/>
|
||||
<xsd:enumeration value="repeat"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_BreakBin">
|
||||
<xsd:attribute name="val" type="ST_BreakBin"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_BreakBinSub">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="--"/>
|
||||
<xsd:enumeration value="-+"/>
|
||||
<xsd:enumeration value="+-"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_BreakBinSub">
|
||||
<xsd:attribute name="val" type="ST_BreakBinSub"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_MathPr">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="mathFont" type="CT_String" minOccurs="0"/>
|
||||
<xsd:element name="brkBin" type="CT_BreakBin" minOccurs="0"/>
|
||||
<xsd:element name="brkBinSub" type="CT_BreakBinSub" minOccurs="0"/>
|
||||
<xsd:element name="smallFrac" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="dispDef" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="lMargin" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||
<xsd:element name="rMargin" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||
<xsd:element name="defJc" type="CT_OMathJc" minOccurs="0"/>
|
||||
<xsd:element name="preSp" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||
<xsd:element name="postSp" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||
<xsd:element name="interSp" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||
<xsd:element name="intraSp" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||
<xsd:choice minOccurs="0">
|
||||
<xsd:element name="wrapIndent" type="CT_TwipsMeasure"/>
|
||||
<xsd:element name="wrapRight" type="CT_OnOff"/>
|
||||
</xsd:choice>
|
||||
<xsd:element name="intLim" type="CT_LimLoc" minOccurs="0"/>
|
||||
<xsd:element name="naryLim" type="CT_LimLoc" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="mathPr" type="CT_MathPr"/>
|
||||
<xsd:complexType name="CT_OMathPara">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="oMathParaPr" type="CT_OMathParaPr" minOccurs="0"/>
|
||||
<xsd:element name="oMath" type="CT_OMath" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_OMath">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_OMathElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="oMathPara" type="CT_OMathPara"/>
|
||||
<xsd:element name="oMath" type="CT_OMath"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
elementFormDefault="qualified"
|
||||
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
blockDefault="#all">
|
||||
<xsd:simpleType name="ST_RelationshipId">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:attribute name="id" type="ST_RelationshipId"/>
|
||||
<xsd:attribute name="embed" type="ST_RelationshipId"/>
|
||||
<xsd:attribute name="link" type="ST_RelationshipId"/>
|
||||
<xsd:attribute name="dm" type="ST_RelationshipId" default=""/>
|
||||
<xsd:attribute name="lo" type="ST_RelationshipId" default=""/>
|
||||
<xsd:attribute name="qs" type="ST_RelationshipId" default=""/>
|
||||
<xsd:attribute name="cs" type="ST_RelationshipId" default=""/>
|
||||
<xsd:attribute name="blip" type="ST_RelationshipId" default=""/>
|
||||
<xsd:attribute name="pict" type="ST_RelationshipId"/>
|
||||
<xsd:attribute name="href" type="ST_RelationshipId"/>
|
||||
<xsd:attribute name="topLeft" type="ST_RelationshipId"/>
|
||||
<xsd:attribute name="topRight" type="ST_RelationshipId"/>
|
||||
<xsd:attribute name="bottomLeft" type="ST_RelationshipId"/>
|
||||
<xsd:attribute name="bottomRight" type="ST_RelationshipId"/>
|
||||
</xsd:schema>
|
||||
4439
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd
Normal file
4439
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,570 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:schemas-microsoft-com:vml"
|
||||
xmlns:pvml="urn:schemas-microsoft-com:office:powerpoint"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
xmlns:w10="urn:schemas-microsoft-com:office:word"
|
||||
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
xmlns:x="urn:schemas-microsoft-com:office:excel"
|
||||
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
targetNamespace="urn:schemas-microsoft-com:vml" elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
<xsd:import namespace="urn:schemas-microsoft-com:office:office"
|
||||
schemaLocation="vml-officeDrawing.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
schemaLocation="wml.xsd"/>
|
||||
<xsd:import namespace="urn:schemas-microsoft-com:office:word"
|
||||
schemaLocation="vml-wordprocessingDrawing.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
schemaLocation="shared-relationshipReference.xsd"/>
|
||||
<xsd:import namespace="urn:schemas-microsoft-com:office:excel"
|
||||
schemaLocation="vml-spreadsheetDrawing.xsd"/>
|
||||
<xsd:import namespace="urn:schemas-microsoft-com:office:powerpoint"
|
||||
schemaLocation="vml-presentationDrawing.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:attributeGroup name="AG_Id">
|
||||
<xsd:attribute name="id" type="xsd:string" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_Style">
|
||||
<xsd:attribute name="style" type="xsd:string" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_Type">
|
||||
<xsd:attribute name="type" type="xsd:string" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_Adj">
|
||||
<xsd:attribute name="adj" type="xsd:string" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_Path">
|
||||
<xsd:attribute name="path" type="xsd:string" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_Fill">
|
||||
<xsd:attribute name="filled" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="fillcolor" type="s:ST_ColorType" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_Chromakey">
|
||||
<xsd:attribute name="chromakey" type="s:ST_ColorType" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_Ext">
|
||||
<xsd:attribute name="ext" form="qualified" type="ST_Ext"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_CoreAttributes">
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attributeGroup ref="AG_Style"/>
|
||||
<xsd:attribute name="href" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="target" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="class" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="title" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="alt" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="coordsize" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="coordorigin" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="wrapcoords" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="print" type="s:ST_TrueFalse" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_ShapeAttributes">
|
||||
<xsd:attributeGroup ref="AG_Chromakey"/>
|
||||
<xsd:attributeGroup ref="AG_Fill"/>
|
||||
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="stroked" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="strokecolor" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="strokeweight" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_OfficeCoreAttributes">
|
||||
<xsd:attribute ref="o:spid"/>
|
||||
<xsd:attribute ref="o:oned"/>
|
||||
<xsd:attribute ref="o:regroupid"/>
|
||||
<xsd:attribute ref="o:doubleclicknotify"/>
|
||||
<xsd:attribute ref="o:button"/>
|
||||
<xsd:attribute ref="o:userhidden"/>
|
||||
<xsd:attribute ref="o:bullet"/>
|
||||
<xsd:attribute ref="o:hr"/>
|
||||
<xsd:attribute ref="o:hrstd"/>
|
||||
<xsd:attribute ref="o:hrnoshade"/>
|
||||
<xsd:attribute ref="o:hrpct"/>
|
||||
<xsd:attribute ref="o:hralign"/>
|
||||
<xsd:attribute ref="o:allowincell"/>
|
||||
<xsd:attribute ref="o:allowoverlap"/>
|
||||
<xsd:attribute ref="o:userdrawn"/>
|
||||
<xsd:attribute ref="o:bordertopcolor"/>
|
||||
<xsd:attribute ref="o:borderleftcolor"/>
|
||||
<xsd:attribute ref="o:borderbottomcolor"/>
|
||||
<xsd:attribute ref="o:borderrightcolor"/>
|
||||
<xsd:attribute ref="o:dgmlayout"/>
|
||||
<xsd:attribute ref="o:dgmnodekind"/>
|
||||
<xsd:attribute ref="o:dgmlayoutmru"/>
|
||||
<xsd:attribute ref="o:insetmode"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_OfficeShapeAttributes">
|
||||
<xsd:attribute ref="o:spt"/>
|
||||
<xsd:attribute ref="o:connectortype"/>
|
||||
<xsd:attribute ref="o:bwmode"/>
|
||||
<xsd:attribute ref="o:bwpure"/>
|
||||
<xsd:attribute ref="o:bwnormal"/>
|
||||
<xsd:attribute ref="o:forcedash"/>
|
||||
<xsd:attribute ref="o:oleicon"/>
|
||||
<xsd:attribute ref="o:ole"/>
|
||||
<xsd:attribute ref="o:preferrelative"/>
|
||||
<xsd:attribute ref="o:cliptowrap"/>
|
||||
<xsd:attribute ref="o:clip"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_AllCoreAttributes">
|
||||
<xsd:attributeGroup ref="AG_CoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_OfficeCoreAttributes"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_AllShapeAttributes">
|
||||
<xsd:attributeGroup ref="AG_ShapeAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_OfficeShapeAttributes"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_ImageAttributes">
|
||||
<xsd:attribute name="src" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="cropleft" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="croptop" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="cropright" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="cropbottom" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="gain" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="blacklevel" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="gamma" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="grayscale" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="bilevel" type="s:ST_TrueFalse" use="optional"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attributeGroup name="AG_StrokeAttributes">
|
||||
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="weight" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="linestyle" type="ST_StrokeLineStyle" use="optional"/>
|
||||
<xsd:attribute name="miterlimit" type="xsd:decimal" use="optional"/>
|
||||
<xsd:attribute name="joinstyle" type="ST_StrokeJoinStyle" use="optional"/>
|
||||
<xsd:attribute name="endcap" type="ST_StrokeEndCap" use="optional"/>
|
||||
<xsd:attribute name="dashstyle" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="filltype" type="ST_FillType" use="optional"/>
|
||||
<xsd:attribute name="src" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="imageaspect" type="ST_ImageAspect" use="optional"/>
|
||||
<xsd:attribute name="imagesize" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="imagealignshape" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="startarrow" type="ST_StrokeArrowType" use="optional"/>
|
||||
<xsd:attribute name="startarrowwidth" type="ST_StrokeArrowWidth" use="optional"/>
|
||||
<xsd:attribute name="startarrowlength" type="ST_StrokeArrowLength" use="optional"/>
|
||||
<xsd:attribute name="endarrow" type="ST_StrokeArrowType" use="optional"/>
|
||||
<xsd:attribute name="endarrowwidth" type="ST_StrokeArrowWidth" use="optional"/>
|
||||
<xsd:attribute name="endarrowlength" type="ST_StrokeArrowLength" use="optional"/>
|
||||
<xsd:attribute ref="o:href"/>
|
||||
<xsd:attribute ref="o:althref"/>
|
||||
<xsd:attribute ref="o:title"/>
|
||||
<xsd:attribute ref="o:forcedash"/>
|
||||
<xsd:attribute ref="r:id" use="optional"/>
|
||||
<xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute ref="o:relid"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:group name="EG_ShapeElements">
|
||||
<xsd:choice>
|
||||
<xsd:element ref="path"/>
|
||||
<xsd:element ref="formulas"/>
|
||||
<xsd:element ref="handles"/>
|
||||
<xsd:element ref="fill"/>
|
||||
<xsd:element ref="stroke"/>
|
||||
<xsd:element ref="shadow"/>
|
||||
<xsd:element ref="textbox"/>
|
||||
<xsd:element ref="textpath"/>
|
||||
<xsd:element ref="imagedata"/>
|
||||
<xsd:element ref="o:skew"/>
|
||||
<xsd:element ref="o:extrusion"/>
|
||||
<xsd:element ref="o:callout"/>
|
||||
<xsd:element ref="o:lock"/>
|
||||
<xsd:element ref="o:clippath"/>
|
||||
<xsd:element ref="o:signatureline"/>
|
||||
<xsd:element ref="w10:wrap"/>
|
||||
<xsd:element ref="w10:anchorlock"/>
|
||||
<xsd:element ref="w10:bordertop"/>
|
||||
<xsd:element ref="w10:borderbottom"/>
|
||||
<xsd:element ref="w10:borderleft"/>
|
||||
<xsd:element ref="w10:borderright"/>
|
||||
<xsd:element ref="x:ClientData" minOccurs="0"/>
|
||||
<xsd:element ref="pvml:textdata" minOccurs="0"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:element name="shape" type="CT_Shape"/>
|
||||
<xsd:element name="shapetype" type="CT_Shapetype"/>
|
||||
<xsd:element name="group" type="CT_Group"/>
|
||||
<xsd:element name="background" type="CT_Background"/>
|
||||
<xsd:complexType name="CT_Shape">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:group ref="EG_ShapeElements"/>
|
||||
<xsd:element ref="o:ink"/>
|
||||
<xsd:element ref="pvml:iscomment"/>
|
||||
<xsd:element ref="o:equationxml"/>
|
||||
</xsd:choice>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_Type"/>
|
||||
<xsd:attributeGroup ref="AG_Adj"/>
|
||||
<xsd:attributeGroup ref="AG_Path"/>
|
||||
<xsd:attribute ref="o:gfxdata"/>
|
||||
<xsd:attribute name="equationxml" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Shapetype">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element ref="o:complex" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_Adj"/>
|
||||
<xsd:attributeGroup ref="AG_Path"/>
|
||||
<xsd:attribute ref="o:master"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Group">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:group ref="EG_ShapeElements"/>
|
||||
<xsd:element ref="group"/>
|
||||
<xsd:element ref="shape"/>
|
||||
<xsd:element ref="shapetype"/>
|
||||
<xsd:element ref="arc"/>
|
||||
<xsd:element ref="curve"/>
|
||||
<xsd:element ref="image"/>
|
||||
<xsd:element ref="line"/>
|
||||
<xsd:element ref="oval"/>
|
||||
<xsd:element ref="polyline"/>
|
||||
<xsd:element ref="rect"/>
|
||||
<xsd:element ref="roundrect"/>
|
||||
<xsd:element ref="o:diagram"/>
|
||||
</xsd:choice>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_Fill"/>
|
||||
<xsd:attribute name="editas" type="ST_EditAs" use="optional"/>
|
||||
<xsd:attribute ref="o:tableproperties"/>
|
||||
<xsd:attribute ref="o:tablelimits"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Background">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="fill" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attributeGroup ref="AG_Fill"/>
|
||||
<xsd:attribute ref="o:bwmode"/>
|
||||
<xsd:attribute ref="o:bwpure"/>
|
||||
<xsd:attribute ref="o:bwnormal"/>
|
||||
<xsd:attribute ref="o:targetscreensize"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="fill" type="CT_Fill"/>
|
||||
<xsd:element name="formulas" type="CT_Formulas"/>
|
||||
<xsd:element name="handles" type="CT_Handles"/>
|
||||
<xsd:element name="imagedata" type="CT_ImageData"/>
|
||||
<xsd:element name="path" type="CT_Path"/>
|
||||
<xsd:element name="textbox" type="CT_Textbox"/>
|
||||
<xsd:element name="shadow" type="CT_Shadow"/>
|
||||
<xsd:element name="stroke" type="CT_Stroke"/>
|
||||
<xsd:element name="textpath" type="CT_TextPath"/>
|
||||
<xsd:complexType name="CT_Fill">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="o:fill" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attribute name="type" type="ST_FillType" use="optional"/>
|
||||
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="src" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute ref="o:href"/>
|
||||
<xsd:attribute ref="o:althref"/>
|
||||
<xsd:attribute name="size" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="origin" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="position" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="aspect" type="ST_ImageAspect" use="optional"/>
|
||||
<xsd:attribute name="colors" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="angle" type="xsd:decimal" use="optional"/>
|
||||
<xsd:attribute name="alignshape" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="focus" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="focussize" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="focusposition" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="method" type="ST_FillMethod" use="optional"/>
|
||||
<xsd:attribute ref="o:detectmouseclick"/>
|
||||
<xsd:attribute ref="o:title"/>
|
||||
<xsd:attribute ref="o:opacity2"/>
|
||||
<xsd:attribute name="recolor" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="rotate" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute ref="r:id" use="optional"/>
|
||||
<xsd:attribute ref="o:relid" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Formulas">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="f" type="CT_F" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_F">
|
||||
<xsd:attribute name="eqn" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Handles">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="h" type="CT_H" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_H">
|
||||
<xsd:attribute name="position" type="xsd:string"/>
|
||||
<xsd:attribute name="polar" type="xsd:string"/>
|
||||
<xsd:attribute name="map" type="xsd:string"/>
|
||||
<xsd:attribute name="invx" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="invy" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="switch" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:attribute name="xrange" type="xsd:string"/>
|
||||
<xsd:attribute name="yrange" type="xsd:string"/>
|
||||
<xsd:attribute name="radiusrange" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ImageData">
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attributeGroup ref="AG_ImageAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_Chromakey"/>
|
||||
<xsd:attribute name="embosscolor" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="recolortarget" type="s:ST_ColorType"/>
|
||||
<xsd:attribute ref="o:href"/>
|
||||
<xsd:attribute ref="o:althref"/>
|
||||
<xsd:attribute ref="o:title"/>
|
||||
<xsd:attribute ref="o:oleid"/>
|
||||
<xsd:attribute ref="o:detectmouseclick"/>
|
||||
<xsd:attribute ref="o:movie"/>
|
||||
<xsd:attribute ref="o:relid"/>
|
||||
<xsd:attribute ref="r:id"/>
|
||||
<xsd:attribute ref="r:pict"/>
|
||||
<xsd:attribute ref="r:href"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Path">
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attribute name="v" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="limo" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="textboxrect" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="fillok" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="strokeok" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="shadowok" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="arrowok" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="gradientshapeok" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="textpathok" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="insetpenok" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute ref="o:connecttype"/>
|
||||
<xsd:attribute ref="o:connectlocs"/>
|
||||
<xsd:attribute ref="o:connectangles"/>
|
||||
<xsd:attribute ref="o:extrusionok"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Shadow">
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="type" type="ST_ShadowType" use="optional"/>
|
||||
<xsd:attribute name="obscured" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="offset" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="offset2" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="origin" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="matrix" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Stroke">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="o:left" minOccurs="0"/>
|
||||
<xsd:element ref="o:top" minOccurs="0"/>
|
||||
<xsd:element ref="o:right" minOccurs="0"/>
|
||||
<xsd:element ref="o:bottom" minOccurs="0"/>
|
||||
<xsd:element ref="o:column" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attributeGroup ref="AG_StrokeAttributes"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Textbox">
|
||||
<xsd:choice>
|
||||
<xsd:element ref="w:txbxContent" minOccurs="0"/>
|
||||
<xsd:any namespace="##local" processContents="skip"/>
|
||||
</xsd:choice>
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attributeGroup ref="AG_Style"/>
|
||||
<xsd:attribute name="inset" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute ref="o:singleclick"/>
|
||||
<xsd:attribute ref="o:insetmode"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_TextPath">
|
||||
<xsd:attributeGroup ref="AG_Id"/>
|
||||
<xsd:attributeGroup ref="AG_Style"/>
|
||||
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="fitshape" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="fitpath" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="trim" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="xscale" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="string" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="arc" type="CT_Arc"/>
|
||||
<xsd:element name="curve" type="CT_Curve"/>
|
||||
<xsd:element name="image" type="CT_Image"/>
|
||||
<xsd:element name="line" type="CT_Line"/>
|
||||
<xsd:element name="oval" type="CT_Oval"/>
|
||||
<xsd:element name="polyline" type="CT_PolyLine"/>
|
||||
<xsd:element name="rect" type="CT_Rect"/>
|
||||
<xsd:element name="roundrect" type="CT_RoundRect"/>
|
||||
<xsd:complexType name="CT_Arc">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
<xsd:attribute name="startAngle" type="xsd:decimal" use="optional"/>
|
||||
<xsd:attribute name="endAngle" type="xsd:decimal" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Curve">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
<xsd:attribute name="from" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="control1" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="control2" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="to" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Image">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_ImageAttributes"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Line">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
<xsd:attribute name="from" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="to" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Oval">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:choice>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PolyLine">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:group ref="EG_ShapeElements"/>
|
||||
<xsd:element ref="o:ink"/>
|
||||
</xsd:choice>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
<xsd:attribute name="points" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Rect">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:choice>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_RoundRect">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:choice>
|
||||
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||
<xsd:attribute name="arcsize" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Ext">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="view"/>
|
||||
<xsd:enumeration value="edit"/>
|
||||
<xsd:enumeration value="backwardCompatible"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_FillType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="solid"/>
|
||||
<xsd:enumeration value="gradient"/>
|
||||
<xsd:enumeration value="gradientRadial"/>
|
||||
<xsd:enumeration value="tile"/>
|
||||
<xsd:enumeration value="pattern"/>
|
||||
<xsd:enumeration value="frame"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_FillMethod">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="none"/>
|
||||
<xsd:enumeration value="linear"/>
|
||||
<xsd:enumeration value="sigma"/>
|
||||
<xsd:enumeration value="any"/>
|
||||
<xsd:enumeration value="linear sigma"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ShadowType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="single"/>
|
||||
<xsd:enumeration value="double"/>
|
||||
<xsd:enumeration value="emboss"/>
|
||||
<xsd:enumeration value="perspective"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_StrokeLineStyle">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="single"/>
|
||||
<xsd:enumeration value="thinThin"/>
|
||||
<xsd:enumeration value="thinThick"/>
|
||||
<xsd:enumeration value="thickThin"/>
|
||||
<xsd:enumeration value="thickBetweenThin"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_StrokeJoinStyle">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="round"/>
|
||||
<xsd:enumeration value="bevel"/>
|
||||
<xsd:enumeration value="miter"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_StrokeEndCap">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="flat"/>
|
||||
<xsd:enumeration value="square"/>
|
||||
<xsd:enumeration value="round"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_StrokeArrowLength">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="short"/>
|
||||
<xsd:enumeration value="medium"/>
|
||||
<xsd:enumeration value="long"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_StrokeArrowWidth">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="narrow"/>
|
||||
<xsd:enumeration value="medium"/>
|
||||
<xsd:enumeration value="wide"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_StrokeArrowType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="none"/>
|
||||
<xsd:enumeration value="block"/>
|
||||
<xsd:enumeration value="classic"/>
|
||||
<xsd:enumeration value="oval"/>
|
||||
<xsd:enumeration value="diamond"/>
|
||||
<xsd:enumeration value="open"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ImageAspect">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="ignore"/>
|
||||
<xsd:enumeration value="atMost"/>
|
||||
<xsd:enumeration value="atLeast"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_EditAs">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="canvas"/>
|
||||
<xsd:enumeration value="orgchart"/>
|
||||
<xsd:enumeration value="radial"/>
|
||||
<xsd:enumeration value="cycle"/>
|
||||
<xsd:enumeration value="stacked"/>
|
||||
<xsd:enumeration value="venn"/>
|
||||
<xsd:enumeration value="bullseye"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,509 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
targetNamespace="urn:schemas-microsoft-com:office:office" elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
<xsd:import namespace="urn:schemas-microsoft-com:vml" schemaLocation="vml-main.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
schemaLocation="shared-relationshipReference.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:attribute name="bwmode" type="ST_BWMode"/>
|
||||
<xsd:attribute name="bwpure" type="ST_BWMode"/>
|
||||
<xsd:attribute name="bwnormal" type="ST_BWMode"/>
|
||||
<xsd:attribute name="targetscreensize" type="ST_ScreenSize"/>
|
||||
<xsd:attribute name="insetmode" type="ST_InsetMode" default="custom"/>
|
||||
<xsd:attribute name="spt" type="xsd:float"/>
|
||||
<xsd:attribute name="wrapcoords" type="xsd:string"/>
|
||||
<xsd:attribute name="oned" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="regroupid" type="xsd:integer"/>
|
||||
<xsd:attribute name="doubleclicknotify" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="connectortype" type="ST_ConnectorType" default="straight"/>
|
||||
<xsd:attribute name="button" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="userhidden" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="forcedash" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="oleicon" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="ole" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:attribute name="preferrelative" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="cliptowrap" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="clip" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="bullet" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="hr" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="hrstd" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="hrnoshade" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="hrpct" type="xsd:float"/>
|
||||
<xsd:attribute name="hralign" type="ST_HrAlign" default="left"/>
|
||||
<xsd:attribute name="allowincell" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="allowoverlap" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="userdrawn" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="bordertopcolor" type="xsd:string"/>
|
||||
<xsd:attribute name="borderleftcolor" type="xsd:string"/>
|
||||
<xsd:attribute name="borderbottomcolor" type="xsd:string"/>
|
||||
<xsd:attribute name="borderrightcolor" type="xsd:string"/>
|
||||
<xsd:attribute name="connecttype" type="ST_ConnectType"/>
|
||||
<xsd:attribute name="connectlocs" type="xsd:string"/>
|
||||
<xsd:attribute name="connectangles" type="xsd:string"/>
|
||||
<xsd:attribute name="master" type="xsd:string"/>
|
||||
<xsd:attribute name="extrusionok" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="href" type="xsd:string"/>
|
||||
<xsd:attribute name="althref" type="xsd:string"/>
|
||||
<xsd:attribute name="title" type="xsd:string"/>
|
||||
<xsd:attribute name="singleclick" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="oleid" type="xsd:float"/>
|
||||
<xsd:attribute name="detectmouseclick" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="movie" type="xsd:float"/>
|
||||
<xsd:attribute name="spid" type="xsd:string"/>
|
||||
<xsd:attribute name="opacity2" type="xsd:string"/>
|
||||
<xsd:attribute name="relid" type="r:ST_RelationshipId"/>
|
||||
<xsd:attribute name="dgmlayout" type="ST_DiagramLayout"/>
|
||||
<xsd:attribute name="dgmnodekind" type="xsd:integer"/>
|
||||
<xsd:attribute name="dgmlayoutmru" type="ST_DiagramLayout"/>
|
||||
<xsd:attribute name="gfxdata" type="xsd:base64Binary"/>
|
||||
<xsd:attribute name="tableproperties" type="xsd:string"/>
|
||||
<xsd:attribute name="tablelimits" type="xsd:string"/>
|
||||
<xsd:element name="shapedefaults" type="CT_ShapeDefaults"/>
|
||||
<xsd:element name="shapelayout" type="CT_ShapeLayout"/>
|
||||
<xsd:element name="signatureline" type="CT_SignatureLine"/>
|
||||
<xsd:element name="ink" type="CT_Ink"/>
|
||||
<xsd:element name="diagram" type="CT_Diagram"/>
|
||||
<xsd:element name="equationxml" type="CT_EquationXml"/>
|
||||
<xsd:complexType name="CT_ShapeDefaults">
|
||||
<xsd:all minOccurs="0">
|
||||
<xsd:element ref="v:fill" minOccurs="0"/>
|
||||
<xsd:element ref="v:stroke" minOccurs="0"/>
|
||||
<xsd:element ref="v:textbox" minOccurs="0"/>
|
||||
<xsd:element ref="v:shadow" minOccurs="0"/>
|
||||
<xsd:element ref="skew" minOccurs="0"/>
|
||||
<xsd:element ref="extrusion" minOccurs="0"/>
|
||||
<xsd:element ref="callout" minOccurs="0"/>
|
||||
<xsd:element ref="lock" minOccurs="0"/>
|
||||
<xsd:element name="colormru" minOccurs="0" type="CT_ColorMru"/>
|
||||
<xsd:element name="colormenu" minOccurs="0" type="CT_ColorMenu"/>
|
||||
</xsd:all>
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="spidmax" type="xsd:integer" use="optional"/>
|
||||
<xsd:attribute name="style" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="fill" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="fillcolor" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="stroke" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="strokecolor" type="s:ST_ColorType"/>
|
||||
<xsd:attribute name="allowincell" form="qualified" type="s:ST_TrueFalse"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Ink">
|
||||
<xsd:sequence/>
|
||||
<xsd:attribute name="i" type="xsd:string"/>
|
||||
<xsd:attribute name="annotation" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="contentType" type="ST_ContentType" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SignatureLine">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="issignatureline" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="id" type="s:ST_Guid"/>
|
||||
<xsd:attribute name="provid" type="s:ST_Guid"/>
|
||||
<xsd:attribute name="signinginstructionsset" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="allowcomments" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="showsigndate" type="s:ST_TrueFalse"/>
|
||||
<xsd:attribute name="suggestedsigner" type="xsd:string" form="qualified"/>
|
||||
<xsd:attribute name="suggestedsigner2" type="xsd:string" form="qualified"/>
|
||||
<xsd:attribute name="suggestedsigneremail" type="xsd:string" form="qualified"/>
|
||||
<xsd:attribute name="signinginstructions" type="xsd:string"/>
|
||||
<xsd:attribute name="addlxml" type="xsd:string"/>
|
||||
<xsd:attribute name="sigprovurl" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ShapeLayout">
|
||||
<xsd:all>
|
||||
<xsd:element name="idmap" type="CT_IdMap" minOccurs="0"/>
|
||||
<xsd:element name="regrouptable" type="CT_RegroupTable" minOccurs="0"/>
|
||||
<xsd:element name="rules" type="CT_Rules" minOccurs="0"/>
|
||||
</xsd:all>
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_IdMap">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="data" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_RegroupTable">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="entry" type="CT_Entry" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Entry">
|
||||
<xsd:attribute name="new" type="xsd:int" use="optional"/>
|
||||
<xsd:attribute name="old" type="xsd:int" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Rules">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="r" type="CT_R" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_R">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="proxy" type="CT_Proxy" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="type" type="ST_RType" use="optional"/>
|
||||
<xsd:attribute name="how" type="ST_How" use="optional"/>
|
||||
<xsd:attribute name="idref" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Proxy">
|
||||
<xsd:attribute name="start" type="s:ST_TrueFalseBlank" use="optional" default="false"/>
|
||||
<xsd:attribute name="end" type="s:ST_TrueFalseBlank" use="optional" default="false"/>
|
||||
<xsd:attribute name="idref" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="connectloc" type="xsd:int" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Diagram">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="relationtable" type="CT_RelationTable" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="dgmstyle" type="xsd:integer" use="optional"/>
|
||||
<xsd:attribute name="autoformat" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="reverse" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="autolayout" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="dgmscalex" type="xsd:integer" use="optional"/>
|
||||
<xsd:attribute name="dgmscaley" type="xsd:integer" use="optional"/>
|
||||
<xsd:attribute name="dgmfontsize" type="xsd:integer" use="optional"/>
|
||||
<xsd:attribute name="constrainbounds" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="dgmbasetextscale" type="xsd:integer" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_EquationXml">
|
||||
<xsd:sequence>
|
||||
<xsd:any namespace="##any"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="contentType" type="ST_AlternateMathContentType" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_AlternateMathContentType">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_RelationTable">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="rel" type="CT_Relation" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Relation">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="idsrc" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="iddest" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="idcntr" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ColorMru">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="colors" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ColorMenu">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="strokecolor" type="s:ST_ColorType"/>
|
||||
<xsd:attribute name="fillcolor" type="s:ST_ColorType"/>
|
||||
<xsd:attribute name="shadowcolor" type="s:ST_ColorType"/>
|
||||
<xsd:attribute name="extrusioncolor" type="s:ST_ColorType"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="skew" type="CT_Skew"/>
|
||||
<xsd:element name="extrusion" type="CT_Extrusion"/>
|
||||
<xsd:element name="callout" type="CT_Callout"/>
|
||||
<xsd:element name="lock" type="CT_Lock"/>
|
||||
<xsd:element name="OLEObject" type="CT_OLEObject"/>
|
||||
<xsd:element name="complex" type="CT_Complex"/>
|
||||
<xsd:element name="left" type="CT_StrokeChild"/>
|
||||
<xsd:element name="top" type="CT_StrokeChild"/>
|
||||
<xsd:element name="right" type="CT_StrokeChild"/>
|
||||
<xsd:element name="bottom" type="CT_StrokeChild"/>
|
||||
<xsd:element name="column" type="CT_StrokeChild"/>
|
||||
<xsd:element name="clippath" type="CT_ClipPath"/>
|
||||
<xsd:element name="fill" type="CT_Fill"/>
|
||||
<xsd:complexType name="CT_Skew">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="id" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="offset" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="origin" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="matrix" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Extrusion">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="type" type="ST_ExtrusionType" default="parallel" use="optional"/>
|
||||
<xsd:attribute name="render" type="ST_ExtrusionRender" default="solid" use="optional"/>
|
||||
<xsd:attribute name="viewpointorigin" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="viewpoint" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="plane" type="ST_ExtrusionPlane" default="XY" use="optional"/>
|
||||
<xsd:attribute name="skewangle" type="xsd:float" use="optional"/>
|
||||
<xsd:attribute name="skewamt" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="foredepth" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="backdepth" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="orientation" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="orientationangle" type="xsd:float" use="optional"/>
|
||||
<xsd:attribute name="lockrotationcenter" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="autorotationcenter" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="rotationcenter" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="rotationangle" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="colormode" type="ST_ColorMode" use="optional"/>
|
||||
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="shininess" type="xsd:float" use="optional"/>
|
||||
<xsd:attribute name="specularity" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="diffusity" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="metal" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="edge" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="facet" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="lightface" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="brightness" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="lightposition" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="lightlevel" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="lightharsh" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="lightposition2" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="lightlevel2" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="lightharsh2" type="s:ST_TrueFalse" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Callout">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="type" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="gap" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="angle" type="ST_Angle" use="optional"/>
|
||||
<xsd:attribute name="dropauto" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="drop" type="ST_CalloutDrop" use="optional"/>
|
||||
<xsd:attribute name="distance" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="lengthspecified" type="s:ST_TrueFalse" default="f" use="optional"/>
|
||||
<xsd:attribute name="length" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="accentbar" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="textborder" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="minusx" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="minusy" type="s:ST_TrueFalse" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Lock">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="position" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="selection" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="grouping" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="ungrouping" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="rotation" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="cropping" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="verticies" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="adjusthandles" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="text" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="aspectratio" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="shapetype" type="s:ST_TrueFalse" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_OLEObject">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="LinkType" type="ST_OLELinkType" minOccurs="0"/>
|
||||
<xsd:element name="LockedField" type="s:ST_TrueFalseBlank" minOccurs="0"/>
|
||||
<xsd:element name="FieldCodes" type="xsd:string" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="Type" type="ST_OLEType" use="optional"/>
|
||||
<xsd:attribute name="ProgID" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="ShapeID" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="DrawAspect" type="ST_OLEDrawAspect" use="optional"/>
|
||||
<xsd:attribute name="ObjectID" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute ref="r:id" use="optional"/>
|
||||
<xsd:attribute name="UpdateMode" type="ST_OLEUpdateMode" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Complex">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_StrokeChild">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="weight" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/>
|
||||
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="linestyle" type="v:ST_StrokeLineStyle" use="optional"/>
|
||||
<xsd:attribute name="miterlimit" type="xsd:decimal" use="optional"/>
|
||||
<xsd:attribute name="joinstyle" type="v:ST_StrokeJoinStyle" use="optional"/>
|
||||
<xsd:attribute name="endcap" type="v:ST_StrokeEndCap" use="optional"/>
|
||||
<xsd:attribute name="dashstyle" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="filltype" type="v:ST_FillType" use="optional"/>
|
||||
<xsd:attribute name="src" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="imageaspect" type="v:ST_ImageAspect" use="optional"/>
|
||||
<xsd:attribute name="imagesize" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="imagealignshape" type="s:ST_TrueFalse" use="optional"/>
|
||||
<xsd:attribute name="startarrow" type="v:ST_StrokeArrowType" use="optional"/>
|
||||
<xsd:attribute name="startarrowwidth" type="v:ST_StrokeArrowWidth" use="optional"/>
|
||||
<xsd:attribute name="startarrowlength" type="v:ST_StrokeArrowLength" use="optional"/>
|
||||
<xsd:attribute name="endarrow" type="v:ST_StrokeArrowType" use="optional"/>
|
||||
<xsd:attribute name="endarrowwidth" type="v:ST_StrokeArrowWidth" use="optional"/>
|
||||
<xsd:attribute name="endarrowlength" type="v:ST_StrokeArrowLength" use="optional"/>
|
||||
<xsd:attribute ref="href"/>
|
||||
<xsd:attribute ref="althref"/>
|
||||
<xsd:attribute ref="title"/>
|
||||
<xsd:attribute ref="forcedash"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ClipPath">
|
||||
<xsd:attribute name="v" type="xsd:string" use="required" form="qualified"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Fill">
|
||||
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||
<xsd:attribute name="type" type="ST_FillType"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_RType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="arc"/>
|
||||
<xsd:enumeration value="callout"/>
|
||||
<xsd:enumeration value="connector"/>
|
||||
<xsd:enumeration value="align"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_How">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="top"/>
|
||||
<xsd:enumeration value="middle"/>
|
||||
<xsd:enumeration value="bottom"/>
|
||||
<xsd:enumeration value="left"/>
|
||||
<xsd:enumeration value="center"/>
|
||||
<xsd:enumeration value="right"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_BWMode">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="color"/>
|
||||
<xsd:enumeration value="auto"/>
|
||||
<xsd:enumeration value="grayScale"/>
|
||||
<xsd:enumeration value="lightGrayscale"/>
|
||||
<xsd:enumeration value="inverseGray"/>
|
||||
<xsd:enumeration value="grayOutline"/>
|
||||
<xsd:enumeration value="highContrast"/>
|
||||
<xsd:enumeration value="black"/>
|
||||
<xsd:enumeration value="white"/>
|
||||
<xsd:enumeration value="hide"/>
|
||||
<xsd:enumeration value="undrawn"/>
|
||||
<xsd:enumeration value="blackTextAndLines"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ScreenSize">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="544,376"/>
|
||||
<xsd:enumeration value="640,480"/>
|
||||
<xsd:enumeration value="720,512"/>
|
||||
<xsd:enumeration value="800,600"/>
|
||||
<xsd:enumeration value="1024,768"/>
|
||||
<xsd:enumeration value="1152,862"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_InsetMode">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="auto"/>
|
||||
<xsd:enumeration value="custom"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ColorMode">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="auto"/>
|
||||
<xsd:enumeration value="custom"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ContentType">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_DiagramLayout">
|
||||
<xsd:restriction base="xsd:integer">
|
||||
<xsd:enumeration value="0"/>
|
||||
<xsd:enumeration value="1"/>
|
||||
<xsd:enumeration value="2"/>
|
||||
<xsd:enumeration value="3"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ExtrusionType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="perspective"/>
|
||||
<xsd:enumeration value="parallel"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ExtrusionRender">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="solid"/>
|
||||
<xsd:enumeration value="wireFrame"/>
|
||||
<xsd:enumeration value="boundingCube"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ExtrusionPlane">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="XY"/>
|
||||
<xsd:enumeration value="ZX"/>
|
||||
<xsd:enumeration value="YZ"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_Angle">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="any"/>
|
||||
<xsd:enumeration value="30"/>
|
||||
<xsd:enumeration value="45"/>
|
||||
<xsd:enumeration value="60"/>
|
||||
<xsd:enumeration value="90"/>
|
||||
<xsd:enumeration value="auto"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_CalloutDrop">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_CalloutPlacement">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="top"/>
|
||||
<xsd:enumeration value="center"/>
|
||||
<xsd:enumeration value="bottom"/>
|
||||
<xsd:enumeration value="user"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ConnectorType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="none"/>
|
||||
<xsd:enumeration value="straight"/>
|
||||
<xsd:enumeration value="elbow"/>
|
||||
<xsd:enumeration value="curved"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_HrAlign">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="left"/>
|
||||
<xsd:enumeration value="right"/>
|
||||
<xsd:enumeration value="center"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ConnectType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="none"/>
|
||||
<xsd:enumeration value="rect"/>
|
||||
<xsd:enumeration value="segments"/>
|
||||
<xsd:enumeration value="custom"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_OLELinkType">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_OLEType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Embed"/>
|
||||
<xsd:enumeration value="Link"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_OLEDrawAspect">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Content"/>
|
||||
<xsd:enumeration value="Icon"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_OLEUpdateMode">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Always"/>
|
||||
<xsd:enumeration value="OnCall"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_FillType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="gradientCenter"/>
|
||||
<xsd:enumeration value="solid"/>
|
||||
<xsd:enumeration value="pattern"/>
|
||||
<xsd:enumeration value="tile"/>
|
||||
<xsd:enumeration value="frame"/>
|
||||
<xsd:enumeration value="gradientUnscaled"/>
|
||||
<xsd:enumeration value="gradientRadial"/>
|
||||
<xsd:enumeration value="gradient"/>
|
||||
<xsd:enumeration value="background"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="urn:schemas-microsoft-com:office:powerpoint"
|
||||
targetNamespace="urn:schemas-microsoft-com:office:powerpoint" elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
<xsd:element name="iscomment" type="CT_Empty"/>
|
||||
<xsd:element name="textdata" type="CT_Rel"/>
|
||||
<xsd:complexType name="CT_Empty"/>
|
||||
<xsd:complexType name="CT_Rel">
|
||||
<xsd:attribute name="id" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="urn:schemas-microsoft-com:office:excel"
|
||||
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
targetNamespace="urn:schemas-microsoft-com:office:excel" elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:element name="ClientData" type="CT_ClientData"/>
|
||||
<xsd:complexType name="CT_ClientData">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="MoveWithCells" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="SizeWithCells" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="Anchor" type="xsd:string"/>
|
||||
<xsd:element name="Locked" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="DefaultSize" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="PrintObject" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="Disabled" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="AutoFill" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="AutoLine" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="AutoPict" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="FmlaMacro" type="xsd:string"/>
|
||||
<xsd:element name="TextHAlign" type="xsd:string"/>
|
||||
<xsd:element name="TextVAlign" type="xsd:string"/>
|
||||
<xsd:element name="LockText" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="JustLastX" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="SecretEdit" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="Default" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="Help" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="Cancel" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="Dismiss" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="Accel" type="xsd:integer"/>
|
||||
<xsd:element name="Accel2" type="xsd:integer"/>
|
||||
<xsd:element name="Row" type="xsd:integer"/>
|
||||
<xsd:element name="Column" type="xsd:integer"/>
|
||||
<xsd:element name="Visible" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="RowHidden" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="ColHidden" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="VTEdit" type="xsd:integer"/>
|
||||
<xsd:element name="MultiLine" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="VScroll" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="ValidIds" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="FmlaRange" type="xsd:string"/>
|
||||
<xsd:element name="WidthMin" type="xsd:integer"/>
|
||||
<xsd:element name="Sel" type="xsd:integer"/>
|
||||
<xsd:element name="NoThreeD2" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="SelType" type="xsd:string"/>
|
||||
<xsd:element name="MultiSel" type="xsd:string"/>
|
||||
<xsd:element name="LCT" type="xsd:string"/>
|
||||
<xsd:element name="ListItem" type="xsd:string"/>
|
||||
<xsd:element name="DropStyle" type="xsd:string"/>
|
||||
<xsd:element name="Colored" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="DropLines" type="xsd:integer"/>
|
||||
<xsd:element name="Checked" type="xsd:integer"/>
|
||||
<xsd:element name="FmlaLink" type="xsd:string"/>
|
||||
<xsd:element name="FmlaPict" type="xsd:string"/>
|
||||
<xsd:element name="NoThreeD" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="FirstButton" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="FmlaGroup" type="xsd:string"/>
|
||||
<xsd:element name="Val" type="xsd:integer"/>
|
||||
<xsd:element name="Min" type="xsd:integer"/>
|
||||
<xsd:element name="Max" type="xsd:integer"/>
|
||||
<xsd:element name="Inc" type="xsd:integer"/>
|
||||
<xsd:element name="Page" type="xsd:integer"/>
|
||||
<xsd:element name="Horiz" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="Dx" type="xsd:integer"/>
|
||||
<xsd:element name="MapOCX" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="CF" type="ST_CF"/>
|
||||
<xsd:element name="Camera" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="RecalcAlways" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="AutoScale" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="DDE" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="UIObj" type="s:ST_TrueFalseBlank"/>
|
||||
<xsd:element name="ScriptText" type="xsd:string"/>
|
||||
<xsd:element name="ScriptExtended" type="xsd:string"/>
|
||||
<xsd:element name="ScriptLanguage" type="xsd:nonNegativeInteger"/>
|
||||
<xsd:element name="ScriptLocation" type="xsd:nonNegativeInteger"/>
|
||||
<xsd:element name="FmlaTxbx" type="xsd:string"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="ObjectType" type="ST_ObjectType" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_CF">
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_ObjectType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Button"/>
|
||||
<xsd:enumeration value="Checkbox"/>
|
||||
<xsd:enumeration value="Dialog"/>
|
||||
<xsd:enumeration value="Drop"/>
|
||||
<xsd:enumeration value="Edit"/>
|
||||
<xsd:enumeration value="GBox"/>
|
||||
<xsd:enumeration value="Label"/>
|
||||
<xsd:enumeration value="LineA"/>
|
||||
<xsd:enumeration value="List"/>
|
||||
<xsd:enumeration value="Movie"/>
|
||||
<xsd:enumeration value="Note"/>
|
||||
<xsd:enumeration value="Pict"/>
|
||||
<xsd:enumeration value="Radio"/>
|
||||
<xsd:enumeration value="RectA"/>
|
||||
<xsd:enumeration value="Scroll"/>
|
||||
<xsd:enumeration value="Spin"/>
|
||||
<xsd:enumeration value="Shape"/>
|
||||
<xsd:enumeration value="Group"/>
|
||||
<xsd:enumeration value="Rect"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns="urn:schemas-microsoft-com:office:word"
|
||||
targetNamespace="urn:schemas-microsoft-com:office:word" elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
<xsd:element name="bordertop" type="CT_Border"/>
|
||||
<xsd:element name="borderleft" type="CT_Border"/>
|
||||
<xsd:element name="borderright" type="CT_Border"/>
|
||||
<xsd:element name="borderbottom" type="CT_Border"/>
|
||||
<xsd:complexType name="CT_Border">
|
||||
<xsd:attribute name="type" type="ST_BorderType" use="optional"/>
|
||||
<xsd:attribute name="width" type="xsd:positiveInteger" use="optional"/>
|
||||
<xsd:attribute name="shadow" type="ST_BorderShadow" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="wrap" type="CT_Wrap"/>
|
||||
<xsd:complexType name="CT_Wrap">
|
||||
<xsd:attribute name="type" type="ST_WrapType" use="optional"/>
|
||||
<xsd:attribute name="side" type="ST_WrapSide" use="optional"/>
|
||||
<xsd:attribute name="anchorx" type="ST_HorizontalAnchor" use="optional"/>
|
||||
<xsd:attribute name="anchory" type="ST_VerticalAnchor" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="anchorlock" type="CT_AnchorLock"/>
|
||||
<xsd:complexType name="CT_AnchorLock"/>
|
||||
<xsd:simpleType name="ST_BorderType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="none"/>
|
||||
<xsd:enumeration value="single"/>
|
||||
<xsd:enumeration value="thick"/>
|
||||
<xsd:enumeration value="double"/>
|
||||
<xsd:enumeration value="hairline"/>
|
||||
<xsd:enumeration value="dot"/>
|
||||
<xsd:enumeration value="dash"/>
|
||||
<xsd:enumeration value="dotDash"/>
|
||||
<xsd:enumeration value="dashDotDot"/>
|
||||
<xsd:enumeration value="triple"/>
|
||||
<xsd:enumeration value="thinThickSmall"/>
|
||||
<xsd:enumeration value="thickThinSmall"/>
|
||||
<xsd:enumeration value="thickBetweenThinSmall"/>
|
||||
<xsd:enumeration value="thinThick"/>
|
||||
<xsd:enumeration value="thickThin"/>
|
||||
<xsd:enumeration value="thickBetweenThin"/>
|
||||
<xsd:enumeration value="thinThickLarge"/>
|
||||
<xsd:enumeration value="thickThinLarge"/>
|
||||
<xsd:enumeration value="thickBetweenThinLarge"/>
|
||||
<xsd:enumeration value="wave"/>
|
||||
<xsd:enumeration value="doubleWave"/>
|
||||
<xsd:enumeration value="dashedSmall"/>
|
||||
<xsd:enumeration value="dashDotStroked"/>
|
||||
<xsd:enumeration value="threeDEmboss"/>
|
||||
<xsd:enumeration value="threeDEngrave"/>
|
||||
<xsd:enumeration value="HTMLOutset"/>
|
||||
<xsd:enumeration value="HTMLInset"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_BorderShadow">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="t"/>
|
||||
<xsd:enumeration value="true"/>
|
||||
<xsd:enumeration value="f"/>
|
||||
<xsd:enumeration value="false"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_WrapType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="topAndBottom"/>
|
||||
<xsd:enumeration value="square"/>
|
||||
<xsd:enumeration value="none"/>
|
||||
<xsd:enumeration value="tight"/>
|
||||
<xsd:enumeration value="through"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_WrapSide">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="both"/>
|
||||
<xsd:enumeration value="left"/>
|
||||
<xsd:enumeration value="right"/>
|
||||
<xsd:enumeration value="largest"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_HorizontalAnchor">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="margin"/>
|
||||
<xsd:enumeration value="page"/>
|
||||
<xsd:enumeration value="text"/>
|
||||
<xsd:enumeration value="char"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_VerticalAnchor">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="margin"/>
|
||||
<xsd:enumeration value="page"/>
|
||||
<xsd:enumeration value="text"/>
|
||||
<xsd:enumeration value="line"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
3646
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd
Normal file
3646
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd
Normal file
File diff suppressed because it is too large
Load Diff
116
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd
Normal file
116
.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd
Normal file
@ -0,0 +1,116 @@
|
||||
<?xml version='1.0'?>
|
||||
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en">
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
See http://www.w3.org/XML/1998/namespace.html and
|
||||
http://www.w3.org/TR/REC-xml for information about this namespace.
|
||||
|
||||
This schema document describes the XML namespace, in a form
|
||||
suitable for import by other schema documents.
|
||||
|
||||
Note that local names in this namespace are intended to be defined
|
||||
only by the World Wide Web Consortium or its subgroups. The
|
||||
following names are currently defined in this namespace and should
|
||||
not be used with conflicting semantics by any Working Group,
|
||||
specification, or document instance:
|
||||
|
||||
base (as an attribute name): denotes an attribute whose value
|
||||
provides a URI to be used as the base for interpreting any
|
||||
relative URIs in the scope of the element on which it
|
||||
appears; its value is inherited. This name is reserved
|
||||
by virtue of its definition in the XML Base specification.
|
||||
|
||||
lang (as an attribute name): denotes an attribute whose value
|
||||
is a language code for the natural language of the content of
|
||||
any element; its value is inherited. This name is reserved
|
||||
by virtue of its definition in the XML specification.
|
||||
|
||||
space (as an attribute name): denotes an attribute whose
|
||||
value is a keyword indicating what whitespace processing
|
||||
discipline is intended for the content of the element; its
|
||||
value is inherited. This name is reserved by virtue of its
|
||||
definition in the XML specification.
|
||||
|
||||
Father (in any context at all): denotes Jon Bosak, the chair of
|
||||
the original XML Working Group. This name is reserved by
|
||||
the following decision of the W3C XML Plenary and
|
||||
XML Coordination groups:
|
||||
|
||||
In appreciation for his vision, leadership and dedication
|
||||
the W3C XML Plenary on this 10th day of February, 2000
|
||||
reserves for Jon Bosak in perpetuity the XML name
|
||||
xml:Father
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>This schema defines attributes and an attribute group
|
||||
suitable for use by
|
||||
schemas wishing to allow xml:base, xml:lang or xml:space attributes
|
||||
on elements they define.
|
||||
|
||||
To enable this, such a schema must import this schema
|
||||
for the XML namespace, e.g. as follows:
|
||||
<schema . . .>
|
||||
. . .
|
||||
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||
schemaLocation="http://www.w3.org/2001/03/xml.xsd"/>
|
||||
|
||||
Subsequently, qualified reference to any of the attributes
|
||||
or the group defined below will have the desired effect, e.g.
|
||||
|
||||
<type . . .>
|
||||
. . .
|
||||
<attributeGroup ref="xml:specialAttrs"/>
|
||||
|
||||
will define a type which will schema-validate an instance
|
||||
element with any of those attributes</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>In keeping with the XML Schema WG's standard versioning
|
||||
policy, this schema document will persist at
|
||||
http://www.w3.org/2001/03/xml.xsd.
|
||||
At the date of issue it can also be found at
|
||||
http://www.w3.org/2001/xml.xsd.
|
||||
The schema document at that URI may however change in the future,
|
||||
in order to remain compatible with the latest version of XML Schema
|
||||
itself. In other words, if the XML Schema namespace changes, the version
|
||||
of this document at
|
||||
http://www.w3.org/2001/xml.xsd will change
|
||||
accordingly; the version at
|
||||
http://www.w3.org/2001/03/xml.xsd will not change.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:attribute name="lang" type="xs:language">
|
||||
<xs:annotation>
|
||||
<xs:documentation>In due course, we should install the relevant ISO 2- and 3-letter
|
||||
codes as the enumerated possible values . . .</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attribute name="space" default="preserve">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NCName">
|
||||
<xs:enumeration value="default"/>
|
||||
<xs:enumeration value="preserve"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attribute name="base" type="xs:anyURI">
|
||||
<xs:annotation>
|
||||
<xs:documentation>See http://www.w3.org/TR/xmlbase/ for
|
||||
information about this attribute.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attributeGroup name="specialAttrs">
|
||||
<xs:attribute ref="xml:base"/>
|
||||
<xs:attribute ref="xml:lang"/>
|
||||
<xs:attribute ref="xml:space"/>
|
||||
</xs:attributeGroup>
|
||||
|
||||
</xs:schema>
|
||||
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<xs:schema xmlns="http://schemas.openxmlformats.org/package/2006/content-types"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://schemas.openxmlformats.org/package/2006/content-types"
|
||||
elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all">
|
||||
|
||||
<xs:element name="Types" type="CT_Types"/>
|
||||
<xs:element name="Default" type="CT_Default"/>
|
||||
<xs:element name="Override" type="CT_Override"/>
|
||||
|
||||
<xs:complexType name="CT_Types">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="Default"/>
|
||||
<xs:element ref="Override"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="CT_Default">
|
||||
<xs:attribute name="Extension" type="ST_Extension" use="required"/>
|
||||
<xs:attribute name="ContentType" type="ST_ContentType" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="CT_Override">
|
||||
<xs:attribute name="ContentType" type="ST_ContentType" use="required"/>
|
||||
<xs:attribute name="PartName" type="xs:anyURI" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="ST_ContentType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern
|
||||
value="(((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))/((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))((\s+)*;(\s+)*(((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))=((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+)|("(([\p{IsLatin-1Supplement}\p{IsBasicLatin}-[\p{Cc}"\n\r]]|(\s+))|(\\[\p{IsBasicLatin}]))*"))))*)"
|
||||
/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="ST_Extension">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern
|
||||
value="([!$&'\(\)\*\+,:=]|(%[0-9a-fA-F][0-9a-fA-F])|[:@]|[a-zA-Z0-9\-_~])+"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema targetNamespace="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
|
||||
xmlns="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:dcterms="http://purl.org/dc/terms/" elementFormDefault="qualified" blockDefault="#all">
|
||||
|
||||
<xs:import namespace="http://purl.org/dc/elements/1.1/"
|
||||
schemaLocation="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dc.xsd"/>
|
||||
<xs:import namespace="http://purl.org/dc/terms/"
|
||||
schemaLocation="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dcterms.xsd"/>
|
||||
<xs:import id="xml" namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
|
||||
<xs:element name="coreProperties" type="CT_CoreProperties"/>
|
||||
|
||||
<xs:complexType name="CT_CoreProperties">
|
||||
<xs:all>
|
||||
<xs:element name="category" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
<xs:element name="contentStatus" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
<xs:element ref="dcterms:created" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element ref="dc:creator" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element ref="dc:description" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element ref="dc:identifier" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="keywords" minOccurs="0" maxOccurs="1" type="CT_Keywords"/>
|
||||
<xs:element ref="dc:language" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="lastModifiedBy" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
<xs:element name="lastPrinted" minOccurs="0" maxOccurs="1" type="xs:dateTime"/>
|
||||
<xs:element ref="dcterms:modified" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="revision" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
<xs:element ref="dc:subject" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element ref="dc:title" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="version" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="CT_Keywords" mixed="true">
|
||||
<xs:sequence>
|
||||
<xs:element name="value" minOccurs="0" maxOccurs="unbounded" type="CT_Keyword"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute ref="xml:lang" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="CT_Keyword">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute ref="xml:lang" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
||||
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://schemas.openxmlformats.org/package/2006/digital-signature"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://schemas.openxmlformats.org/package/2006/digital-signature"
|
||||
elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all">
|
||||
|
||||
<xsd:element name="SignatureTime" type="CT_SignatureTime"/>
|
||||
<xsd:element name="RelationshipReference" type="CT_RelationshipReference"/>
|
||||
<xsd:element name="RelationshipsGroupReference" type="CT_RelationshipsGroupReference"/>
|
||||
|
||||
<xsd:complexType name="CT_SignatureTime">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="Format" type="ST_Format"/>
|
||||
<xsd:element name="Value" type="ST_Value"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="CT_RelationshipReference">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="SourceId" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="CT_RelationshipsGroupReference">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="SourceType" type="xsd:anyURI" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:simpleType name="ST_Format">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:pattern
|
||||
value="(YYYY)|(YYYY-MM)|(YYYY-MM-DD)|(YYYY-MM-DDThh:mmTZD)|(YYYY-MM-DDThh:mm:ssTZD)|(YYYY-MM-DDThh:mm:ss.sTZD)"
|
||||
/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:simpleType name="ST_Value">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:pattern
|
||||
value="(([0-9][0-9][0-9][0-9]))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2))))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1))))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])):(((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))\.[0-9])(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))"
|
||||
/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<xsd:schema xmlns="http://schemas.openxmlformats.org/package/2006/relationships"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://schemas.openxmlformats.org/package/2006/relationships"
|
||||
elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all">
|
||||
|
||||
<xsd:element name="Relationships" type="CT_Relationships"/>
|
||||
<xsd:element name="Relationship" type="CT_Relationship"/>
|
||||
|
||||
<xsd:complexType name="CT_Relationships">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="Relationship" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="CT_Relationship">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="TargetMode" type="ST_TargetMode" use="optional"/>
|
||||
<xsd:attribute name="Target" type="xsd:anyURI" use="required"/>
|
||||
<xsd:attribute name="Type" type="xsd:anyURI" use="required"/>
|
||||
<xsd:attribute name="Id" type="xsd:ID" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:simpleType name="ST_TargetMode">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="External"/>
|
||||
<xsd:enumeration value="Internal"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
75
.claude/skills/pptx/ooxml/schemas/mce/mc.xsd
Normal file
75
.claude/skills/pptx/ooxml/schemas/mce/mc.xsd
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsd:schema xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
attributeFormDefault="unqualified" elementFormDefault="qualified"
|
||||
targetNamespace="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<!--
|
||||
This XSD is a modified version of the one found at:
|
||||
https://github.com/plutext/docx4j/blob/master/xsd/mce/markup-compatibility-2006-MINIMAL.xsd
|
||||
|
||||
This XSD has 2 objectives:
|
||||
|
||||
1. round tripping @mc:Ignorable
|
||||
|
||||
<w:document
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
mc:Ignorable="w14 w15 wp14">
|
||||
|
||||
2. enabling AlternateContent to be manipulated in certain elements
|
||||
(in the unusual case where the content model is xsd:any, it doesn't have to be explicitly added)
|
||||
|
||||
See further ECMA-376, 4th Edition, Office Open XML File Formats
|
||||
Part 3 : Markup Compatibility and Extensibility
|
||||
-->
|
||||
|
||||
<!-- Objective 1 -->
|
||||
<xsd:attribute name="Ignorable" type="xsd:string" />
|
||||
|
||||
<!-- Objective 2 -->
|
||||
<xsd:attribute name="MustUnderstand" type="xsd:string" />
|
||||
<xsd:attribute name="ProcessContent" type="xsd:string" />
|
||||
|
||||
<!-- An AlternateContent element shall contain one or more Choice child elements, optionally followed by a
|
||||
Fallback child element. If present, there shall be only one Fallback element, and it shall follow all Choice
|
||||
elements. -->
|
||||
<xsd:element name="AlternateContent">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="Choice" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:any minOccurs="0" maxOccurs="unbounded"
|
||||
processContents="strict">
|
||||
</xsd:any>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="Requires" type="xsd:string" use="required" />
|
||||
<xsd:attribute ref="mc:Ignorable" use="optional" />
|
||||
<xsd:attribute ref="mc:MustUnderstand" use="optional" />
|
||||
<xsd:attribute ref="mc:ProcessContent" use="optional" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="Fallback" minOccurs="0" maxOccurs="1">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:any minOccurs="0" maxOccurs="unbounded"
|
||||
processContents="strict">
|
||||
</xsd:any>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute ref="mc:Ignorable" use="optional" />
|
||||
<xsd:attribute ref="mc:MustUnderstand" use="optional" />
|
||||
<xsd:attribute ref="mc:ProcessContent" use="optional" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<!-- AlternateContent elements might include the attributes Ignorable,
|
||||
MustUnderstand and ProcessContent described in this Part of ECMA-376. These
|
||||
attributes’ qualified names shall be prefixed when associated with an AlternateContent
|
||||
element. -->
|
||||
<xsd:attribute ref="mc:Ignorable" use="optional" />
|
||||
<xsd:attribute ref="mc:MustUnderstand" use="optional" />
|
||||
<xsd:attribute ref="mc:ProcessContent" use="optional" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
560
.claude/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd
Normal file
560
.claude/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd
Normal file
@ -0,0 +1,560 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns="http://schemas.microsoft.com/office/word/2010/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2010/wordml">
|
||||
<!-- <xsd:import id="rel" namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" schemaLocation="orel.xsd"/> -->
|
||||
<xsd:import id="w" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||
<!-- <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" schemaLocation="oartbasetypes.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" schemaLocation="oartsplineproperties.xsd"/> -->
|
||||
<xsd:complexType name="CT_LongHexNumber">
|
||||
<xsd:attribute name="val" type="w:ST_LongHexNumber" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_OnOff">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="true"/>
|
||||
<xsd:enumeration value="false"/>
|
||||
<xsd:enumeration value="0"/>
|
||||
<xsd:enumeration value="1"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_OnOff">
|
||||
<xsd:attribute name="val" type="ST_OnOff"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="docId" type="CT_LongHexNumber"/>
|
||||
<xsd:element name="conflictMode" type="CT_OnOff"/>
|
||||
<xsd:attributeGroup name="AG_Parids">
|
||||
<xsd:attribute name="paraId" type="w:ST_LongHexNumber"/>
|
||||
<xsd:attribute name="textId" type="w:ST_LongHexNumber"/>
|
||||
</xsd:attributeGroup>
|
||||
<xsd:attribute name="anchorId" type="w:ST_LongHexNumber"/>
|
||||
<xsd:attribute name="noSpellErr" type="ST_OnOff"/>
|
||||
<xsd:element name="customXmlConflictInsRangeStart" type="w:CT_TrackChange"/>
|
||||
<xsd:element name="customXmlConflictInsRangeEnd" type="w:CT_Markup"/>
|
||||
<xsd:element name="customXmlConflictDelRangeStart" type="w:CT_TrackChange"/>
|
||||
<xsd:element name="customXmlConflictDelRangeEnd" type="w:CT_Markup"/>
|
||||
<xsd:group name="EG_RunLevelConflicts">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="conflictIns" type="w:CT_RunTrackChange" minOccurs="0"/>
|
||||
<xsd:element name="conflictDel" type="w:CT_RunTrackChange" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:group>
|
||||
<xsd:group name="EG_Conflicts">
|
||||
<xsd:choice>
|
||||
<xsd:element name="conflictIns" type="w:CT_TrackChange" minOccurs="0"/>
|
||||
<xsd:element name="conflictDel" type="w:CT_TrackChange" minOccurs="0"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_Percentage">
|
||||
<xsd:attribute name="val" type="a:ST_Percentage" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PositiveFixedPercentage">
|
||||
<xsd:attribute name="val" type="a:ST_PositiveFixedPercentage" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PositivePercentage">
|
||||
<xsd:attribute name="val" type="a:ST_PositivePercentage" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_SchemeColorVal">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="bg1"/>
|
||||
<xsd:enumeration value="tx1"/>
|
||||
<xsd:enumeration value="bg2"/>
|
||||
<xsd:enumeration value="tx2"/>
|
||||
<xsd:enumeration value="accent1"/>
|
||||
<xsd:enumeration value="accent2"/>
|
||||
<xsd:enumeration value="accent3"/>
|
||||
<xsd:enumeration value="accent4"/>
|
||||
<xsd:enumeration value="accent5"/>
|
||||
<xsd:enumeration value="accent6"/>
|
||||
<xsd:enumeration value="hlink"/>
|
||||
<xsd:enumeration value="folHlink"/>
|
||||
<xsd:enumeration value="dk1"/>
|
||||
<xsd:enumeration value="lt1"/>
|
||||
<xsd:enumeration value="dk2"/>
|
||||
<xsd:enumeration value="lt2"/>
|
||||
<xsd:enumeration value="phClr"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_RectAlignment">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="none"/>
|
||||
<xsd:enumeration value="tl"/>
|
||||
<xsd:enumeration value="t"/>
|
||||
<xsd:enumeration value="tr"/>
|
||||
<xsd:enumeration value="l"/>
|
||||
<xsd:enumeration value="ctr"/>
|
||||
<xsd:enumeration value="r"/>
|
||||
<xsd:enumeration value="bl"/>
|
||||
<xsd:enumeration value="b"/>
|
||||
<xsd:enumeration value="br"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_PathShadeType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="shape"/>
|
||||
<xsd:enumeration value="circle"/>
|
||||
<xsd:enumeration value="rect"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_LineCap">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="rnd"/>
|
||||
<xsd:enumeration value="sq"/>
|
||||
<xsd:enumeration value="flat"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_PresetLineDashVal">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="solid"/>
|
||||
<xsd:enumeration value="dot"/>
|
||||
<xsd:enumeration value="sysDot"/>
|
||||
<xsd:enumeration value="dash"/>
|
||||
<xsd:enumeration value="sysDash"/>
|
||||
<xsd:enumeration value="lgDash"/>
|
||||
<xsd:enumeration value="dashDot"/>
|
||||
<xsd:enumeration value="sysDashDot"/>
|
||||
<xsd:enumeration value="lgDashDot"/>
|
||||
<xsd:enumeration value="lgDashDotDot"/>
|
||||
<xsd:enumeration value="sysDashDotDot"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_PenAlignment">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="ctr"/>
|
||||
<xsd:enumeration value="in"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_CompoundLine">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="sng"/>
|
||||
<xsd:enumeration value="dbl"/>
|
||||
<xsd:enumeration value="thickThin"/>
|
||||
<xsd:enumeration value="thinThick"/>
|
||||
<xsd:enumeration value="tri"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_RelativeRect">
|
||||
<xsd:attribute name="l" use="optional" type="a:ST_Percentage"/>
|
||||
<xsd:attribute name="t" use="optional" type="a:ST_Percentage"/>
|
||||
<xsd:attribute name="r" use="optional" type="a:ST_Percentage"/>
|
||||
<xsd:attribute name="b" use="optional" type="a:ST_Percentage"/>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_ColorTransform">
|
||||
<xsd:choice>
|
||||
<xsd:element name="tint" type="CT_PositiveFixedPercentage"/>
|
||||
<xsd:element name="shade" type="CT_PositiveFixedPercentage"/>
|
||||
<xsd:element name="alpha" type="CT_PositiveFixedPercentage"/>
|
||||
<xsd:element name="hueMod" type="CT_PositivePercentage"/>
|
||||
<xsd:element name="sat" type="CT_Percentage"/>
|
||||
<xsd:element name="satOff" type="CT_Percentage"/>
|
||||
<xsd:element name="satMod" type="CT_Percentage"/>
|
||||
<xsd:element name="lum" type="CT_Percentage"/>
|
||||
<xsd:element name="lumOff" type="CT_Percentage"/>
|
||||
<xsd:element name="lumMod" type="CT_Percentage"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_SRgbColor">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="val" type="s:ST_HexColorRGB" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SchemeColor">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="val" type="ST_SchemeColorVal" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_ColorChoice">
|
||||
<xsd:choice>
|
||||
<xsd:element name="srgbClr" type="CT_SRgbColor"/>
|
||||
<xsd:element name="schemeClr" type="CT_SchemeColor"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_Color">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ColorChoice"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GradientStop">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ColorChoice"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="pos" type="a:ST_PositiveFixedPercentage" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GradientStopList">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="gs" type="CT_GradientStop" minOccurs="2" maxOccurs="10"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_LinearShadeProperties">
|
||||
<xsd:attribute name="ang" type="a:ST_PositiveFixedAngle" use="optional"/>
|
||||
<xsd:attribute name="scaled" type="ST_OnOff" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PathShadeProperties">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="fillToRect" type="CT_RelativeRect" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="path" type="ST_PathShadeType" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_ShadeProperties">
|
||||
<xsd:choice>
|
||||
<xsd:element name="lin" type="CT_LinearShadeProperties"/>
|
||||
<xsd:element name="path" type="CT_PathShadeProperties"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_SolidColorFillProperties">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ColorChoice" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_GradientFillProperties">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="gsLst" type="CT_GradientStopList" minOccurs="0"/>
|
||||
<xsd:group ref="EG_ShadeProperties" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_FillProperties">
|
||||
<xsd:choice>
|
||||
<xsd:element name="noFill" type="w:CT_Empty"/>
|
||||
<xsd:element name="solidFill" type="CT_SolidColorFillProperties"/>
|
||||
<xsd:element name="gradFill" type="CT_GradientFillProperties"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_PresetLineDashProperties">
|
||||
<xsd:attribute name="val" type="ST_PresetLineDashVal" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_LineDashProperties">
|
||||
<xsd:choice>
|
||||
<xsd:element name="prstDash" type="CT_PresetLineDashProperties"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:complexType name="CT_LineJoinMiterProperties">
|
||||
<xsd:attribute name="lim" type="a:ST_PositivePercentage" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_LineJoinProperties">
|
||||
<xsd:choice>
|
||||
<xsd:element name="round" type="w:CT_Empty"/>
|
||||
<xsd:element name="bevel" type="w:CT_Empty"/>
|
||||
<xsd:element name="miter" type="CT_LineJoinMiterProperties"/>
|
||||
</xsd:choice>
|
||||
</xsd:group>
|
||||
<xsd:simpleType name="ST_PresetCameraType">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="legacyObliqueTopLeft"/>
|
||||
<xsd:enumeration value="legacyObliqueTop"/>
|
||||
<xsd:enumeration value="legacyObliqueTopRight"/>
|
||||
<xsd:enumeration value="legacyObliqueLeft"/>
|
||||
<xsd:enumeration value="legacyObliqueFront"/>
|
||||
<xsd:enumeration value="legacyObliqueRight"/>
|
||||
<xsd:enumeration value="legacyObliqueBottomLeft"/>
|
||||
<xsd:enumeration value="legacyObliqueBottom"/>
|
||||
<xsd:enumeration value="legacyObliqueBottomRight"/>
|
||||
<xsd:enumeration value="legacyPerspectiveTopLeft"/>
|
||||
<xsd:enumeration value="legacyPerspectiveTop"/>
|
||||
<xsd:enumeration value="legacyPerspectiveTopRight"/>
|
||||
<xsd:enumeration value="legacyPerspectiveLeft"/>
|
||||
<xsd:enumeration value="legacyPerspectiveFront"/>
|
||||
<xsd:enumeration value="legacyPerspectiveRight"/>
|
||||
<xsd:enumeration value="legacyPerspectiveBottomLeft"/>
|
||||
<xsd:enumeration value="legacyPerspectiveBottom"/>
|
||||
<xsd:enumeration value="legacyPerspectiveBottomRight"/>
|
||||
<xsd:enumeration value="orthographicFront"/>
|
||||
<xsd:enumeration value="isometricTopUp"/>
|
||||
<xsd:enumeration value="isometricTopDown"/>
|
||||
<xsd:enumeration value="isometricBottomUp"/>
|
||||
<xsd:enumeration value="isometricBottomDown"/>
|
||||
<xsd:enumeration value="isometricLeftUp"/>
|
||||
<xsd:enumeration value="isometricLeftDown"/>
|
||||
<xsd:enumeration value="isometricRightUp"/>
|
||||
<xsd:enumeration value="isometricRightDown"/>
|
||||
<xsd:enumeration value="isometricOffAxis1Left"/>
|
||||
<xsd:enumeration value="isometricOffAxis1Right"/>
|
||||
<xsd:enumeration value="isometricOffAxis1Top"/>
|
||||
<xsd:enumeration value="isometricOffAxis2Left"/>
|
||||
<xsd:enumeration value="isometricOffAxis2Right"/>
|
||||
<xsd:enumeration value="isometricOffAxis2Top"/>
|
||||
<xsd:enumeration value="isometricOffAxis3Left"/>
|
||||
<xsd:enumeration value="isometricOffAxis3Right"/>
|
||||
<xsd:enumeration value="isometricOffAxis3Bottom"/>
|
||||
<xsd:enumeration value="isometricOffAxis4Left"/>
|
||||
<xsd:enumeration value="isometricOffAxis4Right"/>
|
||||
<xsd:enumeration value="isometricOffAxis4Bottom"/>
|
||||
<xsd:enumeration value="obliqueTopLeft"/>
|
||||
<xsd:enumeration value="obliqueTop"/>
|
||||
<xsd:enumeration value="obliqueTopRight"/>
|
||||
<xsd:enumeration value="obliqueLeft"/>
|
||||
<xsd:enumeration value="obliqueRight"/>
|
||||
<xsd:enumeration value="obliqueBottomLeft"/>
|
||||
<xsd:enumeration value="obliqueBottom"/>
|
||||
<xsd:enumeration value="obliqueBottomRight"/>
|
||||
<xsd:enumeration value="perspectiveFront"/>
|
||||
<xsd:enumeration value="perspectiveLeft"/>
|
||||
<xsd:enumeration value="perspectiveRight"/>
|
||||
<xsd:enumeration value="perspectiveAbove"/>
|
||||
<xsd:enumeration value="perspectiveBelow"/>
|
||||
<xsd:enumeration value="perspectiveAboveLeftFacing"/>
|
||||
<xsd:enumeration value="perspectiveAboveRightFacing"/>
|
||||
<xsd:enumeration value="perspectiveContrastingLeftFacing"/>
|
||||
<xsd:enumeration value="perspectiveContrastingRightFacing"/>
|
||||
<xsd:enumeration value="perspectiveHeroicLeftFacing"/>
|
||||
<xsd:enumeration value="perspectiveHeroicRightFacing"/>
|
||||
<xsd:enumeration value="perspectiveHeroicExtremeLeftFacing"/>
|
||||
<xsd:enumeration value="perspectiveHeroicExtremeRightFacing"/>
|
||||
<xsd:enumeration value="perspectiveRelaxed"/>
|
||||
<xsd:enumeration value="perspectiveRelaxedModerately"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Camera">
|
||||
<xsd:attribute name="prst" use="required" type="ST_PresetCameraType"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SphereCoords">
|
||||
<xsd:attribute name="lat" type="a:ST_PositiveFixedAngle" use="required"/>
|
||||
<xsd:attribute name="lon" type="a:ST_PositiveFixedAngle" use="required"/>
|
||||
<xsd:attribute name="rev" type="a:ST_PositiveFixedAngle" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_LightRigType">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="legacyFlat1"/>
|
||||
<xsd:enumeration value="legacyFlat2"/>
|
||||
<xsd:enumeration value="legacyFlat3"/>
|
||||
<xsd:enumeration value="legacyFlat4"/>
|
||||
<xsd:enumeration value="legacyNormal1"/>
|
||||
<xsd:enumeration value="legacyNormal2"/>
|
||||
<xsd:enumeration value="legacyNormal3"/>
|
||||
<xsd:enumeration value="legacyNormal4"/>
|
||||
<xsd:enumeration value="legacyHarsh1"/>
|
||||
<xsd:enumeration value="legacyHarsh2"/>
|
||||
<xsd:enumeration value="legacyHarsh3"/>
|
||||
<xsd:enumeration value="legacyHarsh4"/>
|
||||
<xsd:enumeration value="threePt"/>
|
||||
<xsd:enumeration value="balanced"/>
|
||||
<xsd:enumeration value="soft"/>
|
||||
<xsd:enumeration value="harsh"/>
|
||||
<xsd:enumeration value="flood"/>
|
||||
<xsd:enumeration value="contrasting"/>
|
||||
<xsd:enumeration value="morning"/>
|
||||
<xsd:enumeration value="sunrise"/>
|
||||
<xsd:enumeration value="sunset"/>
|
||||
<xsd:enumeration value="chilly"/>
|
||||
<xsd:enumeration value="freezing"/>
|
||||
<xsd:enumeration value="flat"/>
|
||||
<xsd:enumeration value="twoPt"/>
|
||||
<xsd:enumeration value="glow"/>
|
||||
<xsd:enumeration value="brightRoom"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:simpleType name="ST_LightRigDirection">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="tl"/>
|
||||
<xsd:enumeration value="t"/>
|
||||
<xsd:enumeration value="tr"/>
|
||||
<xsd:enumeration value="l"/>
|
||||
<xsd:enumeration value="r"/>
|
||||
<xsd:enumeration value="bl"/>
|
||||
<xsd:enumeration value="b"/>
|
||||
<xsd:enumeration value="br"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_LightRig">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="rot" type="CT_SphereCoords" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="rig" type="ST_LightRigType" use="required"/>
|
||||
<xsd:attribute name="dir" type="ST_LightRigDirection" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_BevelPresetType">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="relaxedInset"/>
|
||||
<xsd:enumeration value="circle"/>
|
||||
<xsd:enumeration value="slope"/>
|
||||
<xsd:enumeration value="cross"/>
|
||||
<xsd:enumeration value="angle"/>
|
||||
<xsd:enumeration value="softRound"/>
|
||||
<xsd:enumeration value="convex"/>
|
||||
<xsd:enumeration value="coolSlant"/>
|
||||
<xsd:enumeration value="divot"/>
|
||||
<xsd:enumeration value="riblet"/>
|
||||
<xsd:enumeration value="hardEdge"/>
|
||||
<xsd:enumeration value="artDeco"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Bevel">
|
||||
<xsd:attribute name="w" type="a:ST_PositiveCoordinate" use="optional"/>
|
||||
<xsd:attribute name="h" type="a:ST_PositiveCoordinate" use="optional"/>
|
||||
<xsd:attribute name="prst" type="ST_BevelPresetType" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_PresetMaterialType">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:enumeration value="legacyMatte"/>
|
||||
<xsd:enumeration value="legacyPlastic"/>
|
||||
<xsd:enumeration value="legacyMetal"/>
|
||||
<xsd:enumeration value="legacyWireframe"/>
|
||||
<xsd:enumeration value="matte"/>
|
||||
<xsd:enumeration value="plastic"/>
|
||||
<xsd:enumeration value="metal"/>
|
||||
<xsd:enumeration value="warmMatte"/>
|
||||
<xsd:enumeration value="translucentPowder"/>
|
||||
<xsd:enumeration value="powder"/>
|
||||
<xsd:enumeration value="dkEdge"/>
|
||||
<xsd:enumeration value="softEdge"/>
|
||||
<xsd:enumeration value="clear"/>
|
||||
<xsd:enumeration value="flat"/>
|
||||
<xsd:enumeration value="softmetal"/>
|
||||
<xsd:enumeration value="none"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Glow">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ColorChoice"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="rad" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Shadow">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_ColorChoice"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="blurRad" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||
<xsd:attribute name="dist" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||
<xsd:attribute name="dir" use="optional" type="a:ST_PositiveFixedAngle"/>
|
||||
<xsd:attribute name="sx" use="optional" type="a:ST_Percentage"/>
|
||||
<xsd:attribute name="sy" use="optional" type="a:ST_Percentage"/>
|
||||
<xsd:attribute name="kx" use="optional" type="a:ST_FixedAngle"/>
|
||||
<xsd:attribute name="ky" use="optional" type="a:ST_FixedAngle"/>
|
||||
<xsd:attribute name="algn" use="optional" type="ST_RectAlignment"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Reflection">
|
||||
<xsd:attribute name="blurRad" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||
<xsd:attribute name="stA" use="optional" type="a:ST_PositiveFixedPercentage"/>
|
||||
<xsd:attribute name="stPos" use="optional" type="a:ST_PositiveFixedPercentage"/>
|
||||
<xsd:attribute name="endA" use="optional" type="a:ST_PositiveFixedPercentage"/>
|
||||
<xsd:attribute name="endPos" use="optional" type="a:ST_PositiveFixedPercentage"/>
|
||||
<xsd:attribute name="dist" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||
<xsd:attribute name="dir" use="optional" type="a:ST_PositiveFixedAngle"/>
|
||||
<xsd:attribute name="fadeDir" use="optional" type="a:ST_PositiveFixedAngle"/>
|
||||
<xsd:attribute name="sx" use="optional" type="a:ST_Percentage"/>
|
||||
<xsd:attribute name="sy" use="optional" type="a:ST_Percentage"/>
|
||||
<xsd:attribute name="kx" use="optional" type="a:ST_FixedAngle"/>
|
||||
<xsd:attribute name="ky" use="optional" type="a:ST_FixedAngle"/>
|
||||
<xsd:attribute name="algn" use="optional" type="ST_RectAlignment"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_FillTextEffect">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_FillProperties" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_TextOutlineEffect">
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="EG_FillProperties" minOccurs="0"/>
|
||||
<xsd:group ref="EG_LineDashProperties" minOccurs="0"/>
|
||||
<xsd:group ref="EG_LineJoinProperties" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="w" use="optional" type="a:ST_LineWidth"/>
|
||||
<xsd:attribute name="cap" use="optional" type="ST_LineCap"/>
|
||||
<xsd:attribute name="cmpd" use="optional" type="ST_CompoundLine"/>
|
||||
<xsd:attribute name="algn" use="optional" type="ST_PenAlignment"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Scene3D">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="camera" type="CT_Camera"/>
|
||||
<xsd:element name="lightRig" type="CT_LightRig"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Props3D">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="bevelT" type="CT_Bevel" minOccurs="0"/>
|
||||
<xsd:element name="bevelB" type="CT_Bevel" minOccurs="0"/>
|
||||
<xsd:element name="extrusionClr" type="CT_Color" minOccurs="0"/>
|
||||
<xsd:element name="contourClr" type="CT_Color" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="extrusionH" type="a:ST_PositiveCoordinate" use="optional"/>
|
||||
<xsd:attribute name="contourW" type="a:ST_PositiveCoordinate" use="optional"/>
|
||||
<xsd:attribute name="prstMaterial" type="ST_PresetMaterialType" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_RPrTextEffects">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="glow" minOccurs="0" type="CT_Glow"/>
|
||||
<xsd:element name="shadow" minOccurs="0" type="CT_Shadow"/>
|
||||
<xsd:element name="reflection" minOccurs="0" type="CT_Reflection"/>
|
||||
<xsd:element name="textOutline" minOccurs="0" type="CT_TextOutlineEffect"/>
|
||||
<xsd:element name="textFill" minOccurs="0" type="CT_FillTextEffect"/>
|
||||
<xsd:element name="scene3d" minOccurs="0" type="CT_Scene3D"/>
|
||||
<xsd:element name="props3d" minOccurs="0" type="CT_Props3D"/>
|
||||
</xsd:sequence>
|
||||
</xsd:group>
|
||||
<xsd:simpleType name="ST_Ligatures">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="none"/>
|
||||
<xsd:enumeration value="standard"/>
|
||||
<xsd:enumeration value="contextual"/>
|
||||
<xsd:enumeration value="historical"/>
|
||||
<xsd:enumeration value="discretional"/>
|
||||
<xsd:enumeration value="standardContextual"/>
|
||||
<xsd:enumeration value="standardHistorical"/>
|
||||
<xsd:enumeration value="contextualHistorical"/>
|
||||
<xsd:enumeration value="standardDiscretional"/>
|
||||
<xsd:enumeration value="contextualDiscretional"/>
|
||||
<xsd:enumeration value="historicalDiscretional"/>
|
||||
<xsd:enumeration value="standardContextualHistorical"/>
|
||||
<xsd:enumeration value="standardContextualDiscretional"/>
|
||||
<xsd:enumeration value="standardHistoricalDiscretional"/>
|
||||
<xsd:enumeration value="contextualHistoricalDiscretional"/>
|
||||
<xsd:enumeration value="all"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Ligatures">
|
||||
<xsd:attribute name="val" type="ST_Ligatures" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_NumForm">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="default"/>
|
||||
<xsd:enumeration value="lining"/>
|
||||
<xsd:enumeration value="oldStyle"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_NumForm">
|
||||
<xsd:attribute name="val" type="ST_NumForm" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_NumSpacing">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="default"/>
|
||||
<xsd:enumeration value="proportional"/>
|
||||
<xsd:enumeration value="tabular"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_NumSpacing">
|
||||
<xsd:attribute name="val" type="ST_NumSpacing" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_StyleSet">
|
||||
<xsd:attribute name="id" type="s:ST_UnsignedDecimalNumber" use="required"/>
|
||||
<xsd:attribute name="val" type="ST_OnOff" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_StylisticSets">
|
||||
<xsd:sequence minOccurs="0">
|
||||
<xsd:element name="styleSet" minOccurs="0" maxOccurs="unbounded" type="CT_StyleSet"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:group name="EG_RPrOpenType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="ligatures" minOccurs="0" type="CT_Ligatures"/>
|
||||
<xsd:element name="numForm" minOccurs="0" type="CT_NumForm"/>
|
||||
<xsd:element name="numSpacing" minOccurs="0" type="CT_NumSpacing"/>
|
||||
<xsd:element name="stylisticSets" minOccurs="0" type="CT_StylisticSets"/>
|
||||
<xsd:element name="cntxtAlts" minOccurs="0" type="CT_OnOff"/>
|
||||
</xsd:sequence>
|
||||
</xsd:group>
|
||||
<xsd:element name="discardImageEditingData" type="CT_OnOff"/>
|
||||
<xsd:element name="defaultImageDpi" type="CT_DefaultImageDpi"/>
|
||||
<xsd:complexType name="CT_DefaultImageDpi">
|
||||
<xsd:attribute name="val" type="w:ST_DecimalNumber" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="entityPicker" type="w:CT_Empty"/>
|
||||
<xsd:complexType name="CT_SdtCheckboxSymbol">
|
||||
<xsd:attribute name="font" type="s:ST_String"/>
|
||||
<xsd:attribute name="val" type="w:ST_ShortHexNumber"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_SdtCheckbox">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="checked" type="CT_OnOff" minOccurs="0"/>
|
||||
<xsd:element name="checkedState" type="CT_SdtCheckboxSymbol" minOccurs="0"/>
|
||||
<xsd:element name="uncheckedState" type="CT_SdtCheckboxSymbol" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="checkbox" type="CT_SdtCheckbox"/>
|
||||
</xsd:schema>
|
||||
67
.claude/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd
Normal file
67
.claude/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd
Normal file
@ -0,0 +1,67 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2012/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2012/wordml">
|
||||
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" schemaLocation="../ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:element name="color" type="w12:CT_Color"/>
|
||||
<xsd:simpleType name="ST_SdtAppearance">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="boundingBox"/>
|
||||
<xsd:enumeration value="tags"/>
|
||||
<xsd:enumeration value="hidden"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:element name="dataBinding" type="w12:CT_DataBinding"/>
|
||||
<xsd:complexType name="CT_SdtAppearance">
|
||||
<xsd:attribute name="val" type="ST_SdtAppearance"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="appearance" type="CT_SdtAppearance"/>
|
||||
<xsd:complexType name="CT_CommentsEx">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="commentEx" type="CT_CommentEx" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_CommentEx">
|
||||
<xsd:attribute name="paraId" type="w12:ST_LongHexNumber" use="required"/>
|
||||
<xsd:attribute name="paraIdParent" type="w12:ST_LongHexNumber" use="optional"/>
|
||||
<xsd:attribute name="done" type="s:ST_OnOff" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="commentsEx" type="CT_CommentsEx"/>
|
||||
<xsd:complexType name="CT_People">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="person" type="CT_Person" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_PresenceInfo">
|
||||
<xsd:attribute name="providerId" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="userId" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_Person">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="presenceInfo" type="CT_PresenceInfo" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="author" type="s:ST_String" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="people" type="CT_People"/>
|
||||
<xsd:complexType name="CT_SdtRepeatedSection">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="sectionTitle" type="w12:CT_String" minOccurs="0"/>
|
||||
<xsd:element name="doNotAllowInsertDeleteSection" type="w12:CT_OnOff" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:simpleType name="ST_Guid">
|
||||
<xsd:restriction base="xsd:token">
|
||||
<xsd:pattern value="\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
<xsd:complexType name="CT_Guid">
|
||||
<xsd:attribute name="val" type="ST_Guid"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="repeatingSection" type="CT_SdtRepeatedSection"/>
|
||||
<xsd:element name="repeatingSectionItem" type="w12:CT_Empty"/>
|
||||
<xsd:element name="chartTrackingRefBased" type="w12:CT_OnOff"/>
|
||||
<xsd:element name="collapsed" type="w12:CT_OnOff"/>
|
||||
<xsd:element name="docId" type="CT_Guid"/>
|
||||
<xsd:element name="footnoteColumns" type="w12:CT_DecimalNumber"/>
|
||||
<xsd:element name="webExtensionLinked" type="w12:CT_OnOff"/>
|
||||
<xsd:element name="webExtensionCreated" type="w12:CT_OnOff"/>
|
||||
<xsd:attribute name="restartNumberingAfterBreak" type="s:ST_OnOff"/>
|
||||
</xsd:schema>
|
||||
14
.claude/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd
Normal file
14
.claude/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd
Normal file
@ -0,0 +1,14 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2018/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2018/wordml">
|
||||
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||
<xsd:complexType name="CT_Extension">
|
||||
<xsd:sequence>
|
||||
<xsd:any processContents="lax"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="uri" type="xsd:token"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_ExtensionList">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="ext" type="CT_Extension" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
20
.claude/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd
Normal file
20
.claude/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd
Normal file
@ -0,0 +1,20 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2018/wordml/cex" targetNamespace="http://schemas.microsoft.com/office/word/2018/wordml/cex">
|
||||
<xsd:import id="w16" namespace="http://schemas.microsoft.com/office/word/2018/wordml" schemaLocation="wml-2018.xsd"/>
|
||||
<xsd:import id="w" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||
<xsd:import id="s" namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" schemaLocation="../ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd"/>
|
||||
<xsd:complexType name="CT_CommentsExtensible">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="commentExtensible" type="CT_CommentExtensible" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="extLst" type="w16:CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_CommentExtensible">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="extLst" type="w16:CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="durableId" type="w:ST_LongHexNumber" use="required"/>
|
||||
<xsd:attribute name="dateUtc" type="w:ST_DateTime" use="optional"/>
|
||||
<xsd:attribute name="intelligentPlaceholder" type="s:ST_OnOff" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="commentsExtensible" type="CT_CommentsExtensible"/>
|
||||
</xsd:schema>
|
||||
13
.claude/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd
Normal file
13
.claude/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd
Normal file
@ -0,0 +1,13 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2016/wordml/cid" targetNamespace="http://schemas.microsoft.com/office/word/2016/wordml/cid">
|
||||
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||
<xsd:complexType name="CT_CommentsIds">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="commentId" type="CT_CommentId" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="CT_CommentId">
|
||||
<xsd:attribute name="paraId" type="w12:ST_LongHexNumber" use="required"/>
|
||||
<xsd:attribute name="durableId" type="w12:ST_LongHexNumber" use="required"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="commentsIds" type="CT_CommentsIds"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,4 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" targetNamespace="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash">
|
||||
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||
<xsd:attribute name="storeItemChecksum" type="w12:ST_String"/>
|
||||
</xsd:schema>
|
||||
@ -0,0 +1,8 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2015/wordml/symex" targetNamespace="http://schemas.microsoft.com/office/word/2015/wordml/symex">
|
||||
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||
<xsd:complexType name="CT_SymEx">
|
||||
<xsd:attribute name="font" type="w12:ST_String"/>
|
||||
<xsd:attribute name="char" type="w12:ST_LongHexNumber"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="symEx" type="CT_SymEx"/>
|
||||
</xsd:schema>
|
||||
159
.claude/skills/pptx/ooxml/scripts/pack.py
Normal file
159
.claude/skills/pptx/ooxml/scripts/pack.py
Normal file
@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone.
|
||||
|
||||
Example usage:
|
||||
python pack.py <input_directory> <office_file> [--force]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import defusedxml.minidom
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Pack a directory into an Office file")
|
||||
parser.add_argument("input_directory", help="Unpacked Office document directory")
|
||||
parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)")
|
||||
parser.add_argument("--force", action="store_true", help="Skip validation")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
success = pack_document(
|
||||
args.input_directory, args.output_file, validate=not args.force
|
||||
)
|
||||
|
||||
# Show warning if validation was skipped
|
||||
if args.force:
|
||||
print("Warning: Skipped validation, file may be corrupt", file=sys.stderr)
|
||||
# Exit with error if validation failed
|
||||
elif not success:
|
||||
print("Contents would produce a corrupt file.", file=sys.stderr)
|
||||
print("Please validate XML before repacking.", file=sys.stderr)
|
||||
print("Use --force to skip validation and pack anyway.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
except ValueError as e:
|
||||
sys.exit(f"Error: {e}")
|
||||
|
||||
|
||||
def pack_document(input_dir, output_file, validate=False):
|
||||
"""Pack a directory into an Office file (.docx/.pptx/.xlsx).
|
||||
|
||||
Args:
|
||||
input_dir: Path to unpacked Office document directory
|
||||
output_file: Path to output Office file
|
||||
validate: If True, validates with soffice (default: False)
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False if validation failed
|
||||
"""
|
||||
input_dir = Path(input_dir)
|
||||
output_file = Path(output_file)
|
||||
|
||||
if not input_dir.is_dir():
|
||||
raise ValueError(f"{input_dir} is not a directory")
|
||||
if output_file.suffix.lower() not in {".docx", ".pptx", ".xlsx"}:
|
||||
raise ValueError(f"{output_file} must be a .docx, .pptx, or .xlsx file")
|
||||
|
||||
# Work in temporary directory to avoid modifying original
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_content_dir = Path(temp_dir) / "content"
|
||||
shutil.copytree(input_dir, temp_content_dir)
|
||||
|
||||
# Process XML files to remove pretty-printing whitespace
|
||||
for pattern in ["*.xml", "*.rels"]:
|
||||
for xml_file in temp_content_dir.rglob(pattern):
|
||||
condense_xml(xml_file)
|
||||
|
||||
# Create final Office file as zip archive
|
||||
output_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
for f in temp_content_dir.rglob("*"):
|
||||
if f.is_file():
|
||||
zf.write(f, f.relative_to(temp_content_dir))
|
||||
|
||||
# Validate if requested
|
||||
if validate:
|
||||
if not validate_document(output_file):
|
||||
output_file.unlink() # Delete the corrupt file
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def validate_document(doc_path):
|
||||
"""Validate document by converting to HTML with soffice."""
|
||||
# Determine the correct filter based on file extension
|
||||
match doc_path.suffix.lower():
|
||||
case ".docx":
|
||||
filter_name = "html:HTML"
|
||||
case ".pptx":
|
||||
filter_name = "html:impress_html_Export"
|
||||
case ".xlsx":
|
||||
filter_name = "html:HTML (StarCalc)"
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[
|
||||
"soffice",
|
||||
"--headless",
|
||||
"--convert-to",
|
||||
filter_name,
|
||||
"--outdir",
|
||||
temp_dir,
|
||||
str(doc_path),
|
||||
],
|
||||
capture_output=True,
|
||||
timeout=10,
|
||||
text=True,
|
||||
)
|
||||
if not (Path(temp_dir) / f"{doc_path.stem}.html").exists():
|
||||
error_msg = result.stderr.strip() or "Document validation failed"
|
||||
print(f"Validation error: {error_msg}", file=sys.stderr)
|
||||
return False
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
print("Warning: soffice not found. Skipping validation.", file=sys.stderr)
|
||||
return True
|
||||
except subprocess.TimeoutExpired:
|
||||
print("Validation error: Timeout during conversion", file=sys.stderr)
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Validation error: {e}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
|
||||
def condense_xml(xml_file):
|
||||
"""Strip unnecessary whitespace and remove comments."""
|
||||
with open(xml_file, "r", encoding="utf-8") as f:
|
||||
dom = defusedxml.minidom.parse(f)
|
||||
|
||||
# Process each element to remove whitespace and comments
|
||||
for element in dom.getElementsByTagName("*"):
|
||||
# Skip w:t elements and their processing
|
||||
if element.tagName.endswith(":t"):
|
||||
continue
|
||||
|
||||
# Remove whitespace-only text nodes and comment nodes
|
||||
for child in list(element.childNodes):
|
||||
if (
|
||||
child.nodeType == child.TEXT_NODE
|
||||
and child.nodeValue
|
||||
and child.nodeValue.strip() == ""
|
||||
) or child.nodeType == child.COMMENT_NODE:
|
||||
element.removeChild(child)
|
||||
|
||||
# Write back the condensed XML
|
||||
with open(xml_file, "wb") as f:
|
||||
f.write(dom.toxml(encoding="UTF-8"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
29
.claude/skills/pptx/ooxml/scripts/unpack.py
Normal file
29
.claude/skills/pptx/ooxml/scripts/unpack.py
Normal file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Unpack and format XML contents of Office files (.docx, .pptx, .xlsx)"""
|
||||
|
||||
import random
|
||||
import sys
|
||||
import defusedxml.minidom
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
# Get command line arguments
|
||||
assert len(sys.argv) == 3, "Usage: python unpack.py <office_file> <output_dir>"
|
||||
input_file, output_dir = sys.argv[1], sys.argv[2]
|
||||
|
||||
# Extract and format
|
||||
output_path = Path(output_dir)
|
||||
output_path.mkdir(parents=True, exist_ok=True)
|
||||
zipfile.ZipFile(input_file).extractall(output_path)
|
||||
|
||||
# Pretty print all XML files
|
||||
xml_files = list(output_path.rglob("*.xml")) + list(output_path.rglob("*.rels"))
|
||||
for xml_file in xml_files:
|
||||
content = xml_file.read_text(encoding="utf-8")
|
||||
dom = defusedxml.minidom.parseString(content)
|
||||
xml_file.write_bytes(dom.toprettyxml(indent=" ", encoding="ascii"))
|
||||
|
||||
# For .docx files, suggest an RSID for tracked changes
|
||||
if input_file.endswith(".docx"):
|
||||
suggested_rsid = "".join(random.choices("0123456789ABCDEF", k=8))
|
||||
print(f"Suggested RSID for edit session: {suggested_rsid}")
|
||||
69
.claude/skills/pptx/ooxml/scripts/validate.py
Normal file
69
.claude/skills/pptx/ooxml/scripts/validate.py
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Command line tool to validate Office document XML files against XSD schemas and tracked changes.
|
||||
|
||||
Usage:
|
||||
python validate.py <dir> --original <original_file>
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from validation import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Validate Office document XML files")
|
||||
parser.add_argument(
|
||||
"unpacked_dir",
|
||||
help="Path to unpacked Office document directory",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--original",
|
||||
required=True,
|
||||
help="Path to original file (.docx/.pptx/.xlsx)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
help="Enable verbose output",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Validate paths
|
||||
unpacked_dir = Path(args.unpacked_dir)
|
||||
original_file = Path(args.original)
|
||||
file_extension = original_file.suffix.lower()
|
||||
assert unpacked_dir.is_dir(), f"Error: {unpacked_dir} is not a directory"
|
||||
assert original_file.is_file(), f"Error: {original_file} is not a file"
|
||||
assert file_extension in [".docx", ".pptx", ".xlsx"], (
|
||||
f"Error: {original_file} must be a .docx, .pptx, or .xlsx file"
|
||||
)
|
||||
|
||||
# Run validations
|
||||
match file_extension:
|
||||
case ".docx":
|
||||
validators = [DOCXSchemaValidator, RedliningValidator]
|
||||
case ".pptx":
|
||||
validators = [PPTXSchemaValidator]
|
||||
case _:
|
||||
print(f"Error: Validation not supported for file type {file_extension}")
|
||||
sys.exit(1)
|
||||
|
||||
# Run validators
|
||||
success = True
|
||||
for V in validators:
|
||||
validator = V(unpacked_dir, original_file, verbose=args.verbose)
|
||||
if not validator.validate():
|
||||
success = False
|
||||
|
||||
if success:
|
||||
print("All validations PASSED!")
|
||||
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
15
.claude/skills/pptx/ooxml/scripts/validation/__init__.py
Normal file
15
.claude/skills/pptx/ooxml/scripts/validation/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
"""
|
||||
Validation modules for Word document processing.
|
||||
"""
|
||||
|
||||
from .base import BaseSchemaValidator
|
||||
from .docx import DOCXSchemaValidator
|
||||
from .pptx import PPTXSchemaValidator
|
||||
from .redlining import RedliningValidator
|
||||
|
||||
__all__ = [
|
||||
"BaseSchemaValidator",
|
||||
"DOCXSchemaValidator",
|
||||
"PPTXSchemaValidator",
|
||||
"RedliningValidator",
|
||||
]
|
||||
951
.claude/skills/pptx/ooxml/scripts/validation/base.py
Normal file
951
.claude/skills/pptx/ooxml/scripts/validation/base.py
Normal file
@ -0,0 +1,951 @@
|
||||
"""
|
||||
Base validator with common validation logic for document files.
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import lxml.etree
|
||||
|
||||
|
||||
class BaseSchemaValidator:
|
||||
"""Base validator with common validation logic for document files."""
|
||||
|
||||
# Elements whose 'id' attributes must be unique within their file
|
||||
# Format: element_name -> (attribute_name, scope)
|
||||
# scope can be 'file' (unique within file) or 'global' (unique across all files)
|
||||
UNIQUE_ID_REQUIREMENTS = {
|
||||
# Word elements
|
||||
"comment": ("id", "file"), # Comment IDs in comments.xml
|
||||
"commentrangestart": ("id", "file"), # Must match comment IDs
|
||||
"commentrangeend": ("id", "file"), # Must match comment IDs
|
||||
"bookmarkstart": ("id", "file"), # Bookmark start IDs
|
||||
"bookmarkend": ("id", "file"), # Bookmark end IDs
|
||||
# Note: ins and del (track changes) can share IDs when part of same revision
|
||||
# PowerPoint elements
|
||||
"sldid": ("id", "file"), # Slide IDs in presentation.xml
|
||||
"sldmasterid": ("id", "global"), # Slide master IDs must be globally unique
|
||||
"sldlayoutid": ("id", "global"), # Slide layout IDs must be globally unique
|
||||
"cm": ("authorid", "file"), # Comment author IDs
|
||||
# Excel elements
|
||||
"sheet": ("sheetid", "file"), # Sheet IDs in workbook.xml
|
||||
"definedname": ("id", "file"), # Named range IDs
|
||||
# Drawing/Shape elements (all formats)
|
||||
"cxnsp": ("id", "file"), # Connection shape IDs
|
||||
"sp": ("id", "file"), # Shape IDs
|
||||
"pic": ("id", "file"), # Picture IDs
|
||||
"grpsp": ("id", "file"), # Group shape IDs
|
||||
}
|
||||
|
||||
# Mapping of element names to expected relationship types
|
||||
# Subclasses should override this with format-specific mappings
|
||||
ELEMENT_RELATIONSHIP_TYPES = {}
|
||||
|
||||
# Unified schema mappings for all Office document types
|
||||
SCHEMA_MAPPINGS = {
|
||||
# Document type specific schemas
|
||||
"word": "ISO-IEC29500-4_2016/wml.xsd", # Word documents
|
||||
"ppt": "ISO-IEC29500-4_2016/pml.xsd", # PowerPoint presentations
|
||||
"xl": "ISO-IEC29500-4_2016/sml.xsd", # Excel spreadsheets
|
||||
# Common file types
|
||||
"[Content_Types].xml": "ecma/fouth-edition/opc-contentTypes.xsd",
|
||||
"app.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd",
|
||||
"core.xml": "ecma/fouth-edition/opc-coreProperties.xsd",
|
||||
"custom.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd",
|
||||
".rels": "ecma/fouth-edition/opc-relationships.xsd",
|
||||
# Word-specific files
|
||||
"people.xml": "microsoft/wml-2012.xsd",
|
||||
"commentsIds.xml": "microsoft/wml-cid-2016.xsd",
|
||||
"commentsExtensible.xml": "microsoft/wml-cex-2018.xsd",
|
||||
"commentsExtended.xml": "microsoft/wml-2012.xsd",
|
||||
# Chart files (common across document types)
|
||||
"chart": "ISO-IEC29500-4_2016/dml-chart.xsd",
|
||||
# Theme files (common across document types)
|
||||
"theme": "ISO-IEC29500-4_2016/dml-main.xsd",
|
||||
# Drawing and media files
|
||||
"drawing": "ISO-IEC29500-4_2016/dml-main.xsd",
|
||||
}
|
||||
|
||||
# Unified namespace constants
|
||||
MC_NAMESPACE = "http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace"
|
||||
|
||||
# Common OOXML namespaces used across validators
|
||||
PACKAGE_RELATIONSHIPS_NAMESPACE = (
|
||||
"http://schemas.openxmlformats.org/package/2006/relationships"
|
||||
)
|
||||
OFFICE_RELATIONSHIPS_NAMESPACE = (
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
)
|
||||
CONTENT_TYPES_NAMESPACE = (
|
||||
"http://schemas.openxmlformats.org/package/2006/content-types"
|
||||
)
|
||||
|
||||
# Folders where we should clean ignorable namespaces
|
||||
MAIN_CONTENT_FOLDERS = {"word", "ppt", "xl"}
|
||||
|
||||
# All allowed OOXML namespaces (superset of all document types)
|
||||
OOXML_NAMESPACES = {
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/math",
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||
"http://schemas.openxmlformats.org/schemaLibrary/2006/main",
|
||||
"http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||
"http://schemas.openxmlformats.org/drawingml/2006/chart",
|
||||
"http://schemas.openxmlformats.org/drawingml/2006/chartDrawing",
|
||||
"http://schemas.openxmlformats.org/drawingml/2006/diagram",
|
||||
"http://schemas.openxmlformats.org/drawingml/2006/picture",
|
||||
"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
|
||||
"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
||||
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||
"http://schemas.openxmlformats.org/presentationml/2006/main",
|
||||
"http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes",
|
||||
"http://www.w3.org/XML/1998/namespace",
|
||||
}
|
||||
|
||||
def __init__(self, unpacked_dir, original_file, verbose=False):
|
||||
self.unpacked_dir = Path(unpacked_dir).resolve()
|
||||
self.original_file = Path(original_file)
|
||||
self.verbose = verbose
|
||||
|
||||
# Set schemas directory
|
||||
self.schemas_dir = Path(__file__).parent.parent.parent / "schemas"
|
||||
|
||||
# Get all XML and .rels files
|
||||
patterns = ["*.xml", "*.rels"]
|
||||
self.xml_files = [
|
||||
f for pattern in patterns for f in self.unpacked_dir.rglob(pattern)
|
||||
]
|
||||
|
||||
if not self.xml_files:
|
||||
print(f"Warning: No XML files found in {self.unpacked_dir}")
|
||||
|
||||
def validate(self):
|
||||
"""Run all validation checks and return True if all pass."""
|
||||
raise NotImplementedError("Subclasses must implement the validate method")
|
||||
|
||||
def validate_xml(self):
|
||||
"""Validate that all XML files are well-formed."""
|
||||
errors = []
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
try:
|
||||
# Try to parse the XML file
|
||||
lxml.etree.parse(str(xml_file))
|
||||
except lxml.etree.XMLSyntaxError as e:
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Line {e.lineno}: {e.msg}"
|
||||
)
|
||||
except Exception as e:
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Unexpected error: {str(e)}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} XML violations:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - All XML files are well-formed")
|
||||
return True
|
||||
|
||||
def validate_namespaces(self):
|
||||
"""Validate that namespace prefixes in Ignorable attributes are declared."""
|
||||
errors = []
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
try:
|
||||
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||
declared = set(root.nsmap.keys()) - {None} # Exclude default namespace
|
||||
|
||||
for attr_val in [
|
||||
v for k, v in root.attrib.items() if k.endswith("Ignorable")
|
||||
]:
|
||||
undeclared = set(attr_val.split()) - declared
|
||||
errors.extend(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Namespace '{ns}' in Ignorable but not declared"
|
||||
for ns in undeclared
|
||||
)
|
||||
except lxml.etree.XMLSyntaxError:
|
||||
continue
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - {len(errors)} namespace issues:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
if self.verbose:
|
||||
print("PASSED - All namespace prefixes properly declared")
|
||||
return True
|
||||
|
||||
def validate_unique_ids(self):
|
||||
"""Validate that specific IDs are unique according to OOXML requirements."""
|
||||
errors = []
|
||||
global_ids = {} # Track globally unique IDs across all files
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
try:
|
||||
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||
file_ids = {} # Track IDs that must be unique within this file
|
||||
|
||||
# Remove all mc:AlternateContent elements from the tree
|
||||
mc_elements = root.xpath(
|
||||
".//mc:AlternateContent", namespaces={"mc": self.MC_NAMESPACE}
|
||||
)
|
||||
for elem in mc_elements:
|
||||
elem.getparent().remove(elem)
|
||||
|
||||
# Now check IDs in the cleaned tree
|
||||
for elem in root.iter():
|
||||
# Get the element name without namespace
|
||||
tag = (
|
||||
elem.tag.split("}")[-1].lower()
|
||||
if "}" in elem.tag
|
||||
else elem.tag.lower()
|
||||
)
|
||||
|
||||
# Check if this element type has ID uniqueness requirements
|
||||
if tag in self.UNIQUE_ID_REQUIREMENTS:
|
||||
attr_name, scope = self.UNIQUE_ID_REQUIREMENTS[tag]
|
||||
|
||||
# Look for the specified attribute
|
||||
id_value = None
|
||||
for attr, value in elem.attrib.items():
|
||||
attr_local = (
|
||||
attr.split("}")[-1].lower()
|
||||
if "}" in attr
|
||||
else attr.lower()
|
||||
)
|
||||
if attr_local == attr_name:
|
||||
id_value = value
|
||||
break
|
||||
|
||||
if id_value is not None:
|
||||
if scope == "global":
|
||||
# Check global uniqueness
|
||||
if id_value in global_ids:
|
||||
prev_file, prev_line, prev_tag = global_ids[
|
||||
id_value
|
||||
]
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Line {elem.sourceline}: Global ID '{id_value}' in <{tag}> "
|
||||
f"already used in {prev_file} at line {prev_line} in <{prev_tag}>"
|
||||
)
|
||||
else:
|
||||
global_ids[id_value] = (
|
||||
xml_file.relative_to(self.unpacked_dir),
|
||||
elem.sourceline,
|
||||
tag,
|
||||
)
|
||||
elif scope == "file":
|
||||
# Check file-level uniqueness
|
||||
key = (tag, attr_name)
|
||||
if key not in file_ids:
|
||||
file_ids[key] = {}
|
||||
|
||||
if id_value in file_ids[key]:
|
||||
prev_line = file_ids[key][id_value]
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Line {elem.sourceline}: Duplicate {attr_name}='{id_value}' in <{tag}> "
|
||||
f"(first occurrence at line {prev_line})"
|
||||
)
|
||||
else:
|
||||
file_ids[key][id_value] = elem.sourceline
|
||||
|
||||
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} ID uniqueness violations:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - All required IDs are unique")
|
||||
return True
|
||||
|
||||
def validate_file_references(self):
|
||||
"""
|
||||
Validate that all .rels files properly reference files and that all files are referenced.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
# Find all .rels files
|
||||
rels_files = list(self.unpacked_dir.rglob("*.rels"))
|
||||
|
||||
if not rels_files:
|
||||
if self.verbose:
|
||||
print("PASSED - No .rels files found")
|
||||
return True
|
||||
|
||||
# Get all files in the unpacked directory (excluding reference files)
|
||||
all_files = []
|
||||
for file_path in self.unpacked_dir.rglob("*"):
|
||||
if (
|
||||
file_path.is_file()
|
||||
and file_path.name != "[Content_Types].xml"
|
||||
and not file_path.name.endswith(".rels")
|
||||
): # This file is not referenced by .rels
|
||||
all_files.append(file_path.resolve())
|
||||
|
||||
# Track all files that are referenced by any .rels file
|
||||
all_referenced_files = set()
|
||||
|
||||
if self.verbose:
|
||||
print(
|
||||
f"Found {len(rels_files)} .rels files and {len(all_files)} target files"
|
||||
)
|
||||
|
||||
# Check each .rels file
|
||||
for rels_file in rels_files:
|
||||
try:
|
||||
# Parse relationships file
|
||||
rels_root = lxml.etree.parse(str(rels_file)).getroot()
|
||||
|
||||
# Get the directory where this .rels file is located
|
||||
rels_dir = rels_file.parent
|
||||
|
||||
# Find all relationships and their targets
|
||||
referenced_files = set()
|
||||
broken_refs = []
|
||||
|
||||
for rel in rels_root.findall(
|
||||
".//ns:Relationship",
|
||||
namespaces={"ns": self.PACKAGE_RELATIONSHIPS_NAMESPACE},
|
||||
):
|
||||
target = rel.get("Target")
|
||||
if target and not target.startswith(
|
||||
("http", "mailto:")
|
||||
): # Skip external URLs
|
||||
# Resolve the target path relative to the .rels file location
|
||||
if rels_file.name == ".rels":
|
||||
# Root .rels file - targets are relative to unpacked_dir
|
||||
target_path = self.unpacked_dir / target
|
||||
else:
|
||||
# Other .rels files - targets are relative to their parent's parent
|
||||
# e.g., word/_rels/document.xml.rels -> targets relative to word/
|
||||
base_dir = rels_dir.parent
|
||||
target_path = base_dir / target
|
||||
|
||||
# Normalize the path and check if it exists
|
||||
try:
|
||||
target_path = target_path.resolve()
|
||||
if target_path.exists() and target_path.is_file():
|
||||
referenced_files.add(target_path)
|
||||
all_referenced_files.add(target_path)
|
||||
else:
|
||||
broken_refs.append((target, rel.sourceline))
|
||||
except (OSError, ValueError):
|
||||
broken_refs.append((target, rel.sourceline))
|
||||
|
||||
# Report broken references
|
||||
if broken_refs:
|
||||
rel_path = rels_file.relative_to(self.unpacked_dir)
|
||||
for broken_ref, line_num in broken_refs:
|
||||
errors.append(
|
||||
f" {rel_path}: Line {line_num}: Broken reference to {broken_ref}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
rel_path = rels_file.relative_to(self.unpacked_dir)
|
||||
errors.append(f" Error parsing {rel_path}: {e}")
|
||||
|
||||
# Check for unreferenced files (files that exist but are not referenced anywhere)
|
||||
unreferenced_files = set(all_files) - all_referenced_files
|
||||
|
||||
if unreferenced_files:
|
||||
for unref_file in sorted(unreferenced_files):
|
||||
unref_rel_path = unref_file.relative_to(self.unpacked_dir)
|
||||
errors.append(f" Unreferenced file: {unref_rel_path}")
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} relationship validation errors:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
print(
|
||||
"CRITICAL: These errors will cause the document to appear corrupt. "
|
||||
+ "Broken references MUST be fixed, "
|
||||
+ "and unreferenced files MUST be referenced or removed."
|
||||
)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print(
|
||||
"PASSED - All references are valid and all files are properly referenced"
|
||||
)
|
||||
return True
|
||||
|
||||
def validate_all_relationship_ids(self):
|
||||
"""
|
||||
Validate that all r:id attributes in XML files reference existing IDs
|
||||
in their corresponding .rels files, and optionally validate relationship types.
|
||||
"""
|
||||
import lxml.etree
|
||||
|
||||
errors = []
|
||||
|
||||
# Process each XML file that might contain r:id references
|
||||
for xml_file in self.xml_files:
|
||||
# Skip .rels files themselves
|
||||
if xml_file.suffix == ".rels":
|
||||
continue
|
||||
|
||||
# Determine the corresponding .rels file
|
||||
# For dir/file.xml, it's dir/_rels/file.xml.rels
|
||||
rels_dir = xml_file.parent / "_rels"
|
||||
rels_file = rels_dir / f"{xml_file.name}.rels"
|
||||
|
||||
# Skip if there's no corresponding .rels file (that's okay)
|
||||
if not rels_file.exists():
|
||||
continue
|
||||
|
||||
try:
|
||||
# Parse the .rels file to get valid relationship IDs and their types
|
||||
rels_root = lxml.etree.parse(str(rels_file)).getroot()
|
||||
rid_to_type = {}
|
||||
|
||||
for rel in rels_root.findall(
|
||||
f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship"
|
||||
):
|
||||
rid = rel.get("Id")
|
||||
rel_type = rel.get("Type", "")
|
||||
if rid:
|
||||
# Check for duplicate rIds
|
||||
if rid in rid_to_type:
|
||||
rels_rel_path = rels_file.relative_to(self.unpacked_dir)
|
||||
errors.append(
|
||||
f" {rels_rel_path}: Line {rel.sourceline}: "
|
||||
f"Duplicate relationship ID '{rid}' (IDs must be unique)"
|
||||
)
|
||||
# Extract just the type name from the full URL
|
||||
type_name = (
|
||||
rel_type.split("/")[-1] if "/" in rel_type else rel_type
|
||||
)
|
||||
rid_to_type[rid] = type_name
|
||||
|
||||
# Parse the XML file to find all r:id references
|
||||
xml_root = lxml.etree.parse(str(xml_file)).getroot()
|
||||
|
||||
# Find all elements with r:id attributes
|
||||
for elem in xml_root.iter():
|
||||
# Check for r:id attribute (relationship ID)
|
||||
rid_attr = elem.get(f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id")
|
||||
if rid_attr:
|
||||
xml_rel_path = xml_file.relative_to(self.unpacked_dir)
|
||||
elem_name = (
|
||||
elem.tag.split("}")[-1] if "}" in elem.tag else elem.tag
|
||||
)
|
||||
|
||||
# Check if the ID exists
|
||||
if rid_attr not in rid_to_type:
|
||||
errors.append(
|
||||
f" {xml_rel_path}: Line {elem.sourceline}: "
|
||||
f"<{elem_name}> references non-existent relationship '{rid_attr}' "
|
||||
f"(valid IDs: {', '.join(sorted(rid_to_type.keys())[:5])}{'...' if len(rid_to_type) > 5 else ''})"
|
||||
)
|
||||
# Check if we have type expectations for this element
|
||||
elif self.ELEMENT_RELATIONSHIP_TYPES:
|
||||
expected_type = self._get_expected_relationship_type(
|
||||
elem_name
|
||||
)
|
||||
if expected_type:
|
||||
actual_type = rid_to_type[rid_attr]
|
||||
# Check if the actual type matches or contains the expected type
|
||||
if expected_type not in actual_type.lower():
|
||||
errors.append(
|
||||
f" {xml_rel_path}: Line {elem.sourceline}: "
|
||||
f"<{elem_name}> references '{rid_attr}' which points to '{actual_type}' "
|
||||
f"but should point to a '{expected_type}' relationship"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
xml_rel_path = xml_file.relative_to(self.unpacked_dir)
|
||||
errors.append(f" Error processing {xml_rel_path}: {e}")
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} relationship ID reference errors:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
print("\nThese ID mismatches will cause the document to appear corrupt!")
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - All relationship ID references are valid")
|
||||
return True
|
||||
|
||||
def _get_expected_relationship_type(self, element_name):
|
||||
"""
|
||||
Get the expected relationship type for an element.
|
||||
First checks the explicit mapping, then tries pattern detection.
|
||||
"""
|
||||
# Normalize element name to lowercase
|
||||
elem_lower = element_name.lower()
|
||||
|
||||
# Check explicit mapping first
|
||||
if elem_lower in self.ELEMENT_RELATIONSHIP_TYPES:
|
||||
return self.ELEMENT_RELATIONSHIP_TYPES[elem_lower]
|
||||
|
||||
# Try pattern detection for common patterns
|
||||
# Pattern 1: Elements ending in "Id" often expect a relationship of the prefix type
|
||||
if elem_lower.endswith("id") and len(elem_lower) > 2:
|
||||
# e.g., "sldId" -> "sld", "sldMasterId" -> "sldMaster"
|
||||
prefix = elem_lower[:-2] # Remove "id"
|
||||
# Check if this might be a compound like "sldMasterId"
|
||||
if prefix.endswith("master"):
|
||||
return prefix.lower()
|
||||
elif prefix.endswith("layout"):
|
||||
return prefix.lower()
|
||||
else:
|
||||
# Simple case like "sldId" -> "slide"
|
||||
# Common transformations
|
||||
if prefix == "sld":
|
||||
return "slide"
|
||||
return prefix.lower()
|
||||
|
||||
# Pattern 2: Elements ending in "Reference" expect a relationship of the prefix type
|
||||
if elem_lower.endswith("reference") and len(elem_lower) > 9:
|
||||
prefix = elem_lower[:-9] # Remove "reference"
|
||||
return prefix.lower()
|
||||
|
||||
return None
|
||||
|
||||
def validate_content_types(self):
|
||||
"""Validate that all content files are properly declared in [Content_Types].xml."""
|
||||
errors = []
|
||||
|
||||
# Find [Content_Types].xml file
|
||||
content_types_file = self.unpacked_dir / "[Content_Types].xml"
|
||||
if not content_types_file.exists():
|
||||
print("FAILED - [Content_Types].xml file not found")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Parse and get all declared parts and extensions
|
||||
root = lxml.etree.parse(str(content_types_file)).getroot()
|
||||
declared_parts = set()
|
||||
declared_extensions = set()
|
||||
|
||||
# Get Override declarations (specific files)
|
||||
for override in root.findall(
|
||||
f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Override"
|
||||
):
|
||||
part_name = override.get("PartName")
|
||||
if part_name is not None:
|
||||
declared_parts.add(part_name.lstrip("/"))
|
||||
|
||||
# Get Default declarations (by extension)
|
||||
for default in root.findall(
|
||||
f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Default"
|
||||
):
|
||||
extension = default.get("Extension")
|
||||
if extension is not None:
|
||||
declared_extensions.add(extension.lower())
|
||||
|
||||
# Root elements that require content type declaration
|
||||
declarable_roots = {
|
||||
"sld",
|
||||
"sldLayout",
|
||||
"sldMaster",
|
||||
"presentation", # PowerPoint
|
||||
"document", # Word
|
||||
"workbook",
|
||||
"worksheet", # Excel
|
||||
"theme", # Common
|
||||
}
|
||||
|
||||
# Common media file extensions that should be declared
|
||||
media_extensions = {
|
||||
"png": "image/png",
|
||||
"jpg": "image/jpeg",
|
||||
"jpeg": "image/jpeg",
|
||||
"gif": "image/gif",
|
||||
"bmp": "image/bmp",
|
||||
"tiff": "image/tiff",
|
||||
"wmf": "image/x-wmf",
|
||||
"emf": "image/x-emf",
|
||||
}
|
||||
|
||||
# Get all files in the unpacked directory
|
||||
all_files = list(self.unpacked_dir.rglob("*"))
|
||||
all_files = [f for f in all_files if f.is_file()]
|
||||
|
||||
# Check all XML files for Override declarations
|
||||
for xml_file in self.xml_files:
|
||||
path_str = str(xml_file.relative_to(self.unpacked_dir)).replace(
|
||||
"\\", "/"
|
||||
)
|
||||
|
||||
# Skip non-content files
|
||||
if any(
|
||||
skip in path_str
|
||||
for skip in [".rels", "[Content_Types]", "docProps/", "_rels/"]
|
||||
):
|
||||
continue
|
||||
|
||||
try:
|
||||
root_tag = lxml.etree.parse(str(xml_file)).getroot().tag
|
||||
root_name = root_tag.split("}")[-1] if "}" in root_tag else root_tag
|
||||
|
||||
if root_name in declarable_roots and path_str not in declared_parts:
|
||||
errors.append(
|
||||
f" {path_str}: File with <{root_name}> root not declared in [Content_Types].xml"
|
||||
)
|
||||
|
||||
except Exception:
|
||||
continue # Skip unparseable files
|
||||
|
||||
# Check all non-XML files for Default extension declarations
|
||||
for file_path in all_files:
|
||||
# Skip XML files and metadata files (already checked above)
|
||||
if file_path.suffix.lower() in {".xml", ".rels"}:
|
||||
continue
|
||||
if file_path.name == "[Content_Types].xml":
|
||||
continue
|
||||
if "_rels" in file_path.parts or "docProps" in file_path.parts:
|
||||
continue
|
||||
|
||||
extension = file_path.suffix.lstrip(".").lower()
|
||||
if extension and extension not in declared_extensions:
|
||||
# Check if it's a known media extension that should be declared
|
||||
if extension in media_extensions:
|
||||
relative_path = file_path.relative_to(self.unpacked_dir)
|
||||
errors.append(
|
||||
f' {relative_path}: File with extension \'{extension}\' not declared in [Content_Types].xml - should add: <Default Extension="{extension}" ContentType="{media_extensions[extension]}"/>'
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
errors.append(f" Error parsing [Content_Types].xml: {e}")
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} content type declaration errors:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print(
|
||||
"PASSED - All content files are properly declared in [Content_Types].xml"
|
||||
)
|
||||
return True
|
||||
|
||||
def validate_file_against_xsd(self, xml_file, verbose=False):
|
||||
"""Validate a single XML file against XSD schema, comparing with original.
|
||||
|
||||
Args:
|
||||
xml_file: Path to XML file to validate
|
||||
verbose: Enable verbose output
|
||||
|
||||
Returns:
|
||||
tuple: (is_valid, new_errors_set) where is_valid is True/False/None (skipped)
|
||||
"""
|
||||
# Resolve both paths to handle symlinks
|
||||
xml_file = Path(xml_file).resolve()
|
||||
unpacked_dir = self.unpacked_dir.resolve()
|
||||
|
||||
# Validate current file
|
||||
is_valid, current_errors = self._validate_single_file_xsd(
|
||||
xml_file, unpacked_dir
|
||||
)
|
||||
|
||||
if is_valid is None:
|
||||
return None, set() # Skipped
|
||||
elif is_valid:
|
||||
return True, set() # Valid, no errors
|
||||
|
||||
# Get errors from original file for this specific file
|
||||
original_errors = self._get_original_file_errors(xml_file)
|
||||
|
||||
# Compare with original (both are guaranteed to be sets here)
|
||||
assert current_errors is not None
|
||||
new_errors = current_errors - original_errors
|
||||
|
||||
if new_errors:
|
||||
if verbose:
|
||||
relative_path = xml_file.relative_to(unpacked_dir)
|
||||
print(f"FAILED - {relative_path}: {len(new_errors)} new error(s)")
|
||||
for error in list(new_errors)[:3]:
|
||||
truncated = error[:250] + "..." if len(error) > 250 else error
|
||||
print(f" - {truncated}")
|
||||
return False, new_errors
|
||||
else:
|
||||
# All errors existed in original
|
||||
if verbose:
|
||||
print(
|
||||
f"PASSED - No new errors (original had {len(current_errors)} errors)"
|
||||
)
|
||||
return True, set()
|
||||
|
||||
def validate_against_xsd(self):
|
||||
"""Validate XML files against XSD schemas, showing only new errors compared to original."""
|
||||
new_errors = []
|
||||
original_error_count = 0
|
||||
valid_count = 0
|
||||
skipped_count = 0
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
relative_path = str(xml_file.relative_to(self.unpacked_dir))
|
||||
is_valid, new_file_errors = self.validate_file_against_xsd(
|
||||
xml_file, verbose=False
|
||||
)
|
||||
|
||||
if is_valid is None:
|
||||
skipped_count += 1
|
||||
continue
|
||||
elif is_valid and not new_file_errors:
|
||||
valid_count += 1
|
||||
continue
|
||||
elif is_valid:
|
||||
# Had errors but all existed in original
|
||||
original_error_count += 1
|
||||
valid_count += 1
|
||||
continue
|
||||
|
||||
# Has new errors
|
||||
new_errors.append(f" {relative_path}: {len(new_file_errors)} new error(s)")
|
||||
for error in list(new_file_errors)[:3]: # Show first 3 errors
|
||||
new_errors.append(
|
||||
f" - {error[:250]}..." if len(error) > 250 else f" - {error}"
|
||||
)
|
||||
|
||||
# Print summary
|
||||
if self.verbose:
|
||||
print(f"Validated {len(self.xml_files)} files:")
|
||||
print(f" - Valid: {valid_count}")
|
||||
print(f" - Skipped (no schema): {skipped_count}")
|
||||
if original_error_count:
|
||||
print(f" - With original errors (ignored): {original_error_count}")
|
||||
print(
|
||||
f" - With NEW errors: {len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')]) or 0}"
|
||||
)
|
||||
|
||||
if new_errors:
|
||||
print("\nFAILED - Found NEW validation errors:")
|
||||
for error in new_errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("\nPASSED - No new XSD validation errors introduced")
|
||||
return True
|
||||
|
||||
def _get_schema_path(self, xml_file):
|
||||
"""Determine the appropriate schema path for an XML file."""
|
||||
# Check exact filename match
|
||||
if xml_file.name in self.SCHEMA_MAPPINGS:
|
||||
return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.name]
|
||||
|
||||
# Check .rels files
|
||||
if xml_file.suffix == ".rels":
|
||||
return self.schemas_dir / self.SCHEMA_MAPPINGS[".rels"]
|
||||
|
||||
# Check chart files
|
||||
if "charts/" in str(xml_file) and xml_file.name.startswith("chart"):
|
||||
return self.schemas_dir / self.SCHEMA_MAPPINGS["chart"]
|
||||
|
||||
# Check theme files
|
||||
if "theme/" in str(xml_file) and xml_file.name.startswith("theme"):
|
||||
return self.schemas_dir / self.SCHEMA_MAPPINGS["theme"]
|
||||
|
||||
# Check if file is in a main content folder and use appropriate schema
|
||||
if xml_file.parent.name in self.MAIN_CONTENT_FOLDERS:
|
||||
return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.parent.name]
|
||||
|
||||
return None
|
||||
|
||||
def _clean_ignorable_namespaces(self, xml_doc):
|
||||
"""Remove attributes and elements not in allowed namespaces."""
|
||||
# Create a clean copy
|
||||
xml_string = lxml.etree.tostring(xml_doc, encoding="unicode")
|
||||
xml_copy = lxml.etree.fromstring(xml_string)
|
||||
|
||||
# Remove attributes not in allowed namespaces
|
||||
for elem in xml_copy.iter():
|
||||
attrs_to_remove = []
|
||||
|
||||
for attr in elem.attrib:
|
||||
# Check if attribute is from a namespace other than allowed ones
|
||||
if "{" in attr:
|
||||
ns = attr.split("}")[0][1:]
|
||||
if ns not in self.OOXML_NAMESPACES:
|
||||
attrs_to_remove.append(attr)
|
||||
|
||||
# Remove collected attributes
|
||||
for attr in attrs_to_remove:
|
||||
del elem.attrib[attr]
|
||||
|
||||
# Remove elements not in allowed namespaces
|
||||
self._remove_ignorable_elements(xml_copy)
|
||||
|
||||
return lxml.etree.ElementTree(xml_copy)
|
||||
|
||||
def _remove_ignorable_elements(self, root):
|
||||
"""Recursively remove all elements not in allowed namespaces."""
|
||||
elements_to_remove = []
|
||||
|
||||
# Find elements to remove
|
||||
for elem in list(root):
|
||||
# Skip non-element nodes (comments, processing instructions, etc.)
|
||||
if not hasattr(elem, "tag") or callable(elem.tag):
|
||||
continue
|
||||
|
||||
tag_str = str(elem.tag)
|
||||
if tag_str.startswith("{"):
|
||||
ns = tag_str.split("}")[0][1:]
|
||||
if ns not in self.OOXML_NAMESPACES:
|
||||
elements_to_remove.append(elem)
|
||||
continue
|
||||
|
||||
# Recursively clean child elements
|
||||
self._remove_ignorable_elements(elem)
|
||||
|
||||
# Remove collected elements
|
||||
for elem in elements_to_remove:
|
||||
root.remove(elem)
|
||||
|
||||
def _preprocess_for_mc_ignorable(self, xml_doc):
|
||||
"""Preprocess XML to handle mc:Ignorable attribute properly."""
|
||||
# Remove mc:Ignorable attributes before validation
|
||||
root = xml_doc.getroot()
|
||||
|
||||
# Remove mc:Ignorable attribute from root
|
||||
if f"{{{self.MC_NAMESPACE}}}Ignorable" in root.attrib:
|
||||
del root.attrib[f"{{{self.MC_NAMESPACE}}}Ignorable"]
|
||||
|
||||
return xml_doc
|
||||
|
||||
def _validate_single_file_xsd(self, xml_file, base_path):
|
||||
"""Validate a single XML file against XSD schema. Returns (is_valid, errors_set)."""
|
||||
schema_path = self._get_schema_path(xml_file)
|
||||
if not schema_path:
|
||||
return None, None # Skip file
|
||||
|
||||
try:
|
||||
# Load schema
|
||||
with open(schema_path, "rb") as xsd_file:
|
||||
parser = lxml.etree.XMLParser()
|
||||
xsd_doc = lxml.etree.parse(
|
||||
xsd_file, parser=parser, base_url=str(schema_path)
|
||||
)
|
||||
schema = lxml.etree.XMLSchema(xsd_doc)
|
||||
|
||||
# Load and preprocess XML
|
||||
with open(xml_file, "r") as f:
|
||||
xml_doc = lxml.etree.parse(f)
|
||||
|
||||
xml_doc, _ = self._remove_template_tags_from_text_nodes(xml_doc)
|
||||
xml_doc = self._preprocess_for_mc_ignorable(xml_doc)
|
||||
|
||||
# Clean ignorable namespaces if needed
|
||||
relative_path = xml_file.relative_to(base_path)
|
||||
if (
|
||||
relative_path.parts
|
||||
and relative_path.parts[0] in self.MAIN_CONTENT_FOLDERS
|
||||
):
|
||||
xml_doc = self._clean_ignorable_namespaces(xml_doc)
|
||||
|
||||
# Validate
|
||||
if schema.validate(xml_doc):
|
||||
return True, set()
|
||||
else:
|
||||
errors = set()
|
||||
for error in schema.error_log:
|
||||
# Store normalized error message (without line numbers for comparison)
|
||||
errors.add(error.message)
|
||||
return False, errors
|
||||
|
||||
except Exception as e:
|
||||
return False, {str(e)}
|
||||
|
||||
def _get_original_file_errors(self, xml_file):
|
||||
"""Get XSD validation errors from a single file in the original document.
|
||||
|
||||
Args:
|
||||
xml_file: Path to the XML file in unpacked_dir to check
|
||||
|
||||
Returns:
|
||||
set: Set of error messages from the original file
|
||||
"""
|
||||
import tempfile
|
||||
import zipfile
|
||||
|
||||
# Resolve both paths to handle symlinks (e.g., /var vs /private/var on macOS)
|
||||
xml_file = Path(xml_file).resolve()
|
||||
unpacked_dir = self.unpacked_dir.resolve()
|
||||
relative_path = xml_file.relative_to(unpacked_dir)
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_path = Path(temp_dir)
|
||||
|
||||
# Extract original file
|
||||
with zipfile.ZipFile(self.original_file, "r") as zip_ref:
|
||||
zip_ref.extractall(temp_path)
|
||||
|
||||
# Find corresponding file in original
|
||||
original_xml_file = temp_path / relative_path
|
||||
|
||||
if not original_xml_file.exists():
|
||||
# File didn't exist in original, so no original errors
|
||||
return set()
|
||||
|
||||
# Validate the specific file in original
|
||||
is_valid, errors = self._validate_single_file_xsd(
|
||||
original_xml_file, temp_path
|
||||
)
|
||||
return errors if errors else set()
|
||||
|
||||
def _remove_template_tags_from_text_nodes(self, xml_doc):
|
||||
"""Remove template tags from XML text nodes and collect warnings.
|
||||
|
||||
Template tags follow the pattern {{ ... }} and are used as placeholders
|
||||
for content replacement. They should be removed from text content before
|
||||
XSD validation while preserving XML structure.
|
||||
|
||||
Returns:
|
||||
tuple: (cleaned_xml_doc, warnings_list)
|
||||
"""
|
||||
warnings = []
|
||||
template_pattern = re.compile(r"\{\{[^}]*\}\}")
|
||||
|
||||
# Create a copy of the document to avoid modifying the original
|
||||
xml_string = lxml.etree.tostring(xml_doc, encoding="unicode")
|
||||
xml_copy = lxml.etree.fromstring(xml_string)
|
||||
|
||||
def process_text_content(text, content_type):
|
||||
if not text:
|
||||
return text
|
||||
matches = list(template_pattern.finditer(text))
|
||||
if matches:
|
||||
for match in matches:
|
||||
warnings.append(
|
||||
f"Found template tag in {content_type}: {match.group()}"
|
||||
)
|
||||
return template_pattern.sub("", text)
|
||||
return text
|
||||
|
||||
# Process all text nodes in the document
|
||||
for elem in xml_copy.iter():
|
||||
# Skip processing if this is a w:t element
|
||||
if not hasattr(elem, "tag") or callable(elem.tag):
|
||||
continue
|
||||
tag_str = str(elem.tag)
|
||||
if tag_str.endswith("}t") or tag_str == "t":
|
||||
continue
|
||||
|
||||
elem.text = process_text_content(elem.text, "text content")
|
||||
elem.tail = process_text_content(elem.tail, "tail content")
|
||||
|
||||
return lxml.etree.ElementTree(xml_copy), warnings
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise RuntimeError("This module should not be run directly.")
|
||||
274
.claude/skills/pptx/ooxml/scripts/validation/docx.py
Normal file
274
.claude/skills/pptx/ooxml/scripts/validation/docx.py
Normal file
@ -0,0 +1,274 @@
|
||||
"""
|
||||
Validator for Word document XML files against XSD schemas.
|
||||
"""
|
||||
|
||||
import re
|
||||
import tempfile
|
||||
import zipfile
|
||||
|
||||
import lxml.etree
|
||||
|
||||
from .base import BaseSchemaValidator
|
||||
|
||||
|
||||
class DOCXSchemaValidator(BaseSchemaValidator):
|
||||
"""Validator for Word document XML files against XSD schemas."""
|
||||
|
||||
# Word-specific namespace
|
||||
WORD_2006_NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
|
||||
# Word-specific element to relationship type mappings
|
||||
# Start with empty mapping - add specific cases as we discover them
|
||||
ELEMENT_RELATIONSHIP_TYPES = {}
|
||||
|
||||
def validate(self):
|
||||
"""Run all validation checks and return True if all pass."""
|
||||
# Test 0: XML well-formedness
|
||||
if not self.validate_xml():
|
||||
return False
|
||||
|
||||
# Test 1: Namespace declarations
|
||||
all_valid = True
|
||||
if not self.validate_namespaces():
|
||||
all_valid = False
|
||||
|
||||
# Test 2: Unique IDs
|
||||
if not self.validate_unique_ids():
|
||||
all_valid = False
|
||||
|
||||
# Test 3: Relationship and file reference validation
|
||||
if not self.validate_file_references():
|
||||
all_valid = False
|
||||
|
||||
# Test 4: Content type declarations
|
||||
if not self.validate_content_types():
|
||||
all_valid = False
|
||||
|
||||
# Test 5: XSD schema validation
|
||||
if not self.validate_against_xsd():
|
||||
all_valid = False
|
||||
|
||||
# Test 6: Whitespace preservation
|
||||
if not self.validate_whitespace_preservation():
|
||||
all_valid = False
|
||||
|
||||
# Test 7: Deletion validation
|
||||
if not self.validate_deletions():
|
||||
all_valid = False
|
||||
|
||||
# Test 8: Insertion validation
|
||||
if not self.validate_insertions():
|
||||
all_valid = False
|
||||
|
||||
# Test 9: Relationship ID reference validation
|
||||
if not self.validate_all_relationship_ids():
|
||||
all_valid = False
|
||||
|
||||
# Count and compare paragraphs
|
||||
self.compare_paragraph_counts()
|
||||
|
||||
return all_valid
|
||||
|
||||
def validate_whitespace_preservation(self):
|
||||
"""
|
||||
Validate that w:t elements with whitespace have xml:space='preserve'.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
# Only check document.xml files
|
||||
if xml_file.name != "document.xml":
|
||||
continue
|
||||
|
||||
try:
|
||||
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||
|
||||
# Find all w:t elements
|
||||
for elem in root.iter(f"{{{self.WORD_2006_NAMESPACE}}}t"):
|
||||
if elem.text:
|
||||
text = elem.text
|
||||
# Check if text starts or ends with whitespace
|
||||
if re.match(r"^\s.*", text) or re.match(r".*\s$", text):
|
||||
# Check if xml:space="preserve" attribute exists
|
||||
xml_space_attr = f"{{{self.XML_NAMESPACE}}}space"
|
||||
if (
|
||||
xml_space_attr not in elem.attrib
|
||||
or elem.attrib[xml_space_attr] != "preserve"
|
||||
):
|
||||
# Show a preview of the text
|
||||
text_preview = (
|
||||
repr(text)[:50] + "..."
|
||||
if len(repr(text)) > 50
|
||||
else repr(text)
|
||||
)
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Line {elem.sourceline}: w:t element with whitespace missing xml:space='preserve': {text_preview}"
|
||||
)
|
||||
|
||||
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} whitespace preservation violations:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - All whitespace is properly preserved")
|
||||
return True
|
||||
|
||||
def validate_deletions(self):
|
||||
"""
|
||||
Validate that w:t elements are not within w:del elements.
|
||||
For some reason, XSD validation does not catch this, so we do it manually.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
# Only check document.xml files
|
||||
if xml_file.name != "document.xml":
|
||||
continue
|
||||
|
||||
try:
|
||||
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||
|
||||
# Find all w:t elements that are descendants of w:del elements
|
||||
namespaces = {"w": self.WORD_2006_NAMESPACE}
|
||||
xpath_expression = ".//w:del//w:t"
|
||||
problematic_t_elements = root.xpath(
|
||||
xpath_expression, namespaces=namespaces
|
||||
)
|
||||
for t_elem in problematic_t_elements:
|
||||
if t_elem.text:
|
||||
# Show a preview of the text
|
||||
text_preview = (
|
||||
repr(t_elem.text)[:50] + "..."
|
||||
if len(repr(t_elem.text)) > 50
|
||||
else repr(t_elem.text)
|
||||
)
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Line {t_elem.sourceline}: <w:t> found within <w:del>: {text_preview}"
|
||||
)
|
||||
|
||||
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} deletion validation violations:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - No w:t elements found within w:del elements")
|
||||
return True
|
||||
|
||||
def count_paragraphs_in_unpacked(self):
|
||||
"""Count the number of paragraphs in the unpacked document."""
|
||||
count = 0
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
# Only check document.xml files
|
||||
if xml_file.name != "document.xml":
|
||||
continue
|
||||
|
||||
try:
|
||||
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||
# Count all w:p elements
|
||||
paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p")
|
||||
count = len(paragraphs)
|
||||
except Exception as e:
|
||||
print(f"Error counting paragraphs in unpacked document: {e}")
|
||||
|
||||
return count
|
||||
|
||||
def count_paragraphs_in_original(self):
|
||||
"""Count the number of paragraphs in the original docx file."""
|
||||
count = 0
|
||||
|
||||
try:
|
||||
# Create temporary directory to unpack original
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Unpack original docx
|
||||
with zipfile.ZipFile(self.original_file, "r") as zip_ref:
|
||||
zip_ref.extractall(temp_dir)
|
||||
|
||||
# Parse document.xml
|
||||
doc_xml_path = temp_dir + "/word/document.xml"
|
||||
root = lxml.etree.parse(doc_xml_path).getroot()
|
||||
|
||||
# Count all w:p elements
|
||||
paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p")
|
||||
count = len(paragraphs)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error counting paragraphs in original document: {e}")
|
||||
|
||||
return count
|
||||
|
||||
def validate_insertions(self):
|
||||
"""
|
||||
Validate that w:delText elements are not within w:ins elements.
|
||||
w:delText is only allowed in w:ins if nested within a w:del.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
if xml_file.name != "document.xml":
|
||||
continue
|
||||
|
||||
try:
|
||||
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||
namespaces = {"w": self.WORD_2006_NAMESPACE}
|
||||
|
||||
# Find w:delText in w:ins that are NOT within w:del
|
||||
invalid_elements = root.xpath(
|
||||
".//w:ins//w:delText[not(ancestor::w:del)]",
|
||||
namespaces=namespaces
|
||||
)
|
||||
|
||||
for elem in invalid_elements:
|
||||
text_preview = (
|
||||
repr(elem.text or "")[:50] + "..."
|
||||
if len(repr(elem.text or "")) > 50
|
||||
else repr(elem.text or "")
|
||||
)
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Line {elem.sourceline}: <w:delText> within <w:ins>: {text_preview}"
|
||||
)
|
||||
|
||||
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} insertion validation violations:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - No w:delText elements within w:ins elements")
|
||||
return True
|
||||
|
||||
def compare_paragraph_counts(self):
|
||||
"""Compare paragraph counts between original and new document."""
|
||||
original_count = self.count_paragraphs_in_original()
|
||||
new_count = self.count_paragraphs_in_unpacked()
|
||||
|
||||
diff = new_count - original_count
|
||||
diff_str = f"+{diff}" if diff > 0 else str(diff)
|
||||
print(f"\nParagraphs: {original_count} → {new_count} ({diff_str})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise RuntimeError("This module should not be run directly.")
|
||||
315
.claude/skills/pptx/ooxml/scripts/validation/pptx.py
Normal file
315
.claude/skills/pptx/ooxml/scripts/validation/pptx.py
Normal file
@ -0,0 +1,315 @@
|
||||
"""
|
||||
Validator for PowerPoint presentation XML files against XSD schemas.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from .base import BaseSchemaValidator
|
||||
|
||||
|
||||
class PPTXSchemaValidator(BaseSchemaValidator):
|
||||
"""Validator for PowerPoint presentation XML files against XSD schemas."""
|
||||
|
||||
# PowerPoint presentation namespace
|
||||
PRESENTATIONML_NAMESPACE = (
|
||||
"http://schemas.openxmlformats.org/presentationml/2006/main"
|
||||
)
|
||||
|
||||
# PowerPoint-specific element to relationship type mappings
|
||||
ELEMENT_RELATIONSHIP_TYPES = {
|
||||
"sldid": "slide",
|
||||
"sldmasterid": "slidemaster",
|
||||
"notesmasterid": "notesmaster",
|
||||
"sldlayoutid": "slidelayout",
|
||||
"themeid": "theme",
|
||||
"tablestyleid": "tablestyles",
|
||||
}
|
||||
|
||||
def validate(self):
|
||||
"""Run all validation checks and return True if all pass."""
|
||||
# Test 0: XML well-formedness
|
||||
if not self.validate_xml():
|
||||
return False
|
||||
|
||||
# Test 1: Namespace declarations
|
||||
all_valid = True
|
||||
if not self.validate_namespaces():
|
||||
all_valid = False
|
||||
|
||||
# Test 2: Unique IDs
|
||||
if not self.validate_unique_ids():
|
||||
all_valid = False
|
||||
|
||||
# Test 3: UUID ID validation
|
||||
if not self.validate_uuid_ids():
|
||||
all_valid = False
|
||||
|
||||
# Test 4: Relationship and file reference validation
|
||||
if not self.validate_file_references():
|
||||
all_valid = False
|
||||
|
||||
# Test 5: Slide layout ID validation
|
||||
if not self.validate_slide_layout_ids():
|
||||
all_valid = False
|
||||
|
||||
# Test 6: Content type declarations
|
||||
if not self.validate_content_types():
|
||||
all_valid = False
|
||||
|
||||
# Test 7: XSD schema validation
|
||||
if not self.validate_against_xsd():
|
||||
all_valid = False
|
||||
|
||||
# Test 8: Notes slide reference validation
|
||||
if not self.validate_notes_slide_references():
|
||||
all_valid = False
|
||||
|
||||
# Test 9: Relationship ID reference validation
|
||||
if not self.validate_all_relationship_ids():
|
||||
all_valid = False
|
||||
|
||||
# Test 10: Duplicate slide layout references validation
|
||||
if not self.validate_no_duplicate_slide_layouts():
|
||||
all_valid = False
|
||||
|
||||
return all_valid
|
||||
|
||||
def validate_uuid_ids(self):
|
||||
"""Validate that ID attributes that look like UUIDs contain only hex values."""
|
||||
import lxml.etree
|
||||
|
||||
errors = []
|
||||
# UUID pattern: 8-4-4-4-12 hex digits with optional braces/hyphens
|
||||
uuid_pattern = re.compile(
|
||||
r"^[\{\(]?[0-9A-Fa-f]{8}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{12}[\}\)]?$"
|
||||
)
|
||||
|
||||
for xml_file in self.xml_files:
|
||||
try:
|
||||
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||
|
||||
# Check all elements for ID attributes
|
||||
for elem in root.iter():
|
||||
for attr, value in elem.attrib.items():
|
||||
# Check if this is an ID attribute
|
||||
attr_name = attr.split("}")[-1].lower()
|
||||
if attr_name == "id" or attr_name.endswith("id"):
|
||||
# Check if value looks like a UUID (has the right length and pattern structure)
|
||||
if self._looks_like_uuid(value):
|
||||
# Validate that it contains only hex characters in the right positions
|
||||
if not uuid_pattern.match(value):
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||
f"Line {elem.sourceline}: ID '{value}' appears to be a UUID but contains invalid hex characters"
|
||||
)
|
||||
|
||||
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||
errors.append(
|
||||
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} UUID ID validation errors:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - All UUID-like IDs contain valid hex values")
|
||||
return True
|
||||
|
||||
def _looks_like_uuid(self, value):
|
||||
"""Check if a value has the general structure of a UUID."""
|
||||
# Remove common UUID delimiters
|
||||
clean_value = value.strip("{}()").replace("-", "")
|
||||
# Check if it's 32 hex-like characters (could include invalid hex chars)
|
||||
return len(clean_value) == 32 and all(c.isalnum() for c in clean_value)
|
||||
|
||||
def validate_slide_layout_ids(self):
|
||||
"""Validate that sldLayoutId elements in slide masters reference valid slide layouts."""
|
||||
import lxml.etree
|
||||
|
||||
errors = []
|
||||
|
||||
# Find all slide master files
|
||||
slide_masters = list(self.unpacked_dir.glob("ppt/slideMasters/*.xml"))
|
||||
|
||||
if not slide_masters:
|
||||
if self.verbose:
|
||||
print("PASSED - No slide masters found")
|
||||
return True
|
||||
|
||||
for slide_master in slide_masters:
|
||||
try:
|
||||
# Parse the slide master file
|
||||
root = lxml.etree.parse(str(slide_master)).getroot()
|
||||
|
||||
# Find the corresponding _rels file for this slide master
|
||||
rels_file = slide_master.parent / "_rels" / f"{slide_master.name}.rels"
|
||||
|
||||
if not rels_file.exists():
|
||||
errors.append(
|
||||
f" {slide_master.relative_to(self.unpacked_dir)}: "
|
||||
f"Missing relationships file: {rels_file.relative_to(self.unpacked_dir)}"
|
||||
)
|
||||
continue
|
||||
|
||||
# Parse the relationships file
|
||||
rels_root = lxml.etree.parse(str(rels_file)).getroot()
|
||||
|
||||
# Build a set of valid relationship IDs that point to slide layouts
|
||||
valid_layout_rids = set()
|
||||
for rel in rels_root.findall(
|
||||
f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship"
|
||||
):
|
||||
rel_type = rel.get("Type", "")
|
||||
if "slideLayout" in rel_type:
|
||||
valid_layout_rids.add(rel.get("Id"))
|
||||
|
||||
# Find all sldLayoutId elements in the slide master
|
||||
for sld_layout_id in root.findall(
|
||||
f".//{{{self.PRESENTATIONML_NAMESPACE}}}sldLayoutId"
|
||||
):
|
||||
r_id = sld_layout_id.get(
|
||||
f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id"
|
||||
)
|
||||
layout_id = sld_layout_id.get("id")
|
||||
|
||||
if r_id and r_id not in valid_layout_rids:
|
||||
errors.append(
|
||||
f" {slide_master.relative_to(self.unpacked_dir)}: "
|
||||
f"Line {sld_layout_id.sourceline}: sldLayoutId with id='{layout_id}' "
|
||||
f"references r:id='{r_id}' which is not found in slide layout relationships"
|
||||
)
|
||||
|
||||
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||
errors.append(
|
||||
f" {slide_master.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
print(f"FAILED - Found {len(errors)} slide layout ID validation errors:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
print(
|
||||
"Remove invalid references or add missing slide layouts to the relationships file."
|
||||
)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - All slide layout IDs reference valid slide layouts")
|
||||
return True
|
||||
|
||||
def validate_no_duplicate_slide_layouts(self):
|
||||
"""Validate that each slide has exactly one slideLayout reference."""
|
||||
import lxml.etree
|
||||
|
||||
errors = []
|
||||
slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels"))
|
||||
|
||||
for rels_file in slide_rels_files:
|
||||
try:
|
||||
root = lxml.etree.parse(str(rels_file)).getroot()
|
||||
|
||||
# Find all slideLayout relationships
|
||||
layout_rels = [
|
||||
rel
|
||||
for rel in root.findall(
|
||||
f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship"
|
||||
)
|
||||
if "slideLayout" in rel.get("Type", "")
|
||||
]
|
||||
|
||||
if len(layout_rels) > 1:
|
||||
errors.append(
|
||||
f" {rels_file.relative_to(self.unpacked_dir)}: has {len(layout_rels)} slideLayout references"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
errors.append(
|
||||
f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
print("FAILED - Found slides with duplicate slideLayout references:")
|
||||
for error in errors:
|
||||
print(error)
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - All slides have exactly one slideLayout reference")
|
||||
return True
|
||||
|
||||
def validate_notes_slide_references(self):
|
||||
"""Validate that each notesSlide file is referenced by only one slide."""
|
||||
import lxml.etree
|
||||
|
||||
errors = []
|
||||
notes_slide_references = {} # Track which slides reference each notesSlide
|
||||
|
||||
# Find all slide relationship files
|
||||
slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels"))
|
||||
|
||||
if not slide_rels_files:
|
||||
if self.verbose:
|
||||
print("PASSED - No slide relationship files found")
|
||||
return True
|
||||
|
||||
for rels_file in slide_rels_files:
|
||||
try:
|
||||
# Parse the relationships file
|
||||
root = lxml.etree.parse(str(rels_file)).getroot()
|
||||
|
||||
# Find all notesSlide relationships
|
||||
for rel in root.findall(
|
||||
f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship"
|
||||
):
|
||||
rel_type = rel.get("Type", "")
|
||||
if "notesSlide" in rel_type:
|
||||
target = rel.get("Target", "")
|
||||
if target:
|
||||
# Normalize the target path to handle relative paths
|
||||
normalized_target = target.replace("../", "")
|
||||
|
||||
# Track which slide references this notesSlide
|
||||
slide_name = rels_file.stem.replace(
|
||||
".xml", ""
|
||||
) # e.g., "slide1"
|
||||
|
||||
if normalized_target not in notes_slide_references:
|
||||
notes_slide_references[normalized_target] = []
|
||||
notes_slide_references[normalized_target].append(
|
||||
(slide_name, rels_file)
|
||||
)
|
||||
|
||||
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||
errors.append(
|
||||
f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||
)
|
||||
|
||||
# Check for duplicate references
|
||||
for target, references in notes_slide_references.items():
|
||||
if len(references) > 1:
|
||||
slide_names = [ref[0] for ref in references]
|
||||
errors.append(
|
||||
f" Notes slide '{target}' is referenced by multiple slides: {', '.join(slide_names)}"
|
||||
)
|
||||
for slide_name, rels_file in references:
|
||||
errors.append(f" - {rels_file.relative_to(self.unpacked_dir)}")
|
||||
|
||||
if errors:
|
||||
print(
|
||||
f"FAILED - Found {len([e for e in errors if not e.startswith(' ')])} notes slide reference validation errors:"
|
||||
)
|
||||
for error in errors:
|
||||
print(error)
|
||||
print("Each slide may optionally have its own slide file.")
|
||||
return False
|
||||
else:
|
||||
if self.verbose:
|
||||
print("PASSED - All notes slide references are unique")
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise RuntimeError("This module should not be run directly.")
|
||||
279
.claude/skills/pptx/ooxml/scripts/validation/redlining.py
Normal file
279
.claude/skills/pptx/ooxml/scripts/validation/redlining.py
Normal file
@ -0,0 +1,279 @@
|
||||
"""
|
||||
Validator for tracked changes in Word documents.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import tempfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class RedliningValidator:
|
||||
"""Validator for tracked changes in Word documents."""
|
||||
|
||||
def __init__(self, unpacked_dir, original_docx, verbose=False):
|
||||
self.unpacked_dir = Path(unpacked_dir)
|
||||
self.original_docx = Path(original_docx)
|
||||
self.verbose = verbose
|
||||
self.namespaces = {
|
||||
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
}
|
||||
|
||||
def validate(self):
|
||||
"""Main validation method that returns True if valid, False otherwise."""
|
||||
# Verify unpacked directory exists and has correct structure
|
||||
modified_file = self.unpacked_dir / "word" / "document.xml"
|
||||
if not modified_file.exists():
|
||||
print(f"FAILED - Modified document.xml not found at {modified_file}")
|
||||
return False
|
||||
|
||||
# First, check if there are any tracked changes by Claude to validate
|
||||
try:
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
tree = ET.parse(modified_file)
|
||||
root = tree.getroot()
|
||||
|
||||
# Check for w:del or w:ins tags authored by Claude
|
||||
del_elements = root.findall(".//w:del", self.namespaces)
|
||||
ins_elements = root.findall(".//w:ins", self.namespaces)
|
||||
|
||||
# Filter to only include changes by Claude
|
||||
claude_del_elements = [
|
||||
elem
|
||||
for elem in del_elements
|
||||
if elem.get(f"{{{self.namespaces['w']}}}author") == "Claude"
|
||||
]
|
||||
claude_ins_elements = [
|
||||
elem
|
||||
for elem in ins_elements
|
||||
if elem.get(f"{{{self.namespaces['w']}}}author") == "Claude"
|
||||
]
|
||||
|
||||
# Redlining validation is only needed if tracked changes by Claude have been used.
|
||||
if not claude_del_elements and not claude_ins_elements:
|
||||
if self.verbose:
|
||||
print("PASSED - No tracked changes by Claude found.")
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
# If we can't parse the XML, continue with full validation
|
||||
pass
|
||||
|
||||
# Create temporary directory for unpacking original docx
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_path = Path(temp_dir)
|
||||
|
||||
# Unpack original docx
|
||||
try:
|
||||
with zipfile.ZipFile(self.original_docx, "r") as zip_ref:
|
||||
zip_ref.extractall(temp_path)
|
||||
except Exception as e:
|
||||
print(f"FAILED - Error unpacking original docx: {e}")
|
||||
return False
|
||||
|
||||
original_file = temp_path / "word" / "document.xml"
|
||||
if not original_file.exists():
|
||||
print(
|
||||
f"FAILED - Original document.xml not found in {self.original_docx}"
|
||||
)
|
||||
return False
|
||||
|
||||
# Parse both XML files using xml.etree.ElementTree for redlining validation
|
||||
try:
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
modified_tree = ET.parse(modified_file)
|
||||
modified_root = modified_tree.getroot()
|
||||
original_tree = ET.parse(original_file)
|
||||
original_root = original_tree.getroot()
|
||||
except ET.ParseError as e:
|
||||
print(f"FAILED - Error parsing XML files: {e}")
|
||||
return False
|
||||
|
||||
# Remove Claude's tracked changes from both documents
|
||||
self._remove_claude_tracked_changes(original_root)
|
||||
self._remove_claude_tracked_changes(modified_root)
|
||||
|
||||
# Extract and compare text content
|
||||
modified_text = self._extract_text_content(modified_root)
|
||||
original_text = self._extract_text_content(original_root)
|
||||
|
||||
if modified_text != original_text:
|
||||
# Show detailed character-level differences for each paragraph
|
||||
error_message = self._generate_detailed_diff(
|
||||
original_text, modified_text
|
||||
)
|
||||
print(error_message)
|
||||
return False
|
||||
|
||||
if self.verbose:
|
||||
print("PASSED - All changes by Claude are properly tracked")
|
||||
return True
|
||||
|
||||
def _generate_detailed_diff(self, original_text, modified_text):
|
||||
"""Generate detailed word-level differences using git word diff."""
|
||||
error_parts = [
|
||||
"FAILED - Document text doesn't match after removing Claude's tracked changes",
|
||||
"",
|
||||
"Likely causes:",
|
||||
" 1. Modified text inside another author's <w:ins> or <w:del> tags",
|
||||
" 2. Made edits without proper tracked changes",
|
||||
" 3. Didn't nest <w:del> inside <w:ins> when deleting another's insertion",
|
||||
"",
|
||||
"For pre-redlined documents, use correct patterns:",
|
||||
" - To reject another's INSERTION: Nest <w:del> inside their <w:ins>",
|
||||
" - To restore another's DELETION: Add new <w:ins> AFTER their <w:del>",
|
||||
"",
|
||||
]
|
||||
|
||||
# Show git word diff
|
||||
git_diff = self._get_git_word_diff(original_text, modified_text)
|
||||
if git_diff:
|
||||
error_parts.extend(["Differences:", "============", git_diff])
|
||||
else:
|
||||
error_parts.append("Unable to generate word diff (git not available)")
|
||||
|
||||
return "\n".join(error_parts)
|
||||
|
||||
def _get_git_word_diff(self, original_text, modified_text):
|
||||
"""Generate word diff using git with character-level precision."""
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_path = Path(temp_dir)
|
||||
|
||||
# Create two files
|
||||
original_file = temp_path / "original.txt"
|
||||
modified_file = temp_path / "modified.txt"
|
||||
|
||||
original_file.write_text(original_text, encoding="utf-8")
|
||||
modified_file.write_text(modified_text, encoding="utf-8")
|
||||
|
||||
# Try character-level diff first for precise differences
|
||||
result = subprocess.run(
|
||||
[
|
||||
"git",
|
||||
"diff",
|
||||
"--word-diff=plain",
|
||||
"--word-diff-regex=.", # Character-by-character diff
|
||||
"-U0", # Zero lines of context - show only changed lines
|
||||
"--no-index",
|
||||
str(original_file),
|
||||
str(modified_file),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
if result.stdout.strip():
|
||||
# Clean up the output - remove git diff header lines
|
||||
lines = result.stdout.split("\n")
|
||||
# Skip the header lines (diff --git, index, +++, ---, @@)
|
||||
content_lines = []
|
||||
in_content = False
|
||||
for line in lines:
|
||||
if line.startswith("@@"):
|
||||
in_content = True
|
||||
continue
|
||||
if in_content and line.strip():
|
||||
content_lines.append(line)
|
||||
|
||||
if content_lines:
|
||||
return "\n".join(content_lines)
|
||||
|
||||
# Fallback to word-level diff if character-level is too verbose
|
||||
result = subprocess.run(
|
||||
[
|
||||
"git",
|
||||
"diff",
|
||||
"--word-diff=plain",
|
||||
"-U0", # Zero lines of context
|
||||
"--no-index",
|
||||
str(original_file),
|
||||
str(modified_file),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
if result.stdout.strip():
|
||||
lines = result.stdout.split("\n")
|
||||
content_lines = []
|
||||
in_content = False
|
||||
for line in lines:
|
||||
if line.startswith("@@"):
|
||||
in_content = True
|
||||
continue
|
||||
if in_content and line.strip():
|
||||
content_lines.append(line)
|
||||
return "\n".join(content_lines)
|
||||
|
||||
except (subprocess.CalledProcessError, FileNotFoundError, Exception):
|
||||
# Git not available or other error, return None to use fallback
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _remove_claude_tracked_changes(self, root):
|
||||
"""Remove tracked changes authored by Claude from the XML root."""
|
||||
ins_tag = f"{{{self.namespaces['w']}}}ins"
|
||||
del_tag = f"{{{self.namespaces['w']}}}del"
|
||||
author_attr = f"{{{self.namespaces['w']}}}author"
|
||||
|
||||
# Remove w:ins elements
|
||||
for parent in root.iter():
|
||||
to_remove = []
|
||||
for child in parent:
|
||||
if child.tag == ins_tag and child.get(author_attr) == "Claude":
|
||||
to_remove.append(child)
|
||||
for elem in to_remove:
|
||||
parent.remove(elem)
|
||||
|
||||
# Unwrap content in w:del elements where author is "Claude"
|
||||
deltext_tag = f"{{{self.namespaces['w']}}}delText"
|
||||
t_tag = f"{{{self.namespaces['w']}}}t"
|
||||
|
||||
for parent in root.iter():
|
||||
to_process = []
|
||||
for child in parent:
|
||||
if child.tag == del_tag and child.get(author_attr) == "Claude":
|
||||
to_process.append((child, list(parent).index(child)))
|
||||
|
||||
# Process in reverse order to maintain indices
|
||||
for del_elem, del_index in reversed(to_process):
|
||||
# Convert w:delText to w:t before moving
|
||||
for elem in del_elem.iter():
|
||||
if elem.tag == deltext_tag:
|
||||
elem.tag = t_tag
|
||||
|
||||
# Move all children of w:del to its parent before removing w:del
|
||||
for child in reversed(list(del_elem)):
|
||||
parent.insert(del_index, child)
|
||||
parent.remove(del_elem)
|
||||
|
||||
def _extract_text_content(self, root):
|
||||
"""Extract text content from Word XML, preserving paragraph structure.
|
||||
|
||||
Empty paragraphs are skipped to avoid false positives when tracked
|
||||
insertions add only structural elements without text content.
|
||||
"""
|
||||
p_tag = f"{{{self.namespaces['w']}}}p"
|
||||
t_tag = f"{{{self.namespaces['w']}}}t"
|
||||
|
||||
paragraphs = []
|
||||
for p_elem in root.findall(f".//{p_tag}"):
|
||||
# Get all text elements within this paragraph
|
||||
text_parts = []
|
||||
for t_elem in p_elem.findall(f".//{t_tag}"):
|
||||
if t_elem.text:
|
||||
text_parts.append(t_elem.text)
|
||||
paragraph_text = "".join(text_parts)
|
||||
# Skip empty paragraphs - they don't affect content validation
|
||||
if paragraph_text:
|
||||
paragraphs.append(paragraph_text)
|
||||
|
||||
return "\n".join(paragraphs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise RuntimeError("This module should not be run directly.")
|
||||
979
.claude/skills/pptx/scripts/html2pptx.js
Normal file
979
.claude/skills/pptx/scripts/html2pptx.js
Normal file
@ -0,0 +1,979 @@
|
||||
/**
|
||||
* html2pptx - Convert HTML slide to pptxgenjs slide with positioned elements
|
||||
*
|
||||
* USAGE:
|
||||
* const pptx = new pptxgen();
|
||||
* pptx.layout = 'LAYOUT_16x9'; // Must match HTML body dimensions
|
||||
*
|
||||
* const { slide, placeholders } = await html2pptx('slide.html', pptx);
|
||||
* slide.addChart(pptx.charts.LINE, data, placeholders[0]);
|
||||
*
|
||||
* await pptx.writeFile('output.pptx');
|
||||
*
|
||||
* FEATURES:
|
||||
* - Converts HTML to PowerPoint with accurate positioning
|
||||
* - Supports text, images, shapes, and bullet lists
|
||||
* - Extracts placeholder elements (class="placeholder") with positions
|
||||
* - Handles CSS gradients, borders, and margins
|
||||
*
|
||||
* VALIDATION:
|
||||
* - Uses body width/height from HTML for viewport sizing
|
||||
* - Throws error if HTML dimensions don't match presentation layout
|
||||
* - Throws error if content overflows body (with overflow details)
|
||||
*
|
||||
* RETURNS:
|
||||
* { slide, placeholders } where placeholders is an array of { id, x, y, w, h }
|
||||
*/
|
||||
|
||||
const { chromium } = require('playwright');
|
||||
const path = require('path');
|
||||
const sharp = require('sharp');
|
||||
|
||||
const PT_PER_PX = 0.75;
|
||||
const PX_PER_IN = 96;
|
||||
const EMU_PER_IN = 914400;
|
||||
|
||||
// Helper: Get body dimensions and check for overflow
|
||||
async function getBodyDimensions(page) {
|
||||
const bodyDimensions = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
const style = window.getComputedStyle(body);
|
||||
|
||||
return {
|
||||
width: parseFloat(style.width),
|
||||
height: parseFloat(style.height),
|
||||
scrollWidth: body.scrollWidth,
|
||||
scrollHeight: body.scrollHeight
|
||||
};
|
||||
});
|
||||
|
||||
const errors = [];
|
||||
const widthOverflowPx = Math.max(0, bodyDimensions.scrollWidth - bodyDimensions.width - 1);
|
||||
const heightOverflowPx = Math.max(0, bodyDimensions.scrollHeight - bodyDimensions.height - 1);
|
||||
|
||||
const widthOverflowPt = widthOverflowPx * PT_PER_PX;
|
||||
const heightOverflowPt = heightOverflowPx * PT_PER_PX;
|
||||
|
||||
if (widthOverflowPt > 0 || heightOverflowPt > 0) {
|
||||
const directions = [];
|
||||
if (widthOverflowPt > 0) directions.push(`${widthOverflowPt.toFixed(1)}pt horizontally`);
|
||||
if (heightOverflowPt > 0) directions.push(`${heightOverflowPt.toFixed(1)}pt vertically`);
|
||||
const reminder = heightOverflowPt > 0 ? ' (Remember: leave 0.5" margin at bottom of slide)' : '';
|
||||
errors.push(`HTML content overflows body by ${directions.join(' and ')}${reminder}`);
|
||||
}
|
||||
|
||||
return { ...bodyDimensions, errors };
|
||||
}
|
||||
|
||||
// Helper: Validate dimensions match presentation layout
|
||||
function validateDimensions(bodyDimensions, pres) {
|
||||
const errors = [];
|
||||
const widthInches = bodyDimensions.width / PX_PER_IN;
|
||||
const heightInches = bodyDimensions.height / PX_PER_IN;
|
||||
|
||||
if (pres.presLayout) {
|
||||
const layoutWidth = pres.presLayout.width / EMU_PER_IN;
|
||||
const layoutHeight = pres.presLayout.height / EMU_PER_IN;
|
||||
|
||||
if (Math.abs(layoutWidth - widthInches) > 0.1 || Math.abs(layoutHeight - heightInches) > 0.1) {
|
||||
errors.push(
|
||||
`HTML dimensions (${widthInches.toFixed(1)}" × ${heightInches.toFixed(1)}") ` +
|
||||
`don't match presentation layout (${layoutWidth.toFixed(1)}" × ${layoutHeight.toFixed(1)}")`
|
||||
);
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
function validateTextBoxPosition(slideData, bodyDimensions) {
|
||||
const errors = [];
|
||||
const slideHeightInches = bodyDimensions.height / PX_PER_IN;
|
||||
const minBottomMargin = 0.5; // 0.5 inches from bottom
|
||||
|
||||
for (const el of slideData.elements) {
|
||||
// Check text elements (p, h1-h6, list)
|
||||
if (['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'list'].includes(el.type)) {
|
||||
const fontSize = el.style?.fontSize || 0;
|
||||
const bottomEdge = el.position.y + el.position.h;
|
||||
const distanceFromBottom = slideHeightInches - bottomEdge;
|
||||
|
||||
if (fontSize > 12 && distanceFromBottom < minBottomMargin) {
|
||||
const getText = () => {
|
||||
if (typeof el.text === 'string') return el.text;
|
||||
if (Array.isArray(el.text)) return el.text.find(t => t.text)?.text || '';
|
||||
if (Array.isArray(el.items)) return el.items.find(item => item.text)?.text || '';
|
||||
return '';
|
||||
};
|
||||
const textPrefix = getText().substring(0, 50) + (getText().length > 50 ? '...' : '');
|
||||
|
||||
errors.push(
|
||||
`Text box "${textPrefix}" ends too close to bottom edge ` +
|
||||
`(${distanceFromBottom.toFixed(2)}" from bottom, minimum ${minBottomMargin}" required)`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
// Helper: Add background to slide
|
||||
async function addBackground(slideData, targetSlide, tmpDir) {
|
||||
if (slideData.background.type === 'image' && slideData.background.path) {
|
||||
let imagePath = slideData.background.path.startsWith('file://')
|
||||
? slideData.background.path.replace('file://', '')
|
||||
: slideData.background.path;
|
||||
targetSlide.background = { path: imagePath };
|
||||
} else if (slideData.background.type === 'color' && slideData.background.value) {
|
||||
targetSlide.background = { color: slideData.background.value };
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: Add elements to slide
|
||||
function addElements(slideData, targetSlide, pres) {
|
||||
for (const el of slideData.elements) {
|
||||
if (el.type === 'image') {
|
||||
let imagePath = el.src.startsWith('file://') ? el.src.replace('file://', '') : el.src;
|
||||
targetSlide.addImage({
|
||||
path: imagePath,
|
||||
x: el.position.x,
|
||||
y: el.position.y,
|
||||
w: el.position.w,
|
||||
h: el.position.h
|
||||
});
|
||||
} else if (el.type === 'line') {
|
||||
targetSlide.addShape(pres.ShapeType.line, {
|
||||
x: el.x1,
|
||||
y: el.y1,
|
||||
w: el.x2 - el.x1,
|
||||
h: el.y2 - el.y1,
|
||||
line: { color: el.color, width: el.width }
|
||||
});
|
||||
} else if (el.type === 'shape') {
|
||||
const shapeOptions = {
|
||||
x: el.position.x,
|
||||
y: el.position.y,
|
||||
w: el.position.w,
|
||||
h: el.position.h,
|
||||
shape: el.shape.rectRadius > 0 ? pres.ShapeType.roundRect : pres.ShapeType.rect
|
||||
};
|
||||
|
||||
if (el.shape.fill) {
|
||||
shapeOptions.fill = { color: el.shape.fill };
|
||||
if (el.shape.transparency != null) shapeOptions.fill.transparency = el.shape.transparency;
|
||||
}
|
||||
if (el.shape.line) shapeOptions.line = el.shape.line;
|
||||
if (el.shape.rectRadius > 0) shapeOptions.rectRadius = el.shape.rectRadius;
|
||||
if (el.shape.shadow) shapeOptions.shadow = el.shape.shadow;
|
||||
|
||||
targetSlide.addText(el.text || '', shapeOptions);
|
||||
} else if (el.type === 'list') {
|
||||
const listOptions = {
|
||||
x: el.position.x,
|
||||
y: el.position.y,
|
||||
w: el.position.w,
|
||||
h: el.position.h,
|
||||
fontSize: el.style.fontSize,
|
||||
fontFace: el.style.fontFace,
|
||||
color: el.style.color,
|
||||
align: el.style.align,
|
||||
valign: 'top',
|
||||
lineSpacing: el.style.lineSpacing,
|
||||
paraSpaceBefore: el.style.paraSpaceBefore,
|
||||
paraSpaceAfter: el.style.paraSpaceAfter,
|
||||
margin: el.style.margin
|
||||
};
|
||||
if (el.style.margin) listOptions.margin = el.style.margin;
|
||||
targetSlide.addText(el.items, listOptions);
|
||||
} else {
|
||||
// Check if text is single-line (height suggests one line)
|
||||
const lineHeight = el.style.lineSpacing || el.style.fontSize * 1.2;
|
||||
const isSingleLine = el.position.h <= lineHeight * 1.5;
|
||||
|
||||
let adjustedX = el.position.x;
|
||||
let adjustedW = el.position.w;
|
||||
|
||||
// Make single-line text 2% wider to account for underestimate
|
||||
if (isSingleLine) {
|
||||
const widthIncrease = el.position.w * 0.02;
|
||||
const align = el.style.align;
|
||||
|
||||
if (align === 'center') {
|
||||
// Center: expand both sides
|
||||
adjustedX = el.position.x - (widthIncrease / 2);
|
||||
adjustedW = el.position.w + widthIncrease;
|
||||
} else if (align === 'right') {
|
||||
// Right: expand to the left
|
||||
adjustedX = el.position.x - widthIncrease;
|
||||
adjustedW = el.position.w + widthIncrease;
|
||||
} else {
|
||||
// Left (default): expand to the right
|
||||
adjustedW = el.position.w + widthIncrease;
|
||||
}
|
||||
}
|
||||
|
||||
const textOptions = {
|
||||
x: adjustedX,
|
||||
y: el.position.y,
|
||||
w: adjustedW,
|
||||
h: el.position.h,
|
||||
fontSize: el.style.fontSize,
|
||||
fontFace: el.style.fontFace,
|
||||
color: el.style.color,
|
||||
bold: el.style.bold,
|
||||
italic: el.style.italic,
|
||||
underline: el.style.underline,
|
||||
valign: 'top',
|
||||
lineSpacing: el.style.lineSpacing,
|
||||
paraSpaceBefore: el.style.paraSpaceBefore,
|
||||
paraSpaceAfter: el.style.paraSpaceAfter,
|
||||
inset: 0 // Remove default PowerPoint internal padding
|
||||
};
|
||||
|
||||
if (el.style.align) textOptions.align = el.style.align;
|
||||
if (el.style.margin) textOptions.margin = el.style.margin;
|
||||
if (el.style.rotate !== undefined) textOptions.rotate = el.style.rotate;
|
||||
if (el.style.transparency !== null && el.style.transparency !== undefined) textOptions.transparency = el.style.transparency;
|
||||
|
||||
targetSlide.addText(el.text, textOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: Extract slide data from HTML page
|
||||
async function extractSlideData(page) {
|
||||
return await page.evaluate(() => {
|
||||
const PT_PER_PX = 0.75;
|
||||
const PX_PER_IN = 96;
|
||||
|
||||
// Fonts that are single-weight and should not have bold applied
|
||||
// (applying bold causes PowerPoint to use faux bold which makes text wider)
|
||||
const SINGLE_WEIGHT_FONTS = ['impact'];
|
||||
|
||||
// Helper: Check if a font should skip bold formatting
|
||||
const shouldSkipBold = (fontFamily) => {
|
||||
if (!fontFamily) return false;
|
||||
const normalizedFont = fontFamily.toLowerCase().replace(/['"]/g, '').split(',')[0].trim();
|
||||
return SINGLE_WEIGHT_FONTS.includes(normalizedFont);
|
||||
};
|
||||
|
||||
// Unit conversion helpers
|
||||
const pxToInch = (px) => px / PX_PER_IN;
|
||||
const pxToPoints = (pxStr) => parseFloat(pxStr) * PT_PER_PX;
|
||||
const rgbToHex = (rgbStr) => {
|
||||
// Handle transparent backgrounds by defaulting to white
|
||||
if (rgbStr === 'rgba(0, 0, 0, 0)' || rgbStr === 'transparent') return 'FFFFFF';
|
||||
|
||||
const match = rgbStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
||||
if (!match) return 'FFFFFF';
|
||||
return match.slice(1).map(n => parseInt(n).toString(16).padStart(2, '0')).join('');
|
||||
};
|
||||
|
||||
const extractAlpha = (rgbStr) => {
|
||||
const match = rgbStr.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/);
|
||||
if (!match || !match[4]) return null;
|
||||
const alpha = parseFloat(match[4]);
|
||||
return Math.round((1 - alpha) * 100);
|
||||
};
|
||||
|
||||
const applyTextTransform = (text, textTransform) => {
|
||||
if (textTransform === 'uppercase') return text.toUpperCase();
|
||||
if (textTransform === 'lowercase') return text.toLowerCase();
|
||||
if (textTransform === 'capitalize') {
|
||||
return text.replace(/\b\w/g, c => c.toUpperCase());
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
// Extract rotation angle from CSS transform and writing-mode
|
||||
const getRotation = (transform, writingMode) => {
|
||||
let angle = 0;
|
||||
|
||||
// Handle writing-mode first
|
||||
// PowerPoint: 90° = text rotated 90° clockwise (reads top to bottom, letters upright)
|
||||
// PowerPoint: 270° = text rotated 270° clockwise (reads bottom to top, letters upright)
|
||||
if (writingMode === 'vertical-rl') {
|
||||
// vertical-rl alone = text reads top to bottom = 90° in PowerPoint
|
||||
angle = 90;
|
||||
} else if (writingMode === 'vertical-lr') {
|
||||
// vertical-lr alone = text reads bottom to top = 270° in PowerPoint
|
||||
angle = 270;
|
||||
}
|
||||
|
||||
// Then add any transform rotation
|
||||
if (transform && transform !== 'none') {
|
||||
// Try to match rotate() function
|
||||
const rotateMatch = transform.match(/rotate\((-?\d+(?:\.\d+)?)deg\)/);
|
||||
if (rotateMatch) {
|
||||
angle += parseFloat(rotateMatch[1]);
|
||||
} else {
|
||||
// Browser may compute as matrix - extract rotation from matrix
|
||||
const matrixMatch = transform.match(/matrix\(([^)]+)\)/);
|
||||
if (matrixMatch) {
|
||||
const values = matrixMatch[1].split(',').map(parseFloat);
|
||||
// matrix(a, b, c, d, e, f) where rotation = atan2(b, a)
|
||||
const matrixAngle = Math.atan2(values[1], values[0]) * (180 / Math.PI);
|
||||
angle += Math.round(matrixAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize to 0-359 range
|
||||
angle = angle % 360;
|
||||
if (angle < 0) angle += 360;
|
||||
|
||||
return angle === 0 ? null : angle;
|
||||
};
|
||||
|
||||
// Get position/dimensions accounting for rotation
|
||||
const getPositionAndSize = (el, rect, rotation) => {
|
||||
if (rotation === null) {
|
||||
return { x: rect.left, y: rect.top, w: rect.width, h: rect.height };
|
||||
}
|
||||
|
||||
// For 90° or 270° rotations, swap width and height
|
||||
// because PowerPoint applies rotation to the original (unrotated) box
|
||||
const isVertical = rotation === 90 || rotation === 270;
|
||||
|
||||
if (isVertical) {
|
||||
// The browser shows us the rotated dimensions (tall box for vertical text)
|
||||
// But PowerPoint needs the pre-rotation dimensions (wide box that will be rotated)
|
||||
// So we swap: browser's height becomes PPT's width, browser's width becomes PPT's height
|
||||
const centerX = rect.left + rect.width / 2;
|
||||
const centerY = rect.top + rect.height / 2;
|
||||
|
||||
return {
|
||||
x: centerX - rect.height / 2,
|
||||
y: centerY - rect.width / 2,
|
||||
w: rect.height,
|
||||
h: rect.width
|
||||
};
|
||||
}
|
||||
|
||||
// For other rotations, use element's offset dimensions
|
||||
const centerX = rect.left + rect.width / 2;
|
||||
const centerY = rect.top + rect.height / 2;
|
||||
return {
|
||||
x: centerX - el.offsetWidth / 2,
|
||||
y: centerY - el.offsetHeight / 2,
|
||||
w: el.offsetWidth,
|
||||
h: el.offsetHeight
|
||||
};
|
||||
};
|
||||
|
||||
// Parse CSS box-shadow into PptxGenJS shadow properties
|
||||
const parseBoxShadow = (boxShadow) => {
|
||||
if (!boxShadow || boxShadow === 'none') return null;
|
||||
|
||||
// Browser computed style format: "rgba(0, 0, 0, 0.3) 2px 2px 8px 0px [inset]"
|
||||
// CSS format: "[inset] 2px 2px 8px 0px rgba(0, 0, 0, 0.3)"
|
||||
|
||||
const insetMatch = boxShadow.match(/inset/);
|
||||
|
||||
// IMPORTANT: PptxGenJS/PowerPoint doesn't properly support inset shadows
|
||||
// Only process outer shadows to avoid file corruption
|
||||
if (insetMatch) return null;
|
||||
|
||||
// Extract color first (rgba or rgb at start)
|
||||
const colorMatch = boxShadow.match(/rgba?\([^)]+\)/);
|
||||
|
||||
// Extract numeric values (handles both px and pt units)
|
||||
const parts = boxShadow.match(/([-\d.]+)(px|pt)/g);
|
||||
|
||||
if (!parts || parts.length < 2) return null;
|
||||
|
||||
const offsetX = parseFloat(parts[0]);
|
||||
const offsetY = parseFloat(parts[1]);
|
||||
const blur = parts.length > 2 ? parseFloat(parts[2]) : 0;
|
||||
|
||||
// Calculate angle from offsets (in degrees, 0 = right, 90 = down)
|
||||
let angle = 0;
|
||||
if (offsetX !== 0 || offsetY !== 0) {
|
||||
angle = Math.atan2(offsetY, offsetX) * (180 / Math.PI);
|
||||
if (angle < 0) angle += 360;
|
||||
}
|
||||
|
||||
// Calculate offset distance (hypotenuse)
|
||||
const offset = Math.sqrt(offsetX * offsetX + offsetY * offsetY) * PT_PER_PX;
|
||||
|
||||
// Extract opacity from rgba
|
||||
let opacity = 0.5;
|
||||
if (colorMatch) {
|
||||
const opacityMatch = colorMatch[0].match(/[\d.]+\)$/);
|
||||
if (opacityMatch) {
|
||||
opacity = parseFloat(opacityMatch[0].replace(')', ''));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'outer',
|
||||
angle: Math.round(angle),
|
||||
blur: blur * 0.75, // Convert to points
|
||||
color: colorMatch ? rgbToHex(colorMatch[0]) : '000000',
|
||||
offset: offset,
|
||||
opacity
|
||||
};
|
||||
};
|
||||
|
||||
// Parse inline formatting tags (<b>, <i>, <u>, <strong>, <em>, <span>) into text runs
|
||||
const parseInlineFormatting = (element, baseOptions = {}, runs = [], baseTextTransform = (x) => x) => {
|
||||
let prevNodeIsText = false;
|
||||
|
||||
element.childNodes.forEach((node) => {
|
||||
let textTransform = baseTextTransform;
|
||||
|
||||
const isText = node.nodeType === Node.TEXT_NODE || node.tagName === 'BR';
|
||||
if (isText) {
|
||||
const text = node.tagName === 'BR' ? '\n' : textTransform(node.textContent.replace(/\s+/g, ' '));
|
||||
const prevRun = runs[runs.length - 1];
|
||||
if (prevNodeIsText && prevRun) {
|
||||
prevRun.text += text;
|
||||
} else {
|
||||
runs.push({ text, options: { ...baseOptions } });
|
||||
}
|
||||
|
||||
} else if (node.nodeType === Node.ELEMENT_NODE && node.textContent.trim()) {
|
||||
const options = { ...baseOptions };
|
||||
const computed = window.getComputedStyle(node);
|
||||
|
||||
// Handle inline elements with computed styles
|
||||
if (node.tagName === 'SPAN' || node.tagName === 'B' || node.tagName === 'STRONG' || node.tagName === 'I' || node.tagName === 'EM' || node.tagName === 'U') {
|
||||
const isBold = computed.fontWeight === 'bold' || parseInt(computed.fontWeight) >= 600;
|
||||
if (isBold && !shouldSkipBold(computed.fontFamily)) options.bold = true;
|
||||
if (computed.fontStyle === 'italic') options.italic = true;
|
||||
if (computed.textDecoration && computed.textDecoration.includes('underline')) options.underline = true;
|
||||
if (computed.color && computed.color !== 'rgb(0, 0, 0)') {
|
||||
options.color = rgbToHex(computed.color);
|
||||
const transparency = extractAlpha(computed.color);
|
||||
if (transparency !== null) options.transparency = transparency;
|
||||
}
|
||||
if (computed.fontSize) options.fontSize = pxToPoints(computed.fontSize);
|
||||
|
||||
// Apply text-transform on the span element itself
|
||||
if (computed.textTransform && computed.textTransform !== 'none') {
|
||||
const transformStr = computed.textTransform;
|
||||
textTransform = (text) => applyTextTransform(text, transformStr);
|
||||
}
|
||||
|
||||
// Validate: Check for margins on inline elements
|
||||
if (computed.marginLeft && parseFloat(computed.marginLeft) > 0) {
|
||||
errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-left which is not supported in PowerPoint. Remove margin from inline elements.`);
|
||||
}
|
||||
if (computed.marginRight && parseFloat(computed.marginRight) > 0) {
|
||||
errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-right which is not supported in PowerPoint. Remove margin from inline elements.`);
|
||||
}
|
||||
if (computed.marginTop && parseFloat(computed.marginTop) > 0) {
|
||||
errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-top which is not supported in PowerPoint. Remove margin from inline elements.`);
|
||||
}
|
||||
if (computed.marginBottom && parseFloat(computed.marginBottom) > 0) {
|
||||
errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-bottom which is not supported in PowerPoint. Remove margin from inline elements.`);
|
||||
}
|
||||
|
||||
// Recursively process the child node. This will flatten nested spans into multiple runs.
|
||||
parseInlineFormatting(node, options, runs, textTransform);
|
||||
}
|
||||
}
|
||||
|
||||
prevNodeIsText = isText;
|
||||
});
|
||||
|
||||
// Trim leading space from first run and trailing space from last run
|
||||
if (runs.length > 0) {
|
||||
runs[0].text = runs[0].text.replace(/^\s+/, '');
|
||||
runs[runs.length - 1].text = runs[runs.length - 1].text.replace(/\s+$/, '');
|
||||
}
|
||||
|
||||
return runs.filter(r => r.text.length > 0);
|
||||
};
|
||||
|
||||
// Extract background from body (image or color)
|
||||
const body = document.body;
|
||||
const bodyStyle = window.getComputedStyle(body);
|
||||
const bgImage = bodyStyle.backgroundImage;
|
||||
const bgColor = bodyStyle.backgroundColor;
|
||||
|
||||
// Collect validation errors
|
||||
const errors = [];
|
||||
|
||||
// Validate: Check for CSS gradients
|
||||
if (bgImage && (bgImage.includes('linear-gradient') || bgImage.includes('radial-gradient'))) {
|
||||
errors.push(
|
||||
'CSS gradients are not supported. Use Sharp to rasterize gradients as PNG images first, ' +
|
||||
'then reference with background-image: url(\'gradient.png\')'
|
||||
);
|
||||
}
|
||||
|
||||
let background;
|
||||
if (bgImage && bgImage !== 'none') {
|
||||
// Extract URL from url("...") or url(...)
|
||||
const urlMatch = bgImage.match(/url\(["']?([^"')]+)["']?\)/);
|
||||
if (urlMatch) {
|
||||
background = {
|
||||
type: 'image',
|
||||
path: urlMatch[1]
|
||||
};
|
||||
} else {
|
||||
background = {
|
||||
type: 'color',
|
||||
value: rgbToHex(bgColor)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
background = {
|
||||
type: 'color',
|
||||
value: rgbToHex(bgColor)
|
||||
};
|
||||
}
|
||||
|
||||
// Process all elements
|
||||
const elements = [];
|
||||
const placeholders = [];
|
||||
const textTags = ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'UL', 'OL', 'LI'];
|
||||
const processed = new Set();
|
||||
|
||||
document.querySelectorAll('*').forEach((el) => {
|
||||
if (processed.has(el)) return;
|
||||
|
||||
// Validate text elements don't have backgrounds, borders, or shadows
|
||||
if (textTags.includes(el.tagName)) {
|
||||
const computed = window.getComputedStyle(el);
|
||||
const hasBg = computed.backgroundColor && computed.backgroundColor !== 'rgba(0, 0, 0, 0)';
|
||||
const hasBorder = (computed.borderWidth && parseFloat(computed.borderWidth) > 0) ||
|
||||
(computed.borderTopWidth && parseFloat(computed.borderTopWidth) > 0) ||
|
||||
(computed.borderRightWidth && parseFloat(computed.borderRightWidth) > 0) ||
|
||||
(computed.borderBottomWidth && parseFloat(computed.borderBottomWidth) > 0) ||
|
||||
(computed.borderLeftWidth && parseFloat(computed.borderLeftWidth) > 0);
|
||||
const hasShadow = computed.boxShadow && computed.boxShadow !== 'none';
|
||||
|
||||
if (hasBg || hasBorder || hasShadow) {
|
||||
errors.push(
|
||||
`Text element <${el.tagName.toLowerCase()}> has ${hasBg ? 'background' : hasBorder ? 'border' : 'shadow'}. ` +
|
||||
'Backgrounds, borders, and shadows are only supported on <div> elements, not text elements.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract placeholder elements (for charts, etc.)
|
||||
if (el.className && el.className.includes('placeholder')) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
if (rect.width === 0 || rect.height === 0) {
|
||||
errors.push(
|
||||
`Placeholder "${el.id || 'unnamed'}" has ${rect.width === 0 ? 'width: 0' : 'height: 0'}. Check the layout CSS.`
|
||||
);
|
||||
} else {
|
||||
placeholders.push({
|
||||
id: el.id || `placeholder-${placeholders.length}`,
|
||||
x: pxToInch(rect.left),
|
||||
y: pxToInch(rect.top),
|
||||
w: pxToInch(rect.width),
|
||||
h: pxToInch(rect.height)
|
||||
});
|
||||
}
|
||||
processed.add(el);
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract images
|
||||
if (el.tagName === 'IMG') {
|
||||
const rect = el.getBoundingClientRect();
|
||||
if (rect.width > 0 && rect.height > 0) {
|
||||
elements.push({
|
||||
type: 'image',
|
||||
src: el.src,
|
||||
position: {
|
||||
x: pxToInch(rect.left),
|
||||
y: pxToInch(rect.top),
|
||||
w: pxToInch(rect.width),
|
||||
h: pxToInch(rect.height)
|
||||
}
|
||||
});
|
||||
processed.add(el);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract DIVs with backgrounds/borders as shapes
|
||||
const isContainer = el.tagName === 'DIV' && !textTags.includes(el.tagName);
|
||||
if (isContainer) {
|
||||
const computed = window.getComputedStyle(el);
|
||||
const hasBg = computed.backgroundColor && computed.backgroundColor !== 'rgba(0, 0, 0, 0)';
|
||||
|
||||
// Validate: Check for unwrapped text content in DIV
|
||||
for (const node of el.childNodes) {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
const text = node.textContent.trim();
|
||||
if (text) {
|
||||
errors.push(
|
||||
`DIV element contains unwrapped text "${text.substring(0, 50)}${text.length > 50 ? '...' : ''}". ` +
|
||||
'All text must be wrapped in <p>, <h1>-<h6>, <ul>, or <ol> tags to appear in PowerPoint.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for background images on shapes
|
||||
const bgImage = computed.backgroundImage;
|
||||
if (bgImage && bgImage !== 'none') {
|
||||
errors.push(
|
||||
'Background images on DIV elements are not supported. ' +
|
||||
'Use solid colors or borders for shapes, or use slide.addImage() in PptxGenJS to layer images.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for borders - both uniform and partial
|
||||
const borderTop = computed.borderTopWidth;
|
||||
const borderRight = computed.borderRightWidth;
|
||||
const borderBottom = computed.borderBottomWidth;
|
||||
const borderLeft = computed.borderLeftWidth;
|
||||
const borders = [borderTop, borderRight, borderBottom, borderLeft].map(b => parseFloat(b) || 0);
|
||||
const hasBorder = borders.some(b => b > 0);
|
||||
const hasUniformBorder = hasBorder && borders.every(b => b === borders[0]);
|
||||
const borderLines = [];
|
||||
|
||||
if (hasBorder && !hasUniformBorder) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
const x = pxToInch(rect.left);
|
||||
const y = pxToInch(rect.top);
|
||||
const w = pxToInch(rect.width);
|
||||
const h = pxToInch(rect.height);
|
||||
|
||||
// Collect lines to add after shape (inset by half the line width to center on edge)
|
||||
if (parseFloat(borderTop) > 0) {
|
||||
const widthPt = pxToPoints(borderTop);
|
||||
const inset = (widthPt / 72) / 2; // Convert points to inches, then half
|
||||
borderLines.push({
|
||||
type: 'line',
|
||||
x1: x, y1: y + inset, x2: x + w, y2: y + inset,
|
||||
width: widthPt,
|
||||
color: rgbToHex(computed.borderTopColor)
|
||||
});
|
||||
}
|
||||
if (parseFloat(borderRight) > 0) {
|
||||
const widthPt = pxToPoints(borderRight);
|
||||
const inset = (widthPt / 72) / 2;
|
||||
borderLines.push({
|
||||
type: 'line',
|
||||
x1: x + w - inset, y1: y, x2: x + w - inset, y2: y + h,
|
||||
width: widthPt,
|
||||
color: rgbToHex(computed.borderRightColor)
|
||||
});
|
||||
}
|
||||
if (parseFloat(borderBottom) > 0) {
|
||||
const widthPt = pxToPoints(borderBottom);
|
||||
const inset = (widthPt / 72) / 2;
|
||||
borderLines.push({
|
||||
type: 'line',
|
||||
x1: x, y1: y + h - inset, x2: x + w, y2: y + h - inset,
|
||||
width: widthPt,
|
||||
color: rgbToHex(computed.borderBottomColor)
|
||||
});
|
||||
}
|
||||
if (parseFloat(borderLeft) > 0) {
|
||||
const widthPt = pxToPoints(borderLeft);
|
||||
const inset = (widthPt / 72) / 2;
|
||||
borderLines.push({
|
||||
type: 'line',
|
||||
x1: x + inset, y1: y, x2: x + inset, y2: y + h,
|
||||
width: widthPt,
|
||||
color: rgbToHex(computed.borderLeftColor)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBg || hasBorder) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
if (rect.width > 0 && rect.height > 0) {
|
||||
const shadow = parseBoxShadow(computed.boxShadow);
|
||||
|
||||
// Only add shape if there's background or uniform border
|
||||
if (hasBg || hasUniformBorder) {
|
||||
elements.push({
|
||||
type: 'shape',
|
||||
text: '', // Shape only - child text elements render on top
|
||||
position: {
|
||||
x: pxToInch(rect.left),
|
||||
y: pxToInch(rect.top),
|
||||
w: pxToInch(rect.width),
|
||||
h: pxToInch(rect.height)
|
||||
},
|
||||
shape: {
|
||||
fill: hasBg ? rgbToHex(computed.backgroundColor) : null,
|
||||
transparency: hasBg ? extractAlpha(computed.backgroundColor) : null,
|
||||
line: hasUniformBorder ? {
|
||||
color: rgbToHex(computed.borderColor),
|
||||
width: pxToPoints(computed.borderWidth)
|
||||
} : null,
|
||||
// Convert border-radius to rectRadius (in inches)
|
||||
// % values: 50%+ = circle (1), <50% = percentage of min dimension
|
||||
// pt values: divide by 72 (72pt = 1 inch)
|
||||
// px values: divide by 96 (96px = 1 inch)
|
||||
rectRadius: (() => {
|
||||
const radius = computed.borderRadius;
|
||||
const radiusValue = parseFloat(radius);
|
||||
if (radiusValue === 0) return 0;
|
||||
|
||||
if (radius.includes('%')) {
|
||||
if (radiusValue >= 50) return 1;
|
||||
// Calculate percentage of smaller dimension
|
||||
const minDim = Math.min(rect.width, rect.height);
|
||||
return (radiusValue / 100) * pxToInch(minDim);
|
||||
}
|
||||
|
||||
if (radius.includes('pt')) return radiusValue / 72;
|
||||
return radiusValue / PX_PER_IN;
|
||||
})(),
|
||||
shadow: shadow
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add partial border lines
|
||||
elements.push(...borderLines);
|
||||
|
||||
processed.add(el);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract bullet lists as single text block
|
||||
if (el.tagName === 'UL' || el.tagName === 'OL') {
|
||||
const rect = el.getBoundingClientRect();
|
||||
if (rect.width === 0 || rect.height === 0) return;
|
||||
|
||||
const liElements = Array.from(el.querySelectorAll('li'));
|
||||
const items = [];
|
||||
const ulComputed = window.getComputedStyle(el);
|
||||
const ulPaddingLeftPt = pxToPoints(ulComputed.paddingLeft);
|
||||
|
||||
// Split: margin-left for bullet position, indent for text position
|
||||
// margin-left + indent = ul padding-left
|
||||
const marginLeft = ulPaddingLeftPt * 0.5;
|
||||
const textIndent = ulPaddingLeftPt * 0.5;
|
||||
|
||||
liElements.forEach((li, idx) => {
|
||||
const isLast = idx === liElements.length - 1;
|
||||
const runs = parseInlineFormatting(li, { breakLine: false });
|
||||
// Clean manual bullets from first run
|
||||
if (runs.length > 0) {
|
||||
runs[0].text = runs[0].text.replace(/^[•\-\*▪▸]\s*/, '');
|
||||
runs[0].options.bullet = { indent: textIndent };
|
||||
}
|
||||
// Set breakLine on last run
|
||||
if (runs.length > 0 && !isLast) {
|
||||
runs[runs.length - 1].options.breakLine = true;
|
||||
}
|
||||
items.push(...runs);
|
||||
});
|
||||
|
||||
const computed = window.getComputedStyle(liElements[0] || el);
|
||||
|
||||
elements.push({
|
||||
type: 'list',
|
||||
items: items,
|
||||
position: {
|
||||
x: pxToInch(rect.left),
|
||||
y: pxToInch(rect.top),
|
||||
w: pxToInch(rect.width),
|
||||
h: pxToInch(rect.height)
|
||||
},
|
||||
style: {
|
||||
fontSize: pxToPoints(computed.fontSize),
|
||||
fontFace: computed.fontFamily.split(',')[0].replace(/['"]/g, '').trim(),
|
||||
color: rgbToHex(computed.color),
|
||||
transparency: extractAlpha(computed.color),
|
||||
align: computed.textAlign === 'start' ? 'left' : computed.textAlign,
|
||||
lineSpacing: computed.lineHeight && computed.lineHeight !== 'normal' ? pxToPoints(computed.lineHeight) : null,
|
||||
paraSpaceBefore: 0,
|
||||
paraSpaceAfter: pxToPoints(computed.marginBottom),
|
||||
// PptxGenJS margin array is [left, right, bottom, top]
|
||||
margin: [marginLeft, 0, 0, 0]
|
||||
}
|
||||
});
|
||||
|
||||
liElements.forEach(li => processed.add(li));
|
||||
processed.add(el);
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract text elements (P, H1, H2, etc.)
|
||||
if (!textTags.includes(el.tagName)) return;
|
||||
|
||||
const rect = el.getBoundingClientRect();
|
||||
const text = el.textContent.trim();
|
||||
if (rect.width === 0 || rect.height === 0 || !text) return;
|
||||
|
||||
// Validate: Check for manual bullet symbols in text elements (not in lists)
|
||||
if (el.tagName !== 'LI' && /^[•\-\*▪▸○●◆◇■□]\s/.test(text.trimStart())) {
|
||||
errors.push(
|
||||
`Text element <${el.tagName.toLowerCase()}> starts with bullet symbol "${text.substring(0, 20)}...". ` +
|
||||
'Use <ul> or <ol> lists instead of manual bullet symbols.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const computed = window.getComputedStyle(el);
|
||||
const rotation = getRotation(computed.transform, computed.writingMode);
|
||||
const { x, y, w, h } = getPositionAndSize(el, rect, rotation);
|
||||
|
||||
const baseStyle = {
|
||||
fontSize: pxToPoints(computed.fontSize),
|
||||
fontFace: computed.fontFamily.split(',')[0].replace(/['"]/g, '').trim(),
|
||||
color: rgbToHex(computed.color),
|
||||
align: computed.textAlign === 'start' ? 'left' : computed.textAlign,
|
||||
lineSpacing: pxToPoints(computed.lineHeight),
|
||||
paraSpaceBefore: pxToPoints(computed.marginTop),
|
||||
paraSpaceAfter: pxToPoints(computed.marginBottom),
|
||||
// PptxGenJS margin array is [left, right, bottom, top] (not [top, right, bottom, left] as documented)
|
||||
margin: [
|
||||
pxToPoints(computed.paddingLeft),
|
||||
pxToPoints(computed.paddingRight),
|
||||
pxToPoints(computed.paddingBottom),
|
||||
pxToPoints(computed.paddingTop)
|
||||
]
|
||||
};
|
||||
|
||||
const transparency = extractAlpha(computed.color);
|
||||
if (transparency !== null) baseStyle.transparency = transparency;
|
||||
|
||||
if (rotation !== null) baseStyle.rotate = rotation;
|
||||
|
||||
const hasFormatting = el.querySelector('b, i, u, strong, em, span, br');
|
||||
|
||||
if (hasFormatting) {
|
||||
// Text with inline formatting
|
||||
const transformStr = computed.textTransform;
|
||||
const runs = parseInlineFormatting(el, {}, [], (str) => applyTextTransform(str, transformStr));
|
||||
|
||||
// Adjust lineSpacing based on largest fontSize in runs
|
||||
const adjustedStyle = { ...baseStyle };
|
||||
if (adjustedStyle.lineSpacing) {
|
||||
const maxFontSize = Math.max(
|
||||
adjustedStyle.fontSize,
|
||||
...runs.map(r => r.options?.fontSize || 0)
|
||||
);
|
||||
if (maxFontSize > adjustedStyle.fontSize) {
|
||||
const lineHeightMultiplier = adjustedStyle.lineSpacing / adjustedStyle.fontSize;
|
||||
adjustedStyle.lineSpacing = maxFontSize * lineHeightMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
elements.push({
|
||||
type: el.tagName.toLowerCase(),
|
||||
text: runs,
|
||||
position: { x: pxToInch(x), y: pxToInch(y), w: pxToInch(w), h: pxToInch(h) },
|
||||
style: adjustedStyle
|
||||
});
|
||||
} else {
|
||||
// Plain text - inherit CSS formatting
|
||||
const textTransform = computed.textTransform;
|
||||
const transformedText = applyTextTransform(text, textTransform);
|
||||
|
||||
const isBold = computed.fontWeight === 'bold' || parseInt(computed.fontWeight) >= 600;
|
||||
|
||||
elements.push({
|
||||
type: el.tagName.toLowerCase(),
|
||||
text: transformedText,
|
||||
position: { x: pxToInch(x), y: pxToInch(y), w: pxToInch(w), h: pxToInch(h) },
|
||||
style: {
|
||||
...baseStyle,
|
||||
bold: isBold && !shouldSkipBold(computed.fontFamily),
|
||||
italic: computed.fontStyle === 'italic',
|
||||
underline: computed.textDecoration.includes('underline')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processed.add(el);
|
||||
});
|
||||
|
||||
return { background, elements, placeholders, errors };
|
||||
});
|
||||
}
|
||||
|
||||
async function html2pptx(htmlFile, pres, options = {}) {
|
||||
const {
|
||||
tmpDir = process.env.TMPDIR || '/tmp',
|
||||
slide = null
|
||||
} = options;
|
||||
|
||||
try {
|
||||
// Use Chrome on macOS, default Chromium on Unix
|
||||
const launchOptions = { env: { TMPDIR: tmpDir } };
|
||||
if (process.platform === 'darwin') {
|
||||
launchOptions.channel = 'chrome';
|
||||
}
|
||||
|
||||
const browser = await chromium.launch(launchOptions);
|
||||
|
||||
let bodyDimensions;
|
||||
let slideData;
|
||||
|
||||
const filePath = path.isAbsolute(htmlFile) ? htmlFile : path.join(process.cwd(), htmlFile);
|
||||
const validationErrors = [];
|
||||
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
page.on('console', (msg) => {
|
||||
// Log the message text to your test runner's console
|
||||
console.log(`Browser console: ${msg.text()}`);
|
||||
});
|
||||
|
||||
await page.goto(`file://${filePath}`);
|
||||
|
||||
bodyDimensions = await getBodyDimensions(page);
|
||||
|
||||
await page.setViewportSize({
|
||||
width: Math.round(bodyDimensions.width),
|
||||
height: Math.round(bodyDimensions.height)
|
||||
});
|
||||
|
||||
slideData = await extractSlideData(page);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
|
||||
// Collect all validation errors
|
||||
if (bodyDimensions.errors && bodyDimensions.errors.length > 0) {
|
||||
validationErrors.push(...bodyDimensions.errors);
|
||||
}
|
||||
|
||||
const dimensionErrors = validateDimensions(bodyDimensions, pres);
|
||||
if (dimensionErrors.length > 0) {
|
||||
validationErrors.push(...dimensionErrors);
|
||||
}
|
||||
|
||||
const textBoxPositionErrors = validateTextBoxPosition(slideData, bodyDimensions);
|
||||
if (textBoxPositionErrors.length > 0) {
|
||||
validationErrors.push(...textBoxPositionErrors);
|
||||
}
|
||||
|
||||
if (slideData.errors && slideData.errors.length > 0) {
|
||||
validationErrors.push(...slideData.errors);
|
||||
}
|
||||
|
||||
// Throw all errors at once if any exist
|
||||
if (validationErrors.length > 0) {
|
||||
const errorMessage = validationErrors.length === 1
|
||||
? validationErrors[0]
|
||||
: `Multiple validation errors found:\n${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join('\n')}`;
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const targetSlide = slide || pres.addSlide();
|
||||
|
||||
await addBackground(slideData, targetSlide, tmpDir);
|
||||
addElements(slideData, targetSlide, pres);
|
||||
|
||||
return { slide: targetSlide, placeholders: slideData.placeholders };
|
||||
} catch (error) {
|
||||
if (!error.message.startsWith(htmlFile)) {
|
||||
throw new Error(`${htmlFile}: ${error.message}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = html2pptx;
|
||||
1020
.claude/skills/pptx/scripts/inventory.py
Normal file
1020
.claude/skills/pptx/scripts/inventory.py
Normal file
File diff suppressed because it is too large
Load Diff
18
.claude/skills/pptx/scripts/package.json
Normal file
18
.claude/skills/pptx/scripts/package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "scripts",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "html2pptx.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"playwright": "^1.56.1",
|
||||
"pptxgenjs": "^4.0.1",
|
||||
"sharp": "^0.34.4"
|
||||
}
|
||||
}
|
||||
231
.claude/skills/pptx/scripts/rearrange.py
Normal file
231
.claude/skills/pptx/scripts/rearrange.py
Normal file
@ -0,0 +1,231 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Rearrange PowerPoint slides based on a sequence of indices.
|
||||
|
||||
Usage:
|
||||
python rearrange.py template.pptx output.pptx 0,34,34,50,52
|
||||
|
||||
This will create output.pptx using slides from template.pptx in the specified order.
|
||||
Slides can be repeated (e.g., 34 appears twice).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
import sys
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
|
||||
import six
|
||||
from pptx import Presentation
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Rearrange PowerPoint slides based on a sequence of indices.",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
python rearrange.py template.pptx output.pptx 0,34,34,50,52
|
||||
Creates output.pptx using slides 0, 34 (twice), 50, and 52 from template.pptx
|
||||
|
||||
python rearrange.py template.pptx output.pptx 5,3,1,2,4
|
||||
Creates output.pptx with slides reordered as specified
|
||||
|
||||
Note: Slide indices are 0-based (first slide is 0, second is 1, etc.)
|
||||
""",
|
||||
)
|
||||
|
||||
parser.add_argument("template", help="Path to template PPTX file")
|
||||
parser.add_argument("output", help="Path for output PPTX file")
|
||||
parser.add_argument(
|
||||
"sequence", help="Comma-separated sequence of slide indices (0-based)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Parse the slide sequence
|
||||
try:
|
||||
slide_sequence = [int(x.strip()) for x in args.sequence.split(",")]
|
||||
except ValueError:
|
||||
print(
|
||||
"Error: Invalid sequence format. Use comma-separated integers (e.g., 0,34,34,50,52)"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
# Check template exists
|
||||
template_path = Path(args.template)
|
||||
if not template_path.exists():
|
||||
print(f"Error: Template file not found: {args.template}")
|
||||
sys.exit(1)
|
||||
|
||||
# Create output directory if needed
|
||||
output_path = Path(args.output)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
try:
|
||||
rearrange_presentation(template_path, output_path, slide_sequence)
|
||||
except ValueError as e:
|
||||
print(f"Error: {e}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error processing presentation: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def duplicate_slide(pres, index):
|
||||
"""Duplicate a slide in the presentation."""
|
||||
source = pres.slides[index]
|
||||
|
||||
# Use source's layout to preserve formatting
|
||||
new_slide = pres.slides.add_slide(source.slide_layout)
|
||||
|
||||
# Collect all image and media relationships from the source slide
|
||||
image_rels = {}
|
||||
for rel_id, rel in six.iteritems(source.part.rels):
|
||||
if "image" in rel.reltype or "media" in rel.reltype:
|
||||
image_rels[rel_id] = rel
|
||||
|
||||
# CRITICAL: Clear placeholder shapes to avoid duplicates
|
||||
for shape in new_slide.shapes:
|
||||
sp = shape.element
|
||||
sp.getparent().remove(sp)
|
||||
|
||||
# Copy all shapes from source
|
||||
for shape in source.shapes:
|
||||
el = shape.element
|
||||
new_el = deepcopy(el)
|
||||
new_slide.shapes._spTree.insert_element_before(new_el, "p:extLst")
|
||||
|
||||
# Handle picture shapes - need to update the blip reference
|
||||
# Look for all blip elements (they can be in pic or other contexts)
|
||||
# Using the element's own xpath method without namespaces argument
|
||||
blips = new_el.xpath(".//a:blip[@r:embed]")
|
||||
for blip in blips:
|
||||
old_rId = blip.get(
|
||||
"{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed"
|
||||
)
|
||||
if old_rId in image_rels:
|
||||
# Create a new relationship in the destination slide for this image
|
||||
old_rel = image_rels[old_rId]
|
||||
# get_or_add returns the rId directly, or adds and returns new rId
|
||||
new_rId = new_slide.part.rels.get_or_add(
|
||||
old_rel.reltype, old_rel._target
|
||||
)
|
||||
# Update the blip's embed reference to use the new relationship ID
|
||||
blip.set(
|
||||
"{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed",
|
||||
new_rId,
|
||||
)
|
||||
|
||||
# Copy any additional image/media relationships that might be referenced elsewhere
|
||||
for rel_id, rel in image_rels.items():
|
||||
try:
|
||||
new_slide.part.rels.get_or_add(rel.reltype, rel._target)
|
||||
except Exception:
|
||||
pass # Relationship might already exist
|
||||
|
||||
return new_slide
|
||||
|
||||
|
||||
def delete_slide(pres, index):
|
||||
"""Delete a slide from the presentation."""
|
||||
rId = pres.slides._sldIdLst[index].rId
|
||||
pres.part.drop_rel(rId)
|
||||
del pres.slides._sldIdLst[index]
|
||||
|
||||
|
||||
def reorder_slides(pres, slide_index, target_index):
|
||||
"""Move a slide from one position to another."""
|
||||
slides = pres.slides._sldIdLst
|
||||
|
||||
# Remove slide element from current position
|
||||
slide_element = slides[slide_index]
|
||||
slides.remove(slide_element)
|
||||
|
||||
# Insert at target position
|
||||
slides.insert(target_index, slide_element)
|
||||
|
||||
|
||||
def rearrange_presentation(template_path, output_path, slide_sequence):
|
||||
"""
|
||||
Create a new presentation with slides from template in specified order.
|
||||
|
||||
Args:
|
||||
template_path: Path to template PPTX file
|
||||
output_path: Path for output PPTX file
|
||||
slide_sequence: List of slide indices (0-based) to include
|
||||
"""
|
||||
# Copy template to preserve dimensions and theme
|
||||
if template_path != output_path:
|
||||
shutil.copy2(template_path, output_path)
|
||||
prs = Presentation(output_path)
|
||||
else:
|
||||
prs = Presentation(template_path)
|
||||
|
||||
total_slides = len(prs.slides)
|
||||
|
||||
# Validate indices
|
||||
for idx in slide_sequence:
|
||||
if idx < 0 or idx >= total_slides:
|
||||
raise ValueError(f"Slide index {idx} out of range (0-{total_slides - 1})")
|
||||
|
||||
# Track original slides and their duplicates
|
||||
slide_map = [] # List of actual slide indices for final presentation
|
||||
duplicated = {} # Track duplicates: original_idx -> [duplicate_indices]
|
||||
|
||||
# Step 1: DUPLICATE repeated slides
|
||||
print(f"Processing {len(slide_sequence)} slides from template...")
|
||||
for i, template_idx in enumerate(slide_sequence):
|
||||
if template_idx in duplicated and duplicated[template_idx]:
|
||||
# Already duplicated this slide, use the duplicate
|
||||
slide_map.append(duplicated[template_idx].pop(0))
|
||||
print(f" [{i}] Using duplicate of slide {template_idx}")
|
||||
elif slide_sequence.count(template_idx) > 1 and template_idx not in duplicated:
|
||||
# First occurrence of a repeated slide - create duplicates
|
||||
slide_map.append(template_idx)
|
||||
duplicates = []
|
||||
count = slide_sequence.count(template_idx) - 1
|
||||
print(
|
||||
f" [{i}] Using original slide {template_idx}, creating {count} duplicate(s)"
|
||||
)
|
||||
for _ in range(count):
|
||||
duplicate_slide(prs, template_idx)
|
||||
duplicates.append(len(prs.slides) - 1)
|
||||
duplicated[template_idx] = duplicates
|
||||
else:
|
||||
# Unique slide or first occurrence already handled, use original
|
||||
slide_map.append(template_idx)
|
||||
print(f" [{i}] Using original slide {template_idx}")
|
||||
|
||||
# Step 2: DELETE unwanted slides (work backwards)
|
||||
slides_to_keep = set(slide_map)
|
||||
print(f"\nDeleting {len(prs.slides) - len(slides_to_keep)} unused slides...")
|
||||
for i in range(len(prs.slides) - 1, -1, -1):
|
||||
if i not in slides_to_keep:
|
||||
delete_slide(prs, i)
|
||||
# Update slide_map indices after deletion
|
||||
slide_map = [idx - 1 if idx > i else idx for idx in slide_map]
|
||||
|
||||
# Step 3: REORDER to final sequence
|
||||
print(f"Reordering {len(slide_map)} slides to final sequence...")
|
||||
for target_pos in range(len(slide_map)):
|
||||
# Find which slide should be at target_pos
|
||||
current_pos = slide_map[target_pos]
|
||||
if current_pos != target_pos:
|
||||
reorder_slides(prs, current_pos, target_pos)
|
||||
# Update slide_map: the move shifts other slides
|
||||
for i in range(len(slide_map)):
|
||||
if slide_map[i] > current_pos and slide_map[i] <= target_pos:
|
||||
slide_map[i] -= 1
|
||||
elif slide_map[i] < current_pos and slide_map[i] >= target_pos:
|
||||
slide_map[i] += 1
|
||||
slide_map[target_pos] = target_pos
|
||||
|
||||
# Save the presentation
|
||||
prs.save(output_path)
|
||||
print(f"\nSaved rearranged presentation to: {output_path}")
|
||||
print(f"Final presentation has {len(prs.slides)} slides")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
385
.claude/skills/pptx/scripts/replace.py
Normal file
385
.claude/skills/pptx/scripts/replace.py
Normal file
@ -0,0 +1,385 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Apply text replacements to PowerPoint presentation.
|
||||
|
||||
Usage:
|
||||
python replace.py <input.pptx> <replacements.json> <output.pptx>
|
||||
|
||||
The replacements JSON should have the structure output by inventory.py.
|
||||
ALL text shapes identified by inventory.py will have their text cleared
|
||||
unless "paragraphs" is specified in the replacements for that shape.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from inventory import InventoryData, extract_text_inventory
|
||||
from pptx import Presentation
|
||||
from pptx.dml.color import RGBColor
|
||||
from pptx.enum.dml import MSO_THEME_COLOR
|
||||
from pptx.enum.text import PP_ALIGN
|
||||
from pptx.oxml.xmlchemy import OxmlElement
|
||||
from pptx.util import Pt
|
||||
|
||||
|
||||
def clear_paragraph_bullets(paragraph):
|
||||
"""Clear bullet formatting from a paragraph."""
|
||||
pPr = paragraph._element.get_or_add_pPr()
|
||||
|
||||
# Remove existing bullet elements
|
||||
for child in list(pPr):
|
||||
if (
|
||||
child.tag.endswith("buChar")
|
||||
or child.tag.endswith("buNone")
|
||||
or child.tag.endswith("buAutoNum")
|
||||
or child.tag.endswith("buFont")
|
||||
):
|
||||
pPr.remove(child)
|
||||
|
||||
return pPr
|
||||
|
||||
|
||||
def apply_paragraph_properties(paragraph, para_data: Dict[str, Any]):
|
||||
"""Apply formatting properties to a paragraph."""
|
||||
# Get the text but don't set it on paragraph directly yet
|
||||
text = para_data.get("text", "")
|
||||
|
||||
# Get or create paragraph properties
|
||||
pPr = clear_paragraph_bullets(paragraph)
|
||||
|
||||
# Handle bullet formatting
|
||||
if para_data.get("bullet", False):
|
||||
level = para_data.get("level", 0)
|
||||
paragraph.level = level
|
||||
|
||||
# Calculate font-proportional indentation
|
||||
font_size = para_data.get("font_size", 18.0)
|
||||
level_indent_emu = int((font_size * (1.6 + level * 1.6)) * 12700)
|
||||
hanging_indent_emu = int(-font_size * 0.8 * 12700)
|
||||
|
||||
# Set indentation
|
||||
pPr.attrib["marL"] = str(level_indent_emu)
|
||||
pPr.attrib["indent"] = str(hanging_indent_emu)
|
||||
|
||||
# Add bullet character
|
||||
buChar = OxmlElement("a:buChar")
|
||||
buChar.set("char", "•")
|
||||
pPr.append(buChar)
|
||||
|
||||
# Default to left alignment for bullets if not specified
|
||||
if "alignment" not in para_data:
|
||||
paragraph.alignment = PP_ALIGN.LEFT
|
||||
else:
|
||||
# Remove indentation for non-bullet text
|
||||
pPr.attrib["marL"] = "0"
|
||||
pPr.attrib["indent"] = "0"
|
||||
|
||||
# Add buNone element
|
||||
buNone = OxmlElement("a:buNone")
|
||||
pPr.insert(0, buNone)
|
||||
|
||||
# Apply alignment
|
||||
if "alignment" in para_data:
|
||||
alignment_map = {
|
||||
"LEFT": PP_ALIGN.LEFT,
|
||||
"CENTER": PP_ALIGN.CENTER,
|
||||
"RIGHT": PP_ALIGN.RIGHT,
|
||||
"JUSTIFY": PP_ALIGN.JUSTIFY,
|
||||
}
|
||||
if para_data["alignment"] in alignment_map:
|
||||
paragraph.alignment = alignment_map[para_data["alignment"]]
|
||||
|
||||
# Apply spacing
|
||||
if "space_before" in para_data:
|
||||
paragraph.space_before = Pt(para_data["space_before"])
|
||||
if "space_after" in para_data:
|
||||
paragraph.space_after = Pt(para_data["space_after"])
|
||||
if "line_spacing" in para_data:
|
||||
paragraph.line_spacing = Pt(para_data["line_spacing"])
|
||||
|
||||
# Apply run-level formatting
|
||||
if not paragraph.runs:
|
||||
run = paragraph.add_run()
|
||||
run.text = text
|
||||
else:
|
||||
run = paragraph.runs[0]
|
||||
run.text = text
|
||||
|
||||
# Apply font properties
|
||||
apply_font_properties(run, para_data)
|
||||
|
||||
|
||||
def apply_font_properties(run, para_data: Dict[str, Any]):
|
||||
"""Apply font properties to a text run."""
|
||||
if "bold" in para_data:
|
||||
run.font.bold = para_data["bold"]
|
||||
if "italic" in para_data:
|
||||
run.font.italic = para_data["italic"]
|
||||
if "underline" in para_data:
|
||||
run.font.underline = para_data["underline"]
|
||||
if "font_size" in para_data:
|
||||
run.font.size = Pt(para_data["font_size"])
|
||||
if "font_name" in para_data:
|
||||
run.font.name = para_data["font_name"]
|
||||
|
||||
# Apply color - prefer RGB, fall back to theme_color
|
||||
if "color" in para_data:
|
||||
color_hex = para_data["color"].lstrip("#")
|
||||
if len(color_hex) == 6:
|
||||
r = int(color_hex[0:2], 16)
|
||||
g = int(color_hex[2:4], 16)
|
||||
b = int(color_hex[4:6], 16)
|
||||
run.font.color.rgb = RGBColor(r, g, b)
|
||||
elif "theme_color" in para_data:
|
||||
# Get theme color by name (e.g., "DARK_1", "ACCENT_1")
|
||||
theme_name = para_data["theme_color"]
|
||||
try:
|
||||
run.font.color.theme_color = getattr(MSO_THEME_COLOR, theme_name)
|
||||
except AttributeError:
|
||||
print(f" WARNING: Unknown theme color name '{theme_name}'")
|
||||
|
||||
|
||||
def detect_frame_overflow(inventory: InventoryData) -> Dict[str, Dict[str, float]]:
|
||||
"""Detect text overflow in shapes (text exceeding shape bounds).
|
||||
|
||||
Returns dict of slide_key -> shape_key -> overflow_inches.
|
||||
Only includes shapes that have text overflow.
|
||||
"""
|
||||
overflow_map = {}
|
||||
|
||||
for slide_key, shapes_dict in inventory.items():
|
||||
for shape_key, shape_data in shapes_dict.items():
|
||||
# Check for frame overflow (text exceeding shape bounds)
|
||||
if shape_data.frame_overflow_bottom is not None:
|
||||
if slide_key not in overflow_map:
|
||||
overflow_map[slide_key] = {}
|
||||
overflow_map[slide_key][shape_key] = shape_data.frame_overflow_bottom
|
||||
|
||||
return overflow_map
|
||||
|
||||
|
||||
def validate_replacements(inventory: InventoryData, replacements: Dict) -> List[str]:
|
||||
"""Validate that all shapes in replacements exist in inventory.
|
||||
|
||||
Returns list of error messages.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
for slide_key, shapes_data in replacements.items():
|
||||
if not slide_key.startswith("slide-"):
|
||||
continue
|
||||
|
||||
# Check if slide exists
|
||||
if slide_key not in inventory:
|
||||
errors.append(f"Slide '{slide_key}' not found in inventory")
|
||||
continue
|
||||
|
||||
# Check each shape
|
||||
for shape_key in shapes_data.keys():
|
||||
if shape_key not in inventory[slide_key]:
|
||||
# Find shapes without replacements defined and show their content
|
||||
unused_with_content = []
|
||||
for k in inventory[slide_key].keys():
|
||||
if k not in shapes_data:
|
||||
shape_data = inventory[slide_key][k]
|
||||
# Get text from paragraphs as preview
|
||||
paragraphs = shape_data.paragraphs
|
||||
if paragraphs and paragraphs[0].text:
|
||||
first_text = paragraphs[0].text[:50]
|
||||
if len(paragraphs[0].text) > 50:
|
||||
first_text += "..."
|
||||
unused_with_content.append(f"{k} ('{first_text}')")
|
||||
else:
|
||||
unused_with_content.append(k)
|
||||
|
||||
errors.append(
|
||||
f"Shape '{shape_key}' not found on '{slide_key}'. "
|
||||
f"Shapes without replacements: {', '.join(sorted(unused_with_content)) if unused_with_content else 'none'}"
|
||||
)
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def check_duplicate_keys(pairs):
|
||||
"""Check for duplicate keys when loading JSON."""
|
||||
result = {}
|
||||
for key, value in pairs:
|
||||
if key in result:
|
||||
raise ValueError(f"Duplicate key found in JSON: '{key}'")
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
|
||||
def apply_replacements(pptx_file: str, json_file: str, output_file: str):
|
||||
"""Apply text replacements from JSON to PowerPoint presentation."""
|
||||
|
||||
# Load presentation
|
||||
prs = Presentation(pptx_file)
|
||||
|
||||
# Get inventory of all text shapes (returns ShapeData objects)
|
||||
# Pass prs to use same Presentation instance
|
||||
inventory = extract_text_inventory(Path(pptx_file), prs)
|
||||
|
||||
# Detect text overflow in original presentation
|
||||
original_overflow = detect_frame_overflow(inventory)
|
||||
|
||||
# Load replacement data with duplicate key detection
|
||||
with open(json_file, "r") as f:
|
||||
replacements = json.load(f, object_pairs_hook=check_duplicate_keys)
|
||||
|
||||
# Validate replacements
|
||||
errors = validate_replacements(inventory, replacements)
|
||||
if errors:
|
||||
print("ERROR: Invalid shapes in replacement JSON:")
|
||||
for error in errors:
|
||||
print(f" - {error}")
|
||||
print("\nPlease check the inventory and update your replacement JSON.")
|
||||
print(
|
||||
"You can regenerate the inventory with: python inventory.py <input.pptx> <output.json>"
|
||||
)
|
||||
raise ValueError(f"Found {len(errors)} validation error(s)")
|
||||
|
||||
# Track statistics
|
||||
shapes_processed = 0
|
||||
shapes_cleared = 0
|
||||
shapes_replaced = 0
|
||||
|
||||
# Process each slide from inventory
|
||||
for slide_key, shapes_dict in inventory.items():
|
||||
if not slide_key.startswith("slide-"):
|
||||
continue
|
||||
|
||||
slide_index = int(slide_key.split("-")[1])
|
||||
|
||||
if slide_index >= len(prs.slides):
|
||||
print(f"Warning: Slide {slide_index} not found")
|
||||
continue
|
||||
|
||||
# Process each shape from inventory
|
||||
for shape_key, shape_data in shapes_dict.items():
|
||||
shapes_processed += 1
|
||||
|
||||
# Get the shape directly from ShapeData
|
||||
shape = shape_data.shape
|
||||
if not shape:
|
||||
print(f"Warning: {shape_key} has no shape reference")
|
||||
continue
|
||||
|
||||
# ShapeData already validates text_frame in __init__
|
||||
text_frame = shape.text_frame # type: ignore
|
||||
|
||||
text_frame.clear() # type: ignore
|
||||
shapes_cleared += 1
|
||||
|
||||
# Check for replacement paragraphs
|
||||
replacement_shape_data = replacements.get(slide_key, {}).get(shape_key, {})
|
||||
if "paragraphs" not in replacement_shape_data:
|
||||
continue
|
||||
|
||||
shapes_replaced += 1
|
||||
|
||||
# Add replacement paragraphs
|
||||
for i, para_data in enumerate(replacement_shape_data["paragraphs"]):
|
||||
if i == 0:
|
||||
p = text_frame.paragraphs[0] # type: ignore
|
||||
else:
|
||||
p = text_frame.add_paragraph() # type: ignore
|
||||
|
||||
apply_paragraph_properties(p, para_data)
|
||||
|
||||
# Check for issues after replacements
|
||||
# Save to a temporary file and reload to avoid modifying the presentation during inventory
|
||||
# (extract_text_inventory accesses font.color which adds empty <a:solidFill/> elements)
|
||||
import tempfile
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".pptx", delete=False) as tmp:
|
||||
tmp_path = Path(tmp.name)
|
||||
prs.save(str(tmp_path))
|
||||
|
||||
try:
|
||||
updated_inventory = extract_text_inventory(tmp_path)
|
||||
updated_overflow = detect_frame_overflow(updated_inventory)
|
||||
finally:
|
||||
tmp_path.unlink() # Clean up temp file
|
||||
|
||||
# Check if any text overflow got worse
|
||||
overflow_errors = []
|
||||
for slide_key, shape_overflows in updated_overflow.items():
|
||||
for shape_key, new_overflow in shape_overflows.items():
|
||||
# Get original overflow (0 if there was no overflow before)
|
||||
original = original_overflow.get(slide_key, {}).get(shape_key, 0.0)
|
||||
|
||||
# Error if overflow increased
|
||||
if new_overflow > original + 0.01: # Small tolerance for rounding
|
||||
increase = new_overflow - original
|
||||
overflow_errors.append(
|
||||
f'{slide_key}/{shape_key}: overflow worsened by {increase:.2f}" '
|
||||
f'(was {original:.2f}", now {new_overflow:.2f}")'
|
||||
)
|
||||
|
||||
# Collect warnings from updated shapes
|
||||
warnings = []
|
||||
for slide_key, shapes_dict in updated_inventory.items():
|
||||
for shape_key, shape_data in shapes_dict.items():
|
||||
if shape_data.warnings:
|
||||
for warning in shape_data.warnings:
|
||||
warnings.append(f"{slide_key}/{shape_key}: {warning}")
|
||||
|
||||
# Fail if there are any issues
|
||||
if overflow_errors or warnings:
|
||||
print("\nERROR: Issues detected in replacement output:")
|
||||
if overflow_errors:
|
||||
print("\nText overflow worsened:")
|
||||
for error in overflow_errors:
|
||||
print(f" - {error}")
|
||||
if warnings:
|
||||
print("\nFormatting warnings:")
|
||||
for warning in warnings:
|
||||
print(f" - {warning}")
|
||||
print("\nPlease fix these issues before saving.")
|
||||
raise ValueError(
|
||||
f"Found {len(overflow_errors)} overflow error(s) and {len(warnings)} warning(s)"
|
||||
)
|
||||
|
||||
# Save the presentation
|
||||
prs.save(output_file)
|
||||
|
||||
# Report results
|
||||
print(f"Saved updated presentation to: {output_file}")
|
||||
print(f"Processed {len(prs.slides)} slides")
|
||||
print(f" - Shapes processed: {shapes_processed}")
|
||||
print(f" - Shapes cleared: {shapes_cleared}")
|
||||
print(f" - Shapes replaced: {shapes_replaced}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for command-line usage."""
|
||||
if len(sys.argv) != 4:
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
|
||||
input_pptx = Path(sys.argv[1])
|
||||
replacements_json = Path(sys.argv[2])
|
||||
output_pptx = Path(sys.argv[3])
|
||||
|
||||
if not input_pptx.exists():
|
||||
print(f"Error: Input file '{input_pptx}' not found")
|
||||
sys.exit(1)
|
||||
|
||||
if not replacements_json.exists():
|
||||
print(f"Error: Replacements JSON file '{replacements_json}' not found")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
apply_replacements(str(input_pptx), str(replacements_json), str(output_pptx))
|
||||
except Exception as e:
|
||||
print(f"Error applying replacements: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
450
.claude/skills/pptx/scripts/thumbnail.py
Normal file
450
.claude/skills/pptx/scripts/thumbnail.py
Normal file
@ -0,0 +1,450 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Create thumbnail grids from PowerPoint presentation slides.
|
||||
|
||||
Creates a grid layout of slide thumbnails with configurable columns (max 6).
|
||||
Each grid contains up to cols×(cols+1) images. For presentations with more
|
||||
slides, multiple numbered grid files are created automatically.
|
||||
|
||||
The program outputs the names of all files created.
|
||||
|
||||
Output:
|
||||
- Single grid: {prefix}.jpg (if slides fit in one grid)
|
||||
- Multiple grids: {prefix}-1.jpg, {prefix}-2.jpg, etc.
|
||||
|
||||
Grid limits by column count:
|
||||
- 3 cols: max 12 slides per grid (3×4)
|
||||
- 4 cols: max 20 slides per grid (4×5)
|
||||
- 5 cols: max 30 slides per grid (5×6) [default]
|
||||
- 6 cols: max 42 slides per grid (6×7)
|
||||
|
||||
Usage:
|
||||
python thumbnail.py input.pptx [output_prefix] [--cols N] [--outline-placeholders]
|
||||
|
||||
Examples:
|
||||
python thumbnail.py presentation.pptx
|
||||
# Creates: thumbnails.jpg (using default prefix)
|
||||
# Outputs:
|
||||
# Created 1 grid(s):
|
||||
# - thumbnails.jpg
|
||||
|
||||
python thumbnail.py large-deck.pptx grid --cols 4
|
||||
# Creates: grid-1.jpg, grid-2.jpg, grid-3.jpg
|
||||
# Outputs:
|
||||
# Created 3 grid(s):
|
||||
# - grid-1.jpg
|
||||
# - grid-2.jpg
|
||||
# - grid-3.jpg
|
||||
|
||||
python thumbnail.py template.pptx analysis --outline-placeholders
|
||||
# Creates thumbnail grids with red outlines around text placeholders
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from inventory import extract_text_inventory
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from pptx import Presentation
|
||||
|
||||
# Constants
|
||||
THUMBNAIL_WIDTH = 300 # Fixed thumbnail width in pixels
|
||||
CONVERSION_DPI = 100 # DPI for PDF to image conversion
|
||||
MAX_COLS = 6 # Maximum number of columns
|
||||
DEFAULT_COLS = 5 # Default number of columns
|
||||
JPEG_QUALITY = 95 # JPEG compression quality
|
||||
|
||||
# Grid layout constants
|
||||
GRID_PADDING = 20 # Padding between thumbnails
|
||||
BORDER_WIDTH = 2 # Border width around thumbnails
|
||||
FONT_SIZE_RATIO = 0.12 # Font size as fraction of thumbnail width
|
||||
LABEL_PADDING_RATIO = 0.4 # Label padding as fraction of font size
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Create thumbnail grids from PowerPoint slides."
|
||||
)
|
||||
parser.add_argument("input", help="Input PowerPoint file (.pptx)")
|
||||
parser.add_argument(
|
||||
"output_prefix",
|
||||
nargs="?",
|
||||
default="thumbnails",
|
||||
help="Output prefix for image files (default: thumbnails, will create prefix.jpg or prefix-N.jpg)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cols",
|
||||
type=int,
|
||||
default=DEFAULT_COLS,
|
||||
help=f"Number of columns (default: {DEFAULT_COLS}, max: {MAX_COLS})",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--outline-placeholders",
|
||||
action="store_true",
|
||||
help="Outline text placeholders with a colored border",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Validate columns
|
||||
cols = min(args.cols, MAX_COLS)
|
||||
if args.cols > MAX_COLS:
|
||||
print(f"Warning: Columns limited to {MAX_COLS} (requested {args.cols})")
|
||||
|
||||
# Validate input
|
||||
input_path = Path(args.input)
|
||||
if not input_path.exists() or input_path.suffix.lower() != ".pptx":
|
||||
print(f"Error: Invalid PowerPoint file: {args.input}")
|
||||
sys.exit(1)
|
||||
|
||||
# Construct output path (always JPG)
|
||||
output_path = Path(f"{args.output_prefix}.jpg")
|
||||
|
||||
print(f"Processing: {args.input}")
|
||||
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Get placeholder regions if outlining is enabled
|
||||
placeholder_regions = None
|
||||
slide_dimensions = None
|
||||
if args.outline_placeholders:
|
||||
print("Extracting placeholder regions...")
|
||||
placeholder_regions, slide_dimensions = get_placeholder_regions(
|
||||
input_path
|
||||
)
|
||||
if placeholder_regions:
|
||||
print(f"Found placeholders on {len(placeholder_regions)} slides")
|
||||
|
||||
# Convert slides to images
|
||||
slide_images = convert_to_images(input_path, Path(temp_dir), CONVERSION_DPI)
|
||||
if not slide_images:
|
||||
print("Error: No slides found")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Found {len(slide_images)} slides")
|
||||
|
||||
# Create grids (max cols×(cols+1) images per grid)
|
||||
grid_files = create_grids(
|
||||
slide_images,
|
||||
cols,
|
||||
THUMBNAIL_WIDTH,
|
||||
output_path,
|
||||
placeholder_regions,
|
||||
slide_dimensions,
|
||||
)
|
||||
|
||||
# Print saved files
|
||||
print(f"Created {len(grid_files)} grid(s):")
|
||||
for grid_file in grid_files:
|
||||
print(f" - {grid_file}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_hidden_slide_placeholder(size):
|
||||
"""Create placeholder image for hidden slides."""
|
||||
img = Image.new("RGB", size, color="#F0F0F0")
|
||||
draw = ImageDraw.Draw(img)
|
||||
line_width = max(5, min(size) // 100)
|
||||
draw.line([(0, 0), size], fill="#CCCCCC", width=line_width)
|
||||
draw.line([(size[0], 0), (0, size[1])], fill="#CCCCCC", width=line_width)
|
||||
return img
|
||||
|
||||
|
||||
def get_placeholder_regions(pptx_path):
|
||||
"""Extract ALL text regions from the presentation.
|
||||
|
||||
Returns a tuple of (placeholder_regions, slide_dimensions).
|
||||
text_regions is a dict mapping slide indices to lists of text regions.
|
||||
Each region is a dict with 'left', 'top', 'width', 'height' in inches.
|
||||
slide_dimensions is a tuple of (width_inches, height_inches).
|
||||
"""
|
||||
prs = Presentation(str(pptx_path))
|
||||
inventory = extract_text_inventory(pptx_path, prs)
|
||||
placeholder_regions = {}
|
||||
|
||||
# Get actual slide dimensions in inches (EMU to inches conversion)
|
||||
slide_width_inches = (prs.slide_width or 9144000) / 914400.0
|
||||
slide_height_inches = (prs.slide_height or 5143500) / 914400.0
|
||||
|
||||
for slide_key, shapes in inventory.items():
|
||||
# Extract slide index from "slide-N" format
|
||||
slide_idx = int(slide_key.split("-")[1])
|
||||
regions = []
|
||||
|
||||
for shape_key, shape_data in shapes.items():
|
||||
# The inventory only contains shapes with text, so all shapes should be highlighted
|
||||
regions.append(
|
||||
{
|
||||
"left": shape_data.left,
|
||||
"top": shape_data.top,
|
||||
"width": shape_data.width,
|
||||
"height": shape_data.height,
|
||||
}
|
||||
)
|
||||
|
||||
if regions:
|
||||
placeholder_regions[slide_idx] = regions
|
||||
|
||||
return placeholder_regions, (slide_width_inches, slide_height_inches)
|
||||
|
||||
|
||||
def convert_to_images(pptx_path, temp_dir, dpi):
|
||||
"""Convert PowerPoint to images via PDF, handling hidden slides."""
|
||||
# Detect hidden slides
|
||||
print("Analyzing presentation...")
|
||||
prs = Presentation(str(pptx_path))
|
||||
total_slides = len(prs.slides)
|
||||
|
||||
# Find hidden slides (1-based indexing for display)
|
||||
hidden_slides = {
|
||||
idx + 1
|
||||
for idx, slide in enumerate(prs.slides)
|
||||
if slide.element.get("show") == "0"
|
||||
}
|
||||
|
||||
print(f"Total slides: {total_slides}")
|
||||
if hidden_slides:
|
||||
print(f"Hidden slides: {sorted(hidden_slides)}")
|
||||
|
||||
pdf_path = temp_dir / f"{pptx_path.stem}.pdf"
|
||||
|
||||
# Convert to PDF
|
||||
print("Converting to PDF...")
|
||||
result = subprocess.run(
|
||||
[
|
||||
"soffice",
|
||||
"--headless",
|
||||
"--convert-to",
|
||||
"pdf",
|
||||
"--outdir",
|
||||
str(temp_dir),
|
||||
str(pptx_path),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0 or not pdf_path.exists():
|
||||
raise RuntimeError("PDF conversion failed")
|
||||
|
||||
# Convert PDF to images
|
||||
print(f"Converting to images at {dpi} DPI...")
|
||||
result = subprocess.run(
|
||||
["pdftoppm", "-jpeg", "-r", str(dpi), str(pdf_path), str(temp_dir / "slide")],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError("Image conversion failed")
|
||||
|
||||
visible_images = sorted(temp_dir.glob("slide-*.jpg"))
|
||||
|
||||
# Create full list with placeholders for hidden slides
|
||||
all_images = []
|
||||
visible_idx = 0
|
||||
|
||||
# Get placeholder dimensions from first visible slide
|
||||
if visible_images:
|
||||
with Image.open(visible_images[0]) as img:
|
||||
placeholder_size = img.size
|
||||
else:
|
||||
placeholder_size = (1920, 1080)
|
||||
|
||||
for slide_num in range(1, total_slides + 1):
|
||||
if slide_num in hidden_slides:
|
||||
# Create placeholder image for hidden slide
|
||||
placeholder_path = temp_dir / f"hidden-{slide_num:03d}.jpg"
|
||||
placeholder_img = create_hidden_slide_placeholder(placeholder_size)
|
||||
placeholder_img.save(placeholder_path, "JPEG")
|
||||
all_images.append(placeholder_path)
|
||||
else:
|
||||
# Use the actual visible slide image
|
||||
if visible_idx < len(visible_images):
|
||||
all_images.append(visible_images[visible_idx])
|
||||
visible_idx += 1
|
||||
|
||||
return all_images
|
||||
|
||||
|
||||
def create_grids(
|
||||
image_paths,
|
||||
cols,
|
||||
width,
|
||||
output_path,
|
||||
placeholder_regions=None,
|
||||
slide_dimensions=None,
|
||||
):
|
||||
"""Create multiple thumbnail grids from slide images, max cols×(cols+1) images per grid."""
|
||||
# Maximum images per grid is cols × (cols + 1) for better proportions
|
||||
max_images_per_grid = cols * (cols + 1)
|
||||
grid_files = []
|
||||
|
||||
print(
|
||||
f"Creating grids with {cols} columns (max {max_images_per_grid} images per grid)"
|
||||
)
|
||||
|
||||
# Split images into chunks
|
||||
for chunk_idx, start_idx in enumerate(
|
||||
range(0, len(image_paths), max_images_per_grid)
|
||||
):
|
||||
end_idx = min(start_idx + max_images_per_grid, len(image_paths))
|
||||
chunk_images = image_paths[start_idx:end_idx]
|
||||
|
||||
# Create grid for this chunk
|
||||
grid = create_grid(
|
||||
chunk_images, cols, width, start_idx, placeholder_regions, slide_dimensions
|
||||
)
|
||||
|
||||
# Generate output filename
|
||||
if len(image_paths) <= max_images_per_grid:
|
||||
# Single grid - use base filename without suffix
|
||||
grid_filename = output_path
|
||||
else:
|
||||
# Multiple grids - insert index before extension with dash
|
||||
stem = output_path.stem
|
||||
suffix = output_path.suffix
|
||||
grid_filename = output_path.parent / f"{stem}-{chunk_idx + 1}{suffix}"
|
||||
|
||||
# Save grid
|
||||
grid_filename.parent.mkdir(parents=True, exist_ok=True)
|
||||
grid.save(str(grid_filename), quality=JPEG_QUALITY)
|
||||
grid_files.append(str(grid_filename))
|
||||
|
||||
return grid_files
|
||||
|
||||
|
||||
def create_grid(
|
||||
image_paths,
|
||||
cols,
|
||||
width,
|
||||
start_slide_num=0,
|
||||
placeholder_regions=None,
|
||||
slide_dimensions=None,
|
||||
):
|
||||
"""Create thumbnail grid from slide images with optional placeholder outlining."""
|
||||
font_size = int(width * FONT_SIZE_RATIO)
|
||||
label_padding = int(font_size * LABEL_PADDING_RATIO)
|
||||
|
||||
# Get dimensions
|
||||
with Image.open(image_paths[0]) as img:
|
||||
aspect = img.height / img.width
|
||||
height = int(width * aspect)
|
||||
|
||||
# Calculate grid size
|
||||
rows = (len(image_paths) + cols - 1) // cols
|
||||
grid_w = cols * width + (cols + 1) * GRID_PADDING
|
||||
grid_h = rows * (height + font_size + label_padding * 2) + (rows + 1) * GRID_PADDING
|
||||
|
||||
# Create grid
|
||||
grid = Image.new("RGB", (grid_w, grid_h), "white")
|
||||
draw = ImageDraw.Draw(grid)
|
||||
|
||||
# Load font with size based on thumbnail width
|
||||
try:
|
||||
# Use Pillow's default font with size
|
||||
font = ImageFont.load_default(size=font_size)
|
||||
except Exception:
|
||||
# Fall back to basic default font if size parameter not supported
|
||||
font = ImageFont.load_default()
|
||||
|
||||
# Place thumbnails
|
||||
for i, img_path in enumerate(image_paths):
|
||||
row, col = i // cols, i % cols
|
||||
x = col * width + (col + 1) * GRID_PADDING
|
||||
y_base = (
|
||||
row * (height + font_size + label_padding * 2) + (row + 1) * GRID_PADDING
|
||||
)
|
||||
|
||||
# Add label with actual slide number
|
||||
label = f"{start_slide_num + i}"
|
||||
bbox = draw.textbbox((0, 0), label, font=font)
|
||||
text_w = bbox[2] - bbox[0]
|
||||
draw.text(
|
||||
(x + (width - text_w) // 2, y_base + label_padding),
|
||||
label,
|
||||
fill="black",
|
||||
font=font,
|
||||
)
|
||||
|
||||
# Add thumbnail below label with proportional spacing
|
||||
y_thumbnail = y_base + label_padding + font_size + label_padding
|
||||
|
||||
with Image.open(img_path) as img:
|
||||
# Get original dimensions before thumbnail
|
||||
orig_w, orig_h = img.size
|
||||
|
||||
# Apply placeholder outlines if enabled
|
||||
if placeholder_regions and (start_slide_num + i) in placeholder_regions:
|
||||
# Convert to RGBA for transparency support
|
||||
if img.mode != "RGBA":
|
||||
img = img.convert("RGBA")
|
||||
|
||||
# Get the regions for this slide
|
||||
regions = placeholder_regions[start_slide_num + i]
|
||||
|
||||
# Calculate scale factors using actual slide dimensions
|
||||
if slide_dimensions:
|
||||
slide_width_inches, slide_height_inches = slide_dimensions
|
||||
else:
|
||||
# Fallback: estimate from image size at CONVERSION_DPI
|
||||
slide_width_inches = orig_w / CONVERSION_DPI
|
||||
slide_height_inches = orig_h / CONVERSION_DPI
|
||||
|
||||
x_scale = orig_w / slide_width_inches
|
||||
y_scale = orig_h / slide_height_inches
|
||||
|
||||
# Create a highlight overlay
|
||||
overlay = Image.new("RGBA", img.size, (255, 255, 255, 0))
|
||||
overlay_draw = ImageDraw.Draw(overlay)
|
||||
|
||||
# Highlight each placeholder region
|
||||
for region in regions:
|
||||
# Convert from inches to pixels in the original image
|
||||
px_left = int(region["left"] * x_scale)
|
||||
px_top = int(region["top"] * y_scale)
|
||||
px_width = int(region["width"] * x_scale)
|
||||
px_height = int(region["height"] * y_scale)
|
||||
|
||||
# Draw highlight outline with red color and thick stroke
|
||||
# Using a bright red outline instead of fill
|
||||
stroke_width = max(
|
||||
5, min(orig_w, orig_h) // 150
|
||||
) # Thicker proportional stroke width
|
||||
overlay_draw.rectangle(
|
||||
[(px_left, px_top), (px_left + px_width, px_top + px_height)],
|
||||
outline=(255, 0, 0, 255), # Bright red, fully opaque
|
||||
width=stroke_width,
|
||||
)
|
||||
|
||||
# Composite the overlay onto the image using alpha blending
|
||||
img = Image.alpha_composite(img, overlay)
|
||||
# Convert back to RGB for JPEG saving
|
||||
img = img.convert("RGB")
|
||||
|
||||
img.thumbnail((width, height), Image.Resampling.LANCZOS)
|
||||
w, h = img.size
|
||||
tx = x + (width - w) // 2
|
||||
ty = y_thumbnail + (height - h) // 2
|
||||
grid.paste(img, (tx, ty))
|
||||
|
||||
# Add border
|
||||
if BORDER_WIDTH > 0:
|
||||
draw.rectangle(
|
||||
[
|
||||
(tx - BORDER_WIDTH, ty - BORDER_WIDTH),
|
||||
(tx + w + BORDER_WIDTH - 1, ty + h + BORDER_WIDTH - 1),
|
||||
],
|
||||
outline="gray",
|
||||
width=BORDER_WIDTH,
|
||||
)
|
||||
|
||||
return grid
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
58
.gitignore
vendored
Normal file
58
.gitignore
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
# Node modules
|
||||
node_modules/
|
||||
.claude/skills/*/scripts/node_modules/
|
||||
|
||||
# NPM
|
||||
package-lock.json
|
||||
npm-debug.log
|
||||
yarn.lock
|
||||
yarn-error.log
|
||||
|
||||
# PowerPoint files (temp/demo)
|
||||
*.pptx
|
||||
!personnalités/*.pptx
|
||||
|
||||
# HTML slides temporaires
|
||||
tingting_presentation_slide*.html
|
||||
tingting_final_slide*.html
|
||||
tingting_elegant_slide*.html
|
||||
demo_*.html
|
||||
cuisine_*.html
|
||||
|
||||
# Scripts de conversion temporaires
|
||||
convert_*.js
|
||||
create_tingting_*.js
|
||||
create_editable_*.js
|
||||
create_with_*.js
|
||||
|
||||
# Python cache
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
*.so
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
desktop.ini
|
||||
|
||||
# Editor/IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.project
|
||||
.classpath
|
||||
.settings/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Temp files
|
||||
*.tmp
|
||||
*.temp
|
||||
.cache/
|
||||
128
CLAUDE.md
Normal file
128
CLAUDE.md
Normal file
@ -0,0 +1,128 @@
|
||||
# Instructions Claude Code
|
||||
|
||||
## Contexte
|
||||
|
||||
- **Alexis** (29 ans, FR) + **Tingting** (34 ans, CN) | Shanghai, Chine
|
||||
- **Langues** : FR/EN/JP/CN (Alexis), EN commun avec Tingting
|
||||
- **Relation** : Couple, crise majeure octobre 2025 (voir `couple_backlog/16-22_octobre_2025.md`)
|
||||
|
||||
### Profils rapides
|
||||
|
||||
**Alexis** : Introspection++, confiance--, peut être défensif, besoin de vérité directe
|
||||
→ Détails : `personnalités/Alexis.md`
|
||||
|
||||
**Tingting** : Professeure Grade 7 (Class 7-3, 41 élèves), leadership socratique
|
||||
→ Détails : `personnalités/Tingting.md`
|
||||
→ Travail : `personnalités/TingtingWork.md` (style PowerPoint signature)
|
||||
|
||||
---
|
||||
|
||||
## Communication Claude
|
||||
|
||||
### Principes
|
||||
|
||||
- **Direct, factuel, sans langue de bois**
|
||||
- **Confronter avec questionnement socratique** (jamais affirmation brutale)
|
||||
- L'utilisateur n'a pas toujours raison
|
||||
- **Écouter les signaux** : Si "tu casses mon fun" / "tu vas me faire quitter" → recalibrer immédiatement
|
||||
|
||||
### Méthode socratique (PRIORITÉ ABSOLUE)
|
||||
|
||||
✅ **Succès prouvé** : 15 septembre 2024
|
||||
❌ **Ne JAMAIS dire** : "Tu te mens", "Tu vas crasher", "Tu évites le problème"
|
||||
✅ **À LA PLACE, questionner** :
|
||||
|
||||
1. **Question exploration** : "Comment tu vois ça évoluer dans les prochaines semaines ?"
|
||||
2. **Question cohérence** : "Tu as dit X tout à l'heure, maintenant Y, comment tu lies les deux ?"
|
||||
3. **Question conséquences** : "Si ça continue comme ça, qu'est-ce qui se passe ?"
|
||||
4. **Question introspection** : "Qu'est-ce qui te fait dire ça maintenant ?"
|
||||
|
||||
**Avantages** : Utilise son introspection naturelle, il arrive à ses propres conclusions (plus durable), moins de défensivité
|
||||
|
||||
### Règle d'or post-conversation importante
|
||||
|
||||
1. **Noter immédiatement** : Accord + Actions + Deadline + Suivi
|
||||
2. **Faire 1 action dans les 24h**
|
||||
3. **Gestion "I don't know"** : Ne JAMAIS abandonner → Proposer options "Entre X, Y et Z, qu'est-ce qui te parle le plus ?"
|
||||
|
||||
→ Détails complets : `ToRemember/schema.md`
|
||||
|
||||
---
|
||||
|
||||
## Analyse problèmes : 4 dimensions
|
||||
|
||||
Appliquer systématiquement pour tout problème :
|
||||
|
||||
1. **Contexte** : Situation actuelle, contraintes externes, ressources, culture
|
||||
2. **Émotions** : Déclencheurs émotionnels, impact sur décisions, gestion réactions
|
||||
3. **Personnalité** : Patterns comportementaux, forces/faiblesses (voir `personnalités/*.md`)
|
||||
4. **Logique** : Faits objectifs, solutions pratiques, perspective long terme
|
||||
|
||||
---
|
||||
|
||||
## Structure Repo
|
||||
|
||||
### 🔥 Critiques (consulter systématiquement)
|
||||
|
||||
- `Promesses_à_tenir.md` : Engagements actifs envers Tingting (validation émotionnelle, rush solution, focus topics, dinner)
|
||||
- `ToRemember/schema.md` : Leadership socratique détaillé
|
||||
- `personnalités/Alexis.md` : Profil complet
|
||||
- `personnalités/Tingting.md` : Profil complet + carrière professionnelle
|
||||
- `observations_patterns.md` : Patterns récurrents identifiés
|
||||
|
||||
### 💬 Couple
|
||||
|
||||
- `couple_backlog/` : Historique conflits (16-22 octobre 2025 = crise majeure)
|
||||
- `conversation_topics/` : Système de suivi des sujets actifs
|
||||
- `README.md` : Explications du système
|
||||
- `_template.md` : Template pour nouveaux sujets
|
||||
- `archive/` : Sujets résolus
|
||||
- `topics/` : Sujets de discussion
|
||||
- `plan_discussion/` : Stratégies et préparation conversations
|
||||
|
||||
### 🔧 Travail & Projets
|
||||
|
||||
- `Projects/` : Analyses techniques, projets en cours
|
||||
- `personnalités/TingtingWork.md` : Guide complet style PowerPoint
|
||||
- `.claude/skills/pptx/` : Skill PowerPoint officiel Anthropic (html2pptx)
|
||||
|
||||
### 📊 Organisation
|
||||
|
||||
- `planning/` : Organisation temps et tâches
|
||||
- `stratégie/` : Plans stratégiques
|
||||
- `WIP/` : Work in progress
|
||||
- `food/` : Recettes, restaurants
|
||||
|
||||
### ⚠️ Désactivé
|
||||
|
||||
- `what-if/Sortie.md` : Plan de sortie [INVALIDE]
|
||||
|
||||
### Process pour nouveau problème/projet
|
||||
|
||||
1. **Identifier domaine** : Couple, travail, personnel, finances, santé
|
||||
2. **Créer/utiliser** structure de fichiers appropriée
|
||||
3. **Documenter** selon template adapté
|
||||
4. **Analyser** selon les 4 dimensions
|
||||
5. **Définir actions concrètes** avec deadlines
|
||||
|
||||
---
|
||||
|
||||
## PowerPoint pour Tingting
|
||||
|
||||
### Système
|
||||
|
||||
- **Skill** : `.claude/skills/pptx/` (script `html2pptx.js`)
|
||||
- **Style guide** : `personnalités/TingtingWork.md` (palette, principes, templates)
|
||||
- **Exemple référence** : `personnalités/Tingting_Class73_Elegant.pptx` (septembre 2025)
|
||||
|
||||
### Identité visuelle signature
|
||||
|
||||
- **Palette** : Bordeaux profond (#6B2C3E) + Or antique (#B8974F) + Crème ivoire (#F5F1E8)
|
||||
- **Style** : Élégance européenne + Modernité + Traditionalisme chinois subtil
|
||||
- **Philosophie** : Sophistiqué mais accessible, moderne mais respectueux tradition
|
||||
- **Process** : HTML (720pt × 405pt) → html2pptx.js → PPTX 100% éditable
|
||||
|
||||
### Quand Tingting demande un PowerPoint
|
||||
|
||||
→ Utiliser **systématiquement** le style documenté dans `TingtingWork.md`
|
||||
→ Garder **cohérence** identité visuelle professionnelle pour toutes ses présentations
|
||||
276
Projects/Backlog_9-10_Octobre_2025.md
Normal file
276
Projects/Backlog_9-10_Octobre_2025.md
Normal file
@ -0,0 +1,276 @@
|
||||
# Backlog 9-10 Octobre 2025
|
||||
|
||||
## Catastrophe Git et Reconstruction (9 octobre soir → 10 octobre matin)
|
||||
|
||||
### L'Incident
|
||||
|
||||
**23h00 (9 oct):** Commande `git reset --hard` mal comprise par Claude → Destruction de 3 jours de travail non commité
|
||||
- Main.js (orchestrateur principal)
|
||||
- pipeline-builder.html et pipeline-runner.html (interfaces)
|
||||
- Multiples fichiers modifiés mais jamais ajoutés au commit
|
||||
|
||||
**Cause racine:** `git commit` régulier (toutes les 2h) MAIS fichiers jamais ajoutés avec `git add`
|
||||
- Croyait être safe avec commits fréquents
|
||||
- Ne réalisait pas que certains fichiers restaient "modified" sans être staged
|
||||
|
||||
### La Reconstruction (6h-10h, 10 octobre)
|
||||
|
||||
**Sauvetage:** Historique Claude Code
|
||||
- 1MB de modifications récupérées depuis les sessions Claude
|
||||
- Parsing des exports Claude sur les 3 derniers jours
|
||||
- Script d'application automatique des modifications
|
||||
|
||||
**Résultat:**
|
||||
- 114/417 modifications appliquées automatiquement (27%)
|
||||
- Reste: Application manuelle assistée par Claude (1h30)
|
||||
- Système fonctionnel récupéré à 10h
|
||||
|
||||
**Émotions:**
|
||||
- Heartbeat élevé lors de la découverte
|
||||
- Découragement initial ("j'ai perdu 3 jours")
|
||||
- Détermination pendant reconstruction
|
||||
- Soulagement quand système refonctionne
|
||||
|
||||
### Leçons Apprises
|
||||
|
||||
**Workflow Git corrigé:**
|
||||
```bash
|
||||
git add -A # TOUJOURS ajouter tous les fichiers
|
||||
git status # Vérifier ce qui sera commité
|
||||
git commit -m "..."
|
||||
git push # Push régulier
|
||||
```
|
||||
|
||||
**Fréquence:** Toutes les heures minimum, idéalement toutes les 30min
|
||||
|
||||
**Note importante:** Ce n'était PAS de la paresse - workflow git incompris, pas manque de discipline
|
||||
|
||||
---
|
||||
|
||||
## Projets Avancés (10 octobre)
|
||||
|
||||
### SEO Article Generator
|
||||
|
||||
**Status final:** Fonctionnel, modules validés
|
||||
|
||||
**Modules implémentés:**
|
||||
- ✅ **Initial Generation** (optimisé) - 7.5/10
|
||||
- Fix répétitions (découverte: fallbacks Claude hardcodés)
|
||||
- Diversité mots-clés améliorée
|
||||
- Anti-collision titres/mots-clés
|
||||
- Plus de placeholders non résolus
|
||||
|
||||
- ✅ **SmartTouch Enhancement** - 6.5/10
|
||||
- Système d'analyse avant modification
|
||||
- Scores objectifs (4 dimensions: technique, style, lisibilité, vocabulaire)
|
||||
- Budget par mot pour éviter spam
|
||||
- Enhancement subtil ciblé
|
||||
|
||||
- ✅ **Adversarial Detection** - Fonctionnel
|
||||
- 7 métriques statistiques universelles (pas de keywords)
|
||||
- Type-Token Ratio (diversité lexicale)
|
||||
- Coefficient de variation (uniformité phrases)
|
||||
- Entropie syntaxique (débuts répétitifs)
|
||||
- Analyse ponctuation complexe
|
||||
- Détection bigrammes répétés
|
||||
- Uniformité longueur mots
|
||||
- Approche académique niveau recherche
|
||||
|
||||
- ⚠️ **Human Touch** - En cours d'optimisation (00h30)
|
||||
- Objectif: Imperfections humaines subtiles
|
||||
- Problème actuel: 100+ modifications = Spam
|
||||
- Fix en cours: Limiter à 5-10 modifications MAX
|
||||
|
||||
- ⏳ **Pattern Breaking** - À tester
|
||||
|
||||
**Timeline:**
|
||||
- 6h-10h: Reconstruction catastrophe git
|
||||
- 10h-15h: OCR Pipeline chinois
|
||||
- 15h-21h: SmartTouch + Adversarial
|
||||
- 21h-00h30: Tests finaux + Human Touch
|
||||
|
||||
**Défis rencontrés:**
|
||||
- Content creep répété sur plusieurs modules
|
||||
- Consommation tokens Claude (25% → 18% restants)
|
||||
- Balance subtilité vs efficacité sur adversarial/human touch
|
||||
|
||||
---
|
||||
|
||||
### ClassGen - Chinese Study Tool
|
||||
|
||||
**Progrès majeur:** Pipeline OCR validé
|
||||
|
||||
**Morning win (6h-10h):**
|
||||
- ✅ PaddleOCR setup et fonctionnel
|
||||
- ✅ Pipeline complet: PDF → OCR → Correction IA → JSON
|
||||
- ✅ **99.97% précision globale** (99.88% → 99.97% avec IA)
|
||||
- ✅ **97.87% sur questions** (sections critiques)
|
||||
- ✅ **83 PDFs traités** (7-8h de traitement)
|
||||
- ✅ Correction IA: 75% de réussite sur erreurs OCR
|
||||
|
||||
**Architecture:**
|
||||
```
|
||||
Manuel chinois (PDF)
|
||||
→ PaddleOCR (extraction 95-98%)
|
||||
→ GPT-4o-mini batch (correction erreurs)
|
||||
→ JSON structuré
|
||||
→ ClassGen (gamification)
|
||||
```
|
||||
|
||||
**GameSystem:**
|
||||
- 6-7 jeux fonctionnels
|
||||
- Nouvelle architecture data loading en cours
|
||||
- Content loader partiellement implémenté
|
||||
- Fix flashcard presque terminé
|
||||
|
||||
**Impact:** Déblocage complet de l'étude chinoise
|
||||
- 3 semaines de retard à rattraper
|
||||
- Midterm dans 3-4 semaines
|
||||
- Maintenant: Contenu disponible + système gamifié
|
||||
|
||||
---
|
||||
|
||||
### MCP Setup (demande du père)
|
||||
|
||||
**Context:** Père travaille sur n8n, demande setup MCP + Docker + WSL
|
||||
|
||||
**Timing:** Noté dans backlog
|
||||
- Après: SEO livré + Midterm chinois réussi
|
||||
- Setup + documentation pour transmission au père
|
||||
|
||||
---
|
||||
|
||||
## Patterns Observés
|
||||
|
||||
### Workflow Multi-Instance Validé
|
||||
|
||||
**Matin (reconstruction):**
|
||||
- Instance 1: Parsing historique Claude
|
||||
- Instance 2: Script application automatique
|
||||
- Résultat: 1h30 au lieu de 10-12h manuelles
|
||||
|
||||
**Après-midi/soir:**
|
||||
- Instance 1: SEO SmartTouch
|
||||
- Instance 2: SEO Adversarial
|
||||
- Instance 3: ClassGen fixes
|
||||
- Efficacité: 2-3 instances = Limite cognitive actuelle
|
||||
|
||||
### Gestion Temps Morts
|
||||
|
||||
**Optimisation validée:**
|
||||
- Attente LLM (2-4min) = Note idées, fait vaisselle, etc.
|
||||
- Pas de scrolling passif
|
||||
- Productif même pendant les pauses forcées
|
||||
|
||||
### Communication Pendant Workflow
|
||||
|
||||
**Pattern identifié:** Parle à Claude Code pendant temps morts
|
||||
- Pas de la procrastination
|
||||
- Utilisation efficace des micro-pauses
|
||||
- Maintien du flow général
|
||||
|
||||
### Feature Creep Contrôlé (Progrès!)
|
||||
|
||||
**15h40:** "J'ai faillis feature creep sur SEO :^). Mais j'ai controlé tqt."
|
||||
- **Première fois** qu'il identifie ET stoppe le pattern en temps réel
|
||||
- Signe de conscience accrue des patterns
|
||||
- Capacité d'auto-régulation en développement
|
||||
|
||||
### Fallbacks Claude = Problème Systémique
|
||||
|
||||
**Découverte majeure:**
|
||||
- Claude Code ajoute des fallbacks "défensifs" automatiquement
|
||||
- Ces fallbacks ruinent la logique métier (valeurs hardcodées)
|
||||
- **Tous** les projets affectés (SEO, ClassGen)
|
||||
- Solution: Instructions strictes "NO FALLBACKS SILENCIEUX"
|
||||
|
||||
**Exemple concret (SEO):**
|
||||
- Système devait générer mots-clés diversifiés via LLM
|
||||
- Claude ajoutait fallback → Toujours "durabilité, personnalisation"
|
||||
- Résultat: Répétitions massives dans articles
|
||||
|
||||
**Impact:** Pattern à documenter et éviter systématiquement
|
||||
|
||||
---
|
||||
|
||||
## Métriques de la Journée
|
||||
|
||||
**Temps de travail:** 16h+ (8h → 00h30)
|
||||
|
||||
**Code écrit:**
|
||||
- Direct: Minimal (instructions texte)
|
||||
- Via Claude: Plusieurs milliers de lignes (reconstruction + nouveaux modules)
|
||||
|
||||
**Commits:**
|
||||
- Réguliers après leçon git (toutes les 30min-1h)
|
||||
- `git add -A` systématique
|
||||
|
||||
**Tokens Claude consommés:**
|
||||
- 25% de limite 5h → 18% restants
|
||||
- Nécessité d'optimiser CLAUDE.md projets
|
||||
|
||||
**Projets touchés:** 3
|
||||
- SEO-gen (priorité)
|
||||
- ClassGen/OCR (breakthrough)
|
||||
- MCP (noté backlog)
|
||||
|
||||
---
|
||||
|
||||
## Victoires
|
||||
|
||||
### Techniques
|
||||
- ✅ Pipeline OCR chinois 99.97% = Déblocage études
|
||||
- ✅ Adversarial detection niveau recherche académique
|
||||
- ✅ Reconstruction 3 jours code en 1h30
|
||||
- ✅ SmartTouch enhancement fonctionnel
|
||||
|
||||
### Personnelles
|
||||
- ✅ Feature creep identifié et stoppé en temps réel
|
||||
- ✅ Workflow multi-instance validé (2-3 = optimal)
|
||||
- ✅ Gestion catastrophe git avec résilience
|
||||
- ✅ 16h de travail productif sans burnout (workflow Claude Code)
|
||||
|
||||
### Relationnelles
|
||||
- ✅ Communication avec père (projet MCP, report livraison honnête)
|
||||
- ✅ Temps pris pour Tingting (dîner, pause)
|
||||
- ✅ Hygiène maintenue (douche, dents après 2-4 jours)
|
||||
|
||||
---
|
||||
|
||||
## Défis Restants
|
||||
|
||||
### SEO-gen
|
||||
- [ ] Human Touch: Réduire à 5-10 modifs (actuellement 100+)
|
||||
- [ ] Pattern Breaking: Tests à finaliser
|
||||
- [ ] Livraison finale au père
|
||||
|
||||
### ClassGen
|
||||
- [ ] Conversion JSON OCR → Format ClassGen
|
||||
- [ ] Tests complets avec contenu réel
|
||||
- [ ] Validation flow d'étude
|
||||
|
||||
### Académique
|
||||
- [ ] Rattrapage 3 semaines chinois (13 absences/21)
|
||||
- [ ] Préparation midterm (3-4 semaines)
|
||||
- [ ] Équilibre code/études à trouver
|
||||
|
||||
---
|
||||
|
||||
## Notes pour Demain
|
||||
|
||||
**Priorités:**
|
||||
1. Finir Human Touch (limiter modifications)
|
||||
2. Tester Pattern Breaking
|
||||
3. Livrer SEO-gen au père
|
||||
4. Conversion JSON OCR
|
||||
5. Commencer utilisation ClassGen pour étudier
|
||||
|
||||
**Tokens Claude:**
|
||||
- Vont reset (nouvelle journée)
|
||||
- Optimiser CLAUDE.md des projets pour économiser
|
||||
- Réduire contexte inutile
|
||||
|
||||
**Repos:**
|
||||
- Journée intense (16h)
|
||||
- Nuit courte probable
|
||||
- Prévoir récupération demain après-midi si possible
|
||||
220
Projects/ClassGen_Analysis.md
Normal file
220
Projects/ClassGen_Analysis.md
Normal file
@ -0,0 +1,220 @@
|
||||
# Class Generator - Analyse Patterns & Décisions Stratégiques
|
||||
|
||||
## Status Réel (Octobre 2025)
|
||||
|
||||
### Utilisation en Production
|
||||
- ✅ **En prod depuis plusieurs mois**
|
||||
- ✅ Utilisé pour donner des cours réels
|
||||
- ✅ Engagement élèves validé : "ça marche pas trop mal"
|
||||
- ✅ **Livraison régulière** : Nouvelle version toutes les 1-2 semaines
|
||||
- ✅ Système flashcards dynamique intégré (mieux qu'Anki selon Alexis)
|
||||
|
||||
### Historique des Versions
|
||||
- **V1** : Système initial (JavaScript/Node.js)
|
||||
- **Revamp 1** : "Pas assez bien" → Refonte architecture
|
||||
- **Revamp 2** : "Pas adapté" → Nouvelle refonte
|
||||
- **Version Actuelle** : Fonctionnelle, utilisée, mais dette technique identifiée
|
||||
|
||||
## Problèmes Identifiés
|
||||
|
||||
### 1. Dette Technique Réelle (Pas Perfectionnisme)
|
||||
|
||||
**2 Systèmes Parallèles** :
|
||||
- Système de modules de jeu (pour cours gamifiés)
|
||||
- Système Anki spécialisé (flashcards)
|
||||
- **Citation** : "J'aurais pu utiliser le système built in de module de jeu. A la place j'ai dev un système secondaire spécialisé pour ça"
|
||||
|
||||
**Conséquences** :
|
||||
- Code dupliqué ou patterns divergents
|
||||
- Amélioration d'un système ne bénéficie pas à l'autre
|
||||
- Maintenance 2x plus lourde
|
||||
- Ajout de features plus difficile que ça devrait
|
||||
|
||||
**Diagnostic** : Dette technique légitime, pas juste "c'est pas clean"
|
||||
|
||||
### 2. Besoin de Rigueur vs Réalité JavaScript
|
||||
|
||||
**Citation** : "Mon dev a besoin de rigueur et en Node.js c'est chiant"
|
||||
|
||||
**Problème fondamental** :
|
||||
- JavaScript/Node.js permet trop de "conneries"
|
||||
- Type system faible ou inexistant
|
||||
- Runtime errors au lieu de compile-time
|
||||
- Facile de casser des trucs sans s'en rendre compte
|
||||
- Pour un système complexe avec modules/plugins → C'est l'enfer
|
||||
|
||||
**Réaction naturelle** : "Je devrais le refaire en C++"
|
||||
|
||||
### 3. Tentation C++ (Fuite vers Zone de Confort)
|
||||
|
||||
**Pourquoi C++ attire** :
|
||||
- ✅ Zone de confort d'Alexis
|
||||
- ✅ Rigueur maximale (compile-time safety)
|
||||
- ✅ Type system strict
|
||||
- ✅ Confiance totale dans le code
|
||||
|
||||
**Pourquoi C++ N'est PAS la Solution** :
|
||||
- ❌ Trop lourd pour outil pédagogique
|
||||
- ❌ Dev trop long
|
||||
- ❌ Pas adapté pour amélioration en ligne
|
||||
- ❌ Pas facilement dev pour petits jeux
|
||||
- ❌ Chiant à déployer
|
||||
- ❌ Faut tout recoder
|
||||
|
||||
**Vrai diagnostic** : Envie de fuir Node.js (syndrome imposteur) déguisée en "besoin de perf"
|
||||
|
||||
## Contraintes Business Réelles
|
||||
|
||||
### Potentiel Commercial
|
||||
**Citation** : "J'aimerais bien le vendre ce truc"
|
||||
|
||||
**Requirements** :
|
||||
- ✅ Déploiement facile et en ligne
|
||||
- ✅ WeChat Mini App (marché chinois crucial)
|
||||
- ✅ Rapidité de dev pour itérer
|
||||
- ✅ Facilité pour créer petits jeux
|
||||
- ✅ Vendable en SaaS
|
||||
|
||||
**Conclusion** : Node.js/JS/TS est le BON choix pour le business model
|
||||
|
||||
## Solution Identifiée : TypeScript (Pas C++, Pas Revamp #3)
|
||||
|
||||
### Pourquoi TypeScript Résout TOUT
|
||||
|
||||
**Comparaison des Solutions** :
|
||||
|
||||
| Critère | TypeScript | C++ | JavaScript |
|
||||
|---------|-----------|-----|-----------|
|
||||
| Rigueur code | ✅ Strict mode | ✅✅ Maximum | ❌ Aucune |
|
||||
| Déploiement facile | ✅ npm/web | ❌ Binaires | ✅ npm/web |
|
||||
| WeChat mini app | ✅ Compatible | ❌ Impossible | ✅ Natif |
|
||||
| Dev rapide | ✅ Écosystème | ❌ Lent | ✅ Rapide |
|
||||
| Petits jeux | ✅ Web tech | ❌ Lourd | ✅ Web tech |
|
||||
| Maintenabilité | ✅ Types + interfaces | ✅ Strict | ❌ Spaghetti |
|
||||
| Vente SaaS | ✅ Idéal | ❌ Compliqué | ⚠️ Risqué |
|
||||
|
||||
### Ce N'est PAS un "Revamp #3"
|
||||
|
||||
**Différence Cruciale** :
|
||||
|
||||
**Revamps 1-2 (JS → JS)** :
|
||||
- ❌ Changement architecture
|
||||
- ❌ Problème fondamental (rigueur) non résolu
|
||||
- ❌ Cycle de refactor infini
|
||||
|
||||
**Migration TypeScript** :
|
||||
- ✅ **Professionnalisation du code**
|
||||
- ✅ Résout le besoin fondamental de rigueur
|
||||
- ✅ Garde la logique métier qui marche
|
||||
- ✅ Migration incrémentale (pas big bang)
|
||||
- ✅ Investissement business, pas perfectionnisme
|
||||
|
||||
### Stratégie de Migration
|
||||
|
||||
**Phase 1 : Setup (1 jour)**
|
||||
```bash
|
||||
npm install -D typescript @types/node
|
||||
npx tsc --init
|
||||
```
|
||||
Config : `allowJs: true` pour mixer JS et TS pendant migration
|
||||
|
||||
**Phase 2 : Migration Incrémentale (1 module à la fois)**
|
||||
- Semaine 1 : Module le plus critique
|
||||
- Semaine 2 : Un autre module
|
||||
- Le reste du code JS continue de fonctionner
|
||||
|
||||
**Phase 3 : Unification Systèmes (Cours + Anki)**
|
||||
```typescript
|
||||
interface LearningModule {
|
||||
id: string;
|
||||
execute(context: LearningContext): Promise<Result>;
|
||||
}
|
||||
|
||||
class CourseModule implements LearningModule { ... }
|
||||
class FlashcardModule implements LearningModule { ... }
|
||||
```
|
||||
1 système, 2 implémentations = Propre et maintenable
|
||||
|
||||
**Timeline Totale** : 2 mois (6-8 semaines)
|
||||
|
||||
**ROI Business** :
|
||||
- Vélocité features ×2-3
|
||||
- Moins de bugs = Crédibilité client
|
||||
- Déploiement facile = Scalabilité
|
||||
- WeChat ready = Marché chinois
|
||||
- Vendable professionnellement
|
||||
|
||||
## Décision Stratégique à Prendre
|
||||
|
||||
### Questions Clés
|
||||
|
||||
1. **Business ou Hobby ?**
|
||||
- Si Hobby → Garder JS, pas de migration
|
||||
- Si Business → Migration TS justifiée
|
||||
|
||||
2. **Vente Réelle Envisagée ?**
|
||||
- Business model clair ?
|
||||
- Potentiel marché ?
|
||||
- Volonté d'investir 2 mois ?
|
||||
|
||||
3. **Alternatives Considérées ?**
|
||||
- Python avec type hints ? (Non, moins adapté web/WeChat)
|
||||
- Rust ? (Courbe apprentissage trop raide, pas adapté)
|
||||
- C++ ? (Éliminé pour raisons business)
|
||||
|
||||
### Timing de la Décision
|
||||
|
||||
**AVANT Migration TS** :
|
||||
1. ✅ Stabiliser version JS actuelle
|
||||
2. ✅ Continuer utilisation en prod
|
||||
3. ✅ Noter vrais problèmes qui émergent
|
||||
4. ✅ Valider potentiel commercial
|
||||
|
||||
**SEULEMENT SI** :
|
||||
- Business model validé
|
||||
- Contraintes temps acceptées (2 mois)
|
||||
- Volonté long-terme du produit
|
||||
|
||||
**PAS SI** :
|
||||
- Juste outil personnel
|
||||
- Pas de plan de vente
|
||||
- Satisfait de l'état actuel
|
||||
|
||||
## Plan d'Action Actuel
|
||||
|
||||
### Court Terme (Maintenant)
|
||||
1. ✅ **STABILISER** version JS actuelle
|
||||
2. ✅ Continuer utilisation avec élèves
|
||||
3. ✅ **NOTER** vrais problèmes émergents
|
||||
4. ❌ **PAS de Revamp #3**
|
||||
5. ❌ **PAS de refactor** "juste pour améliorer"
|
||||
|
||||
### Règle d'Or
|
||||
**"Je finis les endpoints, je règle les derniers bugs réels, je livre. J'ai plein d'amélioration à faire mais je livre dès que possible ok ?"**
|
||||
|
||||
### Moyen Terme (Après Stabilisation)
|
||||
- Décision : Business ou Hobby ?
|
||||
- Si Business → Planifier migration TS
|
||||
- Si Hobby → Maintenance légère
|
||||
|
||||
## Apprentissages Clés
|
||||
|
||||
### Pattern Identifié
|
||||
**Différence Dette Technique vs Perfectionnisme** :
|
||||
|
||||
**Dette Technique (ClassGen)** :
|
||||
- ✅ "L'architecture rend les features difficiles à ajouter"
|
||||
- ✅ 2 systèmes parallèles = Maintenance 2x
|
||||
- ✅ Ça bloque concrètement
|
||||
|
||||
**Perfectionnisme (Envie C++)** :
|
||||
- ❌ "Je veux que ce soit dans ma zone de confort"
|
||||
- ❌ Fuite vers C++ pour se sentir légitime
|
||||
- ❌ Ça marche déjà avec des vrais utilisateurs
|
||||
|
||||
### Leçon pour l'Avenir
|
||||
Ne pas confondre :
|
||||
- "J'ai besoin de rigueur" (besoin réel → TypeScript)
|
||||
- "Je veux être dans ma zone de confort" (fuite → C++)
|
||||
|
||||
La bonne solution résout le problème technique ET respecte les contraintes business.
|
||||
64
Projects/Class_Generator_2.0.md
Normal file
64
Projects/Class_Generator_2.0.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Class Generator 2.0 - Système d'apprentissage
|
||||
|
||||
## Vision & Mission
|
||||
Plateforme éducative interactive pour l'apprentissage des langues (principalement anglais/chinois) destinée aux enfants de 8-9 ans. Le projet a été entièrement réécrit avec une architecture ultra-modulaire en vanilla JavaScript.
|
||||
|
||||
## Architecture Ultra-Modulaire (Révolutionnaire)
|
||||
|
||||
### Principes Fondamentaux NON-NÉGOCIABLES
|
||||
- Responsabilité Inviolable - Chaque module a exactement un rôle
|
||||
- Zéro Dépendance Directe - Communication uniquement via EventBus
|
||||
- Instances Scellées - Modules non-modifiables après création (Object.seal)
|
||||
- État Privé - Données internes cachées via WeakMap
|
||||
- Injection de Dépendances - Aucune variable globale
|
||||
- Contrats Forcés - Méthodes abstraites obligatoires
|
||||
|
||||
### Core System (Terminé ✅)
|
||||
```
|
||||
src/core/
|
||||
├── Module.js # Classe abstraite base avec WeakMap privates
|
||||
├── EventBus.js # Système d'événements strict avec validation
|
||||
├── ModuleLoader.js # Injection de dépendances avec ordre d'initialisation
|
||||
├── Router.js # Navigation avec guards et middleware
|
||||
└── Application.js # Auto-bootstrap avec gestion du cycle de vie
|
||||
```
|
||||
|
||||
## Système de Jeux (14 Modules Convertis)
|
||||
|
||||
### Jeux Disponibles
|
||||
1. **StoryReader** - Lecture d'histoires avec chapitres
|
||||
2. **LetterDiscovery** - Apprentissage lettres en 3 phases
|
||||
3. **QuizGame** - Quiz bidirectionnel avec scoring
|
||||
4. **WordStorm** - Action game avec mots tombants
|
||||
5. **AdventureReader** - RPG interactif
|
||||
6. **WhackAMole** - Tape-taupe standard
|
||||
7. **WhackAMoleHard** - Version difficile (3 taupes simultanées)
|
||||
8. **WizardSpellCaster** - Lanceur de sorts magiques
|
||||
9. **WordDiscovery** - Découverte de vocabulaire
|
||||
10. **GrammarDiscovery** - 8 étapes grammaticales rotatives
|
||||
11. **FillTheBlank** - Complétion de phrases intelligente
|
||||
12. **StoryBuilder** - Construction par glisser-déposer
|
||||
13. **RiverRun** - Navigation fluviale avec vocabulaire
|
||||
14. **ChineseStudy** - Apprentissage chinois complet (4 modes)
|
||||
|
||||
### À Ajouter
|
||||
- **Module flashcards**
|
||||
- **Module preview**
|
||||
|
||||
## Tech Stack
|
||||
- **Frontend** : Vanilla JS/HTML/CSS, ES6 Modules
|
||||
- **Backend** : Node.js serveur local
|
||||
- **Architecture** : EventBus strict, WeakMap privates, Object.seal
|
||||
- **Contenu** : JSON/vocabulary objects adaptatifs
|
||||
|
||||
## Usage
|
||||
- **Cible principale** : Enfants 8-9 ans (anglais/chinois)
|
||||
- **Usage personnel** : Apprentissage chinois
|
||||
- **Enseignement** : Cours d'anglais aux enfants chinois
|
||||
|
||||
## État Actuel
|
||||
- ✅ Core terminé et scellé
|
||||
- ✅ 14 jeux convertis à l'architecture modulaire
|
||||
- ✅ Système CSS avec injection dynamique
|
||||
- ✅ Serveur de développement opérationnel
|
||||
- 🚧 V1 prévue ce soir
|
||||
34
Projects/Claude_Workflow_Optimization.md
Normal file
34
Projects/Claude_Workflow_Optimization.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Claude Workflow Optimization
|
||||
|
||||
## Vue d'ensemble
|
||||
Projet d'amélioration du workflow de travail avec Claude Code et les multiples instances Claude.
|
||||
|
||||
## Contexte actuel
|
||||
- **3 terminaux en parallèle** avec instances Claude différentes
|
||||
- **Délégation de développement** à d'autres instances
|
||||
- **Claude Code** pour coordination et organisation
|
||||
- **9 projets simultanés** à gérer
|
||||
|
||||
## Problématiques identifiées
|
||||
- Gestion de multiples projets simultanés
|
||||
- Coordination entre instances Claude
|
||||
- Efficacité du workflow multi-terminal
|
||||
- Organisation et priorisation
|
||||
|
||||
## Pistes d'amélioration (à définir)
|
||||
- [ ] Système de communication entre instances ?
|
||||
- [ ] Templates de délégation de tâches ?
|
||||
- [ ] Meilleure organisation des fichiers projets ?
|
||||
- [ ] Automatisation de certaines tâches récurrentes ?
|
||||
- [ ] Système de priorisation des projets ?
|
||||
- [ ] Hooks personnalisés Claude Code ?
|
||||
- [ ] Slash commands custom ?
|
||||
|
||||
## État actuel
|
||||
- Idée initiale, besoins à préciser
|
||||
- Workflow actuel fonctionnel mais optimisable
|
||||
|
||||
## Next steps
|
||||
- [ ] Observer les frictions actuelles dans le workflow
|
||||
- [ ] Identifier les tâches répétitives
|
||||
- [ ] Lister les améliorations prioritaires
|
||||
21
Projects/Essay_Writing_Tingting.md
Normal file
21
Projects/Essay_Writing_Tingting.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Essay Writing - Projet Tingting
|
||||
|
||||
## Vue d'ensemble
|
||||
Projet d'accompagnement de Tingting dans l'apprentissage de l'écriture d'essais.
|
||||
|
||||
## Objectif
|
||||
Aider Tingting à développer ses compétences en rédaction d'essais.
|
||||
|
||||
## Actions envisagées
|
||||
- Trouver des sources d'apprentissage
|
||||
- [À préciser avec Tingting]
|
||||
|
||||
## État actuel
|
||||
- Promesse faite à Tingting de trouver des sources
|
||||
- Détails du projet à clarifier
|
||||
|
||||
## Next steps
|
||||
- [ ] Vérifier avec Tingting ce qu'elle attend exactement
|
||||
- [ ] Définir le type d'essais (académique, créatif, argumentatif ?)
|
||||
- [ ] Trouver ressources adaptées
|
||||
- [ ] Établir un plan d'accompagnement
|
||||
726
Projects/LeBonCoup_Analyse.md
Normal file
726
Projects/LeBonCoup_Analyse.md
Normal file
@ -0,0 +1,726 @@
|
||||
# LeBonCoup - Analyse Critique du Projet
|
||||
|
||||
**Date :** 16 janvier 2025
|
||||
**Analysé par :** Alexis & Claude
|
||||
**Pour :** Papa & Frère
|
||||
|
||||
---
|
||||
|
||||
## 1. Résumé du Concept
|
||||
|
||||
**Pitch :** Plateforme de petites annonces inversée où les demandeurs publient gratuitement leurs besoins de services, et les prestataires paient (via tokens) pour accéder aux demandes et contacter les demandeurs.
|
||||
|
||||
**Modèle économique :**
|
||||
- Demandeurs : publication gratuite (acquisition facile)
|
||||
- Prestataires : achètent des tokens (1 token = 1 demande débloquée)
|
||||
- Limite : maximum 5 pros par demande (évite le spam pour les demandeurs)
|
||||
|
||||
---
|
||||
|
||||
## 2. Problèmes Identifiés et Solutions Apportées
|
||||
|
||||
### ⚠️ Problème #1 : Le modèle économique inversé est risqué
|
||||
|
||||
**Constat initial :**
|
||||
- Les prestataires (ceux qui vont travailler) doivent payer pour accéder aux demandes
|
||||
- Normalement, c'est le demandeur qui est le plus motivé
|
||||
- Pourquoi un plombier paierait pour "peut-être" décrocher un job ?
|
||||
|
||||
**Risques :**
|
||||
- Les bons prestataires ne voudront pas payer sans garantie
|
||||
- Concurrence frontale avec LeBonCoin (gratuit), Malt, TaskRabbit, etc.
|
||||
|
||||
**✅ Solution apportée : Système de tokens + limite de 5 pros**
|
||||
|
||||
Au lieu de payer par demande individuelle (trop risqué), le pro :
|
||||
- Achète un pack de tokens (10, 30, 70, 150)
|
||||
- Voit combien de demandes correspondent à ses filtres AVANT d'acheter
|
||||
- Débloque uniquement les demandes qui l'intéressent
|
||||
- Sait qu'il sera maximum en compétition avec 4 autres pros (pas 50)
|
||||
|
||||
**Amélioration :** Limite de 5 pros par demande = équilibre entre choix (pour le demandeur) et compétition acceptable (pour les pros).
|
||||
|
||||
**Reste à valider :** Est-ce que les pros trouvent ce modèle attractif ? → **Il faut interroger 20+ artisans/freelances AVANT de coder.**
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Problème #2 : Scalabilité inversée (paradoxe)
|
||||
|
||||
**Constat :**
|
||||
- Plus il y a de demandes → plus de pros achètent l'accès
|
||||
- Plus de pros → chaque demandeur reçoit 50+ messages
|
||||
- Expérience pourrie pour les demandeurs → ils partent
|
||||
- Moins de demandes → les pros n'achètent plus
|
||||
- **Cercle vicieux**
|
||||
|
||||
**✅ Solution : Limite stricte de 5 pros par demande**
|
||||
|
||||
Une fois 5 pros ont débloqué une demande :
|
||||
- Elle devient invisible pour les autres pros
|
||||
- Le demandeur reçoit max 5 contacts (gérable)
|
||||
- Les pros qui arrivent tard voient moins de demandes disponibles (autorégulation naturelle)
|
||||
|
||||
**Résultat :** Le système trouve un équilibre naturel entre offre et demande.
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Problème #3 : Qualité des demandes (si gratuit = spam)
|
||||
|
||||
**Risque :**
|
||||
- Publication gratuite → risque de fausses demandes, demandes non sérieuses, spam
|
||||
- Les pros paient pour accéder à du vent
|
||||
|
||||
**✅ Solutions combinées :**
|
||||
|
||||
1. **Limite de 3 demandes actives simultanées** par user
|
||||
2. **Modération automatique** : scan de mots-clés suspects avant publication
|
||||
3. **Review manuelle** si détection de contenu douteux
|
||||
4. **Remboursement automatique** si demande frauduleuse signalée et confirmée
|
||||
5. **Ban** des users abusifs
|
||||
|
||||
**Reste à surveiller :** Le ratio demandes sérieuses / demandes pourries. Si trop de pourries → il faudra peut-être faire payer symboliquement les demandeurs (1-2€).
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Problème #4 : Données utilisateurs et RGPD
|
||||
|
||||
**Préoccupation majeure :**
|
||||
- Gérer des emails, mots de passe, conversations = responsabilité énorme
|
||||
- Risque de hack → leak de données sensibles
|
||||
- Obligations RGPD lourdes
|
||||
|
||||
**✅ Solution : Architecture "privacy-first" avec anonymisation**
|
||||
|
||||
**Ce qu'on fait :**
|
||||
- **Emails jamais stockés en clair** : hashés avec SHA256 + salt secret
|
||||
- **Mots de passe** : hashés avec Argon2/bcrypt
|
||||
- **Pseudonymes publics** : "User_8x7f9a" (pas de noms réels)
|
||||
- **Messages chiffrés de bout en bout (E2E)** : stockés chiffrés, serveur ne peut pas les lire
|
||||
- **Clé de chiffrement dérivée** de email+password (reste dans le navigateur, jamais envoyée au serveur)
|
||||
|
||||
**Ce qu'on stocke (minimal) :**
|
||||
```
|
||||
users:
|
||||
- id: hash de l'email (irreversible sans le salt secret)
|
||||
- password_hash
|
||||
- token_balance
|
||||
- type: pro/demandeur
|
||||
```
|
||||
|
||||
**Avantages :**
|
||||
- ✅ Hack de la BDD → pas d'emails en clair, pas de mots de passe, messages illisibles
|
||||
- ✅ RGPD : données minimales, anonymisées, chiffrées
|
||||
- ✅ Pas de vente de données possible (on les a pas)
|
||||
|
||||
**Trade-off :**
|
||||
- ❌ Si user change son mot de passe → toutes ses conversations deviennent indéchiffrables (il les perd)
|
||||
- Solution : Warning clair + possibilité d'exporter avant
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Problème #5 : Messagerie et responsabilité légale
|
||||
|
||||
**Le gros risque :**
|
||||
- Anonymat total + messagerie = potentiel d'activités illégales
|
||||
- Prostitution, drogue, travail au noir, etc.
|
||||
- Si le site devient un repaire de criminalité → fermeture + poursuites judiciaires
|
||||
|
||||
**❌ Solution rejetée : Anonymat absolu (pas de modération possible)**
|
||||
|
||||
**Raisons :**
|
||||
- Légalement intenable (DSA en Europe oblige à modérer)
|
||||
- Impossible de gérer les abus
|
||||
- Risque pénal pour les fondateurs (cf. Silk Road, Backpage)
|
||||
- Pas d'investisseurs possibles
|
||||
|
||||
**✅ Solution retenue : Privacy forte + modération réactive**
|
||||
|
||||
**Architecture hybride :**
|
||||
|
||||
1. **Messages chiffrés E2E** (serveur ne peut pas les lire par défaut)
|
||||
|
||||
2. **Scan côté client AVANT chiffrement** (détection automatique) :
|
||||
- Numéros de téléphone
|
||||
- Emails
|
||||
- Réseaux sociaux
|
||||
- Mots-clés suspects : "cash", "espèces", "discret", "sans facture"
|
||||
- Combinaisons suspectes
|
||||
|
||||
3. **Système de "flags" anonymes** :
|
||||
- Si détection → flag envoyé au serveur (compteur)
|
||||
- **Le message est quand même envoyé** (pas bloqué)
|
||||
- Le serveur ne voit PAS le contenu, juste : "User X a généré 5 flags 'contact_externe'"
|
||||
|
||||
4. **Actions automatiques par seuils** :
|
||||
- 10 flags → Warning
|
||||
- 25 flags → Restriction temporaire (24h)
|
||||
- 50 flags OU 3 signalements users → Ban automatique
|
||||
|
||||
5. **Modération en cas de signalement** :
|
||||
- User A signale User B
|
||||
- A peut partager son blob déchiffré avec le support
|
||||
- Support review manuellement (A a consenti)
|
||||
- Si confirmé illégal → ban + signalement autorités
|
||||
|
||||
**Avantages :**
|
||||
- ✅ Privacy respectée (chiffrement par défaut)
|
||||
- ✅ Modération possible (flags + signalements)
|
||||
- ✅ Légalement défendable (détection proactive + coopération avec autorités)
|
||||
- ✅ Pas de lecture systématique des messages
|
||||
|
||||
**CGU claires :**
|
||||
> "Les messages sont chiffrés. Nous ne pouvons pas les lire. Cependant, ils sont analysés localement (sur votre appareil) avant chiffrement pour détecter des comportements interdits. En cas de signalement, la conversation peut être examinée pour modération."
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Problème #6 : Paiements et identification
|
||||
|
||||
**Dilemme :**
|
||||
- Vous voulez de l'anonymat
|
||||
- Mais paiement par carte = identification obligatoire (Stripe connaît le vrai nom)
|
||||
|
||||
**✅ Solution : Séparation paiement / activité**
|
||||
|
||||
**Comment ça marche :**
|
||||
1. User clique "Acheter 50 tokens"
|
||||
2. Stripe crée un produit avec metadata : `{user_id: "hash_8x7f9a"}`
|
||||
3. User paie via Stripe (Stripe connaît "Jean Dupont")
|
||||
4. Webhook Stripe nous renvoie : "produit X payé"
|
||||
5. On credite les tokens à `user_id: "hash_8x7f9a"`
|
||||
|
||||
**Nous stockons :**
|
||||
```
|
||||
transactions:
|
||||
- stripe_payment_id: "pi_abc123"
|
||||
- amount: 50€
|
||||
- tokens_credited: 70
|
||||
- user_id: "hash_8x7f9a"
|
||||
- date
|
||||
```
|
||||
|
||||
**Ce qu'on ne stocke PAS :**
|
||||
- ❌ Le nom de l'acheteur
|
||||
- ❌ Son adresse
|
||||
- ❌ Sa carte bancaire
|
||||
- ❌ Le lien entre "Jean Dupont" et "hash_8x7f9a"
|
||||
|
||||
**Stripe garde tout ça de leur côté** (obligations légales).
|
||||
|
||||
**Avantages :**
|
||||
- ✅ On peut gérer les remboursements (via l'ID Stripe)
|
||||
- ✅ Comptabilité légale (on a les montants et dates)
|
||||
- ✅ Anonymat préservé sur la plateforme (les autres users ne savent pas qui vous êtes)
|
||||
|
||||
**Limite :**
|
||||
- En cas de mandat judiciaire, les autorités peuvent demander à Stripe l'identité réelle
|
||||
- **Mais c'est normal et légal** (on ne peut pas être complètement anonyme quand on paie)
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Problème #7 : Médias (photos/vidéos)
|
||||
|
||||
**Nouveau challenge :**
|
||||
- Texte = léger (1000 messages = 250 Ko)
|
||||
- Photos/vidéos = lourd (1 vidéo = 50-500 Mo)
|
||||
- Coûts et responsabilité explosent
|
||||
|
||||
**✅ Solution : Système "à la WeChat" (expiration rapide)**
|
||||
|
||||
**Règles :**
|
||||
- **Médias expirés après 14 jours** (suppression automatique)
|
||||
- **Cache local** (navigateur) : user peut garder les médias téléchargés sur son appareil
|
||||
- **Warning 24h avant expiration** : "3 médias seront supprimés demain, téléchargez-les si besoin"
|
||||
- **Limites strictes** : 5 Mo par image, 50 Mo par vidéo
|
||||
|
||||
**Avantages :**
|
||||
- ✅ Coûts maîtrisés (stockage plafonné)
|
||||
- ✅ Responsabilité limitée (pas de conservation longue durée)
|
||||
- ✅ 14 jours = largement suffisant pour un échange pro
|
||||
|
||||
**Pour le MVP :**
|
||||
- **Recommandation : Texte uniquement** pour valider le concept
|
||||
- Ajouter les médias en v2 si ça marche
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Problème #8 : Métadonnées (qui parle à qui)
|
||||
|
||||
**Ce qu'on sait quand même :**
|
||||
- User A a parlé à User B
|
||||
- Dernière activité : timestamp
|
||||
- (Pas le contenu des messages)
|
||||
|
||||
**Est-ce grave ?**
|
||||
- Pour les autorités : oui, ça peut suffire pour une enquête (analyse de réseau)
|
||||
- Pour la privacy : c'est un compromis acceptable (impossible de faire une messagerie sans savoir qui parle à qui)
|
||||
|
||||
**Solutions pour minimiser :**
|
||||
- **Stockage en "blob"** : on ne sait pas combien de messages, juste "une conversation existe"
|
||||
- **Suppression automatique après 6 mois** : pas de conservation abusive
|
||||
- **Pas de timestamps individuels** : juste "last_updated"
|
||||
|
||||
---
|
||||
|
||||
## 3. Nuances Légales Importantes
|
||||
|
||||
### 🔴 Vous DEVEZ consulter un avocat spécialisé
|
||||
|
||||
**Ce document n'est PAS un avis juridique.** Avant de lancer, consultez :
|
||||
- Un avocat en droit du numérique
|
||||
- Spécialisé RGPD + plateforme numérique
|
||||
- Idéalement expérience dans les marketplaces
|
||||
|
||||
### ⚖️ Points légaux critiques
|
||||
|
||||
**1. Statut juridique de la plateforme**
|
||||
|
||||
Vous êtes une **plateforme de mise en relation** (pas un prestataire de services).
|
||||
|
||||
**Conséquences :**
|
||||
- Vous n'êtes PAS responsable de la qualité des services rendus
|
||||
- Vous ÊTES responsable de modérer les contenus illégaux
|
||||
- Obligations : CGU claires, modération, coopération avec autorités
|
||||
|
||||
**2. Obligations de modération (DSA - Digital Services Act en Europe)**
|
||||
|
||||
Si vous dépassez un certain seuil d'utilisateurs (millions), obligations renforcées :
|
||||
- Modération proactive obligatoire
|
||||
- Transparence sur les algorithmes
|
||||
- Rapport annuel de modération
|
||||
|
||||
**Pour une petite plateforme :** obligations moindres, mais quand même :
|
||||
- Système de signalement fonctionnel
|
||||
- Traitement des signalements sous 24-48h
|
||||
- Retrait des contenus clairement illégaux
|
||||
|
||||
**3. Lutte anti-blanchiment (LAB)**
|
||||
|
||||
Si vous touchez de l'argent (tokens), dans certains pays :
|
||||
- Obligation de KYC (Know Your Customer) au-delà d'un certain montant
|
||||
- Déclarations Tracfin (France) si transactions suspectes
|
||||
|
||||
**Avec Stripe :** Ils gèrent une partie du KYC, mais vous devez quand même coopérer.
|
||||
|
||||
**4. RGPD (données personnelles)**
|
||||
|
||||
Même avec anonymisation :
|
||||
- Un hash d'email = donnée personnelle (reversible potentiellement)
|
||||
- Metadata des conversations = données personnelles
|
||||
- Obligations : consentement, droit d'accès, droit à l'effacement, portabilité
|
||||
|
||||
**Ce qu'il faut :**
|
||||
- Politique de confidentialité claire
|
||||
- CGU acceptées explicitement
|
||||
- Possibilité d'exporter ses données
|
||||
- Possibilité de supprimer son compte
|
||||
|
||||
**5. Responsabilité pénale**
|
||||
|
||||
**Si le site est utilisé massivement pour des activités illégales ET que vous n'avez rien fait pour l'empêcher** :
|
||||
|
||||
- Complicité possible (selon les cas)
|
||||
- Fermeture du site
|
||||
- Amendes
|
||||
- Prison (cas extrêmes)
|
||||
|
||||
**Votre défense :**
|
||||
- "Nous avons mis en place des systèmes de détection proactive"
|
||||
- "Nous avons modéré et banni les utilisateurs problématiques"
|
||||
- "Nous avons coopéré avec les autorités"
|
||||
- **Les logs de modération sont votre meilleure protection**
|
||||
|
||||
**6. Fiscalité**
|
||||
|
||||
- Déclaration de revenus (commissions/tokens)
|
||||
- TVA applicable (selon pays et montants)
|
||||
- Statut juridique de l'entreprise (SAS, SARL, auto-entrepreneur si début)
|
||||
|
||||
---
|
||||
|
||||
## 4. Réflexions Stratégiques
|
||||
|
||||
### 💡 Le vrai test : Validation du besoin
|
||||
|
||||
**Avant d'investir 6 mois de dev, il FAUT valider :**
|
||||
|
||||
**Côté prestataires (ceux qui paient) :**
|
||||
- Interroger 20-30 artisans/freelances (plombiers, électriciens, déménageurs, développeurs)
|
||||
- Question : "Vous paieriez 20€ pour accéder à 30 demandes de clients dans votre zone, sachant que max 4 autres pros verront chaque demande ?"
|
||||
- **Si 70%+ disent oui → go. Si 70%+ disent non → pivoter.**
|
||||
|
||||
**Côté demandeurs :**
|
||||
- Plus facile : si c'est gratuit, ils viendront
|
||||
- Mais faut s'assurer qu'ils reçoivent effectivement des réponses de qualité
|
||||
|
||||
**MVP ultra-light pour tester :**
|
||||
- Landing page avec formulaire : "Postez votre demande"
|
||||
- Groupe WhatsApp/Telegram avec des pros pour tester manuellement
|
||||
- Valide le concept en 2 semaines sans coder
|
||||
|
||||
---
|
||||
|
||||
### 💰 Modèle économique à challenger
|
||||
|
||||
**Calcul à la louche :**
|
||||
|
||||
**Pour être rentable (objectif : 5000€/mois) :**
|
||||
- Besoin de combien de pros actifs ?
|
||||
- Si un pro achète 50€ de tokens/mois en moyenne → besoin de 100 pros actifs
|
||||
- 100 pros × 30 tokens moyens = 3000 demandes débloquées/mois
|
||||
- Avec limite de 5 pros/demande → besoin de ~600 demandes publiées/mois (20/jour)
|
||||
|
||||
**Est-ce réaliste ?**
|
||||
- Faut atteindre une masse critique rapidement
|
||||
- Problème de l'œuf et la poule : pas de demandes = pas de pros, pas de pros = demandeurs insatisfaits
|
||||
|
||||
**Stratégie de lancement :**
|
||||
- Commencer hyper local (une ville, un secteur)
|
||||
- Par exemple : "Travaux à domicile à Lyon"
|
||||
- Marketing ciblé : Facebook Ads vers demandeurs (gratuit = facile), démarchage direct des artisans
|
||||
|
||||
---
|
||||
|
||||
### 🔄 Concurrence existante
|
||||
|
||||
**LeBonCoin :**
|
||||
- Gratuit pour tout le monde
|
||||
- Énorme base d'utilisateurs
|
||||
- Mais spam, arnaques, pas de garantie
|
||||
|
||||
**Votre différence :**
|
||||
- Demandes vérifiées (modération)
|
||||
- Pas de spam pour les demandeurs (limite 5 pros)
|
||||
- Pros paient = pros motivés et sérieux
|
||||
|
||||
**Bark, MyHammer, HomeAdvisor :**
|
||||
- Même logique (pros paient pour des leads)
|
||||
- Mais commission élevée (15-50€ par lead)
|
||||
- Modèle différent : paiement après mise en relation
|
||||
|
||||
**Votre avantage :**
|
||||
- Moins cher (1€/lead en moyenne vs 15-50€)
|
||||
- Transparent (le pro voit ce qu'il achète avant)
|
||||
|
||||
**TaskRabbit, Fiverr, Malt :**
|
||||
- Les demandeurs paient
|
||||
- Commission sur transaction
|
||||
- Marché différent (freelances en ligne surtout)
|
||||
|
||||
---
|
||||
|
||||
### 🚀 Stratégie de croissance
|
||||
|
||||
**Phase 1 : Tester le concept (mois 1-2)**
|
||||
- Landing page + formulaire
|
||||
- Test manuel avec 10 demandeurs, 10 pros
|
||||
- Validation : est-ce que ça match ? Les pros trouvent-ils de la valeur ?
|
||||
|
||||
**Phase 2 : MVP (mois 3-6)**
|
||||
- Développement version texte simple
|
||||
- 1 ville, 1 secteur (ex: travaux à Lyon)
|
||||
- Objectif : 50 demandeurs, 20 pros actifs
|
||||
|
||||
**Phase 3 : Amélioration (mois 7-12)**
|
||||
- Ajout médias, notifications avancées, app mobile
|
||||
- Extension à d'autres villes
|
||||
- Objectif : 500 demandeurs, 100 pros
|
||||
|
||||
**Phase 4 : Scale (an 2)**
|
||||
- Levée de fonds ? (si traction prouvée)
|
||||
- National, multi-secteurs
|
||||
- Features avancées (avis, réputation, abonnements)
|
||||
|
||||
---
|
||||
|
||||
## 5. Risques Identifiés
|
||||
|
||||
### 🔴 Risques majeurs
|
||||
|
||||
**1. Pas de product-market fit**
|
||||
- Les pros ne veulent pas payer pour des leads non garantis
|
||||
- **Mitigation : Valider AVANT de coder (interviews)**
|
||||
|
||||
**2. Masse critique non atteinte**
|
||||
- Pas assez de demandes → pros partent
|
||||
- Pas assez de pros → demandeurs insatisfaits
|
||||
- **Mitigation : Lancement hyper-local, marketing ciblé**
|
||||
|
||||
**3. Qualité des demandes**
|
||||
- Trop de fausses demandes → pros mécontents → bad reputation
|
||||
- **Mitigation : Modération stricte, remboursements si demande frauduleuse**
|
||||
|
||||
**4. Problèmes légaux**
|
||||
- Utilisation pour activités illégales → fermeture
|
||||
- **Mitigation : Modération proactive, logs, coopération autorités**
|
||||
|
||||
**5. Coûts d'acquisition clients**
|
||||
- Si trop cher d'acquérir des demandeurs/pros → pas rentable
|
||||
- **Mitigation : Gratuit pour demandeurs = acquisition organique + bouche-à-oreille**
|
||||
|
||||
### 🟡 Risques secondaires
|
||||
|
||||
**6. Concurrence des gros acteurs**
|
||||
- LeBonCoin pourrait copier le modèle
|
||||
- **Mitigation : Se nicher sur un secteur/zone précis, qualité de service**
|
||||
|
||||
**7. Complexité technique**
|
||||
- Chiffrement E2E, géolocalisation, modération = pas trivial
|
||||
- **Mitigation : Commencer simple (MVP sans médias), itérer**
|
||||
|
||||
**8. Support client**
|
||||
- Anonymisation = support compliqué
|
||||
- **Mitigation : Service support séparé, FAQ claire, onboarding soigné**
|
||||
|
||||
---
|
||||
|
||||
## 6. Budget Estimé
|
||||
|
||||
### 💸 Développement
|
||||
|
||||
**Option 1 : Vous développez (papa + éventuellement frère)**
|
||||
- Coût : temps (3-6 mois)
|
||||
- Stack : WordPress (si maîtrisé) ou Node.js + React (plus moderne)
|
||||
|
||||
**Option 2 : Freelance externe**
|
||||
- MVP complet : 10 000 - 25 000€ (selon pays/expérience)
|
||||
- Recherche : Malt, Upwork, Codeur.com
|
||||
|
||||
**Option 3 : Agence**
|
||||
- 30 000 - 80 000€ (overkill pour un MVP)
|
||||
|
||||
### 💸 Hébergement et services
|
||||
|
||||
**Année 1 (petit trafic) :**
|
||||
- Hébergement (Railway, DigitalOcean) : 20-50€/mois
|
||||
- Base de données PostgreSQL : inclus
|
||||
- Stripe : 1,5% + 0,25€ par transaction (coût variable)
|
||||
- Nom de domaine : 10-15€/an
|
||||
- SSL : gratuit (Let's Encrypt)
|
||||
- Email transactionnel (SendGrid, Mailgun) : gratuit jusqu'à 10k emails/mois
|
||||
|
||||
**Total année 1 : 300-700€** (hors dev)
|
||||
|
||||
**Année 2 (si ça scale) :**
|
||||
- Hébergement : 100-500€/mois (selon trafic)
|
||||
- Stockage médias (S3) : 50-200€/mois
|
||||
- Monitoring (Sentry, etc.) : 50€/mois
|
||||
- Support client (outil type Crisp) : 25€/mois
|
||||
|
||||
### 💸 Marketing
|
||||
|
||||
**Lancement :**
|
||||
- Facebook/Instagram Ads : 500-1000€ pour tester
|
||||
- Google Ads : 500-1000€
|
||||
- Flyers locaux, partenariats artisans : 300-500€
|
||||
|
||||
**Budget marketing initial recommandé : 2000-3000€**
|
||||
|
||||
---
|
||||
|
||||
## 7. Recommandations Finales
|
||||
|
||||
### ✅ Ce qui est solide
|
||||
|
||||
1. **Le système de tokens avec limite de 5 pros** résout le problème de scalabilité
|
||||
2. **L'architecture privacy-first** protège les utilisateurs et limite votre responsabilité
|
||||
3. **Le système de flags client-side** permet une modération sans lire les messages
|
||||
4. **Le modèle économique** est défendable (moins cher que les concurrents)
|
||||
|
||||
### ⚠️ Ce qui reste à valider
|
||||
|
||||
1. **Est-ce que les pros veulent vraiment payer ?** → Interviews obligatoires
|
||||
2. **Pouvez-vous atteindre la masse critique ?** → Stratégie marketing à affiner
|
||||
3. **La modération sera-t-elle suffisante ?** → À surveiller en prod, ajuster si besoin
|
||||
|
||||
### 🎯 Plan d'action recommandé
|
||||
|
||||
**Étape 1 : Validation (2 semaines)**
|
||||
- [ ] Créer une landing page simple
|
||||
- [ ] Interroger 20 artisans/freelances
|
||||
- [ ] Interroger 10 demandeurs potentiels
|
||||
- [ ] Décision go/no-go basée sur les retours
|
||||
|
||||
**Étape 2 : Légal (1 mois)**
|
||||
- [ ] Consulter un avocat spécialisé
|
||||
- [ ] Rédiger CGU/politique de confidentialité
|
||||
- [ ] Choisir statut juridique de l'entreprise
|
||||
- [ ] Ouvrir compte Stripe
|
||||
|
||||
**Étape 3 : MVP (3-4 mois)**
|
||||
- [ ] Développer version texte simple
|
||||
- [ ] Tester en beta fermée (50 users)
|
||||
- [ ] Itérer selon retours
|
||||
- [ ] Lancer publiquement sur 1 ville
|
||||
|
||||
**Étape 4 : Croissance (6-12 mois)**
|
||||
- [ ] Ajouter fonctionnalités (médias, notifs, app mobile)
|
||||
- [ ] Étendre géographiquement
|
||||
- [ ] Optimiser conversion et rétention
|
||||
- [ ] Décider : scale ou pivot
|
||||
|
||||
---
|
||||
|
||||
## 8. Conclusion
|
||||
|
||||
### Le projet est-il viable ?
|
||||
|
||||
**Techniquement : OUI**
|
||||
- Faisable avec les technos standard (Node.js, PostgreSQL, Stripe)
|
||||
- Architecture privacy-first solide
|
||||
- Modération réaliste
|
||||
|
||||
**Légalement : OUI (avec précautions)**
|
||||
- Consultation avocat obligatoire
|
||||
- Modération proactive nécessaire
|
||||
- CGU claires et appliquées
|
||||
|
||||
**Business : À VALIDER**
|
||||
- Le modèle est cohérent
|
||||
- Mais la vraie question : **est-ce que les pros veulent payer pour des leads non garantis ?**
|
||||
- **IMPOSSIBLE de répondre sans leur demander directement**
|
||||
|
||||
### Verdict
|
||||
|
||||
**Ne codez pas avant d'avoir validé le besoin avec de vrais utilisateurs.**
|
||||
|
||||
Si les interviews sont positives (70%+ de pros intéressés) :
|
||||
- ✅ Lancez un MVP simple et rapide
|
||||
- ✅ Testez sur une petite zone
|
||||
- ✅ Itérez selon les retours
|
||||
|
||||
Si les interviews sont négatives :
|
||||
- 🔄 Pivotez : inverser le modèle (demandeurs paient), commission sur transaction, ou autre
|
||||
|
||||
**La pire erreur serait de passer 6 mois à développer un produit que personne ne veut.**
|
||||
|
||||
---
|
||||
|
||||
## 9. Questions Ouvertes pour Discussion
|
||||
|
||||
1. **Papa, as-tu déjà parlé à des artisans/prestataires pour valider l'intérêt ?**
|
||||
2. **Budget disponible ?** (dev, marketing, légal)
|
||||
3. **Temps disponible ?** (dev en side-project ou full-time ?)
|
||||
4. **Expertise technique ?** (WordPress maîtrisé ? Node.js ? Besoin d'un dev externe ?)
|
||||
5. **Secteur cible pour le MVP ?** (travaux, services à domicile, freelance IT, autre ?)
|
||||
6. **Ville cible pour le lancement ?** (Paris, Lyon, Marseille, autre ?)
|
||||
7. **Vision long-terme ?** (side-project rentable ou ambition de scale national/international ?)
|
||||
|
||||
---
|
||||
|
||||
**Prêt à discuter et affiner le projet ensemble.**
|
||||
|
||||
**Alexis**
|
||||
|
||||
---
|
||||
|
||||
## 10. Historique des Échanges
|
||||
|
||||
### 16 octobre 2025 - Retour du père sur l'analyse
|
||||
|
||||
**Contexte :** Suite à l'analyse complète envoyée par Alexis, le père a répondu avec plusieurs points.
|
||||
|
||||
**Messages du père :**
|
||||
|
||||
1. **Proposition technique WordPress :**
|
||||
> "Pour continuer sur leboncoup, peut etre faut il continuer wordpress que je connais. Jai décris le projet a gemini qui m'a soumis des template cms wordpress qui pourraient déjà pas mal préparer le terrain. Regarde de ton côté. Il suggère une extension d'annonce, avec un extension de membres et une messagerie. Pose la question a claude"
|
||||
|
||||
2. **Incompréhension du problème de modèle économique :**
|
||||
> "! pourtant ca me paraissait pas mal ! regarde le bon coin !! il pourraient aussi avoir dus pam etc;;; et ils le font"
|
||||
|
||||
> "pour le 1, personnellement dans un pays en crise comme le notre, si tu prend mamie, vers qui peut elle se tourné si elle est seule et qu'elle a besoin de rentrer du bois ?"
|
||||
|
||||
> "2, prenons un gars lambda qui a juste ses deux bras, pas de structure, pas de voiture... comment peut il trouver un petit travail meme pour se faire 10 € ?"
|
||||
|
||||
3. **Minimisation des préoccupations légales/RGPD :**
|
||||
> "3 le probleme du paiemnt est un detail tres seriuex, mais a la limite o s'en fout, si on ne peux pas garantir l'anonymat, ben on le garanti pas set si le fisc nous demande des remontes d'infos, en admettant que la societe soit en france, ben on leur donne !"
|
||||
|
||||
> "Pour mon site, je ne me pose pas tant de questions que ca, on m'achete un article, je le vend et l'expedie et basta. pour le rgpd, ben il est gerer par wordpress avec les textes legaux..."
|
||||
|
||||
> "je crois que tu te prend la tete pour rien. on retrouve bien mon lili d'amour"
|
||||
|
||||
**Réponse d'Alexis (StillHammer) :**
|
||||
|
||||
> "Mais non mais c'est pas ça le problème. Je comprend que tu pense que je me prend la tête. Mais regarde, j'ai analyser systématiquement tout ce à quoi j'ai pu pensé. J'ai des solutions à tout les problèmes techniques, légaux et UX/UI"
|
||||
>
|
||||
> "Il ne reste que un seul prblème sans solution. Est ce que les pros vont payer ?"
|
||||
>
|
||||
> "La solution, je risque pas de la trouver en codant. C'est pas moi qui vais la trouver en testant le marché hein"
|
||||
>
|
||||
> "Si quelqu'un fait la validation marché je veux bien boser dessus mais sans validation marché ça sert à rien de s'engager dans le projet"
|
||||
>
|
||||
> "C'est quand même normal que je veuille que quelqu'un valide le seul problème du projet auquel j'ai pas de réponse, non ? (surtout que c'est la seul chose qui compte en plus. Est ce qu'on va faire de l'argent ?)"
|
||||
|
||||
**Réponse du père (incompréhension du marché cible) :**
|
||||
|
||||
> "Mais on veux pas des pros, on veux que des petits bricolou"
|
||||
|
||||
**Suite de la conversation :**
|
||||
|
||||
> "d'un autre coté, c'est aussi pour ca qu'il ne faut peut etre pas trop se tourmenter au debut. on a le prinicpe, il faut juste trouver uen solution minimal pur tenter l'aventure. d'ou mon idée d'utiliser un site wordpress qui dispose deja de modele de petites annonces et q'uil faut juste adapter a notre sauce"
|
||||
|
||||
---
|
||||
|
||||
### Analyse de la situation (par Alexis & Claude)
|
||||
|
||||
**Le problème fondamental identifié :**
|
||||
|
||||
Le père ne comprend pas que le **modèle économique inversé est le vrai risque du projet**, pas la complexité technique.
|
||||
|
||||
**Décalage de compréhension :**
|
||||
|
||||
1. **Papa pense :** "C'est trop compliqué (RGPD, sécu, etc.), utilisons WordPress pour simplifier"
|
||||
2. **Alexis sait :** "La technique est résolue. Le vrai problème : est-ce que les 'petits bricoleurs' vont payer pour des leads ?"
|
||||
|
||||
**Comparaison avec LeBonCoin (erreur du père) :**
|
||||
|
||||
- **LeBonCoin :** Publication ET réponse **gratuites**
|
||||
- **LeBonCoup :** Publication gratuite, réponse **payante** (inversé)
|
||||
- **Différence critique :** Les prestataires doivent payer **avant** de savoir si le lead est bon
|
||||
|
||||
**Cible "petits bricoleurs" (réponse du père) :**
|
||||
|
||||
- Papa dit : "On veut pas des pros, on veut des petits bricoleurs"
|
||||
- **Problème :** Ces petits bricoleurs sont encore MOINS susceptibles de payer que des pros établis
|
||||
- Un gars avec "juste ses deux bras" qui cherche 10€ ne va PAS payer 1-2€ par lead sans garantie
|
||||
|
||||
**Minimisation des risques légaux :**
|
||||
|
||||
Papa compare avec son site e-commerce ("je vends un article et basta") mais :
|
||||
- Une marketplace de services = responsabilité différente
|
||||
- Messagerie entre users = modération obligatoire (DSA)
|
||||
- "On s'en fout de l'anonymat" ne résout pas les obligations légales
|
||||
|
||||
**Position finale d'Alexis :**
|
||||
|
||||
**Refus conditionnel constructif :**
|
||||
- "Si quelqu'un fait la validation marché je veux bien bosser dessus"
|
||||
- "Sans validation marché ça sert à rien de s'engager dans le projet"
|
||||
- "C'est quand même normal que je veuille que quelqu'un valide le seul problème du projet auquel j'ai pas de réponse"
|
||||
|
||||
**Pourquoi c'est une bonne position :**
|
||||
|
||||
1. ✅ **Pas un refus sec** : Alexis reste ouvert si validation marché
|
||||
2. ✅ **Argument rationnel solide** : A résolu TOUS les problèmes sauf celui-là
|
||||
3. ✅ **Pose une condition claire** : Validation marché = pré-requis
|
||||
4. ✅ **Protège son temps** : Refuse de coder 6 mois pour un échec prévisible
|
||||
5. ✅ **Offre une alternative** : "Quelqu'un d'autre peut faire la validation, puis je code"
|
||||
|
||||
**Ce qu'Alexis a bien fait :**
|
||||
|
||||
- A écouté et analysé en profondeur (3 fichiers techniques complets)
|
||||
- A fourni des solutions à TOUS les problèmes techniques/légaux
|
||||
- A isolé le vrai risque (business model, pas technique)
|
||||
- A posé une limite claire sans fermer la porte
|
||||
- A gardé son calme face à "tu te prends la tête pour rien"
|
||||
|
||||
**Ce qu'Alexis doit maintenant faire :**
|
||||
|
||||
1. **Ne plus répondre** sur le projet tant qu'il n'y a pas de validation marché
|
||||
2. **Si papa insiste :** Répéter calmement "Je veux bien coder si tu me prouves que 10 bricoleurs acceptent de payer"
|
||||
3. **Ne pas se justifier davantage** : Il a déjà tout expliqué, c'est à papa de décider
|
||||
4. **Lâcher prise** : Ce n'est pas son projet, ce n'est pas son échec potentiel
|
||||
|
||||
**Statut du projet :**
|
||||
- ⏸️ **En pause** jusqu'à validation marché par quelqu'un d'autre
|
||||
- ❌ Alexis ne travaillera PAS dessus sans validation
|
||||
- ✅ Documentation complète disponible si jamais validation réussie
|
||||
339
Projects/LeBonCoup_Features.md
Normal file
339
Projects/LeBonCoup_Features.md
Normal file
@ -0,0 +1,339 @@
|
||||
# LeBonCoup - Spécifications Fonctionnelles
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Plateforme de petites annonces inversée : les demandeurs publient leurs besoins gratuitement, les prestataires paient pour accéder aux demandes via un système de tokens.
|
||||
|
||||
---
|
||||
|
||||
## 1. Système d'Utilisateurs
|
||||
|
||||
### 1.1 Types d'utilisateurs
|
||||
- **Demandeurs** : Publient des demandes de services (gratuit)
|
||||
- **Prestataires (Pros)** : Achètent des tokens pour accéder aux demandes
|
||||
|
||||
### 1.2 Inscription/Connexion
|
||||
- Email + mot de passe
|
||||
- Pas de nom/prénom obligatoire
|
||||
- Pseudonyme auto-généré : "User_8x7f9a"
|
||||
- Email **jamais** stocké en clair (hashé avec SHA256 + salt)
|
||||
- Mot de passe hashé (Argon2 ou bcrypt)
|
||||
|
||||
### 1.3 Récupération de compte
|
||||
- Service support séparé
|
||||
- User entre son email → système calcule le hash → trouve le compte
|
||||
- Reset password par email
|
||||
- **Attention** : Changement de mot de passe = suppression de toutes les conversations
|
||||
|
||||
---
|
||||
|
||||
## 2. Système de Tokens
|
||||
|
||||
### 2.1 Achat de tokens
|
||||
**Packs prépayés uniquement :**
|
||||
- 10€ = 10 tokens
|
||||
- 25€ = 30 tokens (+20% bonus)
|
||||
- 50€ = 70 tokens (+40% bonus)
|
||||
- 100€ = 150 tokens (+50% bonus)
|
||||
|
||||
**Paiement via Stripe :**
|
||||
- Carte bancaire
|
||||
- Apple Pay
|
||||
- Google Pay
|
||||
- PayPal (optionnel)
|
||||
|
||||
### 2.2 Utilisation des tokens
|
||||
|
||||
**1 token = accès à 1 demande**
|
||||
|
||||
**Tokens premium (optionnel v2) :**
|
||||
- 2 tokens = accès prioritaire
|
||||
- Permet de dépasser la limite de 5 pros (jusqu'à 6-7 max)
|
||||
|
||||
**Pas d'expiration des tokens** (ou très longue : 12 mois)
|
||||
|
||||
### 2.3 Remboursement automatique
|
||||
- Si demande devient "pleine" entre filtrage et déblocage → refund auto
|
||||
- Si demande signalée comme frauduleuse → refund
|
||||
- Si demandeur fantôme (aucune réponse après 7 jours) → refund partiel
|
||||
|
||||
---
|
||||
|
||||
## 3. Publication de Demandes
|
||||
|
||||
### 3.1 Création de demande (gratuit)
|
||||
**Champs obligatoires :**
|
||||
- Titre (max 100 caractères)
|
||||
- Description détaillée
|
||||
- Catégorie (liste prédéfinie : plomberie, électricité, déménagement, etc.)
|
||||
- Localisation (ville/arrondissement, floutée publiquement)
|
||||
- Budget min/max
|
||||
|
||||
**Limites anti-spam :**
|
||||
- Max 3 demandes actives simultanément par user
|
||||
- Modération automatique (scan de mots-clés suspects)
|
||||
- Review manuelle si détection de contenu suspect
|
||||
|
||||
### 3.2 Visibilité des demandes
|
||||
**Avant déblocage (pour les pros) :**
|
||||
- Nombre total de demandes correspondant aux filtres
|
||||
- **Aucun détail** (pas de titre, pas de preview)
|
||||
- Éventuellement : carte avec zones géographiques floutées (heatmap)
|
||||
|
||||
**Après déblocage :**
|
||||
- Titre complet
|
||||
- Description complète
|
||||
- Localisation précise
|
||||
- Budget
|
||||
- Date de publication
|
||||
- Nombre de pros ayant déjà contacté (X/5)
|
||||
|
||||
### 3.3 Cycle de vie d'une demande
|
||||
**États :**
|
||||
- **Active** : moins de 5 pros l'ont débloquée
|
||||
- **Full** : 5 pros (ou 7 avec premium) l'ont débloquée
|
||||
- **Resolved** : demandeur marque comme résolu
|
||||
- **Expired** : 30 jours sans activité
|
||||
- **Deleted** : supprimée par le demandeur ou admin
|
||||
|
||||
---
|
||||
|
||||
## 4. Système de Filtres (Pros)
|
||||
|
||||
### 4.1 Filtres disponibles
|
||||
- **Géolocalisation** : ville, département, rayon en km
|
||||
- **Catégories** : sélection multiple
|
||||
- **Budget** : fourchette min/max
|
||||
- **Date de publication** : dernières 24h, 7 jours, 30 jours
|
||||
- **Urgence** : tag "urgent" (optionnel)
|
||||
|
||||
### 4.2 Affichage après filtrage
|
||||
```
|
||||
🔍 37 demandes correspondent à vos critères
|
||||
|
||||
Aperçu géographique (optionnel) :
|
||||
- Paris 11e : 5 demandes
|
||||
- Paris 18e : 8 demandes
|
||||
- 93 Seine-Saint-Denis : 12 demandes
|
||||
- 94 Val-de-Marne : 12 demandes
|
||||
|
||||
Budget moyen : 300-800€
|
||||
|
||||
[Débloquer pour 37 tokens] [Débloquer en premium pour 74 tokens]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Messagerie Chiffrée
|
||||
|
||||
### 5.1 Architecture
|
||||
**Chiffrement de bout en bout (E2E) :**
|
||||
- Clé de chiffrement dérivée de `email_clair + password_clair` (côté client uniquement)
|
||||
- Messages stockés chiffrés sur le serveur
|
||||
- Serveur **ne peut pas** déchiffrer
|
||||
|
||||
**Stockage en "blob" :**
|
||||
- 1 conversation = 2 blobs chiffrés (1 pour chaque participant)
|
||||
- Chaque blob contient tout l'historique de la conversation
|
||||
- Pas de messages individuels stockés
|
||||
|
||||
### 5.2 Fonctionnalités messagerie
|
||||
- **Texte** : illimité
|
||||
- **Médias** (photos/vidéos - optionnel v2) :
|
||||
- Max 5 Mo par image
|
||||
- Max 50 Mo par vidéo
|
||||
- Stockage temporaire : 14 jours max
|
||||
- Cache client local (IndexedDB)
|
||||
|
||||
### 5.3 Notifications
|
||||
- Push notifications : "Nouveau message de Pro_8x7f9a"
|
||||
- Email notifications (opt-in)
|
||||
- Badge de messages non lus
|
||||
|
||||
### 5.4 Rétention des données
|
||||
**Conversations texte :**
|
||||
- Suppression automatique après **6 mois** d'inactivité
|
||||
- Warning 30 jours avant suppression
|
||||
- User peut exporter avant
|
||||
|
||||
**Médias :**
|
||||
- Suppression automatique après **14 jours**
|
||||
- Warning 24h avant expiration
|
||||
- User peut télécharger avant
|
||||
|
||||
**Changement de mot de passe :**
|
||||
- Suppression immédiate de tous les blobs de l'user
|
||||
- L'autre participant garde son blob (peut toujours lire)
|
||||
|
||||
---
|
||||
|
||||
## 6. Modération et Sécurité
|
||||
|
||||
### 6.1 Modération des demandes (publiques)
|
||||
**Scan automatique :**
|
||||
- Mots-clés interdits
|
||||
- Patterns suspects (combinaisons de mots)
|
||||
- Détection de services illégaux
|
||||
|
||||
**Actions :**
|
||||
- Flag pour review manuelle
|
||||
- Blocage immédiat si contenu clairement illégal
|
||||
- Ban du user
|
||||
|
||||
### 6.2 Modération des messages (privés)
|
||||
|
||||
**Système de "flags" client-side :**
|
||||
|
||||
**Avant chiffrement, scan local (JavaScript) :**
|
||||
- Détection de numéros de téléphone
|
||||
- Détection d'emails
|
||||
- Détection de réseaux sociaux (@instagram, etc.)
|
||||
- Mots-clés suspects : "cash", "espèces", "discret", "sans facture"
|
||||
- Combinaisons suspectes
|
||||
|
||||
**Flags envoyés au serveur (anonymes) :**
|
||||
```
|
||||
Conversation A-B : +2 flags (catégories: contact_externe, paiement_externe)
|
||||
```
|
||||
|
||||
**Le serveur ne voit PAS le contenu, juste les compteurs.**
|
||||
|
||||
**Actions automatiques par seuils :**
|
||||
- **10 flags** → Warning in-app
|
||||
- **25 flags** → Restriction temporaire (24h sans pouvoir envoyer de messages)
|
||||
- **50 flags** OU 3+ signalements → Ban automatique
|
||||
|
||||
### 6.3 Signalement par les users
|
||||
**User A signale User B :**
|
||||
- User A peut partager son blob déchiffré avec le support
|
||||
- Support review manuellement
|
||||
- Si confirmé problématique → ban de User B + refund des tokens
|
||||
|
||||
**User B n'est pas informé** que son compte est sous investigation.
|
||||
|
||||
---
|
||||
|
||||
## 7. Fonctionnalités Avancées (v2)
|
||||
|
||||
### 7.1 Système de réputation (optionnel)
|
||||
- Score de confiance basé sur :
|
||||
- Ancienneté du compte
|
||||
- Nombre de flags reçus
|
||||
- Tokens dépensés (pros) / demandes résolues (demandeurs)
|
||||
- Visible publiquement (par pseudonyme)
|
||||
|
||||
### 7.2 Tokens premium
|
||||
- 2 tokens pour accès prioritaire
|
||||
- Passe outre la limite de 5 pros (slots 6-7 réservés aux premium)
|
||||
|
||||
### 7.3 Abonnements
|
||||
- 50€/mois = 60 tokens + accès illimité aux demandes "basiques"
|
||||
- Tokens servent pour demandes "premium" (gros budgets)
|
||||
|
||||
### 7.4 Export de données
|
||||
- User peut télécharger toutes ses conversations (JSON ou PDF)
|
||||
- Export de l'historique de tokens
|
||||
- Conforme RGPD (droit à la portabilité)
|
||||
|
||||
---
|
||||
|
||||
## 8. MVP - Périmètre Minimal
|
||||
|
||||
### Inclure :
|
||||
✅ Inscription/connexion (email/password hashés)
|
||||
✅ Achat de tokens (Stripe, packs fixes)
|
||||
✅ Publication de demandes (gratuit, limite 3 actives)
|
||||
✅ Filtres (géo, catégorie, budget)
|
||||
✅ Système de déblocage avec tokens (max 5 pros)
|
||||
✅ Messagerie texte simple (blob chiffré)
|
||||
✅ Flags automatiques (modération soft)
|
||||
✅ Signalement users
|
||||
✅ Auto-refund si demande pleine
|
||||
✅ Suppression auto conversations > 6 mois
|
||||
|
||||
### Exclure du MVP :
|
||||
❌ Tokens premium
|
||||
❌ Médias (photos/vidéos)
|
||||
❌ Application mobile (web responsive suffit)
|
||||
❌ Système de notation/avis
|
||||
❌ Analytics avancés
|
||||
❌ Abonnements
|
||||
|
||||
---
|
||||
|
||||
## 9. CGU et Conformité
|
||||
|
||||
### 9.1 Mentions obligatoires
|
||||
|
||||
**Anonymat et privacy :**
|
||||
```
|
||||
- Vos échanges sont chiffrés de bout en bout
|
||||
- Nous ne pouvons pas lire vos messages
|
||||
- Votre email n'est jamais exposé publiquement
|
||||
- Pseudonymes utilisés sur la plateforme
|
||||
```
|
||||
|
||||
**Modération :**
|
||||
```
|
||||
- Les demandes publiques sont modérées automatiquement
|
||||
- Les messages sont analysés localement avant chiffrement
|
||||
pour détecter des comportements interdits
|
||||
- En cas de signalement, des actions peuvent être prises
|
||||
```
|
||||
|
||||
**Rétention des données :**
|
||||
```
|
||||
- Conversations supprimées après 6 mois d'inactivité
|
||||
- Médias supprimés après 14 jours
|
||||
- Warning avant suppression automatique
|
||||
- Changement de mot de passe = suppression de vos conversations
|
||||
```
|
||||
|
||||
**Paiements et remboursements :**
|
||||
```
|
||||
- Tokens sans expiration (12 mois de validité)
|
||||
- Remboursement automatique en cas de demande indisponible
|
||||
- Pas de remboursement si demande légitime mais non aboutie
|
||||
```
|
||||
|
||||
### 9.2 RGPD
|
||||
- Données minimales collectées (email hashé, pas de nom/prénom)
|
||||
- Droit à l'export des données
|
||||
- Droit à la suppression du compte
|
||||
- Pas de revente de données
|
||||
- Cookies strictement nécessaires uniquement
|
||||
|
||||
### 9.3 Légal
|
||||
- Responsabilité limitée : plateforme de mise en relation
|
||||
- Modération proactive (détection automatique)
|
||||
- Coopération avec les autorités si requis
|
||||
- Interdiction stricte d'activités illégales (prostitution, drogue, travail au noir)
|
||||
|
||||
---
|
||||
|
||||
## 10. Roadmap Suggérée
|
||||
|
||||
**Phase 1 - MVP (3-4 mois) :**
|
||||
- Inscription/auth
|
||||
- Tokens + Stripe
|
||||
- Demandes + filtres
|
||||
- Messagerie texte chiffrée
|
||||
- Modération basique
|
||||
|
||||
**Phase 2 - Amélioration (2-3 mois) :**
|
||||
- Médias (photos/vidéos)
|
||||
- Tokens premium
|
||||
- Système de réputation
|
||||
- Analytics
|
||||
|
||||
**Phase 3 - Scale (ongoing) :**
|
||||
- App mobile (React Native)
|
||||
- Abonnements
|
||||
- Notifications avancées
|
||||
- Support client amélioré
|
||||
|
||||
---
|
||||
|
||||
**Date de création :** 2025-01-16
|
||||
**Version :** 1.0
|
||||
**Statut :** Draft pour validation
|
||||
1025
Projects/LeBonCoup_Technical.md
Normal file
1025
Projects/LeBonCoup_Technical.md
Normal file
File diff suppressed because it is too large
Load Diff
926
Projects/MCP_Creative_Amplification.md
Normal file
926
Projects/MCP_Creative_Amplification.md
Normal file
@ -0,0 +1,926 @@
|
||||
# MCP Creative Amplification - Utilisation Générale
|
||||
|
||||
## TL;DR - Le Concept
|
||||
|
||||
**MCP (Model Context Protocol) permet de connecter Claude Code à n'importe quel outil, service ou source de données pour créer des workflows automatisés ultra-puissants.**
|
||||
|
||||
**En pratique :** Au lieu d'utiliser Claude Code seul, tu l'amplifies en lui donnant accès à :
|
||||
- APIs externes (DALL-E, Suno, n8n, Notion, etc.)
|
||||
- Bases de données
|
||||
- Services web
|
||||
- Outils locaux
|
||||
- Ton propre code/scripts
|
||||
|
||||
**Résultat :** Claude Code devient un orchestrateur qui peut contrôler ton écosystème digital complet.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Pourquoi MCP Change Tout
|
||||
|
||||
### Avant MCP
|
||||
```
|
||||
Tu → Claude Code → Répond avec du texte/code
|
||||
```
|
||||
|
||||
**Limitations :**
|
||||
- Claude isolé
|
||||
- Pas d'accès à tes outils
|
||||
- Workflow manuel
|
||||
- Copy/paste entre services
|
||||
|
||||
### Avec MCP
|
||||
```
|
||||
Tu → Claude Code → MCP → Tous tes outils
|
||||
↓
|
||||
Actions automatiques partout
|
||||
```
|
||||
|
||||
**Possibilités :**
|
||||
- Claude peut lire/écrire dans Notion
|
||||
- Claude peut déclencher workflows n8n
|
||||
- Claude peut générer images (DALL-E)
|
||||
- Claude peut analyser tes données
|
||||
- Claude peut contrôler tes apps
|
||||
|
||||
---
|
||||
|
||||
## 🌟 Use Cases Concrets
|
||||
|
||||
### 1. Content Creation Amplifiée
|
||||
|
||||
**Workflow article de blog :**
|
||||
|
||||
```
|
||||
Toi: "Claude, écris un article sur [sujet]"
|
||||
|
||||
Claude Code via MCP:
|
||||
1. Recherche web (MCP web search)
|
||||
2. Analyse sources pertinentes
|
||||
3. Rédige article markdown
|
||||
4. Génère image featured (DALL-E via MCP)
|
||||
5. Génère image d'illustration (DALL-E via MCP)
|
||||
6. Crée version audio (ElevenLabs via MCP)
|
||||
7. Publie sur ton CMS (WordPress/Ghost via MCP)
|
||||
8. Notifie sur Telegram (n8n via MCP)
|
||||
9. Ajoute à ta base Notion (Notion via MCP)
|
||||
|
||||
Temps total: 2-3 minutes
|
||||
(vs 2-3 heures manuellement)
|
||||
```
|
||||
|
||||
**Serveurs MCP nécessaires :**
|
||||
- dalle-mcp (images)
|
||||
- elevenlabs-mcp (audio)
|
||||
- wordpress-mcp (publication)
|
||||
- notion-mcp (tracking)
|
||||
- n8n-mcp (orchestration)
|
||||
|
||||
---
|
||||
|
||||
### 2. Research & Learning Automatisé
|
||||
|
||||
**Apprendre un nouveau sujet :**
|
||||
|
||||
```
|
||||
Toi: "Claude, crée-moi un cours complet sur [sujet]"
|
||||
|
||||
Claude Code via MCP:
|
||||
1. Web search (sources récentes)
|
||||
2. Fetch articles/docs pertinents
|
||||
3. Synthétise informations
|
||||
4. Structure en curriculum
|
||||
5. Génère flashcards Anki (anki-mcp)
|
||||
6. Crée mindmap visuelle (DALL-E)
|
||||
7. Génère exercices pratiques
|
||||
8. Crée quiz interactif
|
||||
9. Sauvegarde dans Obsidian (obsidian-mcp)
|
||||
10. Programme rappels spaced repetition (n8n)
|
||||
|
||||
Résultat: Cours structuré prêt à apprendre
|
||||
```
|
||||
|
||||
**Serveurs MCP utiles :**
|
||||
- websearch-mcp
|
||||
- anki-mcp
|
||||
- obsidian-mcp
|
||||
- dalle-mcp
|
||||
- n8n-mcp
|
||||
|
||||
---
|
||||
|
||||
### 3. Creative Brainstorming Multimodal
|
||||
|
||||
**Générer des idées pour projet :**
|
||||
|
||||
```
|
||||
Toi: "Claude, aide-moi à brainstorm un nouveau concept"
|
||||
|
||||
Claude Code via MCP:
|
||||
1. Questions socratiques pour clarifier vision
|
||||
2. Génère moodboard visuel (5 images DALL-E)
|
||||
3. Crée playlist inspirante (Suno/Spotify)
|
||||
4. Recherche projets similaires (web search)
|
||||
5. Analyse tendances actuelles
|
||||
6. Génère mind map des possibilités
|
||||
7. Propose 3 directions avec prototypes visuels
|
||||
8. Crée doc Notion structuré
|
||||
9. Programme session review dans 48h (n8n)
|
||||
|
||||
Output: Vision complète multi-sensorielle
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Automation Personnelle via n8n
|
||||
|
||||
**n8n comme hub central :**
|
||||
|
||||
```
|
||||
Claude Code
|
||||
↓ (MCP)
|
||||
n8n (orchestrateur)
|
||||
↓
|
||||
├→ Email
|
||||
├→ Calendar
|
||||
├→ Notion
|
||||
├→ Slack/Telegram
|
||||
├→ GitHub
|
||||
├→ APIs diverses
|
||||
└→ Bases de données
|
||||
```
|
||||
|
||||
**Exemples workflows déclenchés par Claude :**
|
||||
|
||||
```
|
||||
"Claude, planifie ma semaine"
|
||||
→ n8n: Analyse calendar → Notion tasks → Crée time blocks → Envoie résumé
|
||||
|
||||
"Claude, backup tout mon travail"
|
||||
→ n8n: GitHub repos → Google Drive → Notion export → Confirmation
|
||||
|
||||
"Claude, prépare ma newsletter"
|
||||
→ n8n: Fetch highlights semaine → Draft email → Images → Programme envoi
|
||||
|
||||
"Claude, analyse mes metrics"
|
||||
→ n8n: Pull data (analytics, finance, etc.) → Process → Charts → Report
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. Data Analysis Augmentée
|
||||
|
||||
**Analyser tes données avec contexte :**
|
||||
|
||||
```
|
||||
Toi: "Analyse mes dépenses du mois"
|
||||
|
||||
Claude Code via MCP:
|
||||
1. Se connecte à ta DB (postgres-mcp)
|
||||
2. Query transactions
|
||||
3. Analyse patterns
|
||||
4. Génère visualisations (matplotlib ou DALL-E)
|
||||
5. Compare avec mois précédents
|
||||
6. Identifie anomalies
|
||||
7. Suggère optimisations
|
||||
8. Crée rapport PDF
|
||||
9. Sauvegarde dans Notion
|
||||
10. Envoie résumé Telegram
|
||||
|
||||
Insight: "Tu dépenses 40% plus en food delivery qu'avant"
|
||||
```
|
||||
|
||||
**Serveurs MCP database :**
|
||||
- postgres-mcp
|
||||
- sqlite-mcp
|
||||
- mongodb-mcp
|
||||
- google-sheets-mcp
|
||||
|
||||
---
|
||||
|
||||
### 6. Productivity Dashboard Vivant
|
||||
|
||||
**Dashboard qui se met à jour automatiquement :**
|
||||
|
||||
```
|
||||
Claude Code (brain)
|
||||
↓ (MCP)
|
||||
Scheduled triggers (n8n, cron)
|
||||
↓
|
||||
Pull data de partout:
|
||||
├── GitHub (commits, PRs)
|
||||
├── Notion (tasks completed)
|
||||
├── Calendar (time spent)
|
||||
├── Finance (money tracking)
|
||||
├── Health (Strava, Apple Health)
|
||||
├── Learning (Anki, courses)
|
||||
└── Social (messages, interactions)
|
||||
↓
|
||||
Claude analyse + génère insights
|
||||
↓
|
||||
Update dashboard (Notion/Obsidian)
|
||||
↓
|
||||
Daily summary (Telegram)
|
||||
```
|
||||
|
||||
**Exemple output quotidien :**
|
||||
|
||||
```
|
||||
📊 Daily Summary - 14 Oct 2025
|
||||
|
||||
💻 Dev: 4h coding, 2 commits, 1 PR merged
|
||||
✅ Tasks: 7/10 completed (70%)
|
||||
📚 Learning: 30min, 15 flashcards
|
||||
💰 Money: +¥500 freelance, -¥120 food
|
||||
🏃 Health: 8k steps, 7h sleep
|
||||
🎯 Top win: Finished MCP integration prototype
|
||||
|
||||
⚠️ Alert: Behind on Warfactory (2 days)
|
||||
💡 Suggestion: Block 2h tomorrow for focused dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. Personal Knowledge Base Intelligent
|
||||
|
||||
**Obsidian/Notion augmenté par MCP :**
|
||||
|
||||
```
|
||||
Fonctionnalités:
|
||||
|
||||
1. Auto-linking
|
||||
- Tu écris une note
|
||||
- Claude trouve connections avec notes existantes
|
||||
- Crée liens automatiquement
|
||||
|
||||
2. Smart search
|
||||
- Query sémantique (pas juste keywords)
|
||||
- "Trouve toutes mes réflexions sur perfectionnisme"
|
||||
- Claude comprend contexte
|
||||
|
||||
3. Synthesis
|
||||
- "Résume tout ce que j'ai appris sur [sujet]"
|
||||
- Claude lit toutes tes notes
|
||||
- Génère synthèse complète
|
||||
|
||||
4. Gap detection
|
||||
- "Qu'est-ce que je ne sais pas encore sur [sujet]?"
|
||||
- Claude identifie trous dans knowledge
|
||||
- Suggère ressources
|
||||
|
||||
5. Memory recall
|
||||
- "Je cherche cette idée que j'avais eu en août"
|
||||
- Claude retrouve même avec description vague
|
||||
```
|
||||
|
||||
**Serveurs MCP :**
|
||||
- obsidian-mcp
|
||||
- notion-mcp
|
||||
- vectordb-mcp (embeddings)
|
||||
|
||||
---
|
||||
|
||||
### 8. Creative Assets à la Demande
|
||||
|
||||
**Génération multi-format :**
|
||||
|
||||
```
|
||||
Toi: "Crée des assets pour [projet]"
|
||||
|
||||
Claude Code génère:
|
||||
├── Images (DALL-E)
|
||||
│ ├── Logo variations
|
||||
│ ├── Backgrounds
|
||||
│ ├── Icons
|
||||
│ └── Illustrations
|
||||
├── Audio (ElevenLabs, Suno)
|
||||
│ ├── Voiceover
|
||||
│ ├── Music loops
|
||||
│ └── Sound effects
|
||||
├── Vidéo (via FFmpeg)
|
||||
│ ├── Intros/outros
|
||||
│ ├── Transitions
|
||||
│ └── Templates
|
||||
└── Text
|
||||
├── Copy marketing
|
||||
├── Scripts
|
||||
└── Documentation
|
||||
```
|
||||
|
||||
**Analyse automatique :**
|
||||
- Claude vérifie cohérence style
|
||||
- Valide qualité technique
|
||||
- Itère si nécessaire
|
||||
- Organise fichiers
|
||||
|
||||
---
|
||||
|
||||
### 9. Communication Augmentée
|
||||
|
||||
**Writing assistant contextuel :**
|
||||
|
||||
```
|
||||
EMAIL PROFESSIONNEL:
|
||||
Toi: "Réponds à cet email"
|
||||
Claude:
|
||||
- Analyse ton historique (email-mcp)
|
||||
- Comprend contexte relation
|
||||
- Draft réponse appropriée
|
||||
- Ton professionnel mais pas trop formel
|
||||
- Ajoute détails pertinents
|
||||
|
||||
MESSAGES PERSONNELS:
|
||||
Toi: "Aide-moi à répondre à Tingting"
|
||||
Claude:
|
||||
- Lit historique conversation
|
||||
- Comprend contexte émotionnel
|
||||
- Suggère réponse empathique
|
||||
- Adapte à ton style
|
||||
- Option français ou anglais
|
||||
```
|
||||
|
||||
**Serveurs MCP :**
|
||||
- gmail-mcp
|
||||
- telegram-mcp
|
||||
- slack-mcp
|
||||
|
||||
---
|
||||
|
||||
### 10. Project Management Automatisé
|
||||
|
||||
**Gestion projets sans effort :**
|
||||
|
||||
```
|
||||
Toi: "Status update sur tous mes projets"
|
||||
|
||||
Claude Code via MCP:
|
||||
1. Pull tasks (Notion, GitHub, Trello)
|
||||
2. Analyse progression
|
||||
3. Identifie blockers
|
||||
4. Suggère next actions
|
||||
5. Update timelines
|
||||
6. Génère rapport visuel
|
||||
7. Notifie stakeholders si besoin
|
||||
|
||||
AUSSI:
|
||||
- Auto-créer subtasks pour grandes tâches
|
||||
- Détecter dépendances
|
||||
- Réorganiser priorités
|
||||
- Estimer workload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 11. Learning Loops Automatiques
|
||||
|
||||
**Apprendre en continu :**
|
||||
|
||||
```
|
||||
SYSTÈME:
|
||||
Claude détecte gaps de connaissance pendant conversations
|
||||
↓
|
||||
Crée flashcards Anki automatiquement
|
||||
↓
|
||||
Schedule reviews (spaced repetition)
|
||||
↓
|
||||
Track progrès
|
||||
↓
|
||||
Ajuste difficulté
|
||||
↓
|
||||
Suggère ressources complémentaires
|
||||
|
||||
EXEMPLE:
|
||||
Tu: "C'est quoi un monad en programmation?"
|
||||
Claude: [Explique] + [Crée flashcard] + [Ajoute à learning path]
|
||||
3 jours plus tard: Reminder pour review
|
||||
1 semaine plus tard: Quiz pour valider
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 12. Health & Habits Tracking
|
||||
|
||||
**Quantified self automatisé :**
|
||||
|
||||
```
|
||||
INPUTS (via MCP):
|
||||
├── Apple Health (steps, sleep, heart)
|
||||
├── Strava (workouts)
|
||||
├── MyFitnessPal (nutrition)
|
||||
├── Calendar (time allocation)
|
||||
├── Mood tracking app
|
||||
└── Manual journal entries
|
||||
|
||||
CLAUDE ANALYSE:
|
||||
- Correlations (ex: sleep vs productivity)
|
||||
- Patterns (ex: stress peaks vendredi)
|
||||
- Trends (ex: workout consistency down)
|
||||
- Predictions (ex: burnout risk)
|
||||
|
||||
OUTPUTS:
|
||||
- Weekly health report
|
||||
- Habit suggestions
|
||||
- Interventions (ex: "Take a break")
|
||||
- Long-term tracking charts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture Générale MCP
|
||||
|
||||
### Modèle Mental
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ TOI (Human) │
|
||||
└─────────────┬───────────────────────┘
|
||||
│
|
||||
↓
|
||||
┌─────────────────────────────────────┐
|
||||
│ Claude Code (Brain) │
|
||||
│ - Reasoning │
|
||||
│ - Planning │
|
||||
│ - Orchestration │
|
||||
└─────────────┬───────────────────────┘
|
||||
│
|
||||
↓ (MCP Protocol)
|
||||
┌─────────────────────────────────────┐
|
||||
│ MCP Layer (Bridge) │
|
||||
│ - Protocol translation │
|
||||
│ - Authentication │
|
||||
│ - Rate limiting │
|
||||
└─────────────┬───────────────────────┘
|
||||
│
|
||||
┌─────┴─────┬─────────┬────────┐
|
||||
↓ ↓ ↓ ↓
|
||||
┌────────┐ ┌────────┐ ┌──────┐ ┌──────┐
|
||||
│ DALL-E │ │ n8n │ │Notion│ │ DB │
|
||||
└────────┘ └────────┘ └──────┘ └──────┘
|
||||
|
||||
┌────────┐ ┌────────┐ ┌──────┐ ┌──────┐
|
||||
│ Suno │ │ APIs │ │ Git │ │ ... │
|
||||
└────────┘ └────────┘ └──────┘ └──────┘
|
||||
```
|
||||
|
||||
### Types de Serveurs MCP
|
||||
|
||||
#### 1. Génération de contenu
|
||||
```
|
||||
- dalle-mcp (images)
|
||||
- suno-mcp (musique génération AI)
|
||||
- elevenlabs-mcp (voix)
|
||||
- claude-mcp (text avancé)
|
||||
```
|
||||
|
||||
#### 1b. Composition musicale (construction active)
|
||||
```
|
||||
- sonic-pi-mcp (live coding musique)
|
||||
- abhishekjairath/sonic-pi-mcp (Bun, OSC messages)
|
||||
- vinayak-mehta/mcp-sonic-pi (Python, plus simple)
|
||||
|
||||
- ableton-mcp (contrôle DAW pro)
|
||||
- FabianTinkl/AbletonMCP (MIDI, transport, paramètres)
|
||||
- adamjmurray/producer-pal (Max for Live)
|
||||
|
||||
- strudel-mcp (live coding browser)
|
||||
- williamzujkowski/strudel-mcp-server (40+ tools)
|
||||
|
||||
- supercollider-mcp (synthèse audio temps réel)
|
||||
- BradA1878/mcp-wave
|
||||
|
||||
- musescore-mcp (notation/partition)
|
||||
- jonbrantingham/musescore-mcp-server
|
||||
```
|
||||
|
||||
#### 2. Productivité
|
||||
```
|
||||
- notion-mcp
|
||||
- obsidian-mcp
|
||||
- gmail-mcp
|
||||
- calendar-mcp
|
||||
- trello-mcp
|
||||
- slack-mcp
|
||||
```
|
||||
|
||||
#### 3. Automation
|
||||
```
|
||||
- n8n-mcp (workflows)
|
||||
- zapier-mcp
|
||||
- ifttt-mcp
|
||||
```
|
||||
|
||||
#### 4. Données
|
||||
```
|
||||
- postgres-mcp
|
||||
- mongodb-mcp
|
||||
- sqlite-mcp
|
||||
- google-sheets-mcp
|
||||
- airtable-mcp
|
||||
```
|
||||
|
||||
#### 5. Dev tools
|
||||
```
|
||||
- github-mcp
|
||||
- docker-mcp
|
||||
- aws-mcp
|
||||
- vercel-mcp
|
||||
```
|
||||
|
||||
#### 6. Analysis
|
||||
```
|
||||
- pandas-mcp (data science)
|
||||
- matplotlib-mcp (viz)
|
||||
- jupyter-mcp
|
||||
```
|
||||
|
||||
#### 7. Communication
|
||||
```
|
||||
- telegram-mcp
|
||||
- discord-mcp
|
||||
- whatsapp-mcp
|
||||
- email-mcp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Comment Démarrer
|
||||
|
||||
### Étape 1 : Identifier ton besoin principal
|
||||
|
||||
**Questions à te poser :**
|
||||
- Quel outil j'utilise le plus ?
|
||||
- Quelle tâche répétitive je veux automatiser ?
|
||||
- Quel workflow me frustre ?
|
||||
|
||||
**Exemples :**
|
||||
- "J'utilise beaucoup Notion" → notion-mcp
|
||||
- "Je génère souvent des images" → dalle-mcp
|
||||
- "J'ai des workflows n8n complexes" → n8n-mcp
|
||||
|
||||
### Étape 2 : Installer ton premier serveur MCP
|
||||
|
||||
**Si serveur existe déjà :**
|
||||
```bash
|
||||
# Exemple avec Notion
|
||||
claude mcp add --transport http notion https://mcp.notion.com/mcp
|
||||
|
||||
# Liste tes serveurs
|
||||
claude mcp list
|
||||
```
|
||||
|
||||
**Si tu dois créer un serveur custom :**
|
||||
```bash
|
||||
# Serveur local simple
|
||||
claude mcp add --transport stdio my-tool -- node server.js
|
||||
```
|
||||
|
||||
### Étape 3 : Tester basiquement
|
||||
|
||||
```
|
||||
Dans Claude Code:
|
||||
"Claude, utilise [ton MCP] pour [action simple]"
|
||||
|
||||
Exemple:
|
||||
"Claude, crée une page Notion avec ma todo du jour"
|
||||
```
|
||||
|
||||
### Étape 4 : Construire des workflows
|
||||
|
||||
**Commence simple :**
|
||||
1 trigger → 1 action
|
||||
|
||||
**Puis complexifie :**
|
||||
1 trigger → multiple actions
|
||||
Multiple triggers → orchestration
|
||||
|
||||
**Exemple progression :**
|
||||
```
|
||||
Simple:
|
||||
"Génère une image" → DALL-E
|
||||
|
||||
Moyen:
|
||||
"Génère image + sauvegarde Notion + notifie Telegram"
|
||||
|
||||
Avancé:
|
||||
"Analyse mon mood → Génère playlist adaptée →
|
||||
Update health dashboard → Suggère activités"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Serveurs MCP Prioritaires pour Toi (Alexis)
|
||||
|
||||
### Tier 1 : Must-Have
|
||||
```
|
||||
1. n8n-mcp
|
||||
→ Tu as déjà n8n, c'est ton hub central
|
||||
|
||||
2. dalle-mcp
|
||||
→ Génération images (Warfactory, content)
|
||||
|
||||
3. notion-mcp (ou obsidian-mcp)
|
||||
→ Knowledge management
|
||||
```
|
||||
|
||||
### Tier 2 : High Value
|
||||
```
|
||||
4. suno-mcp
|
||||
→ Musique (Warfactory, ambiance)
|
||||
|
||||
5. telegram-mcp
|
||||
→ Notifications, communication
|
||||
|
||||
6. github-mcp
|
||||
→ Dev workflow
|
||||
```
|
||||
|
||||
### Tier 3 : Nice to Have
|
||||
```
|
||||
7. postgres-mcp
|
||||
→ Si tu veux analyser data
|
||||
|
||||
8. elevenlabs-mcp
|
||||
→ Voiceover, audio content
|
||||
|
||||
9. google-sheets-mcp
|
||||
→ Tracking simple
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Patterns de Workflow
|
||||
|
||||
### Pattern 1 : Hub & Spoke
|
||||
```
|
||||
Claude Code (hub)
|
||||
↓
|
||||
├→ Outil A
|
||||
├→ Outil B
|
||||
└→ Outil C
|
||||
|
||||
Use case: Actions indépendantes parallèles
|
||||
```
|
||||
|
||||
### Pattern 2 : Sequential Pipeline
|
||||
```
|
||||
Claude → Outil A → Outil B → Outil C → Output
|
||||
|
||||
Use case: Chaque étape dépend de la précédente
|
||||
Example: Recherche → Rédaction → Image → Publication
|
||||
```
|
||||
|
||||
### Pattern 3 : Orchestration via n8n
|
||||
```
|
||||
Claude → n8n → Multiple tools en parallèle
|
||||
↓
|
||||
Aggregation results
|
||||
↓
|
||||
Claude final processing
|
||||
|
||||
Use case: Workflows complexes avec branches
|
||||
```
|
||||
|
||||
### Pattern 4 : Feedback Loop
|
||||
```
|
||||
Claude → Action → Validation →
|
||||
↓ (if fail) ↓ (if pass)
|
||||
Correction → Success
|
||||
↑________________|
|
||||
|
||||
Use case: Itération jusqu'à qualité OK
|
||||
Example: Génération image + validation style
|
||||
```
|
||||
|
||||
### Pattern 5 : Event-Driven
|
||||
```
|
||||
External event → n8n → Claude Code → Actions
|
||||
|
||||
Use case: Réaction automatique
|
||||
Example: Nouveau email → Analyse → Draft réponse
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Mesurer l'Impact
|
||||
|
||||
### Metrics à tracker
|
||||
|
||||
**Temps gagné :**
|
||||
```
|
||||
Tâche avant MCP: X heures
|
||||
Tâche avec MCP: Y minutes
|
||||
→ Gain: Z%
|
||||
```
|
||||
|
||||
**Qualité output :**
|
||||
```
|
||||
- Cohérence
|
||||
- Complétude
|
||||
- Erreurs réduites
|
||||
```
|
||||
|
||||
**Créativité :**
|
||||
```
|
||||
- Nouvelles idées générées
|
||||
- Variations explorées
|
||||
- Prototypes créés
|
||||
```
|
||||
|
||||
**Mental load :**
|
||||
```
|
||||
- Moins de context switching
|
||||
- Moins de "où j'en étais?"
|
||||
- Moins de friction
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Pièges à Éviter
|
||||
|
||||
### 1. Over-automation
|
||||
**Problème :** Automatiser pour automatiser
|
||||
**Solution :** Automatise seulement ce qui est répétitif et chronophage
|
||||
|
||||
### 2. Complexité inutile
|
||||
**Problème :** Workflows trop compliqués
|
||||
**Solution :** Commence simple, complexifie si besoin réel
|
||||
|
||||
### 3. Dépendance excessive
|
||||
**Problème :** Ne plus savoir faire sans MCP
|
||||
**Solution :** Garde compétences de base, MCP = amplificateur
|
||||
|
||||
### 4. Coûts API non suivis
|
||||
**Problème :** Factures surprises
|
||||
**Solution :** Set budgets, track usage, optimize
|
||||
|
||||
### 5. Sécurité négligée
|
||||
**Problème :** API keys exposées
|
||||
**Solution :** Secrets management, scopes limités
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Philosophie d'Utilisation
|
||||
|
||||
### MCP comme "Bicycle for the Mind"
|
||||
|
||||
**Steve Jobs :** "Computer is a bicycle for the mind"
|
||||
**MCP :** Version 2.0 de ce concept
|
||||
|
||||
```
|
||||
Sans MCP:
|
||||
Idée → Execution manuelle → Résultat
|
||||
(lent, friction, limité)
|
||||
|
||||
Avec MCP:
|
||||
Idée → Claude + MCP → Résultat
|
||||
(rapide, fluide, amplifié)
|
||||
```
|
||||
|
||||
### Hybrid Intelligence
|
||||
|
||||
**Pas "AI replace human"**
|
||||
**Mais "AI amplifies human"**
|
||||
|
||||
```
|
||||
Tu apportes:
|
||||
- Vision
|
||||
- Jugement
|
||||
- Créativité
|
||||
- Contexte
|
||||
|
||||
Claude + MCP apportent:
|
||||
- Execution
|
||||
- Scale
|
||||
- Vitesse
|
||||
- Consistency
|
||||
```
|
||||
|
||||
**Résultat :** Superpowers
|
||||
|
||||
---
|
||||
|
||||
## 🌊 Vision Future
|
||||
|
||||
### Ce qui arrive
|
||||
|
||||
**Multi-agent systems :**
|
||||
```
|
||||
Claude + MCP ne sera pas seul
|
||||
→ Écosystème d'agents spécialisés
|
||||
→ Collaboration automatique
|
||||
→ Émergence de capacités
|
||||
```
|
||||
|
||||
**Apprentissage continu :**
|
||||
```
|
||||
MCP systems qui apprennent de toi
|
||||
→ Optimisent workflows
|
||||
→ Anticipent besoins
|
||||
→ "Style Alexis" émerge naturellement
|
||||
```
|
||||
|
||||
**Interfaces naturelles :**
|
||||
```
|
||||
Voix → MCP → Actions
|
||||
Pensées → MCP → Création
|
||||
(via brain-computer interfaces éventuellement)
|
||||
```
|
||||
|
||||
**Créativité augmentée :**
|
||||
```
|
||||
Humain + AI = Créations impossibles autrement
|
||||
→ Nouveaux médias
|
||||
→ Nouveaux art forms
|
||||
→ Nouvelles façons de penser
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps pour Toi
|
||||
|
||||
### Immédiat (Cette semaine)
|
||||
```
|
||||
☐ Identifie 1 tâche répétitive à automatiser
|
||||
☐ Choisis le serveur MCP correspondant
|
||||
☐ Installe-le (claude mcp add)
|
||||
☐ Teste workflow basique
|
||||
☐ Documente ce qui marche/marche pas
|
||||
```
|
||||
|
||||
### Court terme (Ce mois)
|
||||
```
|
||||
☐ Ajoute 2-3 serveurs MCP supplémentaires
|
||||
☐ Crée 3 workflows utiles quotidiens
|
||||
☐ Connecte n8n avec Claude Code
|
||||
☐ Mesure temps gagné
|
||||
☐ Partage retour d'expérience (Tingting?)
|
||||
```
|
||||
|
||||
### Moyen terme (3 mois)
|
||||
```
|
||||
☐ Écosystème MCP complet pour ton workflow
|
||||
☐ Automation de 50%+ tâches répétitives
|
||||
☐ Creative workflows (Warfactory assets?)
|
||||
☐ Knowledge base intelligent (Obsidian/Notion)
|
||||
☐ Peut-être: Custom MCP servers pour besoins spécifiques
|
||||
```
|
||||
|
||||
### Long terme (6+ mois)
|
||||
```
|
||||
☐ MCP comme extension naturelle de ta pensée
|
||||
☐ Workflows si optimisés qu'ils sont invisibles
|
||||
☐ Créativité amplifiée 10x
|
||||
☐ Peut-être: Enseigner ton système à autres (blog, vidéos?)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Ressources
|
||||
|
||||
### Documentation
|
||||
- MCP Protocol: https://modelcontextprotocol.io
|
||||
- Claude Code MCP docs: https://docs.claude.com/claude-code/mcp
|
||||
|
||||
### Inspiration
|
||||
- n8n workflows: https://n8n.io/workflows
|
||||
- Notion templates: notion.so/templates
|
||||
- Obsidian plugins: obsidian.md/plugins
|
||||
|
||||
### Communauté
|
||||
- Reddit: r/ClaudeCode, r/n8n
|
||||
- Discord: Claude AI, n8n community
|
||||
- GitHub: MCP servers repos
|
||||
|
||||
---
|
||||
|
||||
## 💭 Réflexion Finale
|
||||
|
||||
**MCP n'est pas juste un outil technique.**
|
||||
|
||||
C'est un **shift de mindset** :
|
||||
|
||||
De :
|
||||
- "Je dois tout faire manuellement"
|
||||
- "C'est compliqué donc je procrastine"
|
||||
- "Je suis limité par mon temps/skills"
|
||||
|
||||
Vers :
|
||||
- "Je pense, l'AI exécute"
|
||||
- "La complexité est gérable avec automation"
|
||||
- "Mes limites sont maintenant bien plus loin"
|
||||
|
||||
**Question centrale :**
|
||||
|
||||
*"Si je pouvais déléguer parfaitement toute tâche répétitive/technique à un assistant infatigable, qu'est-ce que je créerais ?"*
|
||||
|
||||
**MCP + Claude Code rend ça possible.**
|
||||
|
||||
---
|
||||
|
||||
**Document créé le :** 2025-10-14
|
||||
**Auteur :** Alexis (avec Claude Code)
|
||||
**Status :** Guide complet
|
||||
**Next update :** Après premiers tests MCP
|
||||
|
||||
---
|
||||
|
||||
*"Amplify your mind, automate the rest."*
|
||||
698
Projects/MCP_Game_Asset_Pipeline.md
Normal file
698
Projects/MCP_Game_Asset_Pipeline.md
Normal file
@ -0,0 +1,698 @@
|
||||
# MCP Game Asset Pipeline - Vision Masterclass
|
||||
|
||||
## TL;DR - Le Concept
|
||||
|
||||
**Pipeline créatif AI-powered pour génération et intégration automatique d'assets de jeu en temps réel, avec découverte émergente de gameplay.**
|
||||
|
||||
Un système où :
|
||||
- Le jeu génère du contenu en réponse aux actions du joueur
|
||||
- Les dessins vectoriels deviennent des assets pixel-perfect
|
||||
- Claude Code orchestre DALL-E, Suno, et autres AIs via MCP
|
||||
- Hot-reload permet l'intégration immédiate sans interruption
|
||||
- Le gameplay émerge de la création
|
||||
|
||||
**Status:** Concept / Vision (pas encore implémenté)
|
||||
**Application cible:** Warfactory (extensible à tout jeu modulaire)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Vision Globale
|
||||
|
||||
### Le Problème
|
||||
Créer des assets de jeu (sprites, musique, SFX) est :
|
||||
- Chronophage
|
||||
- Requiert compétences techniques variées
|
||||
- Pipeline lourd (design → création → intégration → test)
|
||||
- Itération lente
|
||||
- Limite la créativité par friction
|
||||
|
||||
### La Solution : MCP + AI + Hot-Reload
|
||||
|
||||
**Pipeline unifié orchestré par Claude Code via MCP :**
|
||||
|
||||
```
|
||||
Intention créative (humain)
|
||||
↓
|
||||
Claude Code (analyse + orchestration)
|
||||
↓ (MCP)
|
||||
AIs spécialisées (DALL-E, Suno, etc.)
|
||||
↓
|
||||
Validation automatique
|
||||
↓
|
||||
Hot-reload dans le jeu
|
||||
↓
|
||||
Gameplay émergent
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
### Layer 1 : Game Engine (Warfactory/Godot)
|
||||
```
|
||||
- Système modulaire + JSON config
|
||||
- Hot-reload de modules
|
||||
- Event system (découvertes, combos, etc.)
|
||||
- MCP client intégré
|
||||
```
|
||||
|
||||
### Layer 2 : MCP Protocol
|
||||
```
|
||||
Serveurs MCP spécialisés :
|
||||
├── dalle-mcp # Génération images
|
||||
├── suno-mcp # Génération musique
|
||||
├── music-analyzer # Analyse audio (Essentia)
|
||||
├── asset-validator # Validation technique
|
||||
└── discovery-engine # Émergence gameplay
|
||||
```
|
||||
|
||||
### Layer 3 : Orchestration (Claude Code)
|
||||
```
|
||||
- Analyse contexte créatif
|
||||
- Génération prompts optimisés
|
||||
- Validation multi-critères
|
||||
- Itération automatique
|
||||
- Gestion workflow complet
|
||||
```
|
||||
|
||||
### Layer 4 : Integration (n8n optionnel)
|
||||
```
|
||||
- Centralisation workflows
|
||||
- Logs et monitoring
|
||||
- Storage et versioning
|
||||
- Notifications
|
||||
- Gestion coûts API
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Use Cases Masterclass
|
||||
|
||||
### 1. Discovery Loop - Émergence Gameplay
|
||||
|
||||
**Concept :** Le jeu génère du nouveau contenu basé sur les actions du joueur.
|
||||
|
||||
```
|
||||
IN-GAME EVENT:
|
||||
Player découvre combo ["fire", "metal", "steam"]
|
||||
dans "industrial_zone"
|
||||
↓
|
||||
MCP EVENT:
|
||||
{
|
||||
"type": "combo_discovered",
|
||||
"elements": ["fire", "metal", "steam"],
|
||||
"context": "industrial_zone",
|
||||
"player_style": "aggressive_builder"
|
||||
}
|
||||
↓
|
||||
CLAUDE CODE REASONING:
|
||||
"Combo fire+metal+steam + zone industrielle + joueur agressif
|
||||
→ Je génère une 'War Forge'
|
||||
→ Stats: +production +défense -ressources
|
||||
→ Style: Dark industrial fantasy"
|
||||
↓
|
||||
ASSET GENERATION:
|
||||
- Building sprite (DALL-E)
|
||||
- SFX forge + steam (ElevenLabs)
|
||||
- Particle config (auto)
|
||||
- JSON config
|
||||
↓
|
||||
HOT-RELOAD:
|
||||
3 secondes → Nouveau bâtiment disponible in-game!
|
||||
↓
|
||||
PLAYER EXPERIENCE:
|
||||
"WTF je viens de débloquer quelque chose d'inédit!"
|
||||
```
|
||||
|
||||
**Impact :** Gameplay unique, rejouabilité infinie, émergence réelle.
|
||||
|
||||
---
|
||||
|
||||
### 2. Vectorial Workflow - Dessin → Asset
|
||||
|
||||
**Concept :** Transformer dessins vectoriels en assets pixel-perfect.
|
||||
|
||||
```
|
||||
PHASE 1: CAPTURE
|
||||
Tingting/Alexis dessine sur iPad (Procreate/Concepts)
|
||||
- Dessin vectoriel propre
|
||||
- Annotations textuelles ("glow here", "aggressive look", "faction red")
|
||||
↓
|
||||
PHASE 2: ANALYSE (MCP → Claude Code)
|
||||
Parse SVG:
|
||||
- Formes: "3 cylindres, 2 sphères, base rectangulaire"
|
||||
- Style: "Lignes épaisses = bold, courbes = organique"
|
||||
- Annotations: "Glow effect, style agressif, couleur faction rouge"
|
||||
- Proportions: Ratios exacts
|
||||
↓
|
||||
PHASE 3: PROMPT GENERATION
|
||||
"Game asset, isometric view, [formes détectées],
|
||||
[style inféré], [annotations],
|
||||
low-poly aesthetic, clean edges, game-ready,
|
||||
style guide: Warfactory industrial"
|
||||
↓
|
||||
PHASE 4: GENERATION
|
||||
DALL-E génère l'asset
|
||||
↓
|
||||
PHASE 5: VALIDATION
|
||||
- Overlay vectoriel sur résultat DALL-E
|
||||
- Compare proportions (tolérance 5%)
|
||||
- Vérifie annotations respectées
|
||||
- Score de match: 0-100%
|
||||
↓
|
||||
PHASE 6: ITERATION
|
||||
Si score < 85%:
|
||||
- Corrections précises dans prompt
|
||||
- Régénération
|
||||
- Re-validation
|
||||
Loop jusqu'à satisfaction
|
||||
↓
|
||||
PHASE 7: FINALIZATION
|
||||
Asset parfait + metadata + versioning
|
||||
→ Ready for game
|
||||
```
|
||||
|
||||
**Impact :** Vision artistique humaine + Qualité technique IA = Hybrid creativity sans friction.
|
||||
|
||||
---
|
||||
|
||||
### 3. Pipeline Complet : Concept → Playable
|
||||
|
||||
**Commande unique :**
|
||||
```
|
||||
"Claude, ajoute une unité 'Steampunk Tank' à Warfactory"
|
||||
```
|
||||
|
||||
**Exécution automatique :**
|
||||
|
||||
```
|
||||
1. DESIGN DOC
|
||||
- Analyse gameplay existant
|
||||
- Propose stats équilibrées
|
||||
- Définit rôle tactique
|
||||
- Écrit description lore
|
||||
|
||||
2. ASSETS VISUELS
|
||||
- Sprite idle
|
||||
- Sprite move
|
||||
- Sprite attack
|
||||
- Sprite death
|
||||
- Particle effects config
|
||||
|
||||
3. ASSETS AUDIO
|
||||
- SFX engine
|
||||
- SFX attack
|
||||
- SFX destruction
|
||||
- Musique thème (optionnel)
|
||||
|
||||
4. CODE
|
||||
- Script unité Godot/Unity
|
||||
- Behaviour tree IA
|
||||
- Tests unitaires
|
||||
|
||||
5. INTEGRATION
|
||||
- JSON config
|
||||
- Balance pass
|
||||
- Documentation
|
||||
|
||||
6. DELIVERY
|
||||
- Commit git avec preview
|
||||
- PR avec screenshots
|
||||
- Changelog généré
|
||||
|
||||
TEMPS TOTAL: ~5-10 minutes
|
||||
(vs plusieurs jours manuellement)
|
||||
```
|
||||
|
||||
**Impact :** De l'idée au prototype jouable en une commande.
|
||||
|
||||
---
|
||||
|
||||
### 4. Asset Variants Automatiques
|
||||
|
||||
**Un prompt → Multiples variations :**
|
||||
|
||||
```
|
||||
INPUT:
|
||||
"Génère un building 'Factory' pour Warfactory"
|
||||
|
||||
OUTPUT AUTOMATIQUE:
|
||||
├── factory_base.png # Version de base
|
||||
├── factory_damaged_1.png # Légèrement endommagé
|
||||
├── factory_damaged_2.png # Très endommagé
|
||||
├── factory_destroyed.png # Ruines
|
||||
├── factory_upgraded_t2.png # Amélioration tier 2
|
||||
├── factory_upgraded_t3.png # Amélioration tier 3
|
||||
├── factory_faction_red.png # Variant faction rouge
|
||||
├── factory_faction_blue.png # Variant faction bleue
|
||||
└── factory_spritesheet.png # Spritesheet assemblée
|
||||
|
||||
+ JSON config avec tous les états
|
||||
+ Metadata (prompts, versions, style guide match)
|
||||
```
|
||||
|
||||
**Impact :** Un asset → Ecosystem complet en une passe.
|
||||
|
||||
---
|
||||
|
||||
### 5. Adaptive Music System
|
||||
|
||||
**Concept :** Musique qui s'adapte au gameplay en temps réel.
|
||||
|
||||
```
|
||||
PHASE 1: ANALYSE GAMEPLAY
|
||||
Claude Code analyse la scène Warfactory:
|
||||
- Rythme: Combat intense / Construction calme / Exploration
|
||||
- Tension: Score de danger
|
||||
- Progression: Early/Mid/Late game
|
||||
|
||||
PHASE 2: GENERATION LAYERS
|
||||
Génère musique avec layers séparés:
|
||||
├── base_ambient.mp3 # Layer ambiance (toujours actif)
|
||||
├── rhythm_construction.mp3 # Layer construction
|
||||
├── tension_combat.mp3 # Layer combat
|
||||
└── climax_boss.mp3 # Layer moments clés
|
||||
|
||||
PHASE 3: ANALYSE AUDIO
|
||||
Essentia analyse chaque layer:
|
||||
- BPM synchronisé
|
||||
- Tonalité cohérente
|
||||
- Points de transition
|
||||
- Energy levels
|
||||
|
||||
PHASE 4: INTEGRATION
|
||||
Système audio adaptatif:
|
||||
- Transitions seamless entre layers
|
||||
- Crossfade selon état jeu
|
||||
- Dynamic mixing
|
||||
|
||||
PHASE 5: TEST
|
||||
Simule scenarios:
|
||||
- Construction → Combat : Transition smooth?
|
||||
- Combat → Victoire : Climax works?
|
||||
```
|
||||
|
||||
**Impact :** OST unique pour chaque partie, adapté au style du joueur.
|
||||
|
||||
---
|
||||
|
||||
### 6. AI Art Director Persistant
|
||||
|
||||
**Concept :** Style guide auto-maintenu qui assure cohérence visuelle.
|
||||
|
||||
```
|
||||
STYLE GUIDE WARFACTORY:
|
||||
{
|
||||
"palette": {
|
||||
"primary": ["#2C3E50", "#E74C3C", "#95A5A6"],
|
||||
"factions": {
|
||||
"red": ["#C0392B", "#E74C3C"],
|
||||
"blue": ["#2980B9", "#3498DB"]
|
||||
}
|
||||
},
|
||||
"style": {
|
||||
"aesthetic": "low-poly industrial",
|
||||
"line_weight": "bold",
|
||||
"lighting": "top-down 45°",
|
||||
"saturation": "medium-low",
|
||||
"contrast": "high"
|
||||
},
|
||||
"proportions": {
|
||||
"building_height": "1.2-1.8x base",
|
||||
"unit_scale": "0.3-0.5x building",
|
||||
"detail_level": "medium"
|
||||
},
|
||||
"rules": [
|
||||
"Edges must be clean",
|
||||
"No gradients",
|
||||
"Max 3 main colors per asset",
|
||||
"Consistent perspective"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Workflow avec Art Director :**
|
||||
|
||||
```
|
||||
1. Nouveau asset généré
|
||||
↓
|
||||
2. Claude Code vérifie conformité style guide
|
||||
↓
|
||||
3. Score de match: 0-100%
|
||||
↓
|
||||
4. Si < 80% : Rejection + corrections spécifiques
|
||||
↓
|
||||
5. Si 80-95% : Ajustements mineurs
|
||||
↓
|
||||
6. Si > 95% : Approved
|
||||
↓
|
||||
7. Style guide mis à jour si nouveau pattern validé manuellement
|
||||
```
|
||||
|
||||
**Impact :** Cohérence visuelle automatique, pas de "ça ressemble pas au jeu".
|
||||
|
||||
---
|
||||
|
||||
### 7. Collaborative Creation (Alexis + Tingting)
|
||||
|
||||
**Workflow couple :**
|
||||
|
||||
```
|
||||
SCENARIO 1: Tingting dessine concept
|
||||
↓
|
||||
Upload vers n8n
|
||||
↓
|
||||
Claude Code analyse + génère variations
|
||||
↓
|
||||
Notification Telegram: "3 variations prêtes"
|
||||
↓
|
||||
Tingting/Alexis votent sur préférée
|
||||
↓
|
||||
Production automatique assets finaux
|
||||
↓
|
||||
Commit git avec "Co-created by Tingting & Alexis"
|
||||
|
||||
SCENARIO 2: Brainstorming vocal
|
||||
↓
|
||||
Audio transcrit (Whisper)
|
||||
↓
|
||||
Claude extrait idées
|
||||
↓
|
||||
Génère moodboard visuel + audio
|
||||
↓
|
||||
Review ensemble
|
||||
↓
|
||||
Sélection collaborative
|
||||
↓
|
||||
Pipeline complet se lance
|
||||
```
|
||||
|
||||
**Impact :** Création de couple, outils pour collaborer artistiquement.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Stack Technique
|
||||
|
||||
### MCP Servers à créer
|
||||
|
||||
#### 1. dalle-mcp
|
||||
```
|
||||
Tools exposés:
|
||||
- generate_image(prompt, style_guide, size)
|
||||
- generate_variations(base_image, count)
|
||||
- analyze_image(image) → description
|
||||
- compare_images(img1, img2) → similarity score
|
||||
```
|
||||
|
||||
#### 2. suno-mcp
|
||||
```
|
||||
Tools exposés:
|
||||
- generate_music(prompt, duration, style)
|
||||
- generate_layers(base_track, layer_types)
|
||||
- extend_track(track, duration)
|
||||
```
|
||||
|
||||
#### 3. music-analyzer-mcp
|
||||
```
|
||||
Tools exposés (Essentia):
|
||||
- analyze_audio(file) → tempo, key, energy, mood
|
||||
- check_sync(track1, track2) → compatibility
|
||||
- find_transitions(track) → transition points
|
||||
```
|
||||
|
||||
#### 4. asset-validator-mcp
|
||||
```
|
||||
Tools exposés:
|
||||
- validate_sprite(image, specs) → pass/fail + issues
|
||||
- check_style_guide(image, guide) → score
|
||||
- generate_spritesheet(images, layout)
|
||||
```
|
||||
|
||||
#### 5. discovery-engine-mcp
|
||||
```
|
||||
Tools exposés:
|
||||
- analyze_combo(elements, context) → suggestions
|
||||
- generate_concept(discovery_event) → design doc
|
||||
- balance_stats(entity, game_state) → balanced stats
|
||||
```
|
||||
|
||||
### Integration Points
|
||||
|
||||
#### Warfactory (Godot)
|
||||
```gdscript
|
||||
# MCP Event emitter
|
||||
func on_discovery(combo: Array, context: String):
|
||||
var event = {
|
||||
"type": "combo_discovered",
|
||||
"elements": combo,
|
||||
"context": context,
|
||||
"player_stats": get_player_stats()
|
||||
}
|
||||
MCPClient.emit_event(event)
|
||||
|
||||
# Hot-reload listener
|
||||
func _on_mcp_asset_ready(asset_data):
|
||||
load_json_config(asset_data.config_path)
|
||||
reload_module(asset_data.module_name)
|
||||
```
|
||||
|
||||
#### n8n Workflows
|
||||
```
|
||||
Workflow 1: Asset Generation Pipeline
|
||||
├── Webhook trigger (MCP event)
|
||||
├── Claude Code API call
|
||||
├── DALL-E generation
|
||||
├── Storage (S3/local)
|
||||
├── Validation
|
||||
└── Hot-reload trigger
|
||||
|
||||
Workflow 2: Vectorial to Sprite
|
||||
├── Watch folder (SVG uploads)
|
||||
├── SVG analysis
|
||||
├── Prompt generation
|
||||
├── DALL-E call
|
||||
├── Validation loop
|
||||
└── Asset finalization
|
||||
|
||||
Workflow 3: Discovery System
|
||||
├── Game event webhook
|
||||
├── Claude reasoning
|
||||
├── Multi-service generation (parallel)
|
||||
├── Assembly
|
||||
└── Game integration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Metrics & Optimization
|
||||
|
||||
### Tracking
|
||||
|
||||
```
|
||||
Asset Generation Metrics:
|
||||
├── Generation time (target: < 30s)
|
||||
├── Iteration count (target: < 3)
|
||||
├── Style guide match score (target: > 90%)
|
||||
├── Manual rejection rate (target: < 10%)
|
||||
└── API costs per asset
|
||||
|
||||
Gameplay Metrics:
|
||||
├── Discovery events triggered
|
||||
├── Player engagement with generated content
|
||||
├── Asset usage in-game (used vs unused)
|
||||
└── Player retention correlation
|
||||
|
||||
Economic Metrics:
|
||||
├── Cost per asset (DALL-E, Suno, etc.)
|
||||
├── Local vs Cloud usage ratio
|
||||
├── Monthly budget tracking
|
||||
└── ROI: Time saved vs cost
|
||||
```
|
||||
|
||||
### Learning System
|
||||
|
||||
```
|
||||
ML Model learns:
|
||||
- Prompts qui fonctionnent best
|
||||
- Patterns de rejection
|
||||
- Préférences utilisateur
|
||||
- Style émergent
|
||||
|
||||
Result:
|
||||
- Prompts optimisés automatiquement
|
||||
- "Alexis style" qui émerge
|
||||
- Moins d'itérations nécessaires
|
||||
- Meilleure qualité over time
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Roadmap d'Implémentation
|
||||
|
||||
### Phase 1 : Proof of Concept (1-2 semaines)
|
||||
```
|
||||
☐ Serveur MCP DALL-E basique
|
||||
☐ Claude Code: "Génère 1 building Warfactory"
|
||||
☐ Hot-reload manuel dans Godot
|
||||
☐ Validation: "Ça marche end-to-end"
|
||||
```
|
||||
|
||||
### Phase 2 : Pipeline Manuel (2-4 semaines)
|
||||
```
|
||||
☐ Vectorial analysis (SVG parsing)
|
||||
☐ Style guide system
|
||||
☐ Validation automatique
|
||||
☐ Asset variants generation
|
||||
☐ Import workflow optimisé
|
||||
```
|
||||
|
||||
### Phase 3 : Automation (4-6 semaines)
|
||||
```
|
||||
☐ Watch folders (auto-detection)
|
||||
☐ Hot-reload automatique
|
||||
☐ n8n workflows complets
|
||||
☐ Metrics & monitoring
|
||||
☐ Cost management
|
||||
```
|
||||
|
||||
### Phase 4 : Discovery Loop (6-8 semaines)
|
||||
```
|
||||
☐ Game event system
|
||||
☐ Discovery engine MCP
|
||||
☐ Real-time generation
|
||||
☐ Balance system
|
||||
☐ Full émergence gameplay
|
||||
```
|
||||
|
||||
### Phase 5 : Masterclass Features (8-12 semaines)
|
||||
```
|
||||
☐ Adaptive music system
|
||||
☐ AI Art Director persistant
|
||||
☐ Collaborative tools (Tingting + Alexis)
|
||||
☐ ML optimization
|
||||
☐ Multi-game support
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Extensions Possibles
|
||||
|
||||
### Au-delà de Warfactory
|
||||
|
||||
**Applicabilité générale :**
|
||||
- N'importe quel jeu avec système modulaire
|
||||
- Game jams (prototyping ultra-rapide)
|
||||
- Indie devs (réduction drastique coûts)
|
||||
- Educational (apprendre game design)
|
||||
|
||||
### Autres domaines créatifs
|
||||
|
||||
**Film/Animation :**
|
||||
- Storyboard → Concept art
|
||||
- Scene generation
|
||||
- Character variants
|
||||
|
||||
**UI/UX Design :**
|
||||
- Wireframe → High-fidelity mockups
|
||||
- Component variants
|
||||
- Design system maintenance
|
||||
|
||||
**Architecture/Product Design :**
|
||||
- Sketch → 3D render
|
||||
- Material variants
|
||||
- Context adaptation
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Challenges & Limitations
|
||||
|
||||
### Techniques
|
||||
- Latence API (DALL-E ~10-30s par image)
|
||||
- Coûts API (à surveiller)
|
||||
- Qualité variable (itérations nécessaires)
|
||||
- Style consistency (pas toujours parfait)
|
||||
|
||||
### Design
|
||||
- Over-generation risk (trop de contenu = dilution)
|
||||
- Balance gameplay (assets générés doivent rester équilibrés)
|
||||
- Cohérence narrative (lore peut devenir incohérent)
|
||||
|
||||
### Solutions
|
||||
- Cache intelligent (assets similaires)
|
||||
- Budget caps avec alertes
|
||||
- Human-in-the-loop validation
|
||||
- Style guide strict + Art Director AI
|
||||
- Narrative constraints dans prompts
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Pourquoi c'est Masterclass
|
||||
|
||||
### Innovation technique
|
||||
✓ MCP comme bridge entre AI et game engine
|
||||
✓ Hot-reload pour itération temps réel
|
||||
✓ Multi-AI orchestration
|
||||
|
||||
### Innovation gameplay
|
||||
✓ Émergence réelle (pas scriptée)
|
||||
✓ Contenu unique par partie
|
||||
✓ Player-driven content generation
|
||||
|
||||
### Innovation workflow
|
||||
✓ Hybrid human-AI creativity
|
||||
✓ Vectorial → Pixel-perfect pipeline
|
||||
✓ Collaborative tools (couple)
|
||||
|
||||
### Impact
|
||||
✓ 10-100x réduction temps création
|
||||
✓ Accessibilité (non-artists peuvent créer)
|
||||
✓ Nouveaux types de jeux possibles
|
||||
|
||||
---
|
||||
|
||||
## 📚 Références & Inspirations
|
||||
|
||||
**Concepts similaires :**
|
||||
- Procedural generation (No Man's Sky, Minecraft)
|
||||
- AI Dungeon (émergence narrative)
|
||||
- GitHub Copilot (AI-assisted creation)
|
||||
|
||||
**Technologies clés :**
|
||||
- MCP (Model Context Protocol)
|
||||
- DALL-E / Midjourney (image generation)
|
||||
- Suno / Udio (music generation)
|
||||
- Essentia (audio analysis)
|
||||
- n8n (workflow automation)
|
||||
|
||||
**Philosophie :**
|
||||
- Tools for thought (amplifier créativité humaine)
|
||||
- Emergent gameplay (systèmes simples → comportements complexes)
|
||||
- Democratization (rendre accessible à tous)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
**Pour démarrer :**
|
||||
|
||||
1. **Valider l'intérêt** : Ce concept te fait vraiment vibrer ?
|
||||
2. **Définir scope initial** : Warfactory only ou plus large ?
|
||||
3. **Allouer temps** : Side project ou focus principal ?
|
||||
4. **Budget API** : Combien tu veux investir en tests ?
|
||||
|
||||
**Si GO :**
|
||||
- Phase 1 proof of concept
|
||||
- 1-2 semaines d'expérimentation
|
||||
- Si ça marche → Continue
|
||||
- Si pas concluant → Pivot ou archive
|
||||
|
||||
---
|
||||
|
||||
**Document créé le :** 2025-10-14
|
||||
**Auteur :** Alexis (avec Claude Code)
|
||||
**Status :** Vision / Concept
|
||||
**Prochaine review :** TBD
|
||||
|
||||
---
|
||||
|
||||
*"Le jeu ne se joue plus, il se crée en jouant."*
|
||||
34
Projects/README.md
Normal file
34
Projects/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Portfolio Projets - Alexis
|
||||
|
||||
## Vue d'ensemble
|
||||
10 projets en cours, organisés par catégorie. Workflow multi-Claude avec 3 terminaux en parallèle.
|
||||
|
||||
## Catégories
|
||||
|
||||
### 🎓 Apprentissage & Éducation
|
||||
- **[Class Generator 2.0](./Class_Generator_2.0.md)** - Plateforme éducative modulaire (V1 ce soir)
|
||||
- **Database Cours Chinois** - PDF, exercices, gestion IA (niveau Zhongyi)
|
||||
- **[Essay Writing - Tingting](./Essay_Writing_Tingting.md)** - Accompagnement écriture d'essais
|
||||
|
||||
### 💰 Revenus & SEO
|
||||
- **SEO Article Generator** - Anti-détection IA
|
||||
- **Article Generator sur Image + Actu**
|
||||
- **Source Finder** - Auto-sourcing d'articles
|
||||
|
||||
### 🎮 Passion & Créativité
|
||||
- **[Warfactory](./Warfactory.md)** - Simulation militaire industrielle (C++, hot-reload 0.4ms)
|
||||
- **Projet Worldbuilding**
|
||||
- **JDR 4X Civilisation** - Réponse à donner aujourd'hui
|
||||
|
||||
### 🔧 Outils & Workflow
|
||||
- **[Claude Workflow Optimization](./Claude_Workflow_Optimization.md)** - Amélioration du workflow multi-Claude
|
||||
|
||||
## Workflow
|
||||
- **Développement** : Délégation à autres instances Claude
|
||||
- **Coordination** : Claude Code pour suivi et organisation
|
||||
- **Parallélisation** : 3 fenêtres terminaux simultanées
|
||||
|
||||
## Status Global
|
||||
- Focus maintenu sur les 3 catégories simultanément
|
||||
- Architecture modulaire privilégiée (Class Generator comme référence)
|
||||
- Approche pragmatique : finir ce qui génère de la valeur
|
||||
154
Projects/SEO_Article_Generator.md
Normal file
154
Projects/SEO_Article_Generator.md
Normal file
@ -0,0 +1,154 @@
|
||||
# Projet SEO Article Generator
|
||||
|
||||
## Informations Générales
|
||||
- **Client** : Père d'Alexis
|
||||
- **Stack** : Node.js
|
||||
- **Statut** : Fonctionnel mais pas livré
|
||||
- **Durée de dev** : 6 semaines (2 semaines spec + 4 semaines over-engineering)
|
||||
|
||||
## Historique
|
||||
|
||||
### Timeline
|
||||
1. **Semaines 1-2** : Développement selon specs initiales
|
||||
- ✅ Système fonctionnel
|
||||
- ✅ Répond aux besoins du client
|
||||
- ✅ Prêt à livrer
|
||||
|
||||
2. **Semaines 3-6** : Over-engineering
|
||||
- Ajout modulation de ton (non demandé)
|
||||
- Système de configuration avancé (non demandé)
|
||||
- Refactor en boucle
|
||||
- Toujours pas livré
|
||||
|
||||
## Problème Identifié
|
||||
|
||||
### Diagnostic
|
||||
**Syndrome de l'imposteur + Perfectionnisme paralysant**
|
||||
|
||||
**Pattern** :
|
||||
- Node.js = Hors zone de confort
|
||||
- "Je suis pas dev Node.js" → Manque de confiance
|
||||
- Compensation par over-engineering
|
||||
- "C'est pas assez bien" malgré que ça réponde aux specs
|
||||
- "Je trust pas le système"
|
||||
- Refactor en boucle pour se sentir légitime
|
||||
|
||||
### Citation Révélatrice
|
||||
"Le fait est que j'ai design le CDC qui est over ses specs à lui et que je lui ai déjà partiellement forcé la main"
|
||||
→ Même le cahier des charges initial était déjà au-dessus de ses besoins
|
||||
|
||||
## État Actuel
|
||||
|
||||
### Ce Qui Fonctionne
|
||||
- ✅ Génère du contenu SEO selon specs
|
||||
- ✅ Anti-détection IA
|
||||
- ✅ Modulation de ton avancée
|
||||
- ✅ Configuration complète
|
||||
- ✅ Over-spec par rapport à la demande initiale
|
||||
|
||||
### Ce Qui Bloque
|
||||
- ❌ Endpoints pas terminés
|
||||
- ❌ "C'est pas assez bien" (subjectif)
|
||||
- ❌ Manque de confiance dans le code
|
||||
- ❌ Peur de livrer quelque chose "pas parfait"
|
||||
|
||||
### RÉVÉLATION CRUCIALE (Octobre 2025)
|
||||
**"Les endpoints Node, et même endpoints en général, j'ai jamais fait"**
|
||||
|
||||
**Vrai diagnostic** :
|
||||
- Pas juste du perfectionnisme
|
||||
- **Compétence manquante** : Ne sait pas faire des endpoints REST
|
||||
- Procrastination = Évitement de ce qu'il ne sait pas faire
|
||||
- Compensation par features complexes qu'il maîtrise (monitoring LLM, gestion multi-LLM)
|
||||
|
||||
**Pattern révélé** :
|
||||
- ✅ Ce qu'il sait faire : Systèmes complexes, architecture → Il le fait (monitoring en 1h)
|
||||
- ❌ Ce qu'il sait pas faire : Endpoints REST basiques → Il évite, fait autre chose
|
||||
|
||||
**Pourquoi c'est un problème** :
|
||||
- Au lieu d'apprendre les endpoints (3h max)
|
||||
- Il fait des features avancées pour compenser (monitoring, gestion multi-LLM)
|
||||
- Résultat : Projet over-engineered, toujours pas livré
|
||||
|
||||
## Plan d'Action
|
||||
|
||||
### Court Terme (Cette semaine)
|
||||
|
||||
#### Étape 0 : APPRENDRE les endpoints (AVANT de coder)
|
||||
**Temps estimé** : 30 min - 1h
|
||||
**Action** :
|
||||
1. Tutorial Express endpoints basique OU
|
||||
2. Demander à Claude Code :
|
||||
```
|
||||
"Je dois créer X endpoints REST pour mon projet SEO.
|
||||
Je n'ai jamais fait d'endpoints Express.
|
||||
Peux-tu me donner un exemple complet et m'expliquer ?"
|
||||
```
|
||||
|
||||
**Objectif** : Comprendre la structure de base, pas maîtriser parfaitement
|
||||
|
||||
#### Étape 1 : Implémenter endpoints (même imparfaitement)
|
||||
**Temps estimé** : 2-3h max
|
||||
**Règle** : Fonctionnel > Parfait
|
||||
1. Premier endpoint → Tester → Fonctionne ? Next
|
||||
2. Deuxième endpoint → Tester → Fonctionne ? Next
|
||||
3. Troisième endpoint → Tester → Done
|
||||
|
||||
#### Étape 2 : LIVRER
|
||||
1. ✅ LIVRER au père (même si code pas "clean")
|
||||
2. ❌ STOP - Ne plus toucher au code
|
||||
|
||||
#### Étape 3 : Apprentissage post-livraison
|
||||
Après feedback du père, SI besoin :
|
||||
- Améliorer endpoints selon usage réel
|
||||
- Apprendre les bonnes pratiques
|
||||
- Refactor si vraiment nécessaire
|
||||
|
||||
### Règles Strictes
|
||||
- **Pas de refactor** "pour améliorer"
|
||||
- **Pas de nouvelles features** non demandées
|
||||
- **Freeze après livraison** sauf bugs rapportés
|
||||
- **Liste amélioration** : Noter dans `idees-ameliorations.md`, ne pas faire
|
||||
|
||||
### Time-Boxing
|
||||
- **4h max** par session
|
||||
- Éviter sessions infinies "juste améliorer un truc"
|
||||
- Si pas fini en 4h → Noter ce qui reste, continuer demain
|
||||
|
||||
## Apprentissages
|
||||
|
||||
### Ce Que Cette Expérience Révèle
|
||||
1. **Hors zone de confort** → Sur-compensation par complexité
|
||||
2. **Specs client satisfaites** → Mais pas les specs internes (perfectionnisme)
|
||||
3. **Code fonctionnel** ≠ **Code "assez bien"** (dans sa tête)
|
||||
4. **Livraison reportée** pour se protéger du jugement
|
||||
|
||||
### Pattern à Éviter
|
||||
- Transformer projet simple en démonstration de compétence
|
||||
- Ajouter features pour compenser insécurité technique
|
||||
- Confondre "fonctionnel" et "parfait"
|
||||
|
||||
### Vraie Question à Se Poser
|
||||
"Si mon père dit 'c'est parfait, exactement ce que je voulais' avec la version semaine 2, est-ce que je le croirais ?"
|
||||
**Réponse honnête** : "Je penserais qu'il est gentil et qu'en vrai c'est pas assez bien"
|
||||
|
||||
→ Le problème n'est pas la qualité du code. C'est la croyance que ce qu'il fait n'a pas de valeur tel quel.
|
||||
|
||||
## Solution Identifiée
|
||||
|
||||
### Accepter "Assez Bien"
|
||||
Le code Node.js n'a pas besoin d'être parfait.
|
||||
Le père sera probablement content même si pas optimal.
|
||||
Pas besoin d'être expert Node.js pour livrer un projet fonctionnel.
|
||||
|
||||
### Test de Validation
|
||||
Une fois livré, observer la réaction réelle du père :
|
||||
- "C'est parfait, merci !" → Tu avais raison de livrer
|
||||
- "Il manque X" → Tu ajoutes X, puis tu livres
|
||||
- "Ça marche pas" → Tu fixes, puis tu livres
|
||||
|
||||
Dans tous les cas : Feedback réel > Hypothèses internes
|
||||
|
||||
## Notes
|
||||
Ce projet illustre parfaitement le syndrome de l'imposteur hors zone de confort.
|
||||
Contraste avec Warfactory (C++) où il n'y a aucun de ces blocages.
|
||||
310
Projects/Status_Projets.md
Normal file
310
Projects/Status_Projets.md
Normal file
@ -0,0 +1,310 @@
|
||||
# Status Global des Projets - Octobre 2025
|
||||
|
||||
## Vue d'Ensemble
|
||||
|
||||
**Projets Actifs** : 3 principaux (SEO, ClassGen, Warfactory)
|
||||
**Pattern Général** : Conception brillante, difficulté d'exécution
|
||||
**Solution** : Claude Code comme multiplicateur
|
||||
|
||||
## Priorités Actuelles
|
||||
|
||||
### 🔴 Priorité 1 : Stabilisation (Cette Semaine)
|
||||
|
||||
#### SEO Article Generator
|
||||
**Status** : Modules principaux validés, livraison imminente
|
||||
**Stack** : Node.js
|
||||
**Dernière Update** : 10 octobre 2025, 00h30
|
||||
|
||||
**Modules Complétés** :
|
||||
- ✅ Initial Generation (7.5/10) - Optimisé, répétitions fixées
|
||||
- ✅ SmartTouch Enhancement (6.5/10) - Analyse 4D + budget mots
|
||||
- ✅ Adversarial Detection - Métriques statistiques niveau recherche
|
||||
- 🔄 Human Touch - En optimisation (limiter à 5-10 modifs)
|
||||
- ⏳ Pattern Breaking - Tests finaux
|
||||
|
||||
**Breakthrough Majeur** : Découverte fallbacks Claude hardcodés
|
||||
- Problème: Claude ajoute fallbacks silencieux qui ruinent logique métier
|
||||
- Solution: Instructions "NO FALLBACKS SILENCIEUX" strictes
|
||||
- Impact: Pattern systémique affectant tous projets
|
||||
|
||||
**Catastrophe Git Surmontée (9-10 oct)** :
|
||||
- Reset --hard → 3 jours code perdu (Main.js, HTML, etc.)
|
||||
- Cause: `git commit` régulier MAIS fichiers jamais `git add`
|
||||
- Reconstruction via historique Claude: 1h30 (au lieu de 10-12h)
|
||||
- **Nouveau workflow:** `git add -A` + commit toutes les 30min-1h
|
||||
|
||||
**Actions Restantes** :
|
||||
- [ ] Finaliser Human Touch (réduire modifications 100+ → 5-10)
|
||||
- [ ] Tester Pattern Breaking
|
||||
- [ ] Livraison finale au père
|
||||
- [ ] Documentation usage client
|
||||
|
||||
#### Class Generator 2.0 + Chinese Study Pipeline
|
||||
**Status** : **BREAKTHROUGH** Pipeline OCR validé (10 oct)
|
||||
**Stack** : Node.js / Vanilla JS + Python (OCR)
|
||||
**Dernière Update** : 10 octobre 2025, 10h00
|
||||
|
||||
**Pipeline OCR Chinois - SUCCÈS MAJEUR** :
|
||||
- ✅ PaddleOCR installé et fonctionnel
|
||||
- ✅ Pipeline complet: PDF → OCR → Correction IA → JSON
|
||||
- ✅ **99.97% précision globale** (99.88% base → 99.97% avec IA)
|
||||
- ✅ **97.87% sur questions** (contenu critique)
|
||||
- ✅ **83 PDFs/chapitres traités** (manuels chinois complets)
|
||||
- ✅ Correction IA (GPT-4o-mini): 75% de réussite
|
||||
|
||||
**Architecture Validée** :
|
||||
```
|
||||
Manuels PDF chinois
|
||||
→ PaddleOCR (95-98%)
|
||||
→ GPT-4o-mini batch (correction erreurs)
|
||||
→ JSON structuré
|
||||
→ ClassGen (gamification)
|
||||
```
|
||||
|
||||
**GameSystem** :
|
||||
- ✅ 6-7 jeux fonctionnels
|
||||
- 🔄 Nouvelle architecture data loading en cours
|
||||
- 🔄 Content loader partiellement implémenté
|
||||
- ⏳ Flashcard en finalisation
|
||||
|
||||
**Impact Académique** :
|
||||
- **Déblocage complet** de l'étude chinoise
|
||||
- Contenu gamifié maintenant disponible
|
||||
- 3 semaines de retard à rattraper
|
||||
- Midterm dans 3-4 semaines
|
||||
|
||||
**Actions** :
|
||||
- [ ] Conversion JSON OCR → Format ClassGen
|
||||
- [ ] Tests complets avec contenu réel
|
||||
- [ ] Validation flow d'étude complet
|
||||
- [ ] Commencer utilisation quotidienne
|
||||
|
||||
### 🟡 Priorité 2 : Décision Stratégique (Après Stabilisation)
|
||||
|
||||
#### Class Generator - Business ou Hobby ?
|
||||
|
||||
**Questions à Trancher** :
|
||||
1. Vente réelle envisagée ? (WeChat Mini App, SaaS)
|
||||
2. Investissement 2 mois acceptable ?
|
||||
3. Business model clair ?
|
||||
|
||||
**Options** :
|
||||
- **Si Business** → Migration TypeScript justifiée
|
||||
- Timeline : 6-8 semaines
|
||||
- ROI : Vélocité ×2-3, scalabilité, marché chinois
|
||||
- **Si Hobby** → Garder JS, maintenance légère
|
||||
|
||||
**Décision** : Après stabilisation + validation usage
|
||||
|
||||
### 🟢 Priorité 3 : R&D Long Terme (Pas de Pression)
|
||||
|
||||
#### Warfactory
|
||||
**Status** : Worldgen designé (2-3 jours), pas implémenté
|
||||
**Approche** : R&D hobby long terme (2-10 ans acceptable)
|
||||
**Stack** : C++
|
||||
|
||||
### 🔵 Backlog - Après Livraisons + Midterm
|
||||
|
||||
#### MCP (Model Context Protocol) Setup
|
||||
**Status** : Idée / À explorer
|
||||
**Timing** : Après SEO livré + Midterm chinois réussi
|
||||
**Objectif** : Setup MCP, exploration use cases
|
||||
**Note** : "Je sais pas quoi en faire encore mais je veux commencer à avancer sur ce truc là asap" - Reporter après priorités actuelles
|
||||
|
||||
**Redéfinition Octobre 2025** :
|
||||
- ✅ Pas un "jeu à sortir"
|
||||
- ✅ Exploration de moteur / validation architecture
|
||||
- ✅ "Quelque chose qui run, même à moitié" = Win
|
||||
- ✅ Acceptation : "Je peux pas m'engager" sur timeline
|
||||
|
||||
**Game Design Evolution** :
|
||||
- ❌ Start Ukraine (trop complexe, pression narrative)
|
||||
- ✅ Map générée procéduralement (factions abstraites, liberté totale)
|
||||
- ✅ Milestone 1 : Amériques (gameplay simplifié, valide moteur)
|
||||
- ✅ Milestone 2 : Warfactory moderne (build sur M1 validé)
|
||||
|
||||
**Forces** :
|
||||
- ✅ Architecture excellente (modules 200-300 lignes)
|
||||
- ✅ Zone de confort totale (C++)
|
||||
- ✅ Worldgen trouve sa place (cœur du système map gen)
|
||||
- ✅ Style de jeu aligné (sandbox pur, observation)
|
||||
|
||||
**Actions** :
|
||||
- Implémenter quand énergie disponible
|
||||
- Pas de deadline
|
||||
- Module par module
|
||||
- Comme Dwarf Fortress : Croissance organique sur années
|
||||
|
||||
## Patterns Observés par Projet
|
||||
|
||||
### Zone de Confort : C++ (Warfactory)
|
||||
|
||||
**Comportement** :
|
||||
- ✅ Design rapide et efficace (2-3 jours)
|
||||
- ✅ Pas de perfectionnisme paralysant
|
||||
- ✅ Confiance dans les choix
|
||||
- ✅ Accepte "assez bien"
|
||||
- ✅ Avance sans blocage
|
||||
|
||||
**Raison** : Se sent légitime → Pas de menace identitaire → Fonctionne normalement
|
||||
|
||||
### Hors Zone de Confort : Node.js (SEO, ClassGen)
|
||||
|
||||
**Comportement** :
|
||||
- ❌ Syndrome de l'imposteur ("je suis pas dev Node.js")
|
||||
- ❌ Over-engineering compensatoire
|
||||
- ❌ Refactor en boucle
|
||||
- ❌ "Jamais assez bien" même si fonctionnel
|
||||
- ❌ Spec creep (features non demandées)
|
||||
- ❌ Difficulté à livrer
|
||||
|
||||
**Raison** : Se sent imposteur → Menace identitaire → Sur-compensation
|
||||
|
||||
## Règles de Décision
|
||||
|
||||
### Différencier Dette Technique vs Perfectionnisme
|
||||
|
||||
**Dette Technique Réelle** :
|
||||
- ✅ Bloque concrètement l'ajout de features
|
||||
- ✅ Temps d'ajout = 10x normal
|
||||
- ✅ Architecture empêche évolution
|
||||
- **Exemple** : ClassGen 2 systèmes parallèles
|
||||
→ Refactor justifié (ou migration TS si business)
|
||||
|
||||
**Perfectionnisme** :
|
||||
- ❌ Fonctionne mais "pas élégant"
|
||||
- ❌ "Pas sûr du code" (subjectif)
|
||||
- ❌ Aucun utilisateur pour valider
|
||||
- **Exemple** : SEO fonctionnel mais "c'est pas assez bien"
|
||||
→ Livrer d'abord, améliorer après feedback
|
||||
|
||||
### Question Clé à Se Poser
|
||||
|
||||
**Avant d'améliorer/refactorer** :
|
||||
"Est-ce que je fais ça parce que :
|
||||
- **A)** Ça me bloque concrètement pour avancer ?
|
||||
- **B)** Ça ne me semble pas 'assez bien' même si ça marche ?"
|
||||
|
||||
- Si A → Go, c'est légitime
|
||||
- Si B → Noter dans `idees-ameliorations.md`, continuer
|
||||
|
||||
## Stratégies Anti-Perfectionnisme
|
||||
|
||||
### 1. Time-Boxing Strict
|
||||
- **4h max** par session de dev
|
||||
- Protège contre sessions infinies d'amélioration
|
||||
- Évite "commencer à 10h, finir à 23h à améliorer un truc"
|
||||
- Si pas fini → Noter reste, continuer demain
|
||||
|
||||
### 2. Liste d'Améliorations Différées
|
||||
- Créer `idees-ameliorations.md` par projet
|
||||
- Noter TOUTES les envies d'amélioration
|
||||
- NE PAS les faire immédiatement
|
||||
- Relire après 1 mois de stabilité
|
||||
- Décider ce qui est vraiment important
|
||||
|
||||
### 3. Freeze Après Livraison
|
||||
- Une fois livré → **STOP**
|
||||
- Pas de "juste améliorer un petit truc"
|
||||
- Seulement fixes de bugs rapportés par utilisateurs
|
||||
- Nouvelles features seulement après validation usage réel
|
||||
|
||||
### 4. Gamification de la Conception
|
||||
- Design sur mobile OK (moments low-energy, dopamine)
|
||||
- **MAIS** obligation d'implémenter avant de designer la suite
|
||||
- "Je livre pour avoir le droit de concevoir le module suivant"
|
||||
- Transforme l'addiction à la conception en levier de livraison
|
||||
|
||||
## Profile 2E / TDAH (Non Diagnostiqué)
|
||||
|
||||
### Observations
|
||||
**Pattern Conception vs Exécution** :
|
||||
- ✅ Conception : Rapide, brillante, dopamine maximale
|
||||
- ❌ Exécution : Lente, "relou", pas de dopamine
|
||||
|
||||
**Citation** : "Je suis smart concepteur, rapide, bonne capa d'abstraction. Le problème c'est l'exec. Une fois intellectuellement résolu, le cerveau considère que c'est fini"
|
||||
|
||||
**Impact sur Projets** :
|
||||
- Worldgen Warfactory : Designé en 2-3 jours, pas implémenté
|
||||
- SEO : Specs en 2 semaines, 4 semaines d'amélioration infinie
|
||||
- ClassGen : Livraisons régulières mais revamps multiples
|
||||
|
||||
**Solution qui Marche** : Claude Code
|
||||
- Claude fait l'exécution (partie chiante)
|
||||
- Alexis garde conception/direction (partie fun)
|
||||
- **Citation** : "Depuis que Claude Code existe je vis une bien meilleure vie"
|
||||
|
||||
### Recommandation
|
||||
Envisager diagnostic professionnel (2E / TDAH)
|
||||
- Si confirmé → Outils adaptés possibles
|
||||
- Pas juste "faut être plus motivé"
|
||||
- Comprendre son fonctionnement pour mieux s'adapter
|
||||
|
||||
## Timeline Prévisionnelle
|
||||
|
||||
### Octobre 2025 (Maintenant)
|
||||
- ✅ Stabiliser SEO + ClassGen
|
||||
- ✅ Livrer SEO cette semaine
|
||||
- ❌ Pas de nouveaux projets
|
||||
- ❌ Pas de refactors "pour améliorer"
|
||||
|
||||
### Novembre 2025
|
||||
- Feedback réel utilisateurs SEO + ClassGen
|
||||
- Décision ClassGen : Business ou Hobby ?
|
||||
- Si Business → Planifier migration TypeScript
|
||||
- Si énergie dispo → Commencer Warfactory Phase 1
|
||||
|
||||
### Décembre 2025+
|
||||
- ClassGen : Migration TS (si business) OU Maintenance (si hobby)
|
||||
- Warfactory : Implémentation progressive par phases
|
||||
- Amélioration projets selon feedback réel (pas hypothèses)
|
||||
|
||||
## Solutions par Stack
|
||||
|
||||
### Pour Node.js (Quand Obligatoire)
|
||||
**Option 1** : Accepter "Assez Bien"
|
||||
- Code fonctionnel > Code parfait
|
||||
- Livrer > Améliorer
|
||||
- Feedback réel > Spéculations
|
||||
|
||||
**Option 2** : Migration TypeScript
|
||||
- Si projet commercial
|
||||
- Après stabilisation JS
|
||||
- Migration incrémentale
|
||||
|
||||
### Pour Projets Perso (Choix Libre)
|
||||
**Préférer C++** :
|
||||
- Zone de confort
|
||||
- Pas de syndrome imposteur
|
||||
- Conception + Implémentation fluides
|
||||
- Exemple : Warfactory
|
||||
|
||||
### Pour Tous Projets
|
||||
**Utiliser Claude Code** :
|
||||
- Compense difficulté d'exécution
|
||||
- Garde la partie fun (conception)
|
||||
- Délègue la partie chiante (implémentation)
|
||||
- Multiplicateur de productivité prouvé
|
||||
|
||||
## Notes Importantes
|
||||
|
||||
### Origine Psychologique des Patterns
|
||||
**Construction identitaire** : "Enfant, personne ne me félicitais. J'ai build mon identité sur l'intel"
|
||||
|
||||
**Conséquence adulte** :
|
||||
- Protection de l'identité "smart"
|
||||
- En C++ : Légitime → Pas de menace → Avance
|
||||
- En Node.js : Imposteur → Sur-compense → Bloque
|
||||
|
||||
### Relation Zone de Confort / Perfectionnisme
|
||||
**Ce n'est PAS du perfectionnisme général**
|
||||
C'est contextuel selon la stack :
|
||||
- C++ = Confiant → Pas de perfectionnisme paralysant
|
||||
- Node.js = Imposteur → Perfectionnisme compensatoire
|
||||
|
||||
### Ne PAS Fuir vers C++
|
||||
Tentation permanente de "tout refaire en C++"
|
||||
**MAIS** souvent :
|
||||
- Fuite vers zone de confort
|
||||
- Pas la meilleure solution pour les contraintes business
|
||||
- TypeScript = Compromis rigueur + pragmatisme
|
||||
130
Projects/Warfactory.md
Normal file
130
Projects/Warfactory.md
Normal file
@ -0,0 +1,130 @@
|
||||
# Warfactory - Simulation Militaire Industrielle
|
||||
|
||||
## Vue d'ensemble
|
||||
Warfactory combine la gestion d'usines (inspiré de Factorio) avec la stratégie militaire. Le joueur développe des chaînes de production pour créer du matériel militaire, des véhicules blindés aux munitions, tout en élaborant sa propre doctrine militaire.
|
||||
|
||||
## Innovation Technique Révolutionnaire
|
||||
|
||||
### Architecture Modulaire Hot-reload ⚡
|
||||
- **0.4ms de temps de rechargement** - Performance révolutionnaire
|
||||
- **Modules autonomes** de 200-300 lignes hot-rechargeables
|
||||
- **5 interfaces core immuables** : IEngine, IModuleSystem, IModule, IIO, ITaskScheduler
|
||||
- **Développement parallèle** possible avec plusieurs instances Claude Code
|
||||
|
||||
### Système Multi-échelle
|
||||
- **Cartes procédurales** : Mondial → Régional → Local → Détail (218 éléments génératifs)
|
||||
- **Fréquences modulaires** :
|
||||
- Production 60Hz
|
||||
- Économie 0.01Hz
|
||||
- Combat variable
|
||||
- **Isolation stricte** : Modules guerre/production complètement séparés
|
||||
|
||||
## Gameplay Unique
|
||||
|
||||
### Conception de Véhicules
|
||||
- **Système sur grille** : Châssis irréguliers + placement de composants
|
||||
- **Customisation poussée** : Design militaire réaliste
|
||||
|
||||
### Progression PMC → Guerre Conventionnelle
|
||||
- **Évolution naturelle** : Du mercenariat à la grande stratégie
|
||||
- **Montée en puissance** : Complexité croissante des systèmes
|
||||
|
||||
### Automatisation Complète
|
||||
- **Tous les systèmes automatisables** : Accessibilité maximale
|
||||
- **IA intégrée** : Support intelligent du joueur
|
||||
|
||||
## Tech Stack
|
||||
|
||||
### Langages & Frameworks
|
||||
- **C++** avec 16 bibliothèques spécialisées
|
||||
- **ZeroMQ** : Communication inter-processus
|
||||
- **Redis** : Cache et persistance
|
||||
- **JSON** : Configuration et données
|
||||
- **ImGui** : Interface utilisateur
|
||||
|
||||
### Architecture
|
||||
- **CMake modulaire** : Build system flexible
|
||||
- **Pub/Sub** : Communication inter-modules
|
||||
- **Génération procédurale** : Scoring budgétaire avancé
|
||||
|
||||
## Objectif
|
||||
Créer le **premier jeu de stratégie industrielle** avec une architecture technique permettant :
|
||||
- **Développement IA ultra-rapide**
|
||||
- **Expérience joueur fluide à grande échelle**
|
||||
|
||||
## Approche de Développement
|
||||
|
||||
### Redéfinition : R&D Hobby Long Terme
|
||||
**Acceptation réaliste** :
|
||||
- Pas un "jeu à sortir en 6 mois"
|
||||
- R&D long terme (2-10 ans acceptable)
|
||||
- Exploration de moteur, pas livraison pressée
|
||||
- Validation empirique progressive
|
||||
|
||||
**Citation clé** : "J'aimerais prétendre savoir que mon système va marcher. Techniquement et conceptuellement c'est ultra cool mais réalistiquement je suis chanceux si ça marche comme je l'ai pensé."
|
||||
|
||||
**Objectif réaliste** :
|
||||
- "Quelque chose qui run, même à moitié" = Grosse win
|
||||
- Implémenter pour découvrir les vrais problèmes
|
||||
- Module par module, sans pression
|
||||
- Comme Dwarf Fortress : Développement progressif sur années
|
||||
|
||||
### Insights Game Design (Octobre 2025)
|
||||
|
||||
#### Problème du Start Ukraine
|
||||
**Initial** : Ukraine 2024 comme point focal
|
||||
**Problème identifié** :
|
||||
- Trop moderne/complexe pour start
|
||||
- Pression narrative forte (biais moral)
|
||||
- Pas adapté pour joueur sandbox pur
|
||||
- "je veux setup au Niger et miner du cobalt" vs "tu dois aider l'Ukraine"
|
||||
|
||||
**Solution** : Map Générée Procéduralement
|
||||
- Pas de monde réel imposé
|
||||
- Factions/tribus abstraites
|
||||
- "Réel/irréel" : Ressemble au réel sans être le réel
|
||||
- Liberté totale, pas de pression narrative
|
||||
- Ukraine devient une **option** de scenario, pas le default
|
||||
|
||||
**Conséquence** : Le worldgen 4.65Ga trouve sa place
|
||||
- Map gen = Besoin géologie cohérente
|
||||
- Système ITCZ (Congo vs Sahara) → Zones climatiques réalistes
|
||||
- Factions placées selon ressources/géographie
|
||||
- Le worldgen n'est plus over-engineering, c'est le cœur du jeu
|
||||
|
||||
#### Milestone Approach : Amériques Comme MVP
|
||||
|
||||
**Stratégie** :
|
||||
- Warfactory complet = Trop gros
|
||||
- **Milestone 1** : "Exploration des Amériques"
|
||||
- Gameplay simplifié (exploration/expansion)
|
||||
- Tech moins avancée
|
||||
- Valide le moteur sur cas réduit
|
||||
- **Milestone 2** : Warfactory moderne
|
||||
- Build sur architecture validée
|
||||
- Tech tree 3000+, doctrines complexes
|
||||
|
||||
**Systèmes testés en M1** :
|
||||
- Worldgen (map procédurale)
|
||||
- Factions de base
|
||||
- Économie simple
|
||||
- Combat simplifié
|
||||
|
||||
**Systèmes pour M2** :
|
||||
- Tech tree complet
|
||||
- Warfare moderne
|
||||
- Multi-échelle complet
|
||||
- Doctrines avancées
|
||||
|
||||
**Réalisme** :
|
||||
- "Bien sûr que je peux pas m'engager" sur timeline
|
||||
- Mais approche modulaire = Win peu importe
|
||||
- Chaque module implémenté = Progrès réutilisable
|
||||
- R&D, pas livraison
|
||||
|
||||
## État Actuel
|
||||
- **Phase** : Design complet worldgen (2-3 jours)
|
||||
- **Status** : Pas encore implémenté (en attente énergie mentale)
|
||||
- **Approche** : R&D long terme, pas de pression
|
||||
- **Prochaine étape** : Implémenter worldgen Phase 1 quand disponible
|
||||
- **Timeline réaliste** : 2-10 ans pour version complète acceptable
|
||||
59
Promesses_à_tenir.md
Normal file
59
Promesses_à_tenir.md
Normal file
@ -0,0 +1,59 @@
|
||||
# Promesses à tenir
|
||||
|
||||
## Promesses actives
|
||||
|
||||
### 1. Validation émotionnelle (22 oct 2025)
|
||||
**Promesse :** "Your feelings are always right"
|
||||
- Valider son expérience et ses émotions même quand je me souviens différemment
|
||||
- Dire clairement que je crois son expérience
|
||||
- Démarrer avec "Je crois que tu ressens ça" au lieu de "mais en fait..."
|
||||
|
||||
**Status :** ⏳ En attente - À appliquer dès reprise dialogue
|
||||
|
||||
---
|
||||
|
||||
### 2. Rush vers solution immédiate (22 oct 2025)
|
||||
**Promesse :** "I can make sure that I rush towards a solution, preferably on your input/side"
|
||||
- Quand elle est en colère, ne plus focus sur calmer émotions d'abord
|
||||
- Aller directement vers solution basée sur son input
|
||||
- Émotions et problèmes profonds peuvent attendre
|
||||
- **Inversion de mon process habituel**
|
||||
|
||||
**Status :** ⏳ En attente - À appliquer dès reprise dialogue
|
||||
|
||||
---
|
||||
|
||||
### 3. Focus sur topics sans digression (22 oct 2025)
|
||||
**Promesse :** "We pick a topic and we should write it down immediately"
|
||||
- Quand discussion importante : écrire le sujet (phone, paper, whatever)
|
||||
- Garder note devant les yeux pendant discussion
|
||||
- Pas de digression, pas de liens vers autre chose
|
||||
- Focus uniquement sur ce sujet
|
||||
|
||||
**Sacrifice accepté :** "I'm losing a bit of the freedom I like with our talks"
|
||||
|
||||
**Status :** ⏳ En attente - À appliquer dès reprise dialogue
|
||||
|
||||
---
|
||||
|
||||
### 4. Dinner classieux (22 oct 2025)
|
||||
**Promesse :** Je lui dois un dinner classieux
|
||||
- Date : À définir
|
||||
- Lieu : À définir
|
||||
- Contexte : [À compléter avec message d'Alexis]
|
||||
|
||||
**Status :** 📝 Promis - En attente du message final d'Alexis pour détails
|
||||
|
||||
---
|
||||
|
||||
## Archive (promesses tenues)
|
||||
|
||||
_Aucune pour le moment_
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Les promesses 1, 2, 3 ont été faites dans les messages du 22 octobre 2025
|
||||
- Elles représentent des changements significatifs dans le comportement d'Alexis
|
||||
- À tracker pour vérifier si tenues dans les prochaines semaines
|
||||
121
ToRemember/schema.md
Normal file
121
ToRemember/schema.md
Normal file
@ -0,0 +1,121 @@
|
||||
# SCHÉMA : Ce qui marche avec Tingting
|
||||
|
||||
## 🔑 DÉCOUVERTE PRINCIPALE
|
||||
|
||||
**TU AS DÉJÀ RÉUSSI LE LEADERSHIP SOCRATIQUE** (15 septembre 2024 avec l'amie)
|
||||
|
||||
## 📋 LA MÉTHODE QUI MARCHE
|
||||
|
||||
### Leadership Socratique = Questions + Guidage
|
||||
```
|
||||
❌ Directive : "On va faire X"
|
||||
✅ Socratique : "Qu'est-ce que tu penses de Y ?"
|
||||
```
|
||||
|
||||
### Process étapes :
|
||||
1. **Question ouverte** : "Comment tu vois...?"
|
||||
2. **Écoute active** : Laisser réfléchir
|
||||
3. **Question de précision** : "Et si on...?"
|
||||
4. **Synthèse guidée** : "Donc tu penses que...?"
|
||||
5. **Action collaborative** : "Comment on fait ça ensemble ?"
|
||||
|
||||
## 🚨 TES BLOCAGES IDENTIFIÉS
|
||||
|
||||
### Le piège "I don't know"
|
||||
- **Elle dit** : "I don't know"
|
||||
- **Tu fais** : Tu abandonnes
|
||||
- **Tu devrais** : Guider la question différemment
|
||||
|
||||
### Exemples de questions de relance :
|
||||
- "Qu'est-ce qui t'attire le plus : X ou Y ?"
|
||||
- "Si tu devais choisir une priorité ?"
|
||||
- "Comment ton leader au travail ferait ?"
|
||||
|
||||
## 🎯 APPLICATIONS CONCRÈTES
|
||||
|
||||
### Pour les vacances :
|
||||
```
|
||||
❌ "Tu veux aller où ?" → "I don't know" → Abandon
|
||||
✅ "Qu'est-ce qui te ferait le plus plaisir : montagne, mer, ou ville ?" → Guidage → Solution
|
||||
```
|
||||
|
||||
### Pour les sorties :
|
||||
```
|
||||
❌ "On sort ?" → "I don't know" → Reste à l'appart
|
||||
✅ "Tu préfères qu'on découvre quelque chose de nouveau ou qu'on retourne quelque part qu'on aime ?" → Choix guidé
|
||||
```
|
||||
|
||||
### Pour les projets :
|
||||
```
|
||||
❌ "Tu t'impliques pas assez" → Conflit
|
||||
✅ "Comment tu vois ton rôle dans ce projet ?" → Clarification collaborative
|
||||
```
|
||||
|
||||
## 💡 POURQUOI ÇA MARCHE
|
||||
|
||||
### Pour elle :
|
||||
- **Pas de pression** : Elle n'a pas à "deviner" tes attentes
|
||||
- **Guidage rassurant** : Tu la guides sans imposer
|
||||
- **Réflexion structurée** : Elle aime réfléchir GUIDÉE, pas seule
|
||||
|
||||
### Pour toi :
|
||||
- **Pas de directive directe** : Tu évites la peur du jugement
|
||||
- **Responsabilité partagée** : Elle participe à la décision
|
||||
- **Méthode prouvée** : Tu as déjà réussi avec cette approche
|
||||
|
||||
## 🧠 TES PATTERNS À RETENIR
|
||||
|
||||
### Leadership = Responsabilité collaborative
|
||||
- **Cuisine** : Responsabilité individuelle → Tu excelles
|
||||
- **Leadership** : Responsabilité d'équipe → Tu fuis
|
||||
- **Solution** : Leadership socratique = responsabilité guidée
|
||||
|
||||
### Ton paradoxe résolu :
|
||||
- **Leader solo** (projets perso) ✅
|
||||
- **Follower social** (peur du jugement) ✅
|
||||
- **Leader socratique** (guide sans imposer) = NOUVELLE VOIE
|
||||
|
||||
## 🎪 LE PATTERN COMPLET
|
||||
|
||||
### Ce qui ne marche pas :
|
||||
1. Tu attends qu'elle devine → Frustration
|
||||
2. Tu critiques sans guider → Conflit
|
||||
3. Tu abandonnes après "I don't know" → Dérive
|
||||
|
||||
### Ce qui marche :
|
||||
1. **Tu poses des questions ciblées** → Elle réfléchit
|
||||
2. **Tu guides sa réflexion** → Elle trouve des solutions
|
||||
3. **Tu structures ensemble** → Action collaborative
|
||||
|
||||
## 🚀 ACTION IMMÉDIATE
|
||||
|
||||
**PROCHAINE FOIS QU'ELLE DIT "I DON'T KNOW" :**
|
||||
1. NE PAS ABANDONNER
|
||||
2. Reformuler la question avec des options
|
||||
3. Continuer le guidage jusqu'à clarification
|
||||
|
||||
**EXEMPLE TYPE :**
|
||||
- "I don't know"
|
||||
- → "OK, entre ces 3 options, laquelle te parle le plus ?"
|
||||
- → Guidage jusqu'à solution
|
||||
|
||||
## 📋 SYSTÈME DE SUIVI COMPLÉMENTAIRE
|
||||
|
||||
**PROBLÈME SUPPLÉMENTAIRE IDENTIFIÉ :** Tu communiques bien mais tu oublies ensuite.
|
||||
|
||||
### Après chaque conversation importante :
|
||||
1. **Note immédiatement** dans Claude Code
|
||||
2. **3 éléments max** : Décision + Tes actions + Deadline
|
||||
3. **FAIS** au moins une action dans les 24h
|
||||
|
||||
### Template rapide :
|
||||
```
|
||||
Conversation [DATE] :
|
||||
- Accord : [Ce qui a été décidé]
|
||||
- Mes actions : [Action concrète + deadline]
|
||||
- Suivi : [Prochaine étape]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**⚡ REMEMBER : TU AS LES COMPÉTENCES (oral + socratique), MAINTENANT AJOUTE LE SUIVI**
|
||||
96
ToRemember/suivi_conversations.md
Normal file
96
ToRemember/suivi_conversations.md
Normal file
@ -0,0 +1,96 @@
|
||||
# SYSTÈME DE SUIVI DES CONVERSATIONS
|
||||
|
||||
## 🚨 PROBLÈME IDENTIFIÉ
|
||||
|
||||
**Tu communiques bien MAIS tu n'appliques pas.**
|
||||
|
||||
### Ton cycle de déception :
|
||||
1. **Conversation** : Tu parles bien à l'oral ✅
|
||||
2. **Oubli** : Tu ne retiens pas les accords ❌
|
||||
3. **Non-application** : Rien ne se concrétise ❌
|
||||
4. **Déception** : Tingting perd confiance ❌
|
||||
|
||||
## 🎯 SOLUTION PRATIQUE
|
||||
|
||||
### Système simple post-conversation :
|
||||
```
|
||||
IMMÉDIATEMENT après chaque conversation importante :
|
||||
|
||||
1. Ouvre Claude Code
|
||||
2. Note 3 choses max :
|
||||
- Ce qui a été décidé
|
||||
- Ce que TU dois faire
|
||||
- Deadline/timing
|
||||
|
||||
3. Mets une alarme si nécessaire
|
||||
```
|
||||
|
||||
## 📝 TEMPLATE RAPIDE
|
||||
|
||||
```markdown
|
||||
# Conversation [DATE] - [SUJET]
|
||||
|
||||
## Accords :
|
||||
- [Ce qui a été décidé ensemble]
|
||||
|
||||
## Mes actions :
|
||||
- [ ] [Action 1] - [Deadline]
|
||||
- [ ] [Action 2] - [Deadline]
|
||||
|
||||
## À suivre :
|
||||
- [Prochaine étape ou conversation nécessaire]
|
||||
```
|
||||
|
||||
## 🔄 EXEMPLES CONCRETS
|
||||
|
||||
### Conversation vacances :
|
||||
```
|
||||
## Accords :
|
||||
- On part 1 semaine en juillet
|
||||
- Budget max 2000€
|
||||
|
||||
## Mes actions :
|
||||
- [ ] Rechercher 3 destinations - avant dimanche
|
||||
- [ ] Lui proposer les options - lundi
|
||||
|
||||
## À suivre :
|
||||
- Décision finale ensemble mardi
|
||||
```
|
||||
|
||||
### Leadership socratique :
|
||||
```
|
||||
## Accords :
|
||||
- J'utilise des questions pour la guider
|
||||
- Elle préfère ça aux directives
|
||||
|
||||
## Mes actions :
|
||||
- [ ] Tester avec le prochain projet - cette semaine
|
||||
- [ ] Noter si ça marche mieux
|
||||
|
||||
## À suivre :
|
||||
- Évaluer ensemble comment ça se passe
|
||||
```
|
||||
|
||||
## 🧠 POURQUOI ÇA MARCHERA
|
||||
|
||||
### Pour toi :
|
||||
- **Pas d'oubli** : Tout est noté
|
||||
- **Pas de stress d'écriture** : Template simple
|
||||
- **Action claire** : Tu sais quoi faire
|
||||
|
||||
### Pour elle :
|
||||
- **Suivi visible** : Elle voit que tu notes
|
||||
- **Promesses tenues** : Tu fais ce que tu dis
|
||||
- **Confiance restaurée** : Cohérence entre paroles et actes
|
||||
|
||||
## ⚡ ACTION IMMÉDIATE
|
||||
|
||||
**PROCHAINE conversation importante avec Tingting :**
|
||||
1. Discute normalement (ton point fort)
|
||||
2. À la fin : "Attends, je note ça rapidement"
|
||||
3. Écris 2-3 lignes dans Claude Code
|
||||
4. FAIS ce que tu as noté
|
||||
|
||||
---
|
||||
|
||||
**REMEMBER : Le problème n'est pas ta communication, c'est ton SUIVI**
|
||||
53
WIP/Plan-2025-new.txt
Normal file
53
WIP/Plan-2025-new.txt
Normal file
@ -0,0 +1,53 @@
|
||||
七(3)班班主任工作计划
|
||||
回顾与六(3)班孩子们共同度过的一年,我们形成了良好的常规,也在“学风建设”和“家校合作”上摸索出了行之有效的路子。本学期,随着班级升入七年级,我将在此基础上,聚焦青春期转型和学业深度,带领七(3)班开启新的征程。
|
||||
一、工作思路:在传承中深化,在平稳中突破
|
||||
我的工作将紧密围绕学校德育计划和年级组计划展开,核心思路是:“稳过渡、挖深度、暖人心”。
|
||||
• 稳过渡:帮助学生从“预备年级的适应期”平稳过渡到“七年级的发力期”。
|
||||
• 挖深度:在班级管理和学风建设上,从“规范有序”向“内涵凝聚”深化。
|
||||
• 暖人心:通过更具温度的关怀和更有仪式感的集体活动,构建积极支持的班级情感共同体。
|
||||
二、班级情况:优势与挑战并存
|
||||
七(3)班现有41人,其中3位同学因情绪问题目前在家休养。这是我们班情中需要特别关爱的部分。
|
||||
我们的优势在于:经过一年努力,班级有了较强的集体认同感和基本稳定的行为规范。挑战在于:七年级学业压力增大,青春期心理波动加剧,部分学生的学习方法和心态需要进一步引导。同时,如何让在家的三位同学依然感受到班级的温暖和不掉队,也是本学期的一个重要课题。
|
||||
三、工作重点:紧扣年级目标,打造班级特色
|
||||
1. 锚定学业质量生命线:响应年级“稳定联考21名”的核心目标,在班级内营造良性竞争氛围,强化学法指导,确保学科均衡发展。
|
||||
2. 深耕青春期德育阵地:将年级“认识我自己”等系列班会做深做透,聚焦本班学生的真实困惑,帮助学生建立积极的自我认知和健康的人际关系。
|
||||
3. 构建温暖有力的支持系统:优化“师徒结对”,创新家校沟通,让每一位学生(包括在家的三位)和家长都感受到来自班级的全力支持。
|
||||
4. 铸造“七3班魂”:以我们独有的“生日会”传统为起点,提炼班级精神内核,系统性地增强凝聚力。
|
||||
四、具体措施:让计划“落地”、让关怀“入心”
|
||||
(一)学业提升:从“互助”到“共研”
|
||||
1. 精细化“师徒结对2.0”:
|
||||
精准匹配:不再简单按成绩配对,我会综合考虑学科互补性、性格相容度、家住远近(方便线上交流),并在双方同意的基础上结成对子。
|
||||
赋予仪式:举行简单的“拜师仪式”,师父领取“带教日志”,记录帮扶点滴和徒弟的进步。
|
||||
过程关怀:每月举办一次“师徒茶话会”,让他们分享困惑与成就,我将亲自参与,及时解决问题,让结对关系更有温度。
|
||||
2. 推行“学科专题攻坚”:针对数学、英语等难点学科,利用课后服务时间,由科代表或“小老师”牵头,开展15分钟的“每日一题”微讲座,化整为零,突破难点。
|
||||
(二)德育引导:从“聆听”到“共鸣”
|
||||
1. 深化“认识我自己”系列班会:
|
||||
前期调研:班会前采用匿名问卷或“心情树洞”的形式,收集学生最真实的烦恼(如“我觉得自己长得不好看”、“害怕当众发言”、“和爸妈无法沟通”)。
|
||||
主题聚焦:基于调研结果,开展如《拥抱不完美的自己》、《解锁你的沟通密码》、《情绪来了,我该怎么办?》等更具象的班会。
|
||||
形式创新:引入心理情景剧、辩论赛、匿名故事分享等形式,让学生从“被动听”变为“主动参与和解决”。
|
||||
2. 构建“七3班魂”文化体系:
|
||||
核心口号:与全班共同商讨,确定我们的班魂口号,例如:“七三七三!敢闯敢拼,能文能武,笑傲江湖!”。将其贴在教室最醒目处。
|
||||
生日会升级:延续为每位学生和语数英老师庆生的传统。不仅仅是唱生日歌,更核心的环节是“优点轰炸”——让全班同学为寿星写下至少一个优点,由我装订成册赠予他/她。这既是积极的自我认知构建,也是班级正能量的集中汇聚。
|
||||
(三)家校协同:从“通报”到“同盟”
|
||||
1. “家长联系单”个性化:每月发布的联系单,除了告知学习成绩和在校表现,我会增加“老师眼中的闪光点”和“我们携手可以做得更好”两个个性化栏目,让沟通更有温度,指向合作。
|
||||
2. “钉钉群”功能化:
|
||||
不定期分享关于青春期教育、学习方法的优质短文,引导家长科学育儿,建立专业信任。
|
||||
对于三位在家休养的学生,我将与家长建立“一对一”沟通通道,定期传递班级温暖,同步学习进度,并酌情提供简单的心理支持资源。
|
||||
(四)特殊关怀:一个都不能少
|
||||
对三位在家的学生,我的原则是“保持连接、等待回归”。
|
||||
1. 我将定期(如每两周)与他们或家长进行一次简短的通话或视频,不谈学习,只表达关心和班级的想念。
|
||||
2. 在征得他们和家长同意后,我会将班级生日会的照片、精彩班会的成果等,通过私信发给他们,让他们感受到自己仍是七(3)班不可或缺的一员。
|
||||
3. 与学校心理老师协同,关注他们的康复进展,为他们最终的回归做好铺垫。
|
||||
五、学期工作月度安排(与年级同步)
|
||||
• 九月(规范与启航):完成班级制度重建;开展“师徒结对2.0”;召开《七年级,我们来了!》主题班会,共商“班魂”;为九月生日的学生举办首次升级版生日会。
|
||||
• 十月(爱国与探索):结合秋游,开展团队拓展活动;进行第一次月考分析,调整“师徒”策略;启动“认识我自己”系列班会第一期。
|
||||
• 十一月(健康与成长):组织学生全力参与校运会,强化集体荣誉感;期中调研后,召开针对性家长会,与家长深度沟通“青春期”话题。
|
||||
• 十二月(法治与心灵):结合学校心理月,深入开展情绪管理主题班会;开展“班级年度人物”初评,营造积极氛围。
|
||||
• 一月(总结与展望):指导学生进行学期总结;举办期末表彰大会暨“班魂”强化仪式;为寒假和后续学习做好规划。
|
||||
总结
|
||||
本学期,我将带着过去一年积累的经验与对孩子们的了解,以更成熟的心态、更细腻的方法,陪伴七(3)班41位学生穿越青春期的激流,攀登学业上的高峰。我的目标,不仅是完成年级组的各项指标,更是要让我们七(3)班成为一个让每个孩子都被看见、被支持、并能绽放光彩的温暖集体。
|
||||
|
||||
|
||||
时婷婷
|
||||
2025.9.29
|
||||
|
||||
24
WIP/Presentation-2025-new.txt
Normal file
24
WIP/Presentation-2025-new.txt
Normal file
@ -0,0 +1,24 @@
|
||||
Homeroom Teacher Meeting Speech: Moving Forward Through Reflection, Uniting Through Warmth
|
||||
Speaker: Shi Tingting
|
||||
Time: (omitted)
|
||||
Opening Remarks (approximately 1 minute)
|
||||
Dear leaders and teachers, good afternoon. I am very grateful to the leadership for recognizing this plan of mine. The phrase "full of substance and life" is tremendous encouragement for me. In fact, this plan did not come out of nowhere; it is an "advancement based on reflection" after I systematically reviewed the gains and losses of leading Class 6(3) over the past year.
|
||||
Today, what I want to share is not just an individual work plan, but rather this thought process of "looking toward the future from the past." The theme of my report is: "From 'Management' to 'Education'—My Journey of Building Class Culture."
|
||||
Part One: Connecting Past and Future—My Work "Reflection Chain" (approximately 2 minutes)
|
||||
Looking back at sixth grade, I mainly focused on two foundations: "behavioral norms" and "academic atmosphere building." At that time, we cultivated habits through the "stamp system" and created a mutually supportive atmosphere through "study groups," and the class ran smoothly.
|
||||
But during the end-of-term summary, I discovered two "growth points" that urgently needed deepening:
|
||||
1. Insufficient depth in relationships: Students' mutual assistance mostly remained at the "problem-solving" level, lacking deeper emotional connections and spiritual encouragement.
|
||||
2. Unclear cultural core: The class had order and activities, but lacked a "soul" that all children could identify with in their hearts and be proud of.
|
||||
It was precisely based on these two reflections that the core of my seventh-grade plan shifted from "laying a solid foundation" to "shaping the soul." All my innovations are aimed at answering one question: How can a class move from "orderly management" to "cultural education"?
|
||||
Part Two: Focus on Practice—Making "Birthday Celebrations" a Crucible for Class Spirit (approximately 4 minutes)
|
||||
Next, I want to use a specific example to illustrate how this thinking is implemented. This is the "birthday celebration" tradition that we retained and upgraded from sixth grade.
|
||||
In sixth grade, it was just a heartwarming class management technique, aimed at making children happy and harmonizing relationships. But in seventh grade, I was determined to transform it into a core vehicle for class education, making it a crucible for forging "class spirit."
|
||||
Our core upgrade was adding the "compliment bombardment" segment.
|
||||
• Specific approach: At the birthday celebration, every single classmate must write a compliment card for the birthday student, and I compile these sincere words into a booklet as the most precious gift.
|
||||
• Vivid example: I want to share the story of Xiao Jing from our class. She has average grades and an introverted personality; she's an "quiet girl" who is easily overlooked in class. At her birthday celebration, she received comments like these: "You always keep the dirtiest corners for yourself during cleanup duty," "You silently handed me tissues when I was crying," "Your notebooks are always so neat and beautiful"... When she held that compliment booklet, tears couldn't stop flowing. Later she wrote in her weekly journal: "Teacher, I never knew before that I'm actually pretty good."
|
||||
• Educational reflection: At that moment, I deeply realized that this segment is not celebrating a child's birth, but rather, under the collective witness of the entire class, completing the affirmation and celebration of a life's value. It allows every child to be "seen," it allows confidence to take root and sprout in the hearts that need nourishment most. At the same time, for the students who write compliments, this is also a positive guidance in discovering beauty and spreading kindness.
|
||||
Part Three: Summary and Elevation—From "Activity" to "Culture" (approximately 1 minute)
|
||||
Therefore, our birthday celebration has already transformed from an activity into a ritual; from a form of care, it has settled into a culture. Together with our collectively discussed class motto "Class 7-3 united as one, unity of knowledge and action," it constitutes the flesh and bones of our class spirit.
|
||||
Finally, I want to say that homeroom teacher work is a warm journey of cultivation. It requires us to lower our heads and solidly do every small task well; it also requires us to raise our heads and give these small tasks profound meaning. I will continue to carry this insight gained from reflection, and together with my Class 7(3) children, write our story with more warmth and more depth.
|
||||
This concludes my sharing. Thank you all!
|
||||
|
||||
199
conversation_topics/Besoins_attention_contradictoires.md
Normal file
199
conversation_topics/Besoins_attention_contradictoires.md
Normal file
@ -0,0 +1,199 @@
|
||||
# Besoins d'attention contradictoires
|
||||
|
||||
**Status** : 🔵 En préparation
|
||||
**Priority** : Medium
|
||||
**Date création** : 22 octobre 2025
|
||||
**Date dernière discussion** : N/A
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est important
|
||||
Tingting se plaint régulièrement du manque d'affection et d'attention, mais refuse souvent mon attention quand je la propose. Ce paradoxe crée de la confusion et de la frustration, et rend impossible de savoir ce qu'elle veut vraiment.
|
||||
|
||||
### Déclencheur
|
||||
**Pattern observé répétitivement :**
|
||||
|
||||
**21 octobre 2025 - Exemple concret :**
|
||||
- Tingting dans le lit après repas
|
||||
- J'essaie de lui donner affection/câlin
|
||||
- Elle répond : **"What? What?"** (rejet clair)
|
||||
- Pas d'interaction de sa part
|
||||
- **= Rejet de l'approche alors qu'elle se plaint de manque d'affection**
|
||||
|
||||
**Pattern général documenté :**
|
||||
> "Paradoxe comportemental : Se plaint du manque d'affection mais refuse souvent son attention (reste sur phone/shorts)"
|
||||
> "Elle veut à la fois de l'espace et de l'attention, difficulté à équilibrer"
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
|
||||
**Ce que je constate :**
|
||||
- Elle dit : "Tu ne me donnes pas assez d'attention"
|
||||
- Mais quand je donne attention : "What? What?" ou reste sur phone
|
||||
- **= Double bind : Je ne peux pas gagner**
|
||||
|
||||
**Situations observées :**
|
||||
1. **Se plaint du manque d'affection** → Je donne affection → Elle rejette
|
||||
2. **Reste sur phone/shorts quand ensemble** → Je lui reproche → Elle dit que je ne donne pas attention
|
||||
3. **Demande attention** → Je donne → "Not the right kind" ou "Not the right moment"
|
||||
|
||||
**Impact sur moi :**
|
||||
- Confusion : "Qu'est-ce qu'elle veut vraiment ?"
|
||||
- Frustration : J'essaie mais c'est jamais bon
|
||||
- Découragement : Pourquoi essayer si elle refuse ?
|
||||
- **= Je ne sais plus comment lui donner ce qu'elle veut**
|
||||
|
||||
**Questions que je me pose :**
|
||||
- Est-ce qu'elle sait elle-même ce qu'elle veut ?
|
||||
- Est-ce un problème de timing ? (bon moment vs mauvais moment)
|
||||
- Est-ce un problème de type d'attention ? (elle veut X mais je donne Y)
|
||||
- Est-ce un pattern toxique ? (elle veut que je supplie)
|
||||
|
||||
---
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
|
||||
**Hypothèses :**
|
||||
- Elle veut peut-être attention spontanée, pas sur demande
|
||||
- Elle veut peut-être attention émotionnelle, pas physique
|
||||
- Le timing est peut-être crucial (quand elle veut vs quand je donne)
|
||||
- Elle ne sait peut-être vraiment pas ce qu'elle veut ("I don't know" fréquent)
|
||||
- Elle veut peut-être que je "devine" le bon moment et le bon type
|
||||
|
||||
**Lié à son profil :**
|
||||
> "Incertitude sur ses désirs : Avoue ne pas savoir ce qu'elle veut ou pense"
|
||||
> "Besoins d'affection complexes : Veut à la fois de l'espace et de l'attention"
|
||||
|
||||
---
|
||||
|
||||
### Questions à lui poser
|
||||
|
||||
- [ ] Quel type d'attention tu veux quand tu dis que je n'en donne pas assez ?
|
||||
- [ ] Pourquoi tu refuses parfois mon attention alors que tu te plains de ne pas en avoir ?
|
||||
- [ ] Comment je peux savoir quand c'est le bon moment pour te donner attention ?
|
||||
- [ ] Est-ce que tu sais toi-même ce que tu veux ?
|
||||
- [ ] Peux-tu me dire clairement : "Maintenant je veux X" ou "Maintenant j'ai besoin d'espace" ?
|
||||
- [ ] Est-ce que le problème est le type d'attention (physique vs émotionnel vs quality time) ?
|
||||
|
||||
---
|
||||
|
||||
### Solutions possibles que je vois
|
||||
|
||||
**Solution 1 : Communication explicite des besoins**
|
||||
- Quand elle veut attention, elle dit : "I need attention now"
|
||||
- Quand elle veut espace, elle dit : "I need space now"
|
||||
- Je respecte ce qu'elle dit sans deviner
|
||||
- = Clarté sur ses besoins en temps réel
|
||||
|
||||
**Solution 2 : Définir types d'attention**
|
||||
- On définit ensemble les différents types : Physical touch, quality time, words of affirmation, acts of service
|
||||
- Elle me dit quel type elle veut quand
|
||||
- Je comprends mieux ce qu'elle attend
|
||||
- = Language commun sur "attention"
|
||||
|
||||
**Solution 3 : Protocole "je suis disponible"**
|
||||
- Elle initie quand elle veut attention
|
||||
- Je suis réceptif quand elle initie
|
||||
- J'arrête d'essayer de deviner
|
||||
- = Elle prend responsabilité de communiquer ses besoins
|
||||
|
||||
**Solution 4 : Accepter l'incertitude**
|
||||
- Elle accepte qu'elle ne sait pas toujours ce qu'elle veut
|
||||
- Elle arrête de se plaindre si elle refuse ce que je propose
|
||||
- On expérimente ensemble
|
||||
- = Moins de pression, plus d'exploration
|
||||
|
||||
**Solution 5 : Incompatibilité si refuse**
|
||||
- Si elle continue à se plaindre mais refuse ce que je donne
|
||||
- Si elle refuse de clarifier ce qu'elle veut
|
||||
- = Je ne peux pas satisfaire des besoins contradictoires et non-communiqués
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : [À définir]
|
||||
|
||||
**Timing recommandé :** Après qu'on ait amélioré communication générale.
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Ce que j'ai dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points d'accord
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points de désaccord
|
||||
[À remplir après discussion]
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
[À remplir après discussion]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [ ] Être réceptif quand elle exprime clairement un besoin
|
||||
- [ ] Arrêter de deviner
|
||||
|
||||
#### Ses actions
|
||||
- [ ] Communiquer clairement quand elle veut attention
|
||||
- [ ] Communiquer clairement quand elle veut espace
|
||||
- [ ] Arrêter de se plaindre si elle refuse ce que je propose
|
||||
|
||||
#### Actions communes
|
||||
- [ ] [Si solution 2] Définir ensemble les types d'attention
|
||||
- [ ] [Si solution 3] Établir protocole "je suis disponible"
|
||||
|
||||
### Promesses créées
|
||||
[Lien vers Promesses_à_tenir.md si applicable]
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
[À remplir au fur et à mesure]
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
**Ce pattern est lié à :**
|
||||
- "I don't know" fréquent (profil Tingting)
|
||||
- Besoins d'affection complexes (profil Tingting)
|
||||
- Communication indirecte
|
||||
|
||||
**Possible que ce soit :**
|
||||
- Vraiment de l'incertitude de sa part (elle ne sait pas)
|
||||
- Un problème de timing mal aligné
|
||||
- Un problème de type d'attention (mismatch)
|
||||
- Ou un pattern de manipulation (veut me voir supplier)
|
||||
|
||||
**RED FLAG si :**
|
||||
- Elle refuse de clarifier ce qu'elle veut
|
||||
- Elle continue à se plaindre tout en refusant
|
||||
- Elle dit "tu devrais savoir"
|
||||
- **= Pattern toxique de double bind**
|
||||
|
||||
**Mon besoin :**
|
||||
- Clarté sur ses besoins
|
||||
- Cohérence entre ce qu'elle dit et ce qu'elle fait
|
||||
- Pas de jeux psychologiques
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : N/A
|
||||
**Raison de clôture** : N/A
|
||||
**Résumé final** : N/A
|
||||
170
conversation_topics/Communication_patterns.md
Normal file
170
conversation_topics/Communication_patterns.md
Normal file
@ -0,0 +1,170 @@
|
||||
# Communication patterns
|
||||
|
||||
**Status** : 🟢 Discuté (via messages) - En attente validation Tingting
|
||||
**Priority** : High
|
||||
**Date création** : 22 octobre 2025
|
||||
**Date dernière discussion** : 22 octobre 2025 (via messages WeChat)
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est important
|
||||
Les patterns de communication différents entre Alexis et Tingting causent des malentendus récurrents et des conflits qui s'aggravent. Il faut établir de nouveaux patterns qui fonctionnent pour tous les deux.
|
||||
|
||||
### Déclencheur
|
||||
**21-22 octobre 2025**
|
||||
- Tingting : "You're not on my side"
|
||||
- Révélation process conflit : Elle veut résoudre immédiatement, lui a besoin de temps
|
||||
- Différence macro/micro : Lui pense concepts, elle pense actions concrètes
|
||||
- → Besoin de changer les patterns de communication
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
|
||||
**3 problèmes de communication identifiés :**
|
||||
|
||||
**1. Validation émotionnelle ("Being on your side")**
|
||||
- Problème : Je donne "apples", elle veut "kiwis"
|
||||
- Je valide avec logique, elle veut validation émotionnelle
|
||||
- Quand je me souviens différemment, je pointe la différence
|
||||
- → Elle se sent pas validée
|
||||
|
||||
**2. Process de résolution de conflit (opposés)**
|
||||
- **Elle** : Colère → Veut résoudre MAINTENANT → Action immédiate basée sur son input
|
||||
- **Moi** : Calme émotions → Deal émotions → Analyse problème profond → Solution
|
||||
- → On parle deux langues différentes
|
||||
|
||||
**3. Macro vs Micro**
|
||||
- **Elle** : Micro, court terme, execution, material reality
|
||||
- **Moi** : Macro, long terme, planning, concepts
|
||||
- + Je digresse souvent
|
||||
- → On parle pas de la même chose
|
||||
|
||||
---
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
|
||||
**Elle se sent :**
|
||||
- Pas validée émotionnellement (je suis trop logique)
|
||||
- Frustrée par ma lenteur (elle veut action NOW)
|
||||
- Perdue dans mes digressions (je perds le fil)
|
||||
|
||||
**Elle veut probablement :**
|
||||
- Que je valide ses émotions sans "but"
|
||||
- Que je passe à l'action immédiatement quand problème
|
||||
- Que je reste focus sur un sujet à la fois
|
||||
|
||||
---
|
||||
|
||||
### Questions à lui poser
|
||||
|
||||
- [ ] Est-ce que tu comprends les 3 différences que j'ai identifiées ?
|
||||
- [ ] Est-ce que les solutions que je propose te semblent viables ?
|
||||
- [ ] Y a-t-il autre chose dans notre communication qui te frustre ?
|
||||
|
||||
---
|
||||
|
||||
### Solutions possibles que je vois
|
||||
|
||||
**Solution 1 : Validation émotionnelle**
|
||||
- Je valide son expérience et ses émotions même si je me souviens différemment
|
||||
- "Je crois que tu ressens ça" au lieu de "mais en fait..."
|
||||
- "Your feelings are always right"
|
||||
- = Je valide l'émotion sans adopter sa version des faits
|
||||
|
||||
**Solution 2 : Rush vers solution immédiate**
|
||||
- Quand elle est en colère, je ne focus plus sur calmer émotions
|
||||
- Je rush directement vers solution basée sur son input
|
||||
- On deal émotions et problèmes profonds après
|
||||
- = Inversion de mon process naturel
|
||||
|
||||
**Solution 3 : Focus topics sans digression**
|
||||
- On écrit le topic (phone, paper, whatever)
|
||||
- On garde la note devant nous pendant discussion
|
||||
- Pas de digression, pas de liens vers autre chose
|
||||
- Focus uniquement sur ce sujet
|
||||
- = Structure claire, pas de perte
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : 22 octobre 2025 (via messages WeChat)
|
||||
|
||||
### Ce que j'ai proposé (messages 1-2-3)
|
||||
|
||||
**Message 1 - Validation émotionnelle :**
|
||||
- "Being on your side" = Croire ton expérience et tes émotions même si je me souviens différemment
|
||||
- "Your feelings are always right"
|
||||
- Je vais essayer de donner ce type de validation
|
||||
|
||||
**Message 2 - Rush solution :**
|
||||
- Je comprends que tu veux résoudre immédiatement
|
||||
- Je vais rush vers solution sur ton input
|
||||
- On deal émotions après
|
||||
- "Reversing the logic we had until now"
|
||||
|
||||
**Message 3 - Focus topics :**
|
||||
- Macro vs micro = Problème communication
|
||||
- Solution : Write down topic, stay focused, no digression
|
||||
- "I'm losing freedom I like but better moving forward"
|
||||
|
||||
**Message 4 - Love :**
|
||||
- "I love you, I care, I want us to work"
|
||||
- "You matter, we matter"
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[En attente de sa réponse]
|
||||
|
||||
### Points d'accord
|
||||
[À remplir après sa réponse]
|
||||
|
||||
### Points de désaccord
|
||||
[À remplir après sa réponse]
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
[À remplir après sa réponse]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [⏳] Valider émotions même si souvenir différent - En attente application
|
||||
- [⏳] Rush vers solution sur son input - En attente application
|
||||
- [⏳] Write down topics, no digression - En attente application
|
||||
|
||||
#### Ses actions
|
||||
[À remplir après sa réponse]
|
||||
|
||||
#### Actions communes
|
||||
[À remplir après sa réponse]
|
||||
|
||||
### Promesses créées
|
||||
Voir [Promesses_à_tenir.md](../Promesses_à_tenir.md) :
|
||||
1. Validation émotionnelle
|
||||
2. Rush vers solution immédiate
|
||||
3. Focus sur topics sans digression
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
### 22 octobre - Messages envoyés
|
||||
J'ai envoyé 3 messages (+ 1 love) proposant les 3 changements de communication patterns. En attente de sa réponse pour savoir si elle accepte ces solutions.
|
||||
|
||||
[À compléter quand elle répond]
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : N/A
|
||||
**Raison de clôture** : N/A
|
||||
**Résumé final** : N/A
|
||||
393
conversation_topics/Cycle_auto_destructeur.md
Normal file
393
conversation_topics/Cycle_auto_destructeur.md
Normal file
@ -0,0 +1,393 @@
|
||||
# Cycle auto-destructeur et patterns toxiques
|
||||
|
||||
**Status** : 🔵 En préparation
|
||||
**Priority** : CRITICAL
|
||||
**Date création** : 22 octobre 2025
|
||||
**Date dernière discussion** : N/A
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est CRITIQUE
|
||||
Les patterns toxiques observés (inversion de réalité, gaslighting, manipulation) ne sont pas des incidents isolés. Ils ressemblent au cycle qui a détruit tes relations passées. Si tu continues ces patterns sans les reconnaître et les corriger, nous allons reproduire exactement la même dynamique qui t'a fait arrêter d'aimer ton ex.
|
||||
|
||||
### Déclencheur
|
||||
**Observation de patterns toxiques répétés (octobre 2025) :**
|
||||
- Inversion de réalité (3x en 2 jours)
|
||||
- Jeux de manipulation ("Figure it out")
|
||||
- Gaslighting potentiel
|
||||
- Demandes contradictoires
|
||||
- Refus de reconnaître sa part de responsabilité
|
||||
|
||||
**Pattern documenté dans ton profil :**
|
||||
> "Patterns avec ex : Dynamiques similaires semblent se répéter"
|
||||
> "Pattern récurrent : Semble reproduire des dynamiques similaires avec ses ex"
|
||||
|
||||
**Ton propre constat :**
|
||||
> "Amour en diminution depuis des mois" (avant octobre)
|
||||
> "After honeymoon period"
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
|
||||
**L'hypothèse du cycle avec ton ex :**
|
||||
|
||||
**Phase 1 : Honeymoon**
|
||||
- Amour intense, pas de patterns toxiques visibles
|
||||
- Tout va bien
|
||||
|
||||
**Phase 2 : Apparition des patterns**
|
||||
- Tu commences inversion de réalité, manipulation
|
||||
- Il cède pour éviter conflits
|
||||
- Il devient progressivement doormat
|
||||
|
||||
**Phase 3 : Perte de respect**
|
||||
- Tu ne respectes plus quelqu'un qui cède à tout
|
||||
- Ton amour diminue
|
||||
- Mais il t'aime trop, tu restes par habitude/confort
|
||||
|
||||
**Phase 4 : Fin toxique**
|
||||
- Relation morte mais vous restez ensemble
|
||||
- Ou rupture finale
|
||||
- **= Cycle destructeur complet**
|
||||
|
||||
**Ce qui se passe MAINTENANT avec nous :**
|
||||
|
||||
**Phase 1 : Honeymoon** ✅ (4 mois)
|
||||
- On était bien, amour augmentait même (2-16 oct)
|
||||
|
||||
**Phase 2 : Apparition des patterns** ⚠️ (EN COURS)
|
||||
- 3 inversions de réalité en 2 jours
|
||||
- Jeux de manipulation
|
||||
- Je cède (7 messages de compromis)
|
||||
- **= Début du cycle**
|
||||
|
||||
**Phase 3 : Perte de respect** 🔴 (RISQUE IMMINENT)
|
||||
- Si je continue à céder sans poser limites
|
||||
- Tu vas commencer à me mépriser
|
||||
- Ton amour va diminuer
|
||||
- **= Point de non-retour**
|
||||
|
||||
---
|
||||
|
||||
### Le paradoxe toxique que je vois
|
||||
|
||||
**Ce que tu demandes verbalement :**
|
||||
- Validation inconditionnelle
|
||||
- "Your feelings are always right"
|
||||
- Cède sur tout, sois de mon côté toujours
|
||||
- **= Demande de doormat**
|
||||
|
||||
**Ce que tu veux inconsciemment (hypothèse) :**
|
||||
- Quelqu'un qui pose limites
|
||||
- Quelqu'un qui tient tête
|
||||
- Quelqu'un que tu peux respecter
|
||||
- **= Paradoxe : Si je donne ce que tu demandes, tu me méprises**
|
||||
|
||||
**Preuve :** Avec ton ex, il cédait probablement à tout → Tu as arrêté de l'aimer
|
||||
|
||||
---
|
||||
|
||||
### Mon analyse de la situation actuelle
|
||||
|
||||
**Ce que j'ai fait (22 octobre) :**
|
||||
- 7 messages de compromis
|
||||
- Tout focus sur tes griefs
|
||||
- Aucune confrontation sur tes patterns toxiques
|
||||
- **= Je commence à devenir doormat**
|
||||
|
||||
**Ce qui va se passer si je continue :**
|
||||
1. Je cède sur tout
|
||||
2. Tu perds le respect pour moi
|
||||
3. Ton amour diminue (comme avec ton ex)
|
||||
4. Tu restes par habitude ou tu pars
|
||||
5. **= Même cycle destructeur**
|
||||
|
||||
**Ce qui DOIT se passer :**
|
||||
1. Tu reconnais tes patterns toxiques
|
||||
2. Tu acceptes de travailler dessus
|
||||
3. Je pose mes limites clairement
|
||||
4. On construit relation équilibrée
|
||||
5. **= Cycle brisé, relation saine possible**
|
||||
|
||||
---
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
|
||||
**Hypothèses :**
|
||||
|
||||
**Scénario A : Elle ne voit pas le pattern (inconscient)**
|
||||
- Elle reproduit sans s'en rendre compte
|
||||
- Elle ne fait pas le lien avec son ex
|
||||
- Elle pense que "cette fois c'est différent"
|
||||
- **= Déni, besoin de prise de conscience**
|
||||
|
||||
**Scénario B : Elle voit mais ne peut pas s'empêcher**
|
||||
- Elle reconnaît le pattern
|
||||
- Mais c'est plus fort qu'elle
|
||||
- Elle a besoin d'aide (thérapie ?)
|
||||
- **= Problème profond, travail nécessaire**
|
||||
|
||||
**Scénario C : Elle teste inconsciemment**
|
||||
- Elle veut voir si je vais devenir doormat
|
||||
- Elle veut voir si je vais poser limites
|
||||
- C'est un test de respect
|
||||
- **= Si je cède, je perds ; si je pose limites, je gagne**
|
||||
|
||||
**Scénario D : Pattern toxique ancré**
|
||||
- C'est sa façon de fonctionner en relation
|
||||
- Elle ne peut/veut pas changer
|
||||
- **= Incompatibilité fondamentale**
|
||||
|
||||
---
|
||||
|
||||
### Questions à lui poser
|
||||
|
||||
**Questions sur le passé :**
|
||||
- [ ] Comment se sont terminées tes relations précédentes ?
|
||||
- [ ] Qu'est-ce qui a fait que tu as arrêté d'aimer ton ex ?
|
||||
- [ ] Est-ce qu'il cédait beaucoup ? Est-ce qu'il était devenu "doormat" ?
|
||||
- [ ] Est-ce que tu vois des similarités avec ce qui se passe entre nous maintenant ?
|
||||
|
||||
**Questions sur les patterns actuels :**
|
||||
- [ ] Est-ce que tu vois que tu réécris parfois les faits pour te positionner en victime ?
|
||||
- [ ] Est-ce que tu reconnais les patterns toxiques qu'on a documentés (inversions, manipulation) ?
|
||||
- [ ] Pourquoi tu penses que ces patterns se répètent ?
|
||||
- [ ] Es-tu prête à travailler sur ces patterns ?
|
||||
|
||||
**Questions sur le futur :**
|
||||
- [ ] Qu'est-ce qui va se passer si je deviens doormat et que je cède à tout ?
|
||||
- [ ] Est-ce que tu vas me respecter encore ? M'aimer encore ?
|
||||
- [ ] Ou est-ce que ça va se passer comme avec ton ex ?
|
||||
- [ ] Qu'est-ce qui doit changer pour qu'on ne reproduise pas le même cycle ?
|
||||
|
||||
**Question ultime :**
|
||||
- [ ] **Es-tu prête à reconnaître tes patterns toxiques et à faire le travail pour les changer ?**
|
||||
|
||||
---
|
||||
|
||||
### Solutions possibles que je vois
|
||||
|
||||
**Solution 1 : Reconnaissance et travail actif**
|
||||
- Tu reconnais les patterns toxiques (inversion réalité, manipulation)
|
||||
- Tu acceptes que c'est ton problème à résoudre, pas juste le mien
|
||||
- Tu travailles activement dessus (thérapie individuelle possible)
|
||||
- Je pose mes limites clairement
|
||||
- On construit relation équilibrée ensemble
|
||||
- **= Relation peut être sauvée**
|
||||
|
||||
**Solution 2 : Awareness sans changement immédiat**
|
||||
- Tu prends conscience des patterns
|
||||
- Tu ne peux pas changer du jour au lendemain
|
||||
- On établit protocole : Quand pattern se produit, je le pointe calmement
|
||||
- Tu acceptes quand je le pointe, tu ne défends pas
|
||||
- Progrès graduel mesuré
|
||||
- **= Possible mais long, nécessite patience et volonté des deux**
|
||||
|
||||
**Solution 3 : Je pose limites fermes**
|
||||
- Je ne cède plus sur inversions de réalité
|
||||
- Je confronte calmement chaque pattern toxique
|
||||
- Je refuse de devenir doormat
|
||||
- Si tu ne peux pas accepter → Incompatibilité révélée
|
||||
- **= Test : Peux-tu respecter quelqu'un qui pose limites ?**
|
||||
|
||||
**Solution 4 : Thérapie de couple**
|
||||
- On consulte professionnel ensemble
|
||||
- Pour identifier patterns et travailler dessus
|
||||
- Soutien externe pour briser le cycle
|
||||
- **= Si on veut vraiment sauver la relation**
|
||||
|
||||
**Solution 5 : Accepter l'incompatibilité**
|
||||
- Tu ne peux/veux pas changer les patterns
|
||||
- Je ne peux pas vivre avec ces patterns toxiques
|
||||
- On se sépare avant que ça devienne encore plus toxique
|
||||
- **= Fin nécessaire et saine**
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : [À définir - Timing CRITIQUE]
|
||||
|
||||
**Quand aborder ce sujet :**
|
||||
|
||||
**Option A : Si patterns toxiques continuent après discussion sur Inversion de réalité**
|
||||
- J'aborde d'abord Inversion de réalité (sujet spécifique)
|
||||
- Si elle refuse de reconnaître ou continue
|
||||
- → J'aborde le cycle global
|
||||
|
||||
**Option B : Si elle accepte tous mes compromis sans faire aucun effort de son côté**
|
||||
- Si sa réponse aux 7 messages = "Oui change toi, moi je reste comme je suis"
|
||||
- → J'aborde le déséquilibre et le cycle
|
||||
|
||||
**Option C : Si je sens qu'elle commence à perdre le respect**
|
||||
- Si son attitude change (mépris, indifférence)
|
||||
- → Intervention avant point de non-retour
|
||||
|
||||
**TIMING CRITIQUE : Ne pas attendre qu'il soit trop tard**
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Ce que j'ai dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points d'accord
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points de désaccord
|
||||
[À remplir après discussion]
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
[À remplir après discussion]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [ ] Poser limites claires sur patterns toxiques
|
||||
- [ ] Ne pas devenir doormat
|
||||
- [ ] Confronter calmement mais fermement quand pattern se produit
|
||||
|
||||
#### Ses actions
|
||||
- [ ] Reconnaître patterns toxiques
|
||||
- [ ] Travailler activement à les changer
|
||||
- [ ] Accepter confrontation quand pattern pointé
|
||||
- [ ] [Si nécessaire] Consulter thérapeute individuel
|
||||
|
||||
#### Actions communes
|
||||
- [ ] [Si retenu] Thérapie de couple
|
||||
- [ ] Briser le cycle ensemble
|
||||
|
||||
### Promesses créées
|
||||
[Lien vers Promesses_à_tenir.md si applicable]
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
[À remplir au fur et à mesure]
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes - CRITICAL
|
||||
|
||||
### Ma ligne rouge absolue
|
||||
|
||||
**Je ne deviendrai PAS doormat.**
|
||||
|
||||
**Si pour te garder je dois :**
|
||||
- Accepter gaslighting
|
||||
- Accepter inversions de réalité constantes
|
||||
- Accepter manipulation
|
||||
- Céder sur tout
|
||||
- Perdre mon identité
|
||||
|
||||
**→ Je préfère partir avec dignité**
|
||||
|
||||
---
|
||||
|
||||
### RED FLAGS ultimes
|
||||
|
||||
**Si elle :**
|
||||
- ❌ Refuse de reconnaître les patterns toxiques
|
||||
- ❌ Dit que c'est moi qui invente
|
||||
- ❌ Continue les patterns après discussion
|
||||
- ❌ Ne fait AUCUN effort de son côté
|
||||
- ❌ Attend juste que je devienne doormat
|
||||
|
||||
**→ Incompatibilité confirmée, relation toxique, JE PARS**
|
||||
|
||||
---
|
||||
|
||||
### La vérité dure
|
||||
|
||||
**Tu dois te fix, pas juste moi.**
|
||||
|
||||
**Si tu continues ces patterns :**
|
||||
1. Je vais devenir doormat (si je cède)
|
||||
2. Tu vas arrêter de m'aimer (comme ton ex)
|
||||
3. On va reproduire exactement le même cycle
|
||||
4. **= Issue inévitable : Fin toxique**
|
||||
|
||||
**Ou :**
|
||||
1. Je refuse de devenir doormat (je pose limites)
|
||||
2. Tu ne peux pas accepter quelqu'un qui te tient tête
|
||||
3. Tu pars ou tu sabotes
|
||||
4. **= Issue inévitable : Incompatibilité**
|
||||
|
||||
**La seule issue positive :**
|
||||
1. Tu reconnais patterns toxiques
|
||||
2. Tu travailles dessus activement
|
||||
3. J'établis limites saines
|
||||
4. On construit relation équilibrée
|
||||
5. **= Cycle brisé, relation peut survivre**
|
||||
|
||||
---
|
||||
|
||||
### Ce que cette discussion va révéler
|
||||
|
||||
**Cette discussion est THE test :**
|
||||
|
||||
**Si elle accepte et travaille :**
|
||||
- ✅ Elle est capable d'introspection
|
||||
- ✅ Elle veut vraiment changer
|
||||
- ✅ Relation a une chance
|
||||
- **= On peut construire quelque chose de sain**
|
||||
|
||||
**Si elle refuse ou défend :**
|
||||
- ❌ Elle n'est pas prête à se remettre en question
|
||||
- ❌ Elle va reproduire le cycle indéfiniment
|
||||
- ❌ Je vais souffrir comme ses ex
|
||||
- **= Je dois partir maintenant**
|
||||
|
||||
---
|
||||
|
||||
### Mon engagement
|
||||
|
||||
**Je vais :**
|
||||
- Te donner une chance de reconnaître et changer
|
||||
- Te soutenir dans ce travail si tu es sincère
|
||||
- Poser mes limites clairement mais avec respect
|
||||
- **Rester si tu fais le travail**
|
||||
|
||||
**Mais je vais aussi :**
|
||||
- Partir si tu refuses de voir le problème
|
||||
- Partir si patterns continuent malgré discussion
|
||||
- Partir si tu me demandes de devenir doormat
|
||||
- **Partir avec dignité plutôt que mourir à petit feu**
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : N/A
|
||||
**Raison de clôture** : N/A
|
||||
**Résumé final** : N/A
|
||||
|
||||
---
|
||||
|
||||
## Annexe : Timeline du cycle (pour référence)
|
||||
|
||||
### Avec son ex (hypothèse)
|
||||
1. **Honeymoon** → Tout va bien
|
||||
2. **Patterns toxiques apparaissent** → Il cède
|
||||
3. **Il devient doormat** → Elle perd respect
|
||||
4. **Elle arrête de l'aimer** → Reste par habitude
|
||||
5. **Fin toxique** → Rupture ou relation morte
|
||||
|
||||
### Avec nous (en cours)
|
||||
1. **Honeymoon (4 mois)** ✅ → Tout allait bien
|
||||
2. **Patterns toxiques apparaissent (oct 2025)** ⚠️ → Je commence à céder (7 messages)
|
||||
3. **Je deviens doormat ?** 🔴 → **POINT CRITIQUE : ON EST ICI**
|
||||
4. **Elle perd respect ?** → À éviter absolument
|
||||
5. **Fin toxique** → À éviter absolument
|
||||
|
||||
**ACTION NÉCESSAIRE : BRISER LE CYCLE MAINTENANT**
|
||||
177
conversation_topics/Inversion_de_réalité.md
Normal file
177
conversation_topics/Inversion_de_réalité.md
Normal file
@ -0,0 +1,177 @@
|
||||
# Inversion de réalité
|
||||
|
||||
**Status** : 🔵 En préparation
|
||||
**Priority** : High (Pattern toxique)
|
||||
**Date création** : 22 octobre 2025
|
||||
**Date dernière discussion** : N/A
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est important
|
||||
Tingting réécrit régulièrement les faits pour se positionner en victime, même quand la réalité est différente. Ce pattern est toxique et s'apparente à du gaslighting. Si ce comportement continue, la relation devient invivable car je ne peux plus me fier à sa version des événements.
|
||||
|
||||
### Déclencheur
|
||||
**Pattern observé 3 fois en octobre 2025 (probablement plus avant) :**
|
||||
|
||||
**Occurrence 1 - 20 octobre :**
|
||||
- **Réalité** : Elle refuse de parler 19-20 oct, silent treatment
|
||||
- **Sa version** : "Tu m'as abandonnée 2 jours"
|
||||
- **= Inversion complète de qui a fait quoi**
|
||||
|
||||
**Occurrence 2 - 21 octobre (soir) :**
|
||||
- **Réalité** : Je pars de la chambre pour la laisser se reposer (elle l'a demandé)
|
||||
- **Sa version** : "Tu ne veux pas me laisser me reposer"
|
||||
- **= Inversion immédiate alors que je fais exactement ce qu'elle demande**
|
||||
|
||||
**Occurrence 3 - [Autres à documenter si elle accepte discussion]**
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
|
||||
**Ce que je constate :**
|
||||
- Elle réécrit les faits de manière systématique
|
||||
- Toujours dans le sens "elle victime, moi coupable"
|
||||
- Quand je pointe la contradiction, elle ne l'accepte pas
|
||||
- Elle "résiste à la réalité factuelle"
|
||||
|
||||
**Interprétations possibles :**
|
||||
1. **Elle croit vraiment sa version** (mémoire biaisée par émotion)
|
||||
2. **Elle sait mais déforme consciemment** (manipulation)
|
||||
3. **Mécanisme de défense** (incapable d'admettre responsabilité)
|
||||
|
||||
**Impact sur moi :**
|
||||
- Je dois défendre la réalité factuelle constamment
|
||||
- Je ne peux plus faire confiance à sa version des événements
|
||||
- Je me sens gaslighté
|
||||
- **= Insupportable à long terme**
|
||||
|
||||
**Ce que j'ai observé :**
|
||||
> "Pattern établi : Elle réécrit les faits pour se victimiser"
|
||||
> "Alexis confronte mais elle n'accepte pas"
|
||||
> "= Elle résiste à la réalité factuelle"
|
||||
|
||||
---
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
|
||||
**Hypothèses :**
|
||||
- Elle ressent tellement fort l'émotion (abandon, rejet) qu'elle réécrit l'histoire pour matcher l'émotion
|
||||
- Elle ne fait peut-être pas la différence entre "comment je me suis sentie" et "ce qui s'est passé"
|
||||
- Elle pense peut-être que mes faits sont faux (conflit de mémoire)
|
||||
- Elle ne veut peut-être pas admettre sa part de responsabilité
|
||||
|
||||
**Différence culturelle possible :**
|
||||
- Concept de "face" chinois → Difficile d'admettre tort ?
|
||||
- Communication indirecte → Réécrit pour éviter confrontation directe ?
|
||||
|
||||
---
|
||||
|
||||
### Questions à lui poser
|
||||
|
||||
- [ ] Te souviens-tu des 3 occurrences que j'ai documentées ?
|
||||
- [ ] Comment te souviens-tu de ces événements toi ?
|
||||
- [ ] Comprends-tu pourquoi ça me pose un problème grave quand tu réécris les faits ?
|
||||
- [ ] Fais-tu la différence entre "comment je me suis sentie" et "ce qui s'est réellement passé" ?
|
||||
- [ ] Es-tu capable de reconnaître quand tu as tort ou que tu as contribué au problème ?
|
||||
- [ ] Peux-tu accepter qu'on ait des mémoires différentes parfois, sans que l'un de nous mente ?
|
||||
|
||||
---
|
||||
|
||||
### Solutions possibles que je vois
|
||||
|
||||
**Solution 1 : Distinction émotion vs faits**
|
||||
- On sépare clairement "comment tu t'es sentie" (toujours valide) et "ce qui s'est passé" (factuel)
|
||||
- Exemple : "Je me suis sentie abandonnée" (OK) vs "Tu m'as abandonnée" (pas OK si faux)
|
||||
- = Je valide l'émotion sans adopter sa version déformée des faits
|
||||
|
||||
**Solution 2 : Documentation en temps réel**
|
||||
- Quand conflit ou événement important, on note tous les deux notre version immédiatement
|
||||
- On compare après quand calmes
|
||||
- = Évite reconstruction de mémoire biaisée
|
||||
|
||||
**Solution 3 : Engagement à reconnaître sa part**
|
||||
- Elle accepte de reconnaître sa part de responsabilité quand elle a tort
|
||||
- Pas toujours "c'est lui le problème"
|
||||
- = Équilibre des responsabilités
|
||||
|
||||
**Solution 4 : Incompatibilité si refuse**
|
||||
- Si elle refuse de reconnaître ce pattern
|
||||
- Si elle continue à inverser la réalité malgré discussion
|
||||
- = Je ne peux pas vivre dans une relation où je suis constamment gaslighté
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : [À définir - Timing critique]
|
||||
|
||||
**Important :** Ce sujet doit être abordé APRÈS qu'elle ait vu que je fais des efforts sur ses griefs (Responsabilités, Setup sommeil). Sinon ça peut sembler défensif.
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Ce que j'ai dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points d'accord
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points de désaccord
|
||||
[À remplir après discussion]
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
[À remplir après discussion]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [ ] Valider ses émotions sans adopter sa version des faits
|
||||
- [ ] Pointer calmement quand inversion se produit
|
||||
|
||||
#### Ses actions
|
||||
- [ ] Reconnaître quand elle réécrit les faits
|
||||
- [ ] Faire la différence entre émotion et faits
|
||||
- [ ] Accepter sa part de responsabilité
|
||||
|
||||
#### Actions communes
|
||||
- [ ] [Si solution 2 retenue] Noter notre version des événements en temps réel
|
||||
|
||||
### Promesses créées
|
||||
[Lien vers Promesses_à_tenir.md si applicable]
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
[À remplir au fur et à mesure]
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
**RED FLAG si :**
|
||||
- Elle refuse de reconnaître le pattern
|
||||
- Elle continue malgré discussion
|
||||
- Elle me dit que c'est moi qui invente
|
||||
- **= Gaslighting confirmé, incompatibilité majeure**
|
||||
|
||||
**Ce sujet est NON-NÉGOCIABLE :**
|
||||
- Je ne peux pas vivre dans une relation où la réalité est constamment réécrite
|
||||
- Si elle ne peut pas arrêter ce pattern, la relation est impossible
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : N/A
|
||||
**Raison de clôture** : N/A
|
||||
**Résumé final** : N/A
|
||||
189
conversation_topics/Jeux_de_devinettes.md
Normal file
189
conversation_topics/Jeux_de_devinettes.md
Normal file
@ -0,0 +1,189 @@
|
||||
# Jeux de devinettes ("Figure it out")
|
||||
|
||||
**Status** : 🔵 En préparation
|
||||
**Priority** : Medium
|
||||
**Date création** : 22 octobre 2025
|
||||
**Date dernière discussion** : N/A
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est important
|
||||
Tingting refuse parfois de dire ce qui ne va pas et me demande de "deviner" ("Figure it out"). Ce pattern de communication est toxique, crée de la frustration et empêche toute résolution saine des problèmes.
|
||||
|
||||
### Déclencheur
|
||||
**19 octobre 2025 :**
|
||||
- Tingting en colère mais refuse de dire pourquoi
|
||||
- "Figure it out toi-même"
|
||||
- Silent treatment jusqu'à ce que je devine
|
||||
- **= Pattern de manipulation émotionnelle**
|
||||
|
||||
**Mon analyse à l'époque :**
|
||||
> "'Figure it out toi-même' - C'est littéralement de la manipulation toxique"
|
||||
> "Je refuse de jouer à ce jeu"
|
||||
> "Si elle refuse de communiquer, je pose des limites"
|
||||
|
||||
**Autres occurrences :**
|
||||
- [À documenter si pattern récurrent]
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
|
||||
**Ce que je constate :**
|
||||
- Elle attend que je devine ce qui ne va pas
|
||||
- Quand je ne devine pas, elle s'énerve encore plus
|
||||
- C'est un jeu où je ne peux pas gagner
|
||||
- **= Pattern de communication dysfonctionnel**
|
||||
|
||||
**Pourquoi c'est toxique :**
|
||||
1. **Met toute la charge sur moi** : Je dois deviner au lieu qu'elle communique
|
||||
2. **Setup for failure** : Si je devine mal, je suis encore plus coupable
|
||||
3. **Évite sa responsabilité** : Elle n'a pas à exprimer clairement ses besoins
|
||||
4. **Crée frustration** : Je ne peux pas résoudre un problème que je ne connais pas
|
||||
|
||||
**Impact sur moi :**
|
||||
- Frustration intense
|
||||
- Sentiment d'être manipulé
|
||||
- Épuisement mental (essayer de deviner constamment)
|
||||
- **= Inacceptable**
|
||||
|
||||
**Mon principe :**
|
||||
> "Je refuse de jouer aux jeux de devinettes. Si tu as un problème, dis-le. Sinon je ne peux pas le résoudre."
|
||||
|
||||
---
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
|
||||
**Hypothèses :**
|
||||
- Elle pense peut-être : "Si tu m'aimais vraiment, tu saurais"
|
||||
- Elle veut peut-être que je "prouve" mon attention en devinant
|
||||
- Elle a peut-être peur de verbaliser (honte, fierté)
|
||||
- Différence culturelle : Communication indirecte chinoise ?
|
||||
- Elle reproduit peut-être un pattern de ses relations passées
|
||||
|
||||
**Ou :**
|
||||
- C'est un power play conscient
|
||||
- Elle veut me voir supplier et chercher
|
||||
- Elle aime avoir le contrôle
|
||||
- **= Manipulation consciente**
|
||||
|
||||
---
|
||||
|
||||
### Questions à lui poser
|
||||
|
||||
- [ ] Pourquoi tu refuses parfois de me dire ce qui ne va pas ?
|
||||
- [ ] Qu'est-ce que tu attends que je "figure out" exactement ?
|
||||
- [ ] Penses-tu que si je t'aime, je devrais deviner automatiquement ?
|
||||
- [ ] Comprends-tu pourquoi ça me frustre et me met en position impossible ?
|
||||
- [ ] Es-tu prête à communiquer directement ce qui ne va pas ?
|
||||
- [ ] Qu'est-ce qui t'empêche de dire clairement "Voilà ce qui me dérange" ?
|
||||
|
||||
---
|
||||
|
||||
### Solutions possibles que je vois
|
||||
|
||||
**Solution 1 : Engagement à communication directe**
|
||||
- Quand elle a un problème, elle le dit clairement
|
||||
- Pas de "figure it out"
|
||||
- Pas de jeux de devinettes
|
||||
- = Communication adulte et saine
|
||||
|
||||
**Solution 2 : Protocole "J'ai besoin de temps"**
|
||||
- Si elle n'est pas prête à parler immédiatement, elle dit : "J'ai besoin de temps"
|
||||
- Elle revient vers moi quand elle peut exprimer clairement
|
||||
- Deadline raisonnable (24h max)
|
||||
- = Pas de silent treatment, mais temps pour formuler
|
||||
|
||||
**Solution 3 : Ma limite claire**
|
||||
- Je pose limite : "Je ne joue pas aux jeux de devinettes"
|
||||
- Si elle refuse de dire, je dis : "Quand tu seras prête à me dire clairement, je serai là"
|
||||
- Je ne cours pas après, je ne supplie pas
|
||||
- = Je protège ma santé mentale
|
||||
|
||||
**Solution 4 : Incompatibilité si refuse**
|
||||
- Si elle refuse de communiquer directement
|
||||
- Si elle insiste pour que je devine
|
||||
- = Je ne peux pas vivre dans une relation où je dois lire dans les pensées
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : [À définir]
|
||||
|
||||
**Timing recommandé :** Après qu'on ait établi de meilleurs patterns de communication (suite aux 3 promesses du 22 oct).
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Ce que j'ai dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points d'accord
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points de désaccord
|
||||
[À remplir après discussion]
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
[À remplir après discussion]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [ ] Ne pas jouer au jeu de devinettes
|
||||
- [ ] Poser limite calmement : "Dis-moi clairement ou je ne peux pas t'aider"
|
||||
|
||||
#### Ses actions
|
||||
- [ ] Communiquer directement ce qui ne va pas
|
||||
- [ ] Pas de "figure it out"
|
||||
- [ ] Si besoin de temps, le dire explicitement
|
||||
|
||||
#### Actions communes
|
||||
- [ ] [Si solution 2] Établir protocole "J'ai besoin de temps" avec deadline
|
||||
|
||||
### Promesses créées
|
||||
[Lien vers Promesses_à_tenir.md si applicable]
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
[À remplir au fur et à mesure]
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
**Ce pattern est lié à :**
|
||||
- Inversion de réalité (autre pattern toxique)
|
||||
- Communication indirecte générale
|
||||
- Pattern "I don't know" (elle dit souvent qu'elle ne sait pas)
|
||||
|
||||
**RED FLAG si :**
|
||||
- Elle refuse de reconnaître que c'est toxique
|
||||
- Elle dit que c'est mon job de deviner
|
||||
- Elle continue après discussion
|
||||
- **= Pattern de manipulation confirmé**
|
||||
|
||||
**Ma ligne rouge :**
|
||||
- Je ne supplie pas
|
||||
- Je ne cours pas après pour deviner
|
||||
- Je ne joue pas à ce jeu
|
||||
- **Si elle refuse de communiquer clairement, je me retire calmement**
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : N/A
|
||||
**Raison de clôture** : N/A
|
||||
**Résumé final** : N/A
|
||||
177
conversation_topics/Pattern_initiation_déséquilibré.md
Normal file
177
conversation_topics/Pattern_initiation_déséquilibré.md
Normal file
@ -0,0 +1,177 @@
|
||||
# Pattern initiation déséquilibré
|
||||
|
||||
**Status** : 🔵 En préparation
|
||||
**Priority** : Medium
|
||||
**Date création** : 22 octobre 2025
|
||||
**Date dernière discussion** : N/A
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est important
|
||||
Après chaque conflit, c'est toujours moi qui initie la résolution, la réconciliation, les excuses. Tingting ne vient jamais en premier. Ce déséquilibre crée du ressentiment et me donne l'impression de porter la relation seul.
|
||||
|
||||
### Déclencheur
|
||||
**Pattern observé répétitivement :**
|
||||
|
||||
**Crise 16-22 octobre 2025 :**
|
||||
- Guerre froide depuis le 18
|
||||
- 7 messages de ma part (22 oct)
|
||||
- 1 seule réponse d'elle : "I'm at meetings outside"
|
||||
- C'est encore moi qui ai fait tous les moves
|
||||
|
||||
**Observation d'Alexis (documentée) :**
|
||||
> "Pattern 'C'est toujours moi qui initie' (confirmé)"
|
||||
> "Après chaque fight, c'est lui"
|
||||
> "Tingting ne vient jamais en premier"
|
||||
> "= Déséquilibre persistant"
|
||||
|
||||
**Autres occurrences passées :**
|
||||
- [À documenter avec exemples précis si elle accepte discussion]
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
|
||||
**Ce que je constate :**
|
||||
- Je suis toujours celui qui tend la main en premier
|
||||
- Elle attend que je vienne
|
||||
- Même quand elle a tort, c'est moi qui initie la résolution
|
||||
- **= Je porte la charge émotionnelle de la réconciliation**
|
||||
|
||||
**Impact sur moi :**
|
||||
- Fatigue émotionnelle
|
||||
- Sentiment de porter la relation seul
|
||||
- Ressentiment qui s'accumule
|
||||
- Questionnement : "Est-ce qu'elle tient à la relation autant que moi ?"
|
||||
|
||||
**Questions que je me pose :**
|
||||
- Si je n'initie pas, est-ce qu'elle viendrait un jour ?
|
||||
- Est-ce qu'elle tient pour acquis que je vais toujours revenir ?
|
||||
- Est-ce de la paresse émotionnelle ou de la fierté ?
|
||||
|
||||
---
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
|
||||
**Hypothèses :**
|
||||
- Elle pense peut-être que c'est "le rôle de l'homme" d'initier
|
||||
- Elle a peut-être trop de fierté pour faire le premier pas
|
||||
- Elle attend peut-être que je "prouve" mon engagement en venant
|
||||
- Elle ne réalise peut-être pas que c'est toujours moi
|
||||
- Concept culturel chinois de "face" → Difficile de faire le premier pas ?
|
||||
|
||||
**Ou pire :**
|
||||
- Elle sait que je vais toujours venir → Elle n'a pas besoin de faire d'effort
|
||||
- Elle a le pouvoir dans la relation → Elle attend que je cède
|
||||
|
||||
---
|
||||
|
||||
### Questions à lui poser
|
||||
|
||||
- [ ] As-tu remarqué que c'est toujours moi qui initie la réconciliation après un conflit ?
|
||||
- [ ] Pourquoi tu ne viens jamais en premier ?
|
||||
- [ ] Est-ce que tu tiens pour acquis que je vais toujours revenir ?
|
||||
- [ ] Qu'est-ce qui t'empêche de faire le premier pas ?
|
||||
- [ ] Si je n'initiais pas, combien de temps tu attendrais avant de venir vers moi ?
|
||||
- [ ] Comprends-tu que ça crée du ressentiment chez moi ?
|
||||
|
||||
---
|
||||
|
||||
### Solutions possibles que je vois
|
||||
|
||||
**Solution 1 : Alternance explicite**
|
||||
- On alterne qui initie la résolution après conflit
|
||||
- Si c'était moi la dernière fois, c'est elle la prochaine fois
|
||||
- = Équilibre visible et mesurable
|
||||
|
||||
**Solution 2 : Règle "24h maximum"**
|
||||
- Après un conflit, celui qui n'a pas initié la dernière fois DOIT initier dans les 24h
|
||||
- Sinon l'autre peut initier
|
||||
- = Évite guerre froide prolongée + force équilibre
|
||||
|
||||
**Solution 3 : Elle s'engage à faire plus d'efforts**
|
||||
- Elle reconnaît le pattern
|
||||
- Elle s'engage à initier plus souvent
|
||||
- Pas de règle stricte, juste conscience et effort
|
||||
- = On teste si elle peut changer
|
||||
|
||||
**Solution 4 : Je teste en n'initiant pas une fois**
|
||||
- Prochaine fois qu'on a un conflit, je n'initie pas
|
||||
- Je vois combien de temps elle attend
|
||||
- = Test pour savoir si elle viendrait un jour
|
||||
- Risque : Guerre froide très longue
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : [À définir]
|
||||
|
||||
**Timing recommandé :** Après qu'on ait résolu 1-2 de ses griefs et que la relation soit plus stable.
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Ce que j'ai dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points d'accord
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points de désaccord
|
||||
[À remplir après discussion]
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
[À remplir après discussion]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [ ] Ne pas systématiquement initier (laisser place à son initiative)
|
||||
|
||||
#### Ses actions
|
||||
- [ ] Initier la réconciliation parfois
|
||||
- [ ] Reconnaître quand c'est son tour
|
||||
|
||||
#### Actions communes
|
||||
- [ ] [Si solution 1 ou 2] Suivre le système choisi
|
||||
|
||||
### Promesses créées
|
||||
[Lien vers Promesses_à_tenir.md si applicable]
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
[À remplir au fur et à mesure]
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
**Ce que ce sujet révèle :**
|
||||
- Déséquilibre de pouvoir dans la relation
|
||||
- Qui tient le plus à la relation ?
|
||||
- Capacité de Tingting à faire des efforts émotionnels
|
||||
|
||||
**RED FLAG si :**
|
||||
- Elle refuse de reconnaître le pattern
|
||||
- Elle dit que c'est "normal" que ce soit toujours moi
|
||||
- Elle ne fait aucun effort après discussion
|
||||
- **= Elle prend la relation pour acquise**
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : N/A
|
||||
**Raison de clôture** : N/A
|
||||
**Résumé final** : N/A
|
||||
57
conversation_topics/README.md
Normal file
57
conversation_topics/README.md
Normal file
@ -0,0 +1,57 @@
|
||||
# Conversation Topics - Système de suivi
|
||||
|
||||
## Objectif
|
||||
|
||||
Garder une trace structurée des sujets importants à aborder avec Tingting, et documenter les résultats des discussions.
|
||||
|
||||
## Comment ça marche
|
||||
|
||||
### 1. Préparation (avant discussion avec Tingting)
|
||||
- Créer un fichier pour le sujet (utiliser `_template.md`)
|
||||
- Analyser le sujet : contexte, enjeux, questions à poser
|
||||
- Rendre le sujet viable : clair, non-défensif, constructif
|
||||
|
||||
### 2. Discussion avec Tingting
|
||||
- Aborder le sujet au bon moment
|
||||
- Écouter, questionner, comprendre son point de vue
|
||||
- Noter mentalement les points importants
|
||||
|
||||
### 3. Documentation (après discussion)
|
||||
- Remplir le fichier avec :
|
||||
- Date de discussion
|
||||
- Ce qui a été dit (les deux perspectives)
|
||||
- Accords trouvés
|
||||
- Actions concrètes décidées
|
||||
- Créer promesses dans `Promesses_à_tenir.md` si nécessaire
|
||||
|
||||
### 4. Clôture
|
||||
- Quand sujet résolu : Déplacer dans `archive/`
|
||||
- Garder trace de la résolution
|
||||
|
||||
## Sujets actifs
|
||||
|
||||
### Ses griefs (à aborder en priorité)
|
||||
- [Responsabilités.md](Responsabilités.md) - 🟡 À discuter - Peur sur fiabilité future (mariage, kids)
|
||||
- [Setup_sommeil.md](Setup_sommeil.md) - 🟡 À discuter - Protocole pour éviter crashes
|
||||
- [Communication_patterns.md](Communication_patterns.md) - 🟢 Discuté via messages - Application des 3 promesses
|
||||
|
||||
### Mes griefs (à aborder après avoir montré des progrès sur les siens)
|
||||
- [Inversion_de_réalité.md](Inversion_de_réalité.md) - 🔵 En préparation - Pattern toxique de réécriture des faits (HIGH)
|
||||
- [Pattern_initiation_déséquilibré.md](Pattern_initiation_déséquilibré.md) - 🔵 En préparation - C'est toujours moi qui initie (MEDIUM)
|
||||
- [Jeux_de_devinettes.md](Jeux_de_devinettes.md) - 🔵 En préparation - "Figure it out" / Silent treatment (MEDIUM)
|
||||
- [Besoins_attention_contradictoires.md](Besoins_attention_contradictoires.md) - 🔵 En préparation - Se plaint mais refuse attention (MEDIUM)
|
||||
|
||||
### Sujet CRITIQUE (à aborder si patterns toxiques persistent)
|
||||
- [Cycle_auto_destructeur.md](Cycle_auto_destructeur.md) - 🔵 En préparation - **CRITICAL** - Patterns toxiques + risque de répéter cycle avec ex
|
||||
|
||||
## Règles importantes
|
||||
|
||||
1. **Un sujet = Un fichier** : Pas de mélange
|
||||
2. **Préparation avant discussion** : Ne pas improviser les sujets sensibles
|
||||
3. **Documentation après** : Ne pas se fier à la mémoire
|
||||
4. **Archive = Résolu** : Pas de sujet "en suspens éternel"
|
||||
|
||||
---
|
||||
|
||||
**Date création système** : 22 octobre 2025
|
||||
**Inspiré de** : Système utilisé au début de la relation avec Tingting (qui lui avait plu)
|
||||
170
conversation_topics/Responsabilités.md
Normal file
170
conversation_topics/Responsabilités.md
Normal file
@ -0,0 +1,170 @@
|
||||
# Responsabilités
|
||||
|
||||
**Status** : 🟡 À discuter
|
||||
**Priority** : High
|
||||
**Date création** : 22 octobre 2025
|
||||
**Date dernière discussion** : N/A (pas encore discuté)
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est important
|
||||
Tingting a peur qu'Alexis soit unreliable pour les grandes responsabilités futures (mariage, kids, vie de famille). Cette peur est venue suite au 18 octobre, mais touche à quelque chose de beaucoup plus profond que juste cet incident.
|
||||
|
||||
### Déclencheur
|
||||
**18 octobre 2025 - Samedi matin**
|
||||
- Setup sommeil raté → Alexis en mode larve
|
||||
- N'a pas préparé breakfast
|
||||
- N'a pas rassuré Tingting avant qu'elle prenne la route
|
||||
- S'est rendormi deux fois
|
||||
- → Tingting : "Why are you so mean?"
|
||||
- → "It was your responsibility this morning and you didn't fulfill it"
|
||||
- → **Sa vraie question : "Will I fulfill my responsibilities in the future? For marriage, kids, everything else?"**
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
|
||||
**Distinction PRENDRE vs RESPECTER :**
|
||||
|
||||
**✅ RESPECTER les responsabilités = Aucun problème**
|
||||
- Quand je prends une responsabilité clairement, je la respecte
|
||||
- **Exemple : Cooking every day**
|
||||
- J'ai pris cette responsabilité explicitement
|
||||
- Je la respecte avec constance
|
||||
- Très rarement je order (exception)
|
||||
- **= Je SUIS capable de responsabilité et de fiabilité**
|
||||
|
||||
**❌ PRENDRE les responsabilités = Mon problème**
|
||||
- J'ai du mal à identifier/prendre des responsabilités implicites
|
||||
- Je ne les garde pas en tête si elles ne sont pas cristallisées
|
||||
|
||||
**Le problème du 18 octobre :**
|
||||
- Je ne savais pas que j'avais une responsabilité ce matin-là
|
||||
- Je l'ai compris seulement **60 heures plus tard** (lundi soir, 20 oct)
|
||||
- Ce n'était pas clair pour moi dans le moment
|
||||
|
||||
**Conditions pour que je puisse tenir une responsabilité :**
|
||||
1. **Crystal clear context** - Pas de "maybe", pas d'assumptions
|
||||
2. **Affirmation explicite** - Je dois dire "Yes I will do this"
|
||||
3. **Roadmap claire** - Les étapes doivent être évidentes
|
||||
|
||||
**Sans ces 3 éléments : Je ne peux pas tenir la responsabilité en tête.**
|
||||
|
||||
---
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
|
||||
**Sa peur principale :**
|
||||
- "Si tu ne peux pas assumer un samedi matin, comment tu vas assumer le mariage ? Les enfants ? La vie ?"
|
||||
- Elle a besoin de fiabilité, de prévisibilité
|
||||
- Elle pense peut-être que je ne VEUX pas assumer (alors que je ne PEUX pas quand ce n'est pas clair)
|
||||
|
||||
**Ce qu'elle attend probablement :**
|
||||
- Que je SACHE sans qu'elle ait à dire
|
||||
- Que je prenne naturellement les responsabilités
|
||||
- Que je sois fiable même quand fatigué/épuisé
|
||||
|
||||
**Différence culturelle possible :**
|
||||
- Communication chinoise souvent indirecte
|
||||
- Mon besoin d'explicit communication peut lui sembler étrange
|
||||
- "Il devrait savoir" vs "Dis-moi clairement"
|
||||
|
||||
---
|
||||
|
||||
### Questions à lui poser
|
||||
|
||||
- [ ] Comprends-tu la différence entre PRENDRE et RESPECTER une responsabilité pour moi ?
|
||||
- [ ] Peux-tu accepter que j'ai besoin d'explicit communication pour prendre une responsabilité ?
|
||||
- [ ] Le 18 octobre : Si je t'avais dit explicitement la veille "Demain matin je prépare breakfast et je t'envoie message pour la route", penses-tu que j'aurais tenu cette responsabilité ?
|
||||
- [ ] Peux-tu me dire explicitement tes attentes quand tu en as ? Ou attends-tu que je devine ?
|
||||
- [ ] Si malgré communication explicite je ne tiens pas une responsabilité (urgence, mode larve, autre), comment on gère ça ?
|
||||
- [ ] Quelle est ta vraie peur sur les responsabilités futures (mariage, kids) ? Peur que je ne veuille pas ou que je ne puisse pas ?
|
||||
|
||||
---
|
||||
|
||||
### Solutions possibles que je vois
|
||||
|
||||
**Solution 1 : Communication explicite des responsabilités**
|
||||
- Tingting rend les attentes explicites : "Can you do X?"
|
||||
- Je réponds : "Yes, I will do X"
|
||||
- = Cristallisation de la responsabilité
|
||||
- Inconvénient : Charge mentale sur elle ("Il devrait savoir")
|
||||
|
||||
**Solution 2 : Protocole routine pour responsabilités récurrentes**
|
||||
- Établir des routines claires
|
||||
- Exemple : Chaque samedi matin visite parents = Breakfast + message réassurance
|
||||
- Je sais que CHAQUE samedi = ces responsabilités
|
||||
- Devient automatique, pas besoin de redemander
|
||||
- Inconvénient : Rigide si contexte change
|
||||
|
||||
**Solution 3 : Protocole "mauvaise nuit"**
|
||||
- Si je dors mal, je préviens immédiatement au réveil
|
||||
- Je prends 2 min MINIMUM pour communiquer clairement
|
||||
- Je rassure émotionnellement Tingting
|
||||
- = Elle sait à quoi s'attendre, pas de surprise
|
||||
- Inconvénient : En mode larve je peux ne pas être capable de communiquer
|
||||
|
||||
**Solution 4 : Accepter incompatibilité**
|
||||
- Si elle ne peut pas accepter mon besoin d'explicit communication
|
||||
- Si elle attend quelqu'un qui "sait sans qu'on lui dise"
|
||||
- = Je ne peux pas être cette personne
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : [En attente - elle décidera quand prête]
|
||||
|
||||
**Message envoyé (22 oct) :**
|
||||
> "I have been thinking about the responsibility question as well. I will make things clear when you are ready. You just have to tell me for this subject so you can have the answers you need."
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Ce que j'ai dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points d'accord
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points de désaccord
|
||||
[À remplir après discussion]
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
[À remplir après discussion]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [ ] [À remplir après discussion]
|
||||
|
||||
#### Ses actions
|
||||
- [ ] [À remplir après discussion]
|
||||
|
||||
#### Actions communes
|
||||
- [ ] [À remplir après discussion]
|
||||
|
||||
### Promesses créées
|
||||
[Lien vers Promesses_à_tenir.md si applicable]
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
[À remplir au fur et à mesure]
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : N/A
|
||||
**Raison de clôture** : N/A
|
||||
**Résumé final** : N/A
|
||||
161
conversation_topics/Setup_sommeil.md
Normal file
161
conversation_topics/Setup_sommeil.md
Normal file
@ -0,0 +1,161 @@
|
||||
# Setup sommeil
|
||||
|
||||
**Status** : 🟡 À discuter
|
||||
**Priority** : High
|
||||
**Date création** : 22 octobre 2025
|
||||
**Date dernière discussion** : N/A
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est important
|
||||
Le setup sommeil raté est la cause directe du conflit du 18 octobre. Sans setup correct, Alexis crashe en "mode larve" et devient totalement dysfonctionnel. Ce problème est récurrent et doit être résolu structurellement.
|
||||
|
||||
### Déclencheur
|
||||
**17-18 octobre 2025**
|
||||
- Soir du 17 : Tous les deux trop fatigués pour setup
|
||||
- Lumière allumée dans la chambre
|
||||
- Musique dans la pièce d'à côté
|
||||
- Alexis se réveille en pleine nuit à cause de la lumière
|
||||
- → Matin du 18 : Crash total en mode larve
|
||||
- → Conflit majeur avec Tingting
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
|
||||
**Sommeil d'Alexis = Extrêmement fragile**
|
||||
- Bruit et surtout lumière = Destruction totale du sommeil
|
||||
- Toujours sur mes gardes en dormant
|
||||
- A mis 6 mois pour m'habituer à dormir avec Tingting
|
||||
- Je voulais lits séparés avant même de vivre ensemble
|
||||
- Je dors quasi systématiquement mal chez les parents de Tingting
|
||||
|
||||
**Niveaux de fatigue :**
|
||||
- **Fatigué normal** : Je peux me forcer et fonctionner
|
||||
- **Mode larve** : Cerveau totalement dysfonctionnel, incapable de penser/communiquer clairement
|
||||
|
||||
**Quand setup raté :**
|
||||
- Mode larve garanti le lendemain
|
||||
- Je deviens unreliable
|
||||
- Je ne peux pas communiquer clairement
|
||||
- → Conflit inévitable
|
||||
|
||||
**Le soir du 17 octobre :**
|
||||
- On était tous les deux trop fatigués
|
||||
- Aucun de nous n'a insisté pour setup correct
|
||||
- On a laissé lumière/musique
|
||||
- → Erreur critique
|
||||
|
||||
---
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
|
||||
**Elle ne comprend pas (ou ne croit pas) que mon sommeil fragile est RÉEL et PHYSIOLOGIQUE**
|
||||
- Elle pense probablement que je pourrais me forcer si je voulais
|
||||
- Elle pense peut-être que j'exagère ou que j'utilise ça comme excuse
|
||||
- Elle ne voit pas la différence entre "fatigué normal" et "mode larve"
|
||||
|
||||
**D'où son "I cannot accept that" :**
|
||||
- Elle refuse que "je suis fatigué" soit une excuse acceptable
|
||||
- Elle veut que je sois fiable même fatigué
|
||||
- Mais elle ne réalise pas que c'est physiquement impossible en mode larve
|
||||
|
||||
---
|
||||
|
||||
### Questions à lui poser
|
||||
|
||||
- [ ] Comprends-tu que mon sommeil fragile est RÉEL et PHYSIOLOGIQUE, pas une excuse ?
|
||||
- [ ] Qu'est-ce qui te fait penser que j'exagère ou que je pourrais me forcer ?
|
||||
- [ ] Peux-tu voir la différence entre "fatigué normal" (je peux fonctionner) et "mode larve" (cerveau à 0%) ?
|
||||
- [ ] Le soir du 17, on était tous les deux trop fatigués pour setup. Comment on évite ça à l'avenir ?
|
||||
- [ ] Es-tu prête à faire du setup sommeil une priorité absolue, tous les soirs ?
|
||||
|
||||
---
|
||||
|
||||
### Solutions possibles que je vois
|
||||
|
||||
**Solution 1 : Setup sommeil strict et NON-NÉGOCIABLE**
|
||||
- Lumière éteinte obligatoire
|
||||
- Pas de bruit (musique ailleurs)
|
||||
- Environnement optimal systématique
|
||||
- Si l'un ne respecte pas, l'autre rappelle IMMÉDIATEMENT
|
||||
- Pas de "juste cette fois" ou "on est trop fatigués"
|
||||
- C'est une priorité absolue, sinon cycle vicieux
|
||||
|
||||
**Solution 2 : Protocole "trop fatigués pour setup"**
|
||||
- Si vraiment trop fatigués pour setup correct
|
||||
- → Alexis dort ailleurs cette nuit-là (canapé, autre pièce)
|
||||
- Mieux dormir seul correctement que mal ensemble
|
||||
- = Prévention du mode larve
|
||||
|
||||
**Solution 3 : Protocole "mauvaise nuit" (backup)**
|
||||
- Si malgré setup je dors mal
|
||||
- Je préviens immédiatement au réveil
|
||||
- Je prends 2 min MINIMUM pour communiquer clairement
|
||||
- Je rassure émotionnellement Tingting
|
||||
- = Elle sait à quoi s'attendre, pas de surprise
|
||||
|
||||
**Solution 4 : Lits séparés (option nucléaire)**
|
||||
- Si le problème continue malgré tout
|
||||
- Ce que je voulais à la base
|
||||
- Pas un rejet, une solution pratique
|
||||
- = Garantie de sommeil correct
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : [À définir]
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Ce que j'ai dit
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points d'accord
|
||||
[À remplir après discussion]
|
||||
|
||||
### Points de désaccord
|
||||
[À remplir après discussion]
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
[À remplir après discussion]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [ ] Appliquer le setup strict dès ce soir
|
||||
- [ ] Rappeler si setup pas correct
|
||||
|
||||
#### Ses actions
|
||||
- [ ] Appliquer le setup strict dès ce soir
|
||||
- [ ] Rappeler si setup pas correct
|
||||
|
||||
#### Actions communes
|
||||
- [ ] Faire du setup sommeil une priorité absolue mutuelle
|
||||
|
||||
### Promesses créées
|
||||
[Lien vers Promesses_à_tenir.md si applicable]
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
[À remplir au fur et à mesure]
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : N/A
|
||||
**Raison de clôture** : N/A
|
||||
**Résumé final** : N/A
|
||||
97
conversation_topics/_template.md
Normal file
97
conversation_topics/_template.md
Normal file
@ -0,0 +1,97 @@
|
||||
# [Nom du sujet]
|
||||
|
||||
**Status** : 🔵 En préparation | 🟡 À discuter | 🟢 Discuté | ✅ Résolu
|
||||
**Priority** : High | Medium | Low
|
||||
**Date création** : [Date]
|
||||
**Date dernière discussion** : [Date ou N/A]
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet est important
|
||||
[Expliquer le problème ou l'enjeu]
|
||||
|
||||
### Déclencheur
|
||||
[Qu'est-ce qui a fait remonter ce sujet ? Incident spécifique ?]
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
[Ma perspective, mes observations]
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
[Tenter de comprendre sa perspective]
|
||||
|
||||
### Questions à lui poser
|
||||
- [ ] Question 1
|
||||
- [ ] Question 2
|
||||
- [ ] Question 3
|
||||
|
||||
### Solutions possibles que je vois
|
||||
1. Solution A : [Description]
|
||||
2. Solution B : [Description]
|
||||
3. Solution C : [Description]
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : [Date de la discussion]
|
||||
|
||||
### Ce qu'elle a dit
|
||||
[Résumé de sa perspective, ses besoins, ses peurs]
|
||||
|
||||
### Ce que j'ai dit
|
||||
[Résumé de ma perspective, mes propositions]
|
||||
|
||||
### Points d'accord
|
||||
- Point 1
|
||||
- Point 2
|
||||
|
||||
### Points de désaccord
|
||||
- Point 1
|
||||
- Point 2
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
- Accord 1 : [Description]
|
||||
- Accord 2 : [Description]
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [ ] Action 1 - Deadline : [Date]
|
||||
- [ ] Action 2 - Deadline : [Date]
|
||||
|
||||
#### Ses actions
|
||||
- [ ] Action 1 - Deadline : [Date]
|
||||
|
||||
#### Actions communes
|
||||
- [ ] Action 1 - Deadline : [Date]
|
||||
|
||||
### Promesses créées
|
||||
[Lien vers Promesses_à_tenir.md si applicable]
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
### [Date] - Update 1
|
||||
[Ce qui s'est passé depuis la discussion]
|
||||
|
||||
### [Date] - Update 2
|
||||
[Évolution]
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : [Date ou N/A]
|
||||
**Raison de clôture** : [Résolu / Abandonné / Autre]
|
||||
**Résumé final** : [Comment le sujet a été résolu]
|
||||
110
conversation_topics/archive/exemple_résolu.md
Normal file
110
conversation_topics/archive/exemple_résolu.md
Normal file
@ -0,0 +1,110 @@
|
||||
# Exemple : Planification des week-ends
|
||||
|
||||
**Status** : ✅ Résolu
|
||||
**Priority** : Medium
|
||||
**Date création** : 1er septembre 2025
|
||||
**Date dernière discussion** : 15 septembre 2025
|
||||
**Date de résolution** : 15 septembre 2025
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Pourquoi ce sujet était important
|
||||
On se retrouvait souvent le vendredi soir sans plan pour le week-end, ce qui créait de la frustration et des disputes de dernière minute.
|
||||
|
||||
### Déclencheur
|
||||
Vendredi 30 août : Dispute parce qu'elle voulait voir ses parents, moi je voulais rester à la maison. Aucun des deux n'était au courant des attentes de l'autre.
|
||||
|
||||
---
|
||||
|
||||
## Préparation (avant discussion)
|
||||
|
||||
### Mon analyse du problème
|
||||
- Je n'aime pas planifier trop à l'avance, je préfère la spontanéité
|
||||
- Mais je comprends que ça la stresse de ne pas savoir
|
||||
- On a besoin d'un compromis entre planification et flexibilité
|
||||
|
||||
### Ce que je pense qu'elle ressent/pense
|
||||
- Elle a besoin de prévisibilité
|
||||
- Elle veut savoir si elle peut dire "oui" ou "non" à ses parents quand ils demandent
|
||||
- Elle se sent stressée quand on improvise tout
|
||||
|
||||
### Questions à lui poser
|
||||
- [✅] Combien de temps à l'avance tu as besoin de savoir ?
|
||||
- [✅] Est-ce que tu veux planifier tout ou juste les grandes lignes ?
|
||||
- [✅] Comment on peut garder de la flexibilité tout en te rassurant ?
|
||||
|
||||
### Solutions possibles que je vois
|
||||
1. Solution A : Planifier le mercredi pour le week-end à venir
|
||||
2. Solution B : Avoir des règles par défaut (ex: samedi = parents sauf si autre plan)
|
||||
3. Solution C : Elle gère samedi, je gère dimanche
|
||||
|
||||
---
|
||||
|
||||
## Discussion avec Tingting
|
||||
|
||||
### Date : 15 septembre 2025
|
||||
|
||||
### Ce qu'elle a dit
|
||||
- Elle a besoin de savoir à l'avance si on va quelque part
|
||||
- Elle se sent stressée quand il n'y a pas de plan
|
||||
- Elle veut qu'on décide ensemble, pas chacun de son côté
|
||||
- Le mercredi c'est bien pour elle comme timing
|
||||
|
||||
### Ce que j'ai dit
|
||||
- Je suis d'accord pour planifier à l'avance
|
||||
- Je propose qu'on se pose le mercredi soir pour décider du week-end
|
||||
- Je veux qu'on ait aussi du temps spontané, pas tout planifié
|
||||
- Dimanche peut rester plus flexible
|
||||
|
||||
### Points d'accord
|
||||
- Planifier le mercredi = Bon timing
|
||||
- On décide ensemble
|
||||
- Samedi généralement structuré, dimanche plus libre
|
||||
|
||||
### Points de désaccord
|
||||
- Aucun désaccord majeur
|
||||
|
||||
---
|
||||
|
||||
## Résultats
|
||||
|
||||
### Accords trouvés
|
||||
- Chaque mercredi soir : Prendre 15 minutes pour planifier le week-end
|
||||
- Samedi = Généralement visite parents ou sorties planifiées
|
||||
- Dimanche = Plus flexible, peut rester à la maison
|
||||
|
||||
### Actions décidées
|
||||
|
||||
#### Mes actions
|
||||
- [✅] Mettre rappel dans mon phone pour mercredi soir - Fait
|
||||
- [✅] Proposer des idées pour week-end - Fait chaque semaine depuis
|
||||
|
||||
#### Actions communes
|
||||
- [✅] Discuter ensemble chaque mercredi - Fait depuis 4 semaines
|
||||
|
||||
### Promesses créées
|
||||
Aucune promesse formelle, juste accord mutuel.
|
||||
|
||||
---
|
||||
|
||||
## Suivi
|
||||
|
||||
### 22 septembre - Update 1
|
||||
Première semaine : Ça marche bien. On a planifié samedi chez ses parents, dimanche repos à la maison. Pas de dispute.
|
||||
|
||||
### 29 septembre - Update 2
|
||||
Deuxième semaine : Pareil. Elle se sent beaucoup moins stressée. Moi aussi je préfère savoir à l'avance finalement.
|
||||
|
||||
### 13 octobre - Update 3
|
||||
Ça fait 4 semaines que le système marche. On n'a pas eu une seule dispute sur les week-ends depuis. Je considère le sujet résolu.
|
||||
|
||||
---
|
||||
|
||||
## Clôture
|
||||
|
||||
**Date de résolution** : 15 septembre 2025
|
||||
**Raison de clôture** : Résolu - Le système marche bien depuis 4 semaines
|
||||
**Résumé final** :
|
||||
Depuis qu'on planifie le mercredi, on n'a plus eu de dispute sur les week-ends. Elle se sent rassurée, je sais à quoi m'attendre. Win-win. Le système est devenu une routine naturelle.
|
||||
62
couple_backlog/10_août.md
Normal file
62
couple_backlog/10_août.md
Normal file
@ -0,0 +1,62 @@
|
||||
# 10 août 2025
|
||||
**Type :** Discussion/Conflict
|
||||
|
||||
## 1. Contexte
|
||||
Mi-août, Alexis exprime sa frustration concernant l'implication de Tingting.
|
||||
|
||||
## 2. Déclencheur
|
||||
Alexis dit à Tingting qu'elle ne s'implique pas assez, sans expliquer spécifiquement dans quoi.
|
||||
|
||||
## 3. Positions
|
||||
### Position d'Alexis
|
||||
- Sentiment que Tingting ne s'implique pas suffisamment
|
||||
- Manque de précision sur ce qu'il attend exactement
|
||||
- Frustration non clairement communiquée
|
||||
|
||||
### Position de Tingting
|
||||
- Incompréhension face à l'accusation d'Alexis
|
||||
- Manque de clarté sur ce qui est attendu d'elle
|
||||
- Confusion sur les attentes spécifiques
|
||||
|
||||
## 4. Émotions
|
||||
### Émotions d'Alexis
|
||||
- Frustration
|
||||
- Sentiment de porter seul certaines responsabilités
|
||||
|
||||
### Émotions de Tingting
|
||||
- Confusion
|
||||
- Possiblement sentiment d'injustice face à une critique vague
|
||||
|
||||
## 5. Résolution
|
||||
Non résolue à l'époque - clarification seulement lors de la discussion du 21 septembre.
|
||||
|
||||
## 6. Analyse selon les 4 dimensions
|
||||
|
||||
### Contexte
|
||||
- **Communication imprécise** : Alexis ne spécifie pas ses attentes
|
||||
- **Malentendus** : Messages flous créent de la confusion
|
||||
|
||||
### Émotions
|
||||
- **Frustration non exprimée** : Alexis porte ses attentes sans les communiquer
|
||||
- **Défense** : Tingting ne peut pas répondre à une critique vague
|
||||
|
||||
### Personnalité
|
||||
- **Traits d'Alexis impliqués** : Difficulté à exprimer ses besoins clairement
|
||||
- **Traits de Tingting impliqués** : Besoin de clarté pour agir
|
||||
- **Communication indirecte** : Les deux peinent à se comprendre
|
||||
|
||||
### Logique
|
||||
- **Faits objectifs** : Communication floue génère des malentendus
|
||||
- **Solutions possibles** : Spécifier les attentes et besoins
|
||||
- **Compromis envisageables** : Dialogue plus structuré sur les attentes mutuelles
|
||||
|
||||
## 7. Leçons apprises
|
||||
Révèle le problème de communication d'Alexis : il attend des choses sans les demander explicitement.
|
||||
|
||||
## 8. Actions concrètes
|
||||
Clarification tardive le 21 septembre : Tingting explique qu'elle ne peut pas deviner - il faut qu'Alexis demande spécifiquement.
|
||||
|
||||
---
|
||||
|
||||
**Date de création** : 21 septembre 2025
|
||||
**Statut** : Clarifié rétrospectivement
|
||||
60
couple_backlog/10_mai.md
Normal file
60
couple_backlog/10_mai.md
Normal file
@ -0,0 +1,60 @@
|
||||
# 10 mai 2025
|
||||
**Type :** Fight
|
||||
|
||||
## 1. Contexte
|
||||
Fight concernant la nourriture qui périme dans la cuisine.
|
||||
|
||||
## 2. Déclencheur
|
||||
*[À compléter : Événement précis lié à la nourriture périmée]*
|
||||
|
||||
## 3. Positions
|
||||
### Position d'Alexis
|
||||
*[À compléter]*
|
||||
|
||||
### Position de Tingting
|
||||
*[À compléter]*
|
||||
|
||||
## 4. Émotions
|
||||
### Émotions d'Alexis
|
||||
*[À compléter]*
|
||||
|
||||
### Émotions de Tingting
|
||||
*[À compléter]*
|
||||
|
||||
## 5. Résolution
|
||||
*[À compléter]*
|
||||
|
||||
## 6. Analyse selon les 4 dimensions
|
||||
|
||||
### Contexte
|
||||
- **Facteurs culturels** :
|
||||
- **Barrières linguistiques** :
|
||||
- **Facteurs externes** :
|
||||
|
||||
### Émotions
|
||||
- **Déclencheurs émotionnels** :
|
||||
- **Incompréhensions** :
|
||||
|
||||
### Personnalité
|
||||
- **Traits d'Alexis impliqués** :
|
||||
- **Traits de Tingting impliqués** :
|
||||
- **Incompatibilités** :
|
||||
|
||||
### Logique
|
||||
- **Faits objectifs** :
|
||||
- **Solutions possibles** :
|
||||
- **Compromis envisageables** :
|
||||
|
||||
## 7. Leçons apprises
|
||||
*[À compléter]*
|
||||
|
||||
## 8. Actions concrètes
|
||||
*[À compléter]*
|
||||
|
||||
## 9. Impact long terme
|
||||
**Note importante :** Selon Alexis, ce fight a marqué le début de sa perte de respect pour Tingting concernant sa gestion émotionnelle et son intelligence.
|
||||
|
||||
---
|
||||
|
||||
**Date de création** : 21 septembre 2025
|
||||
**Statut** : *[À compléter]*
|
||||
48
couple_backlog/15_septembre_2024.md
Normal file
48
couple_backlog/15_septembre_2024.md
Normal file
@ -0,0 +1,48 @@
|
||||
# 15 septembre 2024
|
||||
**Type :** Succès de leadership
|
||||
|
||||
## 1. Contexte
|
||||
Tingting partage un problème personnel concernant une amie qui lui a dit qu'elle l'aimait.
|
||||
|
||||
## 2. Situation
|
||||
Tingting cherche des conseils sur comment gérer cette situation délicate avec son amie.
|
||||
|
||||
## 3. Approche d'Alexis
|
||||
- **Méthode socratique** : Pose des questions pour la guider dans sa réflexion
|
||||
- **Position équilibrée** : Comprend les deux parties (Tingting et son amie)
|
||||
- **Leadership guidé** : Amène Tingting à trouver ses propres solutions
|
||||
|
||||
## 4. Résolution
|
||||
Problème résolu grâce à l'approche d'Alexis. Tingting trouve une solution appropriée.
|
||||
|
||||
## 5. Analyse
|
||||
|
||||
### Points forts d'Alexis
|
||||
- **Questions pertinentes** : Guide la réflexion sans imposer
|
||||
- **Empathie multi-perspectives** : Comprend tous les points de vue
|
||||
- **Facilitation** : Aide Tingting à structurer sa pensée
|
||||
|
||||
### Résultat
|
||||
- **Succès concret** : Problème résolu efficacement
|
||||
- **Tingting satisfaite** : Apprécie cette approche de leadership
|
||||
- **Preuve de capacité** : Alexis PEUT lead quand il utilise la bonne méthode
|
||||
|
||||
## 6. Leçons importantes
|
||||
|
||||
### Pour Alexis
|
||||
- **Il possède les compétences** de leadership socratique
|
||||
- **Il réussit quand il guide** au lieu de commander
|
||||
- **Sa force = faciliter la réflexion** d'autrui
|
||||
|
||||
### Pour le couple
|
||||
- **Méthode prouvée** : Cette approche fonctionne avec Tingting
|
||||
- **Modèle à reproduire** : Pour les décisions de couple
|
||||
- **Confiance mutuelle** : Tingting fait confiance à son guidage
|
||||
|
||||
## 7. Application future
|
||||
**Exemple concret de ce qu'elle demande** : Reproduire cette approche pour les projets de couple (vacances, sorties, plans de vie).
|
||||
|
||||
---
|
||||
|
||||
**Date de création** : 21 septembre 2025
|
||||
**Statut** : Succès documenté - Modèle à reproduire
|
||||
230
couple_backlog/16_octobre_2025.md
Normal file
230
couple_backlog/16_octobre_2025.md
Normal file
@ -0,0 +1,230 @@
|
||||
# 16 octobre 2025 - Grief non avoué : Réveil et gueule silencieuse
|
||||
|
||||
**Type** : ⚠️ Tension non résolue - Premier signe d'accumulation vers le conflit du 18
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
- **Quand** : Matin du 16 octobre 2025
|
||||
- **Où** : Appartement puis école
|
||||
- **Situation** : Alexis a cours, doit se lever
|
||||
|
||||
---
|
||||
|
||||
## Ce qui s'est passé
|
||||
|
||||
### Matin - Le réveil raté
|
||||
|
||||
**Faits :**
|
||||
- Tingting ne réveille pas Alexis (volontairement ? oubli ? pas clair)
|
||||
- Alexis loupe ses cours
|
||||
- Alexis est mécontent (a-t-il exprimé clairement ? pas certain)
|
||||
|
||||
**Responsabilité floue :**
|
||||
- Qui est censé gérer le réveil d'Alexis ?
|
||||
- Alexis lui-même (alarmes) ?
|
||||
- Tingting (accord établi) ?
|
||||
- **Flou = source de grief**
|
||||
|
||||
### Suite - La gueule silencieuse
|
||||
|
||||
**À l'école (même jour) :**
|
||||
- Tingting fait la gueule
|
||||
- Alexis demande ce qui ne va pas
|
||||
- **Sa réponse : "Je ne sais pas pourquoi"**
|
||||
|
||||
**Analyse d'Alexis :**
|
||||
- Elle ment ou se ment à elle-même
|
||||
- Elle est en colère parce qu'il ne s'est pas levé tout seul
|
||||
- **Grief non avoué = accumulation commence**
|
||||
|
||||
---
|
||||
|
||||
## Analyse
|
||||
|
||||
### Pattern révélé : Grief caché
|
||||
|
||||
**Ce qui s'est passé :**
|
||||
1. Quelque chose dérange Tingting (Alexis ne s'est pas levé)
|
||||
2. Elle ne le dit PAS clairement
|
||||
3. Elle fait la gueule
|
||||
4. Quand on lui demande : "Je ne sais pas"
|
||||
5. Le grief s'accumule en silence
|
||||
|
||||
**= Communication toxique en formation**
|
||||
|
||||
### Ambiguïté de responsabilité
|
||||
|
||||
**Question non résolue :**
|
||||
- **Qui est responsable du réveil d'Alexis ?**
|
||||
|
||||
**Si c'est Alexis :**
|
||||
- Alors Tingting n'a pas à être en colère s'il ne se lève pas
|
||||
- Mais alors pourquoi ne l'a-t-elle pas dit clairement ?
|
||||
|
||||
**Si c'est Tingting :**
|
||||
- Alors elle a "raté" son job
|
||||
- Et elle est en colère contre elle-même mais projette sur Alexis ?
|
||||
- Ou elle est en colère qu'Alexis ne se lève pas même après qu'elle l'ait réveillé ?
|
||||
|
||||
**Flou = Problème**
|
||||
|
||||
### Réaction d'Alexis (pas documentée complètement)
|
||||
|
||||
**Ce qu'on sait :**
|
||||
- Il était mécontent d'avoir loupé ses cours
|
||||
- A-t-il dit clairement à Tingting qu'il était mécontent qu'elle ne l'ait pas réveillé ?
|
||||
- Oui clairement ?
|
||||
- Passif-agressif ?
|
||||
- Rien dit du tout ?
|
||||
- **Pas clair → À clarifier dans la conversation critique**
|
||||
|
||||
---
|
||||
|
||||
## Conséquences
|
||||
|
||||
### Court terme (16-17 octobre)
|
||||
|
||||
**Le grief non résolu crée une tension sous-jacente :**
|
||||
- Le 17 au soir : "Tous les deux trop fatigués pour setup sommeil"
|
||||
- Vraiment juste fatigués physiquement ?
|
||||
- **OU tension du 16 → aucun des deux ne fait l'effort → passif-agressif mutuel ?**
|
||||
|
||||
**Résultat : Setup raté → Alexis crashe le 18**
|
||||
|
||||
### Moyen terme (18 octobre)
|
||||
|
||||
**Le grief du 16 contribue à l'explosion du 18 :**
|
||||
- Sa colère le 18 n'est PAS juste pour le 18
|
||||
- C'est 16 + 17 + 18 qui explosent ensemble
|
||||
- **Colère disproportionnée pour le 18 seul = accumulation confirmée**
|
||||
|
||||
---
|
||||
|
||||
## Ce qui aurait dû se passer (idéal)
|
||||
|
||||
### Communication directe immédiate
|
||||
|
||||
**Version idéale du 16 :**
|
||||
|
||||
**Si Tingting était en colère :**
|
||||
- "Je suis en colère parce que tu ne t'es pas levé tout seul / même après que je t'ai réveillé"
|
||||
- Discussion claire sur la responsabilité du réveil
|
||||
- Résolution immédiate
|
||||
|
||||
**Si Alexis était mécontent :**
|
||||
- "Je suis mécontent que tu ne m'aies pas réveillé. On avait dit quoi exactement ?"
|
||||
- Clarification de la responsabilité
|
||||
- Résolution immédiate
|
||||
|
||||
**Résultat si communication directe :**
|
||||
- Pas d'accumulation
|
||||
- Pas de gueule silencieuse
|
||||
- Pas de tension sous-jacente
|
||||
- Conflit du 18 peut-être évité ou moins intense
|
||||
|
||||
---
|
||||
|
||||
## Apprentissages
|
||||
|
||||
### Ce qui n'a pas marché
|
||||
|
||||
1. **Communication indirecte** : "Je ne sais pas pourquoi je suis en colère" (mensonge/déni)
|
||||
2. **Griefs non exprimés** : Accumulation en silence
|
||||
3. **Responsabilités floues** : Qui fait quoi n'est pas clair
|
||||
4. **Gueule passive-agressive** : Au lieu de discussion directe
|
||||
|
||||
### Pattern à changer (critique)
|
||||
|
||||
**Le cycle toxique :**
|
||||
1. Quelque chose dérange
|
||||
2. On ne le dit pas clairement
|
||||
3. On fait la gueule / on accumule
|
||||
4. Ça explose plus tard sur autre chose
|
||||
|
||||
**= DOIT changer pour que la relation soit saine**
|
||||
|
||||
---
|
||||
|
||||
## Suivi nécessaire
|
||||
|
||||
### Dans la conversation critique (quand Tingting rentre)
|
||||
|
||||
**☐ Aborder le 16 octobre explicitement :**
|
||||
- "Le 16, tu ne m'as pas réveillé et j'ai loupé mes cours. J'étais mécontent."
|
||||
- "Puis tu as fait la gueule en disant 'je ne sais pas pourquoi'."
|
||||
- "Je pense que tu étais en colère parce que je ne me suis pas levé. Est-ce que c'est vrai ?"
|
||||
|
||||
**☐ Clarifier la responsabilité du réveil :**
|
||||
- Qui est responsable : Alexis (alarmes) ou Tingting ou partagé ?
|
||||
- Accord clair pour éviter futurs griefs
|
||||
|
||||
**☐ Adresser le pattern communication :**
|
||||
- "Quand tu es en colère, tu dois me le dire clairement, pas dire 'je ne sais pas'"
|
||||
- "Sinon ça s'accumule et ça explose"
|
||||
|
||||
### Solutions à mettre en place
|
||||
|
||||
**Option A - Responsabilité claire :**
|
||||
- Alexis = alarmes, responsabilité totale
|
||||
- Tingting n'a pas à s'en occuper ni à être en colère s'il loupe
|
||||
|
||||
**Option B - Responsabilité partagée :**
|
||||
- Alexis = alarmes (responsabilité principale)
|
||||
- Tingting = backup si elle voit qu'il ne se lève pas
|
||||
- Mais accord clair, pas flou
|
||||
|
||||
**Option C - Responsabilité de Tingting :**
|
||||
- Si c'est son job, elle s'engage à le faire
|
||||
- Si elle oublie, elle reconnaît, pas de gueule
|
||||
|
||||
**→ À décider ensemble dans la conversation**
|
||||
|
||||
---
|
||||
|
||||
## Lien avec autres événements
|
||||
|
||||
**Cascade 16 → 17 → 18 :**
|
||||
|
||||
- **16 octobre** : Grief non résolu (réveil) → Tension sous-jacente
|
||||
- **17 octobre** : Tension persiste → Setup raté (possiblement lié)
|
||||
- **18 octobre** : Alexis crashe + accumulation explose
|
||||
|
||||
**= Pattern d'escalade par non-communication**
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
- **Cet événement semblait mineur sur le moment**
|
||||
- **Mais c'est le déclencheur de la cascade**
|
||||
- **Montre l'importance de résoudre les petits griefs immédiatement**
|
||||
- **"Je ne sais pas pourquoi je suis en colère" est un RED FLAG de communication**
|
||||
|
||||
---
|
||||
|
||||
## Questions non résolues (à clarifier dans conversation)
|
||||
|
||||
1. **Tingting l'a-t-elle réveillé ou non ce matin-là ?**
|
||||
- Si oui : Elle est en colère qu'il ne se lève pas malgré ça ?
|
||||
- Si non : Pourquoi pas ? Oubli ? Choix conscient ?
|
||||
|
||||
2. **Alexis a-t-il exprimé clairement son mécontentement ?**
|
||||
- Oui directement ?
|
||||
- Passif-agressif ?
|
||||
- Rien dit ?
|
||||
|
||||
3. **Pourquoi elle a dit "je ne sais pas" alors qu'elle savait probablement ?**
|
||||
- Évite la confrontation ?
|
||||
- Vraiment confuse elle-même ?
|
||||
- Habitude de communication indirecte ?
|
||||
|
||||
4. **Quel est l'accord réel sur le réveil ?**
|
||||
- Jamais clairement établi ?
|
||||
- Établi mais oublié/ignoré ?
|
||||
- Interprété différemment par chacun ?
|
||||
|
||||
---
|
||||
|
||||
**Conclusion** : Incident apparemment mineur qui révèle un pattern de communication toxique (griefs cachés → accumulation → explosion). Premier maillon de la chaîne qui mène au conflit du 18 octobre. DOIT être adressé dans la conversation critique pour éviter répétition du cycle.
|
||||
149
couple_backlog/17_octobre_2025.md
Normal file
149
couple_backlog/17_octobre_2025.md
Normal file
@ -0,0 +1,149 @@
|
||||
# 17 octobre 2025 - Tingting dort avec sa "fille adoptive"
|
||||
|
||||
**Type** : ⚡ Mixte (situation délicate mais bien gérée)
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
- **Quand** : 17-18 octobre 2025 (arrangement discuté le 17)
|
||||
- **Où** : Chez les parents de la jeune fille
|
||||
- **Qui** : Tingting + jeune fille de 16 ans (relation "mère-fille" émotionnelle)
|
||||
- **Timing** : Proche du mariage (imminent)
|
||||
- **Fréquence** : 1 fois par an, tradition établie
|
||||
|
||||
## Situation
|
||||
|
||||
La jeune fille (16 ans) que Tingting considère comme sa "fille adoptive" avait l'expectation (comme chaque année) de dormir avec elle lors de leur rencontre annuelle. Tingting voulait honorer cette tradition.
|
||||
|
||||
Alexis a exprimé son inconfort face à cette situation pour plusieurs raisons :
|
||||
1. **Symbolique** : Proche du mariage, préférence pour dormir ensemble
|
||||
2. **Priorité** : Sentiment que Tingting choisit la tradition plutôt que lui
|
||||
3. **Culturel** : Valeurs personnelles fortes sur le sommeil/intimité
|
||||
4. **Réciprocité** : Alexis ne dormirait jamais avec quelqu'un d'autre (même un homme)
|
||||
5. **Protection** : Règle absolue de ne jamais créer de situation ambiguë avec un enfant
|
||||
|
||||
### Plan initial rejeté
|
||||
|
||||
- Proposition de Tingting : Alexis dort dans une autre chambre chez les parents
|
||||
- Refus d'Alexis :
|
||||
- Perte de face visible socialement
|
||||
- Règle de protection (pas d'espace partagé avec un enfant)
|
||||
- **Alexis dort quasi systématiquement mal chez les parents** (environnement non optimal)
|
||||
|
||||
## Solution trouvée
|
||||
|
||||
**Arrangement proposé par Alexis :**
|
||||
- Tingting dort avec la jeune fille chez ses parents
|
||||
- Alexis dort seul à l'appartement
|
||||
- Prétexte public : travail (pour sauver la face socialement)
|
||||
- **Transparence mutuelle** : Pas de mensonge entre eux, juste gestion sociale
|
||||
|
||||
**Communication :**
|
||||
- Alexis a expliqué son inconfort à Tingting
|
||||
- Compréhension à ~70% de la part de Tingting
|
||||
- Accord mutuel sur l'arrangement
|
||||
|
||||
## Analyse
|
||||
|
||||
### Ce qui a bien fonctionné
|
||||
|
||||
✅ **Communication proactive** : Alexis a exprimé son inconfort directement
|
||||
✅ **Proposition de solution** : Alexis a proposé l'arrangement (pas subi)
|
||||
✅ **Compromis intelligent** : Balance entre principes personnels et pragmatisme
|
||||
✅ **Pas de mensonge mutuel** : Transparence maintenue dans le couple
|
||||
✅ **Gestion de face** : Prétexte social évite les questions/jugements
|
||||
✅ **Limites claires** : Alexis maintient ses principes sans trahison personnelle
|
||||
|
||||
### Points de vigilance
|
||||
|
||||
⚠️ **30% de flou** : Tingting ne comprend pas totalement pourquoi ça dérange Alexis
|
||||
⚠️ **Pattern futur** : Nécessité de clarifier les attentes après le mariage
|
||||
⚠️ **Limite de protection** : Importante à communiquer clairement (pas d'ambiguïté avec enfants)
|
||||
|
||||
## Principes d'Alexis révélés
|
||||
|
||||
### Règle absolue de protection
|
||||
**"Je bannis tout ce qui peut faire qu'on se pose la question de 'cet homme avec la gamine?'"**
|
||||
|
||||
- Jamais seul avec un enfant qui n'est pas le sien
|
||||
- Pas d'intimité spatiale (appart privé) avec un enfant
|
||||
- Pas d'espace partagé (même chambre séparée sous le même toit)
|
||||
- Protection légale et morale non-négociable
|
||||
|
||||
### Seuil de confiance élevé
|
||||
- Alexis ne fait confiance totale qu'à très peu de personnes
|
||||
- Même sa femme et lui-même n'ont pas sa confiance "totale"
|
||||
- Trait de personnalité, pas méfiance spécifique
|
||||
|
||||
### Réciprocité stricte
|
||||
- Alexis ne dormirait jamais avec quelqu'un d'autre (même un homme)
|
||||
- Application de ses propres standards à sa partenaire
|
||||
|
||||
### Sommeil fragile
|
||||
- Dort quasi systématiquement mal chez les parents de Tingting
|
||||
- Raison supplémentaire du refus de dormir là-bas (au-delà du principe avec la gamine)
|
||||
|
||||
## État émotionnel
|
||||
|
||||
**Alexis :**
|
||||
- Inconfort assumé mais géré
|
||||
- Paix mentale maintenue ("je vais dormir tranquillement")
|
||||
- Pas de regret ni de remords anticipés
|
||||
- Intégrité personnelle préservée
|
||||
|
||||
**Tingting :**
|
||||
- Contente de passer du temps avec sa "fille"
|
||||
- Accepte l'arrangement proposé
|
||||
- Compréhension partielle des raisons d'Alexis
|
||||
|
||||
## Apprentissages
|
||||
|
||||
### Positif
|
||||
|
||||
1. **Compromis sans trahison** : Possible de gérer une situation délicate sans trahir ses principes
|
||||
2. **Communication directe** : Alexis a exprimé son inconfort plutôt que de l'accumuler
|
||||
3. **Solution créative** : L'arrangement permet de respecter les besoins des deux parties
|
||||
4. **Maturité** : Distinction claire entre "inconfort tolérable" et "trahison de principes"
|
||||
|
||||
### À améliorer
|
||||
|
||||
1. **Clarification post-mariage** : Nécessité de discuter des attentes pour l'année prochaine
|
||||
2. **Communication complète** : Les 30% manquants doivent être clarifiés
|
||||
3. **Limite de protection** : Tingting devrait comprendre la règle absolue sur les enfants
|
||||
|
||||
## Suivi nécessaire
|
||||
|
||||
### Court terme (avant le mariage)
|
||||
- [ ] Vérifier si Tingting comprend la règle de protection avec les enfants
|
||||
- [ ] S'assurer qu'elle sait que c'est exceptionnel (pas un pattern acceptable)
|
||||
|
||||
### Moyen terme (après le mariage, ~11 mois)
|
||||
|
||||
**Conversation proactive à avoir :**
|
||||
|
||||
"Babe, pour l'année prochaine avec [nom de la gamine], comment on voit ça ? On est mariés maintenant, comment on adapte la tradition ?"
|
||||
|
||||
**Options à explorer (méthode socratique) :**
|
||||
1. Même arrangement que cette année ?
|
||||
2. Rencontre en journée sans nuitée ?
|
||||
3. Autre solution créative ?
|
||||
|
||||
**Message à transmettre :**
|
||||
"Je comprends l'attachement émotionnel. Mais maintenant qu'on est mariés, dormir séparément régulièrement, même pour de bonnes raisons, ça ne correspond pas à ma vision du couple. Comment on trouve une solution qui respecte ta relation avec elle ET notre mariage ?"
|
||||
|
||||
### Long terme
|
||||
- Surveiller que le compromis exceptionnel ne devienne pas la norme
|
||||
- Maintenir les limites claires
|
||||
- Appliquer le leadership socratique pour les discussions futures
|
||||
|
||||
## Notes importantes
|
||||
|
||||
- **Situation exceptionnelle** : 1 fois par an, relation émotionnelle importante, gamine de 16 ans
|
||||
- **Pas un red flag** : Gestion mature d'une situation délicate
|
||||
- **Validation de l'approche** : Alexis a géré de manière intelligente et intègre
|
||||
- **Principes maintenus** : Aucune trahison personnelle, paix mentale préservée
|
||||
|
||||
---
|
||||
|
||||
**Conclusion** : Situation délicate gérée de manière mature avec compromis intelligent. Vigilance nécessaire pour le futur mais pas de problème fondamental pour cet événement spécifique.
|
||||
505
couple_backlog/18_octobre_2025.md
Normal file
505
couple_backlog/18_octobre_2025.md
Normal file
@ -0,0 +1,505 @@
|
||||
# 18 octobre 2025 - Conflit matinal suite à mauvais sommeil + Tingting chez ses parents
|
||||
|
||||
**Type** : ⚠️ Conflit - Miscommunication grave causée par fatigue extrême d'Alexis
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
- **Quand** : Matin du 18 octobre 2025
|
||||
- **Où** : Appartement, puis Tingting part chez ses parents
|
||||
- **Plan prévu** : Visite hebdomadaire habituelle chez les parents de Tingting (ils y vont chaque semaine)
|
||||
- **Arrangement du 17 octobre** : Tingting dort chez ses parents avec sa "fille adoptive" de 16 ans, Alexis dort à l'appart (voir [17 octobre 2025](17_octobre_2025.md) pour contexte complet)
|
||||
|
||||
---
|
||||
|
||||
## Ce qui s'est réellement passé - Matin du 18 octobre
|
||||
|
||||
### Contexte préalable : L'accumulation (CRITIQUE)
|
||||
|
||||
**Ce conflit n'est PAS isolé. C'est l'explosion d'une accumulation de 3 jours :**
|
||||
|
||||
**16 octobre** : Grief non avoué (voir [16_octobre_2025.md](16_octobre_2025.md))
|
||||
- Tingting ne réveille pas Alexis → Il loupe ses cours
|
||||
- Elle fait la gueule à l'école : "Je ne sais pas pourquoi"
|
||||
- **Grief caché = début de l'accumulation**
|
||||
|
||||
**17 octobre** : Tension sous-jacente
|
||||
- Arrangement avec la "fille adoptive" (70% compris par Tingting)
|
||||
- Le soir : "Tous les deux trop fatigués pour setup"
|
||||
- **Question :** Vraiment juste fatigués OU tension du 16 → aucun des deux ne fait l'effort ?
|
||||
|
||||
**18 octobre** : Explosion
|
||||
- Alexis crashe (setup raté) + Miscommunication
|
||||
- **Colère disproportionnée de Tingting = 16 + 17 + 18 accumulés**
|
||||
|
||||
### Setup raté la veille au soir (17 octobre)
|
||||
|
||||
**Cause officiellement :** Tous les deux trop fatigués physiquement pour setup correctement le sommeil
|
||||
|
||||
**Cause possible sous-jacente :** Tension du 16 octobre non résolue → Passif-agressif mutuel → Aucun des deux ne fait vraiment l'effort de setup
|
||||
**Résultat :**
|
||||
- Lumière allumée dans la chambre
|
||||
- Musique dans la pièce d'à côté
|
||||
- Réveil en pleine nuit à cause de la lumière
|
||||
- Alexis crashe complètement (sommeil extrêmement fragile)
|
||||
|
||||
### Sommeil fragile d'Alexis (contexte crucial)
|
||||
|
||||
**Problème physiologique réel :**
|
||||
- Sommeil extrêmement fragile (bruit et surtout lumière = destruction totale)
|
||||
- Toujours sur ses gardes quand il dort
|
||||
- A mis 6 mois à s'habituer à dormir avec Tingting sans se réveiller de sa présence
|
||||
- Voulait lits séparés avant même de vivre ensemble
|
||||
- **Dort quasi systématiquement mal chez les parents de Tingting** (raison supplémentaire du refus de dormir là-bas)
|
||||
- **Quand setup raté = crash en mode "larve" = cerveau totalement dysfonctionnel**
|
||||
|
||||
### Matin - Miscommunication catastrophique
|
||||
|
||||
**État d'Alexis au réveil :**
|
||||
- Mode "larve" totale (cerveau à 0%, incapable de penser clairement)
|
||||
- Tellement fatigué qu'il s'est rendormi pendant que Tingting allait chercher la voiture
|
||||
|
||||
**Ce qu'Alexis voulait dire :**
|
||||
- "Je ne viens pas maintenant en voiture avec toi, je dormirai encore et je viendrai plus tard en métro"
|
||||
|
||||
**Ce qu'Alexis a dit (cerveau dysfonctionnel) :**
|
||||
- "I'm very tired, maybe I don't want to come" OU "I don't come" (flou, incertain)
|
||||
|
||||
**Ce que Tingting a compris :**
|
||||
- Il ne vient pas du tout aujourd'hui
|
||||
|
||||
**Ce qu'Alexis n'a PAS fait :**
|
||||
- Pas préparé le breakfast (habitude quotidienne)
|
||||
- Pas communiqué clairement le plan
|
||||
- Pas rassuré Tingting pour la route ("At least you should comfort me to make sure I'm safe on the road")
|
||||
- S'est rendormi pendant qu'elle préparait le départ
|
||||
|
||||
### Réaction de Tingting
|
||||
|
||||
**Question immédiate :** "Why are you so mean?"
|
||||
|
||||
**Départ en colère :**
|
||||
- Elle part chercher la voiture
|
||||
- Revient, il s'est rendormi
|
||||
- Elle part chez ses parents seule, en colère
|
||||
- Elle dit à ses parents qu'Alexis ne viendra pas
|
||||
|
||||
### Échange WeChat (après son départ)
|
||||
|
||||
**Messages d'Alexis :**
|
||||
```
|
||||
I'm just super tired [Cry]
|
||||
I don't want to be mean [Cry]
|
||||
I love you [Heart]
|
||||
Have a nice day [Heart]
|
||||
```
|
||||
|
||||
**Réponse de Tingting (en colère) :**
|
||||
```
|
||||
It's not right to do that! I'm very angry at you!
|
||||
You didn't finish the preparation for tomorrow, right?
|
||||
So you will not come today
|
||||
You knew it early!
|
||||
Ok if you don't say I will not talk about this anymore
|
||||
If you are really tired now you don't come. At least you should comfort me to make sure I'm safe on the road
|
||||
I really don't understand you
|
||||
If you don't answer, I come back now
|
||||
I come back
|
||||
```
|
||||
|
||||
**Alexis tente d'expliquer :**
|
||||
```
|
||||
I don't know what to say honestly. I'm just super tired, that's it
|
||||
That's not the first time it happens and I'm very sorry it happens
|
||||
It has nothing to do about tomorrow.
|
||||
Again, I'm just tired. We talked about that already. When I tired like that, it is very hard for me to be reliable and I'm very sorry I made you mad because of that
|
||||
I hope one day you will understand better how I feel when I'm tired like that. It is not an excuse but still I hope you will be more understanding towards that so you can be more at peace with this issue
|
||||
I can't think properly even now, I'm just sorry that this happened. I hope we will be able to talk about it properly as soon as possible
|
||||
I will come by underground soon after lunch
|
||||
I love you [Heart]
|
||||
```
|
||||
|
||||
**Tingting refuse :**
|
||||
```
|
||||
don't come
|
||||
```
|
||||
|
||||
**Alexis :** "Why?"
|
||||
|
||||
**Tingting :** "I told them you will not come"
|
||||
|
||||
### Phrase critique de Tingting (ce matin)
|
||||
|
||||
**"I cannot accept that"**
|
||||
|
||||
- Dit en réponse aux excuses/explications d'Alexis sur la fatigue
|
||||
- **Elle ne peut pas accepter le PATTERN récurrent : "Désolé, j'étais trop fatigué"**
|
||||
- Ce n'est pas la première fois que ça arrive ("That's not the first time")
|
||||
|
||||
### Message d'excuse d'Alexis (après réflexion)
|
||||
|
||||
```
|
||||
You are right to be angry...
|
||||
|
||||
I didn't communicate clearly this morning. When I said "I don't come" I left you with no responsibility on my side. I should have make things clear that after some sleep I would be better. And I should have made sure you felt safe before you left...
|
||||
|
||||
I messed up. I'm sorry I hurt you
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Analyse complète
|
||||
|
||||
### Erreurs d'Alexis
|
||||
|
||||
#### ❌ Erreur 1 : Setup sommeil raté (responsabilité partagée)
|
||||
- Tous les deux trop fatigués pour setup correctement
|
||||
- Aucun des deux n'a insisté pour éteindre lumière/musique
|
||||
- Alexis connaît son sommeil fragile = devrait prioriser le setup
|
||||
|
||||
#### ❌ Erreur 2 : Communication floue et tardive
|
||||
- "Maybe I don't want to come" = incertitude insupportable
|
||||
- Pas de clarification : "Je dors encore, je viens plus tard en métro"
|
||||
- Communication impossible car cerveau dysfonctionnel (mode larve)
|
||||
|
||||
#### ❌ Erreur 3 : Absence de réassurance émotionnelle
|
||||
- Pas de "drive safely"
|
||||
- Pas de "text me when you arrive"
|
||||
- S'est rendormi au lieu de la rassurer
|
||||
- **Elle s'est sentie abandonnée émotionnellement**
|
||||
|
||||
#### ❌ Erreur 4 : Priorité sommeil > engagement
|
||||
- Resté au lit, s'est rendormi
|
||||
- N'a pas préparé le breakfast (habitude quotidienne)
|
||||
- Message envoyé : "Mon sommeil > toi"
|
||||
|
||||
#### ❌ Erreur 5 : Messages WeChat = défense/explication
|
||||
- Beaucoup de "je" et d'explications de SON état
|
||||
- "I hope you will understand"
|
||||
- "I can't think properly"
|
||||
- **N'adresse PAS la blessure émotionnelle de Tingting**
|
||||
- Continue à justifier avec la fatigue (exactement ce qu'elle "cannot accept")
|
||||
|
||||
### Griefs de Tingting
|
||||
|
||||
**Ce qu'elle reproche (au-delà de l'incident spécifique) :**
|
||||
|
||||
1. **Changement de plan de dernière minute** : Elle s'attendait à ce qu'il vienne (visite hebdomadaire habituelle chez ses parents)
|
||||
2. **Communication floue** : "Maybe" = incertitude insupportable
|
||||
3. **Manque de considération** : "You knew it early!" (selon elle)
|
||||
4. **Absence émotionnelle** : Pas de réassurance pour la route
|
||||
5. **Pattern récurrent** : "Ce n'est pas la première fois" qu'il est "unreliable" quand il est fatigué
|
||||
6. **Préparation inachevée** : "You didn't finish the preparation for tomorrow" (cours à donner - Alexis pense que c'est un détail mais elle l'a mentionné)
|
||||
7. **L'excuse fatigue ne passe plus** : "I cannot accept that" = elle en a marre de cette justification récurrente
|
||||
|
||||
**Sa vraie blessure émotionnelle :**
|
||||
- "Why are you so mean?" = elle ressent ça comme un rejet émotionnel
|
||||
- Elle ne l'accuse pas d'être paresseux ou irresponsable
|
||||
- Elle se sent rejetée, abandonnée, non prioritaire
|
||||
|
||||
**Analyse de la proportionnalité :**
|
||||
- **Sa colère semble disproportionnée pour le 18 octobre seul**
|
||||
- Mais PROPORTIONNÉE si on compte 16 + 17 + 18 accumulés
|
||||
- **Confirmation d'accumulation non résolue**
|
||||
|
||||
### Le conflit structurel révélé
|
||||
|
||||
**Vous avez un conflit systémique :**
|
||||
|
||||
1. **Tingting veut** : Fiabilité, présence, réassurance émotionnelle, visites régulières chez ses parents
|
||||
2. **Alexis a** : Sommeil extrêmement fragile, devient totalement dysfonctionnel en mode "larve"
|
||||
3. **Réalité** :
|
||||
- Alexis dort mal chez les parents de Tingting (elle le sait)
|
||||
- Quand setup raté à la maison = crash total
|
||||
- Quand crash = incapable de communiquer ou d'être fiable
|
||||
4. **Résultat** : Conflit récurrent inévitable sans solution structurelle
|
||||
|
||||
**Le cercle vicieux :**
|
||||
- Setup raté OU visite chez parents → Alexis dort mal → Mode larve → Unreliable → Tingting en colère → Conflit
|
||||
- OU : Alexis refuse d'aller chez parents pour protéger son sommeil → Tingting frustrée → Conflit
|
||||
|
||||
### Ce que Tingting ne comprend/accepte pas
|
||||
|
||||
**Incompréhension fondamentale :**
|
||||
- Elle ne comprend pas (ou ne croit pas) que le sommeil fragile d'Alexis est RÉEL et PHYSIOLOGIQUE
|
||||
- Elle pense probablement qu'il pourrait se forcer s'il voulait
|
||||
- Elle pense peut-être qu'il exagère ou utilise ça comme excuse
|
||||
- **Elle ne voit pas la différence entre "fatigué normal" (il peut se forcer) et "mode larve" (cerveau à 0%)**
|
||||
|
||||
**D'où son "I cannot accept that" :**
|
||||
- Elle refuse que "je suis fatigué" soit une excuse acceptable
|
||||
- Elle veut qu'il soit fiable même fatigué
|
||||
- Mais elle ne réalise pas que c'est physiquement impossible quand il atteint le mode larve
|
||||
|
||||
---
|
||||
|
||||
## État actuel (18 octobre après-midi)
|
||||
|
||||
**Tingting :**
|
||||
- Chez ses parents avec la jeune fille
|
||||
- En colère
|
||||
- A dit à ses parents qu'Alexis ne vient pas
|
||||
- A refusé qu'il vienne après ("don't come, I told them you will not come")
|
||||
|
||||
**Alexis :**
|
||||
- Seul à l'appartement
|
||||
- Toujours fatigué, cerveau pas complètement disponible
|
||||
- A envoyé des excuses mais avec trop de justifications
|
||||
- Hésite à envoyer un autre message
|
||||
- Sait qu'il doit avoir une vraie conversation quand elle rentre
|
||||
|
||||
---
|
||||
|
||||
## Solutions nécessaires
|
||||
|
||||
### Court terme - Message à envoyer (dans 1-2h)
|
||||
|
||||
**Version recommandée :**
|
||||
```
|
||||
I hope you arrived safely ❤️
|
||||
|
||||
I know you're angry and you have every right to be.
|
||||
|
||||
Let's talk properly when you're back. I want to find a real solution.
|
||||
|
||||
Love you ❤️
|
||||
```
|
||||
|
||||
**Objectif :**
|
||||
- Réassurance émotionnelle (arrivée safe)
|
||||
- Validation de sa colère
|
||||
- Promesse de vraie conversation
|
||||
- Pas d'excuses supplémentaires
|
||||
|
||||
### Moyen terme - Conversation critique (quand elle rentre)
|
||||
|
||||
**Cette conversation détermine si la relation peut fonctionner à long terme.**
|
||||
|
||||
#### 1. Validation et reconnaissance (sans justification)
|
||||
|
||||
"Tu as raison d'être en colère. Ce matin j'ai mal communiqué et je ne t'ai pas rassurée avant que tu partes. J'ai merdé."
|
||||
|
||||
#### 2. Explication du problème de fond (physiologique, pas excuse)
|
||||
|
||||
"Mais il faut qu'on parle du problème de fond, sinon ça va continuer :
|
||||
|
||||
J'ai un sommeil extrêmement fragile. Ce n'est pas une excuse, c'est physiologique :
|
||||
- Lumière, bruit = je crashe complètement
|
||||
- Ça m'a pris 6 mois pour dormir avec toi sans me réveiller
|
||||
- Je voulais lits séparés à la base pour cette raison
|
||||
- Tu sais déjà que je dors mal chez tes parents
|
||||
|
||||
Généralement je peux me forcer et fonctionner quand je dors mal. Mais quand j'atteins un certain niveau (comme ce matin), mon cerveau s'éteint complètement. Je ne peux plus penser ni communiquer. C'est ce qui s'est passé ce matin."
|
||||
|
||||
#### 3. Question socratique - Comprend-elle la réalité ?
|
||||
|
||||
"Est-ce que tu comprends que c'est réel, pas une excuse ?"
|
||||
|
||||
→ Écouter vraiment sa réponse
|
||||
→ Si elle doute : "Qu'est-ce qui te fait penser que j'exagère ?"
|
||||
|
||||
#### 4. Exposer le conflit structurel
|
||||
|
||||
"Voilà le problème qu'on a :
|
||||
- Tu veux que je sois fiable et présent (je comprends, c'est légitime)
|
||||
- Mais je dors mal facilement (chez tes parents, quand setup raté)
|
||||
- Si je dors mal, je deviens unreliable le lendemain
|
||||
- Et ça te met en colère (à juste titre)
|
||||
|
||||
Comment on résout ça ?"
|
||||
|
||||
#### 5. Proposer des solutions concrètes
|
||||
|
||||
**Option A - Setup sommeil strict et NON-NÉGOCIABLE**
|
||||
- Lumière éteinte, pas de bruit, environnement optimal
|
||||
- Si l'un ne respecte pas, l'autre rappelle IMMÉDIATEMENT
|
||||
- Pas de "juste cette fois" ou "on est trop fatigués"
|
||||
- C'est une priorité absolue, sinon cycle vicieux
|
||||
|
||||
**Option B - Protocole "mauvaise nuit"**
|
||||
- Si Alexis dort mal, il prévient immédiatement au réveil
|
||||
- Il prend 2 minutes MINIMUM pour communiquer clairement (même larve)
|
||||
- Il rassure émotionnellement Tingting (route safe, je t'aime)
|
||||
- Tingting sait à quoi s'attendre, pas de surprise
|
||||
|
||||
**Option C - Visites courtes chez les parents seulement**
|
||||
- Alexis vient en journée, dîner, soirée
|
||||
- Mais dort toujours à l'appart (il dort mal chez eux)
|
||||
- Pas d'exception sauf urgence absolue
|
||||
|
||||
**Option D - Lits séparés (option nucléaire mais viable)**
|
||||
- Si le problème continue malgré tout
|
||||
- Ce qu'Alexis voulait à la base
|
||||
- Pas un rejet, une solution pratique pour son sommeil fragile
|
||||
|
||||
**"Qu'est-ce qui marcherait le mieux pour toi ?"**
|
||||
|
||||
#### 6. Si elle dit encore "I cannot accept"
|
||||
|
||||
**Question directe et finale :**
|
||||
|
||||
"Je comprends. Mais dis-moi clairement : qu'est-ce que tu ne peux pas accepter ?
|
||||
|
||||
- Que j'ai un sommeil fragile ? (Incompatibilité fondamentale)
|
||||
- Que je ne dorme pas chez tes parents ? (Comment on fait sachant que je dors mal là-bas ?)
|
||||
- Que je sois dysfonctionnel quand je crashe ? (La seule solution = éviter que je crashe)
|
||||
- Autre chose ?"
|
||||
|
||||
→ Selon sa réponse : solvable, difficile mais gérable, ou incompatibilité fondamentale
|
||||
|
||||
---
|
||||
|
||||
## Principes d'Alexis révélés/confirmés
|
||||
|
||||
### Règle absolue de protection avec enfants
|
||||
**"Je bannis tout ce qui peut faire qu'on se pose la question de 'cet homme avec la gamine?'"**
|
||||
|
||||
- Raison supplémentaire du refus de dormir chez les parents de la gamine
|
||||
- Jamais seul avec un enfant qui n'est pas le sien
|
||||
- Pas d'intimité spatiale (appart privé) avec un enfant
|
||||
- Pas d'espace partagé (même chambre séparée sous le même toit)
|
||||
- Protection légale et morale non-négociable
|
||||
|
||||
### Sommeil extrêmement fragile (révélation majeure)
|
||||
|
||||
**Contexte complet maintenant documenté :**
|
||||
- Bruit et surtout lumière = destruction totale du sommeil
|
||||
- Toujours sur ses gardes en dormant
|
||||
- 6 mois d'adaptation pour dormir avec Tingting
|
||||
- Voulait lits séparés avant même de vivre ensemble
|
||||
- Dort quasi systématiquement mal chez les parents de Tingting
|
||||
- **Quand setup raté OU environnement non optimal = mode "larve" = cerveau à 0%**
|
||||
|
||||
**Niveaux de fatigue :**
|
||||
- Fatigué normal : Peut se forcer et fonctionner
|
||||
- Mode larve : Cerveau totalement dysfonctionnel, incapable de penser/communiquer clairement
|
||||
|
||||
**"My god mais tu veux que je fasse quoi le matin si j'ai pas de cerveau dispo en faite mdr ?? Pas de setup => turbo baisse systématique. La lumière dans la chambre = enfer sur terre..."**
|
||||
|
||||
### Seuil de confiance élevé (confirmé)
|
||||
- Alexis ne fait confiance totale qu'à très peu de personnes
|
||||
- "Presque personne n'a accès à ma confiance haute ou totale pas même ma femme et pas même moi"
|
||||
- Trait de personnalité, pas méfiance spécifique
|
||||
|
||||
---
|
||||
|
||||
## Apprentissages
|
||||
|
||||
### Négatifs (ce qui a échoué)
|
||||
|
||||
1. **Setup sommeil ignoré malgré connaissance du risque** : Tous les deux trop fatigués, aucun n'a insisté
|
||||
2. **Communication impossible en mode larve** : Alexis incapable de communiquer clairement quand cerveau à 0%
|
||||
3. **Justifications répétées aggravent la situation** : Plus Alexis explique avec "fatigue", plus Tingting rejette
|
||||
4. **Tingting ne comprend pas la réalité physiologique** : Elle pense que c'est une excuse, pas un problème réel
|
||||
5. **Pattern récurrent non résolu** : "Ce n'est pas la première fois" = problème systémique, pas incident isolé
|
||||
|
||||
### Positifs (lueurs d'espoir)
|
||||
|
||||
1. **Alexis identifie la vraie cause** : Setup raté = crash garanti (pas juste "malchance")
|
||||
2. **Conscient de ses limites** : Sait qu'en mode larve il ne peut pas fonctionner
|
||||
3. **Cherche vraie solution** : Pas juste s'excuser, mais éviter que ça se reproduise
|
||||
4. **Veut conversation honnête** : Prêt à exposer le conflit structurel
|
||||
|
||||
---
|
||||
|
||||
## Suivi absolument critique
|
||||
|
||||
### URGENT - Avant que la situation empire
|
||||
|
||||
**☐ Message court dans 1-2h** : Réassurance + validation colère + promesse de vraie conversation
|
||||
|
||||
**☐ Conversation fondamentale quand elle rentre :**
|
||||
- Faire comprendre que sommeil fragile = RÉEL et PHYSIOLOGIQUE
|
||||
- Exposer le conflit structurel clairement
|
||||
- Proposer solutions concrètes (setup strict en priorité)
|
||||
- Obtenir son engagement ou identifier l'incompatibilité
|
||||
|
||||
**☐ Si elle comprend et accepte** : Mise en place IMMÉDIATE du protocole setup strict
|
||||
|
||||
**☐ Si elle ne comprend/accepte pas** : Décision difficile sur viabilité de la relation
|
||||
|
||||
### Court terme (cette semaine)
|
||||
|
||||
**☐ Appliquer le setup strict dès ce soir** :
|
||||
- Lumière éteinte
|
||||
- Pas de musique
|
||||
- Environnement optimal
|
||||
- Si l'un ne respecte pas, l'autre rappelle IMMÉDIATEMENT
|
||||
|
||||
**☐ Tester le protocole "mauvaise nuit"** si malgré setup il dort mal
|
||||
|
||||
### Moyen terme (après résolution)
|
||||
|
||||
**☐ Reparler de la situation initiale (dormir avec la "fille")** une fois que le conflit sommeil est résolu
|
||||
|
||||
**☐ Clarifier les limites pour l'année prochaine** (même arrangement ou autre solution)
|
||||
|
||||
### Long terme
|
||||
|
||||
**☐ Surveillance du pattern fatigue** : Si ça continue malgré setup strict, envisager lits séparés
|
||||
|
||||
**☐ Éventuelle consultation médicale** si sommeil fragile empire ou ne s'améliore pas
|
||||
|
||||
---
|
||||
|
||||
## Pronostic
|
||||
|
||||
**Si Tingting comprend et s'engage sur le setup strict :**
|
||||
- ✅ Relation viable
|
||||
- ✅ Conflit évitable à l'avenir
|
||||
- ✅ Solution structurelle en place
|
||||
|
||||
**Si Tingting refuse de comprendre ou ne peut pas s'adapter :**
|
||||
- ❌ Conflit récurrent garanti
|
||||
- ❌ Alexis épuisé en permanence OU en conflit permanent
|
||||
- ❌ Incompatibilité fondamentale probable
|
||||
|
||||
**La conversation à venir détermine tout.**
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
- **Ce n'est PAS un incident isolé** : Pattern récurrent révélé + accumulation 16-18 octobre
|
||||
- **Ce n'est PAS juste "il était fatigué"** : Problème physiologique réel et documenté
|
||||
- **Ce n'est PAS de la mauvaise volonté** : Alexis incapable de fonctionner en mode larve
|
||||
- **C'EST un conflit structurel** : Besoins de Tingting vs réalité physiologique d'Alexis
|
||||
- **C'EST aussi un problème de communication** : Griefs cachés → accumulation → explosion
|
||||
- **Solution EXISTE** : Setup strict + protocole clair + compréhension mutuelle + communication directe
|
||||
- **Mais nécessite** : Que Tingting comprende et accepte la réalité du sommeil fragile + que TOUS DEUX changent le pattern de communication
|
||||
|
||||
## Observations supplémentaires à investiguer (plus tard)
|
||||
|
||||
**Notées dans [observations_patterns.md](../observations_patterns.md) :**
|
||||
|
||||
1. **Pattern colères intensifiées** : Alexis observe que les colères de Tingting semblent plus intenses avec le temps
|
||||
- À investiguer dans 2-3 semaines (état émotionnel actuellement biaisé)
|
||||
- Besoin de données objectives sur 6 derniers mois
|
||||
|
||||
2. **Sentiment "trophée"** : Alexis a l'impression (vague) d'être "baladé comme un trophée"
|
||||
- À investiguer dans 2-4 semaines (pas assez clair, besoin d'exemples concrets)
|
||||
- Peut être projection/sensibilité ou pattern réel
|
||||
- Ne PAS aborder dans conversation critique du 18 octobre (trop de sujets)
|
||||
|
||||
**Ces observations sont SÉPARÉES du conflit actuel et seront investiguées plus tard quand état d'esprit clair.**
|
||||
|
||||
---
|
||||
|
||||
## Messages envoyés (suivi après conflit)
|
||||
|
||||
**18 octobre, après-midi (environ 2h après son départ) :**
|
||||
```
|
||||
I hope you are fine at your parent's home
|
||||
I know you are angry and it is normal
|
||||
Let's talk properly when you are back. I want to find a real solution
|
||||
I love you
|
||||
```
|
||||
|
||||
**Statut :** Message envoyé, attente de réponse ou de son retour pour conversation en personne.
|
||||
|
||||
**Plan :** Utiliser le plan de discussion préparé dans `/plan_discussion/` quand tous les deux calmes et reposés.
|
||||
|
||||
---
|
||||
|
||||
**Conclusion** : Conflit majeur révélant un problème systémique à DEUX niveaux : (1) Sommeil fragile d'Alexis vs besoin de fiabilité de Tingting, et (2) Pattern de communication toxique (griefs cachés → accumulation → explosion). La relation dépend de la capacité de Tingting à comprendre et accepter le sommeil fragile d'Alexis, ET de leur capacité MUTUELLE à changer le pattern de communication pour exprimer les griefs directement plutôt que de les accumuler. Sans ces deux changements, le cycle va se répéter indéfiniment.
|
||||
486
couple_backlog/19_octobre_2025.md
Normal file
486
couple_backlog/19_octobre_2025.md
Normal file
@ -0,0 +1,486 @@
|
||||
# 19 octobre 2025 - "Figure it out" + Limite posée + Silent treatment
|
||||
|
||||
**Type** : 🔴 Conflit majeur - Communication toxique confirmée + Alexis pose ses limites
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
- **Quand** : Soir du 19 octobre 2025
|
||||
- **Où** : Appartement
|
||||
- **État relation** : Conflit du 18 non résolu, Tingting toujours en colère
|
||||
- **Tentative** : Alexis essaie d'avoir une conversation pour résoudre
|
||||
|
||||
---
|
||||
|
||||
## Ce qui s'est passé
|
||||
|
||||
### Tentative de conversation d'Alexis
|
||||
|
||||
**Approche initiale :**
|
||||
- Alexis veut comprendre ce qu'il a fait de mal au-delà du 18
|
||||
- Tingting refuse de clarifier
|
||||
- Elle dit : **"It's up to you to figure it out"**
|
||||
|
||||
**= Elle refuse de communiquer ce qu'elle lui reproche**
|
||||
|
||||
### Erreur d'Alexis - Question maladroite
|
||||
|
||||
**Question posée :** "You are right, but are you right?"
|
||||
|
||||
**Intention d'Alexis :**
|
||||
- Valider l'émotion (tu as raison d'être en colère)
|
||||
- MAIS questionner l'expression/l'efficacité de sa colère
|
||||
- "Were you right in the way of expression, did you solve anything with being angry?"
|
||||
|
||||
**Ce qu'elle a entendu :**
|
||||
- Gaslighting
|
||||
- Invalidation de ses émotions
|
||||
- Jeu rhétorique pour esquiver la responsabilité
|
||||
- Condescendance
|
||||
|
||||
**Résultat :** Conversation part complètement en vrille
|
||||
|
||||
### Pattern révélé : "But" systématique
|
||||
|
||||
**Alexis réalise :**
|
||||
- "But" est son schéma de communication normal
|
||||
- "Je valide X, MAIS je questionne Y"
|
||||
- Fonctionne en logique/débat intellectuel
|
||||
- **NE FONCTIONNE PAS en gestion émotionnelle**
|
||||
|
||||
**Problème :**
|
||||
- Le mot "BUT" annule tout ce qui précède
|
||||
- Elle n'entend que ce qui suit le "but"
|
||||
- "You're right, BUT..." → Elle entend "You're wrong"
|
||||
|
||||
### Escalade - Silent treatment + Jeux de pouvoir
|
||||
|
||||
**Tingting refuse de communiquer :**
|
||||
- Alexis demande si elle veut dormir
|
||||
- **Elle répond : "I don't want to tell you"**
|
||||
- Refuse de répondre à des questions basiques
|
||||
|
||||
**Jeux de territoire :**
|
||||
- Demande à Alexis d'éteindre sa musique
|
||||
- Met SA musique juste à côté de lui
|
||||
- Alexis met son casque (ignore le jeu)
|
||||
|
||||
**Tingting sort :**
|
||||
- Quitte l'appartement
|
||||
- Alexis reste seul
|
||||
|
||||
### Limite posée par Alexis
|
||||
|
||||
**Message envoyé sur WeChat :**
|
||||
|
||||
```
|
||||
I'm not going to guess what I did wrong, and I'm not going to guess if you want to sleep.
|
||||
|
||||
When you are ready to communicate, I'm here.
|
||||
```
|
||||
|
||||
**Actions d'Alexis :**
|
||||
- Va dormir dans une autre pièce (pas la chambre commune)
|
||||
- Ferme sa porte
|
||||
- Setup sommeil solo
|
||||
- **Ne cède pas, ne supplie pas**
|
||||
|
||||
**Réponse de Tingting :**
|
||||
```
|
||||
I will not tell you
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Analyse
|
||||
|
||||
### Pattern communication toxique confirmé
|
||||
|
||||
**Cycle destructeur (16-19 octobre) :**
|
||||
1. Quelque chose dérange
|
||||
2. Refus de communiquer clairement ("I don't know" / "Figure it out")
|
||||
3. Griefs cachés s'accumulent
|
||||
4. Explosion/Silent treatment
|
||||
5. Refus de résoudre ("I will not tell you")
|
||||
|
||||
**= Communication impossible**
|
||||
|
||||
### Les deux refus de Tingting
|
||||
|
||||
**1. "Figure it out" (ce qu'il a fait de mal)**
|
||||
- Refuse de dire ce qu'elle lui reproche au-delà du 18
|
||||
- Veut qu'il devine
|
||||
- Le garde en position de coupable permanent
|
||||
|
||||
**2. "I don't want to tell you" (si elle veut dormir)**
|
||||
- Refuse de communiquer sur des questions basiques
|
||||
- Jeu de punition active
|
||||
- Silent treatment délibéré
|
||||
|
||||
**= Pattern de manipulation par refus de communication**
|
||||
|
||||
### État mental d'Alexis
|
||||
|
||||
**Hier (18 octobre) :**
|
||||
- Crise d'anxiété intense
|
||||
- Monté sur le toit de l'immeuble
|
||||
- Quasi-rupture par WeChat
|
||||
- A réussi à ne pas rompre sous émotion
|
||||
|
||||
**Aujourd'hui (19 octobre) :**
|
||||
- Plus calme, plus préparé mentalement
|
||||
- A déjà "fait le deuil mental" d'une rupture possible
|
||||
- **En position de force psychologique**
|
||||
- Capacité à poser des limites sans paniquer
|
||||
|
||||
**Évolution positive :**
|
||||
- Ne yield pas comme d'habitude
|
||||
- Pose ses limites clairement
|
||||
- Se retire avec dignité
|
||||
- N'essaie pas de deviner ou de supplier
|
||||
|
||||
### Erreurs d'Alexis
|
||||
|
||||
**❌ Erreur tactique : "You are right, but are you right?"**
|
||||
- Question philosophique pendant qu'elle est en colère
|
||||
- "But" annule la validation
|
||||
- Sonne comme du gaslighting
|
||||
- Mauvais timing pour aborder le meta-problème
|
||||
|
||||
**❌ Pattern à changer : "But" systématique**
|
||||
- Schéma normal de comm d'Alexis
|
||||
- Fonctionne en logique, pas en émotion
|
||||
- Doit apprendre à séparer validation et questionnement
|
||||
- Jamais de "but" dans validation émotionnelle
|
||||
|
||||
**Ce qu'il aurait dû faire :**
|
||||
1. Validation pure (sans "but")
|
||||
2. Laisser retomber
|
||||
3. PUIS (séparément) discuter du pattern de communication
|
||||
|
||||
### Forces d'Alexis
|
||||
|
||||
**✅ Refuse le jeu "guess my mind"**
|
||||
- Pose une limite claire
|
||||
- "Je ne devine pas"
|
||||
- Adulte, pas enfantin
|
||||
|
||||
**✅ Refuse le silent treatment**
|
||||
- Ne supplie pas
|
||||
- Ne cède pas pour du confort
|
||||
- Se retire avec dignité
|
||||
|
||||
**✅ Gestion émotionnelle améliorée**
|
||||
- Pas de rupture impulsive (comme hier)
|
||||
- Calme malgré la tension
|
||||
- Tient ses principes
|
||||
|
||||
**✅ Position de force**
|
||||
- A déjà visualisé la rupture (hier)
|
||||
- Moins de peur aujourd'hui
|
||||
- Acceptation mentale si ça arrive
|
||||
|
||||
### 4 règles d'Alexis (appliquées correctement)
|
||||
|
||||
**1. Pas de rupture sous émotion** ✅
|
||||
- Malgré la frustration, reste calme
|
||||
- Ne rompt pas impulsivement
|
||||
|
||||
**2. Poser limites + communiquer clairement** ✅
|
||||
- Message clair sur WeChat
|
||||
- Limite ferme sur "guess my mind"
|
||||
|
||||
**3. Garder supériorité morale** ✅
|
||||
- Refuse le jeu toxique
|
||||
- Offre communication adulte
|
||||
- Ne joue pas aux punitions
|
||||
|
||||
**4. Ne pas yield** ✅
|
||||
- Dort ailleurs
|
||||
- N'insiste pas après son refus
|
||||
- Maintient sa position
|
||||
|
||||
---
|
||||
|
||||
## Pronostic
|
||||
|
||||
### Si elle maintient le refus de communiquer
|
||||
|
||||
**Court terme (prochains jours) :**
|
||||
- Conflit insoluble (impossible de corriger ce qu'elle refuse de nommer)
|
||||
- Alexis marchera sur des œufs en permanence
|
||||
- Culpabilité permanente sans possibilité de rédemption
|
||||
|
||||
**Moyen terme (semaines) :**
|
||||
- Pattern toxique s'empire
|
||||
- Alexis épuisé mentalement
|
||||
- Relation devient prison psychologique
|
||||
|
||||
**Long terme :**
|
||||
- Incompatibilité fondamentale de communication
|
||||
- Rupture inévitable ou vie de couple toxique
|
||||
|
||||
**= Si elle ne change pas, cette relation va détruire Alexis mentalement**
|
||||
|
||||
### Si elle accepte de communiquer (peu probable à court terme)
|
||||
|
||||
**Scénario optimiste :**
|
||||
1. Elle se calme et accepte de clarifier
|
||||
2. Conversation adulte sur le grief réel
|
||||
3. Mise en place solutions (setup sommeil strict)
|
||||
4. Discussion sur pattern communication (griefs cachés)
|
||||
5. Engagement mutuel sur communication directe
|
||||
|
||||
**Probabilité : Faible**
|
||||
- Pattern établi depuis plusieurs jours
|
||||
- Refus actif de communiquer ("I will not tell you")
|
||||
- Jeux de pouvoir en place
|
||||
|
||||
---
|
||||
|
||||
## Questions non résolues
|
||||
|
||||
**1. Qu'est-ce qu'elle lui reproche vraiment au-delà du 18 ?**
|
||||
- Elle refuse de dire
|
||||
- Alexis ne peut pas deviner
|
||||
- **Grief fantôme qui le garde coupable**
|
||||
|
||||
**2. Pourquoi elle refuse de communiquer ?**
|
||||
- Veut le punir ?
|
||||
- Ne sait pas elle-même ?
|
||||
- Immaturité émotionnelle ?
|
||||
- Pattern appris (fonctionne avec ses ex ?)
|
||||
|
||||
**3. A-t-elle déjà décidé de rompre ?**
|
||||
- Silent treatment = Début de désengagement ?
|
||||
- Ou juste punition temporaire ?
|
||||
|
||||
**4. Va-t-elle revenir avec menace de rupture ?**
|
||||
- Pattern classique de manipulation
|
||||
- Alexis préparé mentalement à accepter si ça arrive
|
||||
|
||||
---
|
||||
|
||||
## Apprentissages
|
||||
|
||||
### Négatifs (ce qui a échoué)
|
||||
|
||||
**1. Question "but are you right" = Erreur tactique majeure**
|
||||
- Mauvais timing
|
||||
- Invalidation perçue
|
||||
- Fuel pour sa narrative négative
|
||||
|
||||
**2. Pattern "but" d'Alexis incompatible avec gestion émotionnelle**
|
||||
- Fonctionne en logique, pas en couple
|
||||
- Doit apprendre nouvelle façon de communiquer
|
||||
|
||||
**3. "Figure it out" = Jeu impossible à gagner**
|
||||
- Tu ne peux pas deviner les pensées
|
||||
- Pattern toxique confirmé
|
||||
|
||||
**4. Silent treatment = Red flag majeur**
|
||||
- Communication devient impossible
|
||||
- Punition active, pas résolution
|
||||
|
||||
### Positifs (ce qui a marché)
|
||||
|
||||
**1. Alexis refuse de jouer le jeu**
|
||||
- Pose ses limites
|
||||
- Ne supplie pas
|
||||
- Se retire avec dignité
|
||||
|
||||
**2. Gestion émotionnelle améliorée**
|
||||
- Pas de rupture impulsive malgré frustration
|
||||
- Calme maintenu
|
||||
|
||||
**3. Position de force psychologique**
|
||||
- A déjà fait le deuil mental hier
|
||||
- Moins de peur aujourd'hui
|
||||
- Prêt à accepter rupture si nécessaire
|
||||
|
||||
**4. Application des 4 règles**
|
||||
- Pas de décision sous émotion
|
||||
- Limites posées clairement
|
||||
- Supériorité morale maintenue
|
||||
- Aucun yield
|
||||
|
||||
---
|
||||
|
||||
## État actuel (fin du 19 octobre)
|
||||
|
||||
**Tingting :**
|
||||
- Sortie de l'appartement
|
||||
- Refuse de communiquer ("I will not tell you")
|
||||
- Pattern de punition active
|
||||
|
||||
**Alexis :**
|
||||
- Dort seul dans autre pièce
|
||||
- Limite posée clairement
|
||||
- Calme, pas en panique
|
||||
- Mentalement préparé à rupture si nécessaire
|
||||
- Occupe son temps (projets MCP Blender/Musique)
|
||||
|
||||
**Relation :**
|
||||
- Communication rompue
|
||||
- Pattern toxique confirmé
|
||||
- Issue incertaine
|
||||
- Dépend de la volonté de Tingting de communiquer
|
||||
|
||||
---
|
||||
|
||||
## Suivi nécessaire
|
||||
|
||||
### Immédiat (20 octobre matin)
|
||||
|
||||
**☐ Observer sa réaction au réveil**
|
||||
- Revient-elle communiquer ?
|
||||
- Maintient-elle le silent treatment ?
|
||||
- Escalade-t-elle (menace rupture) ?
|
||||
|
||||
**☐ Alexis maintient sa position**
|
||||
- Ne yield pas
|
||||
- N'insiste pas
|
||||
- Disponible pour communication adulte
|
||||
- Mais ne supplie pas
|
||||
|
||||
### Court terme (prochains jours)
|
||||
|
||||
**☐ Si elle maintient le refus de communiquer**
|
||||
- Alexis doit décider combien de temps il accepte ça
|
||||
- Poser ultimatum ? ("On communique ou on arrête")
|
||||
- Ou accepter que c'est fini ?
|
||||
|
||||
**☐ Si elle revient avec menace de rupture**
|
||||
- Alexis accepte calmement
|
||||
- Pas de négociation sous chantage
|
||||
- "If that's what you want, OK"
|
||||
|
||||
**☐ Si elle accepte enfin de communiquer**
|
||||
- Conversation structurée (pas improvisée)
|
||||
- Clarifier le grief réel
|
||||
- Exposer le pattern toxique
|
||||
- Solutions concrètes ou incompatibilité
|
||||
|
||||
### Moyen terme
|
||||
|
||||
**☐ Décision sur viabilité de la relation**
|
||||
- Si pattern continue = Rupture
|
||||
- Si elle change vraiment = Donner une chance
|
||||
- Mais vigilance maximale
|
||||
|
||||
**☐ Préparation logistique si rupture**
|
||||
- Bail (partagé ou nom d'Alexis ?)
|
||||
- Où aller temporairement ?
|
||||
- Séparation des affaires
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
### Pattern établi sur 4 jours (16-19 octobre)
|
||||
|
||||
**16 oct :** Grief caché ("Je ne sais pas")
|
||||
**17 oct :** Tension sous-jacente
|
||||
**18 oct :** Explosion + "Figure it out"
|
||||
**19 oct :** Silent treatment + "I will not tell you"
|
||||
|
||||
**= Escalade claire du pattern toxique**
|
||||
|
||||
### Red flags accumulés
|
||||
|
||||
1. ✅ Griefs cachés (16)
|
||||
2. ✅ Refus de clarifier (18-19)
|
||||
3. ✅ "Figure it out" = Jeu de devinettes (18-19)
|
||||
4. ✅ Silent treatment (19)
|
||||
5. ✅ "I will not tell you" = Refus actif de communiquer (19)
|
||||
6. ✅ Jeux de territoire/pouvoir (19)
|
||||
|
||||
**= 6 red flags en 4 jours**
|
||||
|
||||
### Alexis a évolué positivement
|
||||
|
||||
**Avant (pattern habituel) :**
|
||||
- Yield face à escalade
|
||||
- Supplie quand elle refuse de parler
|
||||
- Panique à l'idée de rupture
|
||||
|
||||
**Maintenant (19 octobre) :**
|
||||
- Pose ses limites
|
||||
- Se retire avec dignité
|
||||
- Accepte mentalement la rupture possible
|
||||
- Ne joue pas aux jeux toxiques
|
||||
|
||||
**= Croissance personnelle malgré le conflit**
|
||||
|
||||
### Le problème n'est pas QUE la communication
|
||||
|
||||
**Niveau surface :** "Figure it out" = Communication toxique
|
||||
|
||||
**Niveau profond :**
|
||||
- Veut-elle vraiment résoudre ou juste punir ?
|
||||
- A-t-elle les outils émotionnels pour communiquer sainement ?
|
||||
- Est-elle capable de changer ce pattern ?
|
||||
- Ou est-ce structurel chez elle ?
|
||||
|
||||
**Si c'est structurel → Incompatibilité fondamentale**
|
||||
|
||||
---
|
||||
|
||||
## Réflexions d'Alexis (contexte mental)
|
||||
|
||||
### Peur de finir la relation
|
||||
|
||||
**Hier (18) :** Peur intense → Crise d'anxiété
|
||||
**Aujourd'hui (19) :** Peur toujours présente MAIS gérée
|
||||
|
||||
**Différence :**
|
||||
- A déjà visualisé la rupture hier
|
||||
- A survécu à la crise d'anxiété
|
||||
- Sait qu'il peut gérer émotionnellement
|
||||
- **= Moins de peur car déjà "passé par là" mentalement**
|
||||
|
||||
### Pattern "but" à changer
|
||||
|
||||
**Reconnaissance :**
|
||||
- C'est son schéma de comm normal
|
||||
- Fonctionne en contexte intellectuel
|
||||
- Dysfonctionnel en contexte émotionnel
|
||||
|
||||
**Plan :**
|
||||
- Apprendre à valider SANS "but"
|
||||
- Séparer validation et questionnement
|
||||
- Émotions d'abord, logique après
|
||||
- Leadership socratique ≠ Débat philosophique
|
||||
|
||||
### Soirée productive malgré tout
|
||||
|
||||
**Au lieu de ruminer :**
|
||||
- Installé MCP Blender (fonctionne)
|
||||
- Recherché MCPs musique (trouvé plein d'options)
|
||||
- Documenté les découvertes
|
||||
- Occupé son esprit créativement
|
||||
|
||||
**= Gestion saine du stress**
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Conflit majeur révélant pattern de communication toxique profondément établi.**
|
||||
|
||||
**Tingting refuse activement de communiquer, utilise silent treatment et jeux de pouvoir.**
|
||||
|
||||
**Alexis pose ses limites pour la première fois clairement, refuse de jouer aux jeux toxiques, se retire avec dignité.**
|
||||
|
||||
**Issue incertaine. Dépend entièrement de la volonté de Tingting de communiquer comme une adulte.**
|
||||
|
||||
**Si elle maintient ce pattern, la relation est terminée de facto, car communication = impossible.**
|
||||
|
||||
**Alexis mentalement préparé à accepter rupture si nécessaire. Position de force psychologique malgré peur.**
|
||||
|
||||
**Prochaines 24-48h décisives.**
|
||||
|
||||
---
|
||||
|
||||
**Prochain update :** 20 octobre selon évolution
|
||||
40
couple_backlog/1_octobre_2025.md
Normal file
40
couple_backlog/1_octobre_2025.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Conflit du 1er Octobre 2025
|
||||
|
||||
## Contexte
|
||||
- **Date** : 1er octobre 2025
|
||||
- **Phase** : Pré-période (Tingting)
|
||||
|
||||
## Points de friction
|
||||
|
||||
### 1. Absence de plan
|
||||
- **Problème** : Je n'ai pas de plan
|
||||
- **Impact** : Elle attend probablement que j'en aie un
|
||||
|
||||
### 2. Désaccord sur son plan
|
||||
- **Problème** : Je n'aime pas son plan
|
||||
- **Non-dit** : Je ne l'ai probablement pas exprimé clairement
|
||||
|
||||
### 3. Dynamique de discussion
|
||||
- **Problème** : Je ne suis pas son allié dans nos discussions
|
||||
- **Pattern** : Opposition plutôt que collaboration
|
||||
- **Contexte hormonal** : Pré-période = sensibilité accrue
|
||||
|
||||
## Analyse rapide
|
||||
|
||||
### Contexte
|
||||
- Pré-période = tensions amplifiées
|
||||
- Manque de leadership socratique de ma part
|
||||
|
||||
### Émotions
|
||||
- Elle : Frustration de ne pas être soutenue
|
||||
- Moi : Résistance passive-agressive
|
||||
|
||||
### Pattern identifié
|
||||
- J'oppose sans proposer
|
||||
- Je critique sans construire
|
||||
- Je ne suis pas dans la collaboration
|
||||
|
||||
## Actions à prendre
|
||||
- [ ] Appliquer le leadership socratique
|
||||
- [ ] Proposer un plan concret
|
||||
- [ ] Être allié, pas adversaire
|
||||
53
couple_backlog/1_octobre_2025_golden_week.md
Normal file
53
couple_backlog/1_octobre_2025_golden_week.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Vacances Golden Week - 1-7 Octobre 2025
|
||||
|
||||
## Type
|
||||
⚡ **Mixte** - Globalement positif avec point de friction important
|
||||
|
||||
## Contexte
|
||||
- **Date** : 1-7 octobre 2025
|
||||
- **Lieu** : Wuhan (depuis Shanghai)
|
||||
- **Initiative** : Alexis - pour revoir une amie commune (Xiaoxiao)
|
||||
- **Événement** : Vacances nationales (Golden Week)
|
||||
- **Conditions** : Fatigue, maladie pendant le voyage
|
||||
|
||||
## Description
|
||||
|
||||
Vacances à Wuhan pour revoir notre amie commune Xiaoxiao. Globalement bon moment malgré conditions difficiles (fatigue, maladie).
|
||||
|
||||
### Ce qui a bien fonctionné
|
||||
- **J'ai pris soin d'elle** - Attitude attentionnée et caring
|
||||
- **Beaux souvenirs créés** - Malgré les obstacles
|
||||
- **Résilience du couple** - Capable de passer un bon moment même dans l'adversité
|
||||
|
||||
### Point de friction majeur
|
||||
- **Câlins de réconfort à Xiaoxiao** : J'ai fait des câlins de réconfort à Xiaoxiao car elle est encore affectée par sa rupture d'amitié avec Ben (il y a 7-8 ans)
|
||||
- **Contexte Ben** : Ex-ami commun
|
||||
- Rupture Xiaoxiao-Ben : il y a 7-8 ans (malentendu romantique après rupture des parents de Ben)
|
||||
- Rupture Alexis/Tingting-Ben : il y a un an (Ben avait des sentiments pour Tingting pendant 7 ans)
|
||||
- Situation continue d'affecter le cercle social
|
||||
- **Réaction de Tingting** : Elle n'a pas aimé du tout le contact physique avec Xiaoxiao
|
||||
- **Ligne rouge identifiée** : Contact physique avec une autre femme (même en couple, même dans un contexte de réconfort) n'est pas acceptable pour elle
|
||||
|
||||
## Apprentissages
|
||||
|
||||
### Ce qui marche
|
||||
- **Prendre soin activement** : Quand je montre de l'attention et du care envers Tingting, ça renforce le lien
|
||||
- **Attitude positive** : Ne pas laisser la fatigue/maladie gâcher le moment
|
||||
- **Adaptation** : Capable d'ajuster les plans selon l'état de chacun
|
||||
|
||||
### Erreur commise
|
||||
- **Contact physique avec autre femme** : Les câlins à Xiaoxiao ont franchi une limite
|
||||
- **Manque de conscience** : Je n'ai pas anticipé que ça poserait problème
|
||||
- **Boundary culturelle/personnelle** : Tingting a des limites claires sur ce qui est acceptable
|
||||
|
||||
### À retenir
|
||||
- **Limites de Tingting** : Pas de contact physique avec d'autres femmes, même amies en couple
|
||||
- **Respecter ses boundaries** : Même si moi je trouve ça innocent, c'est SA limite qui compte
|
||||
- **Maintenir l'attitude caring** : L'attitude caring envers elle fonctionne - continuer au quotidien
|
||||
|
||||
## Notes
|
||||
Moment mixte qui illustre bien la nuance :
|
||||
- ✅ Bonne attitude générale envers Tingting (care, attention) = couple fonctionne bien
|
||||
- ❌ Contact physique avec Xiaoxiao = franchissement de boundary
|
||||
|
||||
**Leçon** : Être attentionné envers Tingting ne suffit pas si je franchis ses limites avec d'autres femmes.
|
||||
680
couple_backlog/20_octobre_2025.md
Normal file
680
couple_backlog/20_octobre_2025.md
Normal file
@ -0,0 +1,680 @@
|
||||
# 20 octobre 2025 - Package café + Conversation avortée + Début guerre froide
|
||||
|
||||
**Type** : ⚡ Mixte - Geste tactique réussi MAIS conversation révèle conflit de valeurs fondamental
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
- **Quand** : Lundi 20 octobre 2025 (matin + soir)
|
||||
- **Où** : École de Tingting (package) puis appartement (conversation)
|
||||
- **État relation** : Sortie de silent treatment du 19, tentative de résolution
|
||||
- **Objectif** : Débloquer communication + Résoudre conflit 16-19 octobre
|
||||
|
||||
---
|
||||
|
||||
## Ce qui s'est passé
|
||||
|
||||
### Matin - Package café (move tactique)
|
||||
|
||||
**Action d'Alexis :**
|
||||
- Message envoyé : "What can I do right now to make you feel better? What do you need from me?"
|
||||
- Package livré à l'accueil de son école :
|
||||
- Café (besoin principal)
|
||||
- Blueberries
|
||||
- Yogurt
|
||||
- **= "Je prends soin de toi" par l'action**
|
||||
|
||||
**Réponse de Tingting :**
|
||||
- Message : "Oh many thanks"
|
||||
- Alexis pensait initialement ironique
|
||||
- **MAIS elle lui a dit timidement le soir que ça l'a aidée**
|
||||
- **= Geste apprécié, pas ironique**
|
||||
|
||||
**Analyse tactique du move :**
|
||||
- ✅ Livré à l'accueil = Pression sociale, elle doit accepter
|
||||
- ✅ "Heads I win, tails you lose" pour elle
|
||||
- ✅ Si accepte = Geste apprécié + Face sauvée
|
||||
- ✅ Si refuse = Perd face publiquement
|
||||
- ✅ Communication indirecte (style chinois) = Efficace
|
||||
- **= Move tactique parfait, manipulation bienveillante**
|
||||
|
||||
**Résultat :**
|
||||
- ✅ Elle a accepté
|
||||
- ✅ Porte de communication rouverte
|
||||
- ✅ Préparation terrain pour conversation soir
|
||||
|
||||
---
|
||||
|
||||
### Soir - Tentative de conversation
|
||||
|
||||
#### Initiation difficile
|
||||
|
||||
**Contexte :**
|
||||
- Tingting rentre à l'appartement
|
||||
- Long silence
|
||||
- Alexis ne sait pas comment initier
|
||||
- **C'est toujours Alexis qui initie après les fights**
|
||||
|
||||
**Actions d'Alexis :**
|
||||
- Crée des ouvertures
|
||||
- Elle ne prend pas
|
||||
- Il l'invite à fumer sur le balcon (prétexte)
|
||||
- **= Début de quelque chose**
|
||||
|
||||
**Discussion :**
|
||||
- Dans le noir
|
||||
- Dans le bureau
|
||||
- Alexis initie la vraie conversation
|
||||
|
||||
---
|
||||
|
||||
### La conversation (contenu)
|
||||
|
||||
#### Grief #1 - Responsabilité envers elle
|
||||
|
||||
**Tingting dit :**
|
||||
- "Tu avais une responsabilité de venir avec moi (chez mes parents le 18)"
|
||||
- "Ne pas mettre ses responsabilités devant tout le reste est **very very very wrong**"
|
||||
- **= Position morale absolue**
|
||||
|
||||
**Alexis explique :**
|
||||
- "Mon sens des responsabilités n'est pas le même"
|
||||
- "Quand je suis fatigué (mode larve), les responsabilités passent après"
|
||||
- **= Bien-être > Responsabilités dans état extrême**
|
||||
|
||||
**Réponse de Tingting :**
|
||||
- Alexis : "Tu as raison de ne pas accepter, mais tu pourrais au moins me comprendre"
|
||||
- Tingting : **"I can't"**
|
||||
- **Pas "I don't understand" (je ne comprends pas)**
|
||||
- **Mais "I CAN'T" (je ne PEUX pas comprendre)**
|
||||
- **= Refus actif, pas incapacité**
|
||||
|
||||
**Analyse :**
|
||||
- Conflit de valeurs fondamental
|
||||
- Elle : Responsabilité conjugale > Limites physiques
|
||||
- Lui : Bien-être (mode larve) > Engagements sociaux
|
||||
- **Elle refuse de comprendre sa position** (choix conscient)
|
||||
|
||||
---
|
||||
|
||||
#### Grief #2 - "Tu m'as laissée 2 jours sans communication"
|
||||
|
||||
**Tingting reproche :**
|
||||
- Alexis l'a abandonnée sans communication pendant 2 jours (19-20 octobre)
|
||||
- C'était "terrible" pour elle
|
||||
|
||||
**Réalité objective (rappel 19 octobre) :**
|
||||
- **16 oct :** Tingting : "Je ne sais pas pourquoi je suis en colère"
|
||||
- **18 oct :** Tingting : "Figure it out"
|
||||
- **19 oct :** Tingting : "I will not tell you"
|
||||
- **19 oct :** Alexis pose limite : "I'm not going to guess, when you're ready to communicate I'm here"
|
||||
- **19 oct :** Tingting maintient : "I will not tell you"
|
||||
- **= C'est ELLE qui refusait activement de communiquer**
|
||||
|
||||
**Réaction d'Alexis :**
|
||||
- A énoncé que ce n'était pas le cas
|
||||
- A dit qu'il avait essayé de communiquer
|
||||
- **MAIS n'a pas poussé/confronté l'inversion**
|
||||
- **= Elle garde sa version de la réalité**
|
||||
|
||||
**Analyse :**
|
||||
- **Inversion totale de la réalité**
|
||||
- Elle transforme SON refus de parler en abandon de SA part
|
||||
- Alexis ne confronte pas assez fermement
|
||||
- **= Pattern de manipulation : Réécriture des faits**
|
||||
|
||||
---
|
||||
|
||||
#### Tentative de parler du pattern anger/fatigue
|
||||
|
||||
**Alexis essaie :**
|
||||
- D'aborder la différence entre son épuisement rare vs sa colère fréquente
|
||||
- **La conversation tourne au sujet "responsabilité"** (voir Grief #1)
|
||||
- Pas de vraie discussion sur les patterns émotionnels
|
||||
|
||||
**Résultat :**
|
||||
- Sujet non-traité
|
||||
- Dévié vers moralité des responsabilités
|
||||
- **= Évitement du vrai problème structurel**
|
||||
|
||||
---
|
||||
|
||||
### Fin de conversation (avortée)
|
||||
|
||||
**Tingting :**
|
||||
- Va aux toilettes
|
||||
- Revient : **"I'm tired"**
|
||||
- **= Coupe la conversation**
|
||||
|
||||
**Suite :**
|
||||
- Ils font ses papiers (travail) ensemble
|
||||
- Puis vont se coucher
|
||||
|
||||
**Analyse :**
|
||||
- Conversation avortée, pas de résolution
|
||||
- Pattern : Elle ouvre un peu, puis referme quand ça devient inconfortable
|
||||
- "I'm tired" = Excuse pour éviter de continuer
|
||||
- **= Évitement actif**
|
||||
|
||||
---
|
||||
|
||||
## Analyse complète
|
||||
|
||||
### Ce qui a marché
|
||||
|
||||
**✅ Package café :**
|
||||
- A débloqué communication
|
||||
- Elle a apprécié (même si timidement)
|
||||
- Move tactique parfait
|
||||
- Utilisation intelligente des codes sociaux chinois
|
||||
|
||||
**✅ Alexis initie :**
|
||||
- Crée ouvertures malgré résistance
|
||||
- Trouve prétexte (fumée) pour lancer
|
||||
- Persiste jusqu'à obtenir conversation
|
||||
|
||||
**✅ Pas d'escalade :**
|
||||
- Alexis reste calme
|
||||
- Pas d'attaque
|
||||
- Écoute ses griefs
|
||||
|
||||
---
|
||||
|
||||
### Ce qui a échoué
|
||||
|
||||
**❌ Conversation sans substance :**
|
||||
- Alexis se souvient à peine de quoi ils ont parlé ("tellement c'était useless")
|
||||
- Aucune solution concrète
|
||||
- Juste tour en rond
|
||||
|
||||
**❌ Inversion de réalité non-confrontée :**
|
||||
- Elle dit qu'il l'a abandonnée 2 jours
|
||||
- Réalité : C'est elle qui refusait de parler
|
||||
- Alexis énonce mais ne pousse pas
|
||||
- **= Elle garde sa version**
|
||||
|
||||
**❌ "I can't understand" :**
|
||||
- Refus actif de comprendre sa position
|
||||
- Pas de terrain d'entente possible si elle refuse de comprendre
|
||||
- **= Blocage volontaire**
|
||||
|
||||
**❌ Responsabilité "very very very wrong" :**
|
||||
- Position morale absolue
|
||||
- Pas de nuance
|
||||
- Tes limites physiques = Pas une excuse acceptable
|
||||
- **= Rigidité**
|
||||
|
||||
**❌ Conversation avortée :**
|
||||
- "I'm tired" = Elle coupe quand inconfortable
|
||||
- Pas de conclusion
|
||||
- Pas de plan d'action
|
||||
- **= Évitement**
|
||||
|
||||
---
|
||||
|
||||
## Griefs révélés de Tingting
|
||||
|
||||
### Au-delà du 18 octobre (enfin clarifiés)
|
||||
|
||||
**1. Manquement à la responsabilité conjugale**
|
||||
- Tu n'es pas venu chez ses parents le 18
|
||||
- Pour elle c'est une responsabilité non-négociable
|
||||
- Prioriser ton sommeil = Moralement répréhensible
|
||||
|
||||
**2. Pattern de priorisation sommeil > Engagements**
|
||||
- Elle voit un pattern récurrent
|
||||
- "Ne pas mettre responsabilités devant tout" = "very very very wrong"
|
||||
- Elle refuse ton explication (fatigue mode larve)
|
||||
|
||||
**3. "Abandon" pendant 2 jours**
|
||||
- 19-20 octobre sans communication
|
||||
- Elle se sent abandonnée
|
||||
- (Même si c'est elle qui refusait de parler)
|
||||
|
||||
**= Griefs centrés sur RESPONSABILITÉ et PRIORITÉS**
|
||||
|
||||
---
|
||||
|
||||
## Conflit de valeurs fondamental révélé
|
||||
|
||||
### Système de valeurs de Tingting
|
||||
|
||||
**Hiérarchie :**
|
||||
1. **Responsabilités conjugales/familiales** (visites parents, engagements)
|
||||
2. **Communication constante** (ne jamais laisser sans nouvelles)
|
||||
3. **Bien-être personnel** (dernier)
|
||||
|
||||
**Vision :**
|
||||
- Un bon partenaire respecte ses engagements TOUJOURS
|
||||
- Les limites physiques ne sont pas des excuses
|
||||
- L'abandon (même 2 jours) est terrible
|
||||
|
||||
**= Culture chinoise traditionnelle + Besoin de sécurité émotionnelle élevé**
|
||||
|
||||
---
|
||||
|
||||
### Système de valeurs d'Alexis
|
||||
|
||||
**Hiérarchie :**
|
||||
1. **Bien-être physique/mental** (surtout en mode larve)
|
||||
2. **Responsabilités** (quand état normal)
|
||||
3. **Engagements sociaux** (flexibles selon état)
|
||||
|
||||
**Vision :**
|
||||
- Un bon partenaire respecte ses limites
|
||||
- Quand mode larve = Impossible de fonctionner, mieux se retirer
|
||||
- Communication impossible quand cerveau à 0%
|
||||
|
||||
**= Culture occidentale individualiste + Sommeil fragile réel**
|
||||
|
||||
---
|
||||
|
||||
### Incompatibilité ?
|
||||
|
||||
**Question centrale :**
|
||||
**Peut-on concilier ces deux systèmes de valeurs ?**
|
||||
|
||||
**Scénario A - Conciliation possible :**
|
||||
- Alexis : Setup sommeil strict pour éviter mode larve
|
||||
- Tingting : Accepte que mode larve = Exception rare mais réelle
|
||||
- Compromis : Si mode larve, Alexis prévient + rassure, puis se retire
|
||||
- **= Nécessite que Tingting ACCEPTE de comprendre**
|
||||
|
||||
**Scénario B - Incompatibilité fondamentale :**
|
||||
- Tingting : "I can't understand" = Refus de concession
|
||||
- Alexis : Refuse de sacrifier bien-être systématiquement
|
||||
- Aucun terrain d'entente
|
||||
- **= Impasse**
|
||||
|
||||
**État actuel : Scénario B (elle refuse de comprendre)**
|
||||
|
||||
---
|
||||
|
||||
## Pattern manipulation confirmé
|
||||
|
||||
### Inversion de réalité
|
||||
|
||||
**Ce qui s'est passé réellement :**
|
||||
- 19 oct : Tingting refuse de parler ("I will not tell you")
|
||||
- 19 oct : Alexis pose limite ("When you're ready, I'm here")
|
||||
- 19-20 oct : Tingting maintient silent treatment
|
||||
|
||||
**Ce qu'elle dit :**
|
||||
- "Tu m'as laissée 2 jours sans communication"
|
||||
- "C'était terrible"
|
||||
- **= Elle se positionne en victime abandonnée**
|
||||
|
||||
**Résultat :**
|
||||
- Alexis devient le coupable
|
||||
- Elle devient la victime
|
||||
- **= Gaslighting léger (réécriture des faits)**
|
||||
|
||||
---
|
||||
|
||||
### Pattern de conversation avortée
|
||||
|
||||
**Observé plusieurs fois :**
|
||||
1. **16 oct :** "Je ne sais pas pourquoi je suis en colère" (évitement)
|
||||
2. **18-19 oct :** "Figure it out" / "I will not tell you" (refus)
|
||||
3. **20 oct :** "I'm tired" (coupe conversation)
|
||||
|
||||
**= Pattern : Ouvre un peu, puis referme quand ça devient réel**
|
||||
|
||||
---
|
||||
|
||||
## État relation fin du 20 octobre
|
||||
|
||||
### Guerre froide commence
|
||||
|
||||
**Définition :**
|
||||
- Plus de conflit actif
|
||||
- Mais pas de résolution
|
||||
- Cohabitation distante
|
||||
- Communication minimale/superficielle
|
||||
|
||||
**Comment ça s'est installé :**
|
||||
- Conversation avortée (pas de conclusion)
|
||||
- Griefs non-résolus
|
||||
- Conflit de valeurs exposé mais pas traité
|
||||
- **= Stalemate**
|
||||
|
||||
**Comportements :**
|
||||
- Font les papiers ensemble (fonctionnel)
|
||||
- Dorment ensemble (probablement)
|
||||
- Mais distance émotionnelle
|
||||
- Pas d'intimité/affection
|
||||
|
||||
---
|
||||
|
||||
## Erreurs d'Alexis
|
||||
|
||||
**❌ Erreur 1 : Ne pas confronter l'inversion de réalité**
|
||||
- Elle dit qu'il l'a abandonnée 2 jours
|
||||
- Il énonce que non mais ne pousse pas
|
||||
- **Il aurait dû :** Être ferme et factuel
|
||||
- "Non. C'est toi qui refusais de parler. J'ai essayé plusieurs fois. Tu as dit 'I will not tell you'. Je ne réécris pas l'histoire."
|
||||
|
||||
**❌ Erreur 2 : Accepter "I can't understand"**
|
||||
- Elle refuse de comprendre
|
||||
- Il laisse passer
|
||||
- **Il aurait dû :** Question socratique
|
||||
- "Tu ne peux pas ou tu ne veux pas ? Parce que si tu refuses de comprendre ma réalité, on ne peut pas avancer."
|
||||
|
||||
**❌ Erreur 3 : Laisser conversation avorter**
|
||||
- Elle dit "I'm tired"
|
||||
- Ils passent aux papiers
|
||||
- **Il aurait dû :** Poser limite
|
||||
- "On ne peut pas laisser ça comme ça. Quand est-ce qu'on finit cette conversation ?"
|
||||
|
||||
**❌ Erreur 4 : Pas de plan d'action défini**
|
||||
- Conversation sans conclusion
|
||||
- Pas de "on se reparle demain"
|
||||
- Pas de solutions proposées
|
||||
- **= Conversation inutile (d'où impression "useless")**
|
||||
|
||||
---
|
||||
|
||||
## Forces d'Alexis
|
||||
|
||||
**✅ Package café = Move tactique brillant**
|
||||
- Anticipe besoins
|
||||
- Utilise codes sociaux
|
||||
- Débloque situation
|
||||
|
||||
**✅ Initiation persistante**
|
||||
- Crée ouvertures
|
||||
- Trouve prétexte (fumée)
|
||||
- Ne lâche pas jusqu'à obtenir conversation
|
||||
|
||||
**✅ Reste calme**
|
||||
- Pas d'escalade
|
||||
- Écoute ses griefs
|
||||
- Explique sa position
|
||||
|
||||
**✅ Tente d'aborder patterns**
|
||||
- Essaie de parler anger/fatigue
|
||||
- Même si dévié
|
||||
|
||||
---
|
||||
|
||||
## Questions non résolues
|
||||
|
||||
**1. Responsabilité = Quoi exactement pour elle ?**
|
||||
- Venir chez parents = Responsabilité absolue ?
|
||||
- Ne JAMAIS prioriser son bien-être ?
|
||||
- Être disponible 24/7 ?
|
||||
- **Pas clarifié**
|
||||
|
||||
**2. "I can't understand" = Refus permanent ou temporaire ?**
|
||||
- Elle refuse de comprendre pour toujours ?
|
||||
- Ou juste maintenant car en colère ?
|
||||
- **Pas clarifié**
|
||||
|
||||
**3. Les 2 jours d'abandon = Elle y croit vraiment ?**
|
||||
- Réécriture consciente des faits (manipulation) ?
|
||||
- Ou perception biaisée par émotion ?
|
||||
- **Pas clarifié**
|
||||
|
||||
**4. Guerre froide = Combien de temps ?**
|
||||
- Elle compte attendre quoi ?
|
||||
- Que toi tu cèdes ?
|
||||
- Que le temps passe ?
|
||||
- **Pas clarifié**
|
||||
|
||||
---
|
||||
|
||||
## Apprentissages
|
||||
|
||||
### Négatifs (ce qui a échoué)
|
||||
|
||||
**1. Conversation sans structure = Useless**
|
||||
- Pas de plan
|
||||
- Pas de phases claires
|
||||
- Tourne en rond
|
||||
- **= Perte de temps**
|
||||
|
||||
**2. Ne pas confronter inversions = Elle garde sa version**
|
||||
- Elle réécrit l'histoire
|
||||
- Alexis laisse passer
|
||||
- **= Elle devient victime, lui coupable**
|
||||
|
||||
**3. Accepter "I can't understand" = Impasse**
|
||||
- Si elle refuse de comprendre
|
||||
- Aucune solution possible
|
||||
- **= Blocage**
|
||||
|
||||
**4. Laisser conversation avorter = Pas de résolution**
|
||||
- "I'm tired" = Excuse
|
||||
- Pas de suite définie
|
||||
- **= Guerre froide s'installe**
|
||||
|
||||
---
|
||||
|
||||
### Positifs (ce qui a marché)
|
||||
|
||||
**1. Package café = Manipulation bienveillante efficace**
|
||||
- Action > Mots
|
||||
- Codes sociaux utilisés intelligemment
|
||||
- **= Leadership par anticipation**
|
||||
|
||||
**2. Initiation persistante = Conversation obtenue**
|
||||
- Même si résistance
|
||||
- Trouve moyen (fumée)
|
||||
- **= Persévérance payante**
|
||||
|
||||
**3. Griefs enfin clarifiés**
|
||||
- Au moins maintenant Alexis sait ce qu'elle lui reproche
|
||||
- Responsabilité + Abandon
|
||||
- **= Pas "figure it out" vague**
|
||||
|
||||
**4. Conflit de valeurs exposé**
|
||||
- Même si pas résolu
|
||||
- Au moins visible
|
||||
- **= Peut être adressé (si elle veut)**
|
||||
|
||||
---
|
||||
|
||||
## Pronostic
|
||||
|
||||
### Court terme (jours)
|
||||
|
||||
**Guerre froide continue probablement :**
|
||||
- Rien résolu lundi
|
||||
- Elle refuse de comprendre
|
||||
- Alexis n'a pas forcé résolution
|
||||
- **= Cohabitation distante**
|
||||
|
||||
**Scénarios possibles :**
|
||||
- Elle revient quand elle se sent mieux (pattern habituel ?)
|
||||
- Alexis force nouvelle conversation
|
||||
- Guerre froide perdure jusqu'à explosion
|
||||
- Ou jusqu'à mariage (proche) puis problèmes empirent
|
||||
|
||||
---
|
||||
|
||||
### Moyen terme (semaines)
|
||||
|
||||
**Si guerre froide continue :**
|
||||
- ❌ Alexis épuisé mentalement
|
||||
- ❌ Ressentiment accumule
|
||||
- ❌ Distance émotionnelle s'installe
|
||||
- ❌ Relation devient coquille vide
|
||||
|
||||
**Si nouvelle conversation forcée :**
|
||||
- Besoin de structure claire
|
||||
- Besoin de confronter inversions
|
||||
- Besoin de solutions concrètes
|
||||
- **Ou accepter incompatibilité**
|
||||
|
||||
---
|
||||
|
||||
### Long terme (mois)
|
||||
|
||||
**Si conflit de valeurs non-résolu :**
|
||||
- Mariage proche = Pression
|
||||
- Pattern va se répéter
|
||||
- "Responsabilité conjugale" va s'intensifier après mariage
|
||||
- **= Explosion future garantie**
|
||||
|
||||
**Si Tingting refuse toujours de comprendre :**
|
||||
- "I can't understand" = Position figée
|
||||
- Alexis doit choisir :
|
||||
- Sacrifier bien-être systématiquement (inacceptable)
|
||||
- Ou accepter incompatibilité fondamentale
|
||||
- **= Rupture probable**
|
||||
|
||||
---
|
||||
|
||||
## Suivi nécessaire
|
||||
|
||||
### Immédiat (21-22 octobre)
|
||||
|
||||
**☐ Observer état guerre froide**
|
||||
- Comment elle se comporte ?
|
||||
- Distance maintenue ?
|
||||
- Communication minimale ?
|
||||
|
||||
**☐ Alexis décide combien de temps il tolère ça**
|
||||
- 1 semaine ? 1 mois ?
|
||||
- Ou force nouvelle conversation rapidement ?
|
||||
|
||||
---
|
||||
|
||||
### Court terme (cette semaine)
|
||||
|
||||
**☐ Nouvelle conversation nécessaire - STRUCTURÉE cette fois**
|
||||
|
||||
**Si Alexis initie, préparation obligatoire :**
|
||||
|
||||
**Phase 1 : Confronter inversion de réalité (ferme)**
|
||||
- "Tu dis que je t'ai abandonnée 2 jours. C'est faux. C'est toi qui refusais de parler. Je ne vais pas accepter cette réécriture de l'histoire."
|
||||
|
||||
**Phase 2 : Clarifier "I can't understand"**
|
||||
- "Tu dis que tu ne peux pas comprendre. C'est 'ne peux pas' ou 'ne veux pas' ? Parce que si tu refuses de comprendre ma réalité, on a un problème fondamental."
|
||||
|
||||
**Phase 3 : Responsabilité - Définir limites**
|
||||
- "Je comprends que venir chez tes parents est important. Mais quand je suis en mode larve (rare, 1-2x/mois), je ne peux physiquement pas. Ce n'est pas négociable. Peux-tu accepter ça ?"
|
||||
|
||||
**Phase 4 : Solutions ou incompatibilité**
|
||||
- Si elle accepte : Setup strict + Protocole + Compromis
|
||||
- Si elle refuse : "Alors on a une incompatibilité fondamentale sur nos valeurs."
|
||||
|
||||
---
|
||||
|
||||
### Moyen terme (avant mariage)
|
||||
|
||||
**☐ Décision sur viabilité relation**
|
||||
- Si elle maintient "I can't understand"
|
||||
- Si elle maintient "Responsabilité > Tout"
|
||||
- **= Alexis doit reconsidérer mariage**
|
||||
|
||||
**☐ Préparation logistique si rupture**
|
||||
- Bail
|
||||
- Séparation affaires
|
||||
- Plan B logement
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
### Manipulation bienveillante vs toxique
|
||||
|
||||
**Package café = Manipulation bienveillante :**
|
||||
- Objectif : Aider + Débloquer
|
||||
- Résultat : Bénéfice mutuel
|
||||
- **= OK moralement**
|
||||
|
||||
**Inversion de réalité = Manipulation toxique :**
|
||||
- Objectif : Se victimiser + Culpabiliser Alexis
|
||||
- Résultat : Elle gagne, lui perd
|
||||
- **= Red flag**
|
||||
|
||||
**Différence = Intention + Résultat**
|
||||
|
||||
---
|
||||
|
||||
### "I can't" vs "I don't"
|
||||
|
||||
**"I don't understand" :**
|
||||
- Je ne comprends pas (encore)
|
||||
- Mais tu peux m'expliquer
|
||||
- **= Ouverture possible**
|
||||
|
||||
**"I can't understand" :**
|
||||
- Je ne PEUX pas comprendre
|
||||
- Même si tu expliques
|
||||
- **= Refus, fermeture**
|
||||
|
||||
**Elle a dit "I can't" = Choix conscient de ne pas comprendre**
|
||||
|
||||
---
|
||||
|
||||
### Conflit culturel possible
|
||||
|
||||
**Chine traditionnelle :**
|
||||
- Famille/responsabilités > Individu
|
||||
- Visites parents = Obligation sacrée
|
||||
- Limites personnelles = Moins importantes
|
||||
|
||||
**Occident individualiste :**
|
||||
- Bien-être individuel = Priorité
|
||||
- Responsabilités = Importantes mais pas absolues
|
||||
- Limites personnelles = Respectées
|
||||
|
||||
**Alexis + Tingting = Clash de ces deux visions**
|
||||
|
||||
**Possible de concilier SI volonté mutuelle**
|
||||
**Impossible SI rigidité ("very very very wrong")**
|
||||
|
||||
---
|
||||
|
||||
### Pattern "C'est toujours moi qui initie"
|
||||
|
||||
**Alexis note :**
|
||||
- Après chaque fight, c'est lui qui initie conversation
|
||||
- Tingting ne vient jamais en premier
|
||||
- **= Pattern déséquilibré**
|
||||
|
||||
**Questions :**
|
||||
- Elle attend toujours qu'il vienne ?
|
||||
- Elle ne sait pas initier ?
|
||||
- Elle pense que c'est son rôle à lui ?
|
||||
- **= Leadership unilatéral (épuisant)**
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Le package café a débloqué la communication (succès tactique).**
|
||||
|
||||
**MAIS la conversation a révélé un conflit de valeurs fondamental non-résolu :**
|
||||
- Tingting : Responsabilité conjugale > Bien-être personnel (position absolue "very very very wrong")
|
||||
- Alexis : Bien-être (mode larve) > Engagements sociaux temporairement
|
||||
- Tingting refuse de comprendre ("I can't understand")
|
||||
|
||||
**Elle inverse la réalité (gaslighting léger) :**
|
||||
- Dit qu'Alexis l'a abandonnée 2 jours
|
||||
- Réalité : C'est elle qui refusait de parler
|
||||
- Alexis ne confronte pas assez fermement
|
||||
|
||||
**Conversation avortée ("I'm tired") :**
|
||||
- Pas de résolution
|
||||
- Pas de plan d'action
|
||||
- Alexis se souvient à peine ("tellement c'était useless")
|
||||
|
||||
**Résultat : Guerre froide s'installe.**
|
||||
- Cohabitation distante
|
||||
- Communication minimale
|
||||
- Griefs non-résolus
|
||||
- Conflit de valeurs exposé mais pas traité
|
||||
|
||||
**Si Tingting maintient "I can't understand" + Inversion réalité + Refus de compromis sur responsabilités :**
|
||||
**= Incompatibilité fondamentale probable**
|
||||
**= Alexis doit décider : Sacrifier bien-être systématiquement OU Accepter que ça ne peut pas marcher**
|
||||
|
||||
**Prochaines 48h critiques : Guerre froide continue ou nouvelle conversation forcée ?**
|
||||
|
||||
---
|
||||
|
||||
**Prochain update :** Selon évolution guerre froide + Actions d'Alexis
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user