@promptbook/browser 0.112.0-73 → 0.112.0-79
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.
- package/README.md +9 -9
- package/esm/index.es.js +822 -370
- package/esm/index.es.js.map +1 -1
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/esm/src/avatars/visuals/octopus3d2AvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +37 -0
- package/esm/src/book-components/Chat/save/_common/chatExportRendering.d.ts +47 -0
- package/esm/src/book-components/Chat/save/html/htmlSaveFormatDefinition.d.ts +12 -0
- package/esm/src/book-components/Chat/save/index.d.ts +2 -2
- package/esm/src/book-components/Chat/save/markdown/mdSaveFormatDefinition.d.ts +5 -3
- package/esm/src/book-components/Chat/save/pdf/buildChatPdf.d.ts +3 -3
- package/esm/src/book-components/Chat/save/pdf/pdfSaveFormatDefinition.d.ts +1 -1
- package/esm/src/cli/cli-commands/agent/agentProjectPaths.d.ts +8 -8
- package/esm/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -1
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +56 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.d.ts +7 -0
- package/esm/src/cli/cli-commands/agents-server/ensureAgentsServerGitignoreFile.d.ts +7 -0
- package/esm/src/cli/cli-commands/agents-server/init.d.ts +9 -0
- package/esm/src/cli/cli-commands/agents-server/init.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/agents-server/initializeAgentsServerProjectConfiguration.d.ts +17 -0
- package/esm/src/cli/cli-commands/agents-server/printAgentsServerInitializationSummary.d.ts +7 -0
- package/esm/src/cli/cli-commands/agents-server/run.d.ts +14 -0
- package/esm/src/cli/cli-commands/agents-server/run.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +23 -0
- package/esm/src/cli/cli-commands/agents-server.d.ts +8 -0
- package/esm/src/cli/cli-commands/common/projectInitialization.d.ts +65 -0
- package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +44 -0
- package/esm/src/cli/common/$deprecateCliCommand.d.ts +8 -0
- package/esm/src/cli/common/$deprecateCliCommand.test.d.ts +1 -0
- package/esm/src/utils/color/Color.d.ts +4 -44
- package/esm/src/utils/color/ColorValue.d.ts +55 -0
- package/esm/src/utils/color/isHexColorString.d.ts +10 -0
- package/esm/src/utils/color/parseColorString.d.ts +11 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/umd/index.umd.js +822 -370
- package/umd/index.umd.js.map +1 -1
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/umd/src/avatars/visuals/octopus3d2AvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +37 -0
- package/umd/src/book-components/Chat/save/_common/chatExportRendering.d.ts +47 -0
- package/umd/src/book-components/Chat/save/html/htmlSaveFormatDefinition.d.ts +12 -0
- package/umd/src/book-components/Chat/save/index.d.ts +2 -2
- package/umd/src/book-components/Chat/save/markdown/mdSaveFormatDefinition.d.ts +5 -3
- package/umd/src/book-components/Chat/save/pdf/buildChatPdf.d.ts +3 -3
- package/umd/src/book-components/Chat/save/pdf/pdfSaveFormatDefinition.d.ts +1 -1
- package/umd/src/cli/cli-commands/agent/agentProjectPaths.d.ts +8 -8
- package/umd/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -1
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +56 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.d.ts +7 -0
- package/umd/src/cli/cli-commands/agents-server/ensureAgentsServerGitignoreFile.d.ts +7 -0
- package/umd/src/cli/cli-commands/agents-server/init.d.ts +9 -0
- package/umd/src/cli/cli-commands/agents-server/init.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/agents-server/initializeAgentsServerProjectConfiguration.d.ts +17 -0
- package/umd/src/cli/cli-commands/agents-server/printAgentsServerInitializationSummary.d.ts +7 -0
- package/umd/src/cli/cli-commands/agents-server/run.d.ts +14 -0
- package/umd/src/cli/cli-commands/agents-server/run.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +23 -0
- package/umd/src/cli/cli-commands/agents-server.d.ts +8 -0
- package/umd/src/cli/cli-commands/common/projectInitialization.d.ts +65 -0
- package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +44 -0
- package/umd/src/cli/common/$deprecateCliCommand.d.ts +8 -0
- package/umd/src/cli/common/$deprecateCliCommand.test.d.ts +1 -0
- package/umd/src/utils/color/Color.d.ts +4 -44
- package/umd/src/utils/color/ColorValue.d.ts +55 -0
- package/umd/src/utils/color/isHexColorString.d.ts +10 -0
- package/umd/src/utils/color/parseColorString.d.ts +11 -0
- package/umd/src/version.d.ts +1 -1
- package/esm/src/cli/cli-commands/coder/appendBlock.d.ts +0 -6
- package/esm/src/cli/cli-commands/coder/readTextFileIfExists.d.ts +0 -6
- package/umd/src/cli/cli-commands/coder/appendBlock.d.ts +0 -6
- package/umd/src/cli/cli-commands/coder/readTextFileIfExists.d.ts +0 -6
package/umd/index.umd.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* @generated
|
|
28
28
|
* @see https://github.com/webgptorg/promptbook
|
|
29
29
|
*/
|
|
30
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
30
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-79';
|
|
31
31
|
/**
|
|
32
32
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
33
33
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -277,6 +277,111 @@
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Shared immutable channel storage and serialization helpers for `Color`.
|
|
282
|
+
*
|
|
283
|
+
* @private base class of Color
|
|
284
|
+
*/
|
|
285
|
+
class ColorValue {
|
|
286
|
+
constructor(red, green, blue, alpha = 255) {
|
|
287
|
+
this.red = red;
|
|
288
|
+
this.green = green;
|
|
289
|
+
this.blue = blue;
|
|
290
|
+
this.alpha = alpha;
|
|
291
|
+
checkChannelValue('Red', red);
|
|
292
|
+
checkChannelValue('Green', green);
|
|
293
|
+
checkChannelValue('Blue', blue);
|
|
294
|
+
checkChannelValue('Alpha', alpha);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Shortcut for `red` property
|
|
298
|
+
* Number from 0 to 255
|
|
299
|
+
* @alias red
|
|
300
|
+
*/
|
|
301
|
+
get r() {
|
|
302
|
+
return this.red;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Shortcut for `green` property
|
|
306
|
+
* Number from 0 to 255
|
|
307
|
+
* @alias green
|
|
308
|
+
*/
|
|
309
|
+
get g() {
|
|
310
|
+
return this.green;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Shortcut for `blue` property
|
|
314
|
+
* Number from 0 to 255
|
|
315
|
+
* @alias blue
|
|
316
|
+
*/
|
|
317
|
+
get b() {
|
|
318
|
+
return this.blue;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Shortcut for `alpha` property
|
|
322
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
323
|
+
* @alias alpha
|
|
324
|
+
*/
|
|
325
|
+
get a() {
|
|
326
|
+
return this.alpha;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Shortcut for `alpha` property
|
|
330
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
331
|
+
* @alias alpha
|
|
332
|
+
*/
|
|
333
|
+
get opacity() {
|
|
334
|
+
return this.alpha;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Shortcut for 1-`alpha` property
|
|
338
|
+
*/
|
|
339
|
+
get transparency() {
|
|
340
|
+
return 255 - this.alpha;
|
|
341
|
+
}
|
|
342
|
+
clone() {
|
|
343
|
+
return take(this.createColor(this.red, this.green, this.blue, this.alpha));
|
|
344
|
+
}
|
|
345
|
+
toString() {
|
|
346
|
+
return this.toHex();
|
|
347
|
+
}
|
|
348
|
+
toHex() {
|
|
349
|
+
if (this.alpha === 255) {
|
|
350
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
351
|
+
.toString(16)
|
|
352
|
+
.padStart(2, '0')}`;
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
356
|
+
.toString(16)
|
|
357
|
+
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
toRgb() {
|
|
361
|
+
if (this.alpha === 255) {
|
|
362
|
+
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
toHsl() {
|
|
369
|
+
throw new Error(`Getting HSL is not implemented`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Checks if the given value is a valid hex color string
|
|
375
|
+
*
|
|
376
|
+
* @param value - value to check
|
|
377
|
+
* @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
|
|
378
|
+
*
|
|
379
|
+
* @private function of Color
|
|
380
|
+
*/
|
|
381
|
+
function isHexColorString(value) {
|
|
382
|
+
return (typeof value === 'string' && /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value));
|
|
383
|
+
}
|
|
384
|
+
|
|
280
385
|
/**
|
|
281
386
|
* Constant for short hex lengths.
|
|
282
387
|
*/
|
|
@@ -488,16 +593,53 @@
|
|
|
488
593
|
|
|
489
594
|
/**
|
|
490
595
|
* Pattern matching hsl regex.
|
|
596
|
+
*
|
|
597
|
+
* @private function of Color
|
|
491
598
|
*/
|
|
492
599
|
const HSL_REGEX_PATTERN = /^hsl\(\s*([0-9.]+)\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*\)$/;
|
|
493
600
|
/**
|
|
494
601
|
* Pattern matching RGB regex.
|
|
602
|
+
*
|
|
603
|
+
* @private function of Color
|
|
495
604
|
*/
|
|
496
605
|
const RGB_REGEX_PATTERN = /^rgb\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
|
|
497
606
|
/**
|
|
498
607
|
* Pattern matching rgba regex.
|
|
608
|
+
*
|
|
609
|
+
* @private function of Color
|
|
499
610
|
*/
|
|
500
611
|
const RGBA_REGEX_PATTERN = /^rgba\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
|
|
612
|
+
/**
|
|
613
|
+
* Parses a supported color string into RGBA channels.
|
|
614
|
+
*
|
|
615
|
+
* @param color as a string for example `#009edd`, `rgb(0,158,221)`, `rgb(0%,62%,86.7%)`, `hsl(197.1,100%,43.3%)`, `red`, `darkgrey`,...
|
|
616
|
+
* @returns RGBA channel values.
|
|
617
|
+
*
|
|
618
|
+
* @private function of Color
|
|
619
|
+
*/
|
|
620
|
+
function parseColorString(color) {
|
|
621
|
+
const trimmed = color.trim();
|
|
622
|
+
const cssColor = CSS_COLORS[trimmed];
|
|
623
|
+
if (cssColor) {
|
|
624
|
+
return parseColorString(cssColor);
|
|
625
|
+
}
|
|
626
|
+
else if (isHexColorString(trimmed)) {
|
|
627
|
+
return parseHexColor(trimmed);
|
|
628
|
+
}
|
|
629
|
+
if (HSL_REGEX_PATTERN.test(trimmed)) {
|
|
630
|
+
return parseHslColor(trimmed);
|
|
631
|
+
}
|
|
632
|
+
else if (RGB_REGEX_PATTERN.test(trimmed)) {
|
|
633
|
+
return parseRgbColor(trimmed);
|
|
634
|
+
}
|
|
635
|
+
else if (RGBA_REGEX_PATTERN.test(trimmed)) {
|
|
636
|
+
return parseRgbaColor(trimmed);
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
501
643
|
/**
|
|
502
644
|
* Color object represents an RGB color with alpha channel
|
|
503
645
|
*
|
|
@@ -505,7 +647,7 @@
|
|
|
505
647
|
*
|
|
506
648
|
* @public exported from `@promptbook/color`
|
|
507
649
|
*/
|
|
508
|
-
class Color {
|
|
650
|
+
class Color extends ColorValue {
|
|
509
651
|
/**
|
|
510
652
|
* Creates a new Color instance from miscellaneous formats
|
|
511
653
|
* - It can receive Color instance and just return the same instance
|
|
@@ -578,25 +720,7 @@
|
|
|
578
720
|
* @returns Color object
|
|
579
721
|
*/
|
|
580
722
|
static fromString(color) {
|
|
581
|
-
|
|
582
|
-
if (CSS_COLORS[trimmed]) {
|
|
583
|
-
return Color.fromString(CSS_COLORS[trimmed]);
|
|
584
|
-
}
|
|
585
|
-
else if (Color.isHexColorString(trimmed)) {
|
|
586
|
-
return Color.fromHex(trimmed);
|
|
587
|
-
}
|
|
588
|
-
if (HSL_REGEX_PATTERN.test(trimmed)) {
|
|
589
|
-
return Color.fromHsl(trimmed);
|
|
590
|
-
}
|
|
591
|
-
else if (RGB_REGEX_PATTERN.test(trimmed)) {
|
|
592
|
-
return Color.fromRgbString(trimmed);
|
|
593
|
-
}
|
|
594
|
-
else if (RGBA_REGEX_PATTERN.test(trimmed)) {
|
|
595
|
-
return Color.fromRgbaString(trimmed);
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
|
|
599
|
-
}
|
|
723
|
+
return Color.fromColorChannels(parseColorString(color));
|
|
600
724
|
}
|
|
601
725
|
/**
|
|
602
726
|
* Gets common color
|
|
@@ -626,8 +750,7 @@
|
|
|
626
750
|
* @returns Color object
|
|
627
751
|
*/
|
|
628
752
|
static fromHex(hex) {
|
|
629
|
-
|
|
630
|
-
return take(new Color(red, green, blue, alpha));
|
|
753
|
+
return Color.fromColorChannels(parseHexColor(hex));
|
|
631
754
|
}
|
|
632
755
|
/**
|
|
633
756
|
* Creates a new Color instance from color in hsl format
|
|
@@ -636,8 +759,7 @@
|
|
|
636
759
|
* @returns Color object
|
|
637
760
|
*/
|
|
638
761
|
static fromHsl(hsl) {
|
|
639
|
-
|
|
640
|
-
return take(new Color(red, green, blue, alpha));
|
|
762
|
+
return Color.fromColorChannels(parseHslColor(hsl));
|
|
641
763
|
}
|
|
642
764
|
/**
|
|
643
765
|
* Creates a new Color instance from color in rgb format
|
|
@@ -646,8 +768,7 @@
|
|
|
646
768
|
* @returns Color object
|
|
647
769
|
*/
|
|
648
770
|
static fromRgbString(rgb) {
|
|
649
|
-
|
|
650
|
-
return take(new Color(red, green, blue, alpha));
|
|
771
|
+
return Color.fromColorChannels(parseRgbColor(rgb));
|
|
651
772
|
}
|
|
652
773
|
/**
|
|
653
774
|
* Creates a new Color instance from color in rbga format
|
|
@@ -656,8 +777,7 @@
|
|
|
656
777
|
* @returns Color object
|
|
657
778
|
*/
|
|
658
779
|
static fromRgbaString(rgba) {
|
|
659
|
-
|
|
660
|
-
return take(new Color(red, green, blue, alpha));
|
|
780
|
+
return Color.fromColorChannels(parseRgbaColor(rgba));
|
|
661
781
|
}
|
|
662
782
|
/**
|
|
663
783
|
* Creates a new Color for color channels values
|
|
@@ -669,7 +789,7 @@
|
|
|
669
789
|
* @returns Color object
|
|
670
790
|
*/
|
|
671
791
|
static fromValues(red, green, blue, alpha = 255) {
|
|
672
|
-
return
|
|
792
|
+
return Color.fromColorChannels({ red, green, blue, alpha });
|
|
673
793
|
}
|
|
674
794
|
/**
|
|
675
795
|
* Checks if the given value is a valid Color object.
|
|
@@ -702,8 +822,7 @@
|
|
|
702
822
|
* @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
|
|
703
823
|
*/
|
|
704
824
|
static isHexColorString(value) {
|
|
705
|
-
return (
|
|
706
|
-
/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value));
|
|
825
|
+
return isHexColorString(value);
|
|
707
826
|
}
|
|
708
827
|
/**
|
|
709
828
|
* Creates new Color object
|
|
@@ -716,89 +835,13 @@
|
|
|
716
835
|
* @param alpha number from 0 (transparent) to 255 (opaque)
|
|
717
836
|
*/
|
|
718
837
|
constructor(red, green, blue, alpha = 255) {
|
|
719
|
-
|
|
720
|
-
this.green = green;
|
|
721
|
-
this.blue = blue;
|
|
722
|
-
this.alpha = alpha;
|
|
723
|
-
checkChannelValue('Red', red);
|
|
724
|
-
checkChannelValue('Green', green);
|
|
725
|
-
checkChannelValue('Blue', blue);
|
|
726
|
-
checkChannelValue('Alpha', alpha);
|
|
838
|
+
super(red, green, blue, alpha);
|
|
727
839
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
* Number from 0 to 255
|
|
731
|
-
* @alias red
|
|
732
|
-
*/
|
|
733
|
-
get r() {
|
|
734
|
-
return this.red;
|
|
735
|
-
}
|
|
736
|
-
/**
|
|
737
|
-
* Shortcut for `green` property
|
|
738
|
-
* Number from 0 to 255
|
|
739
|
-
* @alias green
|
|
740
|
-
*/
|
|
741
|
-
get g() {
|
|
742
|
-
return this.green;
|
|
743
|
-
}
|
|
744
|
-
/**
|
|
745
|
-
* Shortcut for `blue` property
|
|
746
|
-
* Number from 0 to 255
|
|
747
|
-
* @alias blue
|
|
748
|
-
*/
|
|
749
|
-
get b() {
|
|
750
|
-
return this.blue;
|
|
751
|
-
}
|
|
752
|
-
/**
|
|
753
|
-
* Shortcut for `alpha` property
|
|
754
|
-
* Number from 0 (transparent) to 255 (opaque)
|
|
755
|
-
* @alias alpha
|
|
756
|
-
*/
|
|
757
|
-
get a() {
|
|
758
|
-
return this.alpha;
|
|
840
|
+
createColor(red, green, blue, alpha) {
|
|
841
|
+
return new Color(red, green, blue, alpha);
|
|
759
842
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
* Number from 0 (transparent) to 255 (opaque)
|
|
763
|
-
* @alias alpha
|
|
764
|
-
*/
|
|
765
|
-
get opacity() {
|
|
766
|
-
return this.alpha;
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Shortcut for 1-`alpha` property
|
|
770
|
-
*/
|
|
771
|
-
get transparency() {
|
|
772
|
-
return 255 - this.alpha;
|
|
773
|
-
}
|
|
774
|
-
clone() {
|
|
775
|
-
return take(new Color(this.red, this.green, this.blue, this.alpha));
|
|
776
|
-
}
|
|
777
|
-
toString() {
|
|
778
|
-
return this.toHex();
|
|
779
|
-
}
|
|
780
|
-
toHex() {
|
|
781
|
-
if (this.alpha === 255) {
|
|
782
|
-
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
783
|
-
.toString(16)
|
|
784
|
-
.padStart(2, '0')}`;
|
|
785
|
-
}
|
|
786
|
-
else {
|
|
787
|
-
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
788
|
-
.toString(16)
|
|
789
|
-
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
toRgb() {
|
|
793
|
-
if (this.alpha === 255) {
|
|
794
|
-
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
toHsl() {
|
|
801
|
-
throw new Error(`Getting HSL is not implemented`);
|
|
843
|
+
static fromColorChannels({ red, green, blue, alpha }) {
|
|
844
|
+
return take(new Color(red, green, blue, alpha));
|
|
802
845
|
}
|
|
803
846
|
}
|
|
804
847
|
|
|
@@ -6592,7 +6635,7 @@
|
|
|
6592
6635
|
*
|
|
6593
6636
|
* @private helper of `minecraft2AvatarVisual`
|
|
6594
6637
|
*/
|
|
6595
|
-
const LIGHT_DIRECTION$
|
|
6638
|
+
const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
6596
6639
|
x: 0.4,
|
|
6597
6640
|
y: -0.65,
|
|
6598
6641
|
z: 0.92,
|
|
@@ -6804,7 +6847,7 @@
|
|
|
6804
6847
|
corners: projectedCorners,
|
|
6805
6848
|
texture: faceDefinition.texture,
|
|
6806
6849
|
averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
|
|
6807
|
-
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$
|
|
6850
|
+
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$2), -1, 1),
|
|
6808
6851
|
outlineColor: cuboid.outlineColor,
|
|
6809
6852
|
};
|
|
6810
6853
|
});
|
|
@@ -7864,13 +7907,138 @@
|
|
|
7864
7907
|
context.restore();
|
|
7865
7908
|
}
|
|
7866
7909
|
|
|
7910
|
+
/* eslint-disable no-magic-numbers */
|
|
7911
|
+
/**
|
|
7912
|
+
* Draws one projected eye on a rotated octopus surface.
|
|
7913
|
+
*
|
|
7914
|
+
* @private helper of the 3D octopus avatar visuals
|
|
7915
|
+
*/
|
|
7916
|
+
function drawProjectedOrganicEye(context, localCenter, radiusX, radiusY, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, phase, interaction, eyeStyle) {
|
|
7917
|
+
const centerScenePoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
7918
|
+
if (centerScenePoint.z <= center.z) {
|
|
7919
|
+
return;
|
|
7920
|
+
}
|
|
7921
|
+
const horizontalScenePoint = transformScenePoint({ x: localCenter.x + radiusX, y: localCenter.y, z: localCenter.z }, center, rotationX, rotationY);
|
|
7922
|
+
const verticalScenePoint = transformScenePoint({ x: localCenter.x, y: localCenter.y + radiusY, z: localCenter.z }, center, rotationX, rotationY);
|
|
7923
|
+
const projectedCenterPoint = projectScenePoint(centerScenePoint, size, sceneCenterX, sceneCenterY);
|
|
7924
|
+
const projectedHorizontalPoint = projectScenePoint(horizontalScenePoint, size, sceneCenterX, sceneCenterY);
|
|
7925
|
+
const projectedVerticalPoint = projectScenePoint(verticalScenePoint, size, sceneCenterX, sceneCenterY);
|
|
7926
|
+
const projectedRadiusX = Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y);
|
|
7927
|
+
const projectedRadiusY = Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y);
|
|
7928
|
+
if (projectedRadiusX < size * 0.008 || projectedRadiusY < size * 0.008) {
|
|
7929
|
+
return;
|
|
7930
|
+
}
|
|
7931
|
+
const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
|
|
7932
|
+
radiusX: projectedRadiusX,
|
|
7933
|
+
radiusY: projectedRadiusY,
|
|
7934
|
+
timeMs,
|
|
7935
|
+
phase,
|
|
7936
|
+
interaction,
|
|
7937
|
+
});
|
|
7938
|
+
const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
|
|
7939
|
+
context.save();
|
|
7940
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
7941
|
+
context.rotate(rotation);
|
|
7942
|
+
context.beginPath();
|
|
7943
|
+
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
7944
|
+
context.fillStyle = '#f8fbff';
|
|
7945
|
+
context.fill();
|
|
7946
|
+
context.clip();
|
|
7947
|
+
const irisGradient = context.createRadialGradient(-projectedRadiusX * 0.2, -projectedRadiusY * 0.26, projectedRadiusX * 0.05, 0, 0, projectedRadiusX * 0.92);
|
|
7948
|
+
irisGradient.addColorStop(0, palette.highlight);
|
|
7949
|
+
irisGradient.addColorStop(0.56, palette.secondary);
|
|
7950
|
+
irisGradient.addColorStop(1, palette.shadow);
|
|
7951
|
+
context.beginPath();
|
|
7952
|
+
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.62 * eyeStyle.irisScale, projectedRadiusY * 0.72 * eyeStyle.irisScale, 0, 0, Math.PI * 2);
|
|
7953
|
+
context.fillStyle = irisGradient;
|
|
7954
|
+
context.fill();
|
|
7955
|
+
context.beginPath();
|
|
7956
|
+
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.15 * eyeStyle.pupilWidthScale, projectedRadiusY * 0.48 * eyeStyle.pupilHeightScale, 0, 0, Math.PI * 2);
|
|
7957
|
+
context.fillStyle = palette.ink;
|
|
7958
|
+
context.fill();
|
|
7959
|
+
context.beginPath();
|
|
7960
|
+
context.ellipse(pupilOffsetX - projectedRadiusX * 0.22, pupilOffsetY - projectedRadiusY * 0.24, projectedRadiusX * 0.12, projectedRadiusY * 0.14, 0, 0, Math.PI * 2);
|
|
7961
|
+
context.fillStyle = '#ffffff';
|
|
7962
|
+
context.fill();
|
|
7963
|
+
context.restore();
|
|
7964
|
+
context.save();
|
|
7965
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
7966
|
+
context.rotate(rotation);
|
|
7967
|
+
context.beginPath();
|
|
7968
|
+
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
7969
|
+
context.strokeStyle = `${palette.shadow}cc`;
|
|
7970
|
+
context.lineWidth = projectedRadiusX * 0.16;
|
|
7971
|
+
context.stroke();
|
|
7972
|
+
context.beginPath();
|
|
7973
|
+
context.moveTo(-projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
|
|
7974
|
+
context.quadraticCurveTo(0, -projectedRadiusY * (eyeStyle.upperLidArchRatio - interaction.gazeY * 0.16 + interaction.intensity * 0.08), projectedRadiusX * 0.88, -projectedRadiusY * eyeStyle.upperLidInsetRatio);
|
|
7975
|
+
context.strokeStyle = `${palette.shadow}73`;
|
|
7976
|
+
context.lineWidth = projectedRadiusX * 0.14;
|
|
7977
|
+
context.lineCap = 'round';
|
|
7978
|
+
context.stroke();
|
|
7979
|
+
if (eyeStyle.lowerLidOpacity > 0) {
|
|
7980
|
+
context.beginPath();
|
|
7981
|
+
context.moveTo(-projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
7982
|
+
context.quadraticCurveTo(0, projectedRadiusY * 0.38, projectedRadiusX * 0.74, projectedRadiusY * 0.2);
|
|
7983
|
+
context.strokeStyle = `${palette.highlight}${formatAlphaHex(eyeStyle.lowerLidOpacity)}`;
|
|
7984
|
+
context.lineWidth = projectedRadiusX * 0.08;
|
|
7985
|
+
context.lineCap = 'round';
|
|
7986
|
+
context.stroke();
|
|
7987
|
+
}
|
|
7988
|
+
context.restore();
|
|
7989
|
+
}
|
|
7990
|
+
/**
|
|
7991
|
+
* Draws a subtle projected mouth arc across the front of a rotated octopus surface.
|
|
7992
|
+
*
|
|
7993
|
+
* @private helper of the 3D octopus avatar visuals
|
|
7994
|
+
*/
|
|
7995
|
+
function drawProjectedOrganicMouth(context, localPoints, center, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size) {
|
|
7996
|
+
const scenePoints = localPoints.map((localPoint) => transformScenePoint(localPoint, center, rotationX, rotationY));
|
|
7997
|
+
if (scenePoints.some((scenePoint) => scenePoint.z <= center.z)) {
|
|
7998
|
+
return;
|
|
7999
|
+
}
|
|
8000
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
8001
|
+
context.beginPath();
|
|
8002
|
+
context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
|
|
8003
|
+
context.quadraticCurveTo(projectedPoints[1].x, projectedPoints[1].y, projectedPoints[2].x, projectedPoints[2].y);
|
|
8004
|
+
context.strokeStyle = `${palette.ink}b8`;
|
|
8005
|
+
context.lineWidth = Math.max(1.1, size * 0.009);
|
|
8006
|
+
context.lineCap = 'round';
|
|
8007
|
+
context.stroke();
|
|
8008
|
+
}
|
|
8009
|
+
/**
|
|
8010
|
+
* Draws one filled projected quad.
|
|
8011
|
+
*
|
|
8012
|
+
* @private helper of the 3D octopus avatar visuals
|
|
8013
|
+
*/
|
|
8014
|
+
function drawProjectedQuad(context, corners, fillStyle) {
|
|
8015
|
+
context.beginPath();
|
|
8016
|
+
context.moveTo(corners[0].x, corners[0].y);
|
|
8017
|
+
context.lineTo(corners[1].x, corners[1].y);
|
|
8018
|
+
context.lineTo(corners[2].x, corners[2].y);
|
|
8019
|
+
context.lineTo(corners[3].x, corners[3].y);
|
|
8020
|
+
context.closePath();
|
|
8021
|
+
context.fillStyle = fillStyle;
|
|
8022
|
+
context.fill();
|
|
8023
|
+
}
|
|
8024
|
+
/**
|
|
8025
|
+
* Converts an opacity ratio into a two-digit hexadecimal alpha suffix.
|
|
8026
|
+
*
|
|
8027
|
+
* @private helper of the 3D octopus avatar visuals
|
|
8028
|
+
*/
|
|
8029
|
+
function formatAlphaHex(opacity) {
|
|
8030
|
+
return Math.round(clampNumber$1(opacity, 0, 1) * 255)
|
|
8031
|
+
.toString(16)
|
|
8032
|
+
.padStart(2, '0');
|
|
8033
|
+
}
|
|
8034
|
+
|
|
7867
8035
|
/* eslint-disable no-magic-numbers */
|
|
7868
8036
|
/**
|
|
7869
8037
|
* Light direction used by the organic 3D octopus shading.
|
|
7870
8038
|
*
|
|
7871
8039
|
* @private helper of `octopus3dAvatarVisual`
|
|
7872
8040
|
*/
|
|
7873
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
8041
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
7874
8042
|
x: 0.48,
|
|
7875
8043
|
y: -0.62,
|
|
7876
8044
|
z: 0.94,
|
|
@@ -7983,17 +8151,17 @@
|
|
|
7983
8151
|
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
7984
8152
|
drawTentacleStroke(context, tentacleStroke, palette);
|
|
7985
8153
|
}
|
|
7986
|
-
|
|
8154
|
+
drawProjectedOrganicEye(context, {
|
|
7987
8155
|
x: -faceEyeSpacing,
|
|
7988
8156
|
y: faceEyeYOffset,
|
|
7989
8157
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
7990
8158
|
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
7991
|
-
|
|
8159
|
+
drawProjectedOrganicEye(context, {
|
|
7992
8160
|
x: faceEyeSpacing,
|
|
7993
8161
|
y: faceEyeYOffset,
|
|
7994
8162
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
7995
8163
|
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
|
|
7996
|
-
|
|
8164
|
+
drawProjectedOrganicMouth(context, [
|
|
7997
8165
|
{
|
|
7998
8166
|
x: -mouthHalfWidth,
|
|
7999
8167
|
y: mouthY,
|
|
@@ -8080,7 +8248,7 @@
|
|
|
8080
8248
|
corners: projectedCorners,
|
|
8081
8249
|
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
8082
8250
|
transformedCorners.length,
|
|
8083
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
8251
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1),
|
|
8084
8252
|
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
8085
8253
|
outlineColor,
|
|
8086
8254
|
});
|
|
@@ -8262,128 +8430,260 @@
|
|
|
8262
8430
|
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
8263
8431
|
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
8264
8432
|
}
|
|
8433
|
+
|
|
8434
|
+
/* eslint-disable no-magic-numbers */
|
|
8265
8435
|
/**
|
|
8266
|
-
*
|
|
8436
|
+
* Light direction used by the single-mesh octopus shading.
|
|
8267
8437
|
*
|
|
8268
|
-
* @private helper of `
|
|
8438
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
8269
8439
|
*/
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
|
|
8440
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
8441
|
+
x: 0.38,
|
|
8442
|
+
y: -0.6,
|
|
8443
|
+
z: 0.98,
|
|
8444
|
+
});
|
|
8445
|
+
/**
|
|
8446
|
+
* Octopus 3D 2 avatar visual.
|
|
8447
|
+
*
|
|
8448
|
+
* @private built-in avatar visual
|
|
8449
|
+
*/
|
|
8450
|
+
const octopus3d2AvatarVisual = {
|
|
8451
|
+
id: 'octopus3d2',
|
|
8452
|
+
title: 'Octopus 3D 2',
|
|
8453
|
+
description: 'Continuous blobby 3D octopus portrait with one soft mesh, turning silhouette, and cursor-aware eyes.',
|
|
8454
|
+
isAnimated: true,
|
|
8455
|
+
supportsPointerTracking: true,
|
|
8456
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
8457
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
8458
|
+
const animationRandom = createRandom('octopus3d2-animation-profile');
|
|
8459
|
+
const eyeRandom = createRandom('octopus3d2-eye-profile');
|
|
8460
|
+
const animationPhase = animationRandom() * Math.PI * 2;
|
|
8461
|
+
const sceneCenterX = size * 0.5;
|
|
8462
|
+
const sceneCenterY = size * 0.575;
|
|
8463
|
+
const bob = Math.sin(timeMs / 940 + animationPhase) * size * 0.013;
|
|
8464
|
+
const meshCenter = {
|
|
8465
|
+
x: interaction.bodyOffsetX * size * 0.044 + size * morphologyProfile.body.centerXJitterRatio * 0.5,
|
|
8466
|
+
y: -size * 0.03 + interaction.bodyOffsetY * size * 0.026 + bob,
|
|
8467
|
+
z: interaction.intensity * size * 0.018,
|
|
8468
|
+
};
|
|
8469
|
+
const rotationY = -0.14 +
|
|
8470
|
+
Math.sin(timeMs / 2600 + animationPhase) * 0.04 +
|
|
8471
|
+
interaction.bodyOffsetX * 0.2 +
|
|
8472
|
+
interaction.gazeX * 0.78;
|
|
8473
|
+
const rotationX = -0.06 +
|
|
8474
|
+
Math.cos(timeMs / 3000 + animationPhase * 0.7) * 0.02 -
|
|
8475
|
+
interaction.bodyOffsetY * 0.08 -
|
|
8476
|
+
interaction.gazeY * 0.34;
|
|
8477
|
+
const surfaceOptions = {
|
|
8478
|
+
radiusX: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch * 1.02,
|
|
8479
|
+
radiusY: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.22,
|
|
8480
|
+
radiusZ: size *
|
|
8481
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
8482
|
+
(0.98 + (morphologyProfile.body.horizontalStretch - 1) * 0.2),
|
|
8483
|
+
morphologyProfile,
|
|
8484
|
+
timeMs,
|
|
8485
|
+
animationPhase,
|
|
8486
|
+
};
|
|
8487
|
+
const surfacePatches = resolveVisibleBlobbyOctopusPatches({
|
|
8488
|
+
...surfaceOptions,
|
|
8489
|
+
center: meshCenter,
|
|
8490
|
+
rotationX,
|
|
8491
|
+
rotationY,
|
|
8492
|
+
sceneCenterX,
|
|
8493
|
+
sceneCenterY,
|
|
8494
|
+
size,
|
|
8495
|
+
palette,
|
|
8496
|
+
});
|
|
8497
|
+
const eyeLatitude = clampNumber$1(morphologyProfile.face.eyeCenterYOffsetRatio * 4.4, -0.16, 0.11);
|
|
8498
|
+
const eyeLongitude = clampNumber$1(morphologyProfile.face.eyeSpacingRatio * 3.25, 0.2, 0.34);
|
|
8499
|
+
const mouthLatitude = clampNumber$1(eyeLatitude + 0.19 + morphologyProfile.face.mouthYOffsetRatio * 1.08, 0.08, 0.34);
|
|
8500
|
+
const mouthCenterLongitude = clampNumber$1(morphologyProfile.face.mouthCenterOffsetRatio * 5.8, -0.08, 0.08);
|
|
8501
|
+
const mouthHalfLongitude = clampNumber$1(eyeLongitude * 0.82, 0.16, 0.29);
|
|
8502
|
+
const mouthCurveLatitude = clampNumber$1(mouthLatitude + morphologyProfile.face.mouthCurveDepthRatio * 0.85, mouthLatitude + 0.03, 0.42);
|
|
8503
|
+
drawAvatarFrame(context, size, palette);
|
|
8504
|
+
drawBlobbyOctopusAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
8505
|
+
drawBlobbyOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile);
|
|
8506
|
+
for (const surfacePatch of surfacePatches.sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
8507
|
+
drawBlobbySurfacePatch(context, surfacePatch);
|
|
8508
|
+
}
|
|
8509
|
+
const leftEyeLocalCenter = sampleBlobbyOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude);
|
|
8510
|
+
const rightEyeLocalCenter = sampleBlobbyOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude);
|
|
8511
|
+
const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.78;
|
|
8512
|
+
const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.92;
|
|
8513
|
+
drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
|
|
8514
|
+
drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
|
|
8515
|
+
drawProjectedOrganicMouth(context, [
|
|
8516
|
+
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
8517
|
+
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
8518
|
+
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude + mouthHalfLongitude),
|
|
8519
|
+
], meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size);
|
|
8520
|
+
},
|
|
8521
|
+
};
|
|
8522
|
+
/**
|
|
8523
|
+
* Draws the deep-water glow behind the continuous octopus mesh.
|
|
8524
|
+
*
|
|
8525
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
8526
|
+
*/
|
|
8527
|
+
function drawBlobbyOctopusAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
8528
|
+
const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.11, sceneCenterY - size * 0.17 + interaction.gazeY * size * 0.05, size * 0.05, sceneCenterX, sceneCenterY - size * 0.03, size * 0.66);
|
|
8529
|
+
glowGradient.addColorStop(0, `${palette.highlight}5e`);
|
|
8530
|
+
glowGradient.addColorStop(0.38, `${palette.accent}26`);
|
|
8531
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
8532
|
+
context.fillStyle = glowGradient;
|
|
8533
|
+
context.fillRect(0, 0, size, size);
|
|
8534
|
+
const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1650) * size * 0.045, sceneCenterY + size * 0.28, size * 0.06, sceneCenterX, sceneCenterY + size * 0.28, size * 0.52);
|
|
8535
|
+
lowerGradient.addColorStop(0, `${palette.secondary}22`);
|
|
8536
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
8537
|
+
context.fillStyle = lowerGradient;
|
|
8538
|
+
context.fillRect(0, 0, size, size);
|
|
8539
|
+
}
|
|
8540
|
+
/**
|
|
8541
|
+
* Draws the soft floor shadow that anchors the single mesh in the frame.
|
|
8542
|
+
*
|
|
8543
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
8544
|
+
*/
|
|
8545
|
+
function drawBlobbyOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
8293
8546
|
context.save();
|
|
8294
|
-
context.
|
|
8295
|
-
context.
|
|
8296
|
-
context.beginPath();
|
|
8297
|
-
context.ellipse(0, 0, projectedRadiusX, projectedRadiusY, 0, 0, Math.PI * 2);
|
|
8298
|
-
context.fillStyle = '#f8fbff';
|
|
8299
|
-
context.fill();
|
|
8300
|
-
context.clip();
|
|
8301
|
-
const irisGradient = context.createRadialGradient(-projectedRadiusX * 0.2, -projectedRadiusY * 0.26, projectedRadiusX * 0.05, 0, 0, projectedRadiusX * 0.92);
|
|
8302
|
-
irisGradient.addColorStop(0, palette.highlight);
|
|
8303
|
-
irisGradient.addColorStop(0.56, palette.secondary);
|
|
8304
|
-
irisGradient.addColorStop(1, palette.shadow);
|
|
8305
|
-
context.beginPath();
|
|
8306
|
-
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.62 * eyeStyle.irisScale, projectedRadiusY * 0.72 * eyeStyle.irisScale, 0, 0, Math.PI * 2);
|
|
8307
|
-
context.fillStyle = irisGradient;
|
|
8308
|
-
context.fill();
|
|
8309
|
-
context.beginPath();
|
|
8310
|
-
context.ellipse(pupilOffsetX, pupilOffsetY, projectedRadiusX * 0.15 * eyeStyle.pupilWidthScale, projectedRadiusY * 0.48 * eyeStyle.pupilHeightScale, 0, 0, Math.PI * 2);
|
|
8311
|
-
context.fillStyle = palette.ink;
|
|
8312
|
-
context.fill();
|
|
8547
|
+
context.fillStyle = `${palette.shadow}66`;
|
|
8548
|
+
context.filter = `blur(${size * 0.024}px)`;
|
|
8313
8549
|
context.beginPath();
|
|
8314
|
-
context.ellipse(
|
|
8315
|
-
context.fillStyle = '#ffffff';
|
|
8550
|
+
context.ellipse(size * 0.5 + interaction.gazeX * size * 0.045, size * 0.88 + Math.sin(timeMs / 940) * size * 0.008, size * (0.18 + (morphologyProfile.body.horizontalStretch - 1) * 0.04 + interaction.intensity * 0.018), size * 0.062, 0, 0, Math.PI * 2);
|
|
8316
8551
|
context.fill();
|
|
8317
8552
|
context.restore();
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8553
|
+
}
|
|
8554
|
+
/**
|
|
8555
|
+
* Resolves all visible projected patches for the single blobby octopus mesh.
|
|
8556
|
+
*
|
|
8557
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
8558
|
+
*/
|
|
8559
|
+
function resolveVisibleBlobbyOctopusPatches(options) {
|
|
8560
|
+
const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, morphologyProfile, animationPhase, timeMs, } = options;
|
|
8561
|
+
const latitudePatchCount = 12;
|
|
8562
|
+
const longitudePatchCount = 24;
|
|
8563
|
+
const surfacePatches = [];
|
|
8564
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
8565
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
8566
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
8567
|
+
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
8568
|
+
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
8569
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
8570
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
8571
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
8572
|
+
const centerLongitude = (startLongitude + endLongitude) / 2;
|
|
8573
|
+
const localCorners = [
|
|
8574
|
+
sampleBlobbyOctopusSurfacePoint(options, startLatitude, startLongitude),
|
|
8575
|
+
sampleBlobbyOctopusSurfacePoint(options, startLatitude, endLongitude),
|
|
8576
|
+
sampleBlobbyOctopusSurfacePoint(options, endLatitude, endLongitude),
|
|
8577
|
+
sampleBlobbyOctopusSurfacePoint(options, endLatitude, startLongitude),
|
|
8578
|
+
];
|
|
8579
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
8580
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
8581
|
+
if (surfaceNormal.z <= 0.01) {
|
|
8582
|
+
continue;
|
|
8583
|
+
}
|
|
8584
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
8585
|
+
surfacePatches.push({
|
|
8586
|
+
corners: projectedCorners,
|
|
8587
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
8588
|
+
transformedCorners.length,
|
|
8589
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
8590
|
+
fillStyle: resolveBlobbySurfacePatchFillStyle(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
8591
|
+
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
8592
|
+
});
|
|
8593
|
+
}
|
|
8341
8594
|
}
|
|
8342
|
-
|
|
8595
|
+
return surfacePatches;
|
|
8596
|
+
}
|
|
8597
|
+
/**
|
|
8598
|
+
* Samples one point on the continuous Octopus 3D 2 surface.
|
|
8599
|
+
*
|
|
8600
|
+
* The lower hemisphere widens and falls into soft lobe waves so the octopus stays one connected mesh
|
|
8601
|
+
* instead of switching to separately rendered tentacles.
|
|
8602
|
+
*
|
|
8603
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
8604
|
+
*/
|
|
8605
|
+
function sampleBlobbyOctopusSurfacePoint(options, latitude, longitude) {
|
|
8606
|
+
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
8607
|
+
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
8608
|
+
const verticalProgress = (Math.sin(latitude) + 1) / 2;
|
|
8609
|
+
const upperBlend = Math.pow(1 - verticalProgress, 1.2);
|
|
8610
|
+
const lowerBlend = Math.pow(verticalProgress, 1.42);
|
|
8611
|
+
const lowerLobeWave = resolveLowerLobeWave(longitude, morphologyProfile, animationPhase, timeMs);
|
|
8612
|
+
const skirtEnvelope = Math.pow(cosineLatitude, 0.5) * lowerBlend;
|
|
8613
|
+
const horizontalScale = 1.02 +
|
|
8614
|
+
skirtEnvelope * (0.34 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.22 + lowerLobeWave * 0.22) -
|
|
8615
|
+
upperBlend * 0.08;
|
|
8616
|
+
const depthScale = 1.04 +
|
|
8617
|
+
upperBlend * 0.16 +
|
|
8618
|
+
Math.max(0, Math.cos(longitude)) * 0.1 +
|
|
8619
|
+
skirtEnvelope * (0.08 + lowerLobeWave * 0.06) -
|
|
8620
|
+
Math.max(0, -Math.cos(longitude)) * 0.04;
|
|
8621
|
+
const lowerDrop = skirtEnvelope *
|
|
8622
|
+
radiusY *
|
|
8623
|
+
(0.28 + lowerLobeWave * 0.14 + (morphologyProfile.tentacles.flowLengthScale - 1) * 0.12);
|
|
8624
|
+
const swayX = Math.sin(timeMs / 1250 + longitude * 1.8 + animationPhase) * skirtEnvelope * radiusX * 0.05;
|
|
8625
|
+
const swayZ = Math.cos(timeMs / 1480 + longitude * 1.2 - animationPhase * 0.7) * skirtEnvelope * radiusZ * 0.03;
|
|
8626
|
+
return {
|
|
8627
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX * horizontalScale + swayX,
|
|
8628
|
+
y: Math.sin(latitude) * radiusY * (1 + upperBlend * 0.14) -
|
|
8629
|
+
upperBlend * radiusY * 0.1 +
|
|
8630
|
+
lowerDrop +
|
|
8631
|
+
Math.sin(timeMs / 1780 + animationPhase + latitude * 1.4) * skirtEnvelope * radiusY * 0.02,
|
|
8632
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ * depthScale + swayZ,
|
|
8633
|
+
};
|
|
8343
8634
|
}
|
|
8344
8635
|
/**
|
|
8345
|
-
*
|
|
8636
|
+
* Resolves the soft lower-lobe wave that makes the silhouette read more like a real octopus.
|
|
8346
8637
|
*
|
|
8347
|
-
* @private helper of `
|
|
8638
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
8348
8639
|
*/
|
|
8349
|
-
function
|
|
8350
|
-
const
|
|
8351
|
-
|
|
8352
|
-
return;
|
|
8353
|
-
}
|
|
8354
|
-
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
8355
|
-
context.beginPath();
|
|
8356
|
-
context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
|
|
8357
|
-
context.quadraticCurveTo(projectedPoints[1].x, projectedPoints[1].y, projectedPoints[2].x, projectedPoints[2].y);
|
|
8358
|
-
context.strokeStyle = `${palette.ink}b8`;
|
|
8359
|
-
context.lineWidth = Math.max(1.1, size * 0.009);
|
|
8360
|
-
context.lineCap = 'round';
|
|
8361
|
-
context.stroke();
|
|
8640
|
+
function resolveLowerLobeWave(longitude, morphologyProfile, animationPhase, timeMs) {
|
|
8641
|
+
const lobeCount = Math.max(4, Math.round((morphologyProfile.body.lobeCount + morphologyProfile.tentacles.count) / 2));
|
|
8642
|
+
return (Math.cos(longitude * lobeCount + animationPhase + timeMs / 1040) + 1) / 2;
|
|
8362
8643
|
}
|
|
8363
8644
|
/**
|
|
8364
|
-
*
|
|
8645
|
+
* Resolves one base fill tone for a surface patch on the single octopus mesh.
|
|
8365
8646
|
*
|
|
8366
|
-
* @private helper of `
|
|
8647
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
8367
8648
|
*/
|
|
8368
|
-
function
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8649
|
+
function resolveBlobbySurfacePatchFillStyle(palette, verticalProgress, forwardness, lowerLobeWave) {
|
|
8650
|
+
const tonalProgress = clampNumber$1(verticalProgress + lowerLobeWave * 0.12 - forwardness * 0.07, 0, 1);
|
|
8651
|
+
if (tonalProgress < 0.16) {
|
|
8652
|
+
return palette.highlight;
|
|
8653
|
+
}
|
|
8654
|
+
if (tonalProgress < 0.34) {
|
|
8655
|
+
return palette.secondary;
|
|
8656
|
+
}
|
|
8657
|
+
if (tonalProgress < 0.72) {
|
|
8658
|
+
return forwardness > 0.58 ? palette.secondary : palette.primary;
|
|
8659
|
+
}
|
|
8660
|
+
return `${palette.shadow}f2`;
|
|
8377
8661
|
}
|
|
8378
8662
|
/**
|
|
8379
|
-
*
|
|
8663
|
+
* Draws one projected patch with soft octopus shading.
|
|
8380
8664
|
*
|
|
8381
|
-
* @private helper of `
|
|
8665
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
8382
8666
|
*/
|
|
8383
|
-
function
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
.
|
|
8667
|
+
function drawBlobbySurfacePatch(context, surfacePatch) {
|
|
8668
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
8669
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
8670
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.16 * surfacePatch.lightIntensity})`);
|
|
8671
|
+
}
|
|
8672
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
8673
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
8674
|
+
}
|
|
8675
|
+
context.save();
|
|
8676
|
+
context.beginPath();
|
|
8677
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
8678
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
8679
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
8680
|
+
}
|
|
8681
|
+
context.closePath();
|
|
8682
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
8683
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0042);
|
|
8684
|
+
context.lineJoin = 'round';
|
|
8685
|
+
context.stroke();
|
|
8686
|
+
context.restore();
|
|
8387
8687
|
}
|
|
8388
8688
|
|
|
8389
8689
|
/* eslint-disable no-magic-numbers */
|
|
@@ -9155,6 +9455,7 @@
|
|
|
9155
9455
|
octopus2AvatarVisual,
|
|
9156
9456
|
octopus3AvatarVisual,
|
|
9157
9457
|
octopus3dAvatarVisual,
|
|
9458
|
+
octopus3d2AvatarVisual,
|
|
9158
9459
|
asciiOctopusAvatarVisual,
|
|
9159
9460
|
minecraftAvatarVisual,
|
|
9160
9461
|
minecraft2AvatarVisual,
|
|
@@ -14819,11 +15120,11 @@
|
|
|
14819
15120
|
});
|
|
14820
15121
|
}
|
|
14821
15122
|
/**
|
|
14822
|
-
*
|
|
15123
|
+
* Prepares one attachment for best-effort text decoding.
|
|
14823
15124
|
*
|
|
14824
|
-
* @private
|
|
15125
|
+
* @private function of decodeAttachmentAsText
|
|
14825
15126
|
*/
|
|
14826
|
-
function
|
|
15127
|
+
function createDecodeAttachmentPreparation(input, options) {
|
|
14827
15128
|
var _a;
|
|
14828
15129
|
const maxBytes = Math.max(1, Math.floor((_a = options.maxBytes) !== null && _a !== void 0 ? _a : DEFAULT_ATTACHMENT_TEXT_DECODE_BYTES));
|
|
14829
15130
|
const forceText = options.forceText === true;
|
|
@@ -14837,54 +15138,102 @@
|
|
|
14837
15138
|
const inspection = inspectBytes(truncatedBytes);
|
|
14838
15139
|
const trustedTextMime = isTrustedTextMimeType(mimeType);
|
|
14839
15140
|
const trustedBinaryMime = isTrustedBinaryMimeType(mimeType);
|
|
15141
|
+
const shouldTreatAsBinary = (trustedBinaryMime || inspection.looksBinary) && !trustedTextMime;
|
|
14840
15142
|
if (isTruncated) {
|
|
14841
15143
|
warnings.push(`Decoded only the first ${maxBytes} bytes of \`${input.filename}\` because the attachment exceeded the text preview limit.`);
|
|
14842
15144
|
}
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
15145
|
+
return {
|
|
15146
|
+
warnings,
|
|
15147
|
+
charset,
|
|
15148
|
+
bom,
|
|
15149
|
+
inspection,
|
|
15150
|
+
truncatedBytes,
|
|
15151
|
+
isTruncated,
|
|
15152
|
+
forceText,
|
|
15153
|
+
shouldTreatAsBinary,
|
|
15154
|
+
};
|
|
15155
|
+
}
|
|
15156
|
+
/**
|
|
15157
|
+
* Returns an early result when the attachment should stay classified as binary.
|
|
15158
|
+
*
|
|
15159
|
+
* @private function of decodeAttachmentAsText
|
|
15160
|
+
*/
|
|
15161
|
+
function createBinaryDecodeResult(preparation) {
|
|
15162
|
+
if (!preparation.shouldTreatAsBinary) {
|
|
15163
|
+
return null;
|
|
14854
15164
|
}
|
|
14855
|
-
if (
|
|
14856
|
-
warnings.push('File content looks binary, but text decoding was forced with `forceText`.');
|
|
15165
|
+
if (preparation.forceText) {
|
|
15166
|
+
preparation.warnings.push('File content looks binary, but text decoding was forced with `forceText`.');
|
|
15167
|
+
return null;
|
|
14857
15168
|
}
|
|
14858
|
-
|
|
14859
|
-
|
|
15169
|
+
preparation.warnings.push('File content looks binary, so text decoding was skipped.');
|
|
15170
|
+
return {
|
|
15171
|
+
text: '',
|
|
15172
|
+
encodingUsed: 'binary',
|
|
15173
|
+
confidence: 1,
|
|
15174
|
+
warnings: preparation.warnings,
|
|
15175
|
+
wasBinary: true,
|
|
15176
|
+
isTruncated: preparation.isTruncated,
|
|
15177
|
+
};
|
|
15178
|
+
}
|
|
15179
|
+
/**
|
|
15180
|
+
* Warns when the declared charset cannot be used by the runtime decoder.
|
|
15181
|
+
*
|
|
15182
|
+
* @private function of decodeAttachmentAsText
|
|
15183
|
+
*/
|
|
15184
|
+
function addUnsupportedCharsetWarning(preparation) {
|
|
15185
|
+
if (preparation.charset && !isSupportedEncoding(preparation.charset)) {
|
|
15186
|
+
preparation.warnings.push(`Ignored unsupported declared charset \`${preparation.charset}\` and used best-effort detection instead.`);
|
|
14860
15187
|
}
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
14866
|
-
|
|
14867
|
-
|
|
14868
|
-
|
|
15188
|
+
}
|
|
15189
|
+
/**
|
|
15190
|
+
* Returns the byte slice that should actually be decoded as text.
|
|
15191
|
+
*
|
|
15192
|
+
* @private function of decodeAttachmentAsText
|
|
15193
|
+
*/
|
|
15194
|
+
function getBytesToDecode(preparation) {
|
|
15195
|
+
return preparation.bom ? preparation.truncatedBytes.subarray(preparation.bom.offset) : preparation.truncatedBytes;
|
|
15196
|
+
}
|
|
15197
|
+
/**
|
|
15198
|
+
* Decodes all candidate encodings and sorts the successful results by score.
|
|
15199
|
+
*
|
|
15200
|
+
* @private function of decodeAttachmentAsText
|
|
15201
|
+
*/
|
|
15202
|
+
function decodeAttachmentCandidates(preparation) {
|
|
15203
|
+
return buildCandidateEncodings({
|
|
15204
|
+
charset: preparation.charset && isSupportedEncoding(preparation.charset) ? preparation.charset : null,
|
|
15205
|
+
bom: preparation.bom,
|
|
15206
|
+
inspection: preparation.inspection,
|
|
15207
|
+
})
|
|
14869
15208
|
.map(({ encoding, source }) => {
|
|
14870
|
-
const decoded = decodeWithEncoding(
|
|
15209
|
+
const decoded = decodeWithEncoding(getBytesToDecode(preparation), encoding);
|
|
14871
15210
|
return decoded ? { ...decoded, source } : null;
|
|
14872
15211
|
})
|
|
14873
15212
|
.filter((candidate) => candidate !== null)
|
|
14874
15213
|
.sort((left, right) => left.score - right.score);
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
15214
|
+
}
|
|
15215
|
+
/**
|
|
15216
|
+
* Returns the fallback result used when no text decoder could be applied.
|
|
15217
|
+
*
|
|
15218
|
+
* @private function of decodeAttachmentAsText
|
|
15219
|
+
*/
|
|
15220
|
+
function createNoDecoderAvailableResult(preparation) {
|
|
15221
|
+
preparation.warnings.push('No supported text decoder was available.');
|
|
15222
|
+
return {
|
|
15223
|
+
text: '',
|
|
15224
|
+
encodingUsed: 'binary',
|
|
15225
|
+
confidence: 0,
|
|
15226
|
+
warnings: preparation.warnings,
|
|
15227
|
+
wasBinary: true,
|
|
15228
|
+
isTruncated: preparation.isTruncated,
|
|
15229
|
+
};
|
|
15230
|
+
}
|
|
15231
|
+
/**
|
|
15232
|
+
* Estimates confidence for the winning decoded text candidate.
|
|
15233
|
+
*
|
|
15234
|
+
* @private function of decodeAttachmentAsText
|
|
15235
|
+
*/
|
|
15236
|
+
function computeDecodeConfidence(bestCandidate, secondBestCandidate, preparation) {
|
|
14888
15237
|
const baseConfidence = bestCandidate.source === 'bom'
|
|
14889
15238
|
? 1
|
|
14890
15239
|
: bestCandidate.source === 'charset'
|
|
@@ -14897,27 +15246,62 @@
|
|
|
14897
15246
|
? 0.82
|
|
14898
15247
|
: 0.62;
|
|
14899
15248
|
const scoreMargin = secondBestCandidate ? Math.max(0, secondBestCandidate.score - bestCandidate.score) : 0.2;
|
|
14900
|
-
|
|
15249
|
+
return Math.max(0.2, Math.min(preparation.shouldTreatAsBinary && preparation.forceText ? 0.45 : 1, baseConfidence + Math.min(0.18, scoreMargin / 2)));
|
|
15250
|
+
}
|
|
15251
|
+
/**
|
|
15252
|
+
* Appends user-facing warnings derived from the chosen decoded text candidate.
|
|
15253
|
+
*
|
|
15254
|
+
* @private function of decodeAttachmentAsText
|
|
15255
|
+
*/
|
|
15256
|
+
function addDecodeWarnings(bestCandidate, confidence, preparation) {
|
|
14901
15257
|
if (bestCandidate.source === 'heuristic' && bestCandidate.encoding !== 'utf-8') {
|
|
14902
|
-
warnings.push(`Encoding was guessed as \`${bestCandidate.encoding}\`.`);
|
|
15258
|
+
preparation.warnings.push(`Encoding was guessed as \`${bestCandidate.encoding}\`.`);
|
|
14903
15259
|
}
|
|
14904
15260
|
if (bestCandidate.source === 'heuristic' &&
|
|
14905
15261
|
bestCandidate.encoding === 'utf-8' &&
|
|
14906
15262
|
bestCandidate.replacementCount > 0) {
|
|
14907
|
-
warnings.push('UTF-8 decoding produced replacement characters, so the extracted text may contain errors.');
|
|
15263
|
+
preparation.warnings.push('UTF-8 decoding produced replacement characters, so the extracted text may contain errors.');
|
|
14908
15264
|
}
|
|
14909
15265
|
if (confidence < 0.6) {
|
|
14910
|
-
warnings.push('Decoding confidence is low, so the extracted text may contain errors.');
|
|
15266
|
+
preparation.warnings.push('Decoding confidence is low, so the extracted text may contain errors.');
|
|
14911
15267
|
}
|
|
15268
|
+
}
|
|
15269
|
+
/**
|
|
15270
|
+
* Creates the final decoded-text result from the chosen candidate and accumulated metadata.
|
|
15271
|
+
*
|
|
15272
|
+
* @private function of decodeAttachmentAsText
|
|
15273
|
+
*/
|
|
15274
|
+
function createDecodedTextResult(bestCandidate, confidence, preparation) {
|
|
14912
15275
|
return {
|
|
14913
|
-
text: isTruncated ? appendTruncatedMarker(bestCandidate.text) : bestCandidate.text,
|
|
15276
|
+
text: preparation.isTruncated ? appendTruncatedMarker(bestCandidate.text) : bestCandidate.text,
|
|
14914
15277
|
encodingUsed: bestCandidate.encoding,
|
|
14915
15278
|
confidence,
|
|
14916
|
-
warnings,
|
|
15279
|
+
warnings: preparation.warnings,
|
|
14917
15280
|
wasBinary: false,
|
|
14918
|
-
isTruncated,
|
|
15281
|
+
isTruncated: preparation.isTruncated,
|
|
14919
15282
|
};
|
|
14920
15283
|
}
|
|
15284
|
+
/**
|
|
15285
|
+
* Best-effort decoder for uploaded or remote file bytes whose extension or encoding may be unknown.
|
|
15286
|
+
*
|
|
15287
|
+
* @private internal utility for shared text decoding
|
|
15288
|
+
*/
|
|
15289
|
+
function decodeAttachmentAsText(input, options = {}) {
|
|
15290
|
+
const preparation = createDecodeAttachmentPreparation(input, options);
|
|
15291
|
+
const binaryResult = createBinaryDecodeResult(preparation);
|
|
15292
|
+
if (binaryResult) {
|
|
15293
|
+
return binaryResult;
|
|
15294
|
+
}
|
|
15295
|
+
addUnsupportedCharsetWarning(preparation);
|
|
15296
|
+
const decodedCandidates = decodeAttachmentCandidates(preparation);
|
|
15297
|
+
const bestCandidate = decodedCandidates[0];
|
|
15298
|
+
if (!bestCandidate) {
|
|
15299
|
+
return createNoDecoderAvailableResult(preparation);
|
|
15300
|
+
}
|
|
15301
|
+
const confidence = computeDecodeConfidence(bestCandidate, decodedCandidates[1], preparation);
|
|
15302
|
+
addDecodeWarnings(bestCandidate, confidence, preparation);
|
|
15303
|
+
return createDecodedTextResult(bestCandidate, confidence, preparation);
|
|
15304
|
+
}
|
|
14921
15305
|
|
|
14922
15306
|
/**
|
|
14923
15307
|
* Convert file extension to mime type
|
|
@@ -19285,120 +19669,183 @@
|
|
|
19285
19669
|
* @public exported from `@promptbook/utils`
|
|
19286
19670
|
*/
|
|
19287
19671
|
function checkSerializableAsJson(options) {
|
|
19288
|
-
|
|
19672
|
+
checkSerializableValue(options);
|
|
19673
|
+
}
|
|
19674
|
+
// TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
|
|
19675
|
+
// TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
|
|
19676
|
+
// Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
|
|
19677
|
+
/**
|
|
19678
|
+
* Checks one value and dispatches to the appropriate specialized validator.
|
|
19679
|
+
*
|
|
19680
|
+
* @private function of `checkSerializableAsJson`
|
|
19681
|
+
*/
|
|
19682
|
+
function checkSerializableValue(options) {
|
|
19683
|
+
const { value } = options;
|
|
19684
|
+
if (isSerializablePrimitive(value)) {
|
|
19685
|
+
return;
|
|
19686
|
+
}
|
|
19289
19687
|
if (value === undefined) {
|
|
19290
|
-
throw new UnexpectedError(`${name} is undefined`);
|
|
19688
|
+
throw new UnexpectedError(`${options.name} is undefined`);
|
|
19291
19689
|
}
|
|
19292
|
-
|
|
19293
|
-
|
|
19690
|
+
if (typeof value === 'symbol') {
|
|
19691
|
+
throw new UnexpectedError(`${options.name} is symbol`);
|
|
19294
19692
|
}
|
|
19295
|
-
|
|
19296
|
-
|
|
19693
|
+
if (typeof value === 'function') {
|
|
19694
|
+
throw new UnexpectedError(`${options.name} is function`);
|
|
19297
19695
|
}
|
|
19298
|
-
|
|
19696
|
+
if (Array.isArray(value)) {
|
|
19697
|
+
checkSerializableArray(options, value);
|
|
19299
19698
|
return;
|
|
19300
19699
|
}
|
|
19301
|
-
|
|
19700
|
+
if (value !== null && typeof value === 'object') {
|
|
19701
|
+
checkSerializableObject(options, value);
|
|
19302
19702
|
return;
|
|
19303
19703
|
}
|
|
19304
|
-
|
|
19305
|
-
|
|
19306
|
-
|
|
19307
|
-
|
|
19308
|
-
|
|
19309
|
-
|
|
19310
|
-
|
|
19311
|
-
|
|
19312
|
-
|
|
19313
|
-
|
|
19704
|
+
throwUnknownTypeError(options);
|
|
19705
|
+
}
|
|
19706
|
+
/**
|
|
19707
|
+
* Checks the primitive values that are directly JSON serializable.
|
|
19708
|
+
*
|
|
19709
|
+
* @private function of `checkSerializableAsJson`
|
|
19710
|
+
*/
|
|
19711
|
+
function isSerializablePrimitive(value) {
|
|
19712
|
+
return (value === null ||
|
|
19713
|
+
typeof value === 'boolean' ||
|
|
19714
|
+
(typeof value === 'number' && !isNaN(value)) ||
|
|
19715
|
+
typeof value === 'string');
|
|
19716
|
+
}
|
|
19717
|
+
/**
|
|
19718
|
+
* Recursively checks JSON array items.
|
|
19719
|
+
*
|
|
19720
|
+
* @private function of `checkSerializableAsJson`
|
|
19721
|
+
*/
|
|
19722
|
+
function checkSerializableArray(context, arrayValue) {
|
|
19723
|
+
for (let index = 0; index < arrayValue.length; index++) {
|
|
19724
|
+
checkSerializableAsJson({
|
|
19725
|
+
...context,
|
|
19726
|
+
name: `${context.name}[${index}]`,
|
|
19727
|
+
value: arrayValue[index],
|
|
19728
|
+
});
|
|
19314
19729
|
}
|
|
19315
|
-
|
|
19316
|
-
|
|
19317
|
-
|
|
19318
|
-
|
|
19730
|
+
}
|
|
19731
|
+
/**
|
|
19732
|
+
* Checks object-like values and dispatches special unsupported built-ins.
|
|
19733
|
+
*
|
|
19734
|
+
* @private function of `checkSerializableAsJson`
|
|
19735
|
+
*/
|
|
19736
|
+
function checkSerializableObject(context, objectValue) {
|
|
19737
|
+
checkUnsupportedObjectType(context, objectValue);
|
|
19738
|
+
checkSerializableObjectEntries(context, objectValue);
|
|
19739
|
+
assertJsonStringificationSucceeds(context, objectValue);
|
|
19740
|
+
}
|
|
19741
|
+
/**
|
|
19742
|
+
* Rejects built-in objects that must be converted before JSON serialization.
|
|
19743
|
+
*
|
|
19744
|
+
* @private function of `checkSerializableAsJson`
|
|
19745
|
+
*/
|
|
19746
|
+
function checkUnsupportedObjectType(context, objectValue) {
|
|
19747
|
+
if (objectValue instanceof Date) {
|
|
19748
|
+
throw new UnexpectedError(spacetrim.spaceTrim((block) => `
|
|
19749
|
+
\`${context.name}\` is Date
|
|
19319
19750
|
|
|
19320
|
-
|
|
19751
|
+
Use \`string_date_iso8601\` instead
|
|
19321
19752
|
|
|
19322
|
-
|
|
19323
|
-
|
|
19324
|
-
|
|
19325
|
-
|
|
19326
|
-
|
|
19327
|
-
|
|
19328
|
-
|
|
19329
|
-
|
|
19330
|
-
|
|
19331
|
-
|
|
19332
|
-
|
|
19333
|
-
|
|
19334
|
-
|
|
19335
|
-
|
|
19336
|
-
|
|
19337
|
-
|
|
19753
|
+
Additional message for \`${context.name}\`:
|
|
19754
|
+
${block(context.message || '(nothing)')}
|
|
19755
|
+
`));
|
|
19756
|
+
}
|
|
19757
|
+
if (objectValue instanceof Map) {
|
|
19758
|
+
throw new UnexpectedError(`${context.name} is Map`);
|
|
19759
|
+
}
|
|
19760
|
+
if (objectValue instanceof Set) {
|
|
19761
|
+
throw new UnexpectedError(`${context.name} is Set`);
|
|
19762
|
+
}
|
|
19763
|
+
if (objectValue instanceof RegExp) {
|
|
19764
|
+
throw new UnexpectedError(`${context.name} is RegExp`);
|
|
19765
|
+
}
|
|
19766
|
+
if (objectValue instanceof Error) {
|
|
19767
|
+
throw new UnexpectedError(spacetrim.spaceTrim((block) => `
|
|
19768
|
+
\`${context.name}\` is unserialized Error
|
|
19338
19769
|
|
|
19339
|
-
|
|
19770
|
+
Use function \`serializeError\`
|
|
19340
19771
|
|
|
19341
|
-
|
|
19342
|
-
|
|
19772
|
+
Additional message for \`${context.name}\`:
|
|
19773
|
+
${block(context.message || '(nothing)')}
|
|
19343
19774
|
|
|
19344
|
-
|
|
19775
|
+
`));
|
|
19776
|
+
}
|
|
19777
|
+
}
|
|
19778
|
+
/**
|
|
19779
|
+
* Recursively checks object properties while preserving omitted `undefined` keys.
|
|
19780
|
+
*
|
|
19781
|
+
* @private function of `checkSerializableAsJson`
|
|
19782
|
+
*/
|
|
19783
|
+
function checkSerializableObjectEntries(context, objectValue) {
|
|
19784
|
+
for (const [subName, subValue] of Object.entries(objectValue)) {
|
|
19785
|
+
if (subValue === undefined) {
|
|
19786
|
+
// Note: undefined in object is serializable - it is just omitted
|
|
19787
|
+
continue;
|
|
19345
19788
|
}
|
|
19346
|
-
|
|
19347
|
-
|
|
19348
|
-
|
|
19349
|
-
|
|
19350
|
-
|
|
19351
|
-
|
|
19352
|
-
|
|
19353
|
-
|
|
19354
|
-
|
|
19355
|
-
|
|
19356
|
-
|
|
19357
|
-
|
|
19358
|
-
|
|
19359
|
-
|
|
19360
|
-
|
|
19789
|
+
checkSerializableAsJson({
|
|
19790
|
+
...context,
|
|
19791
|
+
name: `${context.name}.${subName}`,
|
|
19792
|
+
value: subValue,
|
|
19793
|
+
});
|
|
19794
|
+
}
|
|
19795
|
+
}
|
|
19796
|
+
/**
|
|
19797
|
+
* Uses `JSON.stringify` as the final guard for cases like circular references.
|
|
19798
|
+
*
|
|
19799
|
+
* @private function of `checkSerializableAsJson`
|
|
19800
|
+
*/
|
|
19801
|
+
function assertJsonStringificationSucceeds(context, objectValue) {
|
|
19802
|
+
try {
|
|
19803
|
+
JSON.stringify(objectValue); // <- TODO: [0]
|
|
19804
|
+
}
|
|
19805
|
+
catch (error) {
|
|
19806
|
+
assertsError(error);
|
|
19807
|
+
throw new UnexpectedError(spacetrim.spaceTrim((block) => `
|
|
19808
|
+
\`${context.name}\` is not serializable
|
|
19361
19809
|
|
|
19362
|
-
|
|
19810
|
+
${block(error.stack || error.message)}
|
|
19363
19811
|
|
|
19364
|
-
|
|
19365
|
-
|
|
19366
|
-
|
|
19812
|
+
Additional message for \`${context.name}\`:
|
|
19813
|
+
${block(context.message || '(nothing)')}
|
|
19814
|
+
`));
|
|
19815
|
+
}
|
|
19816
|
+
/*
|
|
19817
|
+
TODO: [0] Is there some more elegant way to check circular references?
|
|
19818
|
+
const seen = new Set();
|
|
19819
|
+
const stack = [{ value }];
|
|
19820
|
+
while (stack.length > 0) {
|
|
19821
|
+
const { value } = stack.pop()!;
|
|
19822
|
+
if (typeof value === 'object' && value !== null) {
|
|
19823
|
+
if (seen.has(value)) {
|
|
19824
|
+
throw new UnexpectedError(`${name} has circular reference`);
|
|
19367
19825
|
}
|
|
19368
|
-
|
|
19369
|
-
|
|
19370
|
-
|
|
19371
|
-
|
|
19372
|
-
|
|
19373
|
-
const { value } = stack.pop()!;
|
|
19374
|
-
if (typeof value === 'object' && value !== null) {
|
|
19375
|
-
if (seen.has(value)) {
|
|
19376
|
-
throw new UnexpectedError(`${name} has circular reference`);
|
|
19377
|
-
}
|
|
19378
|
-
seen.add(value);
|
|
19379
|
-
if (Array.isArray(value)) {
|
|
19380
|
-
stack.push(...value.map((value) => ({ value })));
|
|
19381
|
-
} else {
|
|
19382
|
-
stack.push(...Object.values(value).map((value) => ({ value })));
|
|
19383
|
-
}
|
|
19384
|
-
}
|
|
19826
|
+
seen.add(value);
|
|
19827
|
+
if (Array.isArray(value)) {
|
|
19828
|
+
stack.push(...value.map((value) => ({ value })));
|
|
19829
|
+
} else {
|
|
19830
|
+
stack.push(...Object.values(value).map((value) => ({ value })));
|
|
19385
19831
|
}
|
|
19386
|
-
*/
|
|
19387
|
-
return;
|
|
19388
19832
|
}
|
|
19389
19833
|
}
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
19834
|
+
*/
|
|
19835
|
+
}
|
|
19836
|
+
/**
|
|
19837
|
+
* Throws the fallback error for unsupported value types like `bigint` and `NaN`.
|
|
19838
|
+
*
|
|
19839
|
+
* @private function of `checkSerializableAsJson`
|
|
19840
|
+
*/
|
|
19841
|
+
function throwUnknownTypeError(context) {
|
|
19842
|
+
throw new UnexpectedError(spacetrim.spaceTrim((block) => `
|
|
19843
|
+
\`${context.name}\` is unknown type
|
|
19393
19844
|
|
|
19394
|
-
|
|
19395
|
-
|
|
19396
|
-
|
|
19397
|
-
}
|
|
19845
|
+
Additional message for \`${context.name}\`:
|
|
19846
|
+
${block(context.message || '(nothing)')}
|
|
19847
|
+
`));
|
|
19398
19848
|
}
|
|
19399
|
-
// TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
|
|
19400
|
-
// TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
|
|
19401
|
-
// Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
|
|
19402
19849
|
|
|
19403
19850
|
/**
|
|
19404
19851
|
* Creates a deep clone of the given object
|
|
@@ -22351,7 +22798,7 @@
|
|
|
22351
22798
|
*/
|
|
22352
22799
|
function createPostprocessingCommands(task) {
|
|
22353
22800
|
var _a;
|
|
22354
|
-
return ((_a = task.postprocessingFunctionNames) === null || _a === void 0 ? void 0 : _a.map((postprocessingFunctionName) => `POSTPROCESSING \`${postprocessingFunctionName}\``)) || [];
|
|
22801
|
+
return (((_a = task.postprocessingFunctionNames) === null || _a === void 0 ? void 0 : _a.map((postprocessingFunctionName) => `POSTPROCESSING \`${postprocessingFunctionName}\``)) || []);
|
|
22355
22802
|
}
|
|
22356
22803
|
/**
|
|
22357
22804
|
* Collects expectation commands.
|
|
@@ -22894,8 +23341,7 @@
|
|
|
22894
23341
|
* @private internal utility of `validatePipeline`
|
|
22895
23342
|
*/
|
|
22896
23343
|
function validateTaskSupportsJokers(task, pipelineIdentification) {
|
|
22897
|
-
if (task.format ||
|
|
22898
|
-
task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
|
|
23344
|
+
if (task.format || task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
|
|
22899
23345
|
return;
|
|
22900
23346
|
}
|
|
22901
23347
|
throw new PipelineLogicError(spacetrim.spaceTrim((block) => `
|
|
@@ -26260,9 +26706,7 @@
|
|
|
26260
26706
|
${block(quoteMultilineText(((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message) || ''))}
|
|
26261
26707
|
|
|
26262
26708
|
Result:
|
|
26263
|
-
${block(failure.result === null
|
|
26264
|
-
? 'null'
|
|
26265
|
-
: quoteMultilineText(spacetrim.spaceTrim(failure.result)))}
|
|
26709
|
+
${block(failure.result === null ? 'null' : quoteMultilineText(spacetrim.spaceTrim(failure.result)))}
|
|
26266
26710
|
`;
|
|
26267
26711
|
}))
|
|
26268
26712
|
.join('\n\n---\n\n');
|
|
@@ -30102,7 +30546,10 @@
|
|
|
30102
30546
|
Cannot find model in ${this.options.getTitle()} models with name "${defaultModelName}" which should be used as default.
|
|
30103
30547
|
|
|
30104
30548
|
Available models:
|
|
30105
|
-
${block(this.options
|
|
30549
|
+
${block(this.options
|
|
30550
|
+
.getHardcodedModels()
|
|
30551
|
+
.map(({ modelName }) => `- "${modelName}"`)
|
|
30552
|
+
.join('\n'))}
|
|
30106
30553
|
|
|
30107
30554
|
Model "${defaultModelName}" is probably not available anymore, not installed, inaccessible or misconfigured.
|
|
30108
30555
|
|
|
@@ -30456,7 +30903,8 @@
|
|
|
30456
30903
|
};
|
|
30457
30904
|
let rawPromptContent = templateParameters(content, { ...parameters, modelName });
|
|
30458
30905
|
if ('attachments' in prompt && Array.isArray(prompt.attachments) && prompt.attachments.length > 0) {
|
|
30459
|
-
rawPromptContent +=
|
|
30906
|
+
rawPromptContent +=
|
|
30907
|
+
'\n\n' + prompt.attachments.map((attachment) => `Image attachment: ${attachment.url}`).join('\n');
|
|
30460
30908
|
}
|
|
30461
30909
|
const rawRequest = {
|
|
30462
30910
|
...modelSettings,
|
|
@@ -30561,7 +31009,9 @@
|
|
|
30561
31009
|
* Schedules one request through the shared limiter and retry policy.
|
|
30562
31010
|
*/
|
|
30563
31011
|
async executeRateLimitedRequest(requestFn) {
|
|
30564
|
-
return this.limiter
|
|
31012
|
+
return this.limiter
|
|
31013
|
+
.schedule(() => this.makeRequestWithNetworkRetry(requestFn))
|
|
31014
|
+
.catch((error) => {
|
|
30565
31015
|
assertsError(error);
|
|
30566
31016
|
if (this.options.isVerbose) {
|
|
30567
31017
|
console.info(colors__default["default"].bgRed('error'), error);
|
|
@@ -31768,7 +32218,9 @@
|
|
|
31768
32218
|
pollingState.lastProgressAtMs = nowMs;
|
|
31769
32219
|
pollingState.lastProgressKey = progressKey;
|
|
31770
32220
|
}
|
|
31771
|
-
if (this.options.isVerbose &&
|
|
32221
|
+
if (this.options.isVerbose &&
|
|
32222
|
+
(statusCountsKey !== pollingState.lastCountsKey ||
|
|
32223
|
+
nowMs - pollingState.lastLogAtMs >= progressLogIntervalMs)) {
|
|
31772
32224
|
console.info('[🤰]', 'Vector store file batch status', {
|
|
31773
32225
|
vectorStoreId,
|
|
31774
32226
|
batchId,
|