@citolab/pci-3d-blocks 0.0.0-stage → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -2
- package/blocks.svg +62 -0
- package/dist/authoring.json +102 -0
- package/dist/index.js +6 -0
- package/dist/sbom.cdx.json +201 -0
- package/dist/tao-pci-blocks_1.2.0.zip +0 -0
- package/example.png +0 -0
- package/package.json +83 -4
package/README.md
CHANGED
|
@@ -1,3 +1,89 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @citolab/pci-3d-blocks
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A QTI 3 Portable Custom Interaction (PCI) in which the candidate builds with toy bricks on a baseplate, for example to
|
|
4
|
+
recreate a building shown in the item from its front, side and top view. Made with
|
|
5
|
+
[tspci](https://github.com/Citolab/tspci).
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<img src="https://raw.githubusercontent.com/Citolab/tspci-examples/main/tspci-3d-blocks/example.png" alt="Bricks on a baseplate, with the label front" width="320">
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
- **Build**: click a cell of the baseplate to place a brick, click the top of a brick to stack one on it. A brick
|
|
14
|
+
shows where it will land before you click.
|
|
15
|
+
- **Remove**: click the side of a brick to take it away (a brick in the top layer goes with any click); the brick that
|
|
16
|
+
would go is shown in see-through red first.
|
|
17
|
+
- **Look around**: drag to turn the baseplate. The arrow and its label mark the front, so the candidate can tell
|
|
18
|
+
front, side and top apart.
|
|
19
|
+
- **Limits**: bricks stay on the plate, and a stack is at most as high as the grid is wide (5 × 5 × 5 by default).
|
|
20
|
+
- **Colours**: a brick's colour follows from where it stands, so a build looks the same when the candidate comes back
|
|
21
|
+
to it. Colours do not count for the answer.
|
|
22
|
+
- **Delivery**: the build is saved as the item's state and restored. In review (`status: "solution"`) the PCI shows the
|
|
23
|
+
correct response when the delivery system passes it.
|
|
24
|
+
|
|
25
|
+
## What can be configured
|
|
26
|
+
|
|
27
|
+
Every setting is a `data-` attribute of the interaction, as text. `dist/authoring.json` describes them for authoring
|
|
28
|
+
systems; TAO shows them as a form, with a dropdown for the colour mode and colour pickers.
|
|
29
|
+
|
|
30
|
+
| setting | attribute | default | what |
|
|
31
|
+
| -------------------- | ----------------------- | ------------------------------------------------------ | --------------------------------------------------------- |
|
|
32
|
+
| Grid size | `data-grid-divisions` | `5` | cells per side of the baseplate (1 to 6); also the maximum height |
|
|
33
|
+
| Brick size | `data-cube-pixel-size` | `60` | size of a brick (at least 10) |
|
|
34
|
+
| Label at the front | `data-front-label` | `front` | the text under the arrow, for the item's language |
|
|
35
|
+
| Brick colours | `data-brick-color-mode` | `mixed` | `mixed`: the bricks get the colours of the list; `single`: all bricks get the first colour |
|
|
36
|
+
| Colours | `data-brick-colors` | `#c91a09, #f2cd37, #0055bf, #237841, #fe8a18, #5aa5dc` | a list of CSS colours |
|
|
37
|
+
| Baseplate colour | `data-baseplate-color` | `#4b9f4a` | a CSS colour |
|
|
38
|
+
| Width, height | `data-width`, `data-height` | `400`, `400` | size of the interaction in pixels (at least 200) |
|
|
39
|
+
|
|
40
|
+
## Scoring
|
|
41
|
+
|
|
42
|
+
The PCI is made for `match_correct` (`authoring.json`: `"score": ["MATCH_CORRECT", "NONE"]`).
|
|
43
|
+
|
|
44
|
+
**The response** is a string (`cardinality="single" base-type="string"`): the three views of the build, as JSON. Per
|
|
45
|
+
view, every cell of the grid is `found: true` when a brick is seen there.
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{ "xPlane": [{ "y": 0, "z": 0, "found": true }, …], "yPlane": [{ "x": 0, "z": 0, "found": false }, …], "zPlane": [{ "x": 0, "y": 0, "found": true }, …] }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- **What counts**: only the views. Two builds that look the same from the front, the side and the top give the same
|
|
52
|
+
response, even when bricks inside differ, so there is one correct response for all of them.
|
|
53
|
+
- **What does not count**: colours, the order of building, and how the candidate turned the plate.
|
|
54
|
+
- **Setting the correct response**: answer the PCI. In TAO switch the interaction to *Response* and build the answer;
|
|
55
|
+
in qti-construction or the PCI showcase, build it and take it as the correct response. A string comparison then
|
|
56
|
+
scores it: 1 when the views match, otherwise 0.
|
|
57
|
+
- The views depend on the grid size: change the grid size and set the correct response again.
|
|
58
|
+
- **No response**: until the candidate places a brick, `getResponse()` reports nothing.
|
|
59
|
+
- `NONE`: use the PCI without scoring, for instance as a tool or for a human rater.
|
|
60
|
+
|
|
61
|
+
## Using it
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npm install @citolab/pci-3d-blocks
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| file | what |
|
|
68
|
+
| ------------------------------------ | ------------------------------------------------------------------------- |
|
|
69
|
+
| `dist/index.js` | the PCI (AMD module, everything bundled: the package has no dependencies) |
|
|
70
|
+
| `dist/authoring.json` | settings, response and scoring, for authoring systems |
|
|
71
|
+
| `dist/sbom.cdx.json` | CycloneDX SBOM of the bundle |
|
|
72
|
+
| `dist/tao-pci-blocks_<version>.zip` | the PCI for TAO: Settings → Portable Custom Interactions → Add |
|
|
73
|
+
| `blocks.svg`, `example.png` | icon and screenshot |
|
|
74
|
+
|
|
75
|
+
In a QTI 3 item, with `index.js` at `resources/pci/index.js` of the package:
|
|
76
|
+
|
|
77
|
+
```xml
|
|
78
|
+
<qti-response-declaration identifier="RESPONSE" cardinality="single" base-type="string"/>
|
|
79
|
+
…
|
|
80
|
+
<qti-portable-custom-interaction response-identifier="RESPONSE" module="pci" custom-interaction-type-identifier="blocks"
|
|
81
|
+
data-grid-divisions="4" data-brick-color-mode="single">
|
|
82
|
+
<qti-interaction-modules>
|
|
83
|
+
<qti-interaction-module id="pci" primary-path="../resources/pci/index"></qti-interaction-module>
|
|
84
|
+
</qti-interaction-modules>
|
|
85
|
+
<qti-interaction-markup></qti-interaction-markup>
|
|
86
|
+
</qti-portable-custom-interaction>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Source and the other examples: [Citolab/tspci-examples](https://github.com/Citolab/tspci-examples).
|
package/blocks.svg
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
|
|
2
|
+
<defs>
|
|
3
|
+
<clipPath id="a">
|
|
4
|
+
<path d="M4.038,12.935V4.517l6.629-2.569,0,8.333Z" transform="translate(-4.038 -1.948)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" />
|
|
5
|
+
</clipPath>
|
|
6
|
+
<clipPath id="c">
|
|
7
|
+
<path d="M3.767,12.372V4.518L10.4,1.949l-.231,7.856Z" transform="translate(-3.767 -1.949)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" />
|
|
8
|
+
</clipPath>
|
|
9
|
+
</defs>
|
|
10
|
+
<g transform="translate(-8 -8)">
|
|
11
|
+
<rect width="32" height="32" transform="translate(8 8)" fill="rgba(255,0,0,0)" />
|
|
12
|
+
<g transform="translate(2.939 4.939)">
|
|
13
|
+
<rect width="32" height="32" transform="translate(5.061 3.061)" fill="rgba(255,0,0,0)" />
|
|
14
|
+
<g transform="translate(-0.553 -0.501)">
|
|
15
|
+
<g transform="translate(8.42 7.444)">
|
|
16
|
+
<path d="M8.738,10.415l6.634-2.654,6.634,2.654-6.634,2.654Z" transform="translate(-8.407 -7.431)" fill="none" stroke="#000" stroke-linejoin="round" stroke-width="0.5" />
|
|
17
|
+
<path d="M8.518,10.194a.331.331,0,0,1,.112-.073l6.634-2.653a.331.331,0,0,1,.246,0l6.634,2.653a.331.331,0,0,1,0,.616l-6.635,2.655a.331.331,0,0,1-.246,0L8.628,10.736a.331.331,0,0,1-.112-.542Zm6.865-2.061-5.737,2.3,5.737,2.3,5.737-2.3Z" transform="translate(-8.42 -7.444)" fill="none" />
|
|
18
|
+
<path d="M15.1,20.917V12.958L21.735,10.3v7.96Z" transform="translate(-8.137 -7.323)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" />
|
|
19
|
+
<path d="M21.978,18.511a.33.33,0,0,1-.112.073l-6.634,2.654a.331.331,0,0,1-.454-.307V12.97a.331.331,0,0,1,.208-.307l6.634-2.654a.331.331,0,0,1,.454.307v7.96a.331.331,0,0,1-.1.235ZM15.444,20.44l5.969-2.387V10.809L15.447,13.2Z" transform="translate(-8.151 -7.337)" fill="none" />
|
|
20
|
+
<path d="M15.37,20.915v-7.96L8.736,10.3v7.96Z" transform="translate(-8.407 -7.323)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" />
|
|
21
|
+
<path d="M8.517,18.511a.331.331,0,0,1-.1-.233v-7.96a.331.331,0,0,1,.454-.307l6.634,2.654a.331.331,0,0,1,.208.306v7.96a.331.331,0,0,1-.454.307L8.628,18.584A.331.331,0,0,1,8.517,18.511Zm.566-7.7,0,7.238L15.05,20.44V13.2Z" transform="translate(-8.42 -7.337)" fill="none" />
|
|
22
|
+
</g>
|
|
23
|
+
<g transform="translate(8.42 15.401)">
|
|
24
|
+
<path d="M8.518,17.827a.331.331,0,0,1,.112-.073L15.263,15.1a.331.331,0,0,1,.246,0l6.634,2.653a.331.331,0,0,1,0,.616l-6.634,2.654a.331.331,0,0,1-.246,0L8.628,18.369a.331.331,0,0,1-.112-.542Zm6.865-2.061-5.737,2.3,5.737,2.3,5.737-2.3Z" transform="translate(-8.42 -15.077)" fill="none" />
|
|
25
|
+
<path d="M21.978,26.144a.33.33,0,0,1-.112.073l-6.634,2.654a.331.331,0,0,1-.454-.307V20.6a.331.331,0,0,1,.208-.307l6.634-2.654a.331.331,0,0,1,.454.307v7.96a.331.331,0,0,1-.1.235Zm-6.533,1.928,5.969-2.387V18.442l-5.964,2.391Z" transform="translate(-8.151 -14.97)" fill="none" />
|
|
26
|
+
<path d="M15.37,28.548v-7.96L8.736,17.934v7.96Z" transform="translate(-8.407 -14.956)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" />
|
|
27
|
+
<path d="M8.517,26.144a.331.331,0,0,1-.1-.233V17.95a.331.331,0,0,1,.454-.307L15.508,20.3a.331.331,0,0,1,.208.306v7.96a.331.331,0,0,1-.454.307L8.628,26.217a.331.331,0,0,1-.112-.073Zm.566-7.7,0,7.238,5.964,2.391V20.83Z" transform="translate(-8.42 -14.97)" fill="none" />
|
|
28
|
+
</g>
|
|
29
|
+
<g transform="translate(15.05 10.52)">
|
|
30
|
+
<path d="M15.1,20.593l6.634-2.654,6.634,2.654-6.634,2.654Z" transform="translate(-14.768 -10.075)" fill="none" stroke="#000" stroke-linejoin="round" stroke-width="0.5" />
|
|
31
|
+
<path d="M14.879,20.372a.331.331,0,0,1,.112-.073l6.634-2.653a.331.331,0,0,1,.246,0L28.5,20.3a.331.331,0,0,1,0,.616L21.87,23.569a.331.331,0,0,1-.246,0L14.99,20.914a.331.331,0,0,1-.112-.542Zm6.865-2.061-5.737,2.3,5.737,2.3,5.737-2.3Z" transform="translate(-14.781 -10.089)" fill="none" />
|
|
32
|
+
<path d="M28.339,28.689a.33.33,0,0,1-.112.073l-6.634,2.654a.331.331,0,0,1-.454-.307v-7.96a.331.331,0,0,1,.208-.307l6.634-2.654a.331.331,0,0,1,.454.307v7.96A.331.331,0,0,1,28.339,28.689Zm-6.533,1.928,5.969-2.387V20.987l-5.964,2.391Z" transform="translate(-14.512 -9.981)" fill="none" />
|
|
33
|
+
<path d="M21.731,31.093v-7.96L15.1,20.479v7.96Z" transform="translate(-14.768 -9.968)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" />
|
|
34
|
+
<path d="M14.878,28.689a.331.331,0,0,1-.1-.233V20.5a.331.331,0,0,1,.454-.307l6.634,2.654a.331.331,0,0,1,.208.306v7.96a.331.331,0,0,1-.454.307l-6.634-2.654a.331.331,0,0,1-.112-.073Zm.566-7.7,0,7.238,5.964,2.391V23.375Z" transform="translate(-14.781 -9.981)" fill="none" />
|
|
35
|
+
<g transform="translate(6.916 10.608)" clip-path="url(#a)">
|
|
36
|
+
<g transform="translate(-13.618 -1.987)">
|
|
37
|
+
<path d="M-9.027,14.929-3.259,4.36Zm.566,2.115L-1.246,3.821Zm.567,2.114L.768,3.282Zm1.482.428L2.78,2.742Zm2.014-.54L4.8,2.2Zm2.014-.54L6.81,1.662Zm2.014-.54L8.823,1.122Zm2.014-.54L10.837.582Zm2.014-.54L12.851.042Zm2.014-.54L14.485.2Zm2.014-.54,7.366-13.5Zm2.014-.54L15.617,4.423Zm2.014-.54,4.472-8.191Z" transform="translate(9.027 -0.042)" fill="none" stroke="#000" stroke-width="0.5" />
|
|
38
|
+
</g>
|
|
39
|
+
</g>
|
|
40
|
+
<g transform="translate(13.777 7.502)" clip-path="url(#a)">
|
|
41
|
+
<g transform="translate(-13.618 -1.987)">
|
|
42
|
+
<path d="M-9.027,14.929-3.259,4.36Zm.566,2.115L-1.246,3.821Zm.567,2.114L.768,3.282Zm1.482.428L2.78,2.742Zm2.014-.54L4.8,2.2Zm2.014-.54L6.81,1.662Zm2.014-.54L8.823,1.122Zm2.014-.54L10.837.582Zm2.014-.54L12.851.042Zm2.014-.54L14.485.2Zm2.014-.54,7.366-13.5Zm2.014-.54L15.617,4.423Zm2.014-.54,4.472-8.191Z" transform="translate(9.027 -0.042)" fill="none" stroke="#000" stroke-width="0.5" />
|
|
43
|
+
</g>
|
|
44
|
+
</g>
|
|
45
|
+
<g transform="translate(0.515 0)" clip-path="url(#c)">
|
|
46
|
+
<g transform="translate(-13.617 -1.988)">
|
|
47
|
+
<path d="M-9.3,14.929-3.529,4.36Zm.566,2.115L-1.516,3.821Zm.567,2.114L.5,3.282Zm1.482.428L2.51,2.742Zm2.014-.54L4.526,2.2Zm2.014-.54L6.54,1.662Zm2.014-.54L8.553,1.122Zm2.014-.54L10.567.582Zm2.014-.54L12.581.042Zm2.014-.54L14.215.2Zm2.014-.54,7.366-13.5Zm2.014-.54L15.347,4.423Zm2.014-.54,4.472-8.191Z" transform="translate(9.297 -0.042)" fill="none" stroke="#000" stroke-width="0.5" />
|
|
48
|
+
</g>
|
|
49
|
+
</g>
|
|
50
|
+
</g>
|
|
51
|
+
<g transform="translate(21.682 15.401)">
|
|
52
|
+
<path d="M21.461,18.048l6.634-2.654,6.634,2.654L28.095,20.7Z" transform="translate(-21.13 -15.064)" fill="none" stroke="#000" stroke-linejoin="round" stroke-width="0.5" />
|
|
53
|
+
<path d="M21.241,17.827a.331.331,0,0,1,.112-.073L27.986,15.1a.331.331,0,0,1,.246,0l6.634,2.653a.331.331,0,0,1,0,.616l-6.634,2.654a.331.331,0,0,1-.246,0l-6.634-2.655a.331.331,0,0,1-.112-.542Zm6.865-2.061-5.737,2.3,5.737,2.3,5.737-2.3Z" transform="translate(-21.143 -15.077)" fill="none" />
|
|
54
|
+
<path d="M27.824,28.551v-7.96l6.634-2.654V25.9Z" transform="translate(-20.86 -14.956)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.5" />
|
|
55
|
+
<path d="M34.7,26.144a.33.33,0,0,1-.112.073l-6.634,2.654a.331.331,0,0,1-.454-.307V20.6a.331.331,0,0,1,.208-.307l6.634-2.654a.331.331,0,0,1,.454.307v7.96a.331.331,0,0,1-.1.235Zm-6.533,1.928,5.969-2.387V18.442l-5.964,2.391Z" transform="translate(-20.874 -14.97)" fill="none" />
|
|
56
|
+
<path d="M21.24,26.144a.331.331,0,0,1-.1-.233V17.95a.331.331,0,0,1,.454-.307L28.231,20.3a.331.331,0,0,1,.208.306v7.96a.331.331,0,0,1-.454.307l-6.634-2.654A.331.331,0,0,1,21.24,26.144Zm.566-7.7,0,7.238,5.964,2.391V20.83Z" transform="translate(-21.143 -14.97)" fill="none" />
|
|
57
|
+
</g>
|
|
58
|
+
<path d="M8.7,26.145V10.226l6.676-2.653,6.634,2.654v7.96l6.634-2.654,6.906,2.652v7.96L22.013,31.774Z" transform="translate(0.012 0.005)" fill="none" stroke="#000" stroke-linejoin="round" stroke-width="1.5" />
|
|
59
|
+
</g>
|
|
60
|
+
</g>
|
|
61
|
+
</g>
|
|
62
|
+
</svg>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"descriptorVersion": "0",
|
|
3
|
+
"typeIdentifier": "blocks",
|
|
4
|
+
"version": "1.2.0",
|
|
5
|
+
"label": "3d blocks",
|
|
6
|
+
"properties": {
|
|
7
|
+
"gridDivisions": {
|
|
8
|
+
"editor": "integer",
|
|
9
|
+
"default": "5",
|
|
10
|
+
"min": 1,
|
|
11
|
+
"max": 6,
|
|
12
|
+
"label": {
|
|
13
|
+
"en": "Grid size (cells per side)",
|
|
14
|
+
"nl": "Rastergrootte (vakken per zijde)"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"cubePixelSize": {
|
|
18
|
+
"editor": "integer",
|
|
19
|
+
"default": "60",
|
|
20
|
+
"min": 10,
|
|
21
|
+
"label": {
|
|
22
|
+
"en": "Brick size",
|
|
23
|
+
"nl": "Grootte van een blok"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"frontLabel": {
|
|
27
|
+
"editor": "text",
|
|
28
|
+
"default": "front",
|
|
29
|
+
"label": {
|
|
30
|
+
"en": "Label at the front",
|
|
31
|
+
"nl": "Tekst bij de voorkant"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"brickColorMode": {
|
|
35
|
+
"editor": "enum",
|
|
36
|
+
"default": "mixed",
|
|
37
|
+
"options": [
|
|
38
|
+
{
|
|
39
|
+
"value": "mixed",
|
|
40
|
+
"label": {
|
|
41
|
+
"en": "Multiple colours",
|
|
42
|
+
"nl": "Meerdere kleuren"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"value": "single",
|
|
47
|
+
"label": {
|
|
48
|
+
"en": "One colour",
|
|
49
|
+
"nl": "Eén kleur"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"label": {
|
|
54
|
+
"en": "Brick colours",
|
|
55
|
+
"nl": "Kleuren van de blokken"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"brickColors": {
|
|
59
|
+
"editor": "colorList",
|
|
60
|
+
"default": "#c91a09, #f2cd37, #0055bf, #237841, #fe8a18, #5aa5dc",
|
|
61
|
+
"label": {
|
|
62
|
+
"en": "Colours (one colour: the first)",
|
|
63
|
+
"nl": "Kleuren (één kleur: de eerste)"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"baseplateColor": {
|
|
67
|
+
"editor": "color",
|
|
68
|
+
"default": "#4b9f4a",
|
|
69
|
+
"label": {
|
|
70
|
+
"en": "Baseplate colour",
|
|
71
|
+
"nl": "Kleur van de bouwplaat"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"width": {
|
|
75
|
+
"editor": "integer",
|
|
76
|
+
"default": "400",
|
|
77
|
+
"min": 200,
|
|
78
|
+
"label": {
|
|
79
|
+
"en": "Width (px)",
|
|
80
|
+
"nl": "Breedte (px)"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"height": {
|
|
84
|
+
"editor": "integer",
|
|
85
|
+
"default": "400",
|
|
86
|
+
"min": 200,
|
|
87
|
+
"label": {
|
|
88
|
+
"en": "Height (px)",
|
|
89
|
+
"nl": "Hoogte (px)"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"markup": {},
|
|
94
|
+
"response": {
|
|
95
|
+
"cardinality": "single",
|
|
96
|
+
"baseType": "string"
|
|
97
|
+
},
|
|
98
|
+
"score": [
|
|
99
|
+
"MATCH_CORRECT",
|
|
100
|
+
"NONE"
|
|
101
|
+
]
|
|
102
|
+
}
|