diff --git a/docs/FONT_MANAGER.md b/docs/FONT_MANAGER.md index 74fab255..e6691dd7 100644 --- a/docs/FONT_MANAGER.md +++ b/docs/FONT_MANAGER.md @@ -2,8 +2,10 @@ > **Picking a size automatically:** if you want the *largest font that fits > a given area* rather than a fixed size, use the adaptive layout system's -> font ladders (`self.layout.fit_text(...)`) which resolve through this -> FontManager — see [ADAPTIVE_LAYOUT.md](ADAPTIVE_LAYOUT.md). +> font ladders, which resolve through this FontManager. `BasePlugin` +> subclasses get this as `self.layout.fit_text(...)`; other code can build +> a `LayoutContext(width, height, font_manager)` directly — see +> [ADAPTIVE_LAYOUT.md](ADAPTIVE_LAYOUT.md). ## Overview diff --git a/docs/PLUGIN_DEVELOPMENT_GUIDE.md b/docs/PLUGIN_DEVELOPMENT_GUIDE.md index bcb637a3..01ef6029 100644 --- a/docs/PLUGIN_DEVELOPMENT_GUIDE.md +++ b/docs/PLUGIN_DEVELOPMENT_GUIDE.md @@ -2,10 +2,13 @@ This guide explains how to set up a development workflow for plugins that are maintained in separate Git repositories while still being able to test them within the LEDMatrix project. -> **Rendering guidance:** plugins are expected to read the display size -> dynamically and lay themselves out for any panel. The adaptive layout -> system ([ADAPTIVE_LAYOUT.md](ADAPTIVE_LAYOUT.md)) provides the shared -> helpers for that — fonts, images, and composite layouts that scale. +> **Rendering guidance:** plugins should read the display size dynamically +> (`self.display_manager.matrix.width/height`) rather than hardcoding one +> panel. For plugins that want to *scale* their layout to any panel, the +> opt-in adaptive layout system ([ADAPTIVE_LAYOUT.md](ADAPTIVE_LAYOUT.md)) +> provides the shared helpers — fonts, images, and composite layouts that +> scale. Existing plugins keep their classic rendering unless they adopt +> those APIs; nothing migrates automatically. ## Overview diff --git a/scripts/dev_server.py b/scripts/dev_server.py index 105f42a8..86195533 100644 --- a/scripts/dev_server.py +++ b/scripts/dev_server.py @@ -276,14 +276,20 @@ def api_render(): try: plugin_dir, manifest, config, mock_data, skip_update = _parse_render_request(data) - except LookupError as e: - return jsonify({'error': str(e)}), 404 + except LookupError: + return jsonify({'error': f"Plugin not found: {data['plugin_id']}"}), 404 + except Exception: + # Bad manifest.json / schema / fixture — details go to the dev's + # console, not the HTTP response + app.logger.exception('render request preparation failed') + return jsonify({'error': 'Could not prepare render request; see server log'}), 400 try: result = _render_once(data['plugin_id'], plugin_dir, manifest, config, mock_data, width, height, skip_update) - except Exception as e: - return jsonify({'error': f'Failed to load plugin: {e}'}), 500 + except Exception: + app.logger.exception('plugin load failed during render') + return jsonify({'error': 'Failed to load plugin; see server log'}), 500 return jsonify(result) @@ -321,18 +327,22 @@ def api_render_matrix(): try: plugin_dir, manifest, config, mock_data, skip_update = _parse_render_request(data) - except LookupError as e: - return jsonify({'error': str(e)}), 404 + except LookupError: + return jsonify({'error': f"Plugin not found: {data['plugin_id']}"}), 404 + except Exception: + app.logger.exception('render request preparation failed') + return jsonify({'error': 'Could not prepare render request; see server log'}), 400 results = [] for w, h in parsed_sizes: try: results.append(_render_once(data['plugin_id'], plugin_dir, manifest, config, mock_data, w, h, skip_update)) - except Exception as e: + except Exception: + app.logger.exception('plugin load failed during %dx%d render', w, h) results.append({'image': None, 'width': w, 'height': h, 'render_time_ms': 0, - 'errors': [f'Failed to load plugin: {e}'], + 'errors': ['Failed to load plugin; see server log'], 'warnings': []}) return jsonify({'results': results})