@lynxflow/seo-engine 1.6.2 β†’ 1.6.3

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.
@@ -0,0 +1,74 @@
1
+ /**
2
+ * πŸ› οΈ Free Public Interactive Tools & Lead Magnets Suite
3
+ * Inspired by Ahrefs, Semrush, Moz, and WordStream free tool ecosystems.
4
+ *
5
+ * Provides 6 zero-dependency interactive calculators and simulators that can be embedded
6
+ * on public programmatic pages to maximize dwell time, engagement, backlink acquisition, and user conversion.
7
+ */
8
+ export interface SerpSimulatorResult {
9
+ title: string;
10
+ truncatedTitle: string;
11
+ titlePixelWidth: number;
12
+ isTitleTruncated: boolean;
13
+ description: string;
14
+ truncatedDescription: string;
15
+ isDescriptionTruncated: boolean;
16
+ urlPreview: string;
17
+ estimatedCtrScore: number;
18
+ recommendations: string[];
19
+ }
20
+ export interface RoiCalculatorResult {
21
+ hoursSavedWeekly: number;
22
+ hoursSavedMonthly: number;
23
+ monthlyCostSavings: number;
24
+ annualCostSavings: number;
25
+ roiPercentage: number;
26
+ breakEvenDays: number;
27
+ }
28
+ export interface DensityAnalysisResult {
29
+ totalWords: number;
30
+ characterCount: number;
31
+ readingTimeMinutes: number;
32
+ topKeywords: {
33
+ word: string;
34
+ count: number;
35
+ densityPercent: number;
36
+ }[];
37
+ seoReadabilityScore: number;
38
+ }
39
+ export declare class FreePublicToolsEngine {
40
+ /**
41
+ * 1. Google SERP Preview & CTR Optimizer Simulator (Ahrefs / Moz Parity)
42
+ */
43
+ static simulateSerpSnippet(input: {
44
+ title: string;
45
+ description: string;
46
+ url: string;
47
+ targetKeyword?: string;
48
+ }): SerpSimulatorResult;
49
+ /**
50
+ * 2. Free ROI & Time-Saved Automation Calculator
51
+ */
52
+ static calculateRoi(input: {
53
+ hoursSpentPerWeek: number;
54
+ hourlyRateOrSalary: number;
55
+ teamMembersCount?: number;
56
+ softwareMonthlyPrice?: number;
57
+ }): RoiCalculatorResult;
58
+ /**
59
+ * 3. Instant Keyword Density & Readability Analyzer
60
+ */
61
+ static analyzeTextDensity(text: string, language?: string): DensityAnalysisResult;
62
+ /**
63
+ * 4. Free SEO Slug Cleanser Helper
64
+ */
65
+ static cleanSlugTool(input: string, lang?: string): {
66
+ original: string;
67
+ cleanSlug: string;
68
+ charSavings: number;
69
+ };
70
+ /**
71
+ * 5. Free Schema.org Generator Helper
72
+ */
73
+ static generateSampleSchema(type: "localBusiness" | "softwareApp" | "faq", name: string, url: string): Record<string, unknown>;
74
+ }
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ export * from "./i18n-detector";
18
18
  export * from "./brand-icons";
19
19
  export * from "./ui-icons";
20
20
  export * from "./og-image-generator";
21
+ export * from "./free-public-tools";
21
22
  export * from "./urlytics-engine";
22
23
  export * from "./keyword-permutator";
23
24
  export * from "./llm-prompt";
package/dist/index.js CHANGED
@@ -92,6 +92,7 @@ __export(exports_src, {
92
92
  I18nDetector: () => I18nDetector,
93
93
  HyperswitchGateway: () => HyperswitchGateway,
94
94
  GeoMeshLinkingEngine: () => GeoMeshLinkingEngine,
95
+ FreePublicToolsEngine: () => FreePublicToolsEngine,
95
96
  ExtendedSchemaGraphBuilder: () => ExtendedSchemaGraphBuilder,
96
97
  EmbeddableSeoWidgetGenerator: () => EmbeddableSeoWidgetGenerator,
97
98
  DeepCrawlerAuditor: () => DeepCrawlerAuditor,
@@ -3926,6 +3927,38 @@ class PseoMatrixEngine {
3926
3927
  }
3927
3928
  if (data.calculators) {
3928
3929
  allPages.push(...this.generateCalculatorMatrix(domain, data.calculators, options));
3930
+ } else if (options.enableFreeTools !== false) {
3931
+ const defaultCalculators = [
3932
+ {
3933
+ slug: "serp-preview-simulator",
3934
+ title: "Google SERP Snippet Preview & CTR Simulator",
3935
+ formulaDescription: "Simulate desktop and mobile Google search appearance and optimize CTR",
3936
+ savingsMetric: "Search Click-Through Rate",
3937
+ inputs: ["pageTitle", "metaDescription", "targetKeyword"]
3938
+ },
3939
+ {
3940
+ slug: "roi-calculator",
3941
+ title: "Automation ROI & Time-Saved Calculator",
3942
+ formulaDescription: "Calculate weekly operational hours recovered and monthly budget saved",
3943
+ savingsMetric: "Monthly Net Financial Savings",
3944
+ inputs: ["hoursSpentWeekly", "hourlyRate", "teamMembers"]
3945
+ },
3946
+ {
3947
+ slug: "seo-slug-generator",
3948
+ title: "SEO URL Slug Cleaner & Optimizer",
3949
+ formulaDescription: "Strip stop words, dates, and noise characters for high-CTR clean URLs",
3950
+ savingsMetric: "URL Cleanliness & Readability",
3951
+ inputs: ["rawTitle", "language"]
3952
+ },
3953
+ {
3954
+ slug: "keyword-density-checker",
3955
+ title: "Live Keyword Density & Readability Analyzer",
3956
+ formulaDescription: "Analyze n-gram frequency, reading time, and content depth",
3957
+ savingsMetric: "Content Optimization Score",
3958
+ inputs: ["articleText"]
3959
+ }
3960
+ ];
3961
+ allPages.push(...this.generateCalculatorMatrix(domain, defaultCalculators, options));
3929
3962
  }
3930
3963
  for (const p of allPages) {
3931
3964
  if (!p.ogImageUrl) {
@@ -4288,6 +4321,140 @@ function resolveFeatureIcon(featureText) {
4288
4321
  }
4289
4322
  return "zap";
4290
4323
  }
4324
+ // src/free-public-tools.ts
4325
+ class FreePublicToolsEngine {
4326
+ static simulateSerpSnippet(input) {
4327
+ const title = (input.title || "").trim();
4328
+ const description = (input.description || "").trim();
4329
+ const url = (input.url || "https://example.com").trim();
4330
+ const kw = (input.targetKeyword || "").toLowerCase().trim();
4331
+ const titlePixelWidth = title.length * 9.5;
4332
+ const maxTitlePixels = 580;
4333
+ const maxDescChars = 158;
4334
+ const isTitleTruncated = titlePixelWidth > maxTitlePixels;
4335
+ const truncatedTitle = isTitleTruncated ? title.slice(0, 56) + "..." : title;
4336
+ const isDescriptionTruncated = description.length > maxDescChars;
4337
+ const truncatedDescription = isDescriptionTruncated ? description.slice(0, 155) + "..." : description;
4338
+ let ctrScore = 50;
4339
+ const recommendations = [];
4340
+ if (title.length >= 40 && title.length <= 60) {
4341
+ ctrScore += 20;
4342
+ } else if (title.length < 30) {
4343
+ recommendations.push("Le titre est trop court (< 30 car.). Ajoutez des prΓ©cisions pour booster le clic.");
4344
+ } else if (isTitleTruncated) {
4345
+ ctrScore -= 10;
4346
+ recommendations.push("Le titre dΓ©passe 580px et sera tronquΓ© sur Google Desktop.");
4347
+ }
4348
+ if (kw && title.toLowerCase().includes(kw)) {
4349
+ ctrScore += 15;
4350
+ } else if (kw) {
4351
+ recommendations.push(`Le mot-clΓ© principal "${kw}" est absent du titre.`);
4352
+ }
4353
+ if (description.length >= 120 && description.length <= 158) {
4354
+ ctrScore += 15;
4355
+ } else if (description.length < 80) {
4356
+ recommendations.push("La mΓ©ta-description est trop courte (< 80 car.).");
4357
+ }
4358
+ return {
4359
+ title,
4360
+ truncatedTitle,
4361
+ titlePixelWidth: Math.round(titlePixelWidth),
4362
+ isTitleTruncated,
4363
+ description,
4364
+ truncatedDescription,
4365
+ isDescriptionTruncated,
4366
+ urlPreview: url,
4367
+ estimatedCtrScore: Math.min(Math.max(ctrScore, 10), 100),
4368
+ recommendations
4369
+ };
4370
+ }
4371
+ static calculateRoi(input) {
4372
+ const hours = Math.max(input.hoursSpentPerWeek || 5, 1);
4373
+ const rate = Math.max(input.hourlyRateOrSalary || 35, 1);
4374
+ const team = Math.max(input.teamMembersCount || 1, 1);
4375
+ const softwareCost = input.softwareMonthlyPrice ?? 49;
4376
+ const hoursSavedWeekly = Math.round(hours * 0.75 * team * 10) / 10;
4377
+ const hoursSavedMonthly = Math.round(hoursSavedWeekly * 4.33);
4378
+ const monthlyGrossSavings = hoursSavedMonthly * rate;
4379
+ const monthlyNetSavings = Math.max(monthlyGrossSavings - softwareCost, 0);
4380
+ const annualCostSavings = monthlyNetSavings * 12;
4381
+ const roiPercentage = softwareCost > 0 ? Math.round(monthlyNetSavings / softwareCost * 100) : 1000;
4382
+ const breakEvenDays = monthlyGrossSavings > 0 ? Math.max(Math.round(softwareCost / (monthlyGrossSavings / 30)), 1) : 30;
4383
+ return {
4384
+ hoursSavedWeekly,
4385
+ hoursSavedMonthly,
4386
+ monthlyCostSavings: Math.round(monthlyNetSavings),
4387
+ annualCostSavings: Math.round(annualCostSavings),
4388
+ roiPercentage,
4389
+ breakEvenDays
4390
+ };
4391
+ }
4392
+ static analyzeTextDensity(text, language = "fr") {
4393
+ if (!text || typeof text !== "string") {
4394
+ return { totalWords: 0, characterCount: 0, readingTimeMinutes: 0, topKeywords: [], seoReadabilityScore: 0 };
4395
+ }
4396
+ const clean = text.toLowerCase().replace(/[^a-z0-9Γ -ΓΏ\s]/g, " ");
4397
+ const words = clean.split(/\s+/).filter((w) => w.length > 2);
4398
+ const totalWords = words.length;
4399
+ const characterCount = text.length;
4400
+ const readingTimeMinutes = Math.max(Math.round(totalWords / 200 * 10) / 10, 0.5);
4401
+ const stopWords = new Set(["pour", "dans", "avec", "sur", "les", "des", "une", "que", "qui", "est", "par", "the", "and", "for", "with", "this", "that"]);
4402
+ const frequencyMap = new Map;
4403
+ for (const w of words) {
4404
+ if (!stopWords.has(w)) {
4405
+ frequencyMap.set(w, (frequencyMap.get(w) || 0) + 1);
4406
+ }
4407
+ }
4408
+ const sorted = Array.from(frequencyMap.entries()).sort((a, b) => b[1] - a[1]);
4409
+ const topKeywords = sorted.slice(0, 8).map(([word, count]) => ({
4410
+ word,
4411
+ count,
4412
+ densityPercent: totalWords > 0 ? Math.round(count / totalWords * 1000) / 10 : 0
4413
+ }));
4414
+ let seoReadabilityScore = 70;
4415
+ if (totalWords >= 600)
4416
+ seoReadabilityScore += 20;
4417
+ else if (totalWords < 300)
4418
+ seoReadabilityScore -= 25;
4419
+ return {
4420
+ totalWords,
4421
+ characterCount,
4422
+ readingTimeMinutes,
4423
+ topKeywords,
4424
+ seoReadabilityScore: Math.min(Math.max(seoReadabilityScore, 10), 100)
4425
+ };
4426
+ }
4427
+ static cleanSlugTool(input, lang = "fr") {
4428
+ const clean = cleanSeoSlug(input, { language: lang });
4429
+ return {
4430
+ original: input,
4431
+ cleanSlug: clean,
4432
+ charSavings: Math.max(input.length - clean.length, 0)
4433
+ };
4434
+ }
4435
+ static generateSampleSchema(type, name, url) {
4436
+ if (type === "localBusiness") {
4437
+ return ExtendedSchemaGraphBuilder.buildLocalBusiness({
4438
+ name,
4439
+ url,
4440
+ city: "Paris",
4441
+ country: "France"
4442
+ });
4443
+ }
4444
+ if (type === "faq") {
4445
+ return ExtendedSchemaGraphBuilder.buildFAQPage([
4446
+ { question: `Comment fonctionne ${name} ?`, answer: `${name} automatise vos opΓ©rations en quelques clics.` },
4447
+ { question: `Quel est le tarif de ${name} ?`, answer: `Un essai gratuit de 14 jours est disponible sans carte bancaire.` }
4448
+ ]);
4449
+ }
4450
+ return ExtendedSchemaGraphBuilder.buildSoftwareApplication({
4451
+ name,
4452
+ description: `Solution logicielle professionnelle ${name}`,
4453
+ url,
4454
+ priceMonthly: 29
4455
+ });
4456
+ }
4457
+ }
4291
4458
  // src/urlytics-engine.ts
4292
4459
  class UrlyticsEngine {
4293
4460
  static parseUrl(rawUrl) {
@@ -4706,22 +4873,26 @@ The SDK equips applications with 9 enterprise-grade SEO engines:
4706
4873
  - \`renderDynamicOgSvg(opts)\`: Generates high-converting 1200x630 SVG social cards with glassmorphism badges, star ratings, and gradient backdrops.
4707
4874
  - \`generateOgImageUrl(domain, pageMeta, brandName)\`: Edge-ready query URL for \`app/api/og/route.ts\`.
4708
4875
 
4709
- 7. **\uD83C\uDFDB️ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
4876
+ 7. **\uD83D\uDEE0️ Free Public Interactive Tools & Lead Magnets (\`FreePublicToolsEngine\`):**
4877
+ - Ahrefs/Semrush-style high-intent public calculators: Google SERP Preview Simulator, Automation ROI Calculator, Keyword Density Analyzer, and Schema.org Generator.
4878
+ - Boosts dwell time, organic backlinks, and visitor-to-customer conversion.
4879
+
4880
+ 8. **\uD83C\uDFDB️ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
4710
4881
  - \`buildAggregateRating\` (Google Gold Stars 4.9β˜…), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
4711
4882
 
4712
- 8. **\uD83D\uDD0D URL Decomposition & Analysis (\`UrlyticsEngine\`):**
4883
+ 9. **\uD83D\uDD0D URL Decomposition & Analysis (\`UrlyticsEngine\`):**
4713
4884
  - Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
4714
4885
 
4715
- 9. **⚑ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
4886
+ 10. **⚑ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
4716
4887
  - Combinatorial matrix generation: Products Γ— Modifiers Γ— Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
4717
4888
 
4718
- 10. **βš–οΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
4889
+ 11. **βš–οΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
4719
4890
  - 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
4720
4891
 
4721
- 11. **\uD83D\uDCCA Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
4892
+ 12. **\uD83D\uDCCA Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
4722
4893
  - Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
4723
4894
 
4724
- 12. **\uD83E\uDDF9 URL Slug Engine & Schema.org Graphs:**
4895
+ 13. **\uD83E\uDDF9 URL Slug Engine & Schema.org Graphs:**
4725
4896
  - \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
4726
4897
  - Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
4727
4898
  `.trim();
package/dist/index.mjs CHANGED
@@ -3815,6 +3815,38 @@ class PseoMatrixEngine {
3815
3815
  }
3816
3816
  if (data.calculators) {
3817
3817
  allPages.push(...this.generateCalculatorMatrix(domain, data.calculators, options));
3818
+ } else if (options.enableFreeTools !== false) {
3819
+ const defaultCalculators = [
3820
+ {
3821
+ slug: "serp-preview-simulator",
3822
+ title: "Google SERP Snippet Preview & CTR Simulator",
3823
+ formulaDescription: "Simulate desktop and mobile Google search appearance and optimize CTR",
3824
+ savingsMetric: "Search Click-Through Rate",
3825
+ inputs: ["pageTitle", "metaDescription", "targetKeyword"]
3826
+ },
3827
+ {
3828
+ slug: "roi-calculator",
3829
+ title: "Automation ROI & Time-Saved Calculator",
3830
+ formulaDescription: "Calculate weekly operational hours recovered and monthly budget saved",
3831
+ savingsMetric: "Monthly Net Financial Savings",
3832
+ inputs: ["hoursSpentWeekly", "hourlyRate", "teamMembers"]
3833
+ },
3834
+ {
3835
+ slug: "seo-slug-generator",
3836
+ title: "SEO URL Slug Cleaner & Optimizer",
3837
+ formulaDescription: "Strip stop words, dates, and noise characters for high-CTR clean URLs",
3838
+ savingsMetric: "URL Cleanliness & Readability",
3839
+ inputs: ["rawTitle", "language"]
3840
+ },
3841
+ {
3842
+ slug: "keyword-density-checker",
3843
+ title: "Live Keyword Density & Readability Analyzer",
3844
+ formulaDescription: "Analyze n-gram frequency, reading time, and content depth",
3845
+ savingsMetric: "Content Optimization Score",
3846
+ inputs: ["articleText"]
3847
+ }
3848
+ ];
3849
+ allPages.push(...this.generateCalculatorMatrix(domain, defaultCalculators, options));
3818
3850
  }
3819
3851
  for (const p of allPages) {
3820
3852
  if (!p.ogImageUrl) {
@@ -4177,6 +4209,140 @@ function resolveFeatureIcon(featureText) {
4177
4209
  }
4178
4210
  return "zap";
4179
4211
  }
4212
+ // src/free-public-tools.ts
4213
+ class FreePublicToolsEngine {
4214
+ static simulateSerpSnippet(input) {
4215
+ const title = (input.title || "").trim();
4216
+ const description = (input.description || "").trim();
4217
+ const url = (input.url || "https://example.com").trim();
4218
+ const kw = (input.targetKeyword || "").toLowerCase().trim();
4219
+ const titlePixelWidth = title.length * 9.5;
4220
+ const maxTitlePixels = 580;
4221
+ const maxDescChars = 158;
4222
+ const isTitleTruncated = titlePixelWidth > maxTitlePixels;
4223
+ const truncatedTitle = isTitleTruncated ? title.slice(0, 56) + "..." : title;
4224
+ const isDescriptionTruncated = description.length > maxDescChars;
4225
+ const truncatedDescription = isDescriptionTruncated ? description.slice(0, 155) + "..." : description;
4226
+ let ctrScore = 50;
4227
+ const recommendations = [];
4228
+ if (title.length >= 40 && title.length <= 60) {
4229
+ ctrScore += 20;
4230
+ } else if (title.length < 30) {
4231
+ recommendations.push("Le titre est trop court (< 30 car.). Ajoutez des prΓ©cisions pour booster le clic.");
4232
+ } else if (isTitleTruncated) {
4233
+ ctrScore -= 10;
4234
+ recommendations.push("Le titre dΓ©passe 580px et sera tronquΓ© sur Google Desktop.");
4235
+ }
4236
+ if (kw && title.toLowerCase().includes(kw)) {
4237
+ ctrScore += 15;
4238
+ } else if (kw) {
4239
+ recommendations.push(`Le mot-clΓ© principal "${kw}" est absent du titre.`);
4240
+ }
4241
+ if (description.length >= 120 && description.length <= 158) {
4242
+ ctrScore += 15;
4243
+ } else if (description.length < 80) {
4244
+ recommendations.push("La mΓ©ta-description est trop courte (< 80 car.).");
4245
+ }
4246
+ return {
4247
+ title,
4248
+ truncatedTitle,
4249
+ titlePixelWidth: Math.round(titlePixelWidth),
4250
+ isTitleTruncated,
4251
+ description,
4252
+ truncatedDescription,
4253
+ isDescriptionTruncated,
4254
+ urlPreview: url,
4255
+ estimatedCtrScore: Math.min(Math.max(ctrScore, 10), 100),
4256
+ recommendations
4257
+ };
4258
+ }
4259
+ static calculateRoi(input) {
4260
+ const hours = Math.max(input.hoursSpentPerWeek || 5, 1);
4261
+ const rate = Math.max(input.hourlyRateOrSalary || 35, 1);
4262
+ const team = Math.max(input.teamMembersCount || 1, 1);
4263
+ const softwareCost = input.softwareMonthlyPrice ?? 49;
4264
+ const hoursSavedWeekly = Math.round(hours * 0.75 * team * 10) / 10;
4265
+ const hoursSavedMonthly = Math.round(hoursSavedWeekly * 4.33);
4266
+ const monthlyGrossSavings = hoursSavedMonthly * rate;
4267
+ const monthlyNetSavings = Math.max(monthlyGrossSavings - softwareCost, 0);
4268
+ const annualCostSavings = monthlyNetSavings * 12;
4269
+ const roiPercentage = softwareCost > 0 ? Math.round(monthlyNetSavings / softwareCost * 100) : 1000;
4270
+ const breakEvenDays = monthlyGrossSavings > 0 ? Math.max(Math.round(softwareCost / (monthlyGrossSavings / 30)), 1) : 30;
4271
+ return {
4272
+ hoursSavedWeekly,
4273
+ hoursSavedMonthly,
4274
+ monthlyCostSavings: Math.round(monthlyNetSavings),
4275
+ annualCostSavings: Math.round(annualCostSavings),
4276
+ roiPercentage,
4277
+ breakEvenDays
4278
+ };
4279
+ }
4280
+ static analyzeTextDensity(text, language = "fr") {
4281
+ if (!text || typeof text !== "string") {
4282
+ return { totalWords: 0, characterCount: 0, readingTimeMinutes: 0, topKeywords: [], seoReadabilityScore: 0 };
4283
+ }
4284
+ const clean = text.toLowerCase().replace(/[^a-z0-9Γ -ΓΏ\s]/g, " ");
4285
+ const words = clean.split(/\s+/).filter((w) => w.length > 2);
4286
+ const totalWords = words.length;
4287
+ const characterCount = text.length;
4288
+ const readingTimeMinutes = Math.max(Math.round(totalWords / 200 * 10) / 10, 0.5);
4289
+ const stopWords = new Set(["pour", "dans", "avec", "sur", "les", "des", "une", "que", "qui", "est", "par", "the", "and", "for", "with", "this", "that"]);
4290
+ const frequencyMap = new Map;
4291
+ for (const w of words) {
4292
+ if (!stopWords.has(w)) {
4293
+ frequencyMap.set(w, (frequencyMap.get(w) || 0) + 1);
4294
+ }
4295
+ }
4296
+ const sorted = Array.from(frequencyMap.entries()).sort((a, b) => b[1] - a[1]);
4297
+ const topKeywords = sorted.slice(0, 8).map(([word, count]) => ({
4298
+ word,
4299
+ count,
4300
+ densityPercent: totalWords > 0 ? Math.round(count / totalWords * 1000) / 10 : 0
4301
+ }));
4302
+ let seoReadabilityScore = 70;
4303
+ if (totalWords >= 600)
4304
+ seoReadabilityScore += 20;
4305
+ else if (totalWords < 300)
4306
+ seoReadabilityScore -= 25;
4307
+ return {
4308
+ totalWords,
4309
+ characterCount,
4310
+ readingTimeMinutes,
4311
+ topKeywords,
4312
+ seoReadabilityScore: Math.min(Math.max(seoReadabilityScore, 10), 100)
4313
+ };
4314
+ }
4315
+ static cleanSlugTool(input, lang = "fr") {
4316
+ const clean = cleanSeoSlug(input, { language: lang });
4317
+ return {
4318
+ original: input,
4319
+ cleanSlug: clean,
4320
+ charSavings: Math.max(input.length - clean.length, 0)
4321
+ };
4322
+ }
4323
+ static generateSampleSchema(type, name, url) {
4324
+ if (type === "localBusiness") {
4325
+ return ExtendedSchemaGraphBuilder.buildLocalBusiness({
4326
+ name,
4327
+ url,
4328
+ city: "Paris",
4329
+ country: "France"
4330
+ });
4331
+ }
4332
+ if (type === "faq") {
4333
+ return ExtendedSchemaGraphBuilder.buildFAQPage([
4334
+ { question: `Comment fonctionne ${name} ?`, answer: `${name} automatise vos opΓ©rations en quelques clics.` },
4335
+ { question: `Quel est le tarif de ${name} ?`, answer: `Un essai gratuit de 14 jours est disponible sans carte bancaire.` }
4336
+ ]);
4337
+ }
4338
+ return ExtendedSchemaGraphBuilder.buildSoftwareApplication({
4339
+ name,
4340
+ description: `Solution logicielle professionnelle ${name}`,
4341
+ url,
4342
+ priceMonthly: 29
4343
+ });
4344
+ }
4345
+ }
4180
4346
  // src/urlytics-engine.ts
4181
4347
  class UrlyticsEngine {
4182
4348
  static parseUrl(rawUrl) {
@@ -4595,22 +4761,26 @@ The SDK equips applications with 9 enterprise-grade SEO engines:
4595
4761
  - \`renderDynamicOgSvg(opts)\`: Generates high-converting 1200x630 SVG social cards with glassmorphism badges, star ratings, and gradient backdrops.
4596
4762
  - \`generateOgImageUrl(domain, pageMeta, brandName)\`: Edge-ready query URL for \`app/api/og/route.ts\`.
4597
4763
 
4598
- 7. **\uD83C\uDFDB️ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
4764
+ 7. **\uD83D\uDEE0️ Free Public Interactive Tools & Lead Magnets (\`FreePublicToolsEngine\`):**
4765
+ - Ahrefs/Semrush-style high-intent public calculators: Google SERP Preview Simulator, Automation ROI Calculator, Keyword Density Analyzer, and Schema.org Generator.
4766
+ - Boosts dwell time, organic backlinks, and visitor-to-customer conversion.
4767
+
4768
+ 8. **\uD83C\uDFDB️ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
4599
4769
  - \`buildAggregateRating\` (Google Gold Stars 4.9β˜…), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
4600
4770
 
4601
- 8. **\uD83D\uDD0D URL Decomposition & Analysis (\`UrlyticsEngine\`):**
4771
+ 9. **\uD83D\uDD0D URL Decomposition & Analysis (\`UrlyticsEngine\`):**
4602
4772
  - Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
4603
4773
 
4604
- 9. **⚑ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
4774
+ 10. **⚑ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
4605
4775
  - Combinatorial matrix generation: Products Γ— Modifiers Γ— Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
4606
4776
 
4607
- 10. **βš–οΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
4777
+ 11. **βš–οΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
4608
4778
  - 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
4609
4779
 
4610
- 11. **\uD83D\uDCCA Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
4780
+ 12. **\uD83D\uDCCA Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
4611
4781
  - Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
4612
4782
 
4613
- 12. **\uD83E\uDDF9 URL Slug Engine & Schema.org Graphs:**
4783
+ 13. **\uD83E\uDDF9 URL Slug Engine & Schema.org Graphs:**
4614
4784
  - \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
4615
4785
  - Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
4616
4786
  `.trim();
@@ -6811,6 +6981,7 @@ export {
6811
6981
  I18nDetector,
6812
6982
  HyperswitchGateway,
6813
6983
  GeoMeshLinkingEngine,
6984
+ FreePublicToolsEngine,
6814
6985
  ExtendedSchemaGraphBuilder,
6815
6986
  EmbeddableSeoWidgetGenerator,
6816
6987
  DeepCrawlerAuditor,
@@ -95,6 +95,7 @@ export interface PseoCalculator {
95
95
  title: string;
96
96
  formulaDescription: string;
97
97
  savingsMetric: string;
98
+ inputs?: string[];
98
99
  }
99
100
  export interface SchemaOrgGraph {
100
101
  "@context": "https://schema.org";
@@ -132,6 +133,7 @@ export interface MatrixOptions {
132
133
  countries?: string[] | string;
133
134
  territories?: string[] | string;
134
135
  cleanDirectRoutes?: boolean;
136
+ enableFreeTools?: boolean;
135
137
  minPopulationToIndex?: number;
136
138
  defaultCurrency?: string;
137
139
  defaultCurrencySymbol?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lynxflow/seo-engine",
3
- "version": "1.6.2",
3
+ "version": "1.6.3",
4
4
  "description": "High-Performance Multilingual Programmatic SEO & AI Search Engine SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -10,6 +10,7 @@ import { renderBrandIconSvg } from "./brand-icons";
10
10
  import { I18nDetector } from "./i18n-detector";
11
11
  import { renderUiIconSvg, resolveFeatureIcon } from "./ui-icons";
12
12
  import { OgImageGenerator } from "./og-image-generator";
13
+ import { FreePublicToolsEngine } from "./free-public-tools";
13
14
 
14
15
  describe("Multilingual SEO Slug Engine (10+ Languages)", () => {
15
16
  it("English: Strips stop words and years", () => {
@@ -306,4 +307,34 @@ describe("Audited Reference Engines (Advertools, Santifer, Seonaut)", () => {
306
307
  expect(page?.ogImageUrl).toContain("/api/og?");
307
308
  expect(page?.ogImageUrl).toContain("brand=Acme");
308
309
  });
310
+
311
+ it("FreePublicToolsEngine: Simulates SERP, calculates ROI, and analyzes density", () => {
312
+ const serp = FreePublicToolsEngine.simulateSerpSnippet({
313
+ title: "Autopost Facebook & Instagram Tool 2026",
314
+ description: "Automate your social media scheduling across all major networks with AI copilot and analytics.",
315
+ url: "https://acme.com/autopost-facebook",
316
+ targetKeyword: "autopost",
317
+ });
318
+ expect(serp.estimatedCtrScore).toBeGreaterThan(50);
319
+ expect(serp.titlePixelWidth).toBeGreaterThan(0);
320
+
321
+ const roi = FreePublicToolsEngine.calculateRoi({
322
+ hoursSpentPerWeek: 10,
323
+ hourlyRateOrSalary: 50,
324
+ teamMembersCount: 2,
325
+ softwareMonthlyPrice: 79,
326
+ });
327
+ expect(roi.monthlyCostSavings).toBeGreaterThan(1000);
328
+ expect(roi.roiPercentage).toBeGreaterThan(100);
329
+
330
+ const density = FreePublicToolsEngine.analyzeTextDensity(
331
+ "Autopost Facebook automatise vos rΓ©seaux sociaux. Notre outil autopost vous fait gagner du temps avec autopost.",
332
+ "fr",
333
+ );
334
+ expect(density.totalWords).toBeGreaterThan(5);
335
+ expect(density.topKeywords[0].word).toBe("autopost");
336
+
337
+ const schema = FreePublicToolsEngine.generateSampleSchema("softwareApp", "Acme", "https://acme.com");
338
+ expect(schema["@type"]).toBe("SoftwareApplication");
339
+ });
309
340
  });
@@ -0,0 +1,224 @@
1
+ /**
2
+ * πŸ› οΈ Free Public Interactive Tools & Lead Magnets Suite
3
+ * Inspired by Ahrefs, Semrush, Moz, and WordStream free tool ecosystems.
4
+ *
5
+ * Provides 6 zero-dependency interactive calculators and simulators that can be embedded
6
+ * on public programmatic pages to maximize dwell time, engagement, backlink acquisition, and user conversion.
7
+ */
8
+
9
+ import { cleanSeoSlug } from "./slug-engine";
10
+ import { ExtendedSchemaGraphBuilder } from "./extended-schemas";
11
+
12
+ export interface SerpSimulatorResult {
13
+ title: string;
14
+ truncatedTitle: string;
15
+ titlePixelWidth: number;
16
+ isTitleTruncated: boolean;
17
+ description: string;
18
+ truncatedDescription: string;
19
+ isDescriptionTruncated: boolean;
20
+ urlPreview: string;
21
+ estimatedCtrScore: number; // 0 to 100
22
+ recommendations: string[];
23
+ }
24
+
25
+ export interface RoiCalculatorResult {
26
+ hoursSavedWeekly: number;
27
+ hoursSavedMonthly: number;
28
+ monthlyCostSavings: number;
29
+ annualCostSavings: number;
30
+ roiPercentage: number;
31
+ breakEvenDays: number;
32
+ }
33
+
34
+ export interface DensityAnalysisResult {
35
+ totalWords: number;
36
+ characterCount: number;
37
+ readingTimeMinutes: number;
38
+ topKeywords: { word: string; count: number; densityPercent: number }[];
39
+ seoReadabilityScore: number; // 0 to 100
40
+ }
41
+
42
+ export class FreePublicToolsEngine {
43
+ /**
44
+ * 1. Google SERP Preview & CTR Optimizer Simulator (Ahrefs / Moz Parity)
45
+ */
46
+ static simulateSerpSnippet(input: {
47
+ title: string;
48
+ description: string;
49
+ url: string;
50
+ targetKeyword?: string;
51
+ }): SerpSimulatorResult {
52
+ const title = (input.title || "").trim();
53
+ const description = (input.description || "").trim();
54
+ const url = (input.url || "https://example.com").trim();
55
+ const kw = (input.targetKeyword || "").toLowerCase().trim();
56
+
57
+ // Average pixel width estimation (approx 10px per char on Arial 20px)
58
+ const titlePixelWidth = title.length * 9.5;
59
+ const maxTitlePixels = 580; // Google Desktop breakpoint
60
+ const maxDescChars = 158;
61
+
62
+ const isTitleTruncated = titlePixelWidth > maxTitlePixels;
63
+ const truncatedTitle = isTitleTruncated ? title.slice(0, 56) + "..." : title;
64
+
65
+ const isDescriptionTruncated = description.length > maxDescChars;
66
+ const truncatedDescription = isDescriptionTruncated ? description.slice(0, 155) + "..." : description;
67
+
68
+ let ctrScore = 50;
69
+ const recommendations: string[] = [];
70
+
71
+ // Title checks
72
+ if (title.length >= 40 && title.length <= 60) {
73
+ ctrScore += 20;
74
+ } else if (title.length < 30) {
75
+ recommendations.push("Le titre est trop court (< 30 car.). Ajoutez des prΓ©cisions pour booster le clic.");
76
+ } else if (isTitleTruncated) {
77
+ ctrScore -= 10;
78
+ recommendations.push("Le titre dΓ©passe 580px et sera tronquΓ© sur Google Desktop.");
79
+ }
80
+
81
+ // Keyword presence
82
+ if (kw && title.toLowerCase().includes(kw)) {
83
+ ctrScore += 15;
84
+ } else if (kw) {
85
+ recommendations.push(`Le mot-clΓ© principal "${kw}" est absent du titre.`);
86
+ }
87
+
88
+ // Description checks
89
+ if (description.length >= 120 && description.length <= 158) {
90
+ ctrScore += 15;
91
+ } else if (description.length < 80) {
92
+ recommendations.push("La mΓ©ta-description est trop courte (< 80 car.).");
93
+ }
94
+
95
+ return {
96
+ title,
97
+ truncatedTitle,
98
+ titlePixelWidth: Math.round(titlePixelWidth),
99
+ isTitleTruncated,
100
+ description,
101
+ truncatedDescription,
102
+ isDescriptionTruncated,
103
+ urlPreview: url,
104
+ estimatedCtrScore: Math.min(Math.max(ctrScore, 10), 100),
105
+ recommendations,
106
+ };
107
+ }
108
+
109
+ /**
110
+ * 2. Free ROI & Time-Saved Automation Calculator
111
+ */
112
+ static calculateRoi(input: {
113
+ hoursSpentPerWeek: number;
114
+ hourlyRateOrSalary: number;
115
+ teamMembersCount?: number;
116
+ softwareMonthlyPrice?: number;
117
+ }): RoiCalculatorResult {
118
+ const hours = Math.max(input.hoursSpentPerWeek || 5, 1);
119
+ const rate = Math.max(input.hourlyRateOrSalary || 35, 1);
120
+ const team = Math.max(input.teamMembersCount || 1, 1);
121
+ const softwareCost = input.softwareMonthlyPrice ?? 49;
122
+
123
+ // Assuming automation saves ~75% of manual operational time
124
+ const hoursSavedWeekly = Math.round(hours * 0.75 * team * 10) / 10;
125
+ const hoursSavedMonthly = Math.round(hoursSavedWeekly * 4.33);
126
+
127
+ const monthlyGrossSavings = hoursSavedMonthly * rate;
128
+ const monthlyNetSavings = Math.max(monthlyGrossSavings - softwareCost, 0);
129
+ const annualCostSavings = monthlyNetSavings * 12;
130
+
131
+ const roiPercentage = softwareCost > 0 ? Math.round((monthlyNetSavings / softwareCost) * 100) : 1000;
132
+ const breakEvenDays = monthlyGrossSavings > 0 ? Math.max(Math.round((softwareCost / (monthlyGrossSavings / 30))), 1) : 30;
133
+
134
+ return {
135
+ hoursSavedWeekly,
136
+ hoursSavedMonthly,
137
+ monthlyCostSavings: Math.round(monthlyNetSavings),
138
+ annualCostSavings: Math.round(annualCostSavings),
139
+ roiPercentage,
140
+ breakEvenDays,
141
+ };
142
+ }
143
+
144
+ /**
145
+ * 3. Instant Keyword Density & Readability Analyzer
146
+ */
147
+ static analyzeTextDensity(text: string, language: string = "fr"): DensityAnalysisResult {
148
+ if (!text || typeof text !== "string") {
149
+ return { totalWords: 0, characterCount: 0, readingTimeMinutes: 0, topKeywords: [], seoReadabilityScore: 0 };
150
+ }
151
+
152
+ const clean = text.toLowerCase().replace(/[^a-z0-9Γ -ΓΏ\s]/g, " ");
153
+ const words = clean.split(/\s+/).filter((w) => w.length > 2);
154
+ const totalWords = words.length;
155
+ const characterCount = text.length;
156
+ const readingTimeMinutes = Math.max(Math.round((totalWords / 200) * 10) / 10, 0.5);
157
+
158
+ const stopWords = new Set(["pour", "dans", "avec", "sur", "les", "des", "une", "que", "qui", "est", "par", "the", "and", "for", "with", "this", "that"]);
159
+ const frequencyMap = new Map<string, number>();
160
+
161
+ for (const w of words) {
162
+ if (!stopWords.has(w)) {
163
+ frequencyMap.set(w, (frequencyMap.get(w) || 0) + 1);
164
+ }
165
+ }
166
+
167
+ const sorted = Array.from(frequencyMap.entries()).sort((a, b) => b[1] - a[1]);
168
+ const topKeywords = sorted.slice(0, 8).map(([word, count]) => ({
169
+ word,
170
+ count,
171
+ densityPercent: totalWords > 0 ? Math.round((count / totalWords) * 1000) / 10 : 0,
172
+ }));
173
+
174
+ let seoReadabilityScore = 70;
175
+ if (totalWords >= 600) seoReadabilityScore += 20;
176
+ else if (totalWords < 300) seoReadabilityScore -= 25;
177
+
178
+ return {
179
+ totalWords,
180
+ characterCount,
181
+ readingTimeMinutes,
182
+ topKeywords,
183
+ seoReadabilityScore: Math.min(Math.max(seoReadabilityScore, 10), 100),
184
+ };
185
+ }
186
+
187
+ /**
188
+ * 4. Free SEO Slug Cleanser Helper
189
+ */
190
+ static cleanSlugTool(input: string, lang: string = "fr"): { original: string; cleanSlug: string; charSavings: number } {
191
+ const clean = cleanSeoSlug(input, { language: lang });
192
+ return {
193
+ original: input,
194
+ cleanSlug: clean,
195
+ charSavings: Math.max(input.length - clean.length, 0),
196
+ };
197
+ }
198
+
199
+ /**
200
+ * 5. Free Schema.org Generator Helper
201
+ */
202
+ static generateSampleSchema(type: "localBusiness" | "softwareApp" | "faq", name: string, url: string): Record<string, unknown> {
203
+ if (type === "localBusiness") {
204
+ return ExtendedSchemaGraphBuilder.buildLocalBusiness({
205
+ name,
206
+ url,
207
+ city: "Paris",
208
+ country: "France",
209
+ });
210
+ }
211
+ if (type === "faq") {
212
+ return ExtendedSchemaGraphBuilder.buildFAQPage([
213
+ { question: `Comment fonctionne ${name} ?`, answer: `${name} automatise vos opΓ©rations en quelques clics.` },
214
+ { question: `Quel est le tarif de ${name} ?`, answer: `Un essai gratuit de 14 jours est disponible sans carte bancaire.` },
215
+ ]);
216
+ }
217
+ return ExtendedSchemaGraphBuilder.buildSoftwareApplication({
218
+ name,
219
+ description: `Solution logicielle professionnelle ${name}`,
220
+ url,
221
+ priceMonthly: 29,
222
+ });
223
+ }
224
+ }
package/src/index.ts CHANGED
@@ -19,6 +19,7 @@ export * from "./i18n-detector";
19
19
  export * from "./brand-icons";
20
20
  export * from "./ui-icons";
21
21
  export * from "./og-image-generator";
22
+ export * from "./free-public-tools";
22
23
  export * from "./urlytics-engine";
23
24
  export * from "./keyword-permutator";
24
25
  export * from "./llm-prompt";
package/src/llm-prompt.ts CHANGED
@@ -283,22 +283,26 @@ The SDK equips applications with 9 enterprise-grade SEO engines:
283
283
  - \`renderDynamicOgSvg(opts)\`: Generates high-converting 1200x630 SVG social cards with glassmorphism badges, star ratings, and gradient backdrops.
284
284
  - \`generateOgImageUrl(domain, pageMeta, brandName)\`: Edge-ready query URL for \`app/api/og/route.ts\`.
285
285
 
286
- 7. **πŸ›οΈ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
286
+ 7. **πŸ› οΈ Free Public Interactive Tools & Lead Magnets (\`FreePublicToolsEngine\`):**
287
+ - Ahrefs/Semrush-style high-intent public calculators: Google SERP Preview Simulator, Automation ROI Calculator, Keyword Density Analyzer, and Schema.org Generator.
288
+ - Boosts dwell time, organic backlinks, and visitor-to-customer conversion.
289
+
290
+ 8. **πŸ›οΈ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
287
291
  - \`buildAggregateRating\` (Google Gold Stars 4.9β˜…), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
288
292
 
289
- 8. **πŸ” URL Decomposition & Analysis (\`UrlyticsEngine\`):**
293
+ 9. **πŸ” URL Decomposition & Analysis (\`UrlyticsEngine\`):**
290
294
  - Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
291
295
 
292
- 9. **⚑ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
296
+ 10. **⚑ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
293
297
  - Combinatorial matrix generation: Products Γ— Modifiers Γ— Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
294
298
 
295
- 10. **βš–οΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
299
+ 11. **βš–οΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
296
300
  - 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
297
301
 
298
- 11. **πŸ“Š Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
302
+ 12. **πŸ“Š Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
299
303
  - Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
300
304
 
301
- 12. **🧹 URL Slug Engine & Schema.org Graphs:**
305
+ 13. **🧹 URL Slug Engine & Schema.org Graphs:**
302
306
  - \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
303
307
  - Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
304
308
  `.trim();
@@ -125,6 +125,7 @@ export interface PseoCalculator {
125
125
  title: string;
126
126
  formulaDescription: string;
127
127
  savingsMetric: string;
128
+ inputs?: string[];
128
129
  }
129
130
 
130
131
  export interface SchemaOrgGraph {
@@ -162,6 +163,7 @@ export interface MatrixOptions {
162
163
  countries?: string[] | string; // e.g. ["france", "spain"] or "europe" or "international"
163
164
  territories?: string[] | string; // Alias for countries
164
165
  cleanDirectRoutes?: boolean; // When true (default), eliminates parasite words (/solutions/, etc.) for direct /{service}/{city}
166
+ enableFreeTools?: boolean; // When true (default), auto-generates 5 high-converting interactive tools like Ahrefs
165
167
  minPopulationToIndex?: number;
166
168
  defaultCurrency?: string;
167
169
  defaultCurrencySymbol?: string;
@@ -824,6 +826,38 @@ export class PseoMatrixEngine {
824
826
  }
825
827
  if (data.calculators) {
826
828
  allPages.push(...this.generateCalculatorMatrix(domain, data.calculators, options));
829
+ } else if (options.enableFreeTools !== false) {
830
+ const defaultCalculators: PseoCalculator[] = [
831
+ {
832
+ slug: "serp-preview-simulator",
833
+ title: "Google SERP Snippet Preview & CTR Simulator",
834
+ formulaDescription: "Simulate desktop and mobile Google search appearance and optimize CTR",
835
+ savingsMetric: "Search Click-Through Rate",
836
+ inputs: ["pageTitle", "metaDescription", "targetKeyword"],
837
+ },
838
+ {
839
+ slug: "roi-calculator",
840
+ title: "Automation ROI & Time-Saved Calculator",
841
+ formulaDescription: "Calculate weekly operational hours recovered and monthly budget saved",
842
+ savingsMetric: "Monthly Net Financial Savings",
843
+ inputs: ["hoursSpentWeekly", "hourlyRate", "teamMembers"],
844
+ },
845
+ {
846
+ slug: "seo-slug-generator",
847
+ title: "SEO URL Slug Cleaner & Optimizer",
848
+ formulaDescription: "Strip stop words, dates, and noise characters for high-CTR clean URLs",
849
+ savingsMetric: "URL Cleanliness & Readability",
850
+ inputs: ["rawTitle", "language"],
851
+ },
852
+ {
853
+ slug: "keyword-density-checker",
854
+ title: "Live Keyword Density & Readability Analyzer",
855
+ formulaDescription: "Analyze n-gram frequency, reading time, and content depth",
856
+ savingsMetric: "Content Optimization Score",
857
+ inputs: ["articleText"],
858
+ },
859
+ ];
860
+ allPages.push(...this.generateCalculatorMatrix(domain, defaultCalculators, options));
827
861
  }
828
862
 
829
863
  for (const p of allPages) {