{
  "user_guide_file": "Template App Guide.pptx",
  "app_name": "Hand Flop Game",
  "app_version": "1_1",
  "app_id": "065",
  "version_id": "06511",
  "validated_version_range": [
    "3.20.1",
    "4.1.0"
  ],
  "app_description": "Rotate the wrist so the cued node is on top. Mount one node on the inside of the wrist and one on the outside. Each cue interval, the vibrating node is the one that should finish on top. Correct intervals earn points. If the cue repeats, the app can also penalize unnecessary wrist rotation based on orientation swing, even when the final side is still correct. Wrong-way-up repeat misses still use the existing repeat penalty.",
  "parameters_setting": [
    [
      "Save Options",
      {
        "source": "save_mode",
        "title": "Save Mode",
        "type": "combo",
        "validation": [
          "csv",
          "h5",
          "xlsx",
          "none"
        ],
        "description": "Save file in specified format"
      }
    ],
    [
      "Feedback",
      {
        "source": "vibration_duration",
        "title": "Vibration Duration",
        "type": "float",
        "validation": [
          0.05,
          2.0
        ],
        "description": "How long each cue vibration lasts in seconds."
      }
    ],
    [
      "Game Settings",
      {
        "source": "game_time",
        "title": "Game Time",
        "type": "float",
        "validation": [
          5,
          300
        ],
        "description": "Total game duration in seconds."
      },
      {
        "source": "cue_interval",
        "title": "Cue Interval",
        "type": "float",
        "validation": [
          0.25,
          5
        ],
        "description": "Time between cues in seconds."
      },
      {
        "source": "decision_window",
        "title": "Decision Window",
        "type": "float",
        "validation": [
          0.05,
          2
        ],
        "description": "How much of the end of each interval to average for orientation scoring."
      },
      {
        "source": "start_target",
        "title": "Start Target",
        "type": "combo",
        "validation": [
          "random",
          "inside_wrist",
          "outside_wrist"
        ],
        "description": "Which target to cue first."
      },
      {
        "source": "repeat_probability",
        "title": "Repeat Probability",
        "type": "float",
        "validation": [
          0,
          1
        ],
        "description": "Chance that the next cue is the same as the previous cue."
      }
    ],
    [
      "Scoring",
      {
        "source": "points_per_correct",
        "title": "Points Per Correct",
        "type": "int",
        "validation": [
          0,
          10
        ],
        "description": "Points awarded when the correct node is on top at the end of the interval."
      },
      {
        "source": "penalty_same_target_miss",
        "title": "Repeat Cue Penalty",
        "type": "int",
        "validation": [
          -10,
          0
        ],
        "description": "Penalty applied when the cue repeats and the player rotates away from the same target."
      },
      {
        "source": "penalty_changed_target_miss",
        "title": "Change Cue Miss Penalty",
        "type": "int",
        "validation": [
          -10,
          0
        ],
        "description": "Penalty applied when the cue changes and the player still finishes on the wrong side."
      },
      {
        "source": "penalty_repeat_rotation",
        "title": "Repeat Rotation Penalty",
        "type": "int",
        "validation": [
          -10,
          0
        ],
        "description": "Additional penalty applied on repeat cues when orientation swing exceeds the repeat rotation threshold, even if the final side is still correct."
      },
      {
        "source": "unknown_counts_as_miss",
        "title": "Unknown Counts As Miss",
        "type": "bool",
        "description": "Apply miss penalties even when the accelerometer result is too ambiguous to classify."
      }
    ],
    [
      "Top Detection",
      {
        "source": "top_margin_threshold",
        "title": "Top Margin Threshold",
        "type": "float",
        "validation": [
          0,
          2
        ],
        "description": "Minimum difference between the inside and outside top scores before calling one of them on top."
      },
      {
        "source": "repeat_rotation_margin_threshold",
        "title": "Repeat Rotation Threshold",
        "type": "float",
        "validation": [
          0,
          4
        ],
        "description": "Maximum allowed swing in orientation margin during a repeat cue before applying the repeat rotation penalty."
      },
      {
        "source": "orientation_confidence_threshold",
        "title": "Confidence Threshold",
        "type": "float",
        "validation": [
          0,
          2
        ],
        "description": "Minimum normalized Z-axis value needed before the orientation is considered trustworthy."
      }
    ]
  ],
  "user_fields": [
    {
      "name": "time",
      "data_type": "float",
      "size": 1
    },
    {
      "name": "interval_index",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "time_remaining",
      "data_type": "float",
      "size": 1
    },
    {
      "name": "running_score",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "correct_count",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "same_target_penalty_count",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "changed_target_miss_count",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "repeat_rotation_penalty_count",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "unknown_count",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "target_top",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "actual_top",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "cue_changed",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "repeated_target",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "points_awarded",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "correct_this_interval",
      "data_type": "int",
      "size": 1
    },
    {
      "name": "inside_top_score",
      "data_type": "float",
      "size": 1
    },
    {
      "name": "outside_top_score",
      "data_type": "float",
      "size": 1
    },
    {
      "name": "orientation_margin",
      "data_type": "float",
      "size": 1
    },
    {
      "name": "orientation_margin_swing",
      "data_type": "float",
      "size": 1
    },
    {
      "name": "user_defined_status",
      "data_type": "str",
      "size": 1
    }
  ],
  "sensors": [
    "inside_wrist",
    "outside_wrist"
  ],
  "feedback": [],
  "datarate": 100
}
