6.1.1 Core
On this page:
defstep
defstep/  study
defstudy
put/  identity
require
button
with-bot
6.1.1.1 Views
defview
~current-view-uri
6.1.1.2 CSS
add-css
add-css-resource
6.1.1.3 Step Timings
get-step-timings
6.1.1.4 Logging
log-conscript-debug
log-conscript-info
log-conscript-warning
log-conscript-error
log-conscript-fatal
6.1.1.5 Boxes
defbox
6.1.1.5.1 Additional box functions
define-var-box

6.1.1 Core🔗

 (require conscript/base) package: conscript

The bindings provided by this module are also provided by #lang conscript.

syntax

(defstep (step-id) step-body)

Defines a study step. The step-body must be an expression that evaluates to a study page — usually md or html.

syntax

(defstep/study step-id #:study child-study-expr
               maybe-require-bindings
               maybe-provide-bindings)
 
maybe-require-bindings = 
  | #:require-bindings ([child-id parent-id] ...)
     
maybe-provide-bindings = 
  | #:provide-bindings ([parent-id child-id] ...)
Defines a study step named step-id that runs child-study-expr when reached.

The child-study-expr can be either a study value or a procedure that returns a study. When it is a procedure, it is called when the step is reached, allowing the study structure to depend on runtime values (such as participant responses from earlier steps). This is essential for dynamically generated studies using for/study.

The step step-id is said to be part of the "parent" study, of which child-study-expr becomes a "child" study.

The #:require-bindings and #:provide-bindings arguments are deprecated and included for compatibility. Use defvar* and defvar*/instance to share study variables between parent and child studies.

syntax

(defstudy study-id
          maybe-wrapper
          maybe-requires
          maybe-provides
          transition-clause ...+)
 
maybe-wrapper = 
  | #:wrapper wrapper-expr
     
maybe-requires = 
  | #:requires (value-id-sym ...)
     
maybe-provides = 
  | #:provides (value-id-sym ...)
     
transition-clause = [step --> transition ... maybe-lambda]
     
transition = --> step
  | --> {step-id step}
     
maybe-lambda = 
  | --> ,(lambda () transition-expr)
     
transition-expr = done
  | (goto step)
  | '(fail _)
  | 'step-id
  | expr
Defines a study in terms of steps joined by transitions. Each step should be a step defined with defstep or defstep/study.

If #:wrapper is supplied, wrapper-expr must produce a function that takes a study as its only argument and returns a study. (See, for example, add-css and add-css-resource.)

An unquoted lambda at the end of a transition-clause can include arbitrary expr, but this but must evaluate to one of the other possible transition-exprs:

(defstudy college-try
  [attempt --> ,(lambda () (if success
                               (goto good-ending)
                               (goto bad-ending)))]
  [bad-ending --> ,(lambda () '(fail 0))]
  [good-ending --> good-ending])

For any “final” step (that is, a step that, once reached, should prevent the participant from taking any further step) you need to include a separate transition-clause with the step at both ends, or a maybe-lambda expression that returns done:

(defstudy mystudy
  [intro --> question --> final]
  [final --> final])
; OR:
(defstudy mystudy
  [intro --> question --> final --> ,(lambda () done)])

You can reuse the same step function as separate steps with the --> {step-id step} form of transition:

(defstudy repeating-step-study
  [intro --> {message1 message}
         --> {message2 message}
         --> final]
  [final --> final])

The use of #:requires and #:provides arguments is deprecated and included for compatibility. Use defvar* and defvar*/instance to share study variables between parent/child studies.

procedure

(put/identity key value)  void?

  key : symbol?
  value : any/c
If the user enrolled in the study via an identity server, stores value under key within their enrollment on that server; if the user did not enroll through an identity server, it stores the value under key directly on the Congame server.

The point of enrolling via an identity server is to prevent the study author from connecting a participant’s answers with their identity — but there are cases where a well-designed study will still need to attach some data to their identity. For example, at the end of a study you might call (put/identity 'payment-due pay-amount) so that, despite not knowing the participant’s answers, you know how much you need to pay them.

syntax

(require require-spec ...)

Conscript provides its own binding for require that only allows modules from the whitelist below. This prevents unsafe code from running on Congame servers.

procedure

(button [action-proc]    
  label    
  [#:id id    
  #:to-step-id to-step-id    
  #:up-target up-target    
  #:up-transition up-transition])  xexpr?
  action-proc : (-> any/c) = void
  label : string?
  id : string? = ""
  to-step-id : (or/c identifier? #f) = #f
  up-target : string? = ".step"
  up-transition : string? = "none"
Returns a representation of an HTML <a> element styled as a button that navigates to the next step in the study when clicked.

If action-proc is provided, it will be called when the button is clicked, just before the next transition to the next step in the study is run.

The href attribute is dynamically set to the URL of a continuation that first calls action with no arguments, then returns the page provided by to-step-id (or that provided by the next step in the study if to-step-id is #f).

If #:id is provided, it sets the value of the data-widget-id attribute for the element.

syntax

(with-bot step-expr bot-expr)

Wraps step-expr so that its default bot is bot-expr.

(defstep (hello)
  (button "Continue..."))
(defstudy s
  [[hello (with-bot hello bot:continuer)] --> ,(lambda () done)])
6.1.1.1 Views🔗

A view is an additional set of content/functionality that can be associated with a step. Views can be used to provide additional instructions for a step, or to give admins a customized display of study outcomes.

The content of a view is provided by a view handler, which is a function which takes a single request argument (which can be inspected if the view needs to vary depending on the HTTP request) and returns a response. This function will be called by the Congame server when the view is accessed.

syntax

(defview (id req) body ...)

 
  req : request?
Defines a view handler. When the view is accessed, Congame will call the view handler, passing the HTTP request as the req argument.

As with defstep, the body of a defview expression should evaluate to a study page, usually using md or html. The defview form takes care of converting the page to an HTTP response.

Example:

(defview (instructions-popup _request)
  @md{#Instructions
 
      More detail.....})

procedure

(~current-view-uri)  string?

Returns the URI of the view handler page associated with the current step. Intended for use inside defstep.

6.1.1.2 CSS🔗

procedure

(add-css css-string)  (-> study? study?)

  css-string : string?
Returns a procedure, suitable for use with the #:wrapper argument of defstudy, which adds the custom CSS contained in css-string to each step in the study.

procedure

(add-css-resource css-res)  (-> study? study?)

  css-res : resource?
Returns a procedure, suitable for use with the #:wrapper argument of defstudy, which adds the custom CSS resource css-res to each step in the study.

6.1.1.3 Step Timings🔗

Congame automatically tracks timing information for each step in a study. This timing data measures how long participants spend on each page, including both total elapsed time and the time the page was actively in focus (visible to the participant).

procedure

(get-step-timings)

  (cons/c (or/c #f number?) (or/c #f number?))
Returns a pair (cons total-time focus-time) containing timing information for the current step, where both values are measured in milliseconds.

The total-time is the total elapsed time since the participant loaded the page, including time spent with the page in the background (for example, if they switched to another browser tab).

The focus-time is the total time the page was actually visible and in focus. This excludes time when the page was in a background tab or the browser window was minimized.

Both values will be #f if no timing data is available (for example, on the very first page load of a study).

See How to record time spent on a task for an example showing how to use get-step-timings.

6.1.1.4 Logging🔗

syntax

(log-conscript-debug string-expr)

(log-conscript-debug format-string-expr v ...)

syntax

(log-conscript-info string-expr)

(log-conscript-info format-string-expr v ...)

syntax

(log-conscript-warning string-expr)

(log-conscript-warning format-string-expr v ...)

syntax

(log-conscript-error string-expr)

(log-conscript-error format-string-expr v ...)

syntax

(log-conscript-fatal string-expr)

(log-conscript-fatal format-string-expr v ...)

See Logging in the Racket Reference for more information on logging.

Logs an event with the Conscript logger, evaluating string-expr or (format format-string-expr v ...). These forms are listed above in order of severity.

Logging functions are useful for debugging: for example, when you want to capture and surface state information in the middle of a process, or extra context about possible causes of a problem.

Logged events are printed on the console (stderr) of a running Congame server.

Note that since the result of a log-conscript-level form is #<void>, you can’t use it directly inside a study step. Instead, wrap it in a begin expression that returns an empty string:

(defstep (age-name-survey)
  @md{
    # Survey
 
    @form{
      What is your first name? @(set! first-name (input-text))
 
      @(begin
        (log-conscript-info "Hello")
        "")
      @submit-button
  }})

6.1.1.5 Boxes🔗

syntax

(defbox id)

Defines two functions, get-id (which takes no arguments and returns the value of id) and set!-id (which takes one argument and updates the value of id).

Examples:
> (define flux 81)
> (defbox flux)
> (get-flux)

81

> (set!-flux "new")
> (get-flux)

"new"

> flux

"new"

6.1.1.5.1 Additional box functions🔗

 (require conscript/var-box) package: conscript

The bindings from this module are also provided by conscript/base.

syntax

(define-var-box id var)

Binds id to a function that can take zero arguments or one argument. If given no arguments, the function returns the current value of var (which must already be defined elsewhere); if given a single argument, the function set!s the value of var to that value.

The function id can be passed to other functions, allowing them to access or update a local variable.

Examples:
> (define flux #f)
> (define-var-box get-or-set flux)
> (get-or-set)

#f

> (get-or-set 'foo)
> (get-or-set)

'foo

> flux

'foo