@adriansteffan/reactive 0.0.43 → 0.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.claude/settings.local.json +7 -1
  2. package/README.md +106 -3
  3. package/dist/{mod-D6W3wq3h.js → mod-D6DlS3ur.js} +6482 -6114
  4. package/dist/mod.d.ts +54 -2
  5. package/dist/reactive.es.js +42 -33
  6. package/dist/reactive.umd.js +38 -36
  7. package/dist/style.css +1 -1
  8. package/dist/{web-B1hJOwit.js → web-D7VcCd-t.js} +1 -1
  9. package/dist/{web-BYSmfdtR.js → web-o3I0sgwu.js} +1 -1
  10. package/package.json +1 -1
  11. package/src/components/canvasblock.tsx +112 -70
  12. package/src/components/checkdevice.tsx +15 -0
  13. package/src/components/enterfullscreen.tsx +5 -3
  14. package/src/components/exitfullscreen.tsx +4 -1
  15. package/src/components/experimentprovider.tsx +7 -2
  16. package/src/components/experimentrunner.tsx +66 -52
  17. package/src/components/microphonecheck.tsx +3 -0
  18. package/src/components/mobilefilepermission.tsx +3 -0
  19. package/src/components/plaininput.tsx +17 -0
  20. package/src/components/prolificending.tsx +3 -0
  21. package/src/components/quest.tsx +57 -0
  22. package/src/components/storeui.tsx +15 -11
  23. package/src/components/text.tsx +11 -0
  24. package/src/components/upload.tsx +56 -271
  25. package/src/mod.tsx +1 -0
  26. package/src/utils/bytecode.ts +50 -0
  27. package/src/utils/simulation.ts +268 -0
  28. package/src/utils/upload.ts +299 -0
  29. package/template/README.md +59 -0
  30. package/template/backend/src/backend.ts +1 -0
  31. package/template/package.json +2 -0
  32. package/template/simulate.ts +15 -0
  33. package/template/src/Experiment.tsx +58 -5
  34. package/template/src/main.tsx +1 -1
  35. package/template/tsconfig.json +2 -3
  36. package/tsconfig.json +1 -0
  37. package/vite.config.ts +1 -1
@@ -5,7 +5,13 @@
5
5
  "Bash(npm run:*)",
6
6
  "WebSearch",
7
7
  "WebFetch(domain:github.com)",
8
- "WebFetch(domain:surveyjs.io)"
8
+ "WebFetch(domain:surveyjs.io)",
9
+ "Read(//Users/adriansteffan/Projects/rtest/**)",
10
+ "Bash(npm link:*)",
11
+ "Bash(npx tsc:*)",
12
+ "Bash(grep:*)",
13
+ "Bash(cp:*)",
14
+ "Bash(cd:*)"
9
15
  ],
10
16
  "deny": [],
11
17
  "ask": []
package/README.md CHANGED
@@ -42,6 +42,105 @@ Premade components available so far:
42
42
 
43
43
 
44
44
 
45
+ ## Simulation
46
+
47
+ Reactive includes a simulation system that lets you run experiments headlessly, generating synthetic data from simulated participants. This is useful for some basic computational modeling, verifying data pipelines, and sample size planning.
48
+
49
+ ### Quick start
50
+
51
+ Define your participant generator in `Experiment.tsx`:
52
+
53
+ ```tsx
54
+ export const simulationConfig = {
55
+ participants: {
56
+ generator: (i) => ({ id: i, nickname: `participant_${i}` }),
57
+ count: 10,
58
+ },
59
+ };
60
+ ```
61
+
62
+ Run the simulation:
63
+
64
+ ```
65
+ npm run simulate
66
+ ```
67
+
68
+ This starts the backend, simulates all participants through the experiment, uploads data via the real backend (just like real participants would), and shuts down.
69
+
70
+ ### How it works
71
+
72
+ Each built-in component (Text, Quest, CanvasBlock, Upload, etc.) registers a **simulate function** and **default simulators**. The simulate function contains the trial logic. The simulators are replaceable decision functions that model participant behavior at each interaction point.
73
+
74
+ For example, Quest's simulate function iterates through questions and calls `simulators.answerQuestion()` for each one. The default `answerQuestion` picks random valid answers. You can override it to model specific participant behavior.
75
+
76
+ ### Overriding simulators on a trial
77
+
78
+ Add a `simulators` property to any timeline item to override specific decision functions:
79
+
80
+ ```tsx
81
+ {
82
+ type: 'PlainInput',
83
+ props: { content: <p>What is your name?</p> },
84
+ simulators: {
85
+ respond: (_trialProps, participant) => ({
86
+ value: participant.nickname,
87
+ participantState: participant,
88
+ }),
89
+ },
90
+ }
91
+ ```
92
+
93
+ The override is merged with the registered defaults — you only need to specify the decision functions you want to change.
94
+
95
+ ### Custom components
96
+
97
+ Register a simulation for your custom components using `registerSimulation`:
98
+
99
+ ```tsx
100
+ registerSimulation('MyTrial',
101
+ // Simulate function: uses shared trial logic + decision functions
102
+ (trialProps, experimentState, simulators, participant) => {
103
+ const choice = simulators.decide(trialProps, participant);
104
+ return { responseData: { choice: choice.value }, participantState: choice.participantState };
105
+ },
106
+ // Default simulators: one per decision point
107
+ {
108
+ decide: (_trialProps, participant) => ({
109
+ value: 'default_choice',
110
+ participantState: participant,
111
+ }),
112
+ },
113
+ );
114
+ ```
115
+
116
+ The simulate function orchestrates the trial logic. The decision functions are the parts where a human would interact — these are what users override to model different participant behaviors.
117
+
118
+ ### Hybrid mode
119
+
120
+ During development, you can auto-advance simulated trials while manually interacting with others. Add `?hybridSimulation=true` to the URL during development:
121
+
122
+ ```
123
+ http://localhost:5173?hybridSimulation=true
124
+ ```
125
+
126
+ Trials with `simulators` or `simulate: true` defined on them will auto-advance. Trials without them render normally for human interaction.
127
+
128
+ Hybrid mode is enabled by default during development. For production, set `VITE_DISABLE_HYBRID_SIMULATION=true` to disable it regardless of URL parameters.
129
+
130
+ ### Built-in simulator decision functions
131
+
132
+ | Component | Decision functions | Default behavior |
133
+ |---|---|---|
134
+ | Text | `respond` | Click button, random reaction time |
135
+ | PlainInput | `respond` | Returns `'simulated_input'` |
136
+ | Quest | `answerQuestion` | Random valid answer per question type |
137
+ | CanvasBlock | `respondToSlide` | Random key from `allowedKeys`, random RT |
138
+ | Upload | *(none)* | Builds CSVs and POSTs to backend |
139
+ | StoreUI | *(none)* | Uses field default values |
140
+ | CheckDevice | *(none)* | Returns simulated device info |
141
+ | EnterFullscreen, ExitFullscreen, MicrophoneCheck, ProlificEnding, RequestFilePermission | *(none)* | No-op, advances immediately |
142
+
143
+
45
144
  ## Development
46
145
 
47
146
 
@@ -56,11 +155,15 @@ Then create a global link (only needs to run once during setup);
56
155
  npm link
57
156
  ```
58
157
 
59
- Then set up a local testing project:
158
+ Then set up a local testing project (run from the parent directory so it's created as a sibling):
60
159
 
61
160
  ```
62
- npx @adriansteffan/reactive
63
- npm uninstall @adriansteffan/reactive && npm link @adriansteffan/reactive
161
+ cd ..
162
+ node reactive/bin/setup.js
163
+ cd <project-name>
164
+ npm pkg set dependencies.@adriansteffan/reactive="*"
165
+ npm i && npm i --prefix backend
166
+ npm link @adriansteffan/reactive
64
167
  ```
65
168
 
66
169