Loop ring reads as one continuous circle
All six ring connectors are now arcs of the same radius-240 circle (clockwise sweep, station-edge landings) instead of a mix of arcs and right-angled verticals. type-loop.md mandates ring arcs as the type's connector grammar — a documented exception to SKILL.md §6 rule 1, same precedent as medallion's promotion arcs — and adds the mixed arc + orthogonal ring as an anti-pattern. Screenshot recaptured.
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 138 KiB |
@@ -49,13 +49,13 @@
|
||||
<rect width="1040" height="680" fill="#2d3142"/>
|
||||
<rect width="1040" height="680" fill="url(#dots)" opacity="0.55"/>
|
||||
|
||||
<!-- Solid clockwise ring: every endpoint lands on a station edge. -->
|
||||
<path class="ring" d="M600 92 C648 100 696 140 672 188" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M808 236 H824 Q832 236 832 244 V436 Q832 444 824 444 H808" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M672 492 C696 520 648 564 600 572" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M440 572 C392 564 344 520 368 492" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M232 444 H216 Q208 444 208 436 V244 Q208 236 216 236 H232" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M368 188 C344 140 392 100 440 92" marker-end="url(#arrow)"/>
|
||||
<!-- Solid clockwise ring: six arcs on the same r=240 station circle. -->
|
||||
<path class="ring" d="M600 113.726 A240 240 0 0 1 704.969 187.073" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M743.285 252 A240 240 0 0 1 743.722 426.882" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M705.731 492 A240 240 0 0 1 601.130 565.871" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M440 566.274 A240 240 0 0 1 335.031 492.927" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M296.715 428 A240 240 0 0 1 296.278 253.118" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M334.269 188 A240 240 0 0 1 438.870 114.129" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- Dashed write-backs: station inner edge to 6px before the hub stroke. -->
|
||||
<path class="spoke" d="M520 132 V280" marker-end="url(#arrow-soft)"/>
|
||||
|
||||
@@ -69,13 +69,13 @@
|
||||
<rect width="1040" height="680" fill="#f5f5f5"/>
|
||||
<rect width="1040" height="680" fill="url(#dots)" opacity="0.55"/>
|
||||
|
||||
<!-- Solid clockwise ring: every endpoint lands on a station edge. -->
|
||||
<path class="ring" d="M600 92 C648 100 696 140 672 188" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M808 236 H824 Q832 236 832 244 V436 Q832 444 824 444 H808" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M672 492 C696 520 648 564 600 572" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M440 572 C392 564 344 520 368 492" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M232 444 H216 Q208 444 208 436 V244 Q208 236 216 236 H232" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M368 188 C344 140 392 100 440 92" marker-end="url(#arrow)"/>
|
||||
<!-- Solid clockwise ring: six arcs on the same r=240 station circle. -->
|
||||
<path class="ring" d="M600 113.726 A240 240 0 0 1 704.969 187.073" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M743.285 252 A240 240 0 0 1 743.722 426.882" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M705.731 492 A240 240 0 0 1 601.130 565.871" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M440 566.274 A240 240 0 0 1 335.031 492.927" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M296.715 428 A240 240 0 0 1 296.278 253.118" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M334.269 188 A240 240 0 0 1 438.870 114.129" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- Dashed write-backs: station inner edge to 6px before the hub stroke. -->
|
||||
<path class="spoke" d="M520 132 V280" marker-end="url(#arrow-soft)"/>
|
||||
|
||||
@@ -49,13 +49,13 @@
|
||||
<rect width="1040" height="680" fill="#f5f5f5"/>
|
||||
<rect width="1040" height="680" fill="url(#dots)" opacity="0.55"/>
|
||||
|
||||
<!-- Solid clockwise ring: every endpoint lands on a station edge. -->
|
||||
<path class="ring" d="M600 92 C648 100 696 140 672 188" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M808 236 H824 Q832 236 832 244 V436 Q832 444 824 444 H808" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M672 492 C696 520 648 564 600 572" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M440 572 C392 564 344 520 368 492" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M232 444 H216 Q208 444 208 436 V244 Q208 236 216 236 H232" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M368 188 C344 140 392 100 440 92" marker-end="url(#arrow)"/>
|
||||
<!-- Solid clockwise ring: six arcs on the same r=240 station circle. -->
|
||||
<path class="ring" d="M600 113.726 A240 240 0 0 1 704.969 187.073" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M743.285 252 A240 240 0 0 1 743.722 426.882" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M705.731 492 A240 240 0 0 1 601.130 565.871" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M440 566.274 A240 240 0 0 1 335.031 492.927" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M296.715 428 A240 240 0 0 1 296.278 253.118" marker-end="url(#arrow)"/>
|
||||
<path class="ring" d="M334.269 188 A240 240 0 0 1 438.870 114.129" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- Dashed write-backs: station inner edge to 6px before the hub stroke. -->
|
||||
<path class="spoke" d="M520 132 V280" marker-end="url(#arrow-soft)"/>
|
||||
|
||||
@@ -32,7 +32,6 @@ hub_w: 200
|
||||
hub_h: 104
|
||||
radius: 240
|
||||
margin: 64
|
||||
ring_style: "arc" # arc | rounded-orthogonal
|
||||
dark: false
|
||||
```
|
||||
|
||||
@@ -61,51 +60,54 @@ station_x(k) = station_center_x(k) - station_w/2
|
||||
station_y(k) = station_center_y(k) - station_h/2
|
||||
```
|
||||
|
||||
Thus station 1 sits at the top, and increasing `k` moves clockwise. Round rendered coordinates to the nearest 4px grid point after computing the ideal geometry; preserve symmetry when rounding paired stations.
|
||||
Thus station 1 sits at the top, and increasing `k` moves clockwise. Round station rectangles to the nearest 4px grid point after computing the ideal geometry; preserve symmetry when rounding paired stations. Keep ring-circle intersection points to three decimal places so every arc remains on the same circle.
|
||||
|
||||
### 2.2 Solid ring-flow endpoints
|
||||
|
||||
Ring connectors travel from station `k` to station `j = (k + 1) mod N`. They terminate on box edges, never at box centers. The clockwise unit tangent at station `k` is:
|
||||
Ring connectors travel from station `k` to station `j = (k + 1) mod N` as circular SVG arcs on the station circle itself. Every segment uses the same center `C`, radius `R`, and clockwise sweep. The station boxes interrupt the circle; connectors begin at the circle's clockwise exit from the source box and end just before its counterclockwise entry into the destination box, so the marker tip lands on the destination stroke.
|
||||
|
||||
Find the circle/rectangle intersections against all four edges of station `k`. For vertical edge `x = x_e`:
|
||||
|
||||
```text
|
||||
t_k = (-sin(theta_k), cos(theta_k))
|
||||
y = cy +/- sqrt(R^2 - (x_e - cx)^2)
|
||||
```
|
||||
|
||||
The distance from the center of an axis-aligned station box to its boundary along a unit direction `v` is:
|
||||
Keep only candidates whose `y` lies within the edge. For horizontal edge `y = y_e`:
|
||||
|
||||
```text
|
||||
box_distance(v, a, b) = min(a / abs(v.x), b / abs(v.y))
|
||||
x = cx +/- sqrt(R^2 - (y_e - cy)^2)
|
||||
```
|
||||
|
||||
Ignore a division whose denominator is zero. Then:
|
||||
Keep only candidates whose `x` lies within the edge. The two surviving points are classified by their normalized polar angles around `C`:
|
||||
|
||||
```text
|
||||
d_exit = box_distance( t_k, a, b)
|
||||
d_entry = box_distance(-t_j, a, b)
|
||||
|
||||
ring_start(k) = P_k + d_exit * t_k
|
||||
ring_end(k) = P_j - d_entry * t_j
|
||||
q_entry(k) = circle/box intersection immediately before theta_k clockwise
|
||||
q_exit(k) = circle/box intersection immediately after theta_k clockwise
|
||||
```
|
||||
|
||||
For `ring_style: arc`, connect those edge points with a cubic whose control vectors follow the local tangents:
|
||||
Compensate for the marker tip before emitting the destination endpoint. With the canonical marker (`refX=7`, polygon tip at `x=8`) and ring stroke width `1.2`, `marker_overhang = 1.2`:
|
||||
|
||||
```text
|
||||
delta = 2pi / N
|
||||
lambda = 0.55 * R * delta
|
||||
phi_entry = atan2(q_entry(j).y - cy, q_entry(j).x - cx)
|
||||
phi_end = phi_entry - marker_overhang / R
|
||||
q_end = C + R * (cos(phi_end), sin(phi_end))
|
||||
|
||||
M ring_start
|
||||
C ring_start + lambda*t_k,
|
||||
ring_end - lambda*t_j,
|
||||
ring_end
|
||||
M q_exit(k).x q_exit(k).y
|
||||
A R R 0 0 1 q_end.x q_end.y
|
||||
```
|
||||
|
||||
Reduce `lambda` only enough to keep the curve outside the hub and neighboring boxes. For `ring_style: rounded-orthogonal`, route both edge points to an outer rail and join them with `r=8` quarter-arcs. Every bend is rounded; no slanted straight segments. The closing connector from station `N-1` to station 0 uses the same formula and must remain visibly continuous with the other ring arrows.
|
||||
The large-arc flag is `0` because adjacent-station gaps are less than 180 degrees; the sweep flag is always `1` for clockwise motion in SVG coordinates. The arrowhead overhang completes the final 1.2px to `q_entry(j)`, landing on the box edge without crossing its stroke. The closing connector from station `N-1` to station 0 uses the identical formula.
|
||||
|
||||
Loop's circular ring arcs are a documented type-specific exception to SKILL.md §6 rule 1, following the same precedent as Medallion's promotion arcs. A Loop never mixes cubic, straight, or rounded-orthogonal segments into its ring: the six visible gaps must read as pieces of one continuous circle.
|
||||
|
||||
### 2.3 Dashed write-back spoke endpoints
|
||||
|
||||
Each spoke runs inward from the station edge toward the hub. Use the same ray/box intersection formula, now on the radial vector `u_k`:
|
||||
|
||||
```text
|
||||
box_distance(v, half_w, half_h) = min(half_w / abs(v.x), half_h / abs(v.y))
|
||||
# ignore a term whose denominator is zero
|
||||
|
||||
d_station = box_distance(u_k, a, b)
|
||||
d_hub = box_distance(u_k, A, B)
|
||||
marker_gap = 6 # 4..8px; 6px canonical
|
||||
@@ -133,7 +135,7 @@ viewBox_w = right - left
|
||||
viewBox_h = bottom - top
|
||||
```
|
||||
|
||||
If cubic controls or an outer orthogonal rail extend farther than those bounds, grow the corresponding margin. Never shrink the canvas until a station stroke, marker, or curved return clips. For the six-station canonical example, `viewBox="0 0 1040 680"`, `C=(520,340)`, `R=240`, station size `160×64`, and hub size `200×104` leave generous outer clearance.
|
||||
Include the full circle extrema `cx +/- R`, `cy +/- R` plus station bounds and marker clearance when checking these limits. Never shrink the canvas until a station stroke, marker, or ring arc clips. For the six-station canonical example, `viewBox="0 0 1040 680"`, `C=(520,340)`, `R=240`, station size `160×64`, and hub size `200×104` leave generous outer clearance.
|
||||
|
||||
---
|
||||
|
||||
@@ -144,7 +146,7 @@ If cubic controls or an outer orthogonal rail extend farther than those bounds,
|
||||
| Station | Standard node: `paper` fill, `ink` stroke, `radius-md`; name in `node-name`, sublabel in `sublabel` |
|
||||
| Hub | The one dark element: `ink` fill, `paper` text; slightly larger than a station |
|
||||
| Focal station | At most one: `accent-tint` fill, `accent` stroke; station name may use `accent` |
|
||||
| Ring flow | Solid `muted` stroke, default arrowhead at the destination; clockwise only |
|
||||
| Ring flow | Circular `A R R 0 0 1` arcs on the station circle, solid `muted` stroke, default arrowhead at the destination; clockwise only |
|
||||
| Write-back spoke | Dashed `soft` stroke at reduced emphasis, `stroke-dasharray="5,4"`, with a `soft` arrowhead |
|
||||
| Spoke label | `arrow-label` role, `soft`, uppercase, paper mask, 6–10px clear of the connector |
|
||||
|
||||
@@ -156,14 +158,14 @@ The hub is not a seventh process step. It is accumulated state: memory, standard
|
||||
|
||||
## 4. Connector rules (mandatory)
|
||||
|
||||
SKILL.md §6 applies in full, with the radial-spoke exception stated in §2.3:
|
||||
SKILL.md §6 applies in full except for the two Loop-specific connector primitives: circular ring arcs (§2.2) and straight radial spokes (§2.3). Like Medallion's promotion arcs, these replace §6 rule 1 for this diagram type:
|
||||
|
||||
- Ring arrows are solid and clockwise. Their destination markers land on station edges; no connector ends at a center point.
|
||||
- Ring arrows are same-radius circular arcs, solid, and clockwise. Every path uses `A R R 0 0 1`; destination markers land on station edges and no connector ends at a center point.
|
||||
- Spokes are dashed and point inward. A solid spoke destroys the visual distinction between operating flow and write-back.
|
||||
- Labels use opaque masks and maintain a visible 6–10px connector gap. Never place text on the stroke.
|
||||
- No ring connector or spoke may overlap another connector. Ring paths remain outside the hub; spokes occupy distinct radial routes.
|
||||
- When two spokes must leave the same station edge, fan their attach points by the §6 formula with at least 12px separation. The normal Loop has one spoke per station; use a second only when the semantics cannot be merged.
|
||||
- If a ring route would cross the hub, increase `R`, move to the outer rail, or split the diagram. Do not thread flow through shared state.
|
||||
- If a ring route would cross the hub, increase `R` or split the diagram. Do not thread flow through shared state or substitute an orthogonal route.
|
||||
|
||||
---
|
||||
|
||||
@@ -189,7 +191,7 @@ The semantic relationship stays unchanged in dark mode: one `ink`-filled hub, on
|
||||
|
||||
1. Station count is 5–8 and hub count is exactly one.
|
||||
2. Station 0 is at `-90deg`; all others use equal `360/N` steps clockwise.
|
||||
3. Every solid ring arrow connects adjacent stations and the last returns to the first.
|
||||
3. Every solid ring arrow connects adjacent stations with `A R R 0 0 1`, using the same `R`; the last returns to the first.
|
||||
4. Every ring marker lands on a station edge, not its center.
|
||||
5. Every dashed spoke begins on a station's inner edge and stops `marker_gap` before the hub stroke.
|
||||
6. Ring connectors stay outside the hub; spokes do not cross or overlap.
|
||||
@@ -206,6 +208,7 @@ The semantic relationship stays unchanged in dark mode: one `ink`-filled hub, on
|
||||
| Two hubs | Two accumulated states create two systems. Draw two diagrams. |
|
||||
| Solid spokes | They look like primary flow and kill the dashed return signal. Use dashed `soft` write-backs. |
|
||||
| Stations at uneven angles without reason | The ring stops reading as one operating cadence. Use equal `360/N` spacing unless a documented phase grouping requires a deliberate gap. |
|
||||
| Mixed arc + orthogonal ring segments | The ring becomes a rounded rectangle. Every segment must be a circular arc of the same radius so the ring reads as one continuous circle. |
|
||||
| Connectors crossing the hub | Flow becomes confused with state. Route the ring outside or enlarge the radius. |
|
||||
| Accent on multiple stations | The editorial gate disappears. Keep one focal station at most. |
|
||||
| More than 8 stations | Labels and spokes crowd the hub. Split into overview + detail. |
|
||||
|
||||
Reference in New Issue
Block a user