jspsych-tangram 0.0.12 → 0.0.14
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/dist/construct/index.browser.js +283 -64
- package/dist/construct/index.browser.js.map +1 -1
- package/dist/construct/index.browser.min.js +11 -11
- package/dist/construct/index.browser.min.js.map +1 -1
- package/dist/construct/index.cjs +283 -64
- package/dist/construct/index.cjs.map +1 -1
- package/dist/construct/index.d.ts +36 -0
- package/dist/construct/index.js +283 -64
- package/dist/construct/index.js.map +1 -1
- package/dist/index.cjs +394 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +84 -0
- package/dist/index.js +394 -94
- package/dist/index.js.map +1 -1
- package/dist/nback/index.browser.js +112 -37
- package/dist/nback/index.browser.js.map +1 -1
- package/dist/nback/index.browser.min.js +11 -11
- package/dist/nback/index.browser.min.js.map +1 -1
- package/dist/nback/index.cjs +112 -37
- package/dist/nback/index.cjs.map +1 -1
- package/dist/nback/index.d.ts +24 -0
- package/dist/nback/index.js +112 -37
- package/dist/nback/index.js.map +1 -1
- package/dist/prep/index.browser.js +278 -65
- package/dist/prep/index.browser.js.map +1 -1
- package/dist/prep/index.browser.min.js +11 -11
- package/dist/prep/index.browser.min.js.map +1 -1
- package/dist/prep/index.cjs +278 -65
- package/dist/prep/index.cjs.map +1 -1
- package/dist/prep/index.d.ts +24 -0
- package/dist/prep/index.js +278 -65
- package/dist/prep/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/components/board/BoardView.tsx +372 -124
- package/src/core/components/board/GameBoard.tsx +39 -44
- package/src/core/components/board/useGameBoard.ts +52 -0
- package/src/core/components/index.ts +4 -2
- package/src/core/components/pieces/BlueprintRing.tsx +100 -67
- package/src/core/components/pieces/useBlueprintRing.ts +39 -0
- package/src/core/config/config.ts +25 -10
- package/src/plugins/tangram-construct/ConstructionApp.tsx +7 -1
- package/src/plugins/tangram-construct/index.ts +22 -1
- package/src/plugins/tangram-nback/NBackApp.tsx +88 -29
- package/src/plugins/tangram-nback/index.ts +14 -0
- package/src/plugins/tangram-prep/PrepApp.tsx +7 -1
- package/src/plugins/tangram-prep/index.ts +14 -0
- package/tangram-construct.min.js +11 -11
- package/tangram-nback.min.js +11 -11
- package/tangram-prep.min.js +11 -11
package/dist/index.js
CHANGED
|
@@ -5,30 +5,41 @@ import { v4 } from 'uuid';
|
|
|
5
5
|
|
|
6
6
|
const CONFIG = {
|
|
7
7
|
color: {
|
|
8
|
+
background: "#fff7e0ff",
|
|
8
9
|
bands: {
|
|
9
|
-
silhouette: { fillEven: "#
|
|
10
|
-
workspace: { fillEven: "#
|
|
10
|
+
silhouette: { fillEven: "#ffffff", fillOdd: "#ffffff", stroke: "#b1b1b1" },
|
|
11
|
+
workspace: { fillEven: "#ffffff", fillOdd: "#ffffff", stroke: "#b1b1b1" }
|
|
11
12
|
},
|
|
12
|
-
completion: { fill: "#
|
|
13
|
+
completion: { fill: "#ccffcc", stroke: "#13da57" },
|
|
13
14
|
silhouetteMask: "#374151",
|
|
14
15
|
anchors: { invalid: "#7dd3fc", valid: "#475569" },
|
|
15
|
-
|
|
16
|
+
// validFill used here for placed composites
|
|
17
|
+
piece: { draggingFill: "#8e7cc3", validFill: "#8e7cc3", invalidFill: "#d55c00", invalidStroke: "#dc2626", selectedStroke: "#674ea7", allGreenStroke: "#86efac", borderStroke: "#674ea7" },
|
|
16
18
|
ui: { light: "#60a5fa", dark: "#1d4ed8" },
|
|
17
19
|
blueprint: { fill: "#374151", selectedStroke: "#111827", badgeFill: "#000000", labelFill: "#ffffff" },
|
|
18
|
-
tangramDecomposition: { stroke: "#fef2cc" }
|
|
20
|
+
tangramDecomposition: { stroke: "#fef2cc" },
|
|
21
|
+
primitiveColors: [
|
|
22
|
+
// from seaborn "colorblind" palette, 6 colors, with red omitted
|
|
23
|
+
"#0173b2",
|
|
24
|
+
"#de8f05",
|
|
25
|
+
"#029e73",
|
|
26
|
+
"#cc78bc",
|
|
27
|
+
"#ca9161"
|
|
28
|
+
]
|
|
19
29
|
},
|
|
20
30
|
opacity: {
|
|
21
|
-
blueprint: 0.
|
|
31
|
+
blueprint: 0.6,
|
|
22
32
|
silhouetteMask: 0.25,
|
|
23
33
|
//anchors: { valid: 0.80, invalid: 0.50 },
|
|
24
34
|
anchors: { invalid: 0, valid: 0 },
|
|
25
|
-
piece: { invalid:
|
|
35
|
+
piece: { invalid: 1, dragging: 1, locked: 1, normal: 1 }
|
|
26
36
|
},
|
|
27
37
|
size: {
|
|
28
|
-
stroke: { bandPx: 5, pieceSelectedPx:
|
|
38
|
+
stroke: { bandPx: 5, pieceSelectedPx: 5, allGreenStrokePx: 10, pieceBorderPx: 2, tangramDecompositionPx: 1 },
|
|
29
39
|
anchorRadiusPx: { valid: 1, invalid: 1 },
|
|
30
40
|
badgeFontPx: 16,
|
|
31
|
-
centerBadge: { fractionOfOuterR: 0.15, minPx: 20, marginPx: 4 }
|
|
41
|
+
centerBadge: { fractionOfOuterR: 0.15, minPx: 20, marginPx: 4 },
|
|
42
|
+
invalidMarker: { sizePx: 10, strokePx: 4 }
|
|
32
43
|
},
|
|
33
44
|
layout: {
|
|
34
45
|
grid: { stepPx: 20, unitPx: 40 },
|
|
@@ -46,7 +57,8 @@ const CONFIG = {
|
|
|
46
57
|
game: {
|
|
47
58
|
snapRadiusPx: 15,
|
|
48
59
|
showBorders: false,
|
|
49
|
-
hideTouchingBorders: true
|
|
60
|
+
hideTouchingBorders: true,
|
|
61
|
+
silhouettesBelowPieces: true
|
|
50
62
|
}
|
|
51
63
|
};
|
|
52
64
|
|
|
@@ -830,6 +842,31 @@ var unlockedIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAYAAA
|
|
|
830
842
|
function pathD(poly) {
|
|
831
843
|
return `M ${poly.map((pt) => `${pt.x} ${pt.y}`).join(" L ")} Z`;
|
|
832
844
|
}
|
|
845
|
+
function getPieceColor(blueprint, usePrimitiveColors, defaultColor, primitiveColorIndices) {
|
|
846
|
+
if (!usePrimitiveColors) {
|
|
847
|
+
return defaultColor;
|
|
848
|
+
}
|
|
849
|
+
if ("kind" in blueprint) {
|
|
850
|
+
const kind = blueprint.kind;
|
|
851
|
+
const kindToIndex = {
|
|
852
|
+
"square": 0,
|
|
853
|
+
"smalltriangle": 1,
|
|
854
|
+
"parallelogram": 2,
|
|
855
|
+
"medtriangle": 3,
|
|
856
|
+
"largetriangle": 4
|
|
857
|
+
};
|
|
858
|
+
const primitiveIndex = kindToIndex[kind];
|
|
859
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
860
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
861
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
862
|
+
if (color) {
|
|
863
|
+
return color;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return defaultColor;
|
|
867
|
+
}
|
|
868
|
+
return defaultColor;
|
|
869
|
+
}
|
|
833
870
|
function BoardView(props) {
|
|
834
871
|
const {
|
|
835
872
|
controller,
|
|
@@ -849,6 +886,9 @@ function BoardView(props) {
|
|
|
849
886
|
dragInvalid,
|
|
850
887
|
lockedPieceId,
|
|
851
888
|
showTangramDecomposition,
|
|
889
|
+
usePrimitiveColorsBlueprints,
|
|
890
|
+
usePrimitiveColorsTargets,
|
|
891
|
+
primitiveColorIndices,
|
|
852
892
|
svgRef,
|
|
853
893
|
setPieceRef,
|
|
854
894
|
onPiecePointerDown,
|
|
@@ -859,6 +899,144 @@ function BoardView(props) {
|
|
|
859
899
|
onCenterBadgePointerDown
|
|
860
900
|
} = props;
|
|
861
901
|
const VW = viewBox.w, VH = viewBox.h;
|
|
902
|
+
const renderSilhouettes = () => layout.sectors.map((s) => {
|
|
903
|
+
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
904
|
+
if (showTangramDecomposition && sectorCfg?.silhouette.primitiveDecomposition) {
|
|
905
|
+
const primitiveDecomposition = sectorCfg.silhouette.primitiveDecomposition;
|
|
906
|
+
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
907
|
+
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
908
|
+
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
909
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
910
|
+
const primInfo = primitiveDecomposition[i];
|
|
911
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
912
|
+
if (usePrimitiveColorsTargets && primInfo?.kind && primitiveColorIndices) {
|
|
913
|
+
const kindToIndex = {
|
|
914
|
+
"square": 0,
|
|
915
|
+
"smalltriangle": 1,
|
|
916
|
+
"parallelogram": 2,
|
|
917
|
+
"medtriangle": 3,
|
|
918
|
+
"largetriangle": 4
|
|
919
|
+
};
|
|
920
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
921
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
922
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
923
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
924
|
+
if (color) {
|
|
925
|
+
fillColor = color;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return /* @__PURE__ */ React.createElement(
|
|
930
|
+
"path",
|
|
931
|
+
{
|
|
932
|
+
key: `prim-fill-${i}`,
|
|
933
|
+
d: pathD(scaledPoly),
|
|
934
|
+
fill: fillColor,
|
|
935
|
+
opacity: CONFIG.opacity.silhouetteMask,
|
|
936
|
+
stroke: "none"
|
|
937
|
+
}
|
|
938
|
+
);
|
|
939
|
+
}));
|
|
940
|
+
} else {
|
|
941
|
+
const placedPolys = placedSilBySector.get(s.id) ?? [];
|
|
942
|
+
if (!placedPolys.length) return null;
|
|
943
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-${s.id}`, pointerEvents: "none" }, placedPolys.map((poly, i) => /* @__PURE__ */ React.createElement("path", { key: i, d: pathD(poly), fill: CONFIG.color.silhouetteMask, opacity: CONFIG.opacity.silhouetteMask })));
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
const renderPieces = (piecesFilter) => {
|
|
947
|
+
const piecesToRender = pieces;
|
|
948
|
+
return piecesToRender.sort((a, b) => {
|
|
949
|
+
if (draggingId === a.id) return 1;
|
|
950
|
+
if (draggingId === b.id) return -1;
|
|
951
|
+
return 0;
|
|
952
|
+
}).map((p) => {
|
|
953
|
+
const bp = controller.getBlueprint(p.blueprintId);
|
|
954
|
+
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
955
|
+
const isDragging = draggingId === p.id;
|
|
956
|
+
const locked = p.sectorId && controller.isSectorCompleted(p.sectorId);
|
|
957
|
+
const isConnectivityLocked = lockedPieceId === p.id;
|
|
958
|
+
selectedPieceId === p.id;
|
|
959
|
+
const isCarriedInvalid = isDragging && dragInvalid;
|
|
960
|
+
const translateX = p.x - bb.min.x;
|
|
961
|
+
const translateY = p.y - bb.min.y;
|
|
962
|
+
const validFillColor = getPieceColor(
|
|
963
|
+
bp,
|
|
964
|
+
usePrimitiveColorsBlueprints || false,
|
|
965
|
+
CONFIG.color.piece.validFill,
|
|
966
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
967
|
+
);
|
|
968
|
+
const draggingFillColor = getPieceColor(
|
|
969
|
+
bp,
|
|
970
|
+
usePrimitiveColorsBlueprints || false,
|
|
971
|
+
CONFIG.color.piece.draggingFill,
|
|
972
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
973
|
+
);
|
|
974
|
+
return /* @__PURE__ */ React.createElement("g", { key: p.id, ref: setPieceRef(p.id), transform: `translate(${translateX}, ${translateY})`, style: { cursor: locked ? "default" : clickMode ? "pointer" : "grab" }, pointerEvents: clickMode && isDragging ? "none" : "auto" }, ("shape" in bp ? bp.shape : []).map((poly, idx) => {
|
|
975
|
+
const showBorders = shouldShowBorders();
|
|
976
|
+
shouldUseSelectiveBorders(p.blueprintId);
|
|
977
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, /* @__PURE__ */ React.createElement(
|
|
978
|
+
"path",
|
|
979
|
+
{
|
|
980
|
+
d: pathD(poly),
|
|
981
|
+
fill: isConnectivityLocked ? CONFIG.color.piece.invalidFill : isCarriedInvalid ? CONFIG.color.piece.invalidFill : isDragging ? draggingFillColor : validFillColor,
|
|
982
|
+
opacity: isConnectivityLocked ? CONFIG.opacity.piece.invalid : isCarriedInvalid ? CONFIG.opacity.piece.invalid : isDragging ? CONFIG.opacity.piece.dragging : locked ? CONFIG.opacity.piece.locked : CONFIG.opacity.piece.normal,
|
|
983
|
+
stroke: "none",
|
|
984
|
+
onPointerDown: (e) => onPiecePointerDown(e, p)
|
|
985
|
+
}
|
|
986
|
+
), showBorders);
|
|
987
|
+
}), isDragging && isCarriedInvalid && "shape" in bp && bp.shape.length > 0 && (() => {
|
|
988
|
+
const { cx, cy } = polysAABB$1(bp.shape);
|
|
989
|
+
const size = CONFIG.size.invalidMarker.sizePx;
|
|
990
|
+
const strokeWidth = CONFIG.size.invalidMarker.strokePx;
|
|
991
|
+
const borderWidth = strokeWidth + 2;
|
|
992
|
+
return /* @__PURE__ */ React.createElement("g", { key: "invalid-marker" }, /* @__PURE__ */ React.createElement(
|
|
993
|
+
"line",
|
|
994
|
+
{
|
|
995
|
+
x1: cx - size,
|
|
996
|
+
y1: cy - size,
|
|
997
|
+
x2: cx + size,
|
|
998
|
+
y2: cy + size,
|
|
999
|
+
stroke: "white",
|
|
1000
|
+
strokeWidth: borderWidth,
|
|
1001
|
+
strokeLinecap: "round"
|
|
1002
|
+
}
|
|
1003
|
+
), /* @__PURE__ */ React.createElement(
|
|
1004
|
+
"line",
|
|
1005
|
+
{
|
|
1006
|
+
x1: cx - size,
|
|
1007
|
+
y1: cy - size,
|
|
1008
|
+
x2: cx + size,
|
|
1009
|
+
y2: cy + size,
|
|
1010
|
+
stroke: CONFIG.color.piece.invalidStroke,
|
|
1011
|
+
strokeWidth,
|
|
1012
|
+
strokeLinecap: "round"
|
|
1013
|
+
}
|
|
1014
|
+
), /* @__PURE__ */ React.createElement(
|
|
1015
|
+
"line",
|
|
1016
|
+
{
|
|
1017
|
+
x1: cx + size,
|
|
1018
|
+
y1: cy - size,
|
|
1019
|
+
x2: cx - size,
|
|
1020
|
+
y2: cy + size,
|
|
1021
|
+
stroke: "white",
|
|
1022
|
+
strokeWidth: borderWidth,
|
|
1023
|
+
strokeLinecap: "round"
|
|
1024
|
+
}
|
|
1025
|
+
), /* @__PURE__ */ React.createElement(
|
|
1026
|
+
"line",
|
|
1027
|
+
{
|
|
1028
|
+
x1: cx + size,
|
|
1029
|
+
y1: cy - size,
|
|
1030
|
+
x2: cx - size,
|
|
1031
|
+
y2: cy + size,
|
|
1032
|
+
stroke: CONFIG.color.piece.invalidStroke,
|
|
1033
|
+
strokeWidth,
|
|
1034
|
+
strokeLinecap: "round"
|
|
1035
|
+
}
|
|
1036
|
+
));
|
|
1037
|
+
})());
|
|
1038
|
+
});
|
|
1039
|
+
};
|
|
862
1040
|
const centerView = controller.state.blueprintView;
|
|
863
1041
|
const bps = centerView === "primitives" ? controller.state.primitives : controller.state.quickstash;
|
|
864
1042
|
const QS_SLOTS = controller.state.cfg.maxQuickstashSlots;
|
|
@@ -879,6 +1057,12 @@ function BoardView(props) {
|
|
|
879
1057
|
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
880
1058
|
const cx = bb.min.x + bb.width / 2;
|
|
881
1059
|
const cy = bb.min.y + bb.height / 2;
|
|
1060
|
+
const fillColor = getPieceColor(
|
|
1061
|
+
bp,
|
|
1062
|
+
usePrimitiveColorsBlueprints || false,
|
|
1063
|
+
CONFIG.color.blueprint.fill,
|
|
1064
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
1065
|
+
);
|
|
882
1066
|
return /* @__PURE__ */ React.createElement(
|
|
883
1067
|
"g",
|
|
884
1068
|
{
|
|
@@ -890,7 +1074,7 @@ function BoardView(props) {
|
|
|
890
1074
|
{
|
|
891
1075
|
key: idx,
|
|
892
1076
|
d: pathD(poly),
|
|
893
|
-
fill:
|
|
1077
|
+
fill: fillColor,
|
|
894
1078
|
opacity: CONFIG.opacity.blueprint,
|
|
895
1079
|
stroke: "none",
|
|
896
1080
|
strokeWidth: 0,
|
|
@@ -914,7 +1098,7 @@ function BoardView(props) {
|
|
|
914
1098
|
onPointerDown: (e) => {
|
|
915
1099
|
onRootPointerDown(e);
|
|
916
1100
|
},
|
|
917
|
-
style: { background:
|
|
1101
|
+
style: { background: CONFIG.color.background, touchAction: "none", userSelect: "none" }
|
|
918
1102
|
},
|
|
919
1103
|
layout.sectors.map((s, i) => {
|
|
920
1104
|
const done = !!controller.state.sectors[s.id].completedAt;
|
|
@@ -924,35 +1108,7 @@ function BoardView(props) {
|
|
|
924
1108
|
const work = layout.bands.workspace;
|
|
925
1109
|
return /* @__PURE__ */ React.createElement("g", { key: `bands-${s.id}` }, controller.state.cfg.target === "workspace" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("path", { d: wedgePath(layout.cx, layout.cy, sil[0], sil[1], s.start, s.end), fill: baseSil, stroke: CONFIG.color.bands.silhouette.stroke, strokeWidth: CONFIG.size.stroke.bandPx, pointerEvents: "none" }), /* @__PURE__ */ React.createElement("path", { d: wedgePath(layout.cx, layout.cy, work[0], work[1], s.start, s.end), fill: done ? CONFIG.color.completion.fill : baseWork, stroke: done ? CONFIG.color.completion.stroke : CONFIG.color.bands.workspace.stroke, strokeWidth: CONFIG.size.stroke.bandPx, pointerEvents: "none" })) : /* @__PURE__ */ React.createElement("path", { d: wedgePath(layout.cx, layout.cy, sil[0], sil[1], s.start, s.end), fill: done ? CONFIG.color.completion.fill : baseSil, stroke: done ? CONFIG.color.completion.stroke : CONFIG.color.bands.silhouette.stroke, strokeWidth: CONFIG.size.stroke.bandPx, pointerEvents: "none" }));
|
|
926
1110
|
}),
|
|
927
|
-
|
|
928
|
-
if (draggingId === a.id) return 1;
|
|
929
|
-
if (draggingId === b.id) return -1;
|
|
930
|
-
return 0;
|
|
931
|
-
}).map((p) => {
|
|
932
|
-
const bp = controller.getBlueprint(p.blueprintId);
|
|
933
|
-
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
934
|
-
const isDragging = draggingId === p.id;
|
|
935
|
-
const locked = p.sectorId && controller.isSectorCompleted(p.sectorId);
|
|
936
|
-
const isConnectivityLocked = lockedPieceId === p.id;
|
|
937
|
-
selectedPieceId === p.id;
|
|
938
|
-
const isCarriedInvalid = isDragging && dragInvalid;
|
|
939
|
-
const translateX = p.x - bb.min.x;
|
|
940
|
-
const translateY = p.y - bb.min.y;
|
|
941
|
-
return /* @__PURE__ */ React.createElement("g", { key: p.id, ref: setPieceRef(p.id), transform: `translate(${translateX}, ${translateY})`, style: { cursor: locked ? "default" : clickMode ? "pointer" : "grab" }, pointerEvents: clickMode && isDragging ? "none" : "auto" }, ("shape" in bp ? bp.shape : []).map((poly, idx) => {
|
|
942
|
-
const showBorders = shouldShowBorders();
|
|
943
|
-
shouldUseSelectiveBorders(p.blueprintId);
|
|
944
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, /* @__PURE__ */ React.createElement(
|
|
945
|
-
"path",
|
|
946
|
-
{
|
|
947
|
-
d: pathD(poly),
|
|
948
|
-
fill: isConnectivityLocked ? CONFIG.color.piece.invalidFill : isCarriedInvalid ? CONFIG.color.piece.invalidFill : isDragging ? CONFIG.color.piece.draggingFill : CONFIG.color.piece.validFill,
|
|
949
|
-
opacity: isConnectivityLocked ? CONFIG.opacity.piece.invalid : isCarriedInvalid ? CONFIG.opacity.piece.invalid : isDragging ? CONFIG.opacity.piece.dragging : locked ? CONFIG.opacity.piece.locked : CONFIG.opacity.piece.normal,
|
|
950
|
-
stroke: "none",
|
|
951
|
-
onPointerDown: (e) => onPiecePointerDown(e, p)
|
|
952
|
-
}
|
|
953
|
-
), showBorders);
|
|
954
|
-
}));
|
|
955
|
-
}),
|
|
1111
|
+
/* @__PURE__ */ React.createElement(React.Fragment, null, renderSilhouettes(), renderPieces()) ,
|
|
956
1112
|
layout.sectors.map((s) => {
|
|
957
1113
|
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
958
1114
|
if (showTangramDecomposition && sectorCfg?.silhouette.primitiveDecomposition) {
|
|
@@ -960,23 +1116,32 @@ function BoardView(props) {
|
|
|
960
1116
|
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
961
1117
|
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
962
1118
|
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
963
|
-
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) =>
|
|
964
|
-
|
|
965
|
-
{
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
1119
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
1120
|
+
const primInfo = primitiveDecomposition[i];
|
|
1121
|
+
if (usePrimitiveColorsTargets && primInfo?.kind && primitiveColorIndices) {
|
|
1122
|
+
const kindToIndex = {
|
|
1123
|
+
"square": 0,
|
|
1124
|
+
"smalltriangle": 1,
|
|
1125
|
+
"parallelogram": 2,
|
|
1126
|
+
"medtriangle": 3,
|
|
1127
|
+
"largetriangle": 4
|
|
1128
|
+
};
|
|
1129
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
1130
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
1131
|
+
primitiveColorIndices[primitiveIndex];
|
|
1132
|
+
}
|
|
978
1133
|
}
|
|
979
|
-
|
|
1134
|
+
return /* @__PURE__ */ React.createElement(
|
|
1135
|
+
"path",
|
|
1136
|
+
{
|
|
1137
|
+
key: `prim-fill-${i}`,
|
|
1138
|
+
d: pathD(scaledPoly),
|
|
1139
|
+
fill: "none",
|
|
1140
|
+
opacity: 0,
|
|
1141
|
+
stroke: "none"
|
|
1142
|
+
}
|
|
1143
|
+
);
|
|
1144
|
+
}));
|
|
980
1145
|
} else {
|
|
981
1146
|
const placedPolys = placedSilBySector.get(s.id) ?? [];
|
|
982
1147
|
if (!placedPolys.length) return null;
|
|
@@ -1067,7 +1232,25 @@ function BoardView(props) {
|
|
|
1067
1232
|
const by = layout.cy + blueprintRingR * Math.sin(theta);
|
|
1068
1233
|
return renderBlueprintGlyph(bp, bx, by);
|
|
1069
1234
|
}),
|
|
1070
|
-
controller.state.endedAt && /* @__PURE__ */ React.createElement("g", { pointerEvents: "none" }, /* @__PURE__ */ React.createElement("circle", { cx: layout.cx, cy: layout.cy, r: layout.outerR - 3, fill: "none", stroke: CONFIG.color.piece.allGreenStroke, strokeWidth: CONFIG.size.stroke.allGreenStrokePx, opacity: 0 }, /* @__PURE__ */ React.createElement("animate", { attributeName: "opacity", from: "0", to: "1", dur: "160ms", fill: "freeze" }), /* @__PURE__ */ React.createElement("animate", { attributeName: "opacity", from: "1", to: "0", begin: "560ms", dur: "520ms", fill: "freeze" })))
|
|
1235
|
+
controller.state.endedAt && /* @__PURE__ */ React.createElement("g", { pointerEvents: "none" }, /* @__PURE__ */ React.createElement("circle", { cx: layout.cx, cy: layout.cy, r: layout.outerR - 3, fill: "none", stroke: CONFIG.color.piece.allGreenStroke, strokeWidth: CONFIG.size.stroke.allGreenStrokePx, opacity: 0 }, /* @__PURE__ */ React.createElement("animate", { attributeName: "opacity", from: "0", to: "1", dur: "160ms", fill: "freeze" }), /* @__PURE__ */ React.createElement("animate", { attributeName: "opacity", from: "1", to: "0", begin: "560ms", dur: "520ms", fill: "freeze" }))),
|
|
1236
|
+
showTangramDecomposition && layout.sectors.map((s) => {
|
|
1237
|
+
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
1238
|
+
if (!sectorCfg?.silhouette.primitiveDecomposition) return null;
|
|
1239
|
+
const primitiveDecomposition = sectorCfg.silhouette.primitiveDecomposition;
|
|
1240
|
+
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
1241
|
+
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
1242
|
+
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
1243
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-borders-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => /* @__PURE__ */ React.createElement(
|
|
1244
|
+
"path",
|
|
1245
|
+
{
|
|
1246
|
+
key: `prim-border-${i}`,
|
|
1247
|
+
d: pathD(scaledPoly),
|
|
1248
|
+
fill: "none",
|
|
1249
|
+
stroke: CONFIG.color.tangramDecomposition.stroke,
|
|
1250
|
+
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
1251
|
+
}
|
|
1252
|
+
)));
|
|
1253
|
+
})
|
|
1071
1254
|
);
|
|
1072
1255
|
}
|
|
1073
1256
|
|
|
@@ -2952,7 +3135,10 @@ function GameBoard(props) {
|
|
|
2952
3135
|
onPieceRemove,
|
|
2953
3136
|
onInteraction,
|
|
2954
3137
|
onTrialEnd,
|
|
2955
|
-
onControllerReady
|
|
3138
|
+
onControllerReady,
|
|
3139
|
+
usePrimitiveColorsBlueprints,
|
|
3140
|
+
usePrimitiveColorsTargets,
|
|
3141
|
+
primitiveColorIndices
|
|
2956
3142
|
} = props;
|
|
2957
3143
|
const [timeRemaining, setTimeRemaining] = React.useState(timeLimitMs > 0 ? Math.floor(timeLimitMs / 1e3) : 0);
|
|
2958
3144
|
const controller = React.useMemo(() => {
|
|
@@ -3276,7 +3462,7 @@ function GameBoard(props) {
|
|
|
3276
3462
|
justifyContent: "center",
|
|
3277
3463
|
alignItems: "center",
|
|
3278
3464
|
padding: "20px",
|
|
3279
|
-
background:
|
|
3465
|
+
background: CONFIG.color.background,
|
|
3280
3466
|
flex: "0 0 auto"
|
|
3281
3467
|
};
|
|
3282
3468
|
const headerContentStyle = {
|
|
@@ -3292,14 +3478,20 @@ function GameBoard(props) {
|
|
|
3292
3478
|
lineHeight: 1.5,
|
|
3293
3479
|
textAlign: "center"
|
|
3294
3480
|
};
|
|
3481
|
+
const scaleX = svgDimensions.width / viewBox.w;
|
|
3482
|
+
const rightEdgeOfSemicircleLogical = viewBox.w / 2 + layout.outerR;
|
|
3483
|
+
const distanceFromRightEdgeLogical = viewBox.w - rightEdgeOfSemicircleLogical;
|
|
3484
|
+
const distanceFromRightEdgePx = distanceFromRightEdgeLogical * scaleX;
|
|
3485
|
+
const charWidth = 24 * 0.6;
|
|
3486
|
+
const offsetLeft = charWidth * 5;
|
|
3295
3487
|
const timerStyle = {
|
|
3296
3488
|
position: "absolute",
|
|
3297
|
-
right:
|
|
3489
|
+
right: `${distanceFromRightEdgePx + offsetLeft}px`,
|
|
3298
3490
|
fontSize: "24px",
|
|
3299
3491
|
fontWeight: "bold",
|
|
3300
3492
|
fontFamily: "monospace",
|
|
3301
3493
|
color: "#333",
|
|
3302
|
-
|
|
3494
|
+
whiteSpace: "nowrap",
|
|
3303
3495
|
textAlign: "right"
|
|
3304
3496
|
};
|
|
3305
3497
|
const gameboardWrapperStyle = {
|
|
@@ -3344,6 +3536,9 @@ function GameBoard(props) {
|
|
|
3344
3536
|
onCenterBadgePointerDown,
|
|
3345
3537
|
showTangramDecomposition: showTangramDecomposition ?? false,
|
|
3346
3538
|
scaleS,
|
|
3539
|
+
usePrimitiveColorsBlueprints: usePrimitiveColorsBlueprints ?? false,
|
|
3540
|
+
usePrimitiveColorsTargets: usePrimitiveColorsTargets ?? false,
|
|
3541
|
+
primitiveColorIndices: primitiveColorIndices ?? [0, 1, 2, 3, 4],
|
|
3347
3542
|
...eventCallbacks
|
|
3348
3543
|
}
|
|
3349
3544
|
))));
|
|
@@ -3563,7 +3758,10 @@ function startConstructionTrial(display_element, params, _jsPsych) {
|
|
|
3563
3758
|
trialParams,
|
|
3564
3759
|
...params.instructions && { instructions: params.instructions },
|
|
3565
3760
|
...params.onInteraction && { onInteraction: params.onInteraction },
|
|
3566
|
-
...params.onTrialEnd && { onTrialEnd: params.onTrialEnd }
|
|
3761
|
+
...params.onTrialEnd && { onTrialEnd: params.onTrialEnd },
|
|
3762
|
+
...params.usePrimitiveColorsBlueprints !== void 0 && { usePrimitiveColorsBlueprints: params.usePrimitiveColorsBlueprints },
|
|
3763
|
+
...params.usePrimitiveColorsTargets !== void 0 && { usePrimitiveColorsTargets: params.usePrimitiveColorsTargets },
|
|
3764
|
+
...params.primitiveColorIndices !== void 0 && { primitiveColorIndices: params.primitiveColorIndices }
|
|
3567
3765
|
};
|
|
3568
3766
|
const root = createRoot(display_element);
|
|
3569
3767
|
root.render(React.createElement(GameBoard, gameBoardProps));
|
|
@@ -3648,6 +3846,24 @@ const info$2 = {
|
|
|
3648
3846
|
type: ParameterType.FUNCTION,
|
|
3649
3847
|
default: void 0,
|
|
3650
3848
|
description: "Callback when trial completes with full data"
|
|
3849
|
+
},
|
|
3850
|
+
/** Whether to use distinct colors for each primitive shape type in blueprints */
|
|
3851
|
+
use_primitive_colors_blueprints: {
|
|
3852
|
+
type: ParameterType.BOOL,
|
|
3853
|
+
default: false,
|
|
3854
|
+
description: "Whether each primitive shape type should have its own distinct color in the blueprint dock area"
|
|
3855
|
+
},
|
|
3856
|
+
/** Whether to use distinct colors for each primitive shape type in target tangrams */
|
|
3857
|
+
use_primitive_colors_targets: {
|
|
3858
|
+
type: ParameterType.BOOL,
|
|
3859
|
+
default: false,
|
|
3860
|
+
description: "Whether each primitive shape type should have its own distinct color in target tangram silhouettes"
|
|
3861
|
+
},
|
|
3862
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
3863
|
+
primitive_color_indices: {
|
|
3864
|
+
type: ParameterType.OBJECT,
|
|
3865
|
+
default: [0, 1, 2, 3, 4],
|
|
3866
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
3651
3867
|
}
|
|
3652
3868
|
},
|
|
3653
3869
|
data: {
|
|
@@ -3713,7 +3929,10 @@ class TangramConstructPlugin {
|
|
|
3713
3929
|
show_tangram_decomposition: trial.show_tangram_decomposition,
|
|
3714
3930
|
instructions: trial.instructions,
|
|
3715
3931
|
onInteraction: trial.onInteraction,
|
|
3716
|
-
onTrialEnd: wrappedOnTrialEnd
|
|
3932
|
+
onTrialEnd: wrappedOnTrialEnd,
|
|
3933
|
+
usePrimitiveColorsBlueprints: trial.use_primitive_colors_blueprints,
|
|
3934
|
+
usePrimitiveColorsTargets: trial.use_primitive_colors_targets,
|
|
3935
|
+
primitiveColorIndices: trial.primitive_color_indices
|
|
3717
3936
|
};
|
|
3718
3937
|
const { root, display_element: element, jsPsych } = startConstructionTrial(display_element, params, this.jsPsych);
|
|
3719
3938
|
element.__reactContext = { root, jsPsych };
|
|
@@ -3731,7 +3950,9 @@ function startPrepTrial(display_element, params, jsPsych) {
|
|
|
3731
3950
|
quickstashMacros,
|
|
3732
3951
|
primitiveOrder,
|
|
3733
3952
|
onInteraction,
|
|
3734
|
-
onTrialEnd
|
|
3953
|
+
onTrialEnd,
|
|
3954
|
+
usePrimitiveColorsBlueprints,
|
|
3955
|
+
primitiveColorIndices
|
|
3735
3956
|
} = params;
|
|
3736
3957
|
const { onInteraction: _, onTrialEnd: __, ...trialParams } = params;
|
|
3737
3958
|
const PRIMITIVE_BLUEPRINTS_ORDERED = [...PRIMITIVE_BLUEPRINTS].sort((a, b) => primitiveOrder.indexOf(a.kind) - primitiveOrder.indexOf(b.kind));
|
|
@@ -3823,7 +4044,9 @@ function startPrepTrial(display_element, params, jsPsych) {
|
|
|
3823
4044
|
...params.instructions && { instructions: params.instructions },
|
|
3824
4045
|
onControllerReady: handleControllerReady,
|
|
3825
4046
|
...onInteraction && { onInteraction },
|
|
3826
|
-
...onTrialEnd && { onTrialEnd }
|
|
4047
|
+
...onTrialEnd && { onTrialEnd },
|
|
4048
|
+
...usePrimitiveColorsBlueprints !== void 0 && { usePrimitiveColorsBlueprints },
|
|
4049
|
+
...primitiveColorIndices !== void 0 && { primitiveColorIndices }
|
|
3827
4050
|
}));
|
|
3828
4051
|
return { root, display_element, jsPsych };
|
|
3829
4052
|
}
|
|
@@ -3889,6 +4112,18 @@ const info$1 = {
|
|
|
3889
4112
|
onTrialEnd: {
|
|
3890
4113
|
type: ParameterType.FUNCTION,
|
|
3891
4114
|
default: void 0
|
|
4115
|
+
},
|
|
4116
|
+
/** Whether to use distinct colors for each primitive shape type in blueprints */
|
|
4117
|
+
use_primitive_colors_blueprints: {
|
|
4118
|
+
type: ParameterType.BOOL,
|
|
4119
|
+
default: false,
|
|
4120
|
+
description: "Whether each primitive shape type should have its own distinct color in the blueprint dock area"
|
|
4121
|
+
},
|
|
4122
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
4123
|
+
primitive_color_indices: {
|
|
4124
|
+
type: ParameterType.OBJECT,
|
|
4125
|
+
default: [0, 1, 2, 3, 4],
|
|
4126
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
3892
4127
|
}
|
|
3893
4128
|
},
|
|
3894
4129
|
data: {
|
|
@@ -3933,7 +4168,9 @@ class TangramPrepPlugin {
|
|
|
3933
4168
|
primitiveOrder: trial.primitive_order,
|
|
3934
4169
|
instructions: trial.instructions,
|
|
3935
4170
|
onInteraction: trial.onInteraction,
|
|
3936
|
-
onTrialEnd: wrappedOnTrialEnd
|
|
4171
|
+
onTrialEnd: wrappedOnTrialEnd,
|
|
4172
|
+
usePrimitiveColorsBlueprints: trial.use_primitive_colors_blueprints,
|
|
4173
|
+
primitiveColorIndices: trial.primitive_color_indices
|
|
3937
4174
|
};
|
|
3938
4175
|
const { root, display_element: element, jsPsych } = startPrepTrial(display_element, params, this.jsPsych);
|
|
3939
4176
|
element.__reactContext = { root, jsPsych };
|
|
@@ -3953,6 +4190,8 @@ function NBackView({ params }) {
|
|
|
3953
4190
|
instructions,
|
|
3954
4191
|
button_text,
|
|
3955
4192
|
duration,
|
|
4193
|
+
usePrimitiveColors,
|
|
4194
|
+
primitiveColorIndices,
|
|
3956
4195
|
onTrialEnd
|
|
3957
4196
|
} = params;
|
|
3958
4197
|
const trialStartTime = useRef(Date.now());
|
|
@@ -4008,7 +4247,12 @@ function NBackView({ params }) {
|
|
|
4008
4247
|
...data,
|
|
4009
4248
|
accuracy,
|
|
4010
4249
|
tangram_id: tangram.tangramID,
|
|
4011
|
-
is_match: isMatch
|
|
4250
|
+
is_match: isMatch,
|
|
4251
|
+
show_tangram_decomposition,
|
|
4252
|
+
use_primitive_colors: usePrimitiveColors,
|
|
4253
|
+
primitive_color_indices: primitiveColorIndices,
|
|
4254
|
+
duration,
|
|
4255
|
+
button_text
|
|
4012
4256
|
};
|
|
4013
4257
|
if (onTrialEnd) {
|
|
4014
4258
|
onTrialEnd(trialData);
|
|
@@ -4062,35 +4306,77 @@ function NBackView({ params }) {
|
|
|
4062
4306
|
if (show_tangram_decomposition) {
|
|
4063
4307
|
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
4064
4308
|
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, centerPos);
|
|
4065
|
-
return /* @__PURE__ */ React.createElement("g", { key: "sil-decomposed", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) =>
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4309
|
+
return /* @__PURE__ */ React.createElement("g", { key: "sil-decomposed", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
4310
|
+
const primInfo = primitiveDecomposition[i];
|
|
4311
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
4312
|
+
if (usePrimitiveColors && primInfo?.kind && primitiveColorIndices) {
|
|
4313
|
+
const kindToIndex = {
|
|
4314
|
+
"square": 0,
|
|
4315
|
+
"smalltriangle": 1,
|
|
4316
|
+
"parallelogram": 2,
|
|
4317
|
+
"medtriangle": 3,
|
|
4318
|
+
"largetriangle": 4
|
|
4319
|
+
};
|
|
4320
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
4321
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
4322
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
4323
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
4324
|
+
if (color) {
|
|
4325
|
+
fillColor = color;
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4080
4328
|
}
|
|
4081
|
-
|
|
4329
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: `prim-${i}` }, /* @__PURE__ */ React.createElement(
|
|
4330
|
+
"path",
|
|
4331
|
+
{
|
|
4332
|
+
d: pathD(scaledPoly),
|
|
4333
|
+
fill: fillColor,
|
|
4334
|
+
opacity: CONFIG.opacity.silhouetteMask,
|
|
4335
|
+
stroke: "none"
|
|
4336
|
+
}
|
|
4337
|
+
), /* @__PURE__ */ React.createElement(
|
|
4338
|
+
"path",
|
|
4339
|
+
{
|
|
4340
|
+
d: pathD(scaledPoly),
|
|
4341
|
+
fill: "none",
|
|
4342
|
+
stroke: CONFIG.color.tangramDecomposition.stroke,
|
|
4343
|
+
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
4344
|
+
}
|
|
4345
|
+
));
|
|
4346
|
+
}));
|
|
4082
4347
|
} else {
|
|
4083
4348
|
const placedPolys = placeSilhouetteGridAlignedAsPolys(mask, scaleS, centerPos);
|
|
4084
|
-
return /* @__PURE__ */ React.createElement("g", { key: "sil-unified", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) =>
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4349
|
+
return /* @__PURE__ */ React.createElement("g", { key: "sil-unified", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
4350
|
+
const primInfo = primitiveDecomposition[i];
|
|
4351
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
4352
|
+
if (usePrimitiveColors && primInfo?.kind && primitiveColorIndices) {
|
|
4353
|
+
const kindToIndex = {
|
|
4354
|
+
"square": 0,
|
|
4355
|
+
"smalltriangle": 1,
|
|
4356
|
+
"parallelogram": 2,
|
|
4357
|
+
"medtriangle": 3,
|
|
4358
|
+
"largetriangle": 4
|
|
4359
|
+
};
|
|
4360
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
4361
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
4362
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
4363
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
4364
|
+
if (color) {
|
|
4365
|
+
fillColor = color;
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4092
4368
|
}
|
|
4093
|
-
|
|
4369
|
+
return /* @__PURE__ */ React.createElement(
|
|
4370
|
+
"path",
|
|
4371
|
+
{
|
|
4372
|
+
key: `sil-${i}`,
|
|
4373
|
+
d: pathD(scaledPoly),
|
|
4374
|
+
fill: fillColor,
|
|
4375
|
+
opacity: CONFIG.opacity.silhouetteMask,
|
|
4376
|
+
stroke: "none"
|
|
4377
|
+
}
|
|
4378
|
+
);
|
|
4379
|
+
}));
|
|
4094
4380
|
}
|
|
4095
4381
|
};
|
|
4096
4382
|
return /* @__PURE__ */ React.createElement("div", { style: {
|
|
@@ -4099,7 +4385,7 @@ function NBackView({ params }) {
|
|
|
4099
4385
|
alignItems: "center",
|
|
4100
4386
|
justifyContent: "center",
|
|
4101
4387
|
padding: "20px",
|
|
4102
|
-
background: "#
|
|
4388
|
+
background: "#fff7e0ff"
|
|
4103
4389
|
} }, instructions && /* @__PURE__ */ React.createElement(
|
|
4104
4390
|
"div",
|
|
4105
4391
|
{
|
|
@@ -4189,6 +4475,18 @@ const info = {
|
|
|
4189
4475
|
default: 3e3,
|
|
4190
4476
|
description: "Duration in milliseconds to display tangram and accept responses"
|
|
4191
4477
|
},
|
|
4478
|
+
/** Whether to use distinct colors for each primitive shape type */
|
|
4479
|
+
use_primitive_colors: {
|
|
4480
|
+
type: ParameterType.BOOL,
|
|
4481
|
+
default: false,
|
|
4482
|
+
description: "Whether each primitive shape type should have its own distinct color in the displayed tangram"
|
|
4483
|
+
},
|
|
4484
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
4485
|
+
primitive_color_indices: {
|
|
4486
|
+
type: ParameterType.OBJECT,
|
|
4487
|
+
default: [0, 1, 2, 3, 4],
|
|
4488
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
4489
|
+
},
|
|
4192
4490
|
/** Callback fired when trial ends */
|
|
4193
4491
|
onTrialEnd: {
|
|
4194
4492
|
type: ParameterType.FUNCTION,
|
|
@@ -4255,6 +4553,8 @@ class TangramNBackPlugin {
|
|
|
4255
4553
|
instructions: trial.instructions,
|
|
4256
4554
|
button_text: trial.button_text,
|
|
4257
4555
|
duration: trial.duration,
|
|
4556
|
+
usePrimitiveColors: trial.use_primitive_colors,
|
|
4557
|
+
primitiveColorIndices: trial.primitive_color_indices,
|
|
4258
4558
|
onTrialEnd: wrappedOnTrialEnd
|
|
4259
4559
|
};
|
|
4260
4560
|
const { root, display_element: element, jsPsych } = startNBackTrial(display_element, params, this.jsPsych);
|