sevgi-appendix 0.98.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2909d414c4e2306d522871e0f92a7eb5689c31e2e843e89833cd87f72a5f0aa1
4
- data.tar.gz: 9dc7509dd75c93a376d5c812e89b72da4523ad5e9a533c66077a2f3ce5282579
3
+ metadata.gz: de8ed7f67989c92a4f828b1308146b6ec91fbd1971e4643df4c644c784ef32a1
4
+ data.tar.gz: eb023302ed8980659744d2d07d8813d67ad7bb91eb7a24127b612c84fa39641f
5
5
  SHA512:
6
- metadata.gz: e4c8405ba0fe3d9a539714fad7c8558ae43c60e188e6ec43f5d4bf20be308d276a0361cc71ed5ea8bc6c092b488b8192d71f1b6e1d72ec8dbe3d8870a8bd2889
7
- data.tar.gz: ab523aab873367b743bbe60d130d9446c6bf8346ce43e7928eb8debd32e88a7e8c80a5024b4b79e02a3d6c082e1980c5d15c88c4611e2c1440068ac81deb402c
6
+ metadata.gz: 0c3ace1e02a9533c6303049334356816cb2315d4583154e50525323aa1e482d340eedc17f2559e61e3832700ab0afe774b6ca704291dc3c9e3d6595b5b7e2dd5
7
+ data.tar.gz: 554d7b3471bfb370524197507d1cc1746c293e533cf93d91f9e158656215dc77ee76f2bbba407d6b49f1fc994cab5926a1a6ddb2c013fbcbd1d0056f9ca9f9f4
data/CHANGELOG.md CHANGED
@@ -3,7 +3,101 @@
3
3
  This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
- ## Unreleased
6
+ ## 1.0.0 - 2026-09-16
7
+
8
+ ### Added
9
+
10
+ - Added Hatch and Orb Showcase examples and displayed both arc lengths in the Arc example.
11
+
12
+ ### Changed
13
+
14
+ - Matched documentation page widths to the homepage Showcase.
15
+ - Aligned Derender user guidance with UTF-8 normalization and safe subtree selection rules.
16
+ - Clarified the packaged skill's script invocation, subtree copying, and Derender selection and encoding rules.
17
+ - Allowed Canvas and Paper values as the first `SVG` argument when using the default document profile.
18
+ - Made element `dup` and `clone` own independent subtrees while retaining IDs and Ruby copy semantics.
19
+ - Made Segment equality compare length and direction; ordering still compares length only.
20
+ - Limited Tile cell, row, and column queries to the requested geometry and accelerated XML character validation.
21
+ - Simplified the first-run guide and aligned library constructor examples.
22
+ - Updated the packaged skill for canvas origins, alignment, Paper lookup, curved geometry, and export constraints.
23
+ - Revised DSL catalog examples and packaged Sevgi skill guidance to use statement-style calls and show inspection results.
24
+ - Refined Showcase example tabs, made Ruby and XML views fill their panels, and hid executable preambles from Ruby views.
25
+ - Documented non-rendering element data and clarified the related DSL catalog examples.
26
+ - Refined Showcase heading spacing, page-title colors, and DSL catalog cards across light and dark themes.
27
+ - Removed an obsolete ruler example and unused site code.
28
+ - Kept the Squared and Copperplate guidesheet examples together at the end of the Showcase.
29
+ - Updated the packaged skill to avoid duplicate semantic shapes and unnecessary paint passes.
30
+
31
+ ### Fixed
32
+
33
+ - Kept horizontal scrollbars visible in Showcase example code panels.
34
+ - Read Derender input in its declared XML encoding and normalized generated source, XML declarations, and markup to UTF-8.
35
+ - Preserved open-path endpoints and derived edges independently of display precision.
36
+ - Kept near-axis and near-parallel line equations and intersections independent of angle and slope rounding.
37
+ - Corrected the Showcase social image dimensions.
38
+ - Added SVG namespaces to standalone drawing examples and regenerated their outputs.
39
+ - Made failed Sevgi Rake tasks stop dependent tasks and captured required-library failures in executor results.
40
+ - Removed executor signal-handler replacement so the host and shell retain SIGINT ownership.
41
+ - Escaped late export CSS as XML text and inserted it only at a supported final root closing tag.
42
+ - Preserved Derender processing instructions and rejected custom entity references and unsupported trailing document nodes before inclusion.
43
+ - Included both box origins in `Align`, unified Tile index validation, and isolated custom numeric attribute snapshots.
44
+ - Prevented avoidable overflow and underflow in point distances.
45
+ - Corrected browser source-panel expectations and added executable documentation, YARD, and packaged-skill checks.
46
+ - Rendered inline code in DSL catalog summaries and kept linked task themes visible below the sticky header.
47
+ - Restored Showcase tab icons with embedded Font Awesome SVGs.
48
+
49
+ ## 0.100.0 - 2026-09-09
50
+
51
+ ### Added
52
+
53
+ - Added `ArcTo` and `ArcBy` for SVG-native elliptical arc paths.
54
+ - Added Geometry `Arc`, `Ellipse`, and `Circle` with bounds, length, predicates, affine transformations, and
55
+ linear/quadratic intersections. Closed ellipses and circles support sweeps and hatching.
56
+ - Added Geometry `Point.midpoint`, `Element#closed?`, lined `vertices`, open-path traversal, and `Rect#center`.
57
+ - Added Geometry aggregate bounding boxes through `Operation.box`, point collinearity through `Point.collinear?`, and
58
+ polygon `simple?`, `convex?`, and `concave?` predicates.
59
+ - Added Protractor and Arc examples and documented the drawing and calculation APIs.
60
+
61
+ ### Changed
62
+
63
+ - Removed redundant parent scans while duplicating element subtrees.
64
+ - Reused source bounds across Tile cells to reduce repeated calculations and object allocations.
65
+
66
+ ### Fixed
67
+
68
+ - Preserved Showcase card HTML through Markdown rendering so all examples and their tabs remain visible.
69
+ - Preserved XML declarations, pre-root comments, CDATA sections, inline comments, and namespace-only leaves in
70
+ Derender output and evaluation.
71
+ - Limited PDF stamp recoloring to replaced text and carried graphics state across a page's content streams.
72
+ - Corrected decimal interval fitting and made Grid point queries honor the active numeric precision.
73
+ - Prevented implicit shell interpretation of single executable arguments in `F.sh` and `F.sh!`, including paths with spaces or shell metacharacters.
74
+ - Preserved inherited namespaces on detached Derender nodes in generated source and direct evaluation, including imports through `EvaluateChildren` and `IncludeChildren`.
75
+ - Prevented sweep and Hatch lines from crossing the exterior between two tangent vertices of a concave polygon.
76
+ - Aligned Tile cells with their declared bounds for circles, rotated shapes, and polygons whose first vertex differs from their bounding-box origin.
77
+ - Limited `Load` chains to 128 active sources with `Executor::LoadDepthError`, preserving cycle detection and nested load diagnostics.
78
+ - Rejected nil and false aggregate-box inputs with the documented geometry error.
79
+ - Restored precision-aware rejection of zero-length Triangle sides.
80
+ - Made point-set collinearity independent of input order and removed eager polygon edge-pair storage.
81
+ - Applied the collinearity tolerance to every three-point subset, removing coordinate-axis-dependent baseline selection.
82
+
83
+ ## 0.99.0 - 2026-08-09
84
+
85
+ ### Added
86
+
87
+ - Added `SVG.Module` for building anonymous callable drawing modules with their contract installed before definition.
88
+ - Added responsive Mermaid diagrams for the Derender round trip and SVG validation lifecycle.
89
+
90
+ ### Changed
91
+
92
+ - Reorganized the documentation around getting started, usage, composition, documents, layout, output, and examples.
93
+ - Documented how the `igves` and `igsev` command names reflect their conversion directions.
94
+ - Normalized DSL catalog provider labels to lowercase and simplified polyfill-backed editor entries to `inkscape`.
95
+
96
+ ### Fixed
97
+
98
+ - Allowed A5-on-A4 pdfcpu conversion to replace an existing output file.
99
+ - Pre-rendered Mermaid diagrams as inline SVG instead of parsing them in site visitors' browsers.
100
+ - Removed duplicate provider and context labels from DSL catalog entries.
7
101
 
8
102
  ## 0.98.2 - 2026-07-25
9
103
 
@@ -212,7 +306,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
212
306
 
213
307
  ### Changed
214
308
 
215
- - Added the checker board example to the documentation showcase flow.
309
+ - Added the checkerboard example to the documentation showcase flow.
216
310
  - Consolidated Victor Book attribution for adapted showcase examples into a single documentation note.
217
311
 
218
312
  ### Fixed
data/README.md CHANGED
@@ -30,9 +30,9 @@ Locate the skill without guessing a Homebrew prefix or Cellar version:
30
30
  sevgi --skill
31
31
  ```
32
32
 
33
- The command prints one validated absolute path and nothing else. It fails if the installed `sevgi-appendix` version
34
- does not match Sevgi or its `SKILL.md` is missing. Homebrew reports a stable path below its `opt` tree, so an agent's
35
- skill directory may safely link to it. Homebrew keeps that path current across upgrades.
33
+ The command prints one validated absolute path and nothing else. It fails when the `sevgi-appendix` version does not
34
+ match Sevgi. It also fails when `SKILL.md` is missing. Homebrew reports a stable path below its `opt` tree. An agent's
35
+ skill directory can safely link to it. Homebrew keeps that path current across upgrades.
36
36
 
37
37
  Coding agents look for skills in different directories. Paste this prompt into the agent you want to configure:
38
38
 
@@ -15,38 +15,42 @@ visible intent.
15
15
  renderer resolve it. Use Ruby or `Sevgi::Geometry` only for information the program genuinely must derive. Read
16
16
  [drawing.md](references/drawing.md) before adding rendering-related arithmetic.
17
17
  2. **Fix the cause, not the symptom.** Treat the visible result as the acceptance criterion. Trace a mismatch through
18
- drawing geometry, viewport, transforms, styles, strokes, and renderer behavior; fix the layer that owns the faulty
18
+ drawing geometry, viewport, transforms, styles, strokes, and renderer behavior. Fix the layer that owns the faulty
19
19
  contract. Do not hide it with empty margins, oversized frames, clipping, non-uniform scaling, or a one-case offset.
20
20
  3. **Stay native to Sevgi.** Use SVG elements through the Sevgi DSL and prefer Sevgi's existing Graphics, Geometry,
21
21
  Sundries, and Function helpers where they fit. Do not generate raw SVG/XML, another graphics format, or an
22
22
  intermediate string and then convert it into Sevgi. Use Derender only when existing SVG/XML is a genuine input
23
- artifact.
23
+ artifact. Treat Ruby's dynamic evaluation APIs (`eval`, `*_eval`, and `*_exec`) as anti-patterns throughout every
24
+ Derender workflow. Use `Include` or `IncludeChildren` when the editor file remains authoritative, an `Evaluate*`
25
+ operation when the target must be explicit, or reviewed source integrated statically into the maintained DSL.
24
26
 
25
27
  ## Workflow
26
28
 
27
29
  1. Determine the host and installed dependency surface: executable `.sevgi` script, full-toolkit Ruby library, or a
28
30
  focused component. Read [dsl.md](references/dsl.md) for its grammar and facade boundaries.
29
- 2. Choose the component that owns each nontrivial operation. Read [toolkit.md](references/toolkit.md) before writing a
30
- project-local substitute for a Sevgi helper.
31
- 3. Structure data, control flow, and reuse as ordinary Ruby while preserving the DSL shape. Read
32
- [ruby.md](references/ruby.md).
33
- 4. Identify the owner of each visual result before writing arithmetic, offsets, or scaling. Read
34
- [drawing.md](references/drawing.md), and use [svg.md](references/svg.md) when SVG may own the behavior.
35
- 5. Read [layout.md](references/layout.md) for repetition, tiling, alignment, rulers, grids, drawing, or hatching.
36
- 6. For editor-authored SVG/XML, `igves` prints Sevgi source and `igsev` round-trips to normalized SVG; both accept files
37
- or standard input. Read
38
- [derender.md](references/derender.md). For PDF/PNG output, read [output.md](references/output.md).
39
- 7. Before introducing a Sevgi word or signature not established by nearby code or the loaded references, verify it in
40
- the DSL catalog or owning YARD. Do not infer an API from an English name or use `Element` to bypass an unknown
41
- operation.
42
- 8. Write the smallest clear Sevgi expression. Keep case-sensitive, normally lowercase-leading SVG element calls,
31
+ 2. Before introducing an operation, make sure that the target version documents its name, signature, required profile, and component.
32
+ Read [toolkit.md](references/toolkit.md) for lookup paths or before replacing a Sevgi helper.
33
+ Do not infer an API from an English name or use `Element` to bypass an unknown operation.
34
+ 3. Before changing a drawing, state the visible target and the properties that must remain unchanged.
35
+ Keep these acceptance criteria through verification. Equal canvas dimensions do not substitute for equal visible size.
36
+ 4. Read only the references needed for the operation. Use [ruby.md](references/ruby.md) for helpers, callable modules,
37
+ document extensions, or DSL formatting. Before adding visual arithmetic, offsets, or scaling, read
38
+ [drawing.md](references/drawing.md). Use [svg.md](references/svg.md) to find a renderer-owned mechanism.
39
+ 5. Read [layout.md](references/layout.md) for repetition, tiling, alignment, rulers, grids, `Draw`, or hatching.
40
+ 6. For editor-authored SVG/XML, `igves` prints Sevgi source. `igsev` round-trips to normalized SVG. Both accept files or
41
+ standard input. Read [derender.md](references/derender.md). For PDF/PNG output, read [output.md](references/output.md).
42
+ 7. Write the smallest clear Sevgi expression. Keep case-sensitive, normally lowercase-leading SVG element calls,
43
43
  capitalized Sevgi operations, ordinary Ruby control flow, and SVG attributes visibly distinct. Do not mechanically
44
- parenthesize statement-like DSL calls.
45
- 9. Render and inspect the actual output in each context it claims to support. Compare visible bounds and density—not
46
- only canvas or DOM dimensions. For size, alignment, clipping, density, or visual-regression evidence, read
47
- [inspection.md](references/inspection.md) and identify the measurement space before choosing a tool.
48
- 10. Re-read the finished source for raw-XML detours, avoidable calculations, magic offsets, duplicated helpers, and
49
- stale artifacts.
44
+ parenthesize statement-like DSL calls. When braces would require those parentheses, use `do`/`end`.
45
+ 8. Use the verification boundaries in [dsl.md](references/dsl.md). Report unavailable checks rather than claiming they passed.
46
+ 9. For new or visually changed drawings, render and inspect the supported contexts affected by the change.
47
+ Compare the output against the original acceptance criteria. For size, alignment, clipping, density, or visual-regression
48
+ evidence, read [inspection.md](references/inspection.md) before choosing a measurement tool.
49
+ Do not require visual measurements for source-only changes with no effect on rendering.
50
+ 10. Re-read the finished source for raw-XML detours, avoidable calculations, magic offsets, duplicated geometry or
51
+ paint passes, duplicated helpers, and stale artifacts. Emit each semantic shape once by default. Collapse repeated
52
+ draws when one SVG element can carry the required fill and stroke. Add another paint pass only when the visible
53
+ requirement or inspection proves that separate z-order is necessary; make each pass's role evident in the source.
50
54
 
51
55
  ## References
52
56
 
@@ -55,7 +59,7 @@ visible intent.
55
59
  | Choose script/library syntax, profiles, SVG elements, or Sevgi DSL words | [dsl.md](references/dsl.md) |
56
60
  | Choose a component and locate user, YARD, or checkout documentation | [toolkit.md](references/toolkit.md) |
57
61
  | Structure `.sevgi` and library code as idiomatic Ruby | [ruby.md](references/ruby.md) |
58
- | Apply the renderer/program ownership boundary; diagnose visual mismatches | [drawing.md](references/drawing.md) |
62
+ | Apply the renderer/program ownership boundary and diagnose visual mismatches | [drawing.md](references/drawing.md) |
59
63
  | Measure SVG geometry, browser layout, or painted pixels | [inspection.md](references/inspection.md) |
60
64
  | Find an SVG capability and its authoritative specification | [svg.md](references/svg.md) |
61
65
  | Choose repetition, tiling, ruler, grid, Draw, pattern, or Hatch | [layout.md](references/layout.md) |
@@ -2,10 +2,9 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- Some vector geometry is better authored in a visual editor than programmed: a Bezier-heavy logo, traced illustration,
6
- or hand-adjusted path may be correct as artwork but impractical as handwritten Ruby. Derender brings that SVG/XML into
7
- the Sevgi element model so editor-authored geometry can participate in Ruby-driven composition, styling, layout, and
8
- output. This combines both workflows without pretending every path should originate in code.
5
+ Some vector geometry is easier to create in a visual editor. Examples include a Bezier-heavy logo, a traced
6
+ illustration, and a hand-adjusted path. Derender brings that SVG/XML into the Sevgi element model. Editor-authored
7
+ geometry can then participate in Ruby-driven composition, styling, layout, and output.
9
8
 
10
9
  Do not use Derender as a detour for ordinary shapes or relationships that are clearer in the Sevgi DSL. Use it when
11
10
  SVG/XML is a real input artifact.
@@ -21,16 +20,16 @@ SVG/XML is a real input artifact.
21
20
  | Include a selected file node inside an SVG block | — | `Include` | included element or `nil` |
22
21
  | Include only a selected file node's children inside a block | — | `IncludeChildren` | frozen child snapshot |
23
22
 
24
- Use `DerenderFile` when generated Ruby should become the maintained source. Use `Include`, `EvaluateFile`, or their
25
- children variants when the editor file should remain the source of its geometry. Use `DecompileFile` to inspect names,
26
- attributes, namespaces, metadata, and children before choosing. Choose one maintained representation; do not keep
27
- changing both editor SVG and generated Sevgi as parallel sources.
23
+ Use `DerenderFile` when generated Ruby becomes the maintained source. Use `Include`, `EvaluateFile`, or their children
24
+ variants when the editor file remains the geometry source. Use `DecompileFile` to inspect names, attributes,
25
+ namespaces, metadata, and children. Choose one maintained representation. Do not maintain editor SVG and generated
26
+ Sevgi in parallel.
28
27
 
29
28
  Keep the editor file as the geometry source and compose a selected group in Sevgi:
30
29
 
31
30
  ```ruby
32
- SVG :minimal do
33
- Include "brand.svg", "logo", omit: :id
31
+ SVG do
32
+ Include "brand.svg", "logo"
34
33
  end.Save "badge.svg"
35
34
  ```
36
35
 
@@ -45,36 +44,50 @@ drawing.Render
45
44
  Generate Ruby for review and integration into the maintained source instead:
46
45
 
47
46
  ```ruby
48
- source = SVG.DerenderFile "brand.svg", id: "logo", omit: :id
47
+ source = SVG.DerenderFile "brand.svg", id: "logo"
49
48
  puts source
50
49
  ```
51
50
 
52
51
  At the command line, `igves` prints generated Sevgi source. Use `igsev` from the umbrella gem only when the intended
53
52
  result is normalized SVG produced by a complete SVG-to-Sevgi-to-SVG round trip. Both commands accept repeatable
54
- `--omit ATTRIBUTE` and read standard input when the file is omitted or `-`; `igsev` is a structural formatter, not a
53
+ `--omit ATTRIBUTE` and read standard input when the file is omitted or `-`. `igsev` is a structural formatter, not a
55
54
  byte-preserving XML rewrite.
56
55
 
57
- A selected subtree may produce a fragment rather than a standalone `.sevgi` script. Review the conversion, then place
58
- it inside the document or callable module that owns it; do not merely rename an arbitrary fragment to `.sevgi`.
56
+ Derender reads the XML encoding declaration or byte-order mark. Generated Ruby and rendered XML use UTF-8.
57
+ The declaration keeps its version and standalone flag, with any encoding field changed to UTF-8.
58
+
59
+ A selected subtree can produce a fragment rather than a standalone `.sevgi` script. Review the conversion. Then place
60
+ it inside the document or callable module that owns it. Do not rename an arbitrary fragment to `.sevgi`.
59
61
 
60
62
  ## Selection and Cleanup
61
63
 
64
+ Processing instructions retain their target, data, and order as inert XML markup. Custom entity references in the
65
+ selected subtree raise `Sevgi::ArgumentError` before target mutation. Predefined and numeric references remain valid.
66
+ Whole-document conversion rejects nodes after the root except whitespace. Explicit selection ignores unrelated siblings.
67
+
62
68
  - Give reusable editor groups stable IDs and select one with `id:`. `Include` takes that ID as its second positional
63
69
  argument.
70
+ - Selection preserves namespace scope, but does not copy ancestor transforms, inherited styles, or definitions outside the subtree.
71
+ Include the required context explicitly or select a self-contained ancestor.
72
+ - `IncludeChildren` and `EvaluateChildren*` omit the selected wrapper, including its transform and style attributes.
73
+ Use the whole-node form when the wrapper affects appearance.
64
74
  - Inspect an SVG tree with `SVG.DecompileFile` (or component-level `Sevgi::Derender.decompile_file`) before falling back
65
75
  to text search. Grep can mistake editor helpers, generated IDs, metadata, or unrelated layers for reusable artwork.
66
76
  - Use `omit:` with one String/Symbol or an Array of exact, case-sensitive attribute names. Selection happens before
67
- omission, so the selecting ID can be removed.
77
+ omission. The omission applies throughout the selected subtree, not only to its root.
78
+ Removing IDs can break `href`, `url(#...)`, and CSS references. Keep referenced IDs or update their consumers together.
68
79
  - Namespace declarations remain intact, and omitting the `style` attribute does not remove `style` elements. Omit
69
80
  style, transform, or geometry attributes only when their behavior is intentionally replaced.
70
- - Expect paths and other low-level editor geometry to remain low-level. Derender preserves the SVG tree; it cannot
81
+ - Expect paths and other low-level editor geometry to remain low-level. Derender preserves the SVG tree. It cannot
71
82
  reconstruct the loops, modules, or design operations that originally created it.
72
83
  - Treat parsing and executing as separate trust boundaries. Derender parses XML as data and direct evaluation builds
73
- graphics elements without executing generated Ruby. Execute generated source only when it is trusted code.
84
+ graphics elements without executing generated Ruby. Do not pass generated source to Ruby's dynamic evaluation APIs
85
+ (`eval`, `*_eval`, or `*_exec`), even when the input is trusted. When generated Ruby becomes the maintained
86
+ representation, review it and integrate it statically into the owning source or callable module.
74
87
  - After renaming or removing a selected id or source path, update its consumers, regenerate derived drawings, and check
75
88
  for stale references.
76
89
 
77
- Script mode uses bare names such as `DerenderFile`; library mode uses the `SVG.` facade. Component-only consumers use
90
+ Script mode uses bare names such as `DerenderFile`. Library mode uses the `SVG.` facade. Component-only consumers use
78
91
  the lowercase `Sevgi::Derender` methods and `_file` variants.
79
92
 
80
93
  Read the [Derender guide](https://sevgi.roktas.dev/derender/) for the complete workflow and
@@ -22,7 +22,7 @@ and hatching. It is not a parallel rendering engine.
22
22
 
23
23
  ## Example: Preserve the Ownership Boundary
24
24
 
25
- The Showcase Ruler illustrates the general rule; it does not introduce a text-specific recipe. The desired relationship
25
+ The Showcase Ruler illustrates the general rule. It does not introduce a text-specific recipe. The desired relationship
26
26
  is “center each label on this tick,” while the rendered width of a label depends on font metrics known by the SVG
27
27
  renderer.
28
28
 
@@ -63,8 +63,9 @@ Fix the first contract that is false. Do not make a frame larger to hide unequal
63
63
  alignment, clip an overflow caused by wrong geometry, or use a special-case offset that only matches one label or
64
64
  viewport.
65
65
 
66
- Verify every rendering context the artifact claims to support. For browser assets this may include representative
67
- desktop/mobile widths and light/dark themes; for print output it may include page sizes and an independent PDF renderer.
66
+ Make sure that the result works in every rendering context that the artifact supports. Browser assets can require
67
+ representative desktop and mobile widths plus light and dark themes. Print output can require several page sizes and an
68
+ independent PDF renderer.
68
69
  Equal SVG dimensions or DOM boxes do not prove equal visible size.
69
70
 
70
71
  ## Layout Changes
@@ -4,11 +4,13 @@
4
4
 
5
5
  | Form | Meaning |
6
6
  | --- | --- |
7
- | `rect`, `circle`, `linearGradient`, `clipPath`, ... | Standard SVG elements created directly by exact, case-sensitive names; they normally start lowercase |
7
+ | `rect`, `circle`, `linearGradient`, `clipPath`, ... | Standard SVG elements created by exact, case-sensitive names that normally start lowercase |
8
8
  | `Translate`, `Tile`, `Call`, `Render`, ... | Sevgi operations, normally capitalized to stand apart from SVG elements |
9
- | `css`, `layer`, `layer!`, `base` | Deliberate lowercase Sevgi words; `base` belongs to callable-module definitions |
9
+ | `css`, `square`, `symbol!`, `layer`, `layer!`, `base` | Examples of deliberate lowercase Sevgi words. The DSL catalog owns the full list |
10
10
  | `SVG(...)` | Build a document in both script and library code |
11
11
  | `SVG.Canvas(...)` | Call a full-toolkit facade operation in library code |
12
+ | `SVG.Module { ... }` | Build an anonymous callable with public steps and private or protected helpers |
13
+ | `extend SVG::Module` | Apply the same callable contract to an existing or explicitly declared module |
12
14
  | `SVG::Canvas` | Refer to a type or namespace |
13
15
  | `Canvas(...)` | Call the promoted operation in an executable `.sevgi` script |
14
16
 
@@ -22,13 +24,20 @@ text "Ready", x: 12, y: 16, "text-anchor": "middle", "font-weight": "bold"
22
24
 
23
25
  | Host | Load | Vocabulary |
24
26
  | --- | --- | --- |
25
- | Executable script | `ruby -S sevgi` through the `.sevgi` shebang | bare promoted operations such as `Canvas`, `Paper`, and `Grid` |
27
+ | Executable script | `sevgi file.sevgi` or an executable `.sevgi` shebang | bare promoted operations such as `Canvas`, `Paper`, and `Grid` |
26
28
  | Full-toolkit library | `require "sevgi"` | `SVG(...)` plus facade operations such as `SVG.Canvas` and `SVG.Grid` |
27
- | Focused graphics library | `require "sevgi/graphics"` | `Sevgi::Graphics.SVG` and lowercase component constructors; no full `SVG` facade |
29
+ | Focused graphics library | `require "sevgi/graphics"` | `Sevgi::Graphics.SVG` and lowercase component constructors without the full `SVG` facade |
28
30
 
29
31
  Follow the consumer's declared gems and existing dialect. Do not require the full toolkit merely to obtain facade
30
32
  spelling, and do not use facade operations when only a focused component is installed.
31
33
 
34
+ When the project bundle owns the dependencies, use `bundle exec sevgi file.sevgi`.
35
+ The `#!/usr/bin/env -S ruby -S sevgi` shebang helps editors detect Ruby syntax.
36
+ The shorter `#!/usr/bin/env sevgi` also works, but some editors do not recognize it as Ruby.
37
+
38
+ `SVG(...)` is the default constructor in library code as well as scripts. If another method shadows that name, use
39
+ `Sevgi.SVG(...)`. The explicit receiver is supported but not required. `SVG.Canvas(...)` is a separate facade operation.
40
+
32
41
  ## Minimal Forms
33
42
 
34
43
  Executable script:
@@ -38,7 +47,7 @@ Executable script:
38
47
 
39
48
  canvas = Canvas width: 24, height: 24, unit: :px
40
49
 
41
- SVG :minimal, canvas do
50
+ SVG canvas do
42
51
  circle cx: 12, cy: 12, r: 10, fill: "tomato"
43
52
  end.Save "badge.svg"
44
53
  ```
@@ -49,7 +58,9 @@ Ruby library:
49
58
  require "sevgi"
50
59
 
51
60
  canvas = SVG.Canvas width: 24, height: 24, unit: :px
52
- drawing = SVG(:minimal, canvas) { circle cx: 12, cy: 12, r: 10, fill: "tomato" }
61
+ drawing = SVG canvas do
62
+ circle cx: 12, cy: 12, r: 10, fill: "tomato"
63
+ end
53
64
 
54
65
  File.write "badge.svg", drawing.Render
55
66
  ```
@@ -60,32 +71,51 @@ Keep physical size and serialization dialect independent:
60
71
 
61
72
  | Need | Use | Owns |
62
73
  | --- | --- | --- |
63
- | Register or look up a named physical size | `SVG.Paper` / script `Paper` | width, height, and unit |
74
+ | Register a named physical size | `SVG.Paper` / script `Paper` | width, height, and unit |
75
+ | Look up a registered physical size | `SVG::Paper.fetch` | the registered size value |
64
76
  | Build one drawing surface | `SVG.Canvas` / script `Canvas` | size, margins, unit, name, and resulting `viewBox` |
65
77
  | Define or select an SVG document profile | `SVG.Document` / script `Document` | root attributes and preambles |
66
78
 
67
- The first argument to `SVG` selects a document profile; the optional second argument supplies a canvas. Use an
68
- anonymous `Document` for one-off metadata and a named profile only for shared process-wide vocabulary.
69
- Prefer non-bang registration; use `Paper!` or `Document!` only for an intentional overwrite.
79
+ Omitting the profile selects `:default`. A Canvas or Paper can be the first argument when the default profile is
80
+ suitable. Otherwise, the first argument selects a document profile and the optional second argument supplies the
81
+ canvas. Use an anonymous `Document` for one-off metadata. Use a named profile only for shared process-wide vocabulary.
82
+ Prefer non-bang registration. Use `Paper!` or `Document!` only for an intentional overwrite.
83
+
84
+ A canvas's `viewBox` starts at the negative left and top margins. Drawing coordinates remain relative to the inner
85
+ area. For example, `SVG.Canvas(width: 40, height: 20, unit: :px, margins: 2)` starts at `(-2, -2)`.
86
+ With `margins: -2`, it starts at `(2, 2)` instead. Negative margins enlarge the inner area, not the viewport.
70
87
 
71
88
  ## Task-to-Word Map
72
89
 
73
90
  | Task | Start with |
74
91
  | --- | --- |
75
- | Create SVG structure | SVG element names; nest containers with blocks |
76
- | Choose page dimensions and document metadata | `Paper`, `Canvas`, `Document`; keep their responsibilities separate |
92
+ | Create SVG structure | SVG element names with blocks for nested containers |
93
+ | Choose page dimensions and document metadata | `Paper`, `Canvas`, and `Document` with separate responsibilities |
77
94
  | Set reusable styles | `css`, classes, presentation attributes |
78
95
  | Transform an element or group | `Translate`, `Rotate`, `Scale`, `Skew`, `Flip` |
79
- | Center known inner and outer boxes | element `Align`; use `Sevgi::Geometry::Operation` for edge alignment or a Ruby result |
96
+ | Center known inner and outer boxes | element `Align`, or `Sevgi::Geometry::Operation` for edge alignment or a Ruby result |
80
97
  | Draw simple line/path wrappers | `LineTo`, `LineBy`, `HLineTo`, `HLineBy`, `VLineTo`, `VLineBy` |
81
98
  | Reuse or repeat drawing | `defs`/`use`, `Tile`, `TileX`, `TileY`, `Duplicate` |
82
- | Compose reusable drawing code | `SVG::Module`, `base`, `Call`; profile-specific `Group`, `Layer`, `Layer!`, `Symbols` |
99
+ | Compose reusable drawing code | `SVG.Module`, `SVG::Module`, `base`, `Call`, and profile-specific wrappers |
83
100
  | Move existing element trees | `Append`, `Prepend`, `Adopt`, `AdoptFirst`, `Orphan` |
84
101
  | Draw or hatch Geometry values | `Draw`, `Hatch` on `:inkscape` or an explicitly extended custom profile |
85
102
  | Inspect or validate output | `Identifiers`, `Validate`, `Lint` |
86
- | Produce output | `Render`, `Out`, `Save`; optional `PDF` and `PNG` export |
103
+ | Produce output | `Render`, `Out`, `Save`, and optional `PDF` or `PNG` export |
87
104
  | Import existing SVG/XML | `Include`, `Evaluate`, `Derender`, `Decompile` and their file variants |
88
105
 
106
+ ## Verification Boundaries
107
+
108
+ | Check | Establishes | Does not establish |
109
+ | --- | --- | --- |
110
+ | `Validate` | SVG vocabulary and nesting compliance when Standard is available | Visual correctness; without Standard it returns `nil` and performs no validation |
111
+ | `Lint` | No duplicate visible IDs | Complete reference integrity or SVG standard compliance |
112
+ | `Render` | SVG serialization | Correct appearance in a browser or export engine |
113
+ | Visual inspection | Appearance in the inspected context | Correctness in untested contexts |
114
+
115
+ For a new or changed drawing, run `Lint` and, when Standard is available, `Validate` before accepting the output.
116
+ Report a missing Standard component as unavailable validation, not a successful check.
117
+ Inspect visually changed output against the user's acceptance criteria.
118
+
89
119
  ## Profiles
90
120
 
91
121
  | Profile | Use |
@@ -16,7 +16,7 @@ State the question before selecting a tool:
16
16
  | Where does it appear after layout and transforms? | Browser `getBoundingClientRect()` or an equivalent automation API | Viewport-relative CSS pixels |
17
17
  | What is a path's renderer-computed length or point? | `getTotalLength()` or `getPointAtLength()` | SVG user units |
18
18
  | Which pixels were actually painted? | A deterministic PNG or browser screenshot inspected as raster data | Raster pixels |
19
- | Does the result have the intended balance or density? | Visual inspection at representative outputs | Perceptual; no single bounding box proves it |
19
+ | Does the result have the intended balance or density? | Visual inspection at representative outputs | Perceptual because no single bounding box proves it |
20
20
 
21
21
  Do not compare values from different spaces as if they shared units. Label every recorded measurement with:
22
22
 
@@ -46,7 +46,7 @@ and integration-context checks.
46
46
 
47
47
  `getBBox()` applies geometry attributes but does not apply transforms on the element or its parents.
48
48
  `getBoundingClientRect()` is an axis-aligned CSS-pixel rectangle after layout and transforms. Do not treat either value
49
- as the exact painted-pixel boundary: strokes, markers, clipping, filters, font rasterization, and antialiasing may require
49
+ as the exact painted-pixel boundary. Strokes, markers, clipping, filters, font rasterization, and antialiasing can require
50
50
  raster evidence. With rotated or skewed content, transform all relevant corners instead of scaling a width and height.
51
51
 
52
52
  ## Raster Recipe
@@ -59,7 +59,7 @@ regression.
59
59
  2. Inspect the image visually before reducing it to numbers. Confirm that the selected image contains the intended
60
60
  context and that no crop already concealed the defect.
61
61
  3. When ImageMagick or an equivalent tool is available, derive the occupied-pixel box from the alpha channel or a known
62
- background. Record the transparency threshold or color tolerance; antialiased edge pixels make that policy part of
62
+ background. Record the transparency threshold or color tolerance. Antialiased edge pixels make that policy part of
63
63
  the measurement.
64
64
  4. Compare occupied bounds, edge margins, and clipping against the stated acceptance criterion. Pixel counts and boxes
65
65
  do not measure perceived weight or balance by themselves.
@@ -74,9 +74,9 @@ renderer and apply the same fixed-context checks. Do not convert a raster observ
74
74
  - Wrong SVG-user-unit geometry points to coordinates, repetition, transforms, or a Sevgi layout helper.
75
75
  - Correct geometry but wrong CSS-pixel placement points to the viewport, host layout, responsive CSS, or transforms.
76
76
  - Stable browser boxes but different raster bounds point to paint, clipping, filters, fonts, or renderer behavior.
77
- - Equal boxes with visibly unequal results point to spacing, stroke weight, contrast, or density; keep visual inspection
77
+ - Equal boxes with visibly unequal results point to spacing, stroke weight, contrast, or density. Keep visual inspection
78
78
  as the acceptance criterion.
79
79
 
80
80
  Do not measure routine API or source-only changes merely because a browser or image tool is available. Stop when the
81
- chosen evidence answers the original question; extra metrics add confidence only when they test another relevant
81
+ chosen evidence answers the original question. Extra metrics add confidence only when they test another relevant
82
82
  contract.
@@ -8,19 +8,35 @@ Choose by the value the caller needs after the operation, not merely by the visi
8
8
  | --- | --- | --- |
9
9
  | Repeat one SVG subtree in the rendered document | `defs`/`use`, or DSL `Tile`, `TileX`, `TileY` | SVG references with generated positions |
10
10
  | Copy and independently edit an existing subtree | `Duplicate`, `DuplicateX`, `DuplicateY` | Independent SVG element trees |
11
+ | Copy a subtree without attachment or ID changes | `dup` or `clone` | Independent subtree with IDs preserved |
11
12
  | Inspect repeated cells or row/column bounds in Ruby | `Sevgi::Sundries::Tile` | Geometry values and boxes, no SVG elements |
12
13
 
14
+ The repetition APIs have different block contracts:
15
+
16
+ | API channel | Runs for | Use |
17
+ | --- | --- | --- |
18
+ | `Tile`, `TileX`, `TileY` block | One template under `defs` | Draw the shared subtree, not each cell |
19
+ | Tile `proc:` | Each generated `use` element | Mutate that element through the callback argument. Row and column indices are zero-based |
20
+ | `Duplicate`, `DuplicateX`, `DuplicateY` block | Every copied element | Customize the yielded element, not a new drawing context |
21
+
22
+ `Duplicate` moves visible `id` attributes to non-rendering `-id` metadata before customization.
23
+ An existing `-id` takes precedence. When replacing IDs, update their references as well.
24
+ The copied subtree attaches to its target parent after customization. Do not depend on that attachment during the callback.
25
+ Ordinary `dup` and `clone` leave the copy detached.
26
+ Before attaching it beside the original, resolve duplicate IDs and their references.
27
+ Use the exact callback keywords from the selected method's YARD contract. The Tile variants differ.
28
+
13
29
  ## Intervals and Grids
14
30
 
15
31
  | Need | Use |
16
32
  | --- | --- |
17
- | Fit whole major/minor intervals into a span and inspect their distances | `Sevgi::Sundries::Ruler` |
33
+ | Fit whole major/minor intervals into a span and inspect their distances | script `Ruler`, library `SVG.Ruler`, or component `Sevgi::Sundries::Ruler` |
18
34
  | Require an even major-interval count | `Sevgi::Sundries::RulerEven` |
19
35
  | Combine two fitted rulers and obtain lines, points, cells, or a fitted canvas | `SVG.Grid` or `Sevgi::Sundries::Grid` |
20
36
 
21
- `Ruler` is a Ruby value, not a drawing word. `Grid` is also a Ruby layout model; `Draw` materializes its geometry as SVG
22
- when lines are required. In a Grid, `grid.x` returns horizontal lines and `grid.y` vertical lines—the names describe
23
- line direction.
37
+ `Ruler` constructs a Ruby layout value without drawing SVG elements. `Grid` also returns a layout model.
38
+ `Draw` materializes its geometry as SVG when lines are required. In a Grid, `grid.x` returns horizontal lines and
39
+ `grid.y` vertical lines—the names describe line direction.
24
40
 
25
41
  ## Alignment
26
42
 
@@ -30,26 +46,46 @@ line direction.
30
46
  | Align Geometry at center or an edge and return the value or offset | `Sevgi::Geometry::Operation.align` or `Sevgi::Geometry::Operation.alignment` |
31
47
  | Align rendered text or other renderer-owned content | SVG anchoring, baseline, layout, or transform semantics |
32
48
 
33
- Geometry alignment accepts `:center`, `:left`, `:right`, `:top`, and `:bottom`; the element DSL's narrower `Align`
34
- contract accepts only `:center`. Do not calculate font or painted-content bounds merely to feed either API; use them
35
- when the program already owns meaningful box geometry.
49
+ Geometry alignment accepts `:center`, `:left`, `:right`, `:top`, and `:bottom`. The element DSL's narrower `Align`
50
+ contract accepts only `:center`. Do not calculate font or painted-content bounds only to feed either API. Use these
51
+ APIs when the program already owns meaningful box geometry.
52
+
53
+ `Align` includes both box origins. Width-and-height-only objects have origin `(0, 0)`.
54
+ An object with `position` must supply finite numeric `x` and `y` coordinates:
55
+
56
+ ```ruby
57
+ inner = Sevgi::Geometry::Rect[8, 4, position: [2, 3]]
58
+ outer = Sevgi::Geometry::Rect[40, 20, position: [5, 5]]
59
+ drawing = SVG width: 50, height: 30 do
60
+ shape = rect x: 2, y: 3, width: 8, height: 4
61
+ shape.Align :center, inner:, outer:
62
+ end
63
+ drawing.Render # The rectangle receives translate(19 10).
64
+ ```
65
+
66
+ ## Curved Geometry
67
+
68
+ For an SVG path, use `ArcTo` or `ArcBy`. The renderer resolves their endpoint, radius, `large`, and `sweep` rules.
69
+ Use `Geometry::Circle`, `Geometry::Ellipse`, or `Geometry::Arc` when Ruby needs intersections, endpoints, or bounds.
70
+ An arc has a finite extent and no filled interior. Positive angles run clockwise in screen coordinates, where y
71
+ increases downward. See [Geometry](https://sevgi.roktas.dev/geometry/#arcs-and-ellipses) and the installed Geometry YARD.
36
72
 
37
73
  ## Drawing and Hatching
38
74
 
39
75
  | Need | Use |
40
76
  | --- | --- |
41
- | A visual repeated fill whose individual strokes are irrelevant | SVG `pattern`; let the renderer repeat and clip it |
77
+ | A visual repeated fill whose individual strokes are irrelevant | SVG `pattern` that the renderer repeats and clips |
42
78
  | Explicit finite hatch segments that must remain separate geometry/SVG paths | Geometry sweep or `Hatch` |
43
79
  | Existing Geometry values rendered as SVG elements | `Draw` |
44
80
 
45
81
  `Hatch` computes finite segments and emits each as a separate SVG path. Use it for editable, inspectable, plotter-like,
46
- or otherwise explicit line geometrynot merely because a region should look striped. `Draw` and `Hatch` are included by
47
- `:inkscape`; add the Hatch mixture to another profile only when that profile deliberately owns the capability. For a
48
- scoped extension, subclass `SVG::Document::Base`, then call `SVG.Mixin :Hatch, profile`; targeting `Base` itself changes
82
+ or otherwise explicit line geometry. Do not use it only because a region needs stripes. `Draw` and `Hatch` are included
83
+ by `:inkscape`. Add the Hatch mixture to another profile only when that profile owns the capability. For a scoped
84
+ extension, subclass `SVG::Document::Base`, then call `SVG.Mixin :Hatch, profile`. Targeting `Base` itself changes
49
85
  every descendant profile process-wide.
50
86
 
51
- Read the [Sundries guide](https://sevgi.roktas.dev/sundries/) for Ruler, Grid, and both Tile models; read
52
- [Geometry sweeps and hatching](https://sevgi.roktas.dev/geometry/#sweeps) for explicit hatch lines; use the
87
+ Read the [Layout guide](https://sevgi.roktas.dev/layout/) for Ruler, Grid, and both Tile models. Read
88
+ [Geometry sweeps and hatching](https://sevgi.roktas.dev/geometry/#sweeps) for explicit hatch lines. Use the
53
89
  [DSL Catalog](https://sevgi.roktas.dev/dsl/) for exact drawing words. Exact Ruby contracts live in
54
90
  [`sevgi-sundries`](https://www.rubydoc.info/gems/sevgi-sundries) and
55
91
  [`sevgi-graphics`](https://www.rubydoc.info/gems/sevgi-graphics).
@@ -11,9 +11,9 @@ Keep document construction and output policy separate. Choose the final operatio
11
11
  | PNG file | `PNG` |
12
12
  | Export an existing SVG String outside the document | `Sevgi::Sundries::Export.call` |
13
13
 
14
- The `sevgi` command reads standard input when no file is given. Use `sevgi --as badge` when an implicit `Save`, `PDF`,
15
- or `PNG` should derive `badge.svg`, `badge.pdf`, or `badge.png` instead of the default `output` basename. `NAME` is a
16
- basename, not a path; explicit destinations in the source remain authoritative.
14
+ The `sevgi` command reads standard input when no file is given. Use `sevgi --as badge` to make an implicit `Save`, `PDF`,
15
+ or `PNG` derive `badge.svg`, `badge.pdf`, or `badge.png` instead of the default `output` basename. `NAME` is a
16
+ basename, not a path. Explicit destinations in the source remain authoritative.
17
17
 
18
18
  ## PDF
19
19
 
@@ -21,7 +21,7 @@ For a document, use the convenience operation:
21
21
 
22
22
  ```ruby
23
23
  canvas = SVG.Canvas width: 40, height: 40, unit: :px
24
- drawing = SVG :minimal, canvas do
24
+ drawing = SVG canvas do
25
25
  circle cx: 20, cy: 20, r: 16, fill: "tomato"
26
26
  end
27
27
 
@@ -32,30 +32,38 @@ For an application that owns the rendered SVG and output policy separately:
32
32
 
33
33
  ```ruby
34
34
  canvas = SVG.Canvas width: 40, height: 40, unit: :px
35
- svg = SVG(:minimal, canvas) { circle cx: 20, cy: 20, r: 16, fill: "tomato" }.Render
35
+ svg = SVG canvas do
36
+ circle cx: 20, cy: 20, r: 16, fill: "tomato"
37
+ end.Render
36
38
  Sevgi::Sundries::Export.call(svg, "badge.pdf")
37
39
  ```
38
40
 
39
- The output suffix selects PDF when `format:` is omitted. `width:` and `height:` are export dimensions; they do not
41
+ The output suffix selects PDF when `format:` is omitted. `width:` and `height:` are export dimensions. They do not
40
42
  repair or replace the drawing's canvas, `viewBox`, or visible geometry. Fix those in the SVG document. Use `css:` only
41
43
  for deliberate export-only styling, and use `dpi:` when the CSS-pixel-to-output conversion policy must differ.
42
44
 
43
- SVG output has no native graphics dependency. PDF and PNG export lazily require Cairo, RSVG, and HexaPDF; report a
45
+ Export CSS is a last-minute adjustment after document validation. It still obeys the CSS cascade.
46
+ Insertion requires well-formed SVG ending in an unprefixed `</svg>` plus optional XML whitespace.
47
+ Self-closing or prefixed roots and comments after the root are unsupported with `css:`. Without CSS, this restriction
48
+ does not apply. Sevgi escapes CSS as XML text but does not validate the stylesheet. Native `Export.call` runs its source
49
+ callback after insertion and before conversion. Inspect the final output for changed visibility, size, and clipping.
50
+
51
+ SVG output has no native graphics dependency. PDF and PNG export lazily require Cairo, RSVG, and HexaPDF. Report a
44
52
  missing optional component rather than replacing the path with an unrequested external command or raster workaround.
45
53
 
46
54
  ## Verification
47
55
 
48
- Inspect the produced artifact; a successful write does not prove correct rendering. For a parameterized or multi-page
56
+ Inspect the produced artifact. A successful write does not prove correct rendering. For a parameterized or multi-page
49
57
  family, start with a representative output and then check other variants affected by the same rule.
50
58
 
51
59
  For PDF output, validate document structure with `qpdf` when available, render representative pages through Poppler or
52
- an equivalent independent renderer, and inspect embedded fonts when fallback would change the result. Compare raster
53
- output only as evidence; fix discrepancies in the SVG source, export policy, or environment that owns them.
60
+ an equivalent independent renderer. Inspect embedded fonts when fallback changes the result. Compare raster output
61
+ only as evidence. Fix discrepancies in the SVG source, export policy, or environment that owns them.
54
62
 
55
63
  Treat rendered SVGs, PDFs, PNGs, and visual snapshots as derived evidence, not implementation sources. Fix the
56
64
  maintained Sevgi or editor-owned SVG/XML source and regenerate. Update expected artifacts only for an intentional output
57
65
  change, then review the visible diff before accepting it.
58
66
 
59
- Read [Sundries export](https://sevgi.roktas.dev/sundries/#export) for installation and examples, and
67
+ Read [Output](https://sevgi.roktas.dev/output/) for SVG, PDF, and PNG workflows, and
60
68
  [`Sevgi::Sundries::Export`](https://www.rubydoc.info/gems/sevgi-sundries/Sevgi/Sundries/Export) for exact dimensions,
61
69
  options, return paths, and errors.
@@ -4,28 +4,28 @@ A `.sevgi` file is executable Ruby evaluated with Sevgi's drawing vocabulary. It
4
4
  configuration format. Apply ordinary Ruby design and readability rules unless the compact DSL form is clearer.
5
5
 
6
6
  - Use local variables for local drawing state and constants for genuine module/script invariants.
7
- - Use Arrays, Hashes, ranges, loops, Enumerables, methods, and modules directly; do not recreate them as a second DSL.
7
+ - Use Arrays, Hashes, ranges, loops, Enumerables, methods, and modules directly. Do not recreate them as a second DSL.
8
8
  - Separate input data from drawing behavior when that makes either easier to read or test.
9
- - Extract reusable drawing behavior into ordinary methods or `SVG::Module`; use `SVG::Modules` for an owned nested
9
+ - Extract reusable drawing behavior into ordinary methods or `SVG::Module`. Use `SVG::Modules` for an owned nested
10
10
  module family.
11
11
  - Prefer explicit arguments and return values over hidden global state, `eval`, monkey patches, or unnecessary
12
12
  metaprogramming.
13
13
  - Keep side effects at the output boundary: build a document, then `Render`, `Save`, `Out`, `PDF`, or `PNG` deliberately.
14
14
  - Preserve the surrounding project's Ruby version, naming, error, test, and formatting conventions.
15
15
  - Hand-format `.sevgi` source for DSL readability. Do not run a broad Ruby formatter or autocorrect over `.sevgi`
16
- files when it would flatten or obscure the drawing.
16
+ files when it flattens or obscures the drawing.
17
17
 
18
18
  ## Preserve the DSL Shape
19
19
 
20
- Let drawing code read as a Sevgi program rather than mechanically parenthesized Ruby. Use braces for a one-line block,
21
- `do`/`end` for a multiline block, and omit optional parentheses from statement-like SVG elements and Sevgi operations.
22
- Keep parentheses when they bind a compact block or chained expression clearly, as in
23
- `SVG(:minimal) { circle r: 4 }.Render`.
20
+ Let drawing code read as a Sevgi program rather than mechanically parenthesized Ruby. Use braces for a one-line block.
21
+ Use `do`/`end` for a multiline block. Omit optional parentheses from statement-like SVG elements and Sevgi operations.
22
+ If braces require parentheses around a statement-like call, use `do`/`end` instead. Keep parentheses only when Ruby
23
+ grammar still requires them.
24
24
 
25
25
  Avoid:
26
26
 
27
27
  ```ruby
28
- SVG(:minimal) do
28
+ SVG(width: 16, height: 12) do
29
29
  g({ id: "mark" }) do
30
30
  rect({ x: 2, y: 2, width: 12, height: 8 })
31
31
  circle({ cx: 8, cy: 6, r: 3 })
@@ -36,7 +36,7 @@ end.Save("mark.svg")
36
36
  Prefer:
37
37
 
38
38
  ```ruby
39
- SVG :minimal do
39
+ SVG width: 16, height: 12 do
40
40
  g id: "mark" do
41
41
  rect x: 2, y: 2, width: 12, height: 8
42
42
  circle cx: 8, cy: 6, r: 3
@@ -44,36 +44,47 @@ SVG :minimal do
44
44
  end.Save "mark.svg"
45
45
  ```
46
46
 
47
- The first form is valid Ruby; the problem is loss of the drawing vocabulary's visual rhythm.
47
+ The first form is valid Ruby. It hides the drawing vocabulary's visual rhythm.
48
+
49
+ ## Choose Where Helpers Live
50
+
51
+ - Use `SVG.Module` for drawing code that works with different document profiles without adding methods to them.
52
+ Invoke it explicitly with `Call` or another callable wrapper. Every public instance method is a drawing step, so keep
53
+ non-step helpers private or protected. Those helpers run on the callable receiver rather than the SVG document.
54
+ - Subclass `SVG::Document::Base` when every document of a new type needs the same helper methods. The methods can
55
+ be called directly in the drawing block, and subclasses inherit them.
56
+ - Use `SVG.Mixin` to add methods to a document class after it has been defined or from another library. It changes the
57
+ target class and its subclasses. Targeting `SVG::Document::Base` changes every descendant profile process-wide.
48
58
 
49
59
  ## Callable Modules
50
60
 
51
- Extend a Ruby module with `SVG::Module`. Its public instance methods are drawing steps; name the only step `call`, or
52
- give several steps descriptive names. Private methods remain ordinary implementation helpers. A focused
53
- `require "sevgi/graphics"` consumer uses `Sevgi::Graphics::Module` and `Sevgi::Graphics::Modules` instead of the full
54
- facade constants.
61
+ Build an anonymous callable module with `SVG.Module`, or extend an existing Ruby module with `SVG::Module`. Its public
62
+ instance methods are drawing steps. Name the only step `call`, or give several steps descriptive names. Private methods
63
+ remain ordinary implementation helpers. A focused `require "sevgi/graphics"` consumer creates an ordinary `Module`
64
+ and extends it with `Sevgi::Graphics::Module`. Use `Sevgi::Graphics::Modules` for a named module family.
55
65
 
56
66
  `base` registers argument-independent invariant SVG content that runs once per invocation before the public drawing
57
67
  steps. It is not general initialization or an ordering hook.
58
68
 
59
69
  ```ruby
60
- Badge = Module.new do
61
- extend SVG::Module
62
-
70
+ Badge = SVG.Module do
63
71
  base { css ".badge" => { fill: "tomato" } }
64
72
  def call(label:) = text label, class: "badge"
65
73
  end
66
74
 
67
- SVG(:minimal) { Call Badge, label: "OK" }.Render
75
+ SVG :minimal do
76
+ Call Badge, label: "OK"
77
+ end.Render
68
78
  ```
69
79
 
70
80
  `Call` draws directly. On an Inkscape profile, `Group`, `Layer`, and `Layer!` wrap the same invocation in a group,
71
- normal layer, or insensitive layer; `Symbols` expands the public steps into reusable symbols. Lowercase `layer` and
81
+ normal layer, or insensitive layer. `Symbols` expands the public steps into reusable symbols. Lowercase `layer` and
72
82
  `layer!` instead open explicit layer blocks without invoking a module. Use `SVG::Modules` only when one namespace owns
73
83
  a nested family of callable modules.
74
84
 
75
85
  Ruby arithmetic is appropriate for domain data and values the program must know. It does not supersede the renderer
76
86
  ownership rule in [drawing.md](drawing.md): idiomatic Ruby can still be the wrong layer for a rendering calculation.
77
87
 
78
- Use the [Library Mode guide](https://sevgi.roktas.dev/library-mode/) for facade and module composition, and the
79
- [Script Mode guide](https://sevgi.roktas.dev/script-mode/) for executable source behavior.
88
+ Use [Compose](https://sevgi.roktas.dev/compose/) for callable modules,
89
+ [Documents](https://sevgi.roktas.dev/documents/#document-types) for document classes and mixtures, and
90
+ [Usage](https://sevgi.roktas.dev/usage/) for script and library behavior.
@@ -1,19 +1,19 @@
1
1
  # SVG Routing
2
2
 
3
- Use this page to identify the SVG mechanism, then verify exact behavior in MDN or the SVG specification. Do not turn
4
- this index into a cookbook of one-off drawing tips.
3
+ Use this page to identify the SVG mechanism. Then make sure that MDN or the SVG specification documents its exact
4
+ behavior. Do not turn this index into a cookbook of one-off drawing tips.
5
5
 
6
6
  | Rendering concept | Start with |
7
7
  | --- | --- |
8
8
  | Coordinate system and responsive scaling | `viewBox`, viewport dimensions, `preserveAspectRatio` |
9
- | Relative placement of an element tree | `transform`; use Sevgi's transform helpers when available |
9
+ | Relative placement of an element tree | `transform` with Sevgi's transform helpers when available |
10
10
  | Reusable drawing definitions | `defs`, `symbol`, `use` |
11
11
  | Repeated visual fill | `pattern` |
12
12
  | Paint | presentation attributes or CSS, gradients, opacity |
13
- | Visibility boundaries | `clipPath` for hard clipping; `mask` for luminance/alpha compositing |
13
+ | Visibility boundaries | `clipPath` for hard clipping and `mask` for luminance/alpha compositing |
14
14
  | Line decoration | `marker`, stroke width, line cap, line join, dash array |
15
15
  | Renderer effects | `filter` and filter primitives |
16
- | Text relationships | text positioning and anchoring attributes; leave font metrics to the renderer |
16
+ | Text relationships | text positioning and anchoring attributes with font metrics left to the renderer |
17
17
 
18
18
  Resolve questions in this order:
19
19
 
@@ -29,7 +29,7 @@ Authoritative references:
29
29
 
30
30
  - [MDN SVG reference](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference)
31
31
  - [W3C SVG 2 specification](https://www.w3.org/TR/SVG2/)
32
- - [Sevgi SVG Essentials](https://sevgi.roktas.dev/svg/)
32
+ - [Sevgi Documents](https://sevgi.roktas.dev/documents/)
33
33
 
34
34
  Do not invent an SVG name from memory when validation matters. Check MDN and let Sevgi Standard validate known element
35
35
  names, attributes, content, and nesting.
@@ -4,12 +4,13 @@
4
4
 
5
5
  | Need | Component / entry point | Boundary |
6
6
  | --- | --- | --- |
7
- | Build SVG documents and element trees | Graphics; `SVG(...)`, SVG element calls | Default starting point for every drawing |
7
+ | Build SVG documents and element trees | Graphics with `SVG(...)` and SVG element calls | Default starting point for every drawing |
8
8
  | Choose paper size, canvas geometry, or root serialization metadata | `SVG.Paper`, `SVG.Canvas`, `SVG.Document` | Keep physical size, drawing surface, and document profile independent |
9
- | Validate SVG vocabulary and nesting | Standard | Use validation; do not hand-maintain element/attribute allowlists |
9
+ | Validate SVG vocabulary and nesting | Standard | Use validation instead of hand-maintained element/attribute allowlists |
10
10
  | Calculate geometry SVG cannot supply | `Sevgi::Geometry` | Use for constructed values, intersections, sweeps, and algorithmic bounds—not renderer layout |
11
+ | Inspect circle, ellipse, or finite arc geometry | `Sevgi::Geometry::Circle`, `Ellipse`, `Arc` | See `layout.md` for the distinction from renderer-owned `ArcTo` and `ArcBy` |
11
12
  | Fit rulers, grids, and reusable tile layouts | `Sevgi::Sundries`, `SVG.Grid` | Choose the exact model through `layout.md` |
12
- | Reuse supported cross-component helpers | `Sevgi::F` | Check before adding a project-local Sevgi helper; it is not a general utility library |
13
+ | Reuse supported cross-component helpers | `Sevgi::F` | Use it before adding a project-local Sevgi helper. Do not treat it as a general utility library |
13
14
  | Import or inspect existing SVG/XML | Derender facade methods | Choose the source/evaluation relationship through `derender.md` |
14
15
  | Render SVG as PDF or PNG | Sundries export / document `PDF` and `PNG` | Choose the output boundary through `output.md` |
15
16
 
@@ -28,6 +29,14 @@ When a Sevgi checkout is available, prefer its canonical sources:
28
29
  | Exact public contracts | the owning component's `lib/` YARD comments |
29
30
  | Rendered local YARD | `.local/var/ruby/doc/api` after `bundle exec rake doc` |
30
31
 
32
+ ## Installed Gems
33
+
34
+ Without a checkout, use the consumer's active bundle to locate the owning gem, for example `bundle show sevgi-graphics`.
35
+ Outside Bundler, use `gem which sevgi/graphics` to locate that component's entrypoint.
36
+ Read the adjacent `lib/` sources and YARD comments for the installed contract.
37
+ Use the same Ruby and dependency environment as the drawing.
38
+ Do not assume that the latest online API exists in the installed version.
39
+
31
40
  ## Lookup Order
32
41
 
33
42
  1. Read the task-relevant user guide for semantics and workflow.
@@ -38,10 +47,11 @@ When a Sevgi checkout is available, prefer its canonical sources:
38
47
 
39
48
  | Topic | User guide | YARD |
40
49
  | --- | --- | --- |
41
- | Script and library forms | [Getting Started](https://sevgi.roktas.dev/getting-started/), [Library Mode](https://sevgi.roktas.dev/library-mode/) | [`sevgi`](https://www.rubydoc.info/gems/sevgi) |
42
- | SVG documents and DSL | [SVG Essentials](https://sevgi.roktas.dev/svg/), [DSL Catalog](https://sevgi.roktas.dev/dsl/) | [`sevgi-graphics`](https://www.rubydoc.info/gems/sevgi-graphics) |
50
+ | Script and library forms | [Getting Started](https://sevgi.roktas.dev/start/), [Usage](https://sevgi.roktas.dev/usage/) | [`sevgi`](https://www.rubydoc.info/gems/sevgi) |
51
+ | SVG documents and composition | [Documents](https://sevgi.roktas.dev/documents/), [Compose](https://sevgi.roktas.dev/compose/), [DSL Catalog](https://sevgi.roktas.dev/dsl/) | [`sevgi-graphics`](https://www.rubydoc.info/gems/sevgi-graphics) |
43
52
  | Geometry | [Geometry](https://sevgi.roktas.dev/geometry/) | [`sevgi-geometry`](https://www.rubydoc.info/gems/sevgi-geometry) |
44
- | Rulers, grids, tiles, export | [Sundries](https://sevgi.roktas.dev/sundries/) | [`sevgi-sundries`](https://www.rubydoc.info/gems/sevgi-sundries) |
53
+ | Rulers, grids, and tiles | [Layout](https://sevgi.roktas.dev/layout/) | [`sevgi-sundries`](https://www.rubydoc.info/gems/sevgi-sundries) |
54
+ | SVG, PDF, and PNG output | [Output](https://sevgi.roktas.dev/output/) | [`sevgi-graphics`](https://www.rubydoc.info/gems/sevgi-graphics), [`sevgi-sundries`](https://www.rubydoc.info/gems/sevgi-sundries) |
45
55
  | Shared helpers | [Functions](https://sevgi.roktas.dev/functions/) | [`sevgi-function`](https://www.rubydoc.info/gems/sevgi-function) |
46
56
  | SVG/XML import and round trip | [Derender](https://sevgi.roktas.dev/derender/) | [`sevgi-derender`](https://www.rubydoc.info/gems/sevgi-derender) |
47
57
 
@@ -3,6 +3,6 @@
3
3
  module Sevgi
4
4
  module Appendix
5
5
  # Appendix package version.
6
- VERSION = "0.98.2"
6
+ VERSION = "1.0.0"
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sevgi-appendix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.98.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Recai Oktaş
@@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  requirements: []
101
- rubygems_version: 4.0.16
101
+ rubygems_version: 4.0.20
102
102
  specification_version: 4
103
103
  summary: Development extras for the Sevgi SVG DSL.
104
104
  test_files: []