Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
    • Pick-up and Delivery Routing
    • Task Scheduling
  • Platform
Try models
  • Timefold Solver SNAPSHOT
  • Running the Solver
  • As a service
  • Visualization
  • Edit this Page

Timefold Solver SNAPSHOT

    • Introduction
    • Getting started
      • Overview
      • Build as a service
      • Embed as a library
        • Hello World guide
        • Quarkus guide
        • Spring Boot guide
    • Domain modeling
      • Guide
      • Building blocks
      • Common patterns
    • Constraints and score
      • Overview
      • Score calculation
      • Understanding the score
      • Load balancing and fairness
      • Performance tips and tricks
    • Running the Solver
      • Overview
      • As a service
        • REST API
        • Model enrichment
        • Constraint weights
        • Demo data
        • Exposing metrics
        • Visualization
      • As a library
        • Configuring Timefold Solver
        • Constraint weights
        • Quarkus integration
        • Spring Boot integration
        • JPA/JAXB/JSON integration
    • Diagnosing the Solver
      • Benchmarking
      • Solver diagnostics
    • Deploying to the Timefold Platform
      • Overview
      • Guide
      • Platform model metadata
      • Using metrics
      • Visualization
    • Optimization algorithms
      • Overview
      • Construction heuristics
      • Local search
      • Exhaustive search
      • Custom moves
        • Neighborhoods API
        • Move Selector reference
    • Responding to change
      • Continuous planning
      • Real-time planning
      • Non-disruptive replanning
      • Assignment Recommendation API
    • Example use cases
      • Vehicle routing (guide)
      • More examples on GitHub
    • FAQ
    • New and noteworthy
    • Upgrading Timefold Solver
      • Upgrading Timefold Solver: Overview
      • Upgrade from Timefold Solver 1.x to 2.x
      • Upgrading from OptaPlanner
      • Backwards compatibility
      • Migration guides
        • Variable Listeners to Custom Shadow Variables
        • Chained planning variable to planning list variable
    • Commercial editions
      • Overview
      • Installation
      • Performance improvements
      • Score analysis
      • Recommendation API
      • Nearby selection
      • Multithreaded solving
      • Partitioned search
      • Constraint profiling
      • Multistage moves
      • Throttling best solution events
      • License management

Visualization

A model’s solution is often easier to understand as a rendered UI than as raw JSON. This page describes how to build a custom visualization UI for your model and serve it from the service module while running locally.

See Visualization for how this same UI is embedded once your model is deployed to Timefold Platform.

1. Serving a UI locally

Any static file placed under src/main/resources/META-INF/resources is served by Quarkus at the site root. For example, an index.html and app.js placed there are served at http://localhost:8080/index.html and http://localhost:8080/app.js.

This static-resource handling is independent of your REST API path configuration: the UI files and the API endpoints are served from the same Quarkus instance, but the UI does not sit under whatever @Path your ModelRest interface declares.

2. Enabling the UI in the model descriptor archive

Whether the archive generated around your model descriptor (model-descriptor.zip) bundles a UI is controlled by the build-time timefold.model.ui-support property, which accepts one of two values:

  • NONE: no UI is bundled.

  • APP_JS: the files under src/main/resources/META-INF/resources are bundled as the model’s UI.

If you don’t set this property explicitly, it’s auto-detected: if src/main/resources/META-INF/resources exists and contains at least one file, APP_JS is used; otherwise, NONE is used.

3. Tips

3.1. Use relative asset paths

When deployed to Timefold Platform, the same META-INF/resources files are repackaged and served under a ui/ prefix instead of the site root (see Visualization). A root-absolute reference like <script src="/app.js"> breaks once moved under that prefix; a relative one like <script src="./app.js"> still resolves correctly. Use relative asset paths in your index.html for this reason.

3.2. Enable CORS for external dev servers

The service module doesn’t configure CORS for you. To run your UI on a separate dev server (Vite, webpack, …​), add: quarkus.http.cors=true.

See the Quarkus CORS guide for how to restrict allowed origins, methods, or headers.

4. Calling your REST API from the UI

Your UI calls your model’s REST API the same way any other client would.

Open the Swagger UI at http://localhost:8080/q/swagger-ui/, introduced in Getting started: building a service, to check the exact path, rather than assuming a fixed prefix.

See Visualization for how to target your API from inside the platform’s iframe.

  • © 2026 Timefold BV
  • Timefold.ai
  • Documentation
  • Changelog
  • Send feedback
  • Privacy
  • Legal
    • Light mode
    • Dark mode
    • System default