feat: enhance crop marks with edge-based positioning and comprehensive tests

- Move crop marks from corner-based to edge-based positioning (top, bottom, left, right)
- Position crop marks relative to actual bead boundaries within soroban coordinate system
- Add 6 new gallery examples showcasing crop marks with diverse configurations
- Create comprehensive unit test suite (test-crop-marks-unit.js) with 18 assertions
- Update README documentation with edge-based crop mark scheme
- Simplify gallery generation by removing redundant non-static version
- All tests pass: crop marks now correctly define SVG viewBox boundaries

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-09-16 11:39:44 -05:00
parent cc507ca89d
commit 8c7a5b1291
21 changed files with 1886 additions and 775 deletions

View File

@@ -147,7 +147,10 @@ Both templates use Typst's `link()` function to annotate elements for post-proce
Example annotations in generated PDFs:
- `bead://col1-ones-heaven` - Heaven bead in column 1, ones position
- `bead://col2-tens-earth-1` - First earth bead in column 2, tens position
- `crop-mark://top-left` - Top-left crop boundary
- `crop-mark://top` - Top edge crop boundary
- `crop-mark://bottom` - Bottom edge crop boundary
- `crop-mark://left` - Left edge crop boundary
- `crop-mark://right` - Right edge crop boundary
- `crop-mark://center` - Center reference point
### SVG Crop Mark Processing
@@ -214,10 +217,12 @@ updateViewBox('soroban.svg', 'cropped-soroban.svg');
```
**Crop Mark Processing Features:**
- **Edge-Based Marking**: Crop marks positioned at top, bottom, left, right edges (not corners)
- **Automatic ViewBox**: Calculate precise viewBox from crop mark positions
- **Consistent Cropping**: Eliminate manual SVG cropping across all generated files
- **Debugging Support**: Set `show-crop-marks: true` to visually verify boundaries
- **Flexible Margins**: Adjust `crop-margin` to control boundary spacing
- **Semantic Annotations**: `crop-mark://top`, `crop-mark://bottom`, etc. for clear identification
**Example Usage Script:** See `examples/svg-post-processor.js` for a complete implementation

View File

@@ -294,88 +294,57 @@
)
)
// Add crop marks for consistent viewBox handling
// These marks define the intended crop boundaries
#let crop-mark-size = 2pt * base-size
#let crop-mark-stroke = if show-crop-marks { 0.5pt } else { 0pt }
#let crop-mark-color = if show-crop-marks { red } else { none }
// Draw crop marks if enabled
#if show-crop-marks [
// Calculate actual extremes based on what we just drew
#let crop-mark-size = 3pt
#let bead-half-width = if bead-shape == "diamond" {
bead-size * 0.7
} else {
bead-size / 2
}
// Calculate crop boundaries with margin
#let crop-left = -crop-margin
#let crop-right = total-width + crop-margin
#let crop-top = -total-height / 2 - crop-margin
#let crop-bottom = total-height / 2 + crop-margin
// Redefine gaps for crop mark calculations
#let active-gap = 1pt
#let inactive-gap = 8pt
// Top-left crop mark
#place(
dx: crop-left,
dy: crop-top,
link("crop-mark://top-left",
rect(
width: crop-mark-size,
height: crop-mark-size,
fill: crop-mark-color,
stroke: crop-mark-stroke + crop-mark-color
)
// Calculate actual bead boundaries
#let leftmost-x = column-spacing / 2 - bead-half-width - crop-margin
#let rightmost-x = (display-digits.len() - 1) * column-spacing + column-spacing / 2 + bead-half-width + crop-margin
// Top and bottom based on actual bead positions (one bead height beyond extremes)
#let topmost-y = heaven-earth-gap - inactive-gap - bead-size - crop-margin
#let bottommost-y = heaven-earth-gap + bar-thickness + active-gap + 4 * (bead-size + adjacent-spacing) + crop-margin
// Left crop mark (at leftmost boundary, centered on reckoning bar)
#place(
dx: leftmost-x,
dy: heaven-earth-gap + bar-thickness / 2 - crop-mark-size / 2,
link("crop-mark://left", rect(width: crop-mark-size, height: crop-mark-size, fill: red, stroke: 0.5pt + red))
)
)
// Top-right crop mark
#place(
dx: crop-right - crop-mark-size,
dy: crop-top,
link("crop-mark://top-right",
rect(
width: crop-mark-size,
height: crop-mark-size,
fill: crop-mark-color,
stroke: crop-mark-stroke + crop-mark-color
)
// Right crop mark (at rightmost boundary, centered on reckoning bar)
#place(
dx: rightmost-x - crop-mark-size,
dy: heaven-earth-gap + bar-thickness / 2 - crop-mark-size / 2,
link("crop-mark://right", rect(width: crop-mark-size, height: crop-mark-size, fill: red, stroke: 0.5pt + red))
)
)
// Bottom-left crop mark
#place(
dx: crop-left,
dy: crop-bottom - crop-mark-size,
link("crop-mark://bottom-left",
rect(
width: crop-mark-size,
height: crop-mark-size,
fill: crop-mark-color,
stroke: crop-mark-stroke + crop-mark-color
)
// Top crop mark (above topmost bead, centered on first column)
#place(
dx: column-spacing / 2 - crop-mark-size / 2,
dy: topmost-y,
link("crop-mark://top", rect(width: crop-mark-size, height: crop-mark-size, fill: red, stroke: 0.5pt + red))
)
)
// Bottom-right crop mark
#place(
dx: crop-right - crop-mark-size,
dy: crop-bottom - crop-mark-size,
link("crop-mark://bottom-right",
rect(
width: crop-mark-size,
height: crop-mark-size,
fill: crop-mark-color,
stroke: crop-mark-stroke + crop-mark-color
)
// Bottom crop mark (below bottommost bead, centered on last column)
#place(
dx: (display-digits.len() - 1) * column-spacing + column-spacing / 2 - crop-mark-size / 2,
dy: bottommost-y - crop-mark-size,
link("crop-mark://bottom", rect(width: crop-mark-size, height: crop-mark-size, fill: red, stroke: 0.5pt + red))
)
)
]
// Center reference mark (for debugging alignment)
#if show-crop-marks {
place(
dx: total-width / 2 - crop-mark-size / 2,
dy: -crop-mark-size / 2,
link("crop-mark://center",
circle(
radius: crop-mark-size / 2,
fill: rgb("#ff6b6b"),
stroke: 0.5pt + rgb("#ff6b6b")
)
)
)
}
]
]
}

View File

@@ -164,8 +164,8 @@
<div class="stats">
<div class="stats-info">
<strong>6</strong> examples rendered
• Generated on 9/16/2025 at 10:26:11 AM
<strong>8</strong> examples rendered
• Generated on 9/16/2025 at 11:39:33 AM
</div>
</div>
@@ -241,18 +241,6 @@
<g transform="translate(0 45)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 3 L 37.5 3 L 37.5 0 Z "/>
</g>
<g transform="translate(-10 -97.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(44.5 -97.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(-10 94.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(44.5 94.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
@@ -432,18 +420,6 @@
<g transform="translate(0 36)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2.4 L 90 2.4 L 90 0 Z "/>
</g>
<g transform="translate(-10 -81)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.4 L 2.4 2.4 L 2.4 0 Z "/>
</g>
<g transform="translate(97.60000000000001 -81)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.4 L 2.4 2.4 L 2.4 0 Z "/>
</g>
<g transform="translate(-10 78.60000000000001)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.4 L 2.4 2.4 L 2.4 0 Z "/>
</g>
<g transform="translate(97.60000000000001 78.60000000000001)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.4 L 2.4 2.4 L 2.4 0 Z "/>
</g>
</g>
</g>
</g>
@@ -575,18 +551,6 @@
<g transform="translate(0 54)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 3.6 L 90 3.6 L 90 0 Z "/>
</g>
<g transform="translate(-10 -114)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3.6 L 3.6 3.6 L 3.6 0 Z "/>
</g>
<g transform="translate(96.39999999999999 -114)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3.6 L 3.6 3.6 L 3.6 0 Z "/>
</g>
<g transform="translate(-10 110.39999999999999)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3.6 L 3.6 3.6 L 3.6 0 Z "/>
</g>
<g transform="translate(96.39999999999999 110.39999999999999)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3.6 L 3.6 3.6 L 3.6 0 Z "/>
</g>
</g>
</g>
</g>
@@ -670,18 +634,6 @@
<g transform="translate(0 75)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 5 L 62.5 5 L 62.5 0 Z "/>
</g>
<g transform="translate(-10 -152.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 5 L 5 5 L 5 0 Z "/>
</g>
<g transform="translate(67.5 -152.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 5 L 5 5 L 5 0 Z "/>
</g>
<g transform="translate(-10 147.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 5 L 5 5 L 5 0 Z "/>
</g>
<g transform="translate(67.5 147.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 5 L 5 5 L 5 0 Z "/>
</g>
</g>
</g>
</g>
@@ -816,18 +768,6 @@
<g transform="translate(0 30)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2 L 75 2 L 75 0 Z "/>
</g>
<g transform="translate(-10 -70)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2 L 2 2 L 2 0 Z "/>
</g>
<g transform="translate(83 -70)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2 L 2 2 L 2 0 Z "/>
</g>
<g transform="translate(-10 68)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2 L 2 2 L 2 0 Z "/>
</g>
<g transform="translate(83 68)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2 L 2 2 L 2 0 Z "/>
</g>
</g>
</g>
</g>
@@ -1055,17 +995,339 @@
<g transform="translate(0 39)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2.6 L 130 2.6 L 130 0 Z "/>
</g>
<g transform="translate(-10 -86.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.6 L 2.6 2.6 L 2.6 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
</div>
<div class="example-card">
<div class="card-header">
<div class="card-title">Debug: Crop Marks - 89</div>
<div class="card-description">Visible red crop marks showing viewBox boundaries</div>
<div class="config-details">
<strong>Number:</strong> <code>89</code><br>
<strong>bead_shape:</strong> <code>diamond</code><br><strong>color_scheme:</strong> <code>place-value</code><br><strong>show_crop_marks:</strong> <code>true</code><br><strong>crop_margin:</strong> <code>15pt</code><br><strong>base_size:</strong> <code>1.5</code>
</div>
</div>
<div class="card-content">
<svg class="typst-doc" viewBox="0 0 270 210" width="270pt" height="210pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 210 L 270 210 L 270 0 Z "/>
<g>
<g transform="translate(97.5 17.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(16.5 26)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 104.5 L 4.5 104.5 L 4.5 0 Z "/>
</g>
<g transform="translate(137.4 -86.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.6 L 2.6 2.6 L 2.6 0 Z "/>
<g transform="translate(6.150000000000001 26)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(-10 83.89999999999999)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.6 L 2.6 2.6 L 2.6 0 Z "/>
<g transform="translate(6.150000000000001 49)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(137.4 83.89999999999999)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.6 L 2.6 2.6 L 2.6 0 Z "/>
<g transform="translate(6.150000000000001 67.75)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(6.150000000000001 86.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(6.150000000000001 112.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(54 26)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 97.25 L 4.5 97.25 L 4.5 0 Z "/>
</g>
<g transform="translate(43.65 26)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.65 49)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.65 67.75)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.65 86.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.65 105.25)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(0 45)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 3 L 75 3 L 75 0 Z "/>
</g>
<g transform="translate(-8.849999999999998 45)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(80.85000000000001 45)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(17.25 4)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(54.75 136)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
</div>
<div class="example-card">
<div class="card-header">
<div class="card-title">Debug: Crop Marks - 456</div>
<div class="card-description">Three-digit number with visible crop boundaries</div>
<div class="config-details">
<strong>Number:</strong> <code>456</code><br>
<strong>bead_shape:</strong> <code>circle</code><br><strong>color_scheme:</strong> <code>heaven-earth</code><br><strong>show_crop_marks:</strong> <code>true</code><br><strong>crop_margin:</strong> <code>12pt</code><br><strong>base_size:</strong> <code>1.2</code>
</div>
</div>
<div class="card-content">
<svg class="typst-doc" viewBox="0 0 312 174" width="312pt" height="174pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 174 L 312 174 L 312 0 Z "/>
<g>
<g transform="translate(111 16)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(13.200000000000001 13.599999999999998)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 85.2 L 3.6 85.2 L 3.6 0 Z "/>
</g>
<g transform="translate(7.8 13.599999999999998)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.8 39.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.8 54.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.8 69.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.8 84.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.199999999999996 20.599999999999998)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 85.2 L 3.6 85.2 L 3.6 0 Z "/>
</g>
<g transform="translate(37.800000000000004 20.599999999999998)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(37.800000000000004 46.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(37.800000000000004 61.400000000000006)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(37.800000000000004 76.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(37.800000000000004 91.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(73.2 20.599999999999998)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 85.6 L 3.6 85.6 L 3.6 0 Z "/>
</g>
<g transform="translate(67.8 20.599999999999998)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.8 39.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.8 61.800000000000004)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.8 76.8)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.8 91.8)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(0 36)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2.4 L 90 2.4 L 90 0 Z "/>
</g>
<g transform="translate(-4.2 35.699999999999996)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(91.2 35.699999999999996)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(13.5 1.6000000000000003)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(73.5 108.39999999999999)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>

View File

@@ -1,511 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🧮 Soroban Templates Gallery</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #333;
background: #f5f5f5;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 40px;
padding: 40px 20px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
color: #2c3e50;
}
.header p {
font-size: 1.1rem;
color: #666;
margin-bottom: 20px;
}
.controls {
margin-bottom: 20px;
}
.controls button {
background: #3498db;
color: white;
border: none;
padding: 12px 24px;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
margin-right: 10px;
transition: background 0.3s;
}
.controls button:hover {
background: #2980b9;
}
.controls button:disabled {
background: #bdc3c7;
cursor: not-allowed;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 30px;
}
.example-card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
overflow: hidden;
transition: transform 0.3s, box-shadow 0.3s;
}
.example-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
}
.card-header {
padding: 20px;
border-bottom: 1px solid #eee;
}
.card-title {
font-size: 1.3rem;
font-weight: 600;
margin-bottom: 8px;
color: #2c3e50;
}
.card-description {
color: #666;
font-size: 0.95rem;
margin-bottom: 15px;
}
.config-details {
background: #f8f9fa;
padding: 12px;
border-radius: 6px;
font-size: 0.85rem;
}
.config-details strong {
color: #2c3e50;
}
.config-details code {
background: #e9ecef;
padding: 2px 4px;
border-radius: 3px;
font-family: 'Monaco', 'Consolas', monospace;
color: #d63384;
}
.card-content {
padding: 20px;
text-align: center;
min-height: 300px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
}
.card-actions {
padding: 15px 20px;
border-top: 1px solid #eee;
text-align: right;
}
.card-actions button {
background: #27ae60;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 0.9rem;
transition: background 0.3s;
}
.card-actions button:hover {
background: #219a52;
}
.card-actions button:disabled {
background: #bdc3c7;
cursor: not-allowed;
}
.loading {
display: flex;
flex-direction: column;
align-items: center;
color: #666;
}
.loading .spinner {
font-size: 2rem;
margin-bottom: 10px;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.error {
color: #e74c3c;
text-align: center;
}
.error .icon {
font-size: 2rem;
margin-bottom: 10px;
}
.placeholder {
color: #95a5a6;
text-align: center;
}
.placeholder .icon {
font-size: 3rem;
margin-bottom: 10px;
}
.status-bar {
background: white;
padding: 15px 20px;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
display: flex;
justify-content: space-between;
align-items: center;
}
.status-info {
color: #666;
font-size: 0.9rem;
}
.generated-svg {
max-width: 100%;
height: auto;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🧮 Soroban Templates Gallery</h1>
<p>Interactive showcase of soroban template renderings with different configurations</p>
<div class="controls">
<button onclick="generateAll()" id="generateAllBtn">🎨 Load All Examples</button>
<button onclick="clearAll()">🗑️ Clear All</button>
<button onclick="exportConfig()">📋 Export Config</button>
</div>
</div>
<div class="status-bar">
<div class="status-info">
<span id="statusText">Ready to generate examples</span>
</div>
<div class="status-info">
<span id="generatedCount">0</span> / <span id="totalCount">0</span> generated
</div>
</div>
<div class="gallery" id="gallery">
<!-- Examples will be dynamically generated here -->
</div>
</div>
<script>
const examples = [
{
id: 'basic-5',
title: 'Basic Number 5',
description: 'Simple representation of 5 with default settings',
number: 5,
config: {
bead_shape: 'diamond',
color_scheme: 'monochrome',
base_size: 1.5
}
},
{
id: 'colorful-123',
title: 'Colorful 123',
description: 'Number 123 with place-value colors and diamond beads',
number: 123,
config: {
bead_shape: 'diamond',
color_scheme: 'place-value',
base_size: 1.2
}
},
{
id: 'circles-42',
title: 'Circle Beads - 42',
description: 'Number 42 with circular beads and heaven-earth colors',
number: 42,
config: {
bead_shape: 'circle',
color_scheme: 'heaven-earth',
base_size: 1.8
}
},
{
id: 'large-7',
title: 'Large Scale - 7',
description: 'Single digit with maximum scale for detail work',
number: 7,
config: {
bead_shape: 'diamond',
color_scheme: 'place-value',
base_size: 2.5
}
},
{
id: 'compact-999',
title: 'Compact 999',
description: 'Large number with hidden inactive beads for clean look',
number: 999,
config: {
bead_shape: 'square',
color_scheme: 'alternating',
hide_inactive: true,
base_size: 1.0
}
},
{
id: 'educational-1234',
title: 'Educational 1234',
description: 'Four-digit number showing empty columns for learning',
number: 1234,
config: {
bead_shape: 'circle',
color_scheme: 'place-value',
show_empty: true,
base_size: 1.3
}
}
];
let generatedCount = 0;
function initGallery() {
const gallery = document.getElementById('gallery');
document.getElementById('totalCount').textContent = examples.length;
examples.forEach(example => {
const card = createExampleCard(example);
gallery.appendChild(card);
});
updateStatus('Gallery initialized with ' + examples.length + ' examples');
}
function createExampleCard(example) {
const card = document.createElement('div');
card.className = 'example-card';
card.id = `card-${example.id}`;
const configText = Object.entries(example.config)
.map(([key, value]) => `<strong>${key}:</strong> <code>${value}</code>`)
.join('<br>');
card.innerHTML = `
<div class="card-header">
<div class="card-title">${example.title}</div>
<div class="card-description">${example.description}</div>
<div class="config-details">
<strong>Number:</strong> <code>${example.number}</code><br>
${configText}
</div>
</div>
<div class="card-content" id="content-${example.id}">
<div class="placeholder">
<div class="icon">🧮</div>
<div>Click to load SVG</div>
</div>
</div>
<div class="card-actions">
<button onclick="generateExample('${example.id}')" id="btn-${example.id}">
🎨 Load SVG
</button>
</div>
`;
return card;
}
async function generateExample(exampleId) {
const example = examples.find(e => e.id === exampleId);
if (!example) return;
const contentEl = document.getElementById(`content-${exampleId}`);
const btnEl = document.getElementById(`btn-${exampleId}`);
// Show loading state
contentEl.innerHTML = `
<div class="loading">
<div class="spinner">🔄</div>
<div>Loading soroban...</div>
</div>
`;
btnEl.disabled = true;
btnEl.textContent = '⏳ Loading...';
updateStatus(`Loading ${example.title}...`);
try {
// Load the actual generated SVG file
const svg = await generateTypstSvg(example);
contentEl.innerHTML = `<div class="generated-svg">${svg}</div>`;
btnEl.disabled = false;
btnEl.textContent = '✅ Loaded';
generatedCount++;
document.getElementById('generatedCount').textContent = generatedCount;
updateStatus(`Loaded ${example.title} successfully`);
} catch (error) {
contentEl.innerHTML = `
<div class="error">
<div class="icon">❌</div>
<div>Loading failed</div>
<div style="font-size: 0.8rem; margin-top: 5px;">${error.message}</div>
</div>
`;
btnEl.disabled = false;
btnEl.textContent = '🔄 Retry';
updateStatus(`Failed to load ${example.title}: ${error.message}`);
}
}
async function generateTypstSvg(example) {
// For local file access, we'll show a clickable link to the SVG
// This avoids CORS issues with fetch() on local files
const svgPath = `gallery/${example.id}.svg`;
return `
<div style="text-align: center; padding: 20px;">
<div style="border: 2px dashed #ddd; border-radius: 8px; padding: 40px; margin-bottom: 15px;">
<div style="font-size: 2rem; margin-bottom: 10px;">🧮</div>
<div style="font-weight: 600; margin-bottom: 10px;">Soroban for ${example.number}</div>
<div style="color: #666; font-size: 0.9rem; margin-bottom: 15px;">
${example.config.bead_shape} beads, ${example.config.color_scheme} colors
</div>
<a href="${svgPath}"
target="_blank"
style="display: inline-block; background: #3498db; color: white; padding: 10px 20px;
border-radius: 5px; text-decoration: none; font-weight: 500;">
📖 Open SVG File
</a>
</div>
<div style="font-size: 0.8rem; color: #999;">
File: ${svgPath}
</div>
</div>
`;
}
async function generateAll() {
const btn = document.getElementById('generateAllBtn');
btn.disabled = true;
btn.textContent = '⏳ Loading All...';
generatedCount = 0;
document.getElementById('generatedCount').textContent = generatedCount;
for (const example of examples) {
await generateExample(example.id);
// Small delay between loads for visual feedback
await new Promise(resolve => setTimeout(resolve, 100));
}
btn.disabled = false;
btn.textContent = '🎨 Load All Examples';
updateStatus('All examples loaded successfully!');
}
function clearAll() {
examples.forEach(example => {
const contentEl = document.getElementById(`content-${example.id}`);
const btnEl = document.getElementById(`btn-${example.id}`);
contentEl.innerHTML = `
<div class="placeholder">
<div class="icon">🧮</div>
<div>Click to load SVG</div>
</div>
`;
btnEl.disabled = false;
btnEl.textContent = '🎨 Generate';
});
generatedCount = 0;
document.getElementById('generatedCount').textContent = generatedCount;
updateStatus('All examples cleared');
}
function exportConfig() {
const config = examples.map(e => ({
title: e.title,
number: e.number,
config: e.config
}));
const blob = new Blob([JSON.stringify(config, null, 2)],
{ type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'soroban-gallery-config.json';
a.click();
URL.revokeObjectURL(url);
updateStatus('Configuration exported to JSON file');
}
function updateStatus(message) {
document.getElementById('statusText').textContent = message;
}
// Initialize the gallery when the page loads
document.addEventListener('DOMContentLoaded', initGallery);
</script>
</body>
</html>

View File

@@ -58,18 +58,6 @@
<g transform="translate(0 45)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 3 L 37.5 3 L 37.5 0 Z "/>
</g>
<g transform="translate(-10 -97.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(44.5 -97.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(-10 94.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(44.5 94.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -106,18 +106,6 @@
<g transform="translate(0 54)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 3.6 L 90 3.6 L 90 0 Z "/>
</g>
<g transform="translate(-10 -114)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3.6 L 3.6 3.6 L 3.6 0 Z "/>
</g>
<g transform="translate(96.39999999999999 -114)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3.6 L 3.6 3.6 L 3.6 0 Z "/>
</g>
<g transform="translate(-10 110.39999999999999)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3.6 L 3.6 3.6 L 3.6 0 Z "/>
</g>
<g transform="translate(96.39999999999999 110.39999999999999)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3.6 L 3.6 3.6 L 3.6 0 Z "/>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -154,18 +154,6 @@
<g transform="translate(0 36)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2.4 L 90 2.4 L 90 0 Z "/>
</g>
<g transform="translate(-10 -81)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.4 L 2.4 2.4 L 2.4 0 Z "/>
</g>
<g transform="translate(97.60000000000001 -81)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.4 L 2.4 2.4 L 2.4 0 Z "/>
</g>
<g transform="translate(-10 78.60000000000001)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.4 L 2.4 2.4 L 2.4 0 Z "/>
</g>
<g transform="translate(97.60000000000001 78.60000000000001)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.4 L 2.4 2.4 L 2.4 0 Z "/>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -109,18 +109,6 @@
<g transform="translate(0 30)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2 L 75 2 L 75 0 Z "/>
</g>
<g transform="translate(-10 -70)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2 L 2 2 L 2 0 Z "/>
</g>
<g transform="translate(83 -70)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2 L 2 2 L 2 0 Z "/>
</g>
<g transform="translate(-10 68)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2 L 2 2 L 2 0 Z "/>
</g>
<g transform="translate(83 68)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2 L 2 2 L 2 0 Z "/>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,68 @@
<svg class="typst-doc" viewBox="0 0 366 198" width="366pt" height="198pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 198 L 366 198 L 366 0 Z "/>
<g>
<g transform="translate(130.5 17)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(15.4 24.199999999999996)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 19.2 L 4.2 19.2 L 4.2 0 Z "/>
</g>
<g transform="translate(5.740000000000002 24.199999999999996)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 11.76 0 L 23.52 8.4 L 11.76 16.8 L 0 8.4 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(50.4 24.199999999999996)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 19.2 L 4.2 19.2 L 4.2 0 Z "/>
</g>
<g transform="translate(40.74 24.199999999999996)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 11.76 0 L 23.52 8.4 L 11.76 16.8 L 0 8.4 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(85.39999999999999 24.199999999999996)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 19.2 L 4.2 19.2 L 4.2 0 Z "/>
</g>
<g transform="translate(75.74 24.199999999999996)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 11.76 0 L 23.52 8.4 L 11.76 16.8 L 0 8.4 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(0 42)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2.8 L 105 2.8 L 105 0 Z "/>
</g>
<g transform="translate(-9.259999999999998 41.9)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(111.26 41.9)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(16 2.2000000000000006)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(86 127.79999999999998)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,80 @@
<svg class="typst-doc" viewBox="0 0 240 280" width="240pt" height="280pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 280 L 240 280 L 240 0 Z "/>
<g>
<g transform="translate(95 25)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(22 28)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 143 L 6 143 L 6 0 Z "/>
</g>
<g transform="translate(13 28)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 12 C 0 5.378592 5.378592 0 12 0 C 18.621408 0 24 5.378592 24 12 C 24 18.621408 18.621408 24 12 24 C 5.378592 24 0 18.621408 0 12 "/>
</g>
</g>
</g>
</g>
<g transform="translate(13 72)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 12 C 0 5.378592 5.378592 0 12 0 C 18.621408 0 24 5.378592 24 12 C 24 18.621408 18.621408 24 12 24 C 5.378592 24 0 18.621408 0 12 "/>
</g>
</g>
</g>
</g>
<g transform="translate(13 97)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 12 C 0 5.378592 5.378592 0 12 0 C 18.621408 0 24 5.378592 24 12 C 24 18.621408 18.621408 24 12 24 C 5.378592 24 0 18.621408 0 12 "/>
</g>
</g>
</g>
</g>
<g transform="translate(13 122)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 12 C 0 5.378592 5.378592 0 12 0 C 18.621408 0 24 5.378592 24 12 C 24 18.621408 18.621408 24 12 24 C 5.378592 24 0 18.621408 0 12 "/>
</g>
</g>
</g>
</g>
<g transform="translate(13 147)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 12 C 0 5.378592 5.378592 0 12 0 C 18.621408 0 24 5.378592 24 12 C 24 18.621408 18.621408 24 12 24 C 5.378592 24 0 18.621408 0 12 "/>
</g>
</g>
</g>
</g>
<g transform="translate(0 60)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 4 L 50 4 L 50 0 Z "/>
</g>
<g transform="translate(-7 60.5)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(54 60.5)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(23.5 8)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(23.5 182)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,176 @@
<svg class="typst-doc" viewBox="0 0 274 160" width="274pt" height="160pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 160 L 274 160 L 274 0 Z "/>
<g>
<g transform="translate(95.75 14.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(12.100000000000001 11.8)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 86.3 L 3.3 86.3 L 3.3 0 Z "/>
</g>
<g transform="translate(7.150000000000001 11.8)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.150000000000001 36.199999999999996)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.150000000000001 49.949999999999996)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.150000000000001 63.69999999999999)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.150000000000001 84.89999999999999)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(39.60000000000001 11.8)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 86.3 L 3.3 86.3 L 3.3 0 Z "/>
</g>
<g transform="translate(34.650000000000006 11.8)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(34.650000000000006 36.199999999999996)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(34.650000000000006 49.949999999999996)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(34.650000000000006 71.14999999999999)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(34.650000000000006 84.89999999999999)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.10000000000002 11.8)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 86.3 L 3.3 86.3 L 3.3 0 Z "/>
</g>
<g transform="translate(62.15000000000001 11.8)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(62.15000000000001 36.199999999999996)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(62.15000000000001 57.39999999999999)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(62.15000000000001 71.14999999999999)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(62.15000000000001 84.89999999999999)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 6.6 C 0 2.9582255 2.9582255 0 6.6 0 C 10.241775 0 13.2 2.9582255 13.2 6.6 C 13.2 10.241775 10.241775 13.2 6.6 13.2 C 2.9582255 13.2 0 10.241775 0 6.6 "/>
</g>
</g>
</g>
</g>
<g transform="translate(0 33)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2.2 L 82.5 2.2 L 82.5 0 Z "/>
</g>
<g transform="translate(2.1500000000000012 32.6)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(77.35000000000002 32.6)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(12.250000000000002 6.799999999999999)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(67.25000000000001 93.2)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,164 @@
<svg class="typst-doc" viewBox="0 0 276 170" width="276pt" height="170pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 170 L 276 170 L 276 0 Z "/>
<g>
<g transform="translate(98 36)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(8.799999999999999 13.400000000000002)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 52.8 L 2.4 52.8 L 2.4 0 Z "/>
</g>
<g transform="translate(5.2 13.400000000000002)">
<path class="typst-shape" fill="#6a994e" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(5.2 13.400000000000002)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(5.2 26.599999999999998)">
<path class="typst-shape" fill="#6a994e" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(5.2 26.599999999999998)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(5.2 36.599999999999994)">
<path class="typst-shape" fill="#6a994e" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(5.2 36.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(5.2 46.599999999999994)">
<path class="typst-shape" fill="#6a994e" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(5.2 46.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(5.2 56.599999999999994)">
<path class="typst-shape" fill="#6a994e" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(5.2 56.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(28.8 13.400000000000002)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 52.8 L 2.4 52.8 L 2.4 0 Z "/>
</g>
<g transform="translate(25.2 13.400000000000002)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(25.2 13.400000000000002)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(25.2 26.599999999999998)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(25.2 26.599999999999998)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(25.2 36.599999999999994)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(25.2 36.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(25.2 46.599999999999994)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(25.2 46.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(25.2 56.599999999999994)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(25.2 56.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(48.800000000000004 13.400000000000002)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 52.8 L 2.4 52.8 L 2.4 0 Z "/>
</g>
<g transform="translate(45.199999999999996 13.400000000000002)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(45.199999999999996 13.400000000000002)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(45.199999999999996 26.599999999999998)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(45.199999999999996 26.599999999999998)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(45.199999999999996 36.599999999999994)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(45.199999999999996 36.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(45.199999999999996 46.599999999999994)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(45.199999999999996 46.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(45.199999999999996 56.599999999999994)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(45.199999999999996 56.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(68.8 13.400000000000002)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 52.8 L 2.4 52.8 L 2.4 0 Z "/>
</g>
<g transform="translate(65.2 13.400000000000002)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(65.2 13.400000000000002)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(65.2 26.599999999999998)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(65.2 26.599999999999998)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(65.2 36.599999999999994)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(65.2 36.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(65.2 46.599999999999994)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(65.2 46.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(65.2 56.599999999999994)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" d="M 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 Z "/>
</g>
<g transform="translate(65.2 56.599999999999994)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0.75 0 L 8.85 0 C 9.264214 0 9.6 0.33578643 9.6 0.75 L 9.6 8.85 C 9.6 9.264214 9.264214 9.6 8.85 9.6 L 0.75 9.6 C 0.33578643 9.6 0 9.264214 0 8.85 L 0 0.75 C 0 0.33578643 0.33578643 0 0.75 0 "/>
</g>
<g transform="translate(0 24)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 1.6 L 80 1.6 L 80 0 Z "/>
</g>
<g transform="translate(-4.8 23.3)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(81.8 23.3)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(8.5 -3.6000000000000005)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(68.5 73.60000000000001)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,80 @@
<svg class="typst-doc" viewBox="0 0 216 166" width="216pt" height="166pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 166 L 216 166 L 216 0 Z "/>
<g>
<g transform="translate(95.5 23)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(11 10)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 80 L 3 80 L 3 0 Z "/>
</g>
<g transform="translate(4.1000000000000005 10)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 8.4 0 L 16.8 6 L 8.4 12 L 0 6 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(4.1000000000000005 33)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 8.4 0 L 16.8 6 L 8.4 12 L 0 6 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(4.1000000000000005 53)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 8.4 0 L 16.8 6 L 8.4 12 L 0 6 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(4.1000000000000005 65.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 8.4 0 L 16.8 6 L 8.4 12 L 0 6 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(4.1000000000000005 78)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 8.4 0 L 16.8 6 L 8.4 12 L 0 6 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(0 30)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2 L 25 2 L 25 0 Z "/>
</g>
<g transform="translate(-3.8999999999999995 29.5)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(25.900000000000002 29.5)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(11 2)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(11 88)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,176 @@
<svg class="typst-doc" viewBox="0 0 312 174" width="312pt" height="174pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 174 L 312 174 L 312 0 Z "/>
<g>
<g transform="translate(111 16)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(13.200000000000001 13.599999999999998)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 85.2 L 3.6 85.2 L 3.6 0 Z "/>
</g>
<g transform="translate(7.8 13.599999999999998)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.8 39.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.8 54.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.8 69.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(7.8 84.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.199999999999996 20.599999999999998)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 85.2 L 3.6 85.2 L 3.6 0 Z "/>
</g>
<g transform="translate(37.800000000000004 20.599999999999998)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(37.800000000000004 46.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(37.800000000000004 61.400000000000006)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(37.800000000000004 76.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(37.800000000000004 91.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(73.2 20.599999999999998)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 85.6 L 3.6 85.6 L 3.6 0 Z "/>
</g>
<g transform="translate(67.8 20.599999999999998)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#f18f01" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.8 39.4)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.8 61.800000000000004)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.8 76.8)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(67.8 91.8)">
<g class="typst-group">
<g>
<g transform="translate(-0 -0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 7.2 C 0 3.2271552 3.2271552 0 7.2 0 C 11.172845 0 14.4 3.2271552 14.4 7.2 C 14.4 11.172845 11.172845 14.4 7.2 14.4 C 3.2271552 14.4 0 11.172845 0 7.2 "/>
</g>
</g>
</g>
</g>
<g transform="translate(0 36)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2.4 L 90 2.4 L 90 0 Z "/>
</g>
<g transform="translate(-4.2 35.699999999999996)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(91.2 35.699999999999996)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(13.5 1.6000000000000003)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(73.5 108.39999999999999)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,128 @@
<svg class="typst-doc" viewBox="0 0 270 210" width="270pt" height="210pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path class="typst-shape" fill="#ffffff" fill-rule="nonzero" d="M 0 0 L 0 210 L 270 210 L 270 0 Z "/>
<g>
<g transform="translate(97.5 17.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<g class="typst-group">
<g>
<g transform="translate(16.5 26)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 104.5 L 4.5 104.5 L 4.5 0 Z "/>
</g>
<g transform="translate(6.150000000000001 26)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(6.150000000000001 49)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(6.150000000000001 67.75)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(6.150000000000001 86.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#a23b72" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(6.150000000000001 112.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#e6e6e6" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(54 26)">
<path class="typst-shape" fill="#eeeeee" fill-rule="nonzero" d="M 0 0 L 0 97.25 L 4.5 97.25 L 4.5 0 Z "/>
</g>
<g transform="translate(43.65 26)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.65 49)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.65 67.75)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.65 86.5)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(43.65 105.25)">
<g class="typst-group">
<g>
<g transform="translate(0 0)">
<path class="typst-shape" fill="#2e86ab" fill-rule="nonzero" stroke="#000000" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 12.6 0 L 25.2 9 L 12.6 18 L 0 9 Z "/>
</g>
</g>
</g>
</g>
<g transform="translate(0 45)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 3 L 75 3 L 75 0 Z "/>
</g>
<g transform="translate(-8.849999999999998 45)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(80.85000000000001 45)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(17.25 4)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
<g transform="translate(54.75 136)">
<path class="typst-shape" fill="#ff4136" fill-rule="nonzero" stroke="#ff4136" stroke-width="0.5" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 3 L 3 3 L 3 0 Z "/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -202,18 +202,6 @@
<g transform="translate(0 39)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 2.6 L 130 2.6 L 130 0 Z "/>
</g>
<g transform="translate(-10 -86.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.6 L 2.6 2.6 L 2.6 0 Z "/>
</g>
<g transform="translate(137.4 -86.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.6 L 2.6 2.6 L 2.6 0 Z "/>
</g>
<g transform="translate(-10 83.89999999999999)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.6 L 2.6 2.6 L 2.6 0 Z "/>
</g>
<g transform="translate(137.4 83.89999999999999)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 2.6 L 2.6 2.6 L 2.6 0 Z "/>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -58,18 +58,6 @@
<g transform="translate(0 75)">
<path class="typst-shape" fill="#000000" fill-rule="nonzero" d="M 0 0 L 0 5 L 62.5 5 L 62.5 0 Z "/>
</g>
<g transform="translate(-10 -152.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 5 L 5 5 L 5 0 Z "/>
</g>
<g transform="translate(67.5 -152.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 5 L 5 5 L 5 0 Z "/>
</g>
<g transform="translate(-10 147.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 5 L 5 5 L 5 0 Z "/>
</g>
<g transform="translate(67.5 147.5)">
<path class="typst-shape" fill="none" stroke="#000000" stroke-width="0" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 5 L 5 5 L 5 0 Z "/>
</g>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -101,6 +101,72 @@ const examples = [
crop_margin: '12pt',
base_size: 1.2
}
},
{
id: 'crop-single-1',
title: 'Crop Marks: Single Digit',
description: 'Single digit with crop marks for tight cropping',
number: 1,
config: {
bead_shape: 'diamond',
color_scheme: 'monochrome',
show_crop_marks: true,
crop_margin: '8pt',
base_size: 1.0
}
},
{
id: 'crop-quad-9999',
title: 'Crop Marks: Four 9s',
description: 'Maximum digit density with crop boundaries',
number: 9999,
config: {
bead_shape: 'square',
color_scheme: 'place-value',
show_crop_marks: true,
crop_margin: '10pt',
base_size: 0.8
}
},
{
id: 'crop-large-scale-0',
title: 'Crop Marks: Large Zero',
description: 'Zero with large scale and crop marks',
number: 0,
config: {
bead_shape: 'circle',
color_scheme: 'alternating',
show_crop_marks: true,
crop_margin: '20pt',
base_size: 2.0
}
},
{
id: 'crop-hidden-inactive-555',
title: 'Crop Marks: Hidden Inactive',
description: 'Triple 5s with hidden inactive beads and crop marks',
number: 555,
config: {
bead_shape: 'diamond',
color_scheme: 'heaven-earth',
hide_inactive: true,
show_crop_marks: true,
crop_margin: '15pt',
base_size: 1.4
}
},
{
id: 'crop-mixed-geometry-321',
title: 'Crop Marks: Mixed Geometry',
description: 'Different bead count pattern with tight margins',
number: 321,
config: {
bead_shape: 'circle',
color_scheme: 'place-value',
show_crop_marks: true,
crop_margin: '5pt',
base_size: 1.1
}
}
];
@@ -109,27 +175,38 @@ function createTypstFile(example) {
// Calculate canvas size based on number length and scale
const digits = String(number).length;
const width = Math.max(200, digits * 80 * (config.base_size || 1.0));
const height = Math.max(150, 120 * (config.base_size || 1.0));
let width = Math.max(200, digits * 80 * (config.base_size || 1.0));
let height = Math.max(150, 120 * (config.base_size || 1.0));
// Add extra space for crop marks if enabled
if (config.show_crop_marks && config.crop_margin) {
const cropMarginPt = parseFloat(config.crop_margin.replace('pt', ''));
width += cropMarginPt * 2; // Left and right margins
height += cropMarginPt * 2; // Top and bottom margins
}
const content = `#import "../flashcards.typ": draw-soroban
#set page(width: ${width}pt, height: ${height}pt, margin: 12pt, fill: white)
#let soroban-content = draw-soroban(
${number},
columns: ${config.columns || 'auto'},
bead-shape: "${config.bead_shape || 'diamond'}",
color-scheme: "${config.color_scheme || 'monochrome'}",
${config.color_palette ? `color-palette: "${config.color_palette}",` : ''}
${config.show_empty ? 'show-empty: true,' : ''}
${config.hide_inactive ? 'hide-inactive: true,' : ''}
base-size: ${config.base_size || 1.0},
${config.show_crop_marks ? 'show-crop-marks: true,' : ''}
${config.crop_margin ? `crop-margin: ${config.crop_margin},` : ''}
)
#align(center + horizon)[
#draw-soroban(
${number},
columns: ${config.columns || 'auto'},
bead-shape: "${config.bead_shape || 'diamond'}",
color-scheme: "${config.color_scheme || 'monochrome'}",
${config.color_palette ? `color-palette: "${config.color_palette}",` : ''}
${config.show_empty ? 'show-empty: true,' : ''}
${config.hide_inactive ? 'hide-inactive: true,' : ''}
${config.show_crop_marks ? 'show-crop-marks: true,' : ''}
${config.crop_margin ? `crop-margin: ${config.crop_margin},` : ''}
base-size: ${config.base_size || 1.0}
)
]`;
#soroban-content
]
`;
return content;
}

View File

@@ -160,11 +160,39 @@
let crop-top = -crop-margin
let crop-bottom = height + crop-margin
// Top-left crop mark
// Top crop mark (centered on top edge)
place(
dx: width / 2 - crop-mark-size / 2,
dy: crop-top,
link("crop-mark://top",
rect(
width: crop-mark-size,
height: crop-mark-size,
fill: crop-mark-color,
stroke: crop-mark-stroke + crop-mark-color
)
)
)
// Bottom crop mark (centered on bottom edge)
place(
dx: width / 2 - crop-mark-size / 2,
dy: crop-bottom - crop-mark-size,
link("crop-mark://bottom",
rect(
width: crop-mark-size,
height: crop-mark-size,
fill: crop-mark-color,
stroke: crop-mark-stroke + crop-mark-color
)
)
)
// Left crop mark (centered on left edge)
place(
dx: crop-left,
dy: crop-top,
link("crop-mark://top-left",
dy: height / 2 - crop-mark-size / 2,
link("crop-mark://left",
rect(
width: crop-mark-size,
height: crop-mark-size,
@@ -174,39 +202,11 @@
)
)
// Top-right crop mark
// Right crop mark (centered on right edge)
place(
dx: crop-right - crop-mark-size,
dy: crop-top,
link("crop-mark://top-right",
rect(
width: crop-mark-size,
height: crop-mark-size,
fill: crop-mark-color,
stroke: crop-mark-stroke + crop-mark-color
)
)
)
// Bottom-left crop mark
place(
dx: crop-left,
dy: crop-bottom - crop-mark-size,
link("crop-mark://bottom-left",
rect(
width: crop-mark-size,
height: crop-mark-size,
fill: crop-mark-color,
stroke: crop-mark-stroke + crop-mark-color
)
)
)
// Bottom-right crop mark
place(
dx: crop-right - crop-mark-size,
dy: crop-bottom - crop-mark-size,
link("crop-mark://bottom-right",
dy: height / 2 - crop-mark-size / 2,
link("crop-mark://right",
rect(
width: crop-mark-size,
height: crop-mark-size,

View File

@@ -0,0 +1,303 @@
#!/usr/bin/env node
// Unit test for crop mark positioning to prevent regressions
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
// Test cases with expected crop mark properties
const testCases = [
{
id: 'single-digit',
number: 7,
config: {
bead_shape: 'diamond',
color_scheme: 'monochrome',
show_crop_marks: true,
crop_margin: '10pt',
base_size: 1.0
},
expectedProperties: {
cropMarkCount: 4,
leftMarkShouldBeNegative: true,
rightMarkShouldBePositive: true,
topMarkShouldBeSmall: true,
bottomMarkShouldBeLarge: true,
marksWithinSorobanBounds: true
}
},
{
id: 'multi-digit',
number: 123,
config: {
bead_shape: 'circle',
color_scheme: 'place-value',
show_crop_marks: true,
crop_margin: '15pt',
base_size: 1.2
},
expectedProperties: {
cropMarkCount: 4,
leftMarkShouldBeNegative: true,
rightMarkShouldBePositive: true,
topMarkShouldBeSmall: true,
bottomMarkShouldBeLarge: true,
marksWithinSorobanBounds: true
}
},
{
id: 'large-scale',
number: 5,
config: {
bead_shape: 'square',
color_scheme: 'heaven-earth',
show_crop_marks: true,
crop_margin: '20pt',
base_size: 2.0
},
expectedProperties: {
cropMarkCount: 4,
leftMarkShouldBeNegative: true,
rightMarkShouldBePositive: true,
topMarkShouldBeSmall: true,
bottomMarkShouldBeLarge: true,
marksWithinSorobanBounds: true
}
}
];
function parseSVGCropMarks(svgContent) {
const cropMarks = [];
const translateRegex = /transform="translate\(([^)]+)\)"/g;
let match;
while ((match = translateRegex.exec(svgContent)) !== null) {
const coords = match[1].trim().split(/\s+/);
const x = parseFloat(coords[0]);
const y = parseFloat(coords[1]);
// Get the element context to determine if it's a crop mark
const elementStart = svgContent.lastIndexOf('<g', match.index);
const elementEnd = svgContent.indexOf('</g>', match.index);
const elementContent = svgContent.substring(elementStart, elementEnd);
// Check if this is a crop mark (red fill)
const isCropMark = elementContent.includes('fill="#ff4136"');
if (isCropMark) {
// Extract dimensions from path elements
const pathMatch = elementContent.match(/d="M\s+0\s+0\s+L\s+0\s+(\d+)\s+L\s+(\d+)\s+\d+\s+L\s+\d+\s+0\s+Z\s*"/);
if (pathMatch) {
const width = parseFloat(pathMatch[2]);
const height = parseFloat(pathMatch[1]);
cropMarks.push({
x: x,
y: y,
width: width,
height: height,
right: x + width,
bottom: y + height
});
}
}
}
return cropMarks;
}
function generateTestSVG(testCase) {
const { number, config } = testCase;
// Create minimal Typst file for testing
const typstContent = `#import "flashcards.typ": draw-soroban
#set page(width: 200pt, height: 200pt, margin: 12pt, fill: white)
#let soroban-content = draw-soroban(
${number},
bead-shape: "${config.bead_shape}",
color-scheme: "${config.color_scheme}",
base-size: ${config.base_size},
show-crop-marks: ${config.show_crop_marks},
crop-margin: ${config.crop_margin}
)
#align(center + horizon)[
#soroban-content
]`;
const typstFile = `test-${testCase.id}.typ`;
const svgFile = `test-${testCase.id}.svg`;
try {
// Write and compile
fs.writeFileSync(typstFile, typstContent);
execSync(`typst compile --root . --format svg "${typstFile}" "${svgFile}"`, { stdio: 'pipe' });
// Read SVG content
const svgContent = fs.readFileSync(svgFile, 'utf8');
// Clean up
fs.unlinkSync(typstFile);
fs.unlinkSync(svgFile);
return svgContent;
} catch (error) {
// Clean up on error
if (fs.existsSync(typstFile)) fs.unlinkSync(typstFile);
if (fs.existsSync(svgFile)) fs.unlinkSync(svgFile);
throw error;
}
}
function validateCropMarks(cropMarks, expected, testId) {
const results = [];
// Test 1: Correct number of crop marks
const countTest = {
name: `${testId}: Crop mark count`,
expected: expected.cropMarkCount,
actual: cropMarks.length,
pass: cropMarks.length === expected.cropMarkCount
};
results.push(countTest);
if (cropMarks.length === 4) {
// Sort crop marks by position for consistent testing
const leftMark = cropMarks.reduce((min, mark) => mark.x < min.x ? mark : min);
const rightMark = cropMarks.reduce((max, mark) => mark.right > max.right ? mark : max);
const topMark = cropMarks.reduce((min, mark) => mark.y < min.y ? mark : min);
const bottomMark = cropMarks.reduce((max, mark) => mark.bottom > max.bottom ? mark : max);
// Test 2: Left mark should be negative (extends beyond soroban bounds)
if (expected.leftMarkShouldBeNegative) {
results.push({
name: `${testId}: Left mark extends beyond left bound`,
expected: '< 0',
actual: leftMark.x,
pass: leftMark.x < 0
});
}
// Test 3: Right mark should be positive and reasonable
if (expected.rightMarkShouldBePositive) {
results.push({
name: `${testId}: Right mark extends beyond soroban`,
expected: '> 0',
actual: rightMark.right,
pass: rightMark.right > 0
});
}
// Test 4: Top mark should be at small Y value
if (expected.topMarkShouldBeSmall) {
results.push({
name: `${testId}: Top mark positioned near top`,
expected: '< 50',
actual: topMark.y,
pass: topMark.y < 50
});
}
// Test 5: Bottom mark should be at larger Y value than top
if (expected.bottomMarkShouldBeLarge) {
results.push({
name: `${testId}: Bottom mark below top mark`,
expected: `> ${topMark.y}`,
actual: bottomMark.bottom,
pass: bottomMark.bottom > topMark.y
});
}
// Test 6: Marks should be within reasonable soroban coordinate space
if (expected.marksWithinSorobanBounds) {
const allMarksReasonable = cropMarks.every(mark =>
mark.x > -100 && mark.x < 300 &&
mark.y > -50 && mark.y < 300
);
results.push({
name: `${testId}: All marks within reasonable bounds`,
expected: 'reasonable coordinates',
actual: `x: [${Math.min(...cropMarks.map(m => m.x))}, ${Math.max(...cropMarks.map(m => m.right))}], y: [${Math.min(...cropMarks.map(m => m.y))}, ${Math.max(...cropMarks.map(m => m.bottom))}]`,
pass: allMarksReasonable
});
}
}
return results;
}
async function runUnitTests() {
console.log('🧪 Running Crop Mark Unit Tests...\n');
let totalTests = 0;
let passedTests = 0;
const failedTests = [];
for (const testCase of testCases) {
console.log(`📋 Testing: ${testCase.id} (number: ${testCase.number})`);
try {
// Generate SVG for test case
const svgContent = generateTestSVG(testCase);
// Parse crop marks
const cropMarks = parseSVGCropMarks(svgContent);
// Validate crop marks
const results = validateCropMarks(cropMarks, testCase.expectedProperties, testCase.id);
// Report results
for (const result of results) {
totalTests++;
if (result.pass) {
console.log(`${result.name}`);
passedTests++;
} else {
console.log(`${result.name}: expected ${result.expected}, got ${result.actual}`);
failedTests.push(result);
}
}
} catch (error) {
console.log(` ❌ Failed to generate/test ${testCase.id}: ${error.message}`);
totalTests++;
failedTests.push({
name: `${testCase.id}: Generation failed`,
error: error.message
});
}
console.log(); // Empty line between test cases
}
// Summary
console.log('📊 Test Summary:');
console.log(` Total tests: ${totalTests}`);
console.log(` Passed: ${passedTests}`);
console.log(` Failed: ${failedTests.length}`);
if (failedTests.length === 0) {
console.log('\n🎉 All crop mark tests passed! No regressions detected.');
return true;
} else {
console.log('\n💥 Some tests failed. Potential regression detected:');
failedTests.forEach(test => {
console.log(` - ${test.name}${test.error ? ': ' + test.error : ''}`);
});
return false;
}
}
// Export for use in other scripts
module.exports = { runUnitTests, testCases, validateCropMarks, parseSVGCropMarks };
// Run tests if called directly
if (require.main === module) {
runUnitTests().then(success => {
process.exit(success ? 0 : 1);
}).catch(error => {
console.error('❌ Test runner failed:', error);
process.exit(1);
});
}

View File

@@ -0,0 +1,206 @@
#!/usr/bin/env node
// Test script to verify crop marks are positioned at SVG extremes
const fs = require('fs');
const path = require('path');
function parseSVG(svgContent) {
const elements = [];
const cropMarks = [];
// Extract all transform="translate(x y)" patterns
const translateRegex = /transform="translate\(([^)]+)\)"/g;
let match;
while ((match = translateRegex.exec(svgContent)) !== null) {
const coords = match[1].trim().split(/\s+/);
const x = parseFloat(coords[0]);
const y = parseFloat(coords[1]);
// Get the element context to determine if it's a crop mark
const elementStart = svgContent.lastIndexOf('<g', match.index);
const elementEnd = svgContent.indexOf('</g>', match.index);
const elementContent = svgContent.substring(elementStart, elementEnd);
// Check if this is a crop mark (red fill)
const isCropMark = elementContent.includes('fill="#ff4136"') ||
elementContent.includes('fill="red"');
if (isCropMark) {
// Extract dimensions from path elements in crop marks
// Path format: "M 0 0 L 0 3 L 3 3 L 3 0 Z" means 3x3 rectangle
const pathMatch = elementContent.match(/d="M\s+0\s+0\s+L\s+0\s+(\d+)\s+L\s+(\d+)\s+\d+\s+L\s+\d+\s+0\s+Z\s*"/);
if (pathMatch) {
const width = parseFloat(pathMatch[2]);
const height = parseFloat(pathMatch[1]);
cropMarks.push({
x: x,
y: y,
width: width,
height: height,
right: x + width,
bottom: y + height
});
}
} else {
// Extract dimensions for content elements
let width = 0, height = 0;
// Look for rect elements
const rectMatch = elementContent.match(/d="M\s+([^"]+)"/);
if (rectMatch) {
// Parse path data to get approximate bounds
const pathData = rectMatch[1];
const coords = pathData.match(/(\d+\.?\d*)/g);
if (coords && coords.length >= 4) {
width = Math.max(...coords.map(parseFloat)) - Math.min(...coords.map(parseFloat));
height = Math.max(...coords.slice(1).filter((_, i) => i % 2 === 1).map(parseFloat)) -
Math.min(...coords.slice(1).filter((_, i) => i % 2 === 1).map(parseFloat));
}
}
// Look for direct width/height attributes
const widthMatch = elementContent.match(/width="([^"]+)"/);
const heightMatch = elementContent.match(/height="([^"]+)"/);
if (widthMatch) width = parseFloat(widthMatch[1]);
if (heightMatch) height = parseFloat(heightMatch[1]);
// For polygon elements (diamond beads), estimate size
if (elementContent.includes('polygon') || elementContent.includes('L ')) {
if (width === 0) width = 25; // Approximate bead width
if (height === 0) height = 18; // Approximate bead height
}
elements.push({
x: x,
y: y,
width: width,
height: height,
right: x + width,
bottom: y + height
});
}
}
return { elements, cropMarks };
}
function calculateContentBounds(elements) {
if (elements.length === 0) return null;
const left = Math.min(...elements.map(e => e.x));
const right = Math.max(...elements.map(e => e.right));
const top = Math.min(...elements.map(e => e.y));
const bottom = Math.max(...elements.map(e => e.bottom));
return { left, right, top, bottom };
}
function testCropMarks(svgFile) {
console.log(`\n🧪 Testing crop marks in ${svgFile}...`);
const svgContent = fs.readFileSync(svgFile, 'utf8');
const { elements, cropMarks } = parseSVG(svgContent);
console.log(` Found ${elements.length} content elements`);
console.log(` Found ${cropMarks.length} crop marks`);
if (cropMarks.length !== 4) {
console.log(` ❌ Expected 4 crop marks, found ${cropMarks.length}`);
return false;
}
const contentBounds = calculateContentBounds(elements);
if (!contentBounds) {
console.log(` ❌ No content elements found`);
return false;
}
console.log(` Content bounds: left=${contentBounds.left}, right=${contentBounds.right}, top=${contentBounds.top}, bottom=${contentBounds.bottom}`);
// Find crop marks by position
const tolerance = 1; // Allow 1pt tolerance
const leftMark = cropMarks.find(m => Math.abs(m.x - Math.min(...cropMarks.map(c => c.x))) < tolerance);
const rightMark = cropMarks.find(m => Math.abs(m.right - Math.max(...cropMarks.map(c => c.right))) < tolerance);
const topMark = cropMarks.find(m => Math.abs(m.y - Math.min(...cropMarks.map(c => c.y))) < tolerance);
const bottomMark = cropMarks.find(m => Math.abs(m.bottom - Math.max(...cropMarks.map(c => c.bottom))) < tolerance);
console.log(` Crop marks: left=${leftMark?.x}, right=${rightMark?.right}, top=${topMark?.y}, bottom=${bottomMark?.bottom}`);
let passed = true;
const tests = [
{
name: "Left crop mark is leftmost element",
actual: leftMark?.x,
expected: "<= " + contentBounds.left,
pass: leftMark && leftMark.x <= contentBounds.left
},
{
name: "Right crop mark is rightmost element",
actual: rightMark?.right,
expected: "> " + contentBounds.right,
pass: rightMark && rightMark.right > contentBounds.right
},
{
name: "Top crop mark is topmost element",
actual: topMark?.y,
expected: "<= " + contentBounds.top,
pass: topMark && topMark.y <= contentBounds.top
},
{
name: "Bottom crop mark is bottommost element",
actual: bottomMark?.bottom,
expected: "> " + contentBounds.bottom,
pass: bottomMark && bottomMark.bottom > contentBounds.bottom
}
];
for (const test of tests) {
if (test.pass) {
console.log(`${test.name}: ${test.actual} ${test.expected}`);
} else {
console.log(`${test.name}: ${test.actual} should be ${test.expected}`);
passed = false;
}
}
return passed;
}
async function main() {
console.log('🧪 Testing crop mark positioning...\n');
const debugFiles = [
'gallery/debug-crop-marks-89.svg',
'gallery/debug-crop-marks-456.svg'
];
let allPassed = true;
for (const file of debugFiles) {
if (fs.existsSync(file)) {
const passed = testCropMarks(file);
if (!passed) allPassed = false;
} else {
console.log(`❌ File not found: ${file}`);
allPassed = false;
}
}
console.log('\n📊 Test Summary:');
if (allPassed) {
console.log('✅ All crop mark tests passed!');
} else {
console.log('❌ Some crop mark tests failed. Crop marks need repositioning.');
}
return allPassed;
}
if (require.main === module) {
main().catch(console.error);
}
module.exports = { testCropMarks, main };