@ogxjs/core 0.1.1 → 0.2.0-alpha.1

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 (62) hide show
  1. package/dist/builder.d.ts +5 -0
  2. package/dist/builder.d.ts.map +1 -1
  3. package/dist/builder.js +11 -1
  4. package/dist/cache/hash.d.ts +66 -0
  5. package/dist/cache/hash.d.ts.map +1 -0
  6. package/dist/cache/hash.js +161 -0
  7. package/dist/cache/index.d.ts +10 -0
  8. package/dist/cache/index.d.ts.map +1 -0
  9. package/dist/cache/index.js +12 -0
  10. package/dist/cache/lru.d.ts +122 -0
  11. package/dist/cache/lru.d.ts.map +1 -0
  12. package/dist/cache/lru.js +269 -0
  13. package/dist/cache/snapshot.d.ts +116 -0
  14. package/dist/cache/snapshot.d.ts.map +1 -0
  15. package/dist/cache/snapshot.js +204 -0
  16. package/dist/cache.d.ts +2 -2
  17. package/dist/cache.js +2 -2
  18. package/dist/css.d.ts +19 -6
  19. package/dist/css.d.ts.map +1 -1
  20. package/dist/index.d.ts +18 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +41 -10
  23. package/dist/ogx.js +2 -2
  24. package/dist/perf/index.d.ts +8 -0
  25. package/dist/perf/index.d.ts.map +1 -0
  26. package/dist/perf/index.js +7 -0
  27. package/dist/perf/timing.d.ts +160 -0
  28. package/dist/perf/timing.d.ts.map +1 -0
  29. package/dist/perf/timing.js +305 -0
  30. package/dist/presets/blog.js +1 -1
  31. package/dist/presets/docs.d.ts +2 -0
  32. package/dist/presets/docs.d.ts.map +1 -1
  33. package/dist/presets/docs.js +26 -23
  34. package/dist/presets/minimal.d.ts +2 -0
  35. package/dist/presets/minimal.d.ts.map +1 -1
  36. package/dist/presets/minimal.js +8 -16
  37. package/dist/presets/social.d.ts +2 -0
  38. package/dist/presets/social.d.ts.map +1 -1
  39. package/dist/presets/social.js +28 -18
  40. package/dist/render-png.d.ts.map +1 -1
  41. package/dist/render-png.js +9 -1
  42. package/dist/render-svg.d.ts.map +1 -1
  43. package/dist/render-svg.js +11 -1
  44. package/dist/tailwind/class-cache.d.ts +141 -0
  45. package/dist/tailwind/class-cache.d.ts.map +1 -0
  46. package/dist/tailwind/class-cache.js +212 -0
  47. package/dist/tailwind/index.d.ts +14 -1
  48. package/dist/tailwind/index.d.ts.map +1 -1
  49. package/dist/tailwind/index.js +15 -1
  50. package/dist/tailwind/lookup-tables.d.ts +30 -0
  51. package/dist/tailwind/lookup-tables.d.ts.map +1 -0
  52. package/dist/tailwind/lookup-tables.js +427 -0
  53. package/dist/tailwind/parser-v2.d.ts +54 -0
  54. package/dist/tailwind/parser-v2.d.ts.map +1 -0
  55. package/dist/tailwind/parser-v2.js +250 -0
  56. package/dist/tailwind/parser.d.ts +1 -0
  57. package/dist/tailwind/parser.d.ts.map +1 -1
  58. package/dist/tailwind/parser.js +1 -0
  59. package/dist/tailwind/prefix-handlers.d.ts +68 -0
  60. package/dist/tailwind/prefix-handlers.d.ts.map +1 -0
  61. package/dist/tailwind/prefix-handlers.js +931 -0
  62. package/package.json +17 -2
@@ -3,7 +3,7 @@ import { absolute, div, h1, img, p, row, span, stack } from "../builder";
3
3
  * Docs preset - ideal for documentation sites
4
4
  */
5
5
  export const docsPreset = (props) => {
6
- const { title, description, logo, siteName, colorScheme = "dark", slots = {}, } = props;
6
+ const { title, description, logo, siteName, colorScheme = "dark", slots = {}, detailsOG = false, } = props;
7
7
  const isDark = colorScheme === "dark";
8
8
  return stack([
9
9
  "w-full",
@@ -13,56 +13,59 @@ export const docsPreset = (props) => {
13
13
  "relative",
14
14
  ], [
15
15
  // Background Accent (Subtle Grid + Glow)
16
- absolute([
17
- isDark ? "bg-grid-white/5-64" : "bg-grid-zinc-900/5-64",
18
- "inset-0",
19
- ]),
20
- absolute([
21
- "inset-0",
22
- isDark
23
- ? "bg-gradient-to-tr from-zinc-950 via-transparent to-indigo-500/10"
24
- : "bg-gradient-to-tr from-white via-transparent to-indigo-500/5",
25
- ]),
26
- absolute(["bg-grain/10"]), // Quality Boost: Dithering
16
+ ...(detailsOG
17
+ ? [
18
+ absolute([
19
+ isDark ? "bg-grid-white/5-64" : "bg-grid-zinc-900/5-64",
20
+ "inset-0",
21
+ ]),
22
+ absolute([
23
+ "inset-0",
24
+ isDark
25
+ ? "bg-gradient-to-tr from-zinc-950 via-transparent to-indigo-500/10"
26
+ : "bg-gradient-to-tr from-white via-transparent to-indigo-500/5",
27
+ ]),
28
+ ]
29
+ : []),
27
30
  // Content Layout
28
31
  stack("flex-1 gap-12 relative", [
29
32
  // Header
30
33
  slots.header ??
31
34
  row("items-center justify-between", [
32
35
  row("items-center gap-4", [
33
- logo ? img(logo, "w-10 h-10 rounded-lg shadow-sm") : null,
36
+ logo ? img(logo, "w-10 h-10") : null,
34
37
  siteName
35
38
  ? span([
36
39
  "text-2xl",
37
40
  "font-bold",
38
- isDark ? "text-white" : "text-zinc-900",
41
+ isDark ? "text-white" : "text-zinc-950",
39
42
  "tracking-tight",
40
43
  ], siteName)
41
44
  : null,
42
45
  ]),
43
46
  div([
44
- "px-5 py-1 rounded-full border text-xs font-semibold",
47
+ "px-3 py-1 rounded-full border text-xs font-semibold",
45
48
  isDark
46
- ? "bg-white/5 border-white/10 text-zinc-400"
49
+ ? "border-white/10 text-zinc-400"
47
50
  : "bg-zinc-100 border-zinc-200 text-zinc-600",
48
- ], "DOCUMENTATION"),
51
+ ], "DOCS"),
49
52
  ]),
50
53
  // Main content
51
- stack("flex-1 justify-center gap-8", [
54
+ stack("flex-1 justify-center gap-8 w-full", [
52
55
  h1([
53
56
  "text-8xl",
54
57
  "font-black",
55
58
  isDark ? "text-white" : "text-zinc-950",
56
59
  "leading-[1.1]",
57
- "tracking-tight", // Quality Boost
60
+ "tracking-tight",
61
+ "break-all",
58
62
  ], title),
59
63
  description
60
64
  ? p([
61
- "text-4xl",
62
- isDark ? "text-zinc-400" : "text-zinc-500",
63
- "max-w-[900px]",
65
+ "text-3xl",
66
+ isDark ? "text-zinc-400" : "text-zinc-600",
64
67
  "leading-relaxed",
65
- "font-semibold",
68
+ "font-medium",
66
69
  ], description)
67
70
  : null,
68
71
  ]),
@@ -8,6 +8,8 @@ export interface MinimalPresetProps {
8
8
  background?: string;
9
9
  /** Text color (Tailwind class or hex) */
10
10
  textColor?: string;
11
+ /** Color scheme */
12
+ colorScheme?: "dark" | "light";
11
13
  /** Custom slot overrides */
12
14
  slots?: {
13
15
  content?: OGXElement;
@@ -1 +1 @@
1
- {"version":3,"file":"minimal.d.ts","sourceRoot":"","sources":["../../src/presets/minimal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IAClC,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,KAAK,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,UAAU,CAAC;KACrB,CAAC;CACF;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,kBAAkB,CAqEpD,CAAC"}
1
+ {"version":3,"file":"minimal.d.ts","sourceRoot":"","sources":["../../src/presets/minimal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IAClC,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,4BAA4B;IAC5B,KAAK,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,UAAU,CAAC;KACrB,CAAC;CACF;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,kBAAkB,CA6DpD,CAAC"}
@@ -1,9 +1,9 @@
1
- import { absolute, h1, p, stack } from "../builder";
1
+ import { h1, p, stack } from "../builder";
2
2
  /**
3
3
  * Minimal preset - ultra clean, just text
4
4
  */
5
5
  export const minimalPreset = (props) => {
6
- const { title, subtitle, background = "bg-zinc-950", textColor = "text-white", slots = {}, } = props;
6
+ const { title, subtitle, colorScheme = "dark", background = colorScheme === "dark" ? "bg-zinc-950" : "bg-white", textColor = colorScheme === "dark" ? "text-white" : "text-zinc-950", slots = {}, } = props;
7
7
  const bgClass = background.startsWith("bg-")
8
8
  ? background
9
9
  : `bg-[${background}]`;
@@ -15,22 +15,14 @@ export const minimalPreset = (props) => {
15
15
  "h-full",
16
16
  "items-center",
17
17
  "justify-center",
18
- "p-24",
18
+ "p-16",
19
19
  "relative",
20
20
  bgClass,
21
21
  ], [
22
- // Subtle Background Texture
23
- absolute([
24
- "inset-0 opacity-[0.03]",
25
- background.includes("light") || background === "bg-white"
26
- ? "bg-grid-black-32"
27
- : "bg-grid-white-32",
28
- ]),
29
- absolute(["bg-grain/5"]), // Quality Boost: Dithering
30
22
  // Content
31
- stack("items-center justify-center relative", slots.content ?? [
23
+ stack("items-center justify-center relative gap-6", slots.content ?? [
32
24
  h1([
33
- "text-9xl",
25
+ "text-8xl",
34
26
  "font-black",
35
27
  "text-center",
36
28
  "tracking-tightest", // Quality Boost
@@ -39,12 +31,12 @@ export const minimalPreset = (props) => {
39
31
  ], title),
40
32
  subtitle
41
33
  ? p([
42
- "text-3xl",
34
+ "text-2xl",
43
35
  "text-center",
44
- "mt-10",
36
+ "mt-2",
45
37
  "opacity-40",
46
38
  "font-medium",
47
- "tracking-wide",
39
+ "tracking-tight",
48
40
  textClass,
49
41
  ], subtitle.toUpperCase())
50
42
  : null,
@@ -16,6 +16,8 @@ export interface SocialPresetProps {
16
16
  fromColor?: string;
17
17
  /** To color (hex) */
18
18
  toColor?: string;
19
+ /** Color scheme */
20
+ colorScheme?: "dark" | "light";
19
21
  /** Custom slot overrides */
20
22
  slots?: {
21
23
  header?: OGXElement;
@@ -1 +1 @@
1
- {"version":3,"file":"social.d.ts","sourceRoot":"","sources":["../../src/presets/social.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IACjC,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,KAAK,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,UAAU,CAAC;QACpB,MAAM,CAAC,EAAE,UAAU,CAAC;KACpB,CAAC;CACF;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,iBAAiB,CAkGlD,CAAC"}
1
+ {"version":3,"file":"social.d.ts","sourceRoot":"","sources":["../../src/presets/social.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IACjC,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,4BAA4B;IAC5B,KAAK,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,UAAU,CAAC;QACpB,MAAM,CAAC,EAAE,UAAU,CAAC;KACpB,CAAC;CACF;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,iBAAiB,CA6GlD,CAAC"}
@@ -1,11 +1,12 @@
1
- import { absolute, h1, img, row, span, stack } from "../builder";
1
+ import { h1, img, row, span, stack } from "../builder";
2
2
  /**
3
3
  * Social preset - card-style for social media
4
4
  */
5
5
  export const socialPreset = (props) => {
6
- const { title, handle, avatar, brand, logo, gradient = "to-br", fromColor = "oklch(65% 0.25 260)", // Vibrant Indigo-ish
6
+ const { title, handle, avatar, brand, logo, colorScheme = "dark", gradient = "to-br", fromColor = "oklch(65% 0.25 260)", // Vibrant Indigo-ish
7
7
  toColor = "oklch(60% 0.3 300)", // Vibrant Purple-ish
8
8
  slots = {}, } = props;
9
+ const isDark = colorScheme === "dark";
9
10
  const gradientStyle = `linear-gradient(${gradient === "to-r"
10
11
  ? "90deg"
11
12
  : gradient === "to-br"
@@ -14,53 +15,62 @@ export const socialPreset = (props) => {
14
15
  ? "180deg"
15
16
  : "225deg"}, ${fromColor}, ${toColor})`;
16
17
  return stack(["w-full", "h-full", "p-20", "relative", "overflow-hidden"], [
17
- // Background Gradient
18
- absolute("", null, { style: { backgroundImage: gradientStyle } }),
19
- // Subtle Background Texture (Grain/Noise-like mesh)
20
- absolute(["inset-0 opacity-20", "bg-grid-white/5-32"]),
21
- absolute(["bg-grain/15"]), // Quality Boost: Dithering
22
- // Content Layout
18
+ // Content Layout (background applied on container to avoid extra layers)
23
19
  stack("flex-1 justify-between relative", [
24
20
  // Header
25
21
  slots.header ??
26
22
  row("items-center justify-between", [
27
23
  row("items-center gap-4", [
28
- logo ? img(logo, "w-12 h-12 rounded-xl bg-zinc-950") : null,
24
+ logo
25
+ ? img(logo, [
26
+ "w-12 h-12 rounded-xl shadow-lg",
27
+ isDark ? "bg-zinc-950" : "bg-white border border-zinc-200",
28
+ ])
29
+ : null,
29
30
  brand
30
- ? span(["text-2xl font-black text-white tracking-tighter"], brand.toUpperCase())
31
+ ? span([
32
+ "text-2xl font-black tracking-tighter",
33
+ isDark ? "text-white" : "text-zinc-950",
34
+ ], brand.toUpperCase())
31
35
  : null,
32
36
  ]),
33
37
  // Subtle platform indicator
34
- span(["text-white/30 text-xs font-bold tracking-widest"], "SOCIAL CARD"),
38
+ span([
39
+ isDark ? "text-white/30" : "text-black/30",
40
+ "text-xs font-bold tracking-widest",
41
+ ], "SOCIAL CARD"),
35
42
  ]),
36
43
  // Main content
37
44
  stack("gap-6 overflow-hidden", [
38
45
  h1([
39
46
  "text-7xl",
40
47
  "font-black",
41
- "text-white",
48
+ isDark ? "text-white" : "text-zinc-950",
42
49
  "leading-[1.05]",
43
- "tracking-tight", // Quality Boost
50
+ "tracking-tight",
44
51
  ], title),
45
52
  ]),
46
53
  // Footer with user info (Clean Glass Badge)
47
54
  slots.footer ??
48
55
  (handle || avatar
49
56
  ? row([
50
- "items-center gap-4 p-3 pr-6 rounded-full self-start shadow-premium",
51
- "bg-black/10 border border-white/10 backdrop-blur-md",
57
+ "items-center gap-4 p-3 pr-6 rounded-full self-start shadow-lg",
58
+ isDark
59
+ ? "bg-black/20 border border-white/20"
60
+ : "bg-white/40 border border-black/10",
52
61
  ], [
53
62
  avatar
54
63
  ? img(avatar, "w-10 h-10 rounded-full border border-white/20 shadow-sm")
55
64
  : null,
56
65
  handle
57
66
  ? span([
58
- "text-xl font-bold text-white/90 tracking-tight",
59
- "w-fit truncate shrink-0",
67
+ "text-xl font-bold tracking-tight",
68
+ isDark ? "text-white/90" : "text-zinc-900/90",
69
+ "truncate",
60
70
  ], handle)
61
71
  : null,
62
72
  ])
63
73
  : null),
64
74
  ]),
65
- ]);
75
+ ], { style: { backgroundImage: gradientStyle } });
66
76
  };
@@ -1 +1 @@
1
- {"version":3,"file":"render-png.d.ts","sourceRoot":"","sources":["../src/render-png.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEzD;;;GAGG;AACH,wBAAsB,MAAM,CAC3B,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,UAAU,CAAC,CAiBrB"}
1
+ {"version":3,"file":"render-png.d.ts","sourceRoot":"","sources":["../src/render-png.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEzD;;;GAGG;AACH,wBAAsB,MAAM,CAC3B,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,UAAU,CAAC,CA8BrB"}
@@ -4,7 +4,10 @@ import { renderToSVG } from "./render-svg";
4
4
  * Node.js only: uses @resvg/resvg-js for SVG → PNG conversion
5
5
  */
6
6
  export async function render(element, options = {}) {
7
+ const profile = process.env.OGX_PROFILE === "1";
8
+ const tStart = profile ? performance.now() : 0;
7
9
  const svg = await renderToSVG(element, options);
10
+ const tAfterSvg = profile ? performance.now() : 0;
8
11
  const width = options.width ?? 1200;
9
12
  const resvgPkg = "@resvg/resvg-js";
10
13
  const { Resvg } = await import(resvgPkg);
@@ -15,5 +18,10 @@ export async function render(element, options = {}) {
15
18
  },
16
19
  });
17
20
  const pngData = resvg.render();
18
- return pngData.asPng();
21
+ const result = pngData.asPng();
22
+ if (profile) {
23
+ const tEnd = performance.now();
24
+ console.log(`[OGX PROFILE] render png: svg=${(tAfterSvg - tStart).toFixed(2)}ms resvg=${(tEnd - tAfterSvg).toFixed(2)}ms total=${(tEnd - tStart).toFixed(2)}ms`);
25
+ }
26
+ return result;
19
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"render-svg.d.ts","sourceRoot":"","sources":["../src/render-svg.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEX,UAAU,EACV,aAAa,EAEb,MAAM,SAAS,CAAC;AAKjB;;;GAGG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,CA2CjB"}
1
+ {"version":3,"file":"render-svg.d.ts","sourceRoot":"","sources":["../src/render-svg.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEX,UAAU,EACV,aAAa,EAEb,MAAM,SAAS,CAAC;AAKjB;;;GAGG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,CAyDjB"}
@@ -9,6 +9,8 @@ const DEFAULT_HEIGHT = 630;
9
9
  * Browser-safe: uses only Satori (no Node.js dependencies)
10
10
  */
11
11
  export async function renderToSVG(element, options = {}) {
12
+ const profile = process.env.OGX_PROFILE === "1";
13
+ const tStart = profile ? performance.now() : 0;
12
14
  const platformDims = options.platform
13
15
  ? getPlatformDimensions(options.platform)
14
16
  : null;
@@ -35,13 +37,21 @@ export async function renderToSVG(element, options = {}) {
35
37
  theme: options.theme,
36
38
  colorScheme: options.colorScheme,
37
39
  };
40
+ const tTransformStart = profile ? performance.now() : 0;
38
41
  const transformedElement = transformElement(element, debug, fullOptions);
39
- return await satori(transformedElement, {
42
+ const tTransformEnd = profile ? performance.now() : 0;
43
+ const svg = await satori(transformedElement, {
40
44
  width,
41
45
  height,
42
46
  fonts: resolvedFonts.map(fontToSatoriFont),
43
47
  debug,
44
48
  });
49
+ if (profile) {
50
+ const tEnd = performance.now();
51
+ // Log coarse-grained timings for debugging hot paths
52
+ console.log(`[OGX PROFILE] renderToSVG transform=${(tTransformEnd - tTransformStart).toFixed(2)}ms satori=${(tEnd - tTransformEnd).toFixed(2)}ms total=${(tEnd - tStart).toFixed(2)}ms`);
53
+ }
54
+ return svg;
45
55
  }
46
56
  /**
47
57
  * Transform OGX element tree to Satori-compatible format
@@ -0,0 +1,141 @@
1
+ /**
2
+ * @ogxjs/core - Tailwind Class Cache
3
+ * Per-class caching for maximum performance
4
+ *
5
+ * @description
6
+ * Caches individual parsed classes instead of full class strings.
7
+ * This allows reuse across different elements with overlapping classes.
8
+ *
9
+ * @example
10
+ * Element A: "flex bg-blue-500 p-4"
11
+ * Element B: "flex bg-red-500 p-4"
12
+ * → "flex" and "p-4" are parsed once, reused for both
13
+ *
14
+ * @performance
15
+ * - Eliminates redundant parsing for common classes
16
+ * - Reduces memory by sharing parsed results
17
+ * - O(1) lookup per class
18
+ *
19
+ * @version 0.2.0 "Turbo"
20
+ */
21
+ import type { CSSProperties } from "../css";
22
+ /**
23
+ * Cache for individual parsed Tailwind classes
24
+ * Key: class name (e.g., "bg-blue-500")
25
+ * Value: parsed CSS properties
26
+ *
27
+ * @performance v0.2.0 Turbo optimizations:
28
+ * - Direct reference return (no spread copy) - trust consumers
29
+ * - No Object.freeze - avoid expensive operation
30
+ * - Lazy eviction check
31
+ */
32
+ declare class TailwindClassCache {
33
+ private cache;
34
+ private hits;
35
+ private misses;
36
+ /**
37
+ * Get cached CSS properties for a class
38
+ * @returns Cached properties or undefined if not cached
39
+ *
40
+ * @performance Returns direct reference - DO NOT MUTATE
41
+ */
42
+ get(cls: string): CSSProperties | undefined;
43
+ /**
44
+ * Cache CSS properties for a class
45
+ * @param cls - Tailwind class name
46
+ * @param props - Parsed CSS properties (will be stored directly)
47
+ */
48
+ set(cls: string, props: CSSProperties): void;
49
+ /**
50
+ * Check if a class has cached properties
51
+ */
52
+ has(cls: string): boolean;
53
+ /**
54
+ * Clear the entire cache
55
+ */
56
+ clear(): void;
57
+ /**
58
+ * Get cache statistics
59
+ */
60
+ getStats(): CacheStats;
61
+ /**
62
+ * Check if a class should not be cached
63
+ */
64
+ private isUncacheable;
65
+ /**
66
+ * Evict oldest entries (FIFO strategy)
67
+ * Removes 10% of cache to avoid frequent evictions
68
+ */
69
+ private evictOldest;
70
+ }
71
+ /**
72
+ * Cache for full class strings (entire tw prop)
73
+ * Useful when the same exact class string is used multiple times
74
+ *
75
+ * Key: "flex bg-blue-500 p-4"
76
+ * Value: merged CSS properties
77
+ *
78
+ * @performance v0.2.0 Turbo optimizations:
79
+ * - Direct reference return (no spread copy)
80
+ * - No Object.freeze
81
+ * - Efficient LRU-like eviction
82
+ */
83
+ declare class TailwindStringCache {
84
+ private cache;
85
+ private maxSize;
86
+ /**
87
+ * Get cached properties for a full class string
88
+ * @performance Returns direct reference - DO NOT MUTATE
89
+ */
90
+ get(key: string): CSSProperties | undefined;
91
+ /**
92
+ * Cache properties for a full class string
93
+ */
94
+ set(key: string, props: CSSProperties): void;
95
+ /**
96
+ * Check if a string has cached properties
97
+ */
98
+ has(key: string): boolean;
99
+ /**
100
+ * Clear the cache
101
+ */
102
+ clear(): void;
103
+ /**
104
+ * Get cache size
105
+ */
106
+ get size(): number;
107
+ }
108
+ export interface CacheStats {
109
+ /** Current number of cached classes */
110
+ size: number;
111
+ /** Maximum cache size */
112
+ maxSize: number;
113
+ /** Number of cache hits */
114
+ hits: number;
115
+ /** Number of cache misses */
116
+ misses: number;
117
+ /** Hit rate (0-1) */
118
+ hitRate: number;
119
+ }
120
+ /**
121
+ * Singleton instance for class-level caching
122
+ */
123
+ export declare const classCache: TailwindClassCache;
124
+ /**
125
+ * Singleton instance for full string caching
126
+ */
127
+ export declare const stringCache: TailwindStringCache;
128
+ /**
129
+ * Clear all Tailwind caches
130
+ * Useful for testing or when theme changes
131
+ */
132
+ export declare function clearAllCaches(): void;
133
+ /**
134
+ * Get combined cache statistics
135
+ */
136
+ export declare function getCacheStats(): {
137
+ classCache: CacheStats;
138
+ stringCacheSize: number;
139
+ };
140
+ export {};
141
+ //# sourceMappingURL=class-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-cache.d.ts","sourceRoot":"","sources":["../../src/tailwind/class-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAmB5C;;;;;;;;;GASG;AACH,cAAM,kBAAkB;IACvB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IAEnB;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAU3C;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAa5C;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,QAAQ,IAAI,UAAU;IAWtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACH,OAAO,CAAC,WAAW;CAUnB;AAID;;;;;;;;;;;GAWG;AACH,cAAM,mBAAmB;IACxB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,OAAO,CAAQ;IAEvB;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI3C;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAe5C;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACD;AAID,MAAM,WAAW,UAAU;IAC1B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;CAChB;AAID;;GAEG;AACH,eAAO,MAAM,UAAU,oBAA2B,CAAC;AAEnD;;GAEG;AACH,eAAO,MAAM,WAAW,qBAA4B,CAAC;AAErD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACxB,CAKA"}