Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 6x 6x 6x 6x 6x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 1x 1x 1x 1x 1x 1x 6x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | // Abacus Studio — KitPlatePreview stories (Gitea #32).
//
// Every state of the bed picture, staged without a printer, a WASM export or a
// mesh. The GEOMETRY IS REAL: `packKitPlate` needs only footprint numbers and a
// bed, not triangles, so each story runs the actual packer over the actual
// module dimensions (mid 15.5 mm, end 26 mm, 100.5 mm deep at scale 1) and draws
// what it answers. Hand-typed placements would drift from the packer the first
// time a heuristic changed and nobody would notice — the picture would simply
// stop being a picture of anything.
//
// The refusals are staged the same way: the packer is asked for something
// impossible and its own KitPlateFitError copy is what renders, so the words in
// Storybook are the words a user gets.
import type { Meta, StoryObj } from '@storybook/react'
import { BAMBU_256_BED } from './abacus-3mf-assembly'
import {
KitPlateFitError,
type KitPlateLayout,
kitPlateInstances,
type ModuleBasis,
packKitPlate,
} from './abacus-kit-plate'
import { defaultParams, type FilamentMap, type Params } from './abacus-model'
import type { ModuleKind } from './abacus-module-kit'
import { KitPlatePreview } from './KitPlatePreview'
const params = (over: Partial<Params> = {}): Params => ({
...defaultParams,
seam_mode: 'modular',
feet_mode: 'adhesive',
...over,
})
const fm: FilamentMap = {
slots: ['#c9a26e', '#f5f5f5', '#111111', '#2e86ab'],
frame: 0,
markerWhite: 1,
markerBlack: 2,
beadRoles: [3, 1],
markerContrast: 21,
}
/** Measured module footprints at scale 1 — what `moduleBasis` reports off the
* real renders, restated here so a story needs no geometry pipeline. */
const bases: Record<ModuleKind, ModuleBasis> = {
left: { kind: 'left', minX: 0, minY: 0, wMm: 26, hMm: 100.5 },
mid: { kind: 'mid', minX: 0, minY: 0, wMm: 15.5, hMm: 100.5 },
right: { kind: 'right', minX: 0, minY: 0, wMm: 26, hMm: 100.5 },
}
function pack(args: {
cols?: number
bed?: typeof BAMBU_256_BED
supportsAtSlice?: boolean
filaments?: number
}): { layout: KitPlateLayout | null; refusal: KitPlatePreviewRefusal | null } {
const p = params({ cols: args.cols ?? 13 })
try {
return {
layout: packKitPlate({
instances: kitPlateInstances(p, fm),
bases,
bed: args.bed ?? BAMBU_256_BED,
supportsAtSlice: args.supportsAtSlice ?? false,
filaments: args.filaments ?? 3,
}),
refusal: null,
}
} catch (err) {
if (err instanceof KitPlateFitError) {
return {
layout: null,
refusal: { headline: err.headline, remediation: err.remediation, modules: err.modules },
}
}
throw err
}
}
type KitPlatePreviewRefusal = {
headline: string
remediation: string
modules: readonly string[]
}
const meta: Meta<typeof KitPlatePreview> = {
title: 'AbacusStudio/KitPlatePreview',
component: KitPlatePreview,
tags: ['autodocs'],
decorators: [
(Story) => (
// the studio's dark print panel; the preview's palette assumes it
<div
style={{
width: 340,
padding: 12,
borderRadius: 12,
background: 'rgba(17,24,39,0.95)',
color: 'rgba(226,232,240,0.95)',
fontFamily: 'ui-sans-serif, system-ui, sans-serif',
fontSize: 12,
}}
>
<Story />
</div>
),
],
}
export default meta
type Story = StoryObj<typeof KitPlatePreview>
/** The shipped case: 13 columns, three filaments, one 256 bed. */
export const FullKit: Story = {
args: { ...pack({ filaments: 3 }), filaments: 3 },
}
/** Supports on (printed feet, or the operator's style) widens every gap AND the
* tower's clearance ring — the same kit, visibly looser. */
export const SupportsOn: Story = {
args: { ...pack({ supportsAtSlice: true, filaments: 3 }), filaments: 3 },
}
/** A fourth spool (the routed support interface) buys the tower a deeper
* envelope row, and on a full bed that is the difference between fitting and
* not. Compare the reserve against FullKit. */
export const FourFilaments: Story = {
args: { ...pack({ filaments: 4 }), filaments: 4 },
}
/** Few enough modules that the bed is mostly tower and empty space. */
export const SmallKit: Story = {
args: { ...pack({ cols: 4, filaments: 3 }), filaments: 3 },
}
/** A printer with no declared keep-out — the hatched corner is a property of the
* machine, not of the drawing. */
export const NoKeepOut: Story = {
args: {
...pack({ bed: { wMm: 256, dMm: 256 }, filaments: 3 }),
filaments: 3,
},
}
/** The honest refusal, in the packer's own words. */
export const WontFit: Story = {
args: pack({ cols: 13, bed: { wMm: 180, dMm: 180 }, filaments: 3 }),
}
/** Waiting on the module export. */
export const Packing: Story = {
args: { layout: null, pending: true },
}
|