Skip to content

Miscend/VisualLayoutCompiler

Repository files navigation

VisualCompiler

VisualCompiler is a visual-to-CSS layout inference tool. You place rectangles on a canvas and the app infers a likely grid or flex implementation, previews the result, and emits CSS plus responsive snapshots.

Canvas Snapping

Canvas dragging uses soft snapping rather than hard layout enforcement.

Current behavior:

  • nearby edges, centers, and repeated gaps still win first for local cleanup
  • composition-level candidates can beat slightly closer local snaps when they complete a stronger global pattern
  • drag overlays can show inferred ghost rows and columns for emerging grid structure
  • sparse shapes such as plus, T, L, and near-complete grids surface multi-item snap targets
  • a Promote to grid banner can move the dragged item into the single missing grid cell without creating a persistent layout override
  • holding Alt still bypasses all drag-time snapping assistance

Development

Requirements:

  • Node.js 20+
  • npm

Commands:

  • npm run dev starts Vite at http://localhost:5173
  • npm run build runs TypeScript compilation and a production build
  • npm run lint runs ESLint
  • npm run test:unit runs Vitest
  • npm run test:e2e runs Playwright
  • npm test runs unit and end-to-end tests

Project Layout

  • src/canvas/: interactive canvas, snapping, breakpoint capture, item overrides
  • src/inference/: layout inference pipeline, candidate scoring, canonicalization, unit tests
  • src/output/: live preview, CSS panel, ambiguity and override UI
  • tests/: fixture-driven inference and browser tests

Inference Pipeline

The main entrypoint is src/inference/index.ts.

Pipeline summary:

  1. Preprocess input geometry.
  2. Detect column and row tracks.
  3. Compute structural features and raw weakness scores.
  4. Classify the pattern (uniform-grid, sparse-grid, weak-sparse-grid, flex-wrap, ambiguous) using policy thresholds.
  5. Build the literal grid candidate from detected occupancy.
  6. Canonicalize weak sparse grids when allowed.
  7. Score grid vs flex and calibrate candidate confidence.
  8. Emit CSS and return primary plus alternate candidates.

Weak Sparse Canonicalization

Some small sparse shapes are bad fits for both flex-wrap and naive grid auto-placement. Examples:

  • hollow diamonds
  • sparse crosses without a dominant row or column
  • small arrangements with weak alignment continuity and no believable wrap story

For these cases, VisualCompiler can replace the literal sparse occupancy with a stronger canonical grid template.

Weak sparse detection is intentionally generic rather than motif-specific. The feature layer computes raw geometry signals such as:

  • alignment weakness
  • compactness weakness
  • narrative weakness
  • stability weakness

Those raw weakness scores live in src/inference/features.ts. Policy concepts such as the bad-bucket cutoff and minimum weak-bucket count are applied later in src/inference/classifier.ts, so retuning classifier thresholds does not change the geometry feature contract.

Current behavior:

  • Activation is narrow and limited to weak-sparse-grid cases.
  • The canonicalizer compares the literal grid against a small template family.
  • Current template families are balanced-grid, anchored-3col, and hero-with-supporting-items.
  • Template assignment is geometry-driven, not item-array-order-driven.
  • Canonicalization only takes effect when the rescored canonical candidate still wins as grid.
  • The literal candidate must be below an explicit confidence threshold before rewriting is allowed.
  • The selected canonical assignment must stay within explicit canvas-space movement budgets: average item movement in pixels and maximum single-item movement in pixels, both measured from the realized canonical grid layout anchored in the source shape's own frame.
  • Canonicalization still needs a material score gain over the literal layout to apply.
  • Translation alone should not change the movement gate for the same weak sparse shape.

The implementation lives in src/inference/canonicalize.ts.

Confidence Semantics

Confidence is attached to realized candidates, not just the initial literal geometry.

That means:

  • a canonicalized primary grid is calibrated from canonicalized grid structure
  • a canonicalized grid alternate keeps its own canonicalized confidence context even when flex remains primary
  • ambiguity UI bars are derived from each candidate’s own decision, features, and pattern class

Confidence calibration lives in src/inference/calibration.ts.

Overrides

User constraints live in src/types.ts and are stored via the canvas store.

Current override support:

  • forceType: force grid or flex
  • spans: pin per-item grid spans
  • sizing: pin grid track sizing
  • justifyContent: pin flex justification
  • canonicalization: auto or literal

canonicalization: 'literal' disables weak sparse rewriting and keeps the literal sparse grid candidate.

The ambiguity/override UI surfaces canonicalization controls whenever a grid candidate carries weak sparse metadata, even if flex is primary.

Deleting an item also prunes item-linked constraints from the store, so stale per-item override badges do not linger after removal.

Responsive Breakpoints

Responsive snapshots are captured from canvas viewport changes and exported as media-query CSS.

Current behavior:

  • Auto-capture records a snapshot when either layout structure changes or orientation bucket changes.
  • Snapshots are keyed by (width, orientation) rather than width alone, so the same width can preserve separate portrait, square, and landscape states.
  • Orientation buckets match app inference thresholds: landscape when w / h > 6/5, portrait when w / h < 5/6, and square for the inclusive middle range.
  • Responsive CSS generation adds orientation constraints to each breakpoint query: landscape uses (aspect-ratio > 6/5), portrait uses (aspect-ratio < 5/6), and square uses (aspect-ratio >= 5/6) and (aspect-ratio <= 6/5).
  • This keeps same-width, multi-orientation snapshots from collapsing into conflicting duplicate @media (min-width: Xpx) blocks.

Testing

Relevant coverage for the canonicalization layer:

Recommended verification before committing:

  • npm run test:unit
  • npm run build

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages