# Copyright (c) Meta Platforms, Inc. and affiliates. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. """ Html Design Agent Environment Implementation. Renders HTML with a headless Playwright browser and scores it on four dimensions from AGENTS.md: R = 0.25*R_branding + 0.25*R_spacing + 0.25*R_a11y + 0.25*R_composition Three tasks of increasing difficulty: - level1_accessibility : (easy) add missing alt/aria-label/label attributes - level2_spacing : (medium) fix off-grid spacing to the 8pt system - level3_contrast : (hard) fix colours, spacing AND accessibility together """ from __future__ import annotations import json import math import os from dataclasses import dataclass, field from typing import Any, Dict, List, Optional, Tuple from uuid import uuid4 from openenv.core.env_server.interfaces import Environment from openenv.core.env_server.types import State try: from ..models import HtmlDesignAgentAction, HtmlDesignAgentObservation except ImportError: from models import HtmlDesignAgentAction, HtmlDesignAgentObservation # --------------------------------------------------------------------------- # Brand design tokens (single source of truth for all tasks) # --------------------------------------------------------------------------- DESIGN_TOKENS: Dict[str, Any] = { "palette": { "primary": "#1A1A2E", # dark navy – headings, body text "accent": "#E94560", # brand red – CTAs, highlights "white": "#FFFFFF", # page background, reversed text "surface": "#F0F0F5", # card backgrounds "muted": "#646478", # secondary / caption text }, "palette_rgb": { "primary": (26, 26, 46), "accent": (233, 69, 96), "white": (255, 255, 255), "surface": (240, 240, 245), "muted": (100, 100, 120), }, "fonts": ["Inter", "Roboto", "Open Sans", "system-ui", "sans-serif", "-apple-system"], "spacing_scale": [0, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 96, 128], "min_contrast_ratio": 4.5, "max_color_delta_e": 2.0, } # --------------------------------------------------------------------------- # Task definitions # --------------------------------------------------------------------------- @dataclass class TaskDefinition: task_id: str description: str difficulty: str # "easy" | "medium" | "hard" broken_html: str done_threshold: float # episode ends when total reward >= this TASKS: Dict[str, TaskDefinition] = { # ------------------------------------------------------------------ # Level 1 – level1_accessibility (EASY) # Only structural HTML attributes are missing: alt, aria-label, labels. # Colours and spacing are already correct — agent only needs to add # missing attributes, no design knowledge required. # done_threshold is lenient (0.80) because the scorer also considers # composition/branding which are already correct. # ------------------------------------------------------------------ "level1_accessibility": TaskDefinition( task_id="level1_accessibility", description=( "Easy — fix accessibility only: add alt text to images, " "aria-label to icon buttons, and