@tin.so/core 0.3.0 → 0.5.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.
@@ -817,1606 +817,1647 @@ function blend(top, bottom) {
817
817
  const mix = (a, b) => Math.round(a * alpha + b * (1 - alpha));
818
818
  return `rgb(${mix(r1, r2)}, ${mix(g1, g2)}, ${mix(b1, b2)})`;
819
819
  }
820
- // src/themes/index.ts
821
- const THEMES = [
822
- {
823
- "id": "ayu",
824
- "name": "Ayu",
825
- "background": {
826
- "from": "#ff8f40",
827
- "to": "#ffb454"
828
- },
829
- "textmate": {
830
- "dark": "ayu-dark",
831
- "light": "ayu-light"
832
- },
833
- "window": {
834
- "dark": {
835
- "background": "#10141c",
836
- "title": "#5a6378",
837
- "lineNumber": "#5a6378a6",
838
- "divider": "#1b1f29"
839
- },
840
- "light": {
841
- "background": "#fcfcfc",
842
- "title": "#828e9f",
843
- "lineNumber": "#828e9f66",
844
- "divider": "#6b7d8f1f"
845
- }
846
- },
847
- "syntax": {
848
- "dark": {
849
- "foreground": "#bfbdb6",
850
- "keyword": "#ff8f40",
851
- "string": "#aad94c",
852
- "function": "#ffb454",
853
- "comment": "#5a6673",
854
- "highlight": "#161a24"
855
- },
856
- "light": {
857
- "foreground": "#5c6166",
858
- "keyword": "#fa8532",
859
- "string": "#86b300",
860
- "function": "#eba400",
861
- "comment": "#adaeb1",
862
- "highlight": "#828e9f1a"
863
- }
864
- }
865
- },
866
- {
867
- "id": "catppuccin",
868
- "name": "Catppuccin",
869
- "background": {
870
- "from": "#cba6f7",
871
- "to": "#f5c2e7"
872
- },
873
- "textmate": {
874
- "dark": "catppuccin-mocha",
875
- "light": "catppuccin-latte"
876
- },
877
- "window": {
878
- "dark": {
879
- "background": "#1e1e2e",
880
- "title": "#cdd6f4",
881
- "lineNumber": "#7f849c",
882
- "divider": "#181825"
883
- },
884
- "light": {
885
- "background": "#eff1f5",
886
- "title": "#4c4f69",
887
- "lineNumber": "#8c8fa1",
888
- "divider": "#e6e9ef"
889
- }
890
- },
891
- "syntax": {
892
- "dark": {
893
- "foreground": "#cdd6f4",
894
- "keyword": "#cba6f7",
895
- "string": "#a6e3a1",
896
- "function": "#89b4fa",
897
- "comment": "#9399b2",
898
- "highlight": "#cdd6f412"
899
- },
900
- "light": {
901
- "foreground": "#4c4f69",
902
- "keyword": "#8839ef",
903
- "string": "#40a02b",
904
- "function": "#1e66f5",
905
- "comment": "#7c7f93",
906
- "highlight": "#4c4f6912"
907
- }
908
- }
820
+ // src/gradient.ts
821
+ const HEX = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
822
+ const NUMBER = String.raw`[+-]?(?:\d+\.?\d*|\.\d+)`;
823
+ const LENGTH = new RegExp(`^(${NUMBER})(%|px)?$`, "i");
824
+ const ANGLE = new RegExp(`^(${NUMBER})(deg|turn|rad|grad)$`, "i");
825
+ const SIDES = {
826
+ left: { x: -1 },
827
+ right: { x: 1 },
828
+ top: { y: -1 },
829
+ bottom: { y: 1 }
830
+ };
831
+ const EXTENTS = /* @__PURE__ */ new Set([
832
+ "closest-side",
833
+ "closest-corner",
834
+ "farthest-side",
835
+ "farthest-corner"
836
+ ]);
837
+ const POSITION_KEYWORDS = {
838
+ left: {
839
+ axis: "x",
840
+ value: 0
909
841
  },
910
- {
911
- "id": "vscode",
912
- "name": "VS Code",
913
- "background": {
914
- "from": "#c586c0",
915
- "to": "#dcdcaa"
916
- },
917
- "textmate": {
918
- "dark": "dark-plus",
919
- "light": "light-plus"
920
- },
921
- "window": {
922
- "dark": { "background": "#1e1e1e" },
923
- "light": { "background": "#ffffff" }
924
- },
925
- "syntax": {
926
- "dark": {
927
- "foreground": "#d4d4d4",
928
- "keyword": "#c586c0",
929
- "string": "#ce9178",
930
- "function": "#dcdcaa",
931
- "comment": "#6a9955"
932
- },
933
- "light": {
934
- "foreground": "#000000",
935
- "keyword": "#af00db",
936
- "string": "#a31515",
937
- "function": "#795e26",
938
- "comment": "#008000"
939
- }
940
- }
842
+ right: {
843
+ axis: "x",
844
+ value: 100
941
845
  },
942
- {
943
- "id": "dracula",
944
- "name": "Dracula",
945
- "background": {
946
- "from": "#bd93f9",
947
- "to": "#ff79c6"
948
- },
949
- "textmate": {
950
- "dark": "dracula",
951
- "light": "dracula-alucard"
952
- },
953
- "window": {
954
- "dark": {
955
- "background": "#282a36",
956
- "title": "#f8f8f2",
957
- "lineNumber": "#6272a4",
958
- "divider": "#191a21"
959
- },
960
- "light": {
961
- "background": "#fffbeb",
962
- "title": "#1f1f1f",
963
- "lineNumber": "#6c664b",
964
- "divider": "#ceccc0"
965
- }
966
- },
967
- "syntax": {
968
- "dark": {
969
- "foreground": "#f8f8f2",
970
- "keyword": "#ff79c6",
971
- "string": "#f1fa8c",
972
- "function": "#50fa7b",
973
- "comment": "#6272a4",
974
- "highlight": "#44475a"
975
- },
976
- "light": {
977
- "foreground": "#1f1f1f",
978
- "keyword": "#a3144d",
979
- "string": "#846e15",
980
- "function": "#14710a",
981
- "comment": "#6c664b",
982
- "highlight": "#e2deca95"
983
- }
984
- }
846
+ top: {
847
+ axis: "y",
848
+ value: 0
985
849
  },
986
- {
987
- "id": "github",
988
- "name": "GitHub",
989
- "background": {
990
- "from": "#ff7b72",
991
- "to": "#d2a8ff"
992
- },
993
- "textmate": {
994
- "dark": "github-dark-default",
995
- "light": "github-light-default"
996
- },
997
- "window": {
998
- "dark": {
999
- "background": "#0d1117",
1000
- "title": "#7d8590",
1001
- "lineNumber": "#6e7681",
1002
- "divider": "#30363d"
1003
- },
1004
- "light": {
1005
- "background": "#ffffff",
1006
- "title": "#656d76",
1007
- "lineNumber": "#8c959f",
1008
- "divider": "#d0d7de"
1009
- }
1010
- },
1011
- "syntax": {
1012
- "dark": {
1013
- "foreground": "#e6edf3",
1014
- "keyword": "#ff7b72",
1015
- "string": "#a5d6ff",
1016
- "function": "#d2a8ff",
1017
- "comment": "#8b949e",
1018
- "highlight": "#6e76811a"
1019
- },
1020
- "light": {
1021
- "foreground": "#1f2328",
1022
- "keyword": "#cf222e",
1023
- "string": "#0a3069",
1024
- "function": "#8250df",
1025
- "comment": "#6e7781",
1026
- "highlight": "#eaeef280"
1027
- }
1028
- }
850
+ bottom: {
851
+ axis: "y",
852
+ value: 100
1029
853
  },
1030
- {
1031
- "id": "material",
1032
- "name": "Material",
1033
- "background": {
1034
- "from": "#89ddff",
1035
- "to": "#82aaff"
1036
- },
1037
- "textmate": {
1038
- "dark": "material-theme",
1039
- "light": "material-theme-lighter"
1040
- },
1041
- "window": {
1042
- "dark": {
1043
- "background": "#263238",
1044
- "title": "#eeffff",
1045
- "lineNumber": "#465a64",
1046
- "divider": "#263238"
1047
- },
1048
- "light": {
1049
- "background": "#fafafa",
1050
- "title": "#90a4ae",
1051
- "lineNumber": "#cfd8dc",
1052
- "divider": "#fafafa"
1053
- }
1054
- },
1055
- "syntax": {
1056
- "dark": {
1057
- "foreground": "#eeffff",
1058
- "keyword": "#89ddff",
1059
- "string": "#c3e88d",
1060
- "function": "#82aaff",
1061
- "comment": "#546e7a",
1062
- "highlight": "#00000050"
1063
- },
1064
- "light": {
1065
- "foreground": "#90a4ae",
1066
- "keyword": "#39adb5",
1067
- "string": "#91b859",
1068
- "function": "#6182b8",
1069
- "comment": "#90a4ae",
1070
- "highlight": "#ccd7da50"
1071
- }
854
+ center: { value: 50 }
855
+ };
856
+ /** Splits at the separator outside of parentheses */
857
+ function split(text, separator) {
858
+ const parts = [];
859
+ let depth = 0;
860
+ let current = "";
861
+ for (const char of text) {
862
+ if (char === "(") depth++;
863
+ if (char === ")") depth--;
864
+ if (depth < 0) throw new Error("unbalanced parentheses");
865
+ if ((separator === " " ? /\s/.test(char) : char === separator) && depth === 0) {
866
+ parts.push(current.trim());
867
+ current = "";
868
+ } else current += char;
869
+ }
870
+ if (depth !== 0) throw new Error("unbalanced parentheses");
871
+ parts.push(current.trim());
872
+ return separator === " " ? parts.filter(Boolean) : parts;
873
+ }
874
+ function parseHex(hex) {
875
+ const digits = hex.slice(1);
876
+ const full = digits.length <= 4 ? digits.replace(/./g, "$&$&") : digits;
877
+ const channel = (index) => parseInt(full.slice(index * 2, index * 2 + 2), 16);
878
+ return {
879
+ r: channel(0),
880
+ g: channel(1),
881
+ b: channel(2),
882
+ a: full.length === 8 ? channel(3) / 255 : 1
883
+ };
884
+ }
885
+ function parseChannel(text, max) {
886
+ const match = LENGTH.exec(text);
887
+ if (!match || match[2]?.toLowerCase() === "px") throw new Error(`invalid color channel ${text}`);
888
+ const value = Number(match[1]);
889
+ const scaled = match[2] === "%" ? value / 100 * max : value;
890
+ return Math.min(max, Math.max(0, scaled));
891
+ }
892
+ function parseColor(text) {
893
+ const color = text.trim().toLowerCase();
894
+ if (color === "transparent") return {
895
+ r: 0,
896
+ g: 0,
897
+ b: 0,
898
+ a: 0
899
+ };
900
+ if (HEX.test(color)) return parseHex(color);
901
+ const fn = /^rgba?\((.*)\)$/.exec(color);
902
+ if (!fn) return void 0;
903
+ const [channels, alpha] = fn[1].includes("/") ? fn[1].split("/") : [fn[1], void 0];
904
+ const parts = channels.includes(",") ? channels.split(",").map((part) => part.trim()) : split(channels, " ");
905
+ if (alpha !== void 0 && parts.length !== 3) return void 0;
906
+ if (parts.length !== 3 && parts.length !== 4) return void 0;
907
+ const [r, g, b] = parts.slice(0, 3).map((part) => parseChannel(part, 255));
908
+ const a = alpha ?? parts[3];
909
+ return {
910
+ r,
911
+ g,
912
+ b,
913
+ a: a === void 0 ? 1 : parseChannel(a.trim(), 1)
914
+ };
915
+ }
916
+ function parseLength(text) {
917
+ const match = LENGTH.exec(text);
918
+ if (!match) throw new Error(`invalid length ${text}`);
919
+ const value = Number(match[1]);
920
+ if (!match[2] && value !== 0) throw new Error(`a length needs % or px: ${text}`);
921
+ return {
922
+ value,
923
+ unit: match[2]?.toLowerCase() ?? "px"
924
+ };
925
+ }
926
+ function parseStops(args) {
927
+ const stops = args.flatMap((arg) => {
928
+ const [colorText, ...positions] = split(arg, " ");
929
+ const color = parseColor(colorText ?? "");
930
+ if (!color || positions.length > 2) throw new Error(`invalid color stop ${arg}`);
931
+ if (positions.length === 0) return [{ color }];
932
+ return positions.map((position) => ({
933
+ color,
934
+ position: parseLength(position)
935
+ }));
936
+ });
937
+ if (stops.length < 2) throw new Error("a gradient needs two colors");
938
+ return stops;
939
+ }
940
+ function parseAngle(text) {
941
+ const match = ANGLE.exec(text);
942
+ if (!match) return void 0;
943
+ const value = Number(match[1]);
944
+ const unit = match[2].toLowerCase();
945
+ if (unit === "turn") return value * 360;
946
+ if (unit === "rad") return value * 180 / Math.PI;
947
+ if (unit === "grad") return value * .9;
948
+ return value;
949
+ }
950
+ function parseLinear(args) {
951
+ const first = args[0];
952
+ const angle = parseAngle(first);
953
+ if (angle !== void 0) return {
954
+ type: "linear",
955
+ direction: { angle },
956
+ stops: parseStops(args.slice(1))
957
+ };
958
+ const words = split(first, " ");
959
+ if (words[0] === "to") {
960
+ const to = {
961
+ x: 0,
962
+ y: 0
963
+ };
964
+ for (const word of words.slice(1)) {
965
+ const side = SIDES[word];
966
+ if (!side || words.length > 3) throw new Error(`invalid direction ${first}`);
967
+ Object.assign(to, side);
1072
968
  }
1073
- },
1074
- {
1075
- "id": "night-owl",
1076
- "name": "Night Owl",
1077
- "background": {
1078
- "from": "#c792ea",
1079
- "to": "#82aaff"
1080
- },
1081
- "textmate": {
1082
- "dark": "night-owl",
1083
- "light": "night-owl-light"
1084
- },
1085
- "window": {
1086
- "dark": {
1087
- "background": "#011627",
1088
- "title": "#eeefff",
1089
- "lineNumber": "#4b6479",
1090
- "divider": "#262a39"
1091
- },
1092
- "light": {
1093
- "background": "#fbfbfb",
1094
- "title": "#403f53",
1095
- "lineNumber": "#90a7b2",
1096
- "divider": "#f0f0f0"
1097
- }
1098
- },
1099
- "syntax": {
1100
- "dark": {
1101
- "foreground": "#d6deeb",
1102
- "keyword": "#c792ea",
1103
- "string": "#ecc48d",
1104
- "function": "#82aaff",
1105
- "comment": "#637777",
1106
- "highlight": "#28707d29"
969
+ if (words.length < 2) throw new Error(`invalid direction ${first}`);
970
+ return {
971
+ type: "linear",
972
+ direction: { to },
973
+ stops: parseStops(args.slice(1))
974
+ };
975
+ }
976
+ return {
977
+ type: "linear",
978
+ direction: { angle: 180 },
979
+ stops: parseStops(args)
980
+ };
981
+ }
982
+ function parsePosition(words) {
983
+ if (words.length < 1 || words.length > 2) throw new Error("invalid position");
984
+ const at = {};
985
+ const loose = [];
986
+ for (const word of words) {
987
+ const keyword = POSITION_KEYWORDS[word];
988
+ if (keyword?.axis) at[keyword.axis] = {
989
+ value: keyword.value,
990
+ unit: "%"
991
+ };
992
+ else loose.push(keyword ? {
993
+ value: keyword.value,
994
+ unit: "%"
995
+ } : parseLength(word));
996
+ }
997
+ for (const length of loose) if (!at.x) at.x = length;
998
+ else if (!at.y) at.y = length;
999
+ else throw new Error("invalid position");
1000
+ const center = {
1001
+ value: 50,
1002
+ unit: "%"
1003
+ };
1004
+ return {
1005
+ x: at.x ?? center,
1006
+ y: at.y ?? center
1007
+ };
1008
+ }
1009
+ function parseRadial(args) {
1010
+ const first = split(args[0], " ");
1011
+ const isPrelude = first.some((word) => word === "at" || word === "circle" || word === "ellipse" || EXTENTS.has(word)) || parseColor(first[0] ?? "") === void 0 && LENGTH.test(first[0] ?? "");
1012
+ const layer = {
1013
+ type: "radial",
1014
+ shape: "ellipse",
1015
+ size: "farthest-corner",
1016
+ at: {
1017
+ x: {
1018
+ value: 50,
1019
+ unit: "%"
1107
1020
  },
1108
- "light": {
1109
- "foreground": "#403f53",
1110
- "keyword": "#994cc3",
1111
- "string": "#c96765",
1112
- "function": "#4876d6",
1113
- "comment": "#989fb1",
1114
- "highlight": "#f0f0f0"
1021
+ y: {
1022
+ value: 50,
1023
+ unit: "%"
1115
1024
  }
1116
- }
1117
- },
1118
- {
1119
- "id": "nord",
1120
- "name": "Nord",
1121
- "background": {
1122
- "from": "#5e81ac",
1123
- "to": "#8fbcbb"
1124
1025
  },
1125
- "textmate": { "dark": "nord" },
1126
- "window": { "dark": {
1127
- "background": "#2e3440",
1128
- "title": "#d8dee9",
1129
- "lineNumber": "#4c566a",
1130
- "divider": "#3b425200"
1131
- } },
1132
- "syntax": { "dark": {
1133
- "foreground": "#d8dee9",
1134
- "keyword": "#81a1c1",
1135
- "string": "#a3be8c",
1136
- "function": "#88c0d0",
1137
- "comment": "#616e88",
1138
- "highlight": "#3b4252"
1139
- } }
1140
- },
1141
- {
1142
- "id": "one-dark",
1143
- "name": "One Dark",
1144
- "background": {
1145
- "from": "#61afef",
1146
- "to": "#c678dd"
1147
- },
1148
- "textmate": {
1149
- "dark": "one-dark-pro",
1150
- "light": "one-light"
1151
- },
1152
- "window": {
1153
- "dark": {
1154
- "background": "#282c34",
1155
- "title": "#9da5b4",
1156
- "lineNumber": "#495162",
1157
- "divider": "#181a1f"
1158
- },
1159
- "light": {
1160
- "background": "#fafafa",
1161
- "title": "#424243",
1162
- "lineNumber": "#9d9d9f",
1163
- "divider": "#dbdbdc"
1164
- }
1165
- },
1166
- "syntax": {
1167
- "dark": {
1168
- "foreground": "#abb2bf",
1169
- "keyword": "#c678dd",
1170
- "string": "#98c379",
1171
- "function": "#61afef",
1172
- "comment": "#7f848e",
1173
- "highlight": "#2c313c"
1174
- },
1175
- "light": {
1176
- "foreground": "#383a42",
1177
- "keyword": "#a626a4",
1178
- "string": "#50a14f",
1179
- "function": "#4078f2",
1180
- "comment": "#a0a1a7",
1181
- "highlight": "#383a420c"
1026
+ stops: parseStops(isPrelude ? args.slice(1) : args)
1027
+ };
1028
+ if (!isPrelude) return layer;
1029
+ const atIndex = first.indexOf("at");
1030
+ const shapeWords = atIndex === -1 ? first : first.slice(0, atIndex);
1031
+ if (atIndex !== -1) layer.at = parsePosition(first.slice(atIndex + 1));
1032
+ const sizes = [];
1033
+ let shape;
1034
+ for (const word of shapeWords) if (word === "circle" || word === "ellipse") shape = word;
1035
+ else if (EXTENTS.has(word)) layer.size = word;
1036
+ else sizes.push(parseLength(word));
1037
+ if (sizes.length === 1) {
1038
+ if (shape === "ellipse" || sizes[0].unit === "%") throw new Error("a circle needs one px size");
1039
+ layer.size = {
1040
+ x: sizes[0],
1041
+ y: sizes[0]
1042
+ };
1043
+ shape = "circle";
1044
+ } else if (sizes.length === 2) {
1045
+ if (shape === "circle") throw new Error("an ellipse needs two sizes");
1046
+ layer.size = {
1047
+ x: sizes[0],
1048
+ y: sizes[1]
1049
+ };
1050
+ } else if (sizes.length > 2) throw new Error("invalid size");
1051
+ layer.shape = shape ?? "ellipse";
1052
+ return layer;
1053
+ }
1054
+ function parseLayer(text, last) {
1055
+ const fn = /^([a-z-]+)\((.*)\)$/is.exec(text);
1056
+ const name = fn?.[1]?.toLowerCase();
1057
+ if (name === "linear-gradient") return parseLinear(split(fn[2], ","));
1058
+ if (name === "radial-gradient") return parseRadial(split(fn[2], ","));
1059
+ const color = parseColor(text);
1060
+ if (!color) throw new Error(`invalid layer ${text}`);
1061
+ if (!last) throw new Error("only the last layer can be a color");
1062
+ return {
1063
+ type: "color",
1064
+ color
1065
+ };
1066
+ }
1067
+ /** Parses a CSS background, or gives undefined when the spec cannot use it */
1068
+ function parseBackground(css) {
1069
+ try {
1070
+ const parts = split(css.trim().replace(/\s+/g, " "), ",");
1071
+ if (parts.length > 16 || parts.some((part) => part === "")) return void 0;
1072
+ return parts.map((part, index) => parseLayer(part, index === parts.length - 1));
1073
+ } catch {
1074
+ return;
1075
+ }
1076
+ }
1077
+ function isCssBackground(css) {
1078
+ return parseBackground(css) !== void 0;
1079
+ }
1080
+ function hex$2({ r, g, b }) {
1081
+ return `#${[
1082
+ r,
1083
+ g,
1084
+ b
1085
+ ].map((channel) => Math.round(channel).toString(16).padStart(2, "0")).join("")}`;
1086
+ }
1087
+ /**
1088
+ * A color for the places that need one color of the background, such as the color below a
1089
+ * translucent window: the color layer, or else the first visible color of the bottom layer.
1090
+ */
1091
+ function backgroundBaseColor(background) {
1092
+ const bottom = background.at(-1);
1093
+ if (bottom.type === "color") return hex$2(bottom.color);
1094
+ return hex$2((bottom.stops.find((stop) => stop.color.a > 0) ?? bottom.stops[0]).color);
1095
+ }
1096
+ /**
1097
+ * The offsets of the stops from 0 to 1 along a gradient ray of a length in px, with the rules of
1098
+ * CSS: the first stop is at 0, the last at 1, a stop is never before the one ahead of it, and
1099
+ * stops without a position share the space between their neighbors.
1100
+ */
1101
+ function stopOffsets(stops, length) {
1102
+ const offsets = stops.map(({ position }) => position === void 0 ? void 0 : position.unit === "%" ? position.value / 100 : position.value / Math.max(length, .01));
1103
+ offsets[0] ??= 0;
1104
+ offsets[offsets.length - 1] ??= 1;
1105
+ let max = offsets[0];
1106
+ for (let i = 0; i < offsets.length; i++) if (offsets[i] !== void 0) {
1107
+ max = Math.max(max, offsets[i]);
1108
+ offsets[i] = max;
1109
+ }
1110
+ for (let i = 1; i < offsets.length; i++) {
1111
+ if (offsets[i] !== void 0) continue;
1112
+ let end = i;
1113
+ while (offsets[end] === void 0) end++;
1114
+ const start = offsets[i - 1];
1115
+ const step = (offsets[end] - start) / (end - i + 1);
1116
+ for (let k = i; k < end; k++) offsets[k] = start + step * (k - i + 1);
1117
+ }
1118
+ return offsets;
1119
+ }
1120
+ /**
1121
+ * A browser mixes the colors of a gradient with their alpha (premultiplied), SVG does not. A stop
1122
+ * with no alpha takes the color of its neighbors, so that the gradient fades without gray.
1123
+ */
1124
+ function premultiplyStops(stops) {
1125
+ const visible = (from, step) => {
1126
+ for (let i = from; i >= 0 && i < stops.length; i += step) if (stops[i].color.a > 0) return stops[i].color;
1127
+ };
1128
+ return stops.flatMap((stop, index) => {
1129
+ if (stop.color.a > 0) return [stop];
1130
+ const before = visible(index - 1, -1);
1131
+ const after = visible(index + 1, 1);
1132
+ return [before, after].filter((color, i, all) => color && (i === 0 || color !== all[0])).map((color) => ({
1133
+ offset: stop.offset,
1134
+ color: {
1135
+ ...color,
1136
+ a: 0
1182
1137
  }
1138
+ })).concat(before || after ? [] : [stop]);
1139
+ });
1140
+ }
1141
+ function svgStops(stops) {
1142
+ return premultiplyStops(stops).map(({ offset, color }) => `<stop ${attrs({
1143
+ offset: Math.min(1, Math.max(0, offset)),
1144
+ "stop-color": hex$2(color),
1145
+ "stop-opacity": color.a === 1 ? void 0 : round(color.a)
1146
+ })}/>`).join("");
1147
+ }
1148
+ function resolveLength(length, size) {
1149
+ return length.unit === "%" ? length.value / 100 * size : length.value;
1150
+ }
1151
+ /**
1152
+ * Stretches the stops to the range from 0 to 1. Gives the start and the end of the range on the
1153
+ * old scale, so that the caller can move the end points of the gradient.
1154
+ */
1155
+ function normalize(offsets, allowNegative) {
1156
+ const start = allowNegative ? Math.min(0, offsets[0]) : 0;
1157
+ const end = Math.max(1, offsets.at(-1));
1158
+ return {
1159
+ start,
1160
+ end,
1161
+ offsets: offsets.map((offset) => (Math.max(offset, start) - start) / (end - start))
1162
+ };
1163
+ }
1164
+ function linearSvg(id, layer, box) {
1165
+ const line = cssGradientLine("angle" in layer.direction ? layer.direction.angle : Math.atan2(layer.direction.to.x * box.height, -layer.direction.to.y * box.width) * 180 / Math.PI, box);
1166
+ const length = Math.hypot(line.x2 - line.x1, line.y2 - line.y1);
1167
+ const { start, end, offsets } = normalize(stopOffsets(layer.stops, length), true);
1168
+ const dx = line.x2 - line.x1;
1169
+ const dy = line.y2 - line.y1;
1170
+ const points = {
1171
+ x1: line.x1 + dx * start,
1172
+ y1: line.y1 + dy * start,
1173
+ x2: line.x1 + dx * end,
1174
+ y2: line.y1 + dy * end
1175
+ };
1176
+ const stops = layer.stops.map((stop, index) => ({
1177
+ offset: offsets[index],
1178
+ color: stop.color
1179
+ }));
1180
+ return `<linearGradient ${attrs({
1181
+ id,
1182
+ gradientUnits: "userSpaceOnUse",
1183
+ ...points
1184
+ })}>${svgStops(stops)}</linearGradient>`;
1185
+ }
1186
+ function radialRadii(layer, box, center) {
1187
+ if (typeof layer.size === "object") return {
1188
+ x: resolveLength(layer.size.x, box.width),
1189
+ y: resolveLength(layer.size.y, box.height)
1190
+ };
1191
+ const sides = {
1192
+ x: [center.x - box.x, box.x + box.width - center.x].map(Math.abs),
1193
+ y: [center.y - box.y, box.y + box.height - center.y].map(Math.abs)
1194
+ };
1195
+ const closest = layer.size.startsWith("closest");
1196
+ const pick = (values) => closest ? Math.min(...values) : Math.max(...values);
1197
+ const side = {
1198
+ x: pick(sides.x),
1199
+ y: pick(sides.y)
1200
+ };
1201
+ if (layer.shape === "circle") {
1202
+ if (layer.size.endsWith("side")) {
1203
+ const radius = pick([...sides.x, ...sides.y]);
1204
+ return {
1205
+ x: radius,
1206
+ y: radius
1207
+ };
1183
1208
  }
1184
- },
1185
- {
1186
- "id": "rose-pine",
1187
- "name": "Rosé Pine",
1188
- "background": {
1189
- "from": "#31748f",
1190
- "to": "#ebbcba"
1191
- },
1192
- "textmate": {
1193
- "dark": "rose-pine",
1194
- "light": "rose-pine-dawn"
1195
- },
1196
- "window": {
1197
- "dark": {
1198
- "background": "#191724",
1199
- "title": "#908caa",
1200
- "lineNumber": "#908caa",
1201
- "divider": "#00000000"
1202
- },
1203
- "light": {
1204
- "background": "#faf4ed",
1205
- "title": "#797593",
1206
- "lineNumber": "#797593",
1207
- "divider": "#00000000"
1208
- }
1209
- },
1210
- "syntax": {
1211
- "dark": {
1212
- "foreground": "#e0def4",
1213
- "keyword": "#31748f",
1214
- "string": "#f6c177",
1215
- "function": "#ebbcba",
1216
- "comment": "#6e6a86",
1217
- "highlight": "#6e6a861a"
1218
- },
1219
- "light": {
1220
- "foreground": "#575279",
1221
- "keyword": "#286983",
1222
- "string": "#ea9d34",
1223
- "function": "#d7827e",
1224
- "comment": "#9893a5",
1225
- "highlight": "#6e6a860d"
1226
- }
1227
- }
1228
- },
1209
+ const radius = Math.hypot(side.x, side.y);
1210
+ return {
1211
+ x: radius,
1212
+ y: radius
1213
+ };
1214
+ }
1215
+ if (layer.size.endsWith("side")) return side;
1216
+ return {
1217
+ x: side.x * Math.SQRT2,
1218
+ y: side.y * Math.SQRT2
1219
+ };
1220
+ }
1221
+ function radialSvg(id, layer, box) {
1222
+ const center = {
1223
+ x: box.x + resolveLength(layer.at.x, box.width),
1224
+ y: box.y + resolveLength(layer.at.y, box.height)
1225
+ };
1226
+ const radii = radialRadii(layer, box, center);
1227
+ const rx = Math.max(radii.x, .01);
1228
+ const ry = Math.max(radii.y, .01);
1229
+ const { end, offsets } = normalize(stopOffsets(layer.stops, rx), false);
1230
+ const stops = layer.stops.map((stop, index) => ({
1231
+ offset: offsets[index],
1232
+ color: stop.color
1233
+ }));
1234
+ const transform = `translate(${round(center.x)} ${round(center.y)}) scale(1 ${round(ry / rx)})`;
1235
+ return `<radialGradient ${attrs({
1236
+ id,
1237
+ gradientUnits: "userSpaceOnUse",
1238
+ cx: 0,
1239
+ cy: 0,
1240
+ r: rx * end,
1241
+ gradientTransform: transform
1242
+ })}>${svgStops(stops)}</radialGradient>`;
1243
+ }
1244
+ /** The background as SVG on a box: the bottom layer first, as SVG paints in order */
1245
+ function backgroundSvg(background, box, newId) {
1246
+ const rect = (fill, opacity) => `<rect ${attrs({
1247
+ x: box.x,
1248
+ y: box.y,
1249
+ width: box.width,
1250
+ height: box.height,
1251
+ fill,
1252
+ "fill-opacity": opacity
1253
+ })}/>`;
1254
+ return background.toReversed().map((layer) => {
1255
+ if (layer.type === "color") return rect(hex$2(layer.color), layer.color.a === 1 ? void 0 : round(layer.color.a));
1256
+ const id = newId(`background-${layer.type}`);
1257
+ return `<defs>${layer.type === "linear" ? linearSvg(id, layer, box) : radialSvg(id, layer, box)}</defs>${rect(`url(#${id})`)}`;
1258
+ }).join("");
1259
+ }
1260
+ // src/color.ts
1261
+ function rgba(color) {
1262
+ const parsed = parseColor(color);
1263
+ if (!parsed) throw new Error(`Unknown color "${color}"`);
1264
+ return parsed;
1265
+ }
1266
+ const toHex = (channel) => Math.round(Math.min(255, Math.max(0, channel))).toString(16).padStart(2, "0");
1267
+ function hex$1({ r, g, b }) {
1268
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
1269
+ }
1270
+ const toLinear = (channel) => {
1271
+ const value = channel / 255;
1272
+ return value <= .04045 ? value / 12.92 : ((value + .055) / 1.055) ** 2.4;
1273
+ };
1274
+ const fromLinear = (value) => 255 * (value <= .0031308 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - .055);
1275
+ function toOklab({ r, g, b }) {
1276
+ const [lr, lg, lb] = [
1277
+ toLinear(r),
1278
+ toLinear(g),
1279
+ toLinear(b)
1280
+ ];
1281
+ const l = Math.cbrt(.4122214708 * lr + .5363325363 * lg + .0514459929 * lb);
1282
+ const m = Math.cbrt(.2119034982 * lr + .6806995451 * lg + .1073969566 * lb);
1283
+ const s = Math.cbrt(.0883024619 * lr + .2817188376 * lg + .6299787005 * lb);
1284
+ return {
1285
+ l: .2104542553 * l + .793617785 * m - .0040720468 * s,
1286
+ a: 1.9779984951 * l - 2.428592205 * m + .4505937099 * s,
1287
+ b: .0259040371 * l + .7827717662 * m - .808675766 * s
1288
+ };
1289
+ }
1290
+ function fromOklab({ l, a, b }) {
1291
+ const l3 = (l + .3963377774 * a + .2158037573 * b) ** 3;
1292
+ const m3 = (l - .1055613458 * a - .0638541728 * b) ** 3;
1293
+ const s3 = (l - .0894841775 * a - 1.291485548 * b) ** 3;
1294
+ return {
1295
+ r: fromLinear(4.0767416621 * l3 - 3.3077115913 * m3 + .2309699292 * s3),
1296
+ g: fromLinear(-1.2684380046 * l3 + 2.6097574011 * m3 - .3413193965 * s3),
1297
+ b: fromLinear(-.0041960863 * l3 - .7034186147 * m3 + 1.707614701 * s3),
1298
+ a: 1
1299
+ };
1300
+ }
1301
+ /** The opaque color of a translucent color over an opaque one, as hex */
1302
+ function composite(color, below) {
1303
+ const top = rgba(color);
1304
+ const base = rgba(below);
1305
+ const mix = (front, back) => front * top.a + back * (1 - top.a);
1306
+ return hex$1({
1307
+ r: mix(top.r, base.r),
1308
+ g: mix(top.g, base.g),
1309
+ b: mix(top.b, base.b),
1310
+ a: 1
1311
+ });
1312
+ }
1313
+ /**
1314
+ * A color with at least the given lightness difference to an opaque background, as an opaque hex
1315
+ * color. The color keeps its hue and goes further in its own direction: lighter when it is lighter
1316
+ * than the background, darker when it is darker. A color with no difference goes lighter on a dark
1317
+ * background and darker on a light one.
1318
+ */
1319
+ function withContrast(color, background, minimum) {
1320
+ const opaque = composite(color, background);
1321
+ const front = toOklab(rgba(opaque));
1322
+ const back = toOklab(rgba(background));
1323
+ const difference = front.l - back.l;
1324
+ if (Math.abs(difference) >= minimum) return opaque;
1325
+ const step = (difference === 0 ? back.l < .5 : difference > 0) ? 1 : -1;
1326
+ for (let extra = 0; extra < .02; extra += .001) {
1327
+ const result = hex$1(fromOklab({
1328
+ ...front,
1329
+ l: back.l + step * (minimum + extra)
1330
+ }));
1331
+ if (Math.abs(toOklab(rgba(result)).l - back.l) >= minimum) return result;
1332
+ }
1333
+ return hex$1(fromOklab({
1334
+ ...front,
1335
+ l: back.l + step * (minimum + .02)
1336
+ }));
1337
+ }
1338
+ // src/themes/index.ts
1339
+ const THEMES = [
1229
1340
  {
1230
- "id": "solarized",
1231
- "name": "Solarized",
1341
+ "id": "ayu",
1342
+ "name": "Ayu",
1232
1343
  "background": {
1233
- "from": "#b58900",
1234
- "to": "#cb4b16"
1344
+ "from": "#ff8f40",
1345
+ "to": "#ffb454"
1235
1346
  },
1236
1347
  "textmate": {
1237
- "dark": "solarized-dark",
1238
- "light": "solarized-light"
1348
+ "dark": "ayu-dark",
1349
+ "light": "ayu-light"
1239
1350
  },
1240
1351
  "window": {
1241
1352
  "dark": {
1242
- "background": "#002b36",
1243
- "title": "#d6dbdb",
1244
- "divider": "#003847"
1353
+ "background": "#10141c",
1354
+ "title": "#5a6378",
1355
+ "lineNumber": "#5a6378a6",
1356
+ "divider": "#1b1f29"
1245
1357
  },
1246
1358
  "light": {
1247
- "background": "#fdf6e3",
1248
- "divider": "#ddd6c1"
1359
+ "background": "#fcfcfc",
1360
+ "title": "#828e9f",
1361
+ "lineNumber": "#828e9f66",
1362
+ "divider": "#6b7d8f1f"
1249
1363
  }
1250
1364
  },
1251
1365
  "syntax": {
1252
1366
  "dark": {
1253
- "foreground": "#839496",
1254
- "keyword": "#859900",
1255
- "string": "#2aa198",
1256
- "function": "#268bd2",
1257
- "comment": "#586e75",
1258
- "highlight": "#073642"
1367
+ "foreground": "#bfbdb6",
1368
+ "keyword": "#ff8f40",
1369
+ "string": "#aad94c",
1370
+ "function": "#ffb454",
1371
+ "comment": "#5a6673",
1372
+ "highlight": "#161a24"
1259
1373
  },
1260
1374
  "light": {
1261
- "foreground": "#657b83",
1262
- "keyword": "#859900",
1263
- "string": "#2aa198",
1264
- "function": "#268bd2",
1265
- "comment": "#93a1a1",
1266
- "highlight": "#eee8d5"
1375
+ "foreground": "#5c6166",
1376
+ "keyword": "#fa8532",
1377
+ "string": "#86b300",
1378
+ "function": "#eba400",
1379
+ "comment": "#adaeb1",
1380
+ "highlight": "#828e9f1a"
1267
1381
  }
1268
1382
  }
1269
1383
  },
1270
1384
  {
1271
- "id": "synthwave-84",
1272
- "name": "SynthWave '84",
1273
- "background": {
1274
- "from": "#fede5d",
1275
- "to": "#36f9f6"
1276
- },
1277
- "textmate": { "dark": "synthwave-84" },
1278
- "window": { "dark": {
1279
- "background": "#262335",
1280
- "lineNumber": "#ffffff73",
1281
- "divider": "#241b2f00"
1282
- } },
1283
- "syntax": { "dark": {
1284
- "foreground": "#ffffff",
1285
- "keyword": "#fede5d",
1286
- "string": "#ff8b39",
1287
- "function": "#36f9f6",
1288
- "comment": "#848bbd",
1289
- "highlight": "#ffffff20"
1290
- } }
1291
- },
1292
- {
1293
- "id": "tokyo-night",
1294
- "name": "Tokyo Night",
1385
+ "id": "catppuccin",
1386
+ "name": "Catppuccin",
1295
1387
  "background": {
1296
- "from": "#7aa2f7",
1297
- "to": "#bb9af7"
1388
+ "from": "#cba6f7",
1389
+ "to": "#f5c2e7"
1298
1390
  },
1299
1391
  "textmate": {
1300
- "dark": "tokyo-night",
1301
- "light": "tokyo-night-light"
1392
+ "dark": "catppuccin-mocha",
1393
+ "light": "catppuccin-latte"
1302
1394
  },
1303
1395
  "window": {
1304
1396
  "dark": {
1305
- "background": "#1a1b26",
1306
- "title": "#787c99",
1307
- "lineNumber": "#363b54",
1308
- "divider": "#101014"
1397
+ "background": "#1e1e2e",
1398
+ "title": "#cdd6f4",
1399
+ "lineNumber": "#7f849c",
1400
+ "divider": "#181825"
1309
1401
  },
1310
1402
  "light": {
1311
- "background": "#e6e7ed",
1312
- "title": "#363c4d",
1313
- "lineNumber": "#9da0ab",
1314
- "divider": "#c1c2c7"
1403
+ "background": "#eff1f5",
1404
+ "title": "#4c4f69",
1405
+ "lineNumber": "#8c8fa1",
1406
+ "divider": "#e6e9ef"
1315
1407
  }
1316
1408
  },
1317
1409
  "syntax": {
1318
1410
  "dark": {
1319
- "foreground": "#a9b1d6",
1320
- "keyword": "#bb9af7",
1321
- "string": "#9ece6a",
1322
- "function": "#7aa2f7",
1323
- "comment": "#51597d",
1324
- "highlight": "#1e202e"
1411
+ "foreground": "#cdd6f4",
1412
+ "keyword": "#cba6f7",
1413
+ "string": "#a6e3a1",
1414
+ "function": "#89b4fa",
1415
+ "comment": "#9399b2",
1416
+ "highlight": "#cdd6f412"
1325
1417
  },
1326
1418
  "light": {
1327
- "foreground": "#343b59",
1328
- "keyword": "#65359d",
1329
- "string": "#385f0d",
1330
- "function": "#2959aa",
1331
- "comment": "#888b94",
1332
- "highlight": "#dcdee3"
1419
+ "foreground": "#4c4f69",
1420
+ "keyword": "#8839ef",
1421
+ "string": "#40a02b",
1422
+ "function": "#1e66f5",
1423
+ "comment": "#7c7f93",
1424
+ "highlight": "#4c4f6912"
1333
1425
  }
1334
1426
  }
1335
1427
  },
1336
1428
  {
1337
- "id": "vitesse",
1338
- "name": "Vitesse",
1429
+ "id": "vscode",
1430
+ "name": "VS Code",
1339
1431
  "background": {
1340
- "from": "#4d9375",
1341
- "to": "#80a665"
1432
+ "from": "#c586c0",
1433
+ "to": "#dcdcaa"
1342
1434
  },
1343
1435
  "textmate": {
1344
- "dark": "vitesse-dark",
1345
- "light": "vitesse-light"
1436
+ "dark": "dark-plus",
1437
+ "light": "light-plus"
1346
1438
  },
1347
1439
  "window": {
1348
- "dark": {
1349
- "background": "#121212",
1350
- "title": "#bfbaaa",
1351
- "lineNumber": "#dedcd550",
1352
- "divider": "#191919"
1353
- },
1354
- "light": {
1355
- "background": "#ffffff",
1356
- "title": "#4e4f47",
1357
- "lineNumber": "#393a3450",
1358
- "divider": "#f0f0f0"
1359
- }
1440
+ "dark": { "background": "#1e1e1e" },
1441
+ "light": { "background": "#ffffff" }
1360
1442
  },
1361
1443
  "syntax": {
1362
1444
  "dark": {
1363
- "foreground": "#dbd7caee",
1364
- "keyword": "#4d9375",
1365
- "string": "#c98a7d",
1366
- "function": "#80a665",
1367
- "comment": "#758575dd",
1368
- "highlight": "#181818"
1445
+ "foreground": "#d4d4d4",
1446
+ "keyword": "#c586c0",
1447
+ "string": "#ce9178",
1448
+ "function": "#dcdcaa",
1449
+ "comment": "#6a9955"
1369
1450
  },
1370
1451
  "light": {
1371
- "foreground": "#393a34",
1372
- "keyword": "#1e754f",
1373
- "string": "#b56959",
1374
- "function": "#59873a",
1375
- "comment": "#a0ada0",
1376
- "highlight": "#f7f7f7"
1452
+ "foreground": "#000000",
1453
+ "keyword": "#af00db",
1454
+ "string": "#a31515",
1455
+ "function": "#795e26",
1456
+ "comment": "#008000"
1377
1457
  }
1378
1458
  }
1379
- }
1380
- ];
1381
- const THEME_IDS = THEMES.map((theme) => theme.id);
1382
- const DEFAULT_THEME = "github";
1383
- const EDITOR_FRAME = {
1384
- light: {
1385
- highlightBorder: "rgba(0, 0, 0, 0.08)",
1386
- shadowBorder: "rgba(0, 0, 0, 0.1)"
1387
- },
1388
- dark: { highlightBorder: "rgba(255, 255, 255, 0.1)" }
1389
- };
1390
- const FRAME_COLORS = {
1391
- light: {
1392
- background: "rgba(255, 255, 255, 0.75)",
1393
- control: "rgba(0, 0, 0, 0.2)",
1394
- title: "rgba(0, 0, 0, 0.6)",
1395
- shadowBorder: "rgba(0, 0, 0, 0.1)",
1396
- highlightBorder: "rgba(255, 255, 255, 0.75)",
1397
- divider: "rgba(0, 0, 0, 0.08)",
1398
- highlight: "rgba(0, 0, 0, 0.1)",
1399
- highlightBorderLine: "transparent",
1400
- lineNumber: "rgba(0, 0, 0, 0.2)"
1401
- },
1402
- dark: {
1403
- background: "rgba(0, 0, 0, 0.75)",
1404
- control: "rgba(255, 255, 255, 0.2)",
1405
- title: "rgba(255, 255, 255, 0.6)",
1406
- shadowBorder: "rgba(0, 0, 0, 0.8)",
1407
- highlightBorder: "rgba(255, 255, 255, 0.3)",
1408
- divider: "rgba(255, 255, 255, 0.1)",
1409
- highlight: "rgba(255, 255, 255, 0.1)",
1410
- highlightBorderLine: "transparent",
1411
- lineNumber: "rgba(255, 255, 255, 0.2)"
1412
- }
1413
- };
1414
- function getTheme(id) {
1415
- const theme = THEMES.find((theme) => theme.id === id);
1416
- if (!theme) throw new Error(`Unknown theme "${id}". Available themes: ${THEME_IDS.join(", ")}`);
1417
- return theme;
1418
- }
1419
- /** A theme with only one mode always uses that mode */
1420
- function resolveMode(theme, mode) {
1421
- if (!theme.syntax.light) return "dark";
1422
- if (!theme.syntax.dark) return "light";
1423
- return mode;
1424
- }
1425
- function getSyntax(theme, mode) {
1426
- return theme.syntax[resolveMode(theme, mode)] ?? theme.syntax.light ?? theme.syntax.dark;
1427
- }
1428
- function getFrameColors(theme, mode) {
1429
- const resolved = resolveMode(theme, mode);
1430
- const syntax = getSyntax(theme, resolved);
1431
- const frame = {
1432
- backdrop: theme.background,
1433
- ...FRAME_COLORS[resolved],
1434
- ...theme.window?.[resolved] && {
1435
- ...EDITOR_FRAME[resolved],
1436
- ...theme.window[resolved]
1437
- }
1438
- };
1439
- return {
1440
- ...frame,
1441
- highlight: syntax.highlight ?? frame.highlight,
1442
- highlightBorderLine: syntax.highlightBorder ?? frame.highlightBorderLine
1443
- };
1444
- }
1445
- // src/ambient.ts
1446
- /**
1447
- * Backgrounds that the renderer makes from the colors of the image:
1448
- * - ambient-blur: a blurred and larger copy of the code behind the window
1449
- * - ambient-code: a mesh of the colors that the code uses most
1450
- * - ambient-theme: a mesh of the keyword, string, function and constant colors of the theme
1451
- */
1452
- const AMBIENT_BACKGROUNDS = [
1453
- "ambient-blur",
1454
- "ambient-code",
1455
- "ambient-theme"
1456
- ];
1457
- const AMBIENT_ENABLED = false;
1458
- function isAmbientBackground(css) {
1459
- return AMBIENT_BACKGROUNDS.includes(css);
1460
- }
1461
- const rgb = (color) => {
1462
- const [r, g, b] = parseColor$1(color);
1463
- return [
1464
- r,
1465
- g,
1466
- b
1467
- ];
1468
- };
1469
- const hex$1 = (color) => `#${color.map((channel) => Math.round(channel).toString(16).padStart(2, "0")).join("")}`;
1470
- const mix = (a, b, amount) => a.map((channel, index) => channel + (b[index] - channel) * amount);
1471
- function saturation([r, g, b]) {
1472
- const max = Math.max(r, g, b) / 255;
1473
- const min = Math.min(r, g, b) / 255;
1474
- if (max === min) return 0;
1475
- const lightness = (max + min) / 2;
1476
- return (max - min) / (1 - Math.abs(2 * lightness - 1));
1477
- }
1478
- const BLACK = [
1479
- 0,
1480
- 0,
1481
- 0
1482
- ];
1483
- const WHITE = [
1484
- 255,
1485
- 255,
1486
- 255
1487
- ];
1488
- const MIN_SATURATION = .3;
1489
- const POSITIONS = [
1490
- "0% 0%",
1491
- "100% 100%",
1492
- "100% 0%",
1493
- "0% 100%"
1494
- ];
1495
- /** The color below the glows: the window color, darker in dark mode and a little darker in light mode */
1496
- function ambientBase(windowColor, mode) {
1497
- return hex$1(mix(rgb(windowColor), BLACK, mode === "dark" ? .35 : .04));
1498
- }
1499
- function glow(color, mode) {
1500
- return hex$1(mode === "dark" ? mix(rgb(color), BLACK, .15) : mix(rgb(color), WHITE, .45));
1501
- }
1502
- function mesh(colors, windowColor, mode) {
1503
- return [...colors.slice(0, POSITIONS.length).map((color, index) => `radial-gradient(at ${POSITIONS[index]}, ${glow(color, mode)} 0px, transparent ${55 - index * 5}%)`), ambientBase(windowColor, mode)].join(", ");
1504
- }
1505
- function vivid(colors) {
1506
- const seen = /* @__PURE__ */ new Set();
1507
- return colors.filter((color) => {
1508
- if (!color || !color.startsWith("#")) return false;
1509
- const key = color.slice(0, 7).toLowerCase();
1510
- if (seen.has(key) || saturation(rgb(color)) < MIN_SATURATION) return false;
1511
- seen.add(key);
1512
- return true;
1513
- });
1514
- }
1515
- function themeColors(syntax) {
1516
- return vivid([
1517
- syntax.keyword,
1518
- syntax.string,
1519
- syntax.function,
1520
- syntax.constant ?? syntax.number,
1521
- syntax.property,
1522
- syntax.parameter
1523
- ]);
1524
- }
1525
- /** A mesh of the main syntax colors of the theme */
1526
- function themeAmbientCss(syntax, windowColor, mode) {
1527
- return mesh(themeColors(syntax), windowColor, mode);
1528
- }
1529
- /**
1530
- * A mesh of the colors that cover the most characters of the code. Code with fewer than two
1531
- * vivid colors takes the rest from the theme.
1532
- */
1533
- function codeAmbientCss(lines, syntax, windowColor, mode) {
1534
- const weights = /* @__PURE__ */ new Map();
1535
- for (const line of lines) for (const token of line) {
1536
- const characters = token.content.replace(/\s/g, "").length;
1537
- if (characters === 0) continue;
1538
- const key = token.color.slice(0, 7).toLowerCase();
1539
- weights.set(key, (weights.get(key) ?? 0) + characters);
1540
- }
1541
- const ranked = vivid([...weights].sort((a, b) => b[1] - a[1]).map(([color]) => color));
1542
- return mesh((ranked.length >= 2 ? ranked : vivid([...ranked, ...themeColors(syntax)])).slice(0, 3), windowColor, mode);
1543
- }
1544
- /** The theme mesh of a theme in a mode, as a preview of the ambient backgrounds before the code is known */
1545
- function ambientPreviewCss(theme, mode) {
1546
- const resolved = resolveMode(theme, mode);
1547
- return themeAmbientCss(getSyntax(theme, resolved), getFrameColors(theme, resolved).background, resolved);
1548
- }
1549
- // src/backgrounds.ts
1550
- const BACKGROUNDS = [
1551
- {
1552
- id: "black",
1553
- name: "Black",
1554
- kind: "color",
1555
- css: "#000000"
1556
1459
  },
1557
1460
  {
1558
- id: "obsidian",
1559
- name: "Obsidian",
1560
- kind: "gradient",
1561
- css: "linear-gradient(160deg, #0a0a0a 0%, #262626 55%, #404040 100%)"
1461
+ "id": "dracula",
1462
+ "name": "Dracula",
1463
+ "background": {
1464
+ "from": "#bd93f9",
1465
+ "to": "#ff79c6"
1466
+ },
1467
+ "textmate": {
1468
+ "dark": "dracula",
1469
+ "light": "dracula-alucard"
1470
+ },
1471
+ "window": {
1472
+ "dark": {
1473
+ "background": "#282a36",
1474
+ "title": "#f8f8f2",
1475
+ "lineNumber": "#6272a4",
1476
+ "divider": "#191a21"
1477
+ },
1478
+ "light": {
1479
+ "background": "#fffbeb",
1480
+ "title": "#1f1f1f",
1481
+ "lineNumber": "#6c664b",
1482
+ "divider": "#ceccc0"
1483
+ }
1484
+ },
1485
+ "syntax": {
1486
+ "dark": {
1487
+ "foreground": "#f8f8f2",
1488
+ "keyword": "#ff79c6",
1489
+ "string": "#f1fa8c",
1490
+ "function": "#50fa7b",
1491
+ "comment": "#6272a4",
1492
+ "highlight": "#44475a"
1493
+ },
1494
+ "light": {
1495
+ "foreground": "#1f1f1f",
1496
+ "keyword": "#a3144d",
1497
+ "string": "#846e15",
1498
+ "function": "#14710a",
1499
+ "comment": "#6c664b",
1500
+ "highlight": "#e2deca95"
1501
+ }
1502
+ }
1562
1503
  },
1563
1504
  {
1564
- id: "mist",
1565
- name: "Mist",
1566
- kind: "gradient",
1567
- css: "linear-gradient(135deg, #e2e8f0 0%, #f1f5f9 50%, #ffffff 100%)"
1505
+ "id": "github",
1506
+ "name": "GitHub",
1507
+ "background": {
1508
+ "from": "#ff7b72",
1509
+ "to": "#d2a8ff"
1510
+ },
1511
+ "textmate": {
1512
+ "dark": "github-dark-default",
1513
+ "light": "github-light-default"
1514
+ },
1515
+ "window": {
1516
+ "dark": {
1517
+ "background": "#0d1117",
1518
+ "title": "#7d8590",
1519
+ "lineNumber": "#6e7681",
1520
+ "divider": "#30363d"
1521
+ },
1522
+ "light": {
1523
+ "background": "#ffffff",
1524
+ "title": "#656d76",
1525
+ "lineNumber": "#8c959f",
1526
+ "divider": "#d0d7de"
1527
+ }
1528
+ },
1529
+ "syntax": {
1530
+ "dark": {
1531
+ "foreground": "#e6edf3",
1532
+ "keyword": "#ff7b72",
1533
+ "string": "#a5d6ff",
1534
+ "function": "#d2a8ff",
1535
+ "comment": "#8b949e",
1536
+ "highlight": "#6e76811a"
1537
+ },
1538
+ "light": {
1539
+ "foreground": "#1f2328",
1540
+ "keyword": "#cf222e",
1541
+ "string": "#0a3069",
1542
+ "function": "#8250df",
1543
+ "comment": "#6e7781",
1544
+ "highlight": "#eaeef280"
1545
+ }
1546
+ }
1568
1547
  },
1569
1548
  {
1570
- id: "white",
1571
- name: "White",
1572
- kind: "color",
1573
- css: "#ffffff"
1574
- },
1575
- {
1576
- id: "dusk",
1577
- name: "Dusk",
1578
- kind: "gradient",
1579
- css: "linear-gradient(to right top, #0d1117, #6e40c9, #f78166)"
1549
+ "id": "material",
1550
+ "name": "Material",
1551
+ "background": {
1552
+ "from": "#89ddff",
1553
+ "to": "#82aaff"
1554
+ },
1555
+ "textmate": {
1556
+ "dark": "material-theme",
1557
+ "light": "material-theme-lighter"
1558
+ },
1559
+ "window": {
1560
+ "dark": {
1561
+ "background": "#263238",
1562
+ "title": "#eeffff",
1563
+ "lineNumber": "#465a64",
1564
+ "divider": "#263238"
1565
+ },
1566
+ "light": {
1567
+ "background": "#fafafa",
1568
+ "title": "#90a4ae",
1569
+ "lineNumber": "#cfd8dc",
1570
+ "divider": "#fafafa"
1571
+ }
1572
+ },
1573
+ "syntax": {
1574
+ "dark": {
1575
+ "foreground": "#eeffff",
1576
+ "keyword": "#89ddff",
1577
+ "string": "#c3e88d",
1578
+ "function": "#82aaff",
1579
+ "comment": "#546e7a",
1580
+ "highlight": "#00000050"
1581
+ },
1582
+ "light": {
1583
+ "foreground": "#90a4ae",
1584
+ "keyword": "#39adb5",
1585
+ "string": "#91b859",
1586
+ "function": "#6182b8",
1587
+ "comment": "#90a4ae",
1588
+ "highlight": "#ccd7da50"
1589
+ }
1590
+ }
1580
1591
  },
1581
1592
  {
1582
- id: "garnet",
1583
- name: "Garnet",
1584
- kind: "gradient",
1585
- css: "linear-gradient(160deg, #450a0a 0%, #b91c1c 55%, #f87171 100%)"
1593
+ "id": "night-owl",
1594
+ "name": "Night Owl",
1595
+ "background": {
1596
+ "from": "#c792ea",
1597
+ "to": "#82aaff"
1598
+ },
1599
+ "textmate": {
1600
+ "dark": "night-owl",
1601
+ "light": "night-owl-light"
1602
+ },
1603
+ "window": {
1604
+ "dark": {
1605
+ "background": "#011627",
1606
+ "title": "#eeefff",
1607
+ "lineNumber": "#4b6479",
1608
+ "divider": "#262a39"
1609
+ },
1610
+ "light": {
1611
+ "background": "#fbfbfb",
1612
+ "title": "#403f53",
1613
+ "lineNumber": "#90a7b2",
1614
+ "divider": "#f0f0f0"
1615
+ }
1616
+ },
1617
+ "syntax": {
1618
+ "dark": {
1619
+ "foreground": "#d6deeb",
1620
+ "keyword": "#c792ea",
1621
+ "string": "#ecc48d",
1622
+ "function": "#82aaff",
1623
+ "comment": "#637777",
1624
+ "highlight": "#28707d29"
1625
+ },
1626
+ "light": {
1627
+ "foreground": "#403f53",
1628
+ "keyword": "#994cc3",
1629
+ "string": "#c96765",
1630
+ "function": "#4876d6",
1631
+ "comment": "#989fb1",
1632
+ "highlight": "#f0f0f0"
1633
+ }
1634
+ }
1586
1635
  },
1587
1636
  {
1588
- id: "mesh-dawn",
1589
- name: "Dawn",
1590
- kind: "mesh",
1591
- css: "radial-gradient(at 0% 0%, #fda4af 0px, transparent 50%), radial-gradient(at 100% 0%, #fde68a 0px, transparent 50%), radial-gradient(at 100% 100%, #c4b5fd 0px, transparent 55%), radial-gradient(at 0% 100%, #a5f3fc 0px, transparent 55%), #fff7ed"
1637
+ "id": "nord",
1638
+ "name": "Nord",
1639
+ "background": {
1640
+ "from": "#5e81ac",
1641
+ "to": "#8fbcbb"
1642
+ },
1643
+ "textmate": { "dark": "nord" },
1644
+ "window": { "dark": {
1645
+ "background": "#2e3440",
1646
+ "title": "#d8dee9",
1647
+ "lineNumber": "#4c566a",
1648
+ "divider": "#3b425200"
1649
+ } },
1650
+ "syntax": { "dark": {
1651
+ "foreground": "#d8dee9",
1652
+ "keyword": "#81a1c1",
1653
+ "string": "#a3be8c",
1654
+ "function": "#88c0d0",
1655
+ "comment": "#616e88",
1656
+ "highlight": "#3b4252"
1657
+ } }
1592
1658
  },
1593
1659
  {
1594
- id: "blush",
1595
- name: "Blush",
1596
- kind: "color",
1597
- css: "#fecdd3"
1660
+ "id": "one-dark",
1661
+ "name": "One Dark",
1662
+ "background": {
1663
+ "from": "#61afef",
1664
+ "to": "#c678dd"
1665
+ },
1666
+ "textmate": {
1667
+ "dark": "one-dark-pro",
1668
+ "light": "one-light"
1669
+ },
1670
+ "window": {
1671
+ "dark": {
1672
+ "background": "#282c34",
1673
+ "title": "#9da5b4",
1674
+ "lineNumber": "#495162",
1675
+ "divider": "#181a1f"
1676
+ },
1677
+ "light": {
1678
+ "background": "#fafafa",
1679
+ "title": "#424243",
1680
+ "lineNumber": "#9d9d9f",
1681
+ "divider": "#dbdbdc"
1682
+ }
1683
+ },
1684
+ "syntax": {
1685
+ "dark": {
1686
+ "foreground": "#abb2bf",
1687
+ "keyword": "#c678dd",
1688
+ "string": "#98c379",
1689
+ "function": "#61afef",
1690
+ "comment": "#7f848e",
1691
+ "highlight": "#2c313c"
1692
+ },
1693
+ "light": {
1694
+ "foreground": "#383a42",
1695
+ "keyword": "#a626a4",
1696
+ "string": "#50a14f",
1697
+ "function": "#4078f2",
1698
+ "comment": "#a0a1a7",
1699
+ "highlight": "#383a420c"
1700
+ }
1701
+ }
1598
1702
  },
1599
1703
  {
1600
- id: "ember",
1601
- name: "Ember",
1602
- kind: "gradient",
1603
- css: "linear-gradient(160deg, #1c1917 0%, #9a3412 55%, #f97316 100%)"
1704
+ "id": "rose-pine",
1705
+ "name": "Rosé Pine",
1706
+ "background": {
1707
+ "from": "#31748f",
1708
+ "to": "#ebbcba"
1709
+ },
1710
+ "textmate": {
1711
+ "dark": "rose-pine",
1712
+ "light": "rose-pine-dawn"
1713
+ },
1714
+ "window": {
1715
+ "dark": {
1716
+ "background": "#191724",
1717
+ "title": "#908caa",
1718
+ "lineNumber": "#908caa",
1719
+ "divider": "#00000000"
1720
+ },
1721
+ "light": {
1722
+ "background": "#faf4ed",
1723
+ "title": "#797593",
1724
+ "lineNumber": "#797593",
1725
+ "divider": "#00000000"
1726
+ }
1727
+ },
1728
+ "syntax": {
1729
+ "dark": {
1730
+ "foreground": "#e0def4",
1731
+ "keyword": "#31748f",
1732
+ "string": "#f6c177",
1733
+ "function": "#ebbcba",
1734
+ "comment": "#6e6a86",
1735
+ "highlight": "#6e6a861a"
1736
+ },
1737
+ "light": {
1738
+ "foreground": "#575279",
1739
+ "keyword": "#286983",
1740
+ "string": "#ea9d34",
1741
+ "function": "#d7827e",
1742
+ "comment": "#9893a5",
1743
+ "highlight": "#6e6a860d"
1744
+ }
1745
+ }
1604
1746
  },
1605
1747
  {
1606
- id: "orange",
1607
- name: "Orange",
1608
- kind: "color",
1609
- css: "#ea580c"
1748
+ "id": "solarized",
1749
+ "name": "Solarized",
1750
+ "background": {
1751
+ "from": "#b58900",
1752
+ "to": "#cb4b16"
1753
+ },
1754
+ "textmate": {
1755
+ "dark": "solarized-dark",
1756
+ "light": "solarized-light"
1757
+ },
1758
+ "window": {
1759
+ "dark": {
1760
+ "background": "#002b36",
1761
+ "title": "#d6dbdb",
1762
+ "divider": "#003847"
1763
+ },
1764
+ "light": {
1765
+ "background": "#fdf6e3",
1766
+ "divider": "#ddd6c1"
1767
+ }
1768
+ },
1769
+ "syntax": {
1770
+ "dark": {
1771
+ "foreground": "#839496",
1772
+ "keyword": "#859900",
1773
+ "string": "#2aa198",
1774
+ "function": "#268bd2",
1775
+ "comment": "#586e75",
1776
+ "highlight": "#073642"
1777
+ },
1778
+ "light": {
1779
+ "foreground": "#657b83",
1780
+ "keyword": "#859900",
1781
+ "string": "#2aa198",
1782
+ "function": "#268bd2",
1783
+ "comment": "#93a1a1",
1784
+ "highlight": "#eee8d5"
1785
+ }
1786
+ }
1610
1787
  },
1611
1788
  {
1612
- id: "synthwave",
1613
- name: "Synthwave",
1614
- kind: "gradient",
1615
- css: "linear-gradient(180deg, #2a0845 0%, #6441a5 45%, #ff6ec7 80%, #ffd36e 100%)"
1616
- },
1617
- {
1618
- id: "coral",
1619
- name: "Coral",
1620
- kind: "gradient",
1621
- css: "linear-gradient(135deg, #f43f5e 0%, #fb7185 50%, #fdba74 100%)"
1622
- },
1623
- {
1624
- id: "mesh-dune",
1625
- name: "Dune",
1626
- kind: "mesh",
1627
- css: "radial-gradient(at 20% 80%, #d6a46b 0px, transparent 55%), radial-gradient(at 80% 20%, #f2d4b0 0px, transparent 50%), #f7ede0"
1628
- },
1629
- {
1630
- id: "linen",
1631
- name: "Linen",
1632
- kind: "gradient",
1633
- css: "linear-gradient(135deg, #d6c7a8 0%, #e7dcc6 50%, #f5f0e6 100%)"
1634
- },
1635
- {
1636
- id: "daybreak",
1637
- name: "Daybreak",
1638
- kind: "mesh",
1639
- css: "radial-gradient(at 0% 0%, #ffd6a5 0px, transparent 55%), radial-gradient(at 100% 100%, #a5d8ff 0px, transparent 55%), #fdfcfb"
1640
- },
1641
- {
1642
- id: "wildfire",
1643
- name: "Wildfire",
1644
- kind: "gradient",
1645
- css: "linear-gradient(to right top, #7c2d12, #ea580c, #fb923c, #fde68a)"
1646
- },
1647
- {
1648
- id: "honey",
1649
- name: "Honey",
1650
- kind: "gradient",
1651
- css: "linear-gradient(135deg, #f59e0b 0%, #fbbf24 50%, #fef3c7 100%)"
1652
- },
1653
- {
1654
- id: "sage",
1655
- name: "Sage",
1656
- kind: "gradient",
1657
- css: "linear-gradient(135deg, #84a98c 0%, #b7c9a8 50%, #e9edc9 100%)"
1658
- },
1659
- {
1660
- id: "mesh-moss",
1661
- name: "Moss",
1662
- kind: "mesh",
1663
- css: "radial-gradient(at 30% 20%, #4d7c0f 0px, transparent 55%), radial-gradient(at 80% 80%, #0f766e 0px, transparent 55%), #0c1a0e"
1664
- },
1665
- {
1666
- id: "evergreen",
1667
- name: "Evergreen",
1668
- kind: "gradient",
1669
- css: "linear-gradient(160deg, #0d1117 0%, #033a16 55%, #2ea043 100%)"
1670
- },
1671
- {
1672
- id: "octo",
1673
- name: "Octo",
1674
- kind: "gradient",
1675
- css: "linear-gradient(135deg, #0d1117 0%, #0d419d 55%, #2ea043 100%)"
1676
- },
1677
- {
1678
- id: "jade",
1679
- name: "Jade",
1680
- kind: "gradient",
1681
- css: "linear-gradient(160deg, #0b1410 0%, #1f4d3a 55%, #4d9375 100%)"
1682
- },
1683
- {
1684
- id: "fresh",
1685
- name: "Fresh",
1686
- kind: "gradient",
1687
- css: "linear-gradient(160deg, #ffffff 0%, #dafbe1 55%, #6fdd8b 100%)"
1688
- },
1689
- {
1690
- id: "pine",
1691
- name: "Pine",
1692
- kind: "color",
1693
- css: "#052e2b"
1694
- },
1695
- {
1696
- id: "deep-sea",
1697
- name: "Deep Sea",
1698
- kind: "gradient",
1699
- css: "linear-gradient(160deg, #020617 0%, #0c4a6e 55%, #0891b2 100%)"
1700
- },
1701
- {
1702
- id: "teal",
1703
- name: "Teal",
1704
- kind: "color",
1705
- css: "#0d9488"
1706
- },
1707
- {
1708
- id: "mesh-lagoon",
1709
- name: "Lagoon Mesh",
1710
- kind: "mesh",
1711
- css: "radial-gradient(at 10% 90%, #14b8a6 0px, transparent 55%), radial-gradient(at 90% 20%, #6366f1 0px, transparent 50%), radial-gradient(at 50% 50%, #0e7490 0px, transparent 60%), #042f2e"
1712
- },
1713
- {
1714
- id: "lagoon",
1715
- name: "Lagoon",
1716
- kind: "gradient",
1717
- css: "linear-gradient(135deg, #134e4a 0%, #0d9488 55%, #5eead4 100%)"
1718
- },
1719
- {
1720
- id: "nordic",
1721
- name: "Nordic",
1722
- kind: "gradient",
1723
- css: "linear-gradient(135deg, #2e3440 0%, #4c566a 45%, #88c0d0 100%)"
1724
- },
1725
- {
1726
- id: "lime-soda",
1727
- name: "Lime Soda",
1728
- kind: "gradient",
1729
- css: "linear-gradient(135deg, #a3e635 0%, #4ade80 50%, #2dd4bf 100%)"
1730
- },
1731
- {
1732
- id: "seafoam",
1733
- name: "Seafoam",
1734
- kind: "color",
1735
- css: "#ccfbf1"
1736
- },
1737
- {
1738
- id: "night",
1739
- name: "Night",
1740
- kind: "color",
1741
- css: "#0f172a"
1742
- },
1743
- {
1744
- id: "night-sky",
1745
- name: "Night Sky",
1746
- kind: "gradient",
1747
- css: "linear-gradient(180deg, #010409 0%, #0d1117 50%, #1f6feb 100%)"
1748
- },
1749
- {
1750
- id: "primer",
1751
- name: "Primer",
1752
- kind: "gradient",
1753
- css: "linear-gradient(160deg, #0d1117 0%, #0c2d6b 55%, #1f6feb 100%)"
1789
+ "id": "synthwave-84",
1790
+ "name": "SynthWave '84",
1791
+ "background": {
1792
+ "from": "#fede5d",
1793
+ "to": "#36f9f6"
1794
+ },
1795
+ "textmate": { "dark": "synthwave-84" },
1796
+ "window": { "dark": {
1797
+ "background": "#262335",
1798
+ "lineNumber": "#ffffff73",
1799
+ "divider": "#241b2f00"
1800
+ } },
1801
+ "syntax": { "dark": {
1802
+ "foreground": "#ffffff",
1803
+ "keyword": "#fede5d",
1804
+ "string": "#ff8b39",
1805
+ "function": "#36f9f6",
1806
+ "comment": "#848bbd",
1807
+ "highlight": "#ffffff20"
1808
+ } }
1754
1809
  },
1755
1810
  {
1756
- id: "slate",
1757
- name: "Slate",
1758
- kind: "gradient",
1759
- css: "linear-gradient(160deg, #0f172a 0%, #334155 60%, #64748b 100%)"
1811
+ "id": "tokyo-night",
1812
+ "name": "Tokyo Night",
1813
+ "background": {
1814
+ "from": "#7aa2f7",
1815
+ "to": "#bb9af7"
1816
+ },
1817
+ "textmate": {
1818
+ "dark": "tokyo-night",
1819
+ "light": "tokyo-night-light"
1820
+ },
1821
+ "window": {
1822
+ "dark": {
1823
+ "background": "#1a1b26",
1824
+ "title": "#787c99",
1825
+ "lineNumber": "#363b54",
1826
+ "divider": "#101014"
1827
+ },
1828
+ "light": {
1829
+ "background": "#e6e7ed",
1830
+ "title": "#363c4d",
1831
+ "lineNumber": "#9da0ab",
1832
+ "divider": "#c1c2c7"
1833
+ }
1834
+ },
1835
+ "syntax": {
1836
+ "dark": {
1837
+ "foreground": "#a9b1d6",
1838
+ "keyword": "#bb9af7",
1839
+ "string": "#9ece6a",
1840
+ "function": "#7aa2f7",
1841
+ "comment": "#51597d",
1842
+ "highlight": "#1e202e"
1843
+ },
1844
+ "light": {
1845
+ "foreground": "#343b59",
1846
+ "keyword": "#65359d",
1847
+ "string": "#385f0d",
1848
+ "function": "#2959aa",
1849
+ "comment": "#888b94",
1850
+ "highlight": "#dcdee3"
1851
+ }
1852
+ }
1760
1853
  },
1761
1854
  {
1762
- id: "mesh-glacier",
1763
- name: "Glacier",
1764
- kind: "mesh",
1765
- css: "radial-gradient(at 0% 0%, #1d4ed8 0px, transparent 50%), radial-gradient(at 100% 100%, #22d3ee 0px, transparent 50%), #0b1a3a"
1855
+ "id": "vitesse",
1856
+ "name": "Vitesse",
1857
+ "background": {
1858
+ "from": "#4d9375",
1859
+ "to": "#80a665"
1860
+ },
1861
+ "textmate": {
1862
+ "dark": "vitesse-dark",
1863
+ "light": "vitesse-light"
1864
+ },
1865
+ "window": {
1866
+ "dark": {
1867
+ "background": "#121212",
1868
+ "title": "#bfbaaa",
1869
+ "lineNumber": "#dedcd550",
1870
+ "divider": "#191919"
1871
+ },
1872
+ "light": {
1873
+ "background": "#ffffff",
1874
+ "title": "#4e4f47",
1875
+ "lineNumber": "#393a3450",
1876
+ "divider": "#f0f0f0"
1877
+ }
1878
+ },
1879
+ "syntax": {
1880
+ "dark": {
1881
+ "foreground": "#dbd7caee",
1882
+ "keyword": "#4d9375",
1883
+ "string": "#c98a7d",
1884
+ "function": "#80a665",
1885
+ "comment": "#758575dd",
1886
+ "highlight": "#181818"
1887
+ },
1888
+ "light": {
1889
+ "foreground": "#393a34",
1890
+ "keyword": "#1e754f",
1891
+ "string": "#b56959",
1892
+ "function": "#59873a",
1893
+ "comment": "#a0ada0",
1894
+ "highlight": "#f7f7f7"
1895
+ }
1896
+ }
1897
+ }
1898
+ ];
1899
+ const THEME_IDS = THEMES.map((theme) => theme.id);
1900
+ const DEFAULT_THEME = "github";
1901
+ const EDITOR_FRAME = {
1902
+ light: {
1903
+ highlightBorder: "rgba(0, 0, 0, 0.08)",
1904
+ shadowBorder: "rgba(0, 0, 0, 0.1)"
1766
1905
  },
1767
- {
1768
- id: "azure",
1769
- name: "Azure",
1770
- kind: "gradient",
1771
- css: "linear-gradient(to right top, #0369a1, #0ea5e9, #7dd3fc)"
1906
+ dark: { highlightBorder: "rgba(255, 255, 255, 0.1)" }
1907
+ };
1908
+ const FRAME_COLORS = {
1909
+ light: {
1910
+ background: "rgba(255, 255, 255, 0.75)",
1911
+ control: "rgba(0, 0, 0, 0.2)",
1912
+ title: "rgba(0, 0, 0, 0.6)",
1913
+ shadowBorder: "rgba(0, 0, 0, 0.1)",
1914
+ highlightBorder: "rgba(255, 255, 255, 0.75)",
1915
+ divider: "rgba(0, 0, 0, 0.08)",
1916
+ highlight: "rgba(0, 0, 0, 0.1)",
1917
+ highlightBorderLine: "transparent",
1918
+ lineNumber: "rgba(0, 0, 0, 0.2)"
1772
1919
  },
1773
- {
1774
- id: "blue",
1775
- name: "Blue",
1920
+ dark: {
1921
+ background: "rgba(0, 0, 0, 0.75)",
1922
+ control: "rgba(255, 255, 255, 0.2)",
1923
+ title: "rgba(255, 255, 255, 0.6)",
1924
+ shadowBorder: "rgba(0, 0, 0, 0.8)",
1925
+ highlightBorder: "rgba(255, 255, 255, 0.3)",
1926
+ divider: "rgba(255, 255, 255, 0.1)",
1927
+ highlight: "rgba(255, 255, 255, 0.1)",
1928
+ highlightBorderLine: "transparent",
1929
+ lineNumber: "rgba(255, 255, 255, 0.2)"
1930
+ }
1931
+ };
1932
+ function getTheme(id) {
1933
+ const theme = THEMES.find((theme) => theme.id === id);
1934
+ if (!theme) throw new Error(`Unknown theme "${id}". Available themes: ${THEME_IDS.join(", ")}`);
1935
+ return theme;
1936
+ }
1937
+ /** A theme with only one mode always uses that mode */
1938
+ function resolveMode(theme, mode) {
1939
+ if (!theme.syntax.light) return "dark";
1940
+ if (!theme.syntax.dark) return "light";
1941
+ return mode;
1942
+ }
1943
+ function getSyntax(theme, mode) {
1944
+ return theme.syntax[resolveMode(theme, mode)] ?? theme.syntax.light ?? theme.syntax.dark;
1945
+ }
1946
+ /**
1947
+ * The least OKLab lightness difference between a highlighted line and the window. The themes made
1948
+ * their line highlight for the cursor line of an editor, so many are too faint for a code image.
1949
+ */
1950
+ const HIGHLIGHT_CONTRAST = .06;
1951
+ function getFrameColors(theme, mode) {
1952
+ const resolved = resolveMode(theme, mode);
1953
+ const syntax = getSyntax(theme, resolved);
1954
+ const frame = {
1955
+ backdrop: theme.background,
1956
+ ...FRAME_COLORS[resolved],
1957
+ ...theme.window?.[resolved] && {
1958
+ ...EDITOR_FRAME[resolved],
1959
+ ...theme.window[resolved]
1960
+ }
1961
+ };
1962
+ return {
1963
+ ...frame,
1964
+ highlight: withContrast(syntax.highlight ?? frame.highlight, frame.background, HIGHLIGHT_CONTRAST),
1965
+ highlightBorderLine: syntax.highlightBorder ?? frame.highlightBorderLine
1966
+ };
1967
+ }
1968
+ // src/ambient.ts
1969
+ /**
1970
+ * Backgrounds that the renderer makes from the colors of the image:
1971
+ * - ambient-blur: a blurred and larger copy of the code behind the window
1972
+ * - ambient-code: a mesh of the colors that the code uses most
1973
+ * - ambient-theme: a mesh of the keyword, string, function and constant colors of the theme
1974
+ */
1975
+ const AMBIENT_BACKGROUNDS = [
1976
+ "ambient-blur",
1977
+ "ambient-code",
1978
+ "ambient-theme"
1979
+ ];
1980
+ const AMBIENT_ENABLED = false;
1981
+ function isAmbientBackground(css) {
1982
+ return AMBIENT_BACKGROUNDS.includes(css);
1983
+ }
1984
+ const rgb = (color) => {
1985
+ const [r, g, b] = parseColor$1(color);
1986
+ return [
1987
+ r,
1988
+ g,
1989
+ b
1990
+ ];
1991
+ };
1992
+ const hex = (color) => `#${color.map((channel) => Math.round(channel).toString(16).padStart(2, "0")).join("")}`;
1993
+ const mix = (a, b, amount) => a.map((channel, index) => channel + (b[index] - channel) * amount);
1994
+ function saturation([r, g, b]) {
1995
+ const max = Math.max(r, g, b) / 255;
1996
+ const min = Math.min(r, g, b) / 255;
1997
+ if (max === min) return 0;
1998
+ const lightness = (max + min) / 2;
1999
+ return (max - min) / (1 - Math.abs(2 * lightness - 1));
2000
+ }
2001
+ const BLACK = [
2002
+ 0,
2003
+ 0,
2004
+ 0
2005
+ ];
2006
+ const WHITE = [
2007
+ 255,
2008
+ 255,
2009
+ 255
2010
+ ];
2011
+ const MIN_SATURATION = .3;
2012
+ const POSITIONS = [
2013
+ "0% 0%",
2014
+ "100% 100%",
2015
+ "100% 0%",
2016
+ "0% 100%"
2017
+ ];
2018
+ /** The color below the glows: the window color, darker in dark mode and a little darker in light mode */
2019
+ function ambientBase(windowColor, mode) {
2020
+ return hex(mix(rgb(windowColor), BLACK, mode === "dark" ? .35 : .04));
2021
+ }
2022
+ function glow(color, mode) {
2023
+ return hex(mode === "dark" ? mix(rgb(color), BLACK, .15) : mix(rgb(color), WHITE, .45));
2024
+ }
2025
+ function mesh(colors, windowColor, mode) {
2026
+ return [...colors.slice(0, POSITIONS.length).map((color, index) => `radial-gradient(at ${POSITIONS[index]}, ${glow(color, mode)} 0px, transparent ${55 - index * 5}%)`), ambientBase(windowColor, mode)].join(", ");
2027
+ }
2028
+ function vivid(colors) {
2029
+ const seen = /* @__PURE__ */ new Set();
2030
+ return colors.filter((color) => {
2031
+ if (!color || !color.startsWith("#")) return false;
2032
+ const key = color.slice(0, 7).toLowerCase();
2033
+ if (seen.has(key) || saturation(rgb(color)) < MIN_SATURATION) return false;
2034
+ seen.add(key);
2035
+ return true;
2036
+ });
2037
+ }
2038
+ function themeColors(syntax) {
2039
+ return vivid([
2040
+ syntax.keyword,
2041
+ syntax.string,
2042
+ syntax.function,
2043
+ syntax.constant ?? syntax.number,
2044
+ syntax.property,
2045
+ syntax.parameter
2046
+ ]);
2047
+ }
2048
+ /** A mesh of the main syntax colors of the theme */
2049
+ function themeAmbientCss(syntax, windowColor, mode) {
2050
+ return mesh(themeColors(syntax), windowColor, mode);
2051
+ }
2052
+ /**
2053
+ * A mesh of the colors that cover the most characters of the code. Code with fewer than two
2054
+ * vivid colors takes the rest from the theme.
2055
+ */
2056
+ function codeAmbientCss(lines, syntax, windowColor, mode) {
2057
+ const weights = /* @__PURE__ */ new Map();
2058
+ for (const line of lines) for (const token of line) {
2059
+ const characters = token.content.replace(/\s/g, "").length;
2060
+ if (characters === 0) continue;
2061
+ const key = token.color.slice(0, 7).toLowerCase();
2062
+ weights.set(key, (weights.get(key) ?? 0) + characters);
2063
+ }
2064
+ const ranked = vivid([...weights].sort((a, b) => b[1] - a[1]).map(([color]) => color));
2065
+ return mesh((ranked.length >= 2 ? ranked : vivid([...ranked, ...themeColors(syntax)])).slice(0, 3), windowColor, mode);
2066
+ }
2067
+ /** The theme mesh of a theme in a mode, as a preview of the ambient backgrounds before the code is known */
2068
+ function ambientPreviewCss(theme, mode) {
2069
+ const resolved = resolveMode(theme, mode);
2070
+ return themeAmbientCss(getSyntax(theme, resolved), getFrameColors(theme, resolved).background, resolved);
2071
+ }
2072
+ // src/backgrounds.ts
2073
+ const BACKGROUNDS = [
2074
+ {
2075
+ id: "black",
2076
+ name: "Black",
1776
2077
  kind: "color",
1777
- css: "#2563eb"
2078
+ css: "#000000"
1778
2079
  },
1779
2080
  {
1780
- id: "primer-light",
1781
- name: "Primer Light",
2081
+ id: "obsidian",
2082
+ name: "Obsidian",
1782
2083
  kind: "gradient",
1783
- css: "linear-gradient(160deg, #ffffff 0%, #ddf4ff 55%, #54aeff 100%)"
2084
+ css: "linear-gradient(160deg, #0a0a0a 0%, #262626 55%, #404040 100%)"
1784
2085
  },
1785
2086
  {
1786
- id: "ice",
1787
- name: "Ice",
2087
+ id: "mist",
2088
+ name: "Mist",
1788
2089
  kind: "gradient",
1789
- css: "linear-gradient(135deg, #bae6fd 0%, #e0f2fe 55%, #f8fafc 100%)"
2090
+ css: "linear-gradient(135deg, #e2e8f0 0%, #f1f5f9 50%, #ffffff 100%)"
1790
2091
  },
1791
2092
  {
1792
- id: "sky",
1793
- name: "Sky",
1794
- kind: "mesh",
1795
- css: "radial-gradient(at 0% 0%, #ddf4ff 0px, transparent 55%), radial-gradient(at 100% 100%, #dafbe1 0px, transparent 55%), #ffffff"
2093
+ id: "white",
2094
+ name: "White",
2095
+ kind: "color",
2096
+ css: "#ffffff"
1796
2097
  },
1797
2098
  {
1798
- id: "navy",
1799
- name: "Navy",
1800
- kind: "color",
1801
- css: "#172554"
2099
+ id: "dusk",
2100
+ name: "Dusk",
2101
+ kind: "gradient",
2102
+ css: "linear-gradient(to right top, #0d1117, #6e40c9, #f78166)"
1802
2103
  },
1803
2104
  {
1804
- id: "periwinkle",
1805
- name: "Periwinkle",
2105
+ id: "merlot",
2106
+ name: "Merlot",
1806
2107
  kind: "gradient",
1807
- css: "linear-gradient(135deg, #818cf8 0%, #a5b4fc 50%, #c7d2fe 100%)"
2108
+ css: "linear-gradient(160deg, #1c0a12 0%, #4c0519 55%, #be123c 100%)"
1808
2109
  },
1809
2110
  {
1810
- id: "lilac",
1811
- name: "Lilac",
2111
+ id: "blush",
2112
+ name: "Blush",
1812
2113
  kind: "color",
1813
- css: "#ddd6fe"
2114
+ css: "#fecdd3"
1814
2115
  },
1815
2116
  {
1816
- id: "aubergine",
1817
- name: "Aubergine",
2117
+ id: "red",
2118
+ name: "Red",
1818
2119
  kind: "color",
1819
- css: "#2e1065"
2120
+ css: "#dc2626"
1820
2121
  },
1821
2122
  {
1822
- id: "copilot",
1823
- name: "Copilot",
2123
+ id: "ember",
2124
+ name: "Ember",
1824
2125
  kind: "gradient",
1825
- css: "linear-gradient(135deg, #0d1117 0%, #3c1e70 50%, #8957e5 100%)"
2126
+ css: "linear-gradient(160deg, #1c1917 0%, #9a3412 55%, #f97316 100%)"
1826
2127
  },
1827
2128
  {
1828
- id: "mesh-nebula",
1829
- name: "Nebula",
1830
- kind: "mesh",
1831
- css: "radial-gradient(at 20% 20%, #7c3aed 0px, transparent 50%), radial-gradient(at 80% 10%, #db2777 0px, transparent 50%), radial-gradient(at 70% 90%, #2563eb 0px, transparent 55%), #0b0820"
2129
+ id: "orange",
2130
+ name: "Orange",
2131
+ kind: "color",
2132
+ css: "#ea580c"
1832
2133
  },
1833
2134
  {
1834
- id: "aurora",
1835
- name: "Aurora",
1836
- kind: "gradient",
1837
- css: "linear-gradient(to right top, #064e3b, #059669, #22d3ee, #a78bfa)"
2135
+ id: "amber",
2136
+ name: "Amber",
2137
+ kind: "color",
2138
+ css: "#f59e0b"
1838
2139
  },
1839
2140
  {
1840
- id: "violet",
1841
- name: "Violet",
2141
+ id: "forest",
2142
+ name: "Forest",
1842
2143
  kind: "color",
1843
- css: "#7c3aed"
2144
+ css: "#14532d"
1844
2145
  },
1845
2146
  {
1846
- id: "ocean",
1847
- name: "Ocean",
1848
- kind: "gradient",
1849
- css: "linear-gradient(135deg, #54aeff 0%, #8250df 100%)"
2147
+ id: "green",
2148
+ name: "Green",
2149
+ kind: "color",
2150
+ css: "#16a34a"
1850
2151
  },
1851
2152
  {
1852
- id: "violet-wash",
1853
- name: "Violet Wash",
2153
+ id: "synthwave",
2154
+ name: "Synthwave",
1854
2155
  kind: "gradient",
1855
- css: "linear-gradient(135deg, #8250df 0%, #a371f7 50%, #e9d8fd 100%)"
2156
+ css: "linear-gradient(180deg, #2a0845 0%, #6441a5 45%, #ff6ec7 80%, #ffd36e 100%)"
1856
2157
  },
1857
2158
  {
1858
- id: "sunrise",
1859
- name: "Sunrise",
2159
+ id: "coral",
2160
+ name: "Coral",
1860
2161
  kind: "gradient",
1861
- css: "linear-gradient(to right top, #ffd8b5, #ffd8eb, #e9d8fd)"
2162
+ css: "linear-gradient(135deg, #f43f5e 0%, #fb7185 50%, #fdba74 100%)"
1862
2163
  },
1863
2164
  {
1864
- id: "plum",
1865
- name: "Plum",
1866
- kind: "gradient",
1867
- css: "linear-gradient(135deg, #3b2a4a 0%, #6b3f7a 50%, #c678dd 100%)"
2165
+ id: "mesh-dune",
2166
+ name: "Dune",
2167
+ kind: "mesh",
2168
+ css: "radial-gradient(at 20% 80%, #d6a46b 0px, transparent 55%), radial-gradient(at 80% 20%, #f2d4b0 0px, transparent 50%), #f7ede0"
1868
2169
  },
1869
2170
  {
1870
- id: "mesh-orchid",
1871
- name: "Orchid",
2171
+ id: "daybreak",
2172
+ name: "Daybreak",
1872
2173
  kind: "mesh",
1873
- css: "radial-gradient(at 15% 85%, #c026d3 0px, transparent 50%), radial-gradient(at 85% 15%, #f0abfc 0px, transparent 45%), radial-gradient(at 60% 60%, #6d28d9 0px, transparent 55%), #1a0526"
2174
+ css: "radial-gradient(at 0% 0%, #ffd6a5 0px, transparent 55%), radial-gradient(at 100% 100%, #a5d8ff 0px, transparent 55%), #fdfcfb"
1874
2175
  },
1875
2176
  {
1876
- id: "lavender",
1877
- name: "Lavender",
2177
+ id: "wildfire",
2178
+ name: "Wildfire",
1878
2179
  kind: "gradient",
1879
- css: "linear-gradient(135deg, #a78bfa 0%, #c4b5fd 50%, #f5d0fe 100%)"
2180
+ css: "linear-gradient(to right top, #7c2d12, #ea580c, #fb923c, #fde68a)"
1880
2181
  },
1881
2182
  {
1882
- id: "magenta",
1883
- name: "Magenta",
2183
+ id: "honey",
2184
+ name: "Honey",
1884
2185
  kind: "gradient",
1885
- css: "linear-gradient(to right top, #701a75, #c026d3, #f472b6)"
2186
+ css: "linear-gradient(135deg, #f59e0b 0%, #fbbf24 50%, #fef3c7 100%)"
1886
2187
  },
1887
2188
  {
1888
- id: "pink",
1889
- name: "Pink",
1890
- kind: "color",
1891
- css: "#db2777"
2189
+ id: "lemon",
2190
+ name: "Lemon",
2191
+ kind: "gradient",
2192
+ css: "linear-gradient(135deg, #facc15 0%, #fde68a 50%, #fefce8 100%)"
1892
2193
  },
1893
2194
  {
1894
- id: "violet-pop",
1895
- name: "Violet Pop",
2195
+ id: "sage",
2196
+ name: "Sage",
1896
2197
  kind: "gradient",
1897
- css: "linear-gradient(135deg, #8250df 0%, #bf3989 100%)"
2198
+ css: "linear-gradient(135deg, #84a98c 0%, #b7c9a8 50%, #e9edc9 100%)"
1898
2199
  },
1899
2200
  {
1900
- id: "twilight",
1901
- name: "Twilight",
2201
+ id: "evergreen",
2202
+ name: "Evergreen",
1902
2203
  kind: "gradient",
1903
- css: "linear-gradient(to right top, #1e1b4b, #4338ca, #c084fc, #f9a8d4)"
2204
+ css: "linear-gradient(160deg, #0d1117 0%, #033a16 55%, #2ea043 100%)"
1904
2205
  },
1905
2206
  {
1906
- id: "mesh-sorbet",
1907
- name: "Sorbet Mesh",
2207
+ id: "emerald",
2208
+ name: "Emerald",
2209
+ kind: "gradient",
2210
+ css: "linear-gradient(135deg, #047857 0%, #10b981 50%, #6ee7b7 100%)"
2211
+ },
2212
+ {
2213
+ id: "jade",
2214
+ name: "Jade",
2215
+ kind: "gradient",
2216
+ css: "linear-gradient(160deg, #0b1410 0%, #1f4d3a 55%, #4d9375 100%)"
2217
+ },
2218
+ {
2219
+ id: "pine",
2220
+ name: "Pine",
2221
+ kind: "color",
2222
+ css: "#052e2b"
2223
+ },
2224
+ {
2225
+ id: "deep-sea",
2226
+ name: "Deep Sea",
2227
+ kind: "gradient",
2228
+ css: "linear-gradient(160deg, #020617 0%, #0c4a6e 55%, #0891b2 100%)"
2229
+ },
2230
+ {
2231
+ id: "teal",
2232
+ name: "Teal",
2233
+ kind: "color",
2234
+ css: "#0d9488"
2235
+ },
2236
+ {
2237
+ id: "mesh-lagoon",
2238
+ name: "Lagoon Mesh",
1908
2239
  kind: "mesh",
1909
- css: "radial-gradient(at 0% 50%, #f472b6 0px, transparent 55%), radial-gradient(at 100% 30%, #a78bfa 0px, transparent 50%), radial-gradient(at 60% 100%, #fbbf24 0px, transparent 50%), #fdf2f8"
2240
+ css: "radial-gradient(at 10% 90%, #14b8a6 0px, transparent 55%), radial-gradient(at 90% 20%, #6366f1 0px, transparent 50%), radial-gradient(at 50% 50%, #0e7490 0px, transparent 60%), #042f2e"
1910
2241
  },
1911
2242
  {
1912
- id: "peach",
1913
- name: "Peach",
2243
+ id: "lagoon",
2244
+ name: "Lagoon",
1914
2245
  kind: "gradient",
1915
- css: "linear-gradient(135deg, #fdba74 0%, #fecaca 55%, #fce7f3 100%)"
2246
+ css: "linear-gradient(135deg, #134e4a 0%, #0d9488 55%, #5eead4 100%)"
1916
2247
  },
1917
2248
  {
1918
- id: "rose",
1919
- name: "Rose",
2249
+ id: "nordic",
2250
+ name: "Nordic",
1920
2251
  kind: "gradient",
1921
- css: "linear-gradient(135deg, #fda4af 0%, #fbcfe8 50%, #fdf2f8 100%)"
1922
- }
1923
- ];
1924
- const THEME_BACKGROUNDS = {
1925
- ayu: {
1926
- dark: "ember",
1927
- light: "honey"
2252
+ css: "linear-gradient(135deg, #2e3440 0%, #4c566a 45%, #88c0d0 100%)"
1928
2253
  },
1929
- catppuccin: {
1930
- dark: "twilight",
1931
- light: "lavender"
2254
+ {
2255
+ id: "lime-soda",
2256
+ name: "Lime Soda",
2257
+ kind: "gradient",
2258
+ css: "linear-gradient(135deg, #a3e635 0%, #4ade80 50%, #2dd4bf 100%)"
1932
2259
  },
1933
- dracula: {
1934
- dark: "mesh-orchid",
1935
- light: "rose"
2260
+ {
2261
+ id: "aqua",
2262
+ name: "Aqua",
2263
+ kind: "gradient",
2264
+ css: "linear-gradient(135deg, #22d3ee 0%, #a5f3fc 55%, #ecfeff 100%)"
1936
2265
  },
1937
- github: {
1938
- dark: "dusk",
1939
- light: "sunrise"
2266
+ {
2267
+ id: "primer",
2268
+ name: "Primer",
2269
+ kind: "gradient",
2270
+ css: "linear-gradient(160deg, #0d1117 0%, #0c2d6b 55%, #1f6feb 100%)"
1940
2271
  },
1941
- material: {
1942
- dark: "slate",
1943
- light: "ice"
2272
+ {
2273
+ id: "slate",
2274
+ name: "Slate",
2275
+ kind: "gradient",
2276
+ css: "linear-gradient(160deg, #0f172a 0%, #334155 60%, #64748b 100%)"
1944
2277
  },
1945
- "night-owl": {
1946
- dark: "deep-sea",
1947
- light: "ice"
2278
+ {
2279
+ id: "mesh-glacier",
2280
+ name: "Glacier",
2281
+ kind: "mesh",
2282
+ css: "radial-gradient(at 0% 0%, #1d4ed8 0px, transparent 50%), radial-gradient(at 100% 100%, #22d3ee 0px, transparent 50%), #0b1a3a"
1948
2283
  },
1949
- nord: { dark: "nordic" },
1950
- "one-dark": {
1951
- dark: "plum",
1952
- light: "mist"
2284
+ {
2285
+ id: "azure",
2286
+ name: "Azure",
2287
+ kind: "gradient",
2288
+ css: "linear-gradient(to right top, #0369a1, #0ea5e9, #7dd3fc)"
1953
2289
  },
1954
- "rose-pine": {
1955
- dark: "mesh-orchid",
1956
- light: "peach"
2290
+ {
2291
+ id: "blue",
2292
+ name: "Blue",
2293
+ kind: "color",
2294
+ css: "#2563eb"
1957
2295
  },
1958
- solarized: {
1959
- dark: "deep-sea",
1960
- light: "mesh-dune"
2296
+ {
2297
+ id: "ice",
2298
+ name: "Ice",
2299
+ kind: "gradient",
2300
+ css: "linear-gradient(135deg, #bae6fd 0%, #e0f2fe 55%, #f8fafc 100%)"
1961
2301
  },
1962
- "synthwave-84": { dark: "synthwave" },
1963
- "tokyo-night": {
1964
- dark: "twilight",
1965
- light: "periwinkle"
2302
+ {
2303
+ id: "navy",
2304
+ name: "Navy",
2305
+ kind: "color",
2306
+ css: "#172554"
1966
2307
  },
1967
- vitesse: {
1968
- dark: "jade",
1969
- light: "sage"
2308
+ {
2309
+ id: "periwinkle",
2310
+ name: "Periwinkle",
2311
+ kind: "gradient",
2312
+ css: "linear-gradient(135deg, #818cf8 0%, #a5b4fc 50%, #c7d2fe 100%)"
1970
2313
  },
1971
- vscode: {
1972
- dark: "primer",
1973
- light: "daybreak"
1974
- }
1975
- };
1976
- /** The background preset of a theme in a mode, or undefined when the theme has none */
1977
- function themeBackground(theme, mode) {
1978
- const id = THEME_BACKGROUNDS[theme.id]?.[mode];
1979
- return BACKGROUNDS.find((preset) => preset.id === id);
1980
- }
1981
- // src/gradient.ts
1982
- const HEX = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
1983
- const NUMBER = String.raw`[+-]?(?:\d+\.?\d*|\.\d+)`;
1984
- const LENGTH = new RegExp(`^(${NUMBER})(%|px)?$`, "i");
1985
- const ANGLE = new RegExp(`^(${NUMBER})(deg|turn|rad|grad)$`, "i");
1986
- const SIDES = {
1987
- left: { x: -1 },
1988
- right: { x: 1 },
1989
- top: { y: -1 },
1990
- bottom: { y: 1 }
1991
- };
1992
- const EXTENTS = /* @__PURE__ */ new Set([
1993
- "closest-side",
1994
- "closest-corner",
1995
- "farthest-side",
1996
- "farthest-corner"
1997
- ]);
1998
- const POSITION_KEYWORDS = {
1999
- left: {
2000
- axis: "x",
2001
- value: 0
2314
+ {
2315
+ id: "mesh-nebula",
2316
+ name: "Nebula",
2317
+ kind: "mesh",
2318
+ css: "radial-gradient(at 20% 20%, #7c3aed 0px, transparent 50%), radial-gradient(at 80% 10%, #db2777 0px, transparent 50%), radial-gradient(at 70% 90%, #2563eb 0px, transparent 55%), #0b0820"
2002
2319
  },
2003
- right: {
2004
- axis: "x",
2005
- value: 100
2320
+ {
2321
+ id: "aurora",
2322
+ name: "Aurora",
2323
+ kind: "gradient",
2324
+ css: "linear-gradient(to right top, #064e3b, #059669, #22d3ee, #a78bfa)"
2006
2325
  },
2007
- top: {
2008
- axis: "y",
2009
- value: 0
2326
+ {
2327
+ id: "violet",
2328
+ name: "Violet",
2329
+ kind: "color",
2330
+ css: "#7c3aed"
2010
2331
  },
2011
- bottom: {
2012
- axis: "y",
2013
- value: 100
2332
+ {
2333
+ id: "fuchsia",
2334
+ name: "Fuchsia",
2335
+ kind: "color",
2336
+ css: "#c026d3"
2014
2337
  },
2015
- center: { value: 50 }
2016
- };
2017
- /** Splits at the separator outside of parentheses */
2018
- function split(text, separator) {
2019
- const parts = [];
2020
- let depth = 0;
2021
- let current = "";
2022
- for (const char of text) {
2023
- if (char === "(") depth++;
2024
- if (char === ")") depth--;
2025
- if (depth < 0) throw new Error("unbalanced parentheses");
2026
- if ((separator === " " ? /\s/.test(char) : char === separator) && depth === 0) {
2027
- parts.push(current.trim());
2028
- current = "";
2029
- } else current += char;
2030
- }
2031
- if (depth !== 0) throw new Error("unbalanced parentheses");
2032
- parts.push(current.trim());
2033
- return separator === " " ? parts.filter(Boolean) : parts;
2034
- }
2035
- function parseHex(hex) {
2036
- const digits = hex.slice(1);
2037
- const full = digits.length <= 4 ? digits.replace(/./g, "$&$&") : digits;
2038
- const channel = (index) => parseInt(full.slice(index * 2, index * 2 + 2), 16);
2039
- return {
2040
- r: channel(0),
2041
- g: channel(1),
2042
- b: channel(2),
2043
- a: full.length === 8 ? channel(3) / 255 : 1
2044
- };
2045
- }
2046
- function parseChannel(text, max) {
2047
- const match = LENGTH.exec(text);
2048
- if (!match || match[2]?.toLowerCase() === "px") throw new Error(`invalid color channel ${text}`);
2049
- const value = Number(match[1]);
2050
- const scaled = match[2] === "%" ? value / 100 * max : value;
2051
- return Math.min(max, Math.max(0, scaled));
2052
- }
2053
- function parseColor(text) {
2054
- const color = text.trim().toLowerCase();
2055
- if (color === "transparent") return {
2056
- r: 0,
2057
- g: 0,
2058
- b: 0,
2059
- a: 0
2060
- };
2061
- if (HEX.test(color)) return parseHex(color);
2062
- const fn = /^rgba?\((.*)\)$/.exec(color);
2063
- if (!fn) return void 0;
2064
- const [channels, alpha] = fn[1].includes("/") ? fn[1].split("/") : [fn[1], void 0];
2065
- const parts = channels.includes(",") ? channels.split(",").map((part) => part.trim()) : split(channels, " ");
2066
- if (alpha !== void 0 && parts.length !== 3) return void 0;
2067
- if (parts.length !== 3 && parts.length !== 4) return void 0;
2068
- const [r, g, b] = parts.slice(0, 3).map((part) => parseChannel(part, 255));
2069
- const a = alpha ?? parts[3];
2070
- return {
2071
- r,
2072
- g,
2073
- b,
2074
- a: a === void 0 ? 1 : parseChannel(a.trim(), 1)
2075
- };
2076
- }
2077
- function parseLength(text) {
2078
- const match = LENGTH.exec(text);
2079
- if (!match) throw new Error(`invalid length ${text}`);
2080
- const value = Number(match[1]);
2081
- if (!match[2] && value !== 0) throw new Error(`a length needs % or px: ${text}`);
2082
- return {
2083
- value,
2084
- unit: match[2]?.toLowerCase() ?? "px"
2085
- };
2086
- }
2087
- function parseStops(args) {
2088
- const stops = args.flatMap((arg) => {
2089
- const [colorText, ...positions] = split(arg, " ");
2090
- const color = parseColor(colorText ?? "");
2091
- if (!color || positions.length > 2) throw new Error(`invalid color stop ${arg}`);
2092
- if (positions.length === 0) return [{ color }];
2093
- return positions.map((position) => ({
2094
- color,
2095
- position: parseLength(position)
2096
- }));
2097
- });
2098
- if (stops.length < 2) throw new Error("a gradient needs two colors");
2099
- return stops;
2100
- }
2101
- function parseAngle(text) {
2102
- const match = ANGLE.exec(text);
2103
- if (!match) return void 0;
2104
- const value = Number(match[1]);
2105
- const unit = match[2].toLowerCase();
2106
- if (unit === "turn") return value * 360;
2107
- if (unit === "rad") return value * 180 / Math.PI;
2108
- if (unit === "grad") return value * .9;
2109
- return value;
2110
- }
2111
- function parseLinear(args) {
2112
- const first = args[0];
2113
- const angle = parseAngle(first);
2114
- if (angle !== void 0) return {
2115
- type: "linear",
2116
- direction: { angle },
2117
- stops: parseStops(args.slice(1))
2118
- };
2119
- const words = split(first, " ");
2120
- if (words[0] === "to") {
2121
- const to = {
2122
- x: 0,
2123
- y: 0
2124
- };
2125
- for (const word of words.slice(1)) {
2126
- const side = SIDES[word];
2127
- if (!side || words.length > 3) throw new Error(`invalid direction ${first}`);
2128
- Object.assign(to, side);
2129
- }
2130
- if (words.length < 2) throw new Error(`invalid direction ${first}`);
2131
- return {
2132
- type: "linear",
2133
- direction: { to },
2134
- stops: parseStops(args.slice(1))
2135
- };
2136
- }
2137
- return {
2138
- type: "linear",
2139
- direction: { angle: 180 },
2140
- stops: parseStops(args)
2141
- };
2142
- }
2143
- function parsePosition(words) {
2144
- if (words.length < 1 || words.length > 2) throw new Error("invalid position");
2145
- const at = {};
2146
- const loose = [];
2147
- for (const word of words) {
2148
- const keyword = POSITION_KEYWORDS[word];
2149
- if (keyword?.axis) at[keyword.axis] = {
2150
- value: keyword.value,
2151
- unit: "%"
2152
- };
2153
- else loose.push(keyword ? {
2154
- value: keyword.value,
2155
- unit: "%"
2156
- } : parseLength(word));
2157
- }
2158
- for (const length of loose) if (!at.x) at.x = length;
2159
- else if (!at.y) at.y = length;
2160
- else throw new Error("invalid position");
2161
- const center = {
2162
- value: 50,
2163
- unit: "%"
2164
- };
2165
- return {
2166
- x: at.x ?? center,
2167
- y: at.y ?? center
2168
- };
2169
- }
2170
- function parseRadial(args) {
2171
- const first = split(args[0], " ");
2172
- const isPrelude = first.some((word) => word === "at" || word === "circle" || word === "ellipse" || EXTENTS.has(word)) || parseColor(first[0] ?? "") === void 0 && LENGTH.test(first[0] ?? "");
2173
- const layer = {
2174
- type: "radial",
2175
- shape: "ellipse",
2176
- size: "farthest-corner",
2177
- at: {
2178
- x: {
2179
- value: 50,
2180
- unit: "%"
2181
- },
2182
- y: {
2183
- value: 50,
2184
- unit: "%"
2185
- }
2186
- },
2187
- stops: parseStops(isPrelude ? args.slice(1) : args)
2188
- };
2189
- if (!isPrelude) return layer;
2190
- const atIndex = first.indexOf("at");
2191
- const shapeWords = atIndex === -1 ? first : first.slice(0, atIndex);
2192
- if (atIndex !== -1) layer.at = parsePosition(first.slice(atIndex + 1));
2193
- const sizes = [];
2194
- let shape;
2195
- for (const word of shapeWords) if (word === "circle" || word === "ellipse") shape = word;
2196
- else if (EXTENTS.has(word)) layer.size = word;
2197
- else sizes.push(parseLength(word));
2198
- if (sizes.length === 1) {
2199
- if (shape === "ellipse" || sizes[0].unit === "%") throw new Error("a circle needs one px size");
2200
- layer.size = {
2201
- x: sizes[0],
2202
- y: sizes[0]
2203
- };
2204
- shape = "circle";
2205
- } else if (sizes.length === 2) {
2206
- if (shape === "circle") throw new Error("an ellipse needs two sizes");
2207
- layer.size = {
2208
- x: sizes[0],
2209
- y: sizes[1]
2210
- };
2211
- } else if (sizes.length > 2) throw new Error("invalid size");
2212
- layer.shape = shape ?? "ellipse";
2213
- return layer;
2214
- }
2215
- function parseLayer(text, last) {
2216
- const fn = /^([a-z-]+)\((.*)\)$/is.exec(text);
2217
- const name = fn?.[1]?.toLowerCase();
2218
- if (name === "linear-gradient") return parseLinear(split(fn[2], ","));
2219
- if (name === "radial-gradient") return parseRadial(split(fn[2], ","));
2220
- const color = parseColor(text);
2221
- if (!color) throw new Error(`invalid layer ${text}`);
2222
- if (!last) throw new Error("only the last layer can be a color");
2223
- return {
2224
- type: "color",
2225
- color
2226
- };
2227
- }
2228
- /** Parses a CSS background, or gives undefined when the spec cannot use it */
2229
- function parseBackground(css) {
2230
- try {
2231
- const parts = split(css.trim().replace(/\s+/g, " "), ",");
2232
- if (parts.length > 16 || parts.some((part) => part === "")) return void 0;
2233
- return parts.map((part, index) => parseLayer(part, index === parts.length - 1));
2234
- } catch {
2235
- return;
2236
- }
2237
- }
2238
- function isCssBackground(css) {
2239
- return parseBackground(css) !== void 0;
2240
- }
2241
- function hex({ r, g, b }) {
2242
- return `#${[
2243
- r,
2244
- g,
2245
- b
2246
- ].map((channel) => Math.round(channel).toString(16).padStart(2, "0")).join("")}`;
2247
- }
2248
- /**
2249
- * A color for the places that need one color of the background, such as the color below a
2250
- * translucent window: the color layer, or else the first visible color of the bottom layer.
2251
- */
2252
- function backgroundBaseColor(background) {
2253
- const bottom = background.at(-1);
2254
- if (bottom.type === "color") return hex(bottom.color);
2255
- return hex((bottom.stops.find((stop) => stop.color.a > 0) ?? bottom.stops[0]).color);
2256
- }
2257
- /**
2258
- * The offsets of the stops from 0 to 1 along a gradient ray of a length in px, with the rules of
2259
- * CSS: the first stop is at 0, the last at 1, a stop is never before the one ahead of it, and
2260
- * stops without a position share the space between their neighbors.
2261
- */
2262
- function stopOffsets(stops, length) {
2263
- const offsets = stops.map(({ position }) => position === void 0 ? void 0 : position.unit === "%" ? position.value / 100 : position.value / Math.max(length, .01));
2264
- offsets[0] ??= 0;
2265
- offsets[offsets.length - 1] ??= 1;
2266
- let max = offsets[0];
2267
- for (let i = 0; i < offsets.length; i++) if (offsets[i] !== void 0) {
2268
- max = Math.max(max, offsets[i]);
2269
- offsets[i] = max;
2270
- }
2271
- for (let i = 1; i < offsets.length; i++) {
2272
- if (offsets[i] !== void 0) continue;
2273
- let end = i;
2274
- while (offsets[end] === void 0) end++;
2275
- const start = offsets[i - 1];
2276
- const step = (offsets[end] - start) / (end - i + 1);
2277
- for (let k = i; k < end; k++) offsets[k] = start + step * (k - i + 1);
2338
+ {
2339
+ id: "ocean",
2340
+ name: "Ocean",
2341
+ kind: "gradient",
2342
+ css: "linear-gradient(135deg, #54aeff 0%, #8250df 100%)"
2343
+ },
2344
+ {
2345
+ id: "sunrise",
2346
+ name: "Sunrise",
2347
+ kind: "gradient",
2348
+ css: "linear-gradient(to right top, #ffd8b5, #ffd8eb, #e9d8fd)"
2349
+ },
2350
+ {
2351
+ id: "plum",
2352
+ name: "Plum",
2353
+ kind: "gradient",
2354
+ css: "linear-gradient(135deg, #3b2a4a 0%, #6b3f7a 50%, #c678dd 100%)"
2355
+ },
2356
+ {
2357
+ id: "mesh-orchid",
2358
+ name: "Orchid",
2359
+ kind: "mesh",
2360
+ css: "radial-gradient(at 15% 85%, #c026d3 0px, transparent 50%), radial-gradient(at 85% 15%, #f0abfc 0px, transparent 45%), radial-gradient(at 60% 60%, #6d28d9 0px, transparent 55%), #1a0526"
2361
+ },
2362
+ {
2363
+ id: "lavender",
2364
+ name: "Lavender",
2365
+ kind: "gradient",
2366
+ css: "linear-gradient(135deg, #a78bfa 0%, #c4b5fd 50%, #f5d0fe 100%)"
2367
+ },
2368
+ {
2369
+ id: "pink",
2370
+ name: "Pink",
2371
+ kind: "color",
2372
+ css: "#db2777"
2373
+ },
2374
+ {
2375
+ id: "violet-pop",
2376
+ name: "Violet Pop",
2377
+ kind: "gradient",
2378
+ css: "linear-gradient(135deg, #8250df 0%, #bf3989 100%)"
2379
+ },
2380
+ {
2381
+ id: "twilight",
2382
+ name: "Twilight",
2383
+ kind: "gradient",
2384
+ css: "linear-gradient(to right top, #1e1b4b, #4338ca, #c084fc, #f9a8d4)"
2385
+ },
2386
+ {
2387
+ id: "mesh-sorbet",
2388
+ name: "Sorbet Mesh",
2389
+ kind: "mesh",
2390
+ css: "radial-gradient(at 0% 50%, #f472b6 0px, transparent 55%), radial-gradient(at 100% 30%, #a78bfa 0px, transparent 50%), radial-gradient(at 60% 100%, #fbbf24 0px, transparent 50%), #fdf2f8"
2391
+ },
2392
+ {
2393
+ id: "peach",
2394
+ name: "Peach",
2395
+ kind: "gradient",
2396
+ css: "linear-gradient(135deg, #fdba74 0%, #fecaca 55%, #fce7f3 100%)"
2397
+ },
2398
+ {
2399
+ id: "rose",
2400
+ name: "Rose",
2401
+ kind: "gradient",
2402
+ css: "linear-gradient(135deg, #fda4af 0%, #fbcfe8 50%, #fdf2f8 100%)"
2278
2403
  }
2279
- return offsets;
2280
- }
2281
- /**
2282
- * A browser mixes the colors of a gradient with their alpha (premultiplied), SVG does not. A stop
2283
- * with no alpha takes the color of its neighbors, so that the gradient fades without gray.
2284
- */
2285
- function premultiplyStops(stops) {
2286
- const visible = (from, step) => {
2287
- for (let i = from; i >= 0 && i < stops.length; i += step) if (stops[i].color.a > 0) return stops[i].color;
2288
- };
2289
- return stops.flatMap((stop, index) => {
2290
- if (stop.color.a > 0) return [stop];
2291
- const before = visible(index - 1, -1);
2292
- const after = visible(index + 1, 1);
2293
- return [before, after].filter((color, i, all) => color && (i === 0 || color !== all[0])).map((color) => ({
2294
- offset: stop.offset,
2295
- color: {
2296
- ...color,
2297
- a: 0
2298
- }
2299
- })).concat(before || after ? [] : [stop]);
2300
- });
2301
- }
2302
- function svgStops(stops) {
2303
- return premultiplyStops(stops).map(({ offset, color }) => `<stop ${attrs({
2304
- offset: Math.min(1, Math.max(0, offset)),
2305
- "stop-color": hex(color),
2306
- "stop-opacity": color.a === 1 ? void 0 : round(color.a)
2307
- })}/>`).join("");
2308
- }
2309
- function resolveLength(length, size) {
2310
- return length.unit === "%" ? length.value / 100 * size : length.value;
2311
- }
2312
- /**
2313
- * Stretches the stops to the range from 0 to 1. Gives the start and the end of the range on the
2314
- * old scale, so that the caller can move the end points of the gradient.
2315
- */
2316
- function normalize(offsets, allowNegative) {
2317
- const start = allowNegative ? Math.min(0, offsets[0]) : 0;
2318
- const end = Math.max(1, offsets.at(-1));
2319
- return {
2320
- start,
2321
- end,
2322
- offsets: offsets.map((offset) => (Math.max(offset, start) - start) / (end - start))
2323
- };
2324
- }
2325
- function linearSvg(id, layer, box) {
2326
- const line = cssGradientLine("angle" in layer.direction ? layer.direction.angle : Math.atan2(layer.direction.to.x * box.height, -layer.direction.to.y * box.width) * 180 / Math.PI, box);
2327
- const length = Math.hypot(line.x2 - line.x1, line.y2 - line.y1);
2328
- const { start, end, offsets } = normalize(stopOffsets(layer.stops, length), true);
2329
- const dx = line.x2 - line.x1;
2330
- const dy = line.y2 - line.y1;
2331
- const points = {
2332
- x1: line.x1 + dx * start,
2333
- y1: line.y1 + dy * start,
2334
- x2: line.x1 + dx * end,
2335
- y2: line.y1 + dy * end
2336
- };
2337
- const stops = layer.stops.map((stop, index) => ({
2338
- offset: offsets[index],
2339
- color: stop.color
2340
- }));
2341
- return `<linearGradient ${attrs({
2342
- id,
2343
- gradientUnits: "userSpaceOnUse",
2344
- ...points
2345
- })}>${svgStops(stops)}</linearGradient>`;
2346
- }
2347
- function radialRadii(layer, box, center) {
2348
- if (typeof layer.size === "object") return {
2349
- x: resolveLength(layer.size.x, box.width),
2350
- y: resolveLength(layer.size.y, box.height)
2351
- };
2352
- const sides = {
2353
- x: [center.x - box.x, box.x + box.width - center.x].map(Math.abs),
2354
- y: [center.y - box.y, box.y + box.height - center.y].map(Math.abs)
2355
- };
2356
- const closest = layer.size.startsWith("closest");
2357
- const pick = (values) => closest ? Math.min(...values) : Math.max(...values);
2358
- const side = {
2359
- x: pick(sides.x),
2360
- y: pick(sides.y)
2361
- };
2362
- if (layer.shape === "circle") {
2363
- if (layer.size.endsWith("side")) {
2364
- const radius = pick([...sides.x, ...sides.y]);
2365
- return {
2366
- x: radius,
2367
- y: radius
2368
- };
2369
- }
2370
- const radius = Math.hypot(side.x, side.y);
2371
- return {
2372
- x: radius,
2373
- y: radius
2374
- };
2404
+ ];
2405
+ const THEME_BACKGROUNDS = {
2406
+ ayu: {
2407
+ dark: "ember",
2408
+ light: "honey"
2409
+ },
2410
+ catppuccin: {
2411
+ dark: "twilight",
2412
+ light: "lavender"
2413
+ },
2414
+ dracula: {
2415
+ dark: "mesh-orchid",
2416
+ light: "rose"
2417
+ },
2418
+ github: {
2419
+ dark: "dusk",
2420
+ light: "sunrise"
2421
+ },
2422
+ material: {
2423
+ dark: "slate",
2424
+ light: "ice"
2425
+ },
2426
+ "night-owl": {
2427
+ dark: "deep-sea",
2428
+ light: "ice"
2429
+ },
2430
+ nord: { dark: "nordic" },
2431
+ "one-dark": {
2432
+ dark: "plum",
2433
+ light: "mist"
2434
+ },
2435
+ "rose-pine": {
2436
+ dark: "mesh-orchid",
2437
+ light: "peach"
2438
+ },
2439
+ solarized: {
2440
+ dark: "deep-sea",
2441
+ light: "mesh-dune"
2442
+ },
2443
+ "synthwave-84": { dark: "synthwave" },
2444
+ "tokyo-night": {
2445
+ dark: "twilight",
2446
+ light: "periwinkle"
2447
+ },
2448
+ vitesse: {
2449
+ dark: "jade",
2450
+ light: "sage"
2451
+ },
2452
+ vscode: {
2453
+ dark: "primer",
2454
+ light: "daybreak"
2375
2455
  }
2376
- if (layer.size.endsWith("side")) return side;
2377
- return {
2378
- x: side.x * Math.SQRT2,
2379
- y: side.y * Math.SQRT2
2380
- };
2381
- }
2382
- function radialSvg(id, layer, box) {
2383
- const center = {
2384
- x: box.x + resolveLength(layer.at.x, box.width),
2385
- y: box.y + resolveLength(layer.at.y, box.height)
2386
- };
2387
- const radii = radialRadii(layer, box, center);
2388
- const rx = Math.max(radii.x, .01);
2389
- const ry = Math.max(radii.y, .01);
2390
- const { end, offsets } = normalize(stopOffsets(layer.stops, rx), false);
2391
- const stops = layer.stops.map((stop, index) => ({
2392
- offset: offsets[index],
2393
- color: stop.color
2394
- }));
2395
- const transform = `translate(${round(center.x)} ${round(center.y)}) scale(1 ${round(ry / rx)})`;
2396
- return `<radialGradient ${attrs({
2397
- id,
2398
- gradientUnits: "userSpaceOnUse",
2399
- cx: 0,
2400
- cy: 0,
2401
- r: rx * end,
2402
- gradientTransform: transform
2403
- })}>${svgStops(stops)}</radialGradient>`;
2404
- }
2405
- /** The background as SVG on a box: the bottom layer first, as SVG paints in order */
2406
- function backgroundSvg(background, box, newId) {
2407
- const rect = (fill, opacity) => `<rect ${attrs({
2408
- x: box.x,
2409
- y: box.y,
2410
- width: box.width,
2411
- height: box.height,
2412
- fill,
2413
- "fill-opacity": opacity
2414
- })}/>`;
2415
- return background.toReversed().map((layer) => {
2416
- if (layer.type === "color") return rect(hex(layer.color), layer.color.a === 1 ? void 0 : round(layer.color.a));
2417
- const id = newId(`background-${layer.type}`);
2418
- return `<defs>${layer.type === "linear" ? linearSvg(id, layer, box) : radialSvg(id, layer, box)}</defs>${rect(`url(#${id})`)}`;
2419
- }).join("");
2456
+ };
2457
+ /** The background preset of a theme in a mode, or undefined when the theme has none */
2458
+ function themeBackground(theme, mode) {
2459
+ const id = THEME_BACKGROUNDS[theme.id]?.[mode];
2460
+ return BACKGROUNDS.find((preset) => preset.id === id);
2420
2461
  }
2421
2462
  // src/icons/icons.generated.json
2422
2463
  var icons_generated_default = {
@@ -2900,6 +2941,15 @@ const EDITOR_TEXTMATE_THEMES = {
2900
2941
  // src/highlight/index.ts
2901
2942
  const PLAIN_TEXT = "text";
2902
2943
  const LANGUAGE_IDS = [PLAIN_TEXT, ...bundledLanguagesInfo.map((language) => language.id)];
2944
+ const LANGUAGES = [{
2945
+ id: PLAIN_TEXT,
2946
+ name: "Plain Text",
2947
+ aliases: []
2948
+ }, ...bundledLanguagesInfo.map(({ id, name, aliases }) => ({
2949
+ id,
2950
+ name,
2951
+ aliases: aliases ?? []
2952
+ }))];
2903
2953
  /** The display name of a language, such as "TypeScript" for "typescript" */
2904
2954
  function languageName(language) {
2905
2955
  if (language === "text") return "Plain Text";
@@ -4654,4 +4704,4 @@ function toSvg(scene, options = {}) {
4654
4704
  "</svg>"
4655
4705
  ].join("\n");
4656
4706
  }
4657
- export { resolveIcon as $, SpecSchema as A, createLink as B, isSpecSchemaUrl as C, MARK_STYLES as D, LATEST_SPEC_VERSION as E, highlight as F, IMPLICIT_SPEC_VERSION as G, encodeSpec as H, inferLanguage as I, AUTO_ICON as J, schemaVersion as K, isKnownLanguage as L, parseSpec as M, LANGUAGE_IDS as N, SPEC_LIMITS as O, PLAIN_TEXT as P, getIcon as Q, resolveLanguage as R, SPEC_SCHEMA_URL as S, measureUiText as St, ANNOTATION_TYPES as T, readLink as U, decodeSpec as V, EXTENSION_PREFIX as W, ICON_IDS as X, FILE_ICON as Y, NO_ICON as Z, WINDOW_RADIUS as _, UI_FONT as _t, svgToPng as a, ambientPreviewCss as at, normalizeCode as b, getFace as bt, SOFTWARE as c, THEMES as ct, createImageMetadata as d, getSyntax as dt, isCssBackground as et, readImageSpec as f, getTheme as ft, TAB_HEADER as g, DEFAULT_CODE_FONT as gt, POPOVER as h, CODE_FONT_IDS as ht, sceneFontFiles as i, AMBIENT_ENABLED as it, expandLineRanges as j, SpecError as k, SVG_NAMESPACE as l, THEME_IDS as lt, LINE_HEIGHT as m, CODE_FONTS as mt, initPng as n, themeBackground as nt, METADATA_BY_DEFAULT as o, isAmbientBackground as ot, FONT_SIZE as p, resolveMode as pt, stampSpecVersion as q, loadSceneFonts as r, AMBIENT_BACKGROUNDS as rt, PNG_KEYWORDS as s, DEFAULT_THEME as st, toSvg as t, BACKGROUNDS as tt, addPngMetadata as u, getFrameColors as ut, cellCount as v, cssFontFamily as vt, specJsonSchema as w, MAC_HEADER as x, measureCodeText as xt, layout as y, getCodeFont as yt, DEFAULT_APP_URL as z };
4707
+ export { NO_ICON as $, SpecSchema as A, resolveLanguage as B, isSpecSchemaUrl as C, measureCodeText as Ct, MARK_STYLES as D, LATEST_SPEC_VERSION as E, PLAIN_TEXT as F, readLink as G, createLink as H, highlight as I, schemaVersion as J, EXTENSION_PREFIX as K, inferLanguage as L, parseSpec as M, LANGUAGES as N, SPEC_LIMITS as O, LANGUAGE_IDS as P, ICON_IDS as Q, isKnownLanguage as R, SPEC_SCHEMA_URL as S, getFace as St, ANNOTATION_TYPES as T, decodeSpec as U, DEFAULT_APP_URL as V, encodeSpec as W, AUTO_ICON as X, stampSpecVersion as Y, FILE_ICON as Z, WINDOW_RADIUS as _, CODE_FONT_IDS as _t, svgToPng as a, AMBIENT_ENABLED as at, normalizeCode as b, cssFontFamily as bt, SOFTWARE as c, DEFAULT_THEME as ct, createImageMetadata as d, getFrameColors as dt, getIcon as et, readImageSpec as f, getSyntax as ft, TAB_HEADER as g, CODE_FONTS as gt, POPOVER as h, isCssBackground as ht, sceneFontFiles as i, AMBIENT_BACKGROUNDS as it, expandLineRanges as j, SpecError as k, SVG_NAMESPACE as l, THEMES as lt, LINE_HEIGHT as m, resolveMode as mt, initPng as n, BACKGROUNDS as nt, METADATA_BY_DEFAULT as o, ambientPreviewCss as ot, FONT_SIZE as p, getTheme as pt, IMPLICIT_SPEC_VERSION as q, loadSceneFonts as r, themeBackground as rt, PNG_KEYWORDS as s, isAmbientBackground as st, toSvg as t, resolveIcon as tt, addPngMetadata as u, THEME_IDS as ut, cellCount as v, DEFAULT_CODE_FONT as vt, specJsonSchema as w, measureUiText as wt, MAC_HEADER as x, getCodeFont as xt, layout as y, UI_FONT as yt, languageName as z };