Loading...
Loading...
JavaFX UI/UX design skill — visual design, layout composition, color tokens, typography, spacing systems, CSS styling, control theming, accessibility, and usability improvements for the Renamer App. Use whenever the task involves styling, beautifying, or improving visual appearance — choosing colors, fonts, layouts, spacing, CSS stylesheets, control variants, responsive sizing, dark/light themes, or any UI/UX polish. Trigger on phrases like "make it look better", "improve the UI", "redesign the layout", "style the controls", "create a theme", "CSS for JavaFX", or any visual/aesthetic concern. Complements the separate /javafx skill that handles technical/functional concerns (threading, DI, FXML loading). When both design and functional changes are needed, use this skill for design aspects and /javafx for wiring concerns.
npx skill4agent add sanyokkua/renamer_app javafx-ui-designerPurpose: Guide the design of visually polished, usable, and consistent JavaFX interfaces for the Renamer App. Covers layout composition, color palettes, typography, spacing systems, CSS styling, control theming, accessibility, and responsive design.Supporting files in this directory:
— CSS property reference + full control styling patterns (sections 7–8)css-control-patterns.md — theming architecture, responsive design, CSS transitions (sections 9, 11–12)theming-and-motion.md
project_name: "Renamer App"
javafx_version: 25
java_version: 25
build_tool: maven
css_location: app/ui/src/main/resources/styles/ # create this dir; no CSS files exist yet
fxml_location: app/ui/src/main/resources/fxml/
target_platform: desktop
design_style: modern-flat
color_scheme: light # dark/auto as future option
primary_color: "#2196F3" # placeholder — replace when theme is chosen
secondary_color: "#FF9800"
base_font_family: "System" # platform default; replace with Inter/Segoe later
base_font_size: 14px
spacing_unit: 8px
min_window_width: 900
min_window_height: 600
scene_builder_used: false # Guice controllers; no fx:controller attribute
existing_theme: none # Modena default — no AtlantaFX/JMetronode.setStyle(...)ua.renamer.app.ui.enums.TableStylesscene.getStylesheets().add(...)RenamerApplication.start()TableStyles.error.readyApplicationMainViewControllerRenamerApplicationApplicationua.renamer.app.RenamerApplicationua.renamer.app.Launcherapp/ui/src/main/resources/styles/theming-and-motion.md.root:hover:focused:pressed:disabled:selected-fx-spacing-fx-alignmentcolumnConstraintsrowConstraintshgapvgapBorderPane (root)
├── top: VBox
│ ├── MenuBar
│ └── HBox (toolbar)
├── left: VBox (sidebar/navigation)
├── center: StackPane
│ └── ScrollPane
│ └── VBox (content)
├── bottom: HBox (status bar)HBox.setHgrow(contentArea, Priority.ALWAYS);
VBox.setVgrow(scrollPane, Priority.ALWAYS);<HBox>
<Label text="Fixed" />
<Region HBox.hgrow="ALWAYS" /> <!-- spacer -->
<Button text="Action" />
</HBox>In this project:usesApplicationMainView.fxmlas root. Mode views useBorderPane. Prefer constraint-based growth overVBox/HBox/GridPane. TheAnchorPanedrivesFxStateMirrordata — do not replace theTableViewbinding on the table.ObservableList
.root.root {
/* ── Primary palette ── */
-fx-primary: #2196F3;
-fx-primary-hover: derive(-fx-primary, -10%);
-fx-primary-pressed: derive(-fx-primary, -20%);
-fx-primary-subtle: derive(-fx-primary, 85%);
/* ── Neutral palette ── */
-fx-bg-base: #FFFFFF;
-fx-bg-surface: #F8F9FA;
-fx-bg-elevated: #FFFFFF;
-fx-border-default: #DEE2E6;
-fx-border-subtle: #E9ECEF;
/* ── Text palette ── */
-fx-text-primary: #212529;
-fx-text-secondary: #6C757D;
-fx-text-tertiary: #ADB5BD;
-fx-text-on-primary: #FFFFFF;
/* ── Semantic palette ── */
-fx-success: #28A745;
-fx-warning: #FFC107;
-fx-danger: #DC3545;
-fx-info: #17A2B8;
/* ── Assign to built-in looked-up colors ── */
-fx-base: -fx-bg-base;
-fx-background: -fx-bg-surface;
-fx-accent: -fx-primary;
-fx-focus-color: derive(-fx-primary, 40%);
-fx-faint-focus-color: transparent;
}derive()ladder()derive(color, percentage)ladder(color, stop1, stop2, ...).label {
-fx-text-fill: ladder(-fx-background,
-fx-text-on-primary 49%,
-fx-text-primary 50%
);
}derive()#000000#FFFFFF// Load before scene creation
Font.loadFont(getClass().getResourceAsStream("/fonts/Inter-Regular.ttf"), 14);
Font.loadFont(getClass().getResourceAsStream("/fonts/Inter-Bold.ttf"), 14);@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Regular.ttf');
}.root.root {
-fx-font-family: "System";
-fx-font-size: 14px;
/* ── Type scale (1.25 ratio) ── */
-fx-font-size-xs: 10px;
-fx-font-size-sm: 12px;
-fx-font-size-base: 14px;
-fx-font-size-md: 16px;
-fx-font-size-lg: 18px;
-fx-font-size-xl: 22px;
-fx-font-size-2xl: 28px;
-fx-font-size-3xl: 34px;
}
.h1 {
-fx-font-size: -fx-font-size-3xl;
-fx-font-weight: bold;
-fx-text-fill: -fx-text-primary;
}
.h2 {
-fx-font-size: -fx-font-size-2xl;
-fx-font-weight: bold;
-fx-text-fill: -fx-text-primary;
}
.h3 {
-fx-font-size: -fx-font-size-xl;
-fx-font-weight: 600;
-fx-text-fill: -fx-text-primary;
}
.subtitle {
-fx-font-size: -fx-font-size-md;
-fx-text-fill: -fx-text-secondary;
}
.caption {
-fx-font-size: -fx-font-size-xs;
-fx-text-fill: -fx-text-tertiary;
}
.monospace {
-fx-font-family: "JetBrains Mono", "Consolas", monospace;
}-fx-font-size.root-fx-font-family-fx-font-size-fx-font-weight-fx-font-style-fx-text-fill-fx-text-alignment-fx-line-spacing.root.root {
/* ── Spacing scale (8px base) ── */
-fx-spacing-xs: 4px;
-fx-spacing-sm: 8px;
-fx-spacing-md: 12px;
-fx-spacing-lg: 16px;
-fx-spacing-xl: 24px;
-fx-spacing-2xl: 32px;
-fx-spacing-3xl: 48px;
}.card {
-fx-padding: -fx-spacing-lg;
-fx-spacing: -fx-spacing-md;
}minWidth/HeightprefWidth/HeightmaxWidth/HeightprefWidth/HeightmaxWidthInfinityDouble.MAX_VALUERegion.USE_COMPUTED_SIZE.stretch-button {
-fx-max-width: Infinity;
}
.sidebar {
-fx-pref-width: 240px;
-fx-min-width: 200px;
-fx-max-width: 280px;
}Region┌─────────────────────────────────────┐
│ background-color │
│ ┌───────────────────────────────┐ │ ← background-insets
│ │ border-color │ │
│ │ ┌─────────────────────────┐ │ │ ← border-width + border-insets
│ │ │ padding │ │ │
│ │ │ ┌───────────────────┐ │ │ │ ← padding
│ │ │ │ CONTENT AREA │ │ │ │
│ │ │ └───────────────────┘ │ │ │
│ │ └─────────────────────────┘ │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘.card-elevated {
-fx-background-color:
derive(-fx-border-default, -5%), /* outer shadow layer */
-fx-border-default, /* border layer */
-fx-bg-elevated; /* content background */
-fx-background-insets: -1, 0, 1;
-fx-background-radius: 9, 8, 7;
}.button:focused {
-fx-border-color: -fx-primary;
-fx-border-width: 2px;
}.root.root {
-fx-focus-color: derive(-fx-primary, 20%);
-fx-faint-focus-color: transparent; /* removes outer glow */
}focusTraversable="true"_Saveaccelerator.tooltip {
-fx-background-color: -fx-text-primary;
-fx-text-fill: -fx-bg-base;
-fx-font-size: -fx-font-size-sm;
-fx-background-radius: 4px;
-fx-padding: 4px 8px;
}Existing pattern: controllers createin Java viaTooltip. The CSScontrol.setTooltip(new Tooltip(...))rule styles them globally without changing any Java code..tooltip { }
.icon-button {
-fx-min-width: 36px;
-fx-min-height: 36px;
-fx-padding: 8px;
}.root.root-fx-text-overrun: ellipsis:hover-fx-cursor: hand.root-fx-background-color-fx-background-insets-fx-effect<Button styleClass="button, primary, large" text="Submit" />.large { -fx-padding: 12px 24px; -fx-font-size: -fx-font-size-lg; }.error.success.loading.root {
-fx-radius-sm: 4px;
-fx-radius-md: 8px;
-fx-radius-lg: 12px;
-fx-radius-full: 100px; /* for pills and circles */
}node.setStyle("-fx-background-color: red")-fx-base-fx-base-fx-effect: dropshadow(...)AnchorPane