from otree.api import * doc = """ Sandbox Practice: a no-stakes interactive board to learn mechanics. Single-player; client-only coalition logic; unlocks Next after short practice. """ def timer(player, seconds): """Return seconds if timers are enabled, else None.""" return seconds if player.session.config.get('enable_timers', False) else None class Constants(BaseConstants): name_in_url = 'sandbox_practice' players_per_group = None num_rounds = 1 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): practiced = models.BooleanField(initial=False) class Sandbox(Page): form_model = 'player' form_fields = [] @staticmethod def vars_for_template(player: Player): # You can pass config values here if you want them visible (e.g., real 10s threshold) return dict( real_threshold_seconds = 10, # real game threshold (for text) practice_threshold_seconds = 10, # how long to hold in sandbox to unlock Next sandbox_round_limit = 5, # Sandbox Round Limit ) @staticmethod def get_timeout_seconds(player): return timer(player, 300) @staticmethod def before_next_page(player: Player, timeout_happened): # Flag that they practiced (optional; could be used later for QA) player.practiced = True if timeout_happened: # Even if they time out here, it should not kill the session — just proceed pass page_sequence = [Sandbox]