@jjlmoya/utils-developer 1.15.0 → 1.17.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.
Files changed (63) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +3 -1
  3. package/src/entries.ts +7 -1
  4. package/src/index.ts +4 -0
  5. package/src/tests/locale_completeness.test.ts +2 -3
  6. package/src/tests/pagespeed_best_practices.test.ts +198 -0
  7. package/src/tests/tool_validation.test.ts +2 -2
  8. package/src/tool/aspectRatio/component.astro +3 -1
  9. package/src/tool/colorConverter/component.astro +3 -3
  10. package/src/tool/jwtDecoder/bibliography.astro +14 -0
  11. package/src/tool/jwtDecoder/bibliography.ts +12 -0
  12. package/src/tool/jwtDecoder/component.astro +209 -0
  13. package/src/tool/jwtDecoder/entry.ts +30 -0
  14. package/src/tool/jwtDecoder/i18n/de.ts +248 -0
  15. package/src/tool/jwtDecoder/i18n/en.ts +247 -0
  16. package/src/tool/jwtDecoder/i18n/es.ts +248 -0
  17. package/src/tool/jwtDecoder/i18n/fr.ts +248 -0
  18. package/src/tool/jwtDecoder/i18n/id.ts +248 -0
  19. package/src/tool/jwtDecoder/i18n/it.ts +248 -0
  20. package/src/tool/jwtDecoder/i18n/ja.ts +248 -0
  21. package/src/tool/jwtDecoder/i18n/ko.ts +248 -0
  22. package/src/tool/jwtDecoder/i18n/nl.ts +247 -0
  23. package/src/tool/jwtDecoder/i18n/pl.ts +247 -0
  24. package/src/tool/jwtDecoder/i18n/pt.ts +247 -0
  25. package/src/tool/jwtDecoder/i18n/ru.ts +248 -0
  26. package/src/tool/jwtDecoder/i18n/sv.ts +248 -0
  27. package/src/tool/jwtDecoder/i18n/tr.ts +248 -0
  28. package/src/tool/jwtDecoder/i18n/zh.ts +248 -0
  29. package/src/tool/jwtDecoder/index.ts +11 -0
  30. package/src/tool/jwtDecoder/jwt-decoder-parser-and-claims-inspector.css +358 -0
  31. package/src/tool/jwtDecoder/logic.ts +96 -0
  32. package/src/tool/jwtDecoder/seo.astro +15 -0
  33. package/src/tool/jwtDecoder/ui.ts +38 -0
  34. package/src/tool/llmCostCalculator/component.astro +1 -2
  35. package/src/tool/mobileMockupGenerator/component.astro +4 -5
  36. package/src/tool/placeholderGenerator/component.astro +2 -2
  37. package/src/tool/readabilityCalculator/component.astro +4 -4
  38. package/src/tool/serpPixelSimulator/bibliography.astro +14 -0
  39. package/src/tool/serpPixelSimulator/bibliography.ts +16 -0
  40. package/src/tool/serpPixelSimulator/component.astro +84 -0
  41. package/src/tool/serpPixelSimulator/controller.ts +323 -0
  42. package/src/tool/serpPixelSimulator/entry.ts +30 -0
  43. package/src/tool/serpPixelSimulator/i18n/de.ts +214 -0
  44. package/src/tool/serpPixelSimulator/i18n/en.ts +213 -0
  45. package/src/tool/serpPixelSimulator/i18n/es.ts +214 -0
  46. package/src/tool/serpPixelSimulator/i18n/fr.ts +214 -0
  47. package/src/tool/serpPixelSimulator/i18n/id.ts +214 -0
  48. package/src/tool/serpPixelSimulator/i18n/it.ts +214 -0
  49. package/src/tool/serpPixelSimulator/i18n/ja.ts +214 -0
  50. package/src/tool/serpPixelSimulator/i18n/ko.ts +214 -0
  51. package/src/tool/serpPixelSimulator/i18n/nl.ts +214 -0
  52. package/src/tool/serpPixelSimulator/i18n/pl.ts +214 -0
  53. package/src/tool/serpPixelSimulator/i18n/pt.ts +214 -0
  54. package/src/tool/serpPixelSimulator/i18n/ru.ts +214 -0
  55. package/src/tool/serpPixelSimulator/i18n/sv.ts +214 -0
  56. package/src/tool/serpPixelSimulator/i18n/tr.ts +214 -0
  57. package/src/tool/serpPixelSimulator/i18n/zh.ts +214 -0
  58. package/src/tool/serpPixelSimulator/index.ts +8 -0
  59. package/src/tool/serpPixelSimulator/logic.ts +18 -0
  60. package/src/tool/serpPixelSimulator/seo.astro +15 -0
  61. package/src/tool/serpPixelSimulator/serp-pixel-simulator.css +335 -0
  62. package/src/tool/serpPixelSimulator/ui.ts +33 -0
  63. package/src/tools.ts +3 -2
@@ -0,0 +1,214 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { SerpPixelSimulatorUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'serp-simulator-pixel-zaehler';
7
+ const title = 'SERP Simulator und SEO Pixelzähler';
8
+ const description = 'Vorschau von Google-ähnlichen Such-Snippets in Echtzeit, messen Sie die Breite von Titel und Meta-Beschreibung in Pixeln und sehen Sie genau, wo Ihr Text abgeschnitten wird.';
9
+
10
+ const howTo = [
11
+ {
12
+ name: 'Geben Sie den Title-Tag ein',
13
+ text: 'Tippen oder fügen Sie den Seitentitel ein, den Sie testen möchten. Die SERP-Vorschau und der Pixelmesser werden bei jedem Tastendruck aktualisiert.',
14
+ },
15
+ {
16
+ name: 'Fügen Sie die sichtbare URL hinzu',
17
+ text: 'Verwenden Sie eine realistische Domain und einen Pfad, damit das Snippet dem Ergebnis ähnelt, das ein Suchender scannen würde.',
18
+ },
19
+ {
20
+ name: 'Schreiben Sie die Meta-Beschreibung',
21
+ text: 'Fügen Sie den Beschreibungstext hinzu und beobachten Sie den Pixelbalken. Wenn er die empfohlene visuelle Breite überschreitet, kürzt die Vorschau ihn mit Auslassungspunkten.',
22
+ },
23
+ {
24
+ name: 'Wechseln Sie zwischen Desktop und Mobilgerät',
25
+ text: 'Vergleichen Sie die Titeldarstellung mit der Desktop- oder mobilen Kartenbreite, bevor Sie Metadaten veröffentlichen.',
26
+ },
27
+ ];
28
+
29
+ const faq = [
30
+ {
31
+ question: 'Warum Pixel statt Zeichen für SEO-Titel zählen?',
32
+ answer: 'Google-Suchergebniskarten sind durch die visuelle Breite begrenzt. Ein Titel mit vielen schmalen Buchstaben kann mehr Zeichen enthalten als ein Titel mit breiten Buchstaben, Großbuchstaben oder fett wirkenden Glyphen. Die Pixelmessung liefert eine genauere Vorschau des sichtbaren Ergebnisses.',
33
+ },
34
+ {
35
+ question: 'Garantiert dies genau, wie Google mein Snippet abschneidet?',
36
+ answer: 'Nein. Google kann Titel-Links und Snippets umschreiben, und die Darstellung kann je nach Suchanfrage, Gerät, Sprache und Experiment variieren. Das Tool ist als praktische visuelle Orientierungshilfe gedacht, um Metadaten zu schreiben, die weniger wahrscheinlich abgeschnitten werden.',
37
+ },
38
+ {
39
+ question: 'Welche Pixelgrenzen verwendet der Simulator?',
40
+ answer: 'Die Standard-Titelgrenze für Desktop beträgt 580 px, für Mobilgeräte 600 px und die Meta-Beschreibungsgrenze liegt bei 920 px. Dies sind Schreibziele, keine offiziellen Google-Grenzwerte.',
41
+ },
42
+ {
43
+ question: 'Warum fügt die Vorschau Auslassungspunkte hinzu?',
44
+ answer: 'Wenn der gemessene Text die verfügbare Pixelbreite überschreitet, kürzt der Simulator die Zeichenkette am letzten passenden Zeichen und hängt drei Punkte an, was dem praktischen Verhalten entspricht, das SEO-Teams benötigen, um Bedeutungsverlust zu erkennen.',
45
+ },
46
+ ];
47
+
48
+ const ui: SerpPixelSimulatorUI = {
49
+ titleLabel: 'Title-Tag',
50
+ titlePlaceholder: 'GameBob | Indie-Entwicklungsstudio',
51
+ urlLabel: 'Sichtbare URL',
52
+ urlPlaceholder: 'https://www.gamebob.dev/de/',
53
+ descriptionLabel: 'Meta-Beschreibung',
54
+ descriptionPlaceholder: 'Entdecken Sie unsere Sammlung von Tools und Spielen, die Ihren digitalen Workflow und Ihre Unterhaltung bereichern.',
55
+ deviceLabel: 'Vorschaumodus',
56
+ desktopLabel: 'Desktop',
57
+ mobileLabel: 'Mobil',
58
+ titlePixelsLabel: 'Titelbreite',
59
+ descriptionPixelsLabel: 'Beschreibungsbreite',
60
+ charactersLabel: 'Zeichen',
61
+ previewLabel: 'Live-Vorschau im Google-Stil',
62
+ tooLongLabel: 'Zu breit',
63
+ goodLabel: 'Passt',
64
+ emptyTitle: 'Ihr Titel erscheint hier',
65
+ emptyDescription: 'Die Vorschau Ihrer Meta-Beschreibung erscheint hier, während Sie tippen.',
66
+ defaultTitle: 'GameBob | Indie-Entwicklungsstudio',
67
+ defaultUrl: 'https://www.gamebob.dev/de/',
68
+ defaultDescription: 'Entdecken Sie unsere Sammlung von Tools und Spielen, die Ihren digitalen Workflow und Ihre Unterhaltung bereichern.',
69
+ fallbackUrl: 'beispiel.de',
70
+ fallbackFaviconText: 'G',
71
+ pixelUnit: 'px',
72
+ ellipsis: '...',
73
+ fetchButtonLabel: 'Abrufen',
74
+ fetchLoadingLabel: 'Wird abgerufen...',
75
+ fetchSuccessLabel: 'Metadaten von der URL geladen.',
76
+ fetchCorsError: 'Der Browser konnte diese Seite nicht lesen. Sie könnte durch CORS, eine Weiterleitung, gemischten Inhalt oder eine Netzwerkregel blockiert sein. Sie können die Metadaten weiterhin manuell einfügen oder bearbeiten.',
77
+ fetchInvalidUrlError: 'Geben Sie eine gültige URL ein, bevor Sie Metadaten abrufen.',
78
+ fetchNoMetadataError: 'Die Seite wurde abgerufen, aber es wurde kein Titel oder keine Meta-Beschreibung gefunden.',
79
+ fetchGenericError: 'Metadaten konnten von dieser URL nicht abgerufen werden. Überprüfen Sie die Adresse oder füllen Sie die Felder manuell aus.',
80
+ };
81
+
82
+ const faqSchema: WithContext<FAQPage> = {
83
+ '@context': 'https://schema.org',
84
+ '@type': 'FAQPage',
85
+ mainEntity: faq.map((item) => ({
86
+ '@type': 'Question',
87
+ name: item.question,
88
+ acceptedAnswer: {
89
+ '@type': 'Answer',
90
+ text: item.answer,
91
+ },
92
+ })),
93
+ };
94
+
95
+ const howToSchema: WithContext<HowTo> = {
96
+ '@context': 'https://schema.org',
97
+ '@type': 'HowTo',
98
+ name: title,
99
+ description,
100
+ step: howTo.map((step, index) => ({
101
+ '@type': 'HowToStep',
102
+ position: index + 1,
103
+ name: step.name,
104
+ text: step.text,
105
+ })),
106
+ };
107
+
108
+ const appSchema: WithContext<SoftwareApplication> = {
109
+ '@context': 'https://schema.org',
110
+ '@type': 'SoftwareApplication',
111
+ name: title,
112
+ description,
113
+ applicationCategory: 'BusinessApplication',
114
+ operatingSystem: 'Any',
115
+ offers: {
116
+ '@type': 'Offer',
117
+ price: '0',
118
+ priceCurrency: 'EUR',
119
+ },
120
+ inLanguage: 'de',
121
+ };
122
+
123
+ export const content: ToolLocaleContent<SerpPixelSimulatorUI> = {
124
+ slug,
125
+ title,
126
+ description,
127
+ ui,
128
+ faqTitle: 'Häufig gestellte Fragen zum SERP-Simulator',
129
+ faq,
130
+ bibliographyTitle: 'Dokumentation zu Suchergebnissen',
131
+ bibliography,
132
+ howTo,
133
+ schemas: [appSchema, faqSchema, howToSchema],
134
+ seo: [
135
+ {
136
+ type: 'title',
137
+ text: 'Hören Sie auf zu raten, wie Ihr Google-Ergebnis aussehen wird',
138
+ level: 2,
139
+ },
140
+ {
141
+ type: 'paragraph',
142
+ html: 'Ein Title-Tag kann in einer Tabelle perfekt aussehen und im Suchergebnis trotzdem versagen. Google reserviert keinen Platz nach Zeichenanzahl; es rendert Text innerhalb einer visuellen Karte. Das bedeutet, dass <strong>GameBob | Indie-Entwicklungsstudio</strong> und ein anderer Titel mit der gleichen Zeichenanzahl je nach Buchstaben, Groß-/Kleinschreibung, Zeichensetzung und Abständen sehr unterschiedliche Breiten einnehmen können.',
143
+ },
144
+ {
145
+ type: 'tip',
146
+ title: 'Die Regel, die wirklich hilft',
147
+ html: 'Schreiben Sie das Snippet so, dass das wichtige Versprechen die Auslassungspunkte überlebt. Platzieren Sie Seitentyp, Suchabsicht und den stärksten Klickgrund vor der Pixelgrenze. Markennamen sind nützlich, sollten aber den Hauptnutzen nicht aus dem Blickfeld drängen.',
148
+ },
149
+ {
150
+ type: 'title',
151
+ text: 'Was der Pixelzähler misst',
152
+ level: 3,
153
+ },
154
+ {
155
+ type: 'table',
156
+ headers: ['Element', 'Was zählt', 'So nutzen Sie das Ergebnis'],
157
+ rows: [
158
+ ['Title-Tag', 'Gerenderte Breite in Pixeln, nicht rohe Zeichenanzahl', 'Halten Sie das Hauptkeyword und das Klickversprechen vor der Kürzung sichtbar.'],
159
+ ['Sichtbare URL', 'Visuelles Vertrauen und Themenklarheit', 'Verwenden Sie einen lesbaren Pfad, der das Ziel des Ergebnisses unterstreicht.'],
160
+ ['Meta-Beschreibung', 'Ein breiterer Snippet-Bereich mit suchanfragenabhängigem Verhalten', 'Stellen Sie den Nutzen an den Anfang, da Google ihn kürzen oder umschreiben kann.'],
161
+ ['Gerätemodus', 'Desktop- und Mobilkarten können sich unterschiedlich anfühlen', 'Überprüfen Sie beide, bevor Sie Metadaten für wichtige Seiten veröffentlichen.'],
162
+ ],
163
+ },
164
+ {
165
+ type: 'title',
166
+ text: 'Warum Zeichenbegrenzungen eine schwache SEO-Gewohnheit sind',
167
+ level: 3,
168
+ },
169
+ {
170
+ type: 'paragraph',
171
+ html: 'Der traditionelle Ratschlag wie "Titel unter 60 Zeichen halten" ist bequem, verschleiert aber das eigentliche Problem. Breite Buchstaben wie W und M, Großbuchstaben, Trennzeichen, Zahlen und lange Markennamen verbrauchen alle unterschiedlichen Platz. Die Pixelmessung macht den Kompromiss sofort sichtbar: Sie können sehen, ob eine Phrase ihren Platz verdient oder Raum von einer stärkeren Botschaft stiehlt.',
172
+ },
173
+ {
174
+ type: 'title',
175
+ text: 'Ein praktischer Workflow für bessere Snippets',
176
+ level: 3,
177
+ },
178
+ {
179
+ type: 'list',
180
+ items: [
181
+ '<strong>Beginnen Sie mit der Absicht:</strong> beschreiben Sie, was der Nutzer bekommt, nicht nur, wie die Seite heißt.',
182
+ '<strong>Testen Sie den vollständigen Titel:</strong> fügen Sie ihn in den Simulator ein und beobachten Sie den Balken vor der Veröffentlichung.',
183
+ '<strong>Entfernen Sie schwache Wörter:</strong> wenn der Balken rot wird, entfernen Sie Füllwörter, bevor Sie wertvolle Begriffe kürzen.',
184
+ '<strong>Prüfen Sie die Auslassungspunkte:</strong> wenn die gekürzte Vorschau an Bedeutung verliert, schreiben Sie den Titel um, anstatt die Kürzung hinzunehmen.',
185
+ '<strong>Wiederholen Sie dies für die Beschreibung:</strong> stellen Sie sicher, dass der erste Satz das Wertversprechen für sich allein trägt.',
186
+ ],
187
+ },
188
+ {
189
+ type: 'diagnostic',
190
+ variant: 'info',
191
+ title: 'Wenn der Balken rot wird',
192
+ html: 'Ein roter Balken ist keine Strafwarnung. Er bedeutet, dass der aktuelle Text breiter ist als das gewählte visuelle Ziel, sodass der Simulator ihn mit Punkten kürzt. Betrachten Sie dies als redaktionelles Signal: Entscheiden Sie, ob die versteckten Wörter verzichtbar sind oder ob das Snippet eine schärfere Struktur benötigt.',
193
+ },
194
+ {
195
+ type: 'title',
196
+ text: 'Grenzen, Umschreibungen und realistische Erwartungen',
197
+ level: 3,
198
+ },
199
+ {
200
+ type: 'paragraph',
201
+ html: 'Kein Simulator kann das exakte Snippet garantieren, das Google anzeigen wird. Google kann Titel-Links umschreiben, Suchbegriffe fett formatieren, Seitentext anstelle der Meta-Beschreibung wählen oder verschiedene Snippets für verschiedene Suchanfragen anzeigen. Dieses Tool eignet sich am besten als schneller Schreib- und QA-Schritt: Es erkennt offensichtlichen visuellen Überlauf, bevor die Seite in die Produktion gelangt.',
202
+ },
203
+ {
204
+ type: 'summary',
205
+ title: 'Beste Nutzung dieses SERP Simulators',
206
+ items: [
207
+ 'Nutzen Sie den Pixelbalken, um visuellen Überlauf vor der Veröffentlichung von Metadaten zu erkennen.',
208
+ 'Halten Sie die Hauptsuchabsicht und das Klickversprechen vor jeder Auslassung sichtbar.',
209
+ 'Rufen Sie Metadaten von URLs ab, die CORS erlauben, und bearbeiten Sie das Ergebnis bei Bedarf manuell.',
210
+ 'Betrachten Sie die Vorschau als Schreibhilfe, denn Google kann Snippets pro Suchanfrage weiterhin umschreiben.',
211
+ ],
212
+ },
213
+ ],
214
+ };
@@ -0,0 +1,213 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { SerpPixelSimulatorUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'serp-pixel-simulator';
7
+ const title = 'SERP Simulator and SEO Pixel Counter';
8
+ const description = 'Preview Google-style search snippets in real time, measure title and meta description width by pixels, and see exactly where your copy will be trimmed.';
9
+
10
+ const howTo = [
11
+ {
12
+ name: 'Enter the title tag',
13
+ text: 'Type or paste the page title you want to test. The SERP preview and pixel meter update on every keystroke.',
14
+ },
15
+ {
16
+ name: 'Add the visible URL',
17
+ text: 'Use a realistic domain and path so the snippet resembles the result a searcher would scan.',
18
+ },
19
+ {
20
+ name: 'Write the meta description',
21
+ text: 'Add the description copy and watch the pixel bar. When it exceeds the recommended visual width, the preview trims it with an ellipsis.',
22
+ },
23
+ {
24
+ name: 'Switch desktop and mobile',
25
+ text: 'Compare title rendering with a desktop or mobile card width before publishing metadata.',
26
+ },
27
+ ];
28
+
29
+ const faq = [
30
+ {
31
+ question: 'Why count pixels instead of characters for SEO titles?',
32
+ answer: 'Google search cards are constrained by visual width. A title with many narrow letters can fit more characters than a title with wide letters, uppercase words, or bold-looking glyphs. Pixel measurement gives a closer preview of the visible result.',
33
+ },
34
+ {
35
+ question: 'Does this guarantee exactly how Google will truncate my snippet?',
36
+ answer: 'No. Google can rewrite title links and snippets, and rendering can vary by query, device, language and experiment. The tool is designed as a practical visual guardrail for writing metadata that is less likely to be cut off.',
37
+ },
38
+ {
39
+ question: 'What pixel limits does the simulator use?',
40
+ answer: 'The default desktop title limit is 580 px, the mobile title limit is 600 px, and the meta description guardrail is 920 px. These are writing targets, not official Google limits.',
41
+ },
42
+ {
43
+ question: 'Why does the preview add an ellipsis?',
44
+ answer: 'When the measured text exceeds the available pixel width, the simulator trims the string at the last fitting character and appends three dots, matching the practical behavior SEO teams need to spot lost meaning.',
45
+ },
46
+ ];
47
+
48
+ const ui: SerpPixelSimulatorUI = {
49
+ titleLabel: 'Title tag',
50
+ titlePlaceholder: 'GameBob | Indie Development Studio',
51
+ urlLabel: 'Displayed URL',
52
+ urlPlaceholder: 'https://www.gamebob.dev/en/',
53
+ descriptionLabel: 'Meta description',
54
+ descriptionPlaceholder: 'Discover our collection of tools and games designed to elevate your digital workflow and entertainment.',
55
+ deviceLabel: 'Preview mode',
56
+ desktopLabel: 'Desktop',
57
+ mobileLabel: 'Mobile',
58
+ titlePixelsLabel: 'Title width',
59
+ descriptionPixelsLabel: 'Description width',
60
+ charactersLabel: 'characters',
61
+ previewLabel: 'Live Google-style preview',
62
+ tooLongLabel: 'Too wide',
63
+ goodLabel: 'Fits',
64
+ emptyTitle: 'Your title will appear here',
65
+ emptyDescription: 'Your meta description preview will appear here as you type.',
66
+ defaultTitle: 'GameBob | Indie Development Studio',
67
+ defaultUrl: 'https://www.gamebob.dev/en/',
68
+ defaultDescription: 'Discover our collection of tools and games designed to elevate your digital workflow and entertainment.',
69
+ fallbackUrl: 'example.com',
70
+ fallbackFaviconText: 'G',
71
+ pixelUnit: 'px',
72
+ ellipsis: '...',
73
+ fetchButtonLabel: 'Fetch',
74
+ fetchLoadingLabel: 'Fetching...',
75
+ fetchSuccessLabel: 'Metadata loaded from the URL.',
76
+ fetchCorsError: 'The browser could not read this page. It may be blocked by CORS, a redirect, mixed content or a network rule. You can still paste or edit the metadata manually.',
77
+ fetchInvalidUrlError: 'Enter a valid URL before fetching metadata.',
78
+ fetchNoMetadataError: 'The page was fetched, but no title or meta description was found.',
79
+ fetchGenericError: 'Metadata could not be fetched from this URL. Check the address or paste the fields manually.',
80
+ };
81
+
82
+ const faqSchema: WithContext<FAQPage> = {
83
+ '@context': 'https://schema.org',
84
+ '@type': 'FAQPage',
85
+ mainEntity: faq.map((item) => ({
86
+ '@type': 'Question',
87
+ name: item.question,
88
+ acceptedAnswer: {
89
+ '@type': 'Answer',
90
+ text: item.answer,
91
+ },
92
+ })),
93
+ };
94
+
95
+ const howToSchema: WithContext<HowTo> = {
96
+ '@context': 'https://schema.org',
97
+ '@type': 'HowTo',
98
+ name: title,
99
+ description,
100
+ step: howTo.map((step, index) => ({
101
+ '@type': 'HowToStep',
102
+ position: index + 1,
103
+ name: step.name,
104
+ text: step.text,
105
+ })),
106
+ };
107
+
108
+ const appSchema: WithContext<SoftwareApplication> = {
109
+ '@context': 'https://schema.org',
110
+ '@type': 'SoftwareApplication',
111
+ name: title,
112
+ description,
113
+ applicationCategory: 'BusinessApplication',
114
+ operatingSystem: 'Any',
115
+ offers: {
116
+ '@type': 'Offer',
117
+ price: '0',
118
+ priceCurrency: 'EUR',
119
+ },
120
+ };
121
+
122
+ export const content: ToolLocaleContent<SerpPixelSimulatorUI> = {
123
+ slug,
124
+ title,
125
+ description,
126
+ ui,
127
+ faqTitle: 'SERP simulator FAQ',
128
+ faq,
129
+ bibliographyTitle: 'Search result documentation',
130
+ bibliography,
131
+ howTo,
132
+ schemas: [appSchema, faqSchema, howToSchema],
133
+ seo: [
134
+ {
135
+ type: 'title',
136
+ text: 'Stop guessing how your Google result will look',
137
+ level: 2,
138
+ },
139
+ {
140
+ type: 'paragraph',
141
+ html: 'A title tag can look perfect in a spreadsheet and still break in the search result. Google does not reserve space by character count; it renders text inside a visual card. That means <strong>GameBob | Indie Development Studio</strong> and another title with the same number of characters can occupy very different widths depending on the letters, casing, punctuation and spacing.',
142
+ },
143
+ {
144
+ type: 'tip',
145
+ title: 'The rule that actually helps',
146
+ html: 'Write the snippet so the important promise survives the ellipsis. Put the page type, the search intent and the strongest reason to click before the pixel limit. Brand names are useful, but they should not push the main benefit out of view.',
147
+ },
148
+ {
149
+ type: 'title',
150
+ text: 'What the pixel counter is measuring',
151
+ level: 3,
152
+ },
153
+ {
154
+ type: 'table',
155
+ headers: ['Element', 'What matters', 'How to use the result'],
156
+ rows: [
157
+ ['Title tag', 'Rendered width in pixels, not raw character count', 'Keep the primary keyword and click promise visible before truncation.'],
158
+ ['Displayed URL', 'Visual trust and topic clarity', 'Use a readable path that reinforces where the result leads.'],
159
+ ['Meta description', 'A wider snippet area with query-dependent behavior', 'Front-load the benefit because Google may shorten or rewrite it.'],
160
+ ['Device mode', 'Desktop and mobile cards can feel different', 'Check both before shipping metadata for important pages.'],
161
+ ],
162
+ },
163
+ {
164
+ type: 'title',
165
+ text: 'Why character limits are a weak SEO habit',
166
+ level: 3,
167
+ },
168
+ {
169
+ type: 'paragraph',
170
+ html: 'Traditional advice such as "keep titles under 60 characters" is convenient, but it hides the real problem. Wide letters like W and M, uppercase words, separators, numbers and long brand names all consume different space. Pixel measurement makes the trade-off visible immediately: you can see whether a phrase earns its place or steals room from a stronger message.',
171
+ },
172
+ {
173
+ type: 'title',
174
+ text: 'A practical workflow for better snippets',
175
+ level: 3,
176
+ },
177
+ {
178
+ type: 'list',
179
+ items: [
180
+ '<strong>Start with intent:</strong> describe what the user gets, not just what the page is called.',
181
+ '<strong>Test the full title:</strong> paste it into the simulator and watch the bar before publishing.',
182
+ '<strong>Move weak words out:</strong> if the bar turns red, remove filler before cutting valuable terms.',
183
+ '<strong>Check the ellipsis:</strong> if the truncated preview loses meaning, rewrite the title instead of accepting the cut.',
184
+ '<strong>Repeat for the description:</strong> make sure the first sentence carries the value proposition on its own.',
185
+ ],
186
+ },
187
+ {
188
+ type: 'diagnostic',
189
+ variant: 'info',
190
+ title: 'When the bar turns red',
191
+ html: 'A red bar is not a penalty warning. It means the current text is wider than the selected visual target, so the simulator trims it with dots. Treat that as an editorial signal: decide whether the hidden words are disposable, or whether the snippet needs a sharper structure.',
192
+ },
193
+ {
194
+ type: 'title',
195
+ text: 'Limits, rewrites and real-world expectations',
196
+ level: 3,
197
+ },
198
+ {
199
+ type: 'paragraph',
200
+ html: 'No simulator can guarantee the exact snippet Google will show. Google may rewrite title links, bold query terms, choose page text instead of the meta description, or display different snippets for different searches. This tool is best used as a fast writing and QA step: it catches obvious visual overflow before the page reaches production.',
201
+ },
202
+ {
203
+ type: 'summary',
204
+ title: 'Best use of this SERP simulator',
205
+ items: [
206
+ 'Use the pixel bar to catch visual overflow before publishing metadata.',
207
+ 'Keep the main search intent and click promise visible before any ellipsis.',
208
+ 'Fetch metadata from URLs that allow CORS, then edit the result manually when needed.',
209
+ 'Treat the preview as a writing guardrail, because Google can still rewrite snippets per query.',
210
+ ],
211
+ },
212
+ ],
213
+ };
@@ -0,0 +1,214 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { SerpPixelSimulatorUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'simulador-serp-contador-pixeles';
7
+ const title = 'Simulador SERP y Contador de Píxeles SEO';
8
+ const description = 'Previsualiza fragmentos de búsqueda estilo Google en tiempo real, mide la anchura en píxeles del título y la meta descripción, y ve exactamente dónde se truncará tu texto.';
9
+
10
+ const howTo = [
11
+ {
12
+ name: 'Introduce la etiqueta title',
13
+ text: 'Escribe o pega el título de página que quieres probar. La vista previa SERP y el medidor de píxeles se actualizan con cada pulsación.',
14
+ },
15
+ {
16
+ name: 'Añade la URL visible',
17
+ text: 'Usa un dominio y ruta realistas para que el fragmento se parezca al resultado que un buscador analizaría.',
18
+ },
19
+ {
20
+ name: 'Escribe la meta descripción',
21
+ text: 'Añade el texto de la descripción y observa la barra de píxeles. Cuando supera el ancho visual recomendado, la vista previa la trunca con puntos suspensivos.',
22
+ },
23
+ {
24
+ name: 'Alterna entre escritorio y móvil',
25
+ text: 'Compara la representación del título con el ancho de tarjeta de escritorio o móvil antes de publicar los metadatos.',
26
+ },
27
+ ];
28
+
29
+ const faq = [
30
+ {
31
+ question: '¿Por qué contar píxeles en vez de caracteres para los títulos SEO?',
32
+ answer: 'Las tarjetas de resultados de Google están limitadas por el ancho visual. Un título con muchas letras estrechas puede albergar más caracteres que uno con letras anchas, mayúsculas o glifos de aspecto grueso. La medición en píxeles ofrece una vista previa más fiel del resultado visible.',
33
+ },
34
+ {
35
+ question: '¿Garantiza esto exactamente cómo truncará Google mi fragmento?',
36
+ answer: 'No. Google puede reescribir los enlaces de título y los fragmentos, y la representación puede variar según la consulta, el dispositivo, el idioma y los experimentos. La herramienta está diseñada como una guía visual práctica para redactar metadatos con menos probabilidades de ser cortados.',
37
+ },
38
+ {
39
+ question: '¿Qué límites de píxeles usa el simulador?',
40
+ answer: 'El límite predeterminado del título en escritorio es de 580 px, el del título en móvil es de 600 px y el de la meta descripción es de 920 px. Son objetivos de redacción, no límites oficiales de Google.',
41
+ },
42
+ {
43
+ question: '¿Por qué la vista previa añade puntos suspensivos?',
44
+ answer: 'Cuando el texto medido supera el ancho de píxeles disponible, el simulador trunca la cadena en el último carácter que cabe y añade tres puntos, imitando el comportamiento práctico que los equipos SEO necesitan para detectar pérdida de significado.',
45
+ },
46
+ ];
47
+
48
+ const ui: SerpPixelSimulatorUI = {
49
+ titleLabel: 'Etiqueta title',
50
+ titlePlaceholder: 'GameBob | Estudio de Desarrollo Indie',
51
+ urlLabel: 'URL visible',
52
+ urlPlaceholder: 'https://www.gamebob.dev/es/',
53
+ descriptionLabel: 'Meta descripción',
54
+ descriptionPlaceholder: 'Descubre nuestra colección de herramientas y juegos diseñados para elevar tu flujo de trabajo digital y entretenimiento.',
55
+ deviceLabel: 'Modo de vista previa',
56
+ desktopLabel: 'Escritorio',
57
+ mobileLabel: 'Móvil',
58
+ titlePixelsLabel: 'Ancho del título',
59
+ descriptionPixelsLabel: 'Ancho de la descripción',
60
+ charactersLabel: 'caracteres',
61
+ previewLabel: 'Vista previa estilo Google',
62
+ tooLongLabel: 'Demasiado ancho',
63
+ goodLabel: 'Correcto',
64
+ emptyTitle: 'Tu título aparecerá aquí',
65
+ emptyDescription: 'La vista previa de tu meta descripción aparecerá aquí mientras escribes.',
66
+ defaultTitle: 'GameBob | Estudio de Desarrollo Indie',
67
+ defaultUrl: 'https://www.gamebob.dev/es/',
68
+ defaultDescription: 'Descubre nuestra colección de herramientas y juegos diseñados para elevar tu flujo de trabajo digital y entretenimiento.',
69
+ fallbackUrl: 'ejemplo.com',
70
+ fallbackFaviconText: 'G',
71
+ pixelUnit: 'px',
72
+ ellipsis: '...',
73
+ fetchButtonLabel: 'Obtener',
74
+ fetchLoadingLabel: 'Obteniendo...',
75
+ fetchSuccessLabel: 'Metadatos cargados desde la URL.',
76
+ fetchCorsError: 'El navegador no pudo leer esta página. Puede estar bloqueada por CORS, una redirección, contenido mixto o una regla de red. Puedes pegar o editar los metadatos manualmente.',
77
+ fetchInvalidUrlError: 'Introduce una URL válida antes de obtener los metadatos.',
78
+ fetchNoMetadataError: 'La página se obtuvo, pero no se encontró título ni meta descripción.',
79
+ fetchGenericError: 'No se pudieron obtener los metadatos de esta URL. Comprueba la dirección o completa los campos manualmente.',
80
+ };
81
+
82
+ const faqSchema: WithContext<FAQPage> = {
83
+ '@context': 'https://schema.org',
84
+ '@type': 'FAQPage',
85
+ mainEntity: faq.map((item) => ({
86
+ '@type': 'Question',
87
+ name: item.question,
88
+ acceptedAnswer: {
89
+ '@type': 'Answer',
90
+ text: item.answer,
91
+ },
92
+ })),
93
+ };
94
+
95
+ const howToSchema: WithContext<HowTo> = {
96
+ '@context': 'https://schema.org',
97
+ '@type': 'HowTo',
98
+ name: title,
99
+ description,
100
+ step: howTo.map((step, index) => ({
101
+ '@type': 'HowToStep',
102
+ position: index + 1,
103
+ name: step.name,
104
+ text: step.text,
105
+ })),
106
+ };
107
+
108
+ const appSchema: WithContext<SoftwareApplication> = {
109
+ '@context': 'https://schema.org',
110
+ '@type': 'SoftwareApplication',
111
+ name: title,
112
+ description,
113
+ applicationCategory: 'BusinessApplication',
114
+ operatingSystem: 'Any',
115
+ offers: {
116
+ '@type': 'Offer',
117
+ price: '0',
118
+ priceCurrency: 'EUR',
119
+ },
120
+ inLanguage: 'es',
121
+ };
122
+
123
+ export const content: ToolLocaleContent<SerpPixelSimulatorUI> = {
124
+ slug,
125
+ title,
126
+ description,
127
+ ui,
128
+ faqTitle: 'Preguntas frecuentes sobre el simulador SERP',
129
+ faq,
130
+ bibliographyTitle: 'Documentación sobre resultados de búsqueda',
131
+ bibliography,
132
+ howTo,
133
+ schemas: [appSchema, faqSchema, howToSchema],
134
+ seo: [
135
+ {
136
+ type: 'title',
137
+ text: 'Deja de adivinar cómo se verá tu resultado en Google',
138
+ level: 2,
139
+ },
140
+ {
141
+ type: 'paragraph',
142
+ html: 'Un title tag puede parecer perfecto en una hoja de cálculo y aun así fallar en el resultado de búsqueda. Google no reserva espacio por número de caracteres; renderiza el texto dentro de una tarjeta visual. Eso significa que <strong>GameBob | Estudio de Desarrollo Indie</strong> y otro título con la misma cantidad de caracteres pueden ocupar anchos muy diferentes según las letras, mayúsculas, puntuación y espaciado.',
143
+ },
144
+ {
145
+ type: 'tip',
146
+ title: 'La regla que realmente ayuda',
147
+ html: 'Escribe el fragmento para que la promesa importante sobreviva a los puntos suspensivos. Pon el tipo de página, la intención de búsqueda y la razón más fuerte para hacer clic antes del límite de píxeles. Los nombres de marca son útiles, pero no deben desplazar el beneficio principal fuera de la vista.',
148
+ },
149
+ {
150
+ type: 'title',
151
+ text: 'Qué mide el contador de píxeles',
152
+ level: 3,
153
+ },
154
+ {
155
+ type: 'table',
156
+ headers: ['Elemento', 'Qué importa', 'Cómo usar el resultado'],
157
+ rows: [
158
+ ['Etiqueta title', 'Ancho renderizado en píxeles, no el número de caracteres', 'Mantén la palabra clave principal y la promesa de clic visibles antes del truncamiento.'],
159
+ ['URL visible', 'Confianza visual y claridad del tema', 'Usa una ruta legible que refuerce hacia dónde lleva el resultado.'],
160
+ ['Meta descripción', 'Un área de fragmento más amplia con comportamiento dependiente de la consulta', 'Pon el beneficio al principio porque Google puede acortarla o reescribirla.'],
161
+ ['Modo dispositivo', 'Las tarjetas de escritorio y móvil pueden sentirse diferentes', 'Revisa ambas antes de publicar metadatos de páginas importantes.'],
162
+ ],
163
+ },
164
+ {
165
+ type: 'title',
166
+ text: 'Por qué los límites de caracteres son un mal hábito SEO',
167
+ level: 3,
168
+ },
169
+ {
170
+ type: 'paragraph',
171
+ html: 'El consejo tradicional de "mantén los títulos por debajo de 60 caracteres" es cómodo, pero oculta el problema real. Letras anchas como la W y la M, palabras en mayúsculas, separadores, números y nombres de marca largos consumen espacios diferentes. La medición en píxeles hace visible el compromiso de inmediato: puedes ver si una frase se gana su sitio o le roba espacio a un mensaje más fuerte.',
172
+ },
173
+ {
174
+ type: 'title',
175
+ text: 'Un flujo de trabajo práctico para mejores fragmentos',
176
+ level: 3,
177
+ },
178
+ {
179
+ type: 'list',
180
+ items: [
181
+ '<strong>Empieza por la intención:</strong> describe lo que obtiene el usuario, no solo cómo se llama la página.',
182
+ '<strong>Prueba el título completo:</strong> pégalo en el simulador y observa la barra antes de publicar.',
183
+ '<strong>Quita las palabras débiles:</strong> si la barra se vuelve roja, elimina relleno antes de recortar términos valiosos.',
184
+ '<strong>Revisa los puntos suspensivos:</strong> si la vista previa truncada pierde sentido, reescribe el título en vez de aceptar el corte.',
185
+ '<strong>Repite para la descripción:</strong> asegúrate de que la primera frase transmita la propuesta de valor por sí sola.',
186
+ ],
187
+ },
188
+ {
189
+ type: 'diagnostic',
190
+ variant: 'info',
191
+ title: 'Cuando la barra se vuelve roja',
192
+ html: 'Una barra roja no es un aviso de penalización. Significa que el texto actual es más ancho que el objetivo visual seleccionado, por lo que el simulador lo trunca con puntos. Trátalo como una señal editorial: decide si las palabras ocultas son prescindibles o si el fragmento necesita una estructura más afilada.',
193
+ },
194
+ {
195
+ type: 'title',
196
+ text: 'Límites, reescrituras y expectativas realistas',
197
+ level: 3,
198
+ },
199
+ {
200
+ type: 'paragraph',
201
+ html: 'Ningún simulador puede garantizar el fragmento exacto que Google mostrará. Google puede reescribir los enlaces de título, poner en negrita los términos de la consulta, elegir texto de la página en lugar de la meta descripción o mostrar fragmentos distintos para diferentes búsquedas. Esta herramienta funciona mejor como un paso rápido de redacción y control de calidad: detecta desbordamientos visuales evidentes antes de que la página llegue a producción.',
202
+ },
203
+ {
204
+ type: 'summary',
205
+ title: 'Mejor uso de este simulador SERP',
206
+ items: [
207
+ 'Usa la barra de píxeles para detectar desbordamientos visuales antes de publicar metadatos.',
208
+ 'Mantén la intención de búsqueda principal y la promesa de clic visibles antes de cualquier elipsis.',
209
+ 'Obtén metadatos de URLs que permitan CORS y edita el resultado manualmente cuando sea necesario.',
210
+ 'Considera la vista previa como una guía de redacción, ya que Google puede reescribir fragmentos según la consulta.',
211
+ ],
212
+ },
213
+ ],
214
+ };