fontisan 0.2.14 → 0.2.16

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.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +79 -4
  3. data/docs/.gitignore +17 -0
  4. data/docs/.vitepress/config.ts +317 -0
  5. data/docs/.vitepress/theme/components/ApiMethod.vue +127 -0
  6. data/docs/.vitepress/theme/components/Badge.vue +51 -0
  7. data/docs/.vitepress/theme/components/FeatureComparison.vue +87 -0
  8. data/docs/.vitepress/theme/components/HeroCodeBlock.vue +98 -0
  9. data/docs/.vitepress/theme/components/WithinHero.vue +30 -0
  10. data/docs/.vitepress/theme/index.ts +22 -0
  11. data/docs/.vitepress/theme/style.css +330 -0
  12. data/docs/api/conversion-options.md +141 -0
  13. data/docs/api/converters/curve-converter.md +34 -0
  14. data/docs/api/converters/hint-converter.md +34 -0
  15. data/docs/api/converters/outline-converter.md +27 -0
  16. data/docs/api/font-loader.md +111 -0
  17. data/docs/api/font-writer.md +103 -0
  18. data/docs/api/index.md +79 -0
  19. data/docs/api/models/glyph-accessor.md +43 -0
  20. data/docs/api/models/glyph.md +40 -0
  21. data/docs/api/models/table-analyzer.md +35 -0
  22. data/docs/api/sfnt-font.md +53 -0
  23. data/docs/api/type1-font.md +43 -0
  24. data/docs/api/validators/font-validator.md +31 -0
  25. data/docs/api/validators/helper.md +36 -0
  26. data/docs/api/validators/profile.md +39 -0
  27. data/docs/cli/convert.md +87 -0
  28. data/docs/cli/dump-table.md +110 -0
  29. data/docs/cli/export.md +176 -0
  30. data/docs/cli/features.md +124 -0
  31. data/docs/cli/glyphs.md +90 -0
  32. data/docs/cli/index.md +208 -0
  33. data/docs/cli/info.md +254 -0
  34. data/docs/cli/instance.md +122 -0
  35. data/docs/cli/ls.md +95 -0
  36. data/docs/cli/optical-size.md +94 -0
  37. data/docs/cli/pack.md +125 -0
  38. data/docs/cli/scripts.md +105 -0
  39. data/docs/cli/subset.md +39 -0
  40. data/docs/cli/tables.md +84 -0
  41. data/docs/cli/unicode.md +101 -0
  42. data/docs/cli/validate.md +48 -0
  43. data/docs/cli/variable.md +126 -0
  44. data/docs/cli/version.md +46 -0
  45. data/docs/guide/cli/convert.md +108 -0
  46. data/docs/guide/cli/export.md +138 -0
  47. data/docs/guide/cli/index.md +99 -0
  48. data/docs/guide/cli/info.md +144 -0
  49. data/docs/guide/cli/pack.md +155 -0
  50. data/docs/guide/cli/subset.md +118 -0
  51. data/docs/guide/cli/validate.md +139 -0
  52. data/docs/guide/color-fonts/bitmaps.md +177 -0
  53. data/docs/guide/color-fonts/colr-cpal.md +175 -0
  54. data/docs/guide/color-fonts/index.md +140 -0
  55. data/docs/guide/color-fonts/svg.md +154 -0
  56. data/docs/guide/color.md +51 -0
  57. data/docs/guide/comparisons/font-validator.md +222 -0
  58. data/docs/guide/comparisons/fonttools.md +200 -0
  59. data/docs/guide/comparisons/index.md +83 -0
  60. data/docs/guide/comparisons/lcdf-typetools.md +205 -0
  61. data/docs/guide/contributing.md +279 -0
  62. data/docs/guide/conversion/collections.md +251 -0
  63. data/docs/guide/conversion/curves.md +246 -0
  64. data/docs/guide/conversion/index.md +157 -0
  65. data/docs/guide/conversion/options.md +251 -0
  66. data/docs/guide/conversion/ttf-otf.md +184 -0
  67. data/docs/guide/conversion/type1.md +208 -0
  68. data/docs/guide/conversion/web.md +240 -0
  69. data/docs/guide/conversion.md +39 -0
  70. data/docs/guide/formats/collections.md +147 -0
  71. data/docs/guide/formats/dfont.md +99 -0
  72. data/docs/guide/formats/index.md +65 -0
  73. data/docs/guide/formats/otf.md +103 -0
  74. data/docs/guide/formats/svg.md +97 -0
  75. data/docs/guide/formats/ttf.md +105 -0
  76. data/docs/guide/formats/type1.md +118 -0
  77. data/docs/guide/formats/woff.md +115 -0
  78. data/docs/guide/hinting/autohint.md +141 -0
  79. data/docs/guide/hinting/conversion.md +161 -0
  80. data/docs/guide/hinting/index.md +86 -0
  81. data/docs/guide/hinting/postscript.md +149 -0
  82. data/docs/guide/hinting/truetype.md +135 -0
  83. data/docs/guide/hinting.md +44 -0
  84. data/docs/guide/index.md +152 -0
  85. data/docs/guide/installation.md +116 -0
  86. data/docs/guide/migrations/extract-ttc.md +549 -0
  87. data/docs/guide/migrations/font-validator.md +260 -0
  88. data/docs/guide/migrations/fonttools.md +208 -0
  89. data/docs/guide/migrations/index.md +64 -0
  90. data/docs/guide/migrations/otfinfo.md +197 -0
  91. data/docs/guide/quick-start.md +204 -0
  92. data/docs/guide/type1.md +58 -0
  93. data/docs/guide/universal-outline.md +151 -0
  94. data/docs/guide/validation/custom.md +195 -0
  95. data/docs/guide/validation/helpers.md +188 -0
  96. data/docs/guide/validation/index.md +132 -0
  97. data/docs/guide/validation/profiles.md +156 -0
  98. data/docs/guide/validation.md +47 -0
  99. data/docs/guide/variable-fonts/advanced.md +231 -0
  100. data/docs/guide/variable-fonts/axes.md +209 -0
  101. data/docs/guide/variable-fonts/conversion.md +197 -0
  102. data/docs/guide/variable-fonts/index.md +84 -0
  103. data/docs/guide/variable-fonts/instances.md +187 -0
  104. data/docs/guide/variable-fonts/named-instances.md +194 -0
  105. data/docs/guide/variable-fonts/static.md +168 -0
  106. data/docs/guide/variable.md +58 -0
  107. data/docs/guide/woff.md +59 -0
  108. data/docs/index.md +136 -0
  109. data/docs/lychee.toml +37 -0
  110. data/docs/package-lock.json +2560 -0
  111. data/docs/package.json +15 -0
  112. data/docs/public/apple-touch-icon.png +0 -0
  113. data/docs/public/favicon-96x96.png +0 -0
  114. data/docs/public/favicon.ico +0 -0
  115. data/docs/public/favicon.svg +1 -0
  116. data/docs/public/logo-full.svg +1 -0
  117. data/docs/public/logo.svg +1 -0
  118. data/docs/public/site.webmanifest +21 -0
  119. data/docs/public/web-app-manifest-192x192.png +0 -0
  120. data/docs/public/web-app-manifest-512x512.png +0 -0
  121. data/fontisan.gemspec +1 -1
  122. data/lib/fontisan/commands/features_command.rb +0 -1
  123. data/lib/fontisan/commands/scripts_command.rb +0 -1
  124. data/lib/fontisan/loading_modes.rb +0 -2
  125. data/lib/fontisan/sfnt_font.rb +4 -3
  126. data/lib/fontisan/tables/glyf/compound_glyph.rb +0 -1
  127. data/lib/fontisan/variable/delta_applicator.rb +3 -3
  128. data/lib/fontisan/variation/optimizer.rb +0 -1
  129. data/lib/fontisan/version.rb +1 -1
  130. data/lib/fontisan.rb +3 -2
  131. metadata +122 -4
@@ -0,0 +1,87 @@
1
+ <template>
2
+ <table class="feature-comparison">
3
+ <thead>
4
+ <tr>
5
+ <th>Feature</th>
6
+ <th v-for="tool in tools" :key="tool">{{ tool }}</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <tr v-for="feature in features" :key="feature.name">
11
+ <td class="feature-name">{{ feature.name }}</td>
12
+ <td
13
+ v-for="(tool, index) in tools"
14
+ :key="tool"
15
+ :class="getSupportClass(feature.support[index])"
16
+ >
17
+ <span class="support-icon">{{ getSupportIcon(feature.support[index]) }}</span>
18
+ <span v-if="feature.notes?.[index]" class="note">{{ feature.notes[index] }}</span>
19
+ </td>
20
+ </tr>
21
+ </tbody>
22
+ </table>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ interface Feature {
27
+ name: string;
28
+ support: boolean[];
29
+ notes?: string[];
30
+ }
31
+
32
+ defineProps<{
33
+ tools: string[];
34
+ features: Feature[];
35
+ }>();
36
+
37
+ function getSupportIcon(supported: boolean): string {
38
+ return supported ? "✓" : "✗";
39
+ }
40
+
41
+ function getSupportClass(supported: boolean): string {
42
+ return supported ? "supported" : "not-supported";
43
+ }
44
+ </script>
45
+
46
+ <style scoped>
47
+ .feature-comparison {
48
+ width: 100%;
49
+ border-collapse: collapse;
50
+ margin: 1rem 0;
51
+ }
52
+
53
+ .feature-comparison th,
54
+ .feature-comparison td {
55
+ padding: 0.75rem 1rem;
56
+ text-align: left;
57
+ border-bottom: 1px solid var(--vp-c-divider);
58
+ }
59
+
60
+ .feature-comparison th {
61
+ background: var(--vp-c-bg-soft);
62
+ font-weight: 600;
63
+ }
64
+
65
+ .feature-name {
66
+ font-weight: 500;
67
+ }
68
+
69
+ .supported {
70
+ color: var(--vp-c-green-1);
71
+ }
72
+
73
+ .not-supported {
74
+ color: var(--vp-c-red-1);
75
+ }
76
+
77
+ .support-icon {
78
+ font-weight: bold;
79
+ }
80
+
81
+ .note {
82
+ display: block;
83
+ font-size: 0.85rem;
84
+ color: var(--vp-c-text-2);
85
+ margin-top: 0.25rem;
86
+ }
87
+ </style>
@@ -0,0 +1,98 @@
1
+ <script setup>
2
+ defineProps({
3
+ title: {
4
+ type: String,
5
+ default: 'Terminal'
6
+ }
7
+ })
8
+ </script>
9
+
10
+ <template>
11
+ <div class="hero-code-block">
12
+ <div class="code-header">
13
+ <span class="dot"></span>
14
+ <span class="dot"></span>
15
+ <span class="dot"></span>
16
+ <span class="code-title">{{ title }}</span>
17
+ </div>
18
+ <div class="code-content"><slot /></div>
19
+ </div>
20
+ </template>
21
+
22
+ <style scoped>
23
+ .hero-code-block {
24
+ background: var(--vp-c-bg-soft);
25
+ border: 1px solid var(--vp-c-divider);
26
+ border-radius: 12px;
27
+ overflow: hidden;
28
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
29
+ max-width: 550px;
30
+ width: 100%;
31
+ font-size: 0.85rem;
32
+ }
33
+
34
+ @media (max-width: 768px) {
35
+ .hero-code-block {
36
+ max-width: 100%;
37
+ font-size: 0.8rem;
38
+ }
39
+ }
40
+
41
+ .code-header {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 0.5rem;
45
+ padding: 0.75rem 1rem;
46
+ background: var(--vp-c-bg-alt);
47
+ border-bottom: 1px solid var(--vp-c-divider);
48
+ }
49
+
50
+ .dot {
51
+ width: 12px;
52
+ height: 12px;
53
+ border-radius: 50%;
54
+ flex-shrink: 0;
55
+ }
56
+
57
+ .dot:nth-child(1) { background: #ff5f56; }
58
+ .dot:nth-child(2) { background: #ffbd2e; }
59
+ .dot:nth-child(3) { background: #28c840; }
60
+
61
+ .code-title {
62
+ margin-left: auto;
63
+ font-size: 0.8rem;
64
+ color: var(--vp-c-text-3);
65
+ }
66
+
67
+ .code-content {
68
+ margin: 0;
69
+ padding: 1.25rem;
70
+ font-family: var(--vp-font-family-mono);
71
+ font-size: inherit;
72
+ line-height: 1.7;
73
+ overflow-x: auto;
74
+ -webkit-overflow-scrolling: touch;
75
+ }
76
+
77
+ .code-content :deep(.line) {
78
+ display: block;
79
+ }
80
+
81
+ .code-content :deep(.prompt) {
82
+ color: var(--vp-c-brand-1);
83
+ font-weight: 500;
84
+ }
85
+
86
+ .code-content :deep(.success) {
87
+ color: #28c840;
88
+ }
89
+
90
+ .code-content :deep(.comment) {
91
+ color: var(--vp-c-text-3);
92
+ font-style: italic;
93
+ }
94
+
95
+ .code-content :deep(.cmd) {
96
+ font-weight: 600;
97
+ }
98
+ </style>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <ClientOnly>
3
+ <Teleport to=".VPHero > .container">
4
+ <div class="within-hero__slot-container">
5
+ <slot />
6
+ </div>
7
+ </Teleport>
8
+ </ClientOnly>
9
+ </template>
10
+
11
+ <style>
12
+ .within-hero__slot-container {
13
+ order: 2;
14
+ }
15
+
16
+ .VPHero > .container > .main {
17
+ width: unset;
18
+ flex-shrink: unset;
19
+ }
20
+
21
+ .VPHero > .container {
22
+ gap: 32px;
23
+ }
24
+
25
+ @media (min-width: 960px) {
26
+ .VPHero > .container {
27
+ gap: 64px;
28
+ }
29
+ }
30
+ </style>
@@ -0,0 +1,22 @@
1
+ import DefaultTheme from "vitepress/theme";
2
+ import type { Theme } from "vitepress";
3
+ import "./style.css";
4
+
5
+ // Import custom components
6
+ import FeatureComparison from "./components/FeatureComparison.vue";
7
+ import Badge from "./components/Badge.vue";
8
+ import ApiMethod from "./components/ApiMethod.vue";
9
+ import HeroCodeBlock from "./components/HeroCodeBlock.vue";
10
+ import WithinHero from "./components/WithinHero.vue";
11
+
12
+ export default {
13
+ extends: DefaultTheme,
14
+ enhanceApp({ app }) {
15
+ // Register global components
16
+ app.component("FeatureComparison", FeatureComparison);
17
+ app.component("Badge", Badge);
18
+ app.component("ApiMethod", ApiMethod);
19
+ app.component("HeroCodeBlock", HeroCodeBlock);
20
+ app.component("WithinHero", WithinHero);
21
+ },
22
+ } satisfies Theme;
@@ -0,0 +1,330 @@
1
+ :root {
2
+ /* Brand Colors from Logo */
3
+ --fontist-rose: #bf4e6a;
4
+ --fontist-rose-light: #d4718a;
5
+ --fontist-dark: #4d4b54;
6
+ --fontist-gray: #676565;
7
+ --fontist-cream: #e1dfd2;
8
+ --fontist-beige: #bebbac;
9
+ --fontist-pale: #dddac8;
10
+
11
+ /* VitePress Theme Overrides - Light Mode */
12
+ --vp-c-brand-1: var(--fontist-rose);
13
+ --vp-c-brand-2: #a3435a;
14
+ --vp-c-brand-3: var(--fontist-dark);
15
+ --vp-c-brand-soft: rgba(191, 78, 106, 0.14);
16
+
17
+ /* Text Colors */
18
+ --vp-c-text-1: var(--fontist-dark);
19
+ --vp-c-text-2: var(--fontist-gray);
20
+ --vp-c-text-3: #8a8888;
21
+
22
+ /* Background Colors */
23
+ --vp-c-bg-soft: #f8f7f4;
24
+ --vp-c-bg-alt: #f2f1ed;
25
+ --vp-c-bg: #ffffff;
26
+
27
+ /* Hero */
28
+ --vp-home-hero-name-color: var(--fontist-rose);
29
+ --vp-home-hero-name-background: linear-gradient(
30
+ 120deg,
31
+ var(--fontist-rose) 30%,
32
+ #d4718a
33
+ );
34
+
35
+ /* Buttons */
36
+ --vp-button-brand-border: var(--fontist-rose);
37
+ --vp-button-brand-text: #ffffff;
38
+ --vp-button-brand-bg: var(--fontist-rose);
39
+ --vp-button-brand-hover-border: #a3435a;
40
+ --vp-button-brand-hover-text: #ffffff;
41
+ --vp-button-brand-hover-bg: #a3435a;
42
+ --vp-button-brand-active-border: #8a3849;
43
+ --vp-button-brand-active-text: #ffffff;
44
+ --vp-button-brand-active-bg: #8a3849;
45
+
46
+ /* Sidebar */
47
+ --vp-sidebar-bg-color: var(--vp-c-bg-soft);
48
+
49
+ /* Nav */
50
+ --vp-nav-bg-color: var(--vp-c-bg);
51
+ }
52
+
53
+ /* Dark Mode */
54
+ html.dark {
55
+ --vp-c-brand-1: var(--fontist-rose-light);
56
+ --vp-c-brand-2: var(--fontist-rose);
57
+ --vp-c-brand-3: #e1dfd2;
58
+ --vp-c-brand-soft: rgba(212, 113, 138, 0.14);
59
+
60
+ /* Text Colors - Dark Mode */
61
+ --vp-c-text-1: #e1dfd2;
62
+ --vp-c-text-2: #bebbac;
63
+ --vp-c-text-3: #8a8888;
64
+
65
+ /* Background Colors - Dark Mode */
66
+ --vp-c-bg: #1a1918;
67
+ --vp-c-bg-soft: #222120;
68
+ --vp-c-bg-alt: #2a2826;
69
+ --vp-c-bg-elv: #2a2826;
70
+
71
+ /* Hero - Dark Mode */
72
+ --vp-home-hero-name-background: linear-gradient(
73
+ 120deg,
74
+ var(--fontist-rose-light) 30%,
75
+ #e08a9e
76
+ );
77
+
78
+ /* Buttons - Dark Mode */
79
+ --vp-button-brand-border: var(--fontist-rose-light);
80
+ --vp-button-brand-text: #1a1918;
81
+ --vp-button-brand-bg: var(--fontist-rose-light);
82
+ --vp-button-brand-hover-border: var(--fontist-rose);
83
+ --vp-button-brand-hover-text: #1a1918;
84
+ --vp-button-brand-hover-bg: var(--fontist-rose);
85
+ --vp-button-brand-active-border: #a3435a;
86
+ --vp-button-brand-active-text: #1a1918;
87
+ --vp-button-brand-active-bg: #a3435a;
88
+ }
89
+
90
+ /* Feature cards on home page - Light */
91
+ .VPFeature .title {
92
+ color: var(--fontist-dark);
93
+ }
94
+
95
+ .VPFeature .details {
96
+ color: var(--fontist-gray);
97
+ }
98
+
99
+ .VPFeature:hover {
100
+ border-color: var(--fontist-rose);
101
+ }
102
+
103
+ /* Feature cards - Dark */
104
+ html.dark .VPFeature .title {
105
+ color: var(--fontist-cream);
106
+ }
107
+
108
+ html.dark .VPFeature .details {
109
+ color: var(--fontist-beige);
110
+ }
111
+
112
+ /* Links */
113
+ .vp-doc a {
114
+ color: var(--fontist-rose);
115
+ }
116
+
117
+ .vp-doc a:hover {
118
+ color: #a3435a;
119
+ }
120
+
121
+ html.dark .vp-doc a {
122
+ color: var(--fontist-rose-light);
123
+ }
124
+
125
+ html.dark .vp-doc a:hover {
126
+ color: var(--fontist-rose);
127
+ }
128
+
129
+ /* Footer */
130
+ .VPFooter {
131
+ background-color: var(--vp-c-bg-soft);
132
+ border-top: 1px solid var(--fontist-pale);
133
+ }
134
+
135
+ html.dark .VPFooter {
136
+ border-top-color: #3a3836;
137
+ }
138
+
139
+ /* Code blocks - Light */
140
+ .vp-doc [class*="language-"] {
141
+ background-color: var(--fontist-dark);
142
+ }
143
+
144
+ /* Code blocks - Dark */
145
+ html.dark .vp-doc [class*="language-"] {
146
+ background-color: #0d0c0c;
147
+ }
148
+
149
+ /* Logo sizing */
150
+ .VPNav .VPImage {
151
+ height: 39px;
152
+ }
153
+
154
+ /* Search */
155
+ .VPLocalSearchBox {
156
+ --vp-c-brand-1: var(--fontist-rose);
157
+ }
158
+
159
+ /* Feature Comparison Tables */
160
+ .feature-comparison {
161
+ width: 100%;
162
+ border-collapse: collapse;
163
+ margin: 1.5rem 0;
164
+ font-size: 0.9rem;
165
+ }
166
+
167
+ .feature-comparison th,
168
+ .feature-comparison td {
169
+ padding: 0.75rem 1rem;
170
+ text-align: left;
171
+ border-bottom: 1px solid var(--vp-c-divider);
172
+ }
173
+
174
+ .feature-comparison th {
175
+ background: var(--vp-c-bg-soft);
176
+ font-weight: 600;
177
+ white-space: nowrap;
178
+ }
179
+
180
+ .feature-comparison .feature-name {
181
+ font-weight: 500;
182
+ }
183
+
184
+ .feature-comparison .supported {
185
+ color: var(--vp-c-green-1);
186
+ }
187
+
188
+ .feature-comparison .not-supported {
189
+ color: var(--vp-c-red-1);
190
+ }
191
+
192
+ .feature-comparison .advantage {
193
+ background: linear-gradient(
194
+ 135deg,
195
+ rgba(191, 78, 106, 0.1) 0%,
196
+ rgba(212, 113, 138, 0.05) 100%
197
+ );
198
+ }
199
+
200
+ /* Badge styles */
201
+ .badge {
202
+ display: inline-flex;
203
+ align-items: center;
204
+ padding: 0.125rem 0.625rem;
205
+ border-radius: 9999px;
206
+ font-size: 0.75rem;
207
+ font-weight: 600;
208
+ line-height: 1.25rem;
209
+ vertical-align: middle;
210
+ }
211
+
212
+ .badge.pure-ruby {
213
+ background: linear-gradient(135deg, var(--fontist-rose), #d4718a);
214
+ color: white;
215
+ font-weight: 700;
216
+ text-transform: uppercase;
217
+ letter-spacing: 0.05em;
218
+ }
219
+
220
+ .badge.tip {
221
+ background-color: var(--vp-c-brand-soft);
222
+ color: var(--vp-c-brand-1);
223
+ }
224
+
225
+ .badge.preview {
226
+ background-color: rgba(255, 197, 61, 0.14);
227
+ color: #c4a226;
228
+ }
229
+
230
+ .badge.planned {
231
+ background-color: rgba(96, 165, 250, 0.14);
232
+ color: #60a5fa;
233
+ }
234
+
235
+ /* Home page enhancements */
236
+ .my-index-page .VPHero .name {
237
+ display: flex;
238
+ align-items: center;
239
+ gap: 0.5rem;
240
+ }
241
+
242
+ .my-index-page .VPHero .tagline {
243
+ font-size: 1.25rem !important;
244
+ opacity: 0.9;
245
+ }
246
+
247
+ /* Pure Ruby badge on hero */
248
+ .pure-ruby-hero {
249
+ display: inline-flex;
250
+ align-items: center;
251
+ gap: 0.5rem;
252
+ padding: 0.25rem 0.75rem;
253
+ background: linear-gradient(135deg, var(--fontist-rose), #d4718a);
254
+ color: white;
255
+ border-radius: 9999px;
256
+ font-size: 0.85rem;
257
+ font-weight: 700;
258
+ text-transform: uppercase;
259
+ letter-spacing: 0.05em;
260
+ margin-top: 1rem;
261
+ }
262
+
263
+ /* Code comparison blocks */
264
+ .code-comparison {
265
+ display: grid;
266
+ grid-template-columns: 1fr 1fr;
267
+ gap: 1rem;
268
+ margin: 1.5rem 0;
269
+ }
270
+
271
+ @media (max-width: 768px) {
272
+ .code-comparison {
273
+ grid-template-columns: 1fr;
274
+ }
275
+ }
276
+
277
+ .code-comparison > div {
278
+ background: var(--vp-c-bg-soft);
279
+ border-radius: 8px;
280
+ overflow: hidden;
281
+ }
282
+
283
+ .code-comparison h4 {
284
+ margin: 0;
285
+ padding: 0.75rem 1rem;
286
+ background: var(--vp-c-bg-alt);
287
+ font-size: 0.85rem;
288
+ font-weight: 600;
289
+ border-bottom: 1px solid var(--vp-c-divider);
290
+ }
291
+
292
+ /* CLI command reference */
293
+ .cli-command {
294
+ padding: 1rem;
295
+ margin: 1rem 0;
296
+ background: var(--vp-c-bg-soft);
297
+ border-radius: 8px;
298
+ border-left: 3px solid var(--fontist-rose);
299
+ }
300
+
301
+ .cli-command code {
302
+ font-weight: 500;
303
+ }
304
+
305
+ /* Info boxes */
306
+ .custom-block {
307
+ margin: 1.5rem 0;
308
+ padding: 1rem 1.25rem;
309
+ border-radius: 8px;
310
+ }
311
+
312
+ .custom-block.tip {
313
+ border-left: 4px solid var(--fontist-rose);
314
+ background: rgba(191, 78, 106, 0.08);
315
+ }
316
+
317
+ .custom-block.warning {
318
+ border-left: 4px solid #ffc53d;
319
+ background: rgba(255, 197, 61, 0.08);
320
+ }
321
+
322
+ .custom-block.danger {
323
+ border-left: 4px solid #f43f5e;
324
+ background: rgba(244, 63, 94, 0.08);
325
+ }
326
+
327
+ .custom-block.info {
328
+ border-left: 4px solid #60a5fa;
329
+ background: rgba(96, 165, 250, 0.08);
330
+ }
@@ -0,0 +1,141 @@
1
+ ---
2
+ title: ConversionOptions
3
+ ---
4
+
5
+ # ConversionOptions
6
+
7
+ Type-safe conversion configuration.
8
+
9
+ ## Overview
10
+
11
+ `Fontisan::ConversionOptions` provides a type-safe way to configure font conversions.
12
+
13
+ ## Class Methods
14
+
15
+ ### recommended(from:, to:)
16
+
17
+ Get recommended options for a conversion type.
18
+
19
+ ```ruby
20
+ options = Fontisan::ConversionOptions.recommended(from: :ttf, to: :otf)
21
+ # => #<Fontisan::ConversionOptions ...>
22
+
23
+ # Access settings
24
+ options.opening # => { convert_curves: true, ... }
25
+ options.generating # => { hinting_mode: "auto", ... }
26
+ ```
27
+
28
+ **Parameters:**
29
+
30
+ | Name | Type | Description |
31
+ |------|------|-------------|
32
+ | from | Symbol | Source format |
33
+ | to | Symbol | Target format |
34
+
35
+ ### from_preset(name)
36
+
37
+ Load options from a named preset.
38
+
39
+ ```ruby
40
+ # Web optimization preset
41
+ options = Fontisan::ConversionOptions.from_preset(:web_optimized)
42
+
43
+ # Type 1 to modern
44
+ options = Fontisan::ConversionOptions.from_preset(:type1_to_modern)
45
+ ```
46
+
47
+ **Available Presets:**
48
+
49
+ | Preset | From | To |
50
+ |--------|------|-----|
51
+ | `type1_to_modern` | Type 1 | OTF |
52
+ | `modern_to_type1` | OTF | Type 1 |
53
+ | `web_optimized` | OTF | WOFF2 |
54
+ | `archive_to_modern` | TTC | OTF |
55
+
56
+ ### new(**kwargs)
57
+
58
+ Create custom options.
59
+
60
+ ```ruby
61
+ options = Fontisan::ConversionOptions.new(
62
+ from: :ttf,
63
+ to: :otf,
64
+ opening: {
65
+ convert_curves: true,
66
+ autohint: true
67
+ },
68
+ generating: {
69
+ hinting_mode: 'auto',
70
+ optimize_tables: true
71
+ }
72
+ )
73
+ ```
74
+
75
+ ## Instance Attributes
76
+
77
+ ### opening
78
+
79
+ Opening options control source font processing.
80
+
81
+ | Option | Type | Default |
82
+ |--------|------|---------|
83
+ | `decompose_composites` | Boolean | false |
84
+ | `convert_curves` | Boolean | true |
85
+ | `scale_to_1000` | Boolean | false |
86
+ | `scale_from_1000` | Boolean | false |
87
+ | `autohint` | Boolean | false |
88
+ | `generate_unicode` | Boolean | false |
89
+ | `store_custom_tables` | Boolean | true |
90
+ | `store_native_hinting` | Boolean | false |
91
+ | `interpret_ot` | Boolean | false |
92
+ | `read_all_records` | Boolean | false |
93
+ | `preserve_encoding` | String | nil |
94
+
95
+ ### generating
96
+
97
+ Generating options control output font writing.
98
+
99
+ | Option | Type | Default |
100
+ |--------|------|---------|
101
+ | `write_pfm` | Boolean | false |
102
+ | `write_afm` | Boolean | false |
103
+ | `write_inf` | Boolean | false |
104
+ | `select_encoding_automatically` | Boolean | false |
105
+ | `hinting_mode` | String | 'preserve' |
106
+ | `decompose_on_output` | Boolean | false |
107
+ | `write_custom_tables` | Boolean | true |
108
+ | `optimize_tables` | Boolean | false |
109
+ | `compression` | String | nil |
110
+ | `transform_tables` | Boolean | false |
111
+ | `preserve_metadata` | Boolean | true |
112
+
113
+ ## Examples
114
+
115
+ ### Basic Conversion
116
+
117
+ ```ruby
118
+ options = Fontisan::ConversionOptions.recommended(from: :ttf, to: :otf)
119
+ converter = Fontisan::Converters::OutlineConverter.new
120
+ result = converter.convert(font, options: options)
121
+ ```
122
+
123
+ ### Web Optimization
124
+
125
+ ```ruby
126
+ options = Fontisan::ConversionOptions.from_preset(:web_optimized)
127
+ Fontisan::FontWriter.write(font, 'output.woff2', options: options)
128
+ ```
129
+
130
+ ### Custom Options
131
+
132
+ ```ruby
133
+ options = Fontisan::ConversionOptions.new(
134
+ opening: { autohint: true },
135
+ generating: {
136
+ hinting_mode: 'auto',
137
+ optimize_tables: true,
138
+ compression: 'brotli'
139
+ }
140
+ )
141
+ ```