@shipload/item-renderer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +14 -0
- package/.gitignore +6 -0
- package/Makefile +50 -0
- package/biome.json +18 -0
- package/bun.lock +123 -0
- package/package.json +51 -0
- package/scripts/check-bundle-size.ts +37 -0
- package/scripts/copy-fonts.ts +41 -0
- package/scripts/preview.ts +43 -0
- package/src/errors.ts +22 -0
- package/src/fonts/index.ts +36 -0
- package/src/fonts/inter-400.woff2 +0 -0
- package/src/fonts/inter-600.woff2 +0 -0
- package/src/fonts/jetbrains-500.woff2 +0 -0
- package/src/fonts/load-bun.ts +16 -0
- package/src/fonts/orbitron-700.woff2 +0 -0
- package/src/index.ts +46 -0
- package/src/links.ts +19 -0
- package/src/meta.ts +42 -0
- package/src/payload/base64url.ts +27 -0
- package/src/payload/codec.ts +26 -0
- package/src/primitives/category-icon.ts +87 -0
- package/src/primitives/compact-row.ts +38 -0
- package/src/primitives/divider.ts +20 -0
- package/src/primitives/icon-hex.ts +39 -0
- package/src/primitives/module-slot.ts +147 -0
- package/src/primitives/panel.ts +24 -0
- package/src/primitives/quantity-badge.ts +37 -0
- package/src/primitives/span-paragraph.ts +72 -0
- package/src/primitives/stat-bar.ts +85 -0
- package/src/primitives/svg.ts +25 -0
- package/src/primitives/text.ts +42 -0
- package/src/primitives/wrap.ts +24 -0
- package/src/render.ts +33 -0
- package/src/templates/_shared.ts +15 -0
- package/src/templates/component.ts +139 -0
- package/src/templates/index.ts +30 -0
- package/src/templates/item-cell.ts +96 -0
- package/src/templates/module.ts +190 -0
- package/src/templates/packed-entity.ts +30 -0
- package/src/templates/resource.ts +151 -0
- package/src/templates/ship-panel.ts +145 -0
- package/src/tokens/colors.ts +45 -0
- package/src/tokens/index.ts +7 -0
- package/src/tokens/spacing.ts +10 -0
- package/src/tokens/typography.ts +19 -0
- package/test/__image_snapshots__/.gitkeep +0 -0
- package/test/__image_snapshots__/component-hull-plates.png +0 -0
- package/test/__image_snapshots__/module-engine-t1.png +0 -0
- package/test/__image_snapshots__/module-storage-t1.png +0 -0
- package/test/__image_snapshots__/packed-entity-ship-t1-only-engine.png +0 -0
- package/test/__image_snapshots__/packed-entity-ship-t1-two-modules.diff.png +0 -0
- package/test/__image_snapshots__/packed-entity-ship-t1-two-modules.png +0 -0
- package/test/__image_snapshots__/resource-iron.diff.png +0 -0
- package/test/__image_snapshots__/resource-iron.png +0 -0
- package/test/__snapshots__/templates-component.test.ts.snap +5 -0
- package/test/__snapshots__/templates-item-cell.test.ts.snap +9 -0
- package/test/__snapshots__/templates-module.test.ts.snap +17 -0
- package/test/__snapshots__/templates-packed-entity.test.ts.snap +5 -0
- package/test/__snapshots__/templates-resource.test.ts.snap +7 -0
- package/test/base64url.test.ts +33 -0
- package/test/codec.test.ts +43 -0
- package/test/errors.test.ts +24 -0
- package/test/fixtures/cargo-items.ts +122 -0
- package/test/fonts.test.ts +28 -0
- package/test/links-meta.test.ts +34 -0
- package/test/pixel.test.ts +66 -0
- package/test/primitives-category-icon.test.ts +79 -0
- package/test/primitives-compact-row.test.ts +44 -0
- package/test/primitives-domain.test.ts +72 -0
- package/test/primitives-layout.test.ts +56 -0
- package/test/primitives-module-slot.test.ts +88 -0
- package/test/render.test.ts +40 -0
- package/test/sanity.test.ts +6 -0
- package/test/sdk-link.test.ts +19 -0
- package/test/snapshots/.gitkeep +0 -0
- package/test/svg.test.ts +28 -0
- package/test/templates-component.test.ts +36 -0
- package/test/templates-dispatch.test.ts +35 -0
- package/test/templates-item-cell.test.ts +94 -0
- package/test/templates-module.test.ts +63 -0
- package/test/templates-packed-entity.test.ts +47 -0
- package/test/templates-resource.test.ts +71 -0
- package/test/templates-ship-panel.test.ts +87 -0
- package/test/tokens.test.ts +32 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { ResourceTier, TextSpan } from '@shipload/sdk'
|
|
2
|
+
import { panel } from '../primitives/panel.ts'
|
|
3
|
+
import { iconHex } from '../primitives/icon-hex.ts'
|
|
4
|
+
import { text } from '../primitives/text.ts'
|
|
5
|
+
import { divider } from '../primitives/divider.ts'
|
|
6
|
+
import { moduleSlot } from '../primitives/module-slot.ts'
|
|
7
|
+
import { quantityBadge } from '../primitives/quantity-badge.ts'
|
|
8
|
+
import { wrapText } from '../primitives/wrap.ts'
|
|
9
|
+
import { tokens } from '../tokens/index.ts'
|
|
10
|
+
|
|
11
|
+
export interface ShipPanelSlot {
|
|
12
|
+
name?: string
|
|
13
|
+
installed: boolean
|
|
14
|
+
description?: string | TextSpan[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ShipPanelProps {
|
|
18
|
+
name: string
|
|
19
|
+
tier: ResourceTier
|
|
20
|
+
quantity?: number
|
|
21
|
+
attributes: { capability: string; attributes: { label: string; value: number }[] }[]
|
|
22
|
+
slots: ShipPanelSlot[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function formatNumber(n: number): string {
|
|
26
|
+
return n.toLocaleString('en-US')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function tierBorder(tier: string): string {
|
|
30
|
+
const key = tier.toLowerCase() as keyof typeof tokens.colors.tier
|
|
31
|
+
return tokens.colors.tier[key] ?? tokens.colors.surface.panelBorder
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const MODULE_LABEL_PREFIX = (capability: string) => `${capability}: `
|
|
35
|
+
|
|
36
|
+
function rowHeightFor(slot: ShipPanelSlot): number {
|
|
37
|
+
if (!slot.installed) return 24
|
|
38
|
+
const desc = slot.description
|
|
39
|
+
const plain =
|
|
40
|
+
typeof desc === 'string'
|
|
41
|
+
? desc
|
|
42
|
+
: Array.isArray(desc)
|
|
43
|
+
? desc.map((s) => s.text).join('')
|
|
44
|
+
: ''
|
|
45
|
+
if (plain.length === 0) return 24
|
|
46
|
+
const combined = MODULE_LABEL_PREFIX(slot.name ?? 'Module') + plain
|
|
47
|
+
const lineCount = Math.max(1, wrapText({ value: combined, charsPerLine: 36 }).length)
|
|
48
|
+
return 10 + lineCount * 14
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function renderShipPanel(props: ShipPanelProps): string {
|
|
52
|
+
const w = tokens.spacing.panelWidth
|
|
53
|
+
const pad = tokens.spacing.panelPadding
|
|
54
|
+
const innerW = w - pad * 2
|
|
55
|
+
const quantity = props.quantity ?? 0
|
|
56
|
+
|
|
57
|
+
const hullGroup = props.attributes?.find((g) => g.capability.toLowerCase() === 'hull')
|
|
58
|
+
const hullRows = hullGroup?.attributes ?? []
|
|
59
|
+
|
|
60
|
+
const headerH = 48
|
|
61
|
+
const hullHeaderH = 20
|
|
62
|
+
const hullRowH = 22
|
|
63
|
+
const sectionGap = 12
|
|
64
|
+
const rowHeights = props.slots.map(rowHeightFor)
|
|
65
|
+
const modulesHeight = rowHeights.reduce((a, b) => a + b, 0)
|
|
66
|
+
const height =
|
|
67
|
+
headerH +
|
|
68
|
+
hullHeaderH +
|
|
69
|
+
hullRows.length * hullRowH +
|
|
70
|
+
sectionGap +
|
|
71
|
+
modulesHeight +
|
|
72
|
+
pad
|
|
73
|
+
|
|
74
|
+
const chrome = panel({ width: w, height, borderColor: tierBorder(props.tier) })
|
|
75
|
+
|
|
76
|
+
const icon = iconHex({
|
|
77
|
+
x: pad,
|
|
78
|
+
y: pad + 4,
|
|
79
|
+
color: tokens.colors.text.accent,
|
|
80
|
+
code: 'SH',
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const name = text({
|
|
84
|
+
x: pad + 34,
|
|
85
|
+
y: pad + 22,
|
|
86
|
+
value: props.name,
|
|
87
|
+
size: tokens.typography.sizes.title,
|
|
88
|
+
weight: 700,
|
|
89
|
+
family: tokens.typography.display,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const badge = quantityBadge({ x: w - pad, y: pad, quantity })
|
|
93
|
+
|
|
94
|
+
const hullHeader = text({
|
|
95
|
+
x: pad,
|
|
96
|
+
y: pad + headerH,
|
|
97
|
+
value: 'HULL',
|
|
98
|
+
size: tokens.typography.sizes.subtitle,
|
|
99
|
+
weight: 700,
|
|
100
|
+
color: tokens.colors.text.secondary,
|
|
101
|
+
letterSpacing: 1,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
let y = pad + headerH + 6
|
|
105
|
+
let hullSvg = ''
|
|
106
|
+
for (const row of hullRows) {
|
|
107
|
+
hullSvg +=
|
|
108
|
+
text({
|
|
109
|
+
x: pad,
|
|
110
|
+
y: y + 12,
|
|
111
|
+
value: row.label,
|
|
112
|
+
size: tokens.typography.sizes.body,
|
|
113
|
+
color: tokens.colors.text.secondary,
|
|
114
|
+
}) +
|
|
115
|
+
text({
|
|
116
|
+
x: w - pad,
|
|
117
|
+
y: y + 12,
|
|
118
|
+
value: formatNumber(row.value),
|
|
119
|
+
size: tokens.typography.sizes.body,
|
|
120
|
+
weight: 700,
|
|
121
|
+
anchor: 'end',
|
|
122
|
+
}) +
|
|
123
|
+
divider({ x: pad, y: y + hullRowH - 4, width: innerW, color: tokens.colors.surface.panelBorderBright })
|
|
124
|
+
y += hullRowH
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
y += sectionGap
|
|
128
|
+
let modulesSvg = ''
|
|
129
|
+
for (let i = 0; i < props.slots.length; i++) {
|
|
130
|
+
const slot = props.slots[i]!
|
|
131
|
+
modulesSvg += moduleSlot({
|
|
132
|
+
x: pad,
|
|
133
|
+
y,
|
|
134
|
+
width: innerW,
|
|
135
|
+
installed: slot.installed,
|
|
136
|
+
capability: slot.name,
|
|
137
|
+
description: slot.description,
|
|
138
|
+
accentColor: tokens.colors.brand.teal,
|
|
139
|
+
})
|
|
140
|
+
y += rowHeights[i]!
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const inner = `${chrome}${icon}${name}${badge}${hullHeader}${hullSvg}${modulesSvg}`
|
|
144
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${height}" viewBox="0 0 ${w} ${height}">${inner}</svg>`
|
|
145
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { tierColors } from '@shipload/sdk'
|
|
2
|
+
|
|
3
|
+
export const colors = {
|
|
4
|
+
surface: {
|
|
5
|
+
background: '#0a0a0c',
|
|
6
|
+
panel: '#11141a',
|
|
7
|
+
panelBorder: '#1e242e',
|
|
8
|
+
panelBorderBright: '#2a3340',
|
|
9
|
+
},
|
|
10
|
+
text: {
|
|
11
|
+
primary: '#e6e8ec',
|
|
12
|
+
secondary: '#8f98a8',
|
|
13
|
+
muted: '#5b6373',
|
|
14
|
+
accent: '#f4c96b',
|
|
15
|
+
},
|
|
16
|
+
brand: {
|
|
17
|
+
pink: '#ff4f9a',
|
|
18
|
+
teal: '#2fd6d1',
|
|
19
|
+
cyan: '#6cb9ff',
|
|
20
|
+
},
|
|
21
|
+
category: {
|
|
22
|
+
metal: '#b5b9c2',
|
|
23
|
+
gas: '#6cb9ff',
|
|
24
|
+
mineral: '#b38aff',
|
|
25
|
+
organic: '#58d08c',
|
|
26
|
+
precious: '#f4c96b',
|
|
27
|
+
},
|
|
28
|
+
tier: tierColors,
|
|
29
|
+
accent: {
|
|
30
|
+
component: '#8f98a8',
|
|
31
|
+
},
|
|
32
|
+
capability: {
|
|
33
|
+
engine: '#4a8abf',
|
|
34
|
+
generator: '#22c55e',
|
|
35
|
+
gatherer: '#f59e0b',
|
|
36
|
+
loader: '#eab308',
|
|
37
|
+
manufacturing: '#a855f7',
|
|
38
|
+
storage: '#14b8a6',
|
|
39
|
+
hauler: '#f97316',
|
|
40
|
+
},
|
|
41
|
+
} as const
|
|
42
|
+
|
|
43
|
+
export type CategoryColorKey = keyof typeof colors.category
|
|
44
|
+
export type TierColorKey = keyof typeof colors.tier
|
|
45
|
+
export type CapabilityColorKey = keyof typeof colors.capability
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { colors } from './colors.ts'
|
|
2
|
+
import { spacing } from './spacing.ts'
|
|
3
|
+
import { typography } from './typography.ts'
|
|
4
|
+
|
|
5
|
+
export const tokens = { colors, spacing, typography } as const
|
|
6
|
+
export type Tokens = typeof tokens
|
|
7
|
+
export { colors, spacing, typography }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const typography = {
|
|
2
|
+
display: '"Orbitron", "Orbitron Variable", system-ui, sans-serif',
|
|
3
|
+
sans: '"Inter", "Inter Variable", system-ui, sans-serif',
|
|
4
|
+
mono: '"JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace',
|
|
5
|
+
sizes: {
|
|
6
|
+
title: 16,
|
|
7
|
+
subtitle: 11,
|
|
8
|
+
body: 12,
|
|
9
|
+
stat: 12,
|
|
10
|
+
statValue: 14,
|
|
11
|
+
label: 10,
|
|
12
|
+
caption: 10,
|
|
13
|
+
},
|
|
14
|
+
weights: {
|
|
15
|
+
regular: 400,
|
|
16
|
+
semibold: 600,
|
|
17
|
+
bold: 700,
|
|
18
|
+
},
|
|
19
|
+
} as const
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
|
+
|
|
3
|
+
exports[`matches the committed Hull Plates snapshot: component-hull-plates.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="164" viewBox="0 0 280 164"><rect x="0.5" y="0.5" width="279" height="163" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#8f98a8" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#8f98a8" text-anchor="middle">01</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Hull Plates</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">COMPONENT · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">50,000</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="108" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">STR</text><text x="36" y="108" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Strength</text><text x="266" y="108" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="14" font-weight="700" fill="#5B9BD5" text-anchor="end">745</text><rect x="14" y="114" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><rect x="14" y="114" width="183" height="4" rx="2" ry="2" fill="#5B9BD5"/><text x="14" y="134" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">DEN</text><text x="36" y="134" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Density</text><text x="266" y="134" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="14" font-weight="700" fill="#5B9BD5" text-anchor="end">330</text><rect x="14" y="140" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><rect x="14" y="140" width="170" height="4" rx="2" ry="2" fill="#5B9BD5"/></svg>"`;
|
|
4
|
+
|
|
5
|
+
exports[`renderComponent ranges mode matches snapshot: component-ranges 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="164" viewBox="0 0 280 164"><rect x="0.5" y="0.5" width="279" height="163" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#8f98a8" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#8f98a8" text-anchor="middle">01</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Hull Plates</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">COMPONENT · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">50,000</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="108" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">STR</text><text x="36" y="108" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Strength</text><rect x="14" y="114" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><text x="14" y="134" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">DEN</text><text x="36" y="134" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Density</text><rect x="14" y="140" width="252" height="4" rx="2" ry="2" fill="#1e242e"/></svg>"`;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
|
+
|
|
3
|
+
exports[`matches golden SVG snapshot per itemType: item-cell-resource 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="48" height="60" viewBox="0 0 48 60"><rect x="0.5" y="0.5" width="47" height="59" rx="6" ry="6" fill="#11141a" stroke="#8b8b8b" stroke-width="1.5"/><polygon points="24.00,11.52 30.65,15.36 30.65,23.04 24.00,26.88 17.35,23.04 17.35,15.36" fill="none" stroke="#5B9BD5" stroke-width="1.5" stroke-linejoin="round"/><text x="42" y="54" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#e6e8ec" text-anchor="end">3</text></svg>"`;
|
|
4
|
+
|
|
5
|
+
exports[`matches golden SVG snapshot per itemType: item-cell-component 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="48" height="60" viewBox="0 0 48 60"><rect x="0.5" y="0.5" width="47" height="59" rx="6" ry="6" fill="#11141a" stroke="#8b8b8b" stroke-width="1.5"/><text x="24" y="21.6" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="13" font-weight="700" fill="#e6e8ec" text-anchor="middle">HP</text><text x="42" y="54" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#e6e8ec" text-anchor="end">3</text></svg>"`;
|
|
6
|
+
|
|
7
|
+
exports[`matches golden SVG snapshot per itemType: item-cell-module 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="48" height="60" viewBox="0 0 48 60"><rect x="0.5" y="0.5" width="47" height="59" rx="6" ry="6" fill="#11141a" stroke="#8b8b8b" stroke-width="1.5"/><text x="24" y="21.6" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="13" font-weight="700" fill="#e6e8ec" text-anchor="middle">EN</text><text x="42" y="54" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#e6e8ec" text-anchor="end">3</text></svg>"`;
|
|
8
|
+
|
|
9
|
+
exports[`matches golden SVG snapshot per itemType: item-cell-entity 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="48" height="60" viewBox="0 0 48 60"><rect x="0.5" y="0.5" width="47" height="59" rx="6" ry="6" fill="#11141a" stroke="#8b8b8b" stroke-width="1.5"/><text x="24" y="21.6" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="13" font-weight="700" fill="#e6e8ec" text-anchor="middle">SH</text><text x="42" y="54" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#e6e8ec" text-anchor="end">3</text></svg>"`;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
|
+
|
|
3
|
+
exports[`matches the committed engineT1 snapshot: module-engineT1.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="174" viewBox="0 0 280 174"><rect x="0.5" y="0.5" width="279" height="173" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#4a8abf" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#4a8abf" text-anchor="middle">00</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Engine</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">MODULE · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">0</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="112" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#4a8abf" letter-spacing="1">ENGINE</text><text x="14" y="132" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">generates </tspan><tspan fill="#f4c96b">700</tspan><tspan fill="#8f98a8"> thrust for travel</tspan></text><text x="14" y="146" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">while draining </tspan><tspan fill="#f4c96b">45</tspan><tspan fill="#8f98a8"> energy per</tspan></text><text x="14" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">distance travelled</tspan></text></svg>"`;
|
|
4
|
+
|
|
5
|
+
exports[`matches the committed generatorT1 snapshot: module-generatorT1.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="174" viewBox="0 0 280 174"><rect x="0.5" y="0.5" width="279" height="173" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#22c55e" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#22c55e" text-anchor="middle">01</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Generator</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">MODULE · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">0</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="112" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#22c55e" letter-spacing="1">GENERATOR</text><text x="14" y="132" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">holds </tspan><tspan fill="#f4c96b">450</tspan><tspan fill="#8f98a8"> maximum energy and</tspan></text><text x="14" y="146" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">restores </tspan><tspan fill="#f4c96b">3</tspan><tspan fill="#8f98a8"> per second while</tspan></text><text x="14" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">recharging</tspan></text></svg>"`;
|
|
6
|
+
|
|
7
|
+
exports[`matches the committed gathererT1 snapshot: module-gathererT1.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="188" viewBox="0 0 280 188"><rect x="0.5" y="0.5" width="279" height="187" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#f59e0b" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#f59e0b" text-anchor="middle">02</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Gatherer</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">MODULE · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">0</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="112" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#f59e0b" letter-spacing="1">GATHERER</text><text x="14" y="132" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">mines resources at </tspan><tspan fill="#f4c96b">600</tspan><tspan fill="#8f98a8"> speed to a</tspan></text><text x="14" y="146" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">max depth of </tspan><tspan fill="#f4c96b">350</tspan><tspan fill="#8f98a8"> with </tspan><tspan fill="#f4c96b">200</tspan><tspan fill="#8f98a8"> gather</tspan></text><text x="14" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">speed while draining </tspan><tspan fill="#f4c96b">300</tspan><tspan fill="#8f98a8"> energy per</tspan></text><text x="14" y="174" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">second</tspan></text></svg>"`;
|
|
8
|
+
|
|
9
|
+
exports[`matches the committed loaderT1 snapshot: module-loaderT1.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="160" viewBox="0 0 280 160"><rect x="0.5" y="0.5" width="279" height="159" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#eab308" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#eab308" text-anchor="middle">03</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Loader</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">MODULE · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">0</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="112" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#eab308" letter-spacing="1">LOADER</text><text x="14" y="132" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#f4c96b">1</tspan><tspan fill="#8f98a8"> loader that generates </tspan><tspan fill="#f4c96b">2</tspan><tspan fill="#8f98a8"> thrust</tspan></text><text x="14" y="146" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">with a weight of </tspan><tspan fill="#f4c96b">500</tspan><tspan fill="#8f98a8"> per unit</tspan></text></svg>"`;
|
|
10
|
+
|
|
11
|
+
exports[`matches the committed crafterT1 snapshot: module-crafterT1.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="160" viewBox="0 0 280 160"><rect x="0.5" y="0.5" width="279" height="159" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#a855f7" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#a855f7" text-anchor="middle">04</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Manufacturing</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">MODULE · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">0</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="112" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#a855f7" letter-spacing="1">MANUFACTURING</text><text x="14" y="132" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">manufactures items at </tspan><tspan fill="#f4c96b">580</tspan><tspan fill="#8f98a8"> speed</tspan></text><text x="14" y="146" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">while draining </tspan><tspan fill="#f4c96b">15</tspan><tspan fill="#8f98a8"> energy per second</tspan></text></svg>"`;
|
|
12
|
+
|
|
13
|
+
exports[`matches the committed storageT1 snapshot: module-storageT1.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="146" viewBox="0 0 280 146"><rect x="0.5" y="0.5" width="279" height="145" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#14b8a6" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#14b8a6" text-anchor="middle">05</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Storage</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">MODULE · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">0</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="112" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#14b8a6" letter-spacing="1">STORAGE</text><text x="14" y="132" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">boosts cargo capacity by </tspan><tspan fill="#f4c96b">17</tspan><tspan fill="#8f98a8">%</tspan></text></svg>"`;
|
|
14
|
+
|
|
15
|
+
exports[`matches the committed haulerT1 snapshot: module-haulerT1.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="174" viewBox="0 0 280 174"><rect x="0.5" y="0.5" width="279" height="173" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#f97316" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#f97316" text-anchor="middle">06</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Hauler Module T1</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">MODULE · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">0</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="112" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#f97316" letter-spacing="1">HAULER</text><text x="14" y="132" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">locks onto up to </tspan><tspan fill="#f4c96b">2</tspan><tspan fill="#8f98a8"> targets at </tspan><tspan fill="#f4c96b">2,192</tspan></text><text x="14" y="146" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">efficiency while draining </tspan><tspan fill="#f4c96b">15</tspan><tspan fill="#8f98a8"> energy</tspan></text><text x="14" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">per distance travelled per target</tspan></text></svg>"`;
|
|
16
|
+
|
|
17
|
+
exports[`renderModule ranges mode matches snapshot: module-ranges 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="132" viewBox="0 0 280 132"><rect x="0.5" y="0.5" width="279" height="131" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#4a8abf" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#4a8abf" text-anchor="middle">00</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Engine</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Type</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">MODULE · T1</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">0</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="112" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#4a8abf" letter-spacing="1">ENGINE</text></svg>"`;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
|
+
|
|
3
|
+
exports[`matches the committed Ship T1 (two modules) snapshot: packed-entity-ship-t1-two-modules.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="314" viewBox="0 0 280 314"><rect x="0.5" y="0.5" width="279" height="313" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#f4c96b" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#f4c96b" text-anchor="middle">SH</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Ship T1 (Packed)</text><text x="14" y="62" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#8f98a8" letter-spacing="1">HULL</text><text x="14" y="80" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="80" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="700" fill="#e6e8ec" text-anchor="end">25,000</text><line x1="14" x2="266" y1="86" y2="86" stroke="#2a3340" stroke-width="1"/><text x="14" y="102" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Capacity</text><text x="266" y="102" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="700" fill="#e6e8ec" text-anchor="end">1,000,000</text><line x1="14" x2="266" y1="108" y2="108" stroke="#2a3340" stroke-width="1"/><polygon points="20,125 25,130 20,135 15,130" fill="#2fd6d1"/><text x="34" y="133" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan font-weight="600" fill="#e6e8ec">Engine: </tspan><tspan fill="#8f98a8">generates </tspan><tspan fill="#f4c96b">598</tspan><tspan fill="#8f98a8"> thrust for</tspan></text><text x="34" y="147" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">travel while draining </tspan><tspan fill="#f4c96b">47</tspan><tspan fill="#8f98a8"> energy per</tspan></text><text x="34" y="161" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">distance travelled</tspan></text><polygon points="20,177 25,182 20,187 15,182" fill="#2fd6d1"/><text x="34" y="185" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan font-weight="600" fill="#e6e8ec">Generator: </tspan><tspan fill="#8f98a8">holds </tspan><tspan fill="#f4c96b">456</tspan><tspan fill="#8f98a8"> maximum energy</tspan></text><text x="34" y="199" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">and restores </tspan><tspan fill="#f4c96b">3</tspan><tspan fill="#8f98a8"> per second while</tspan></text><text x="34" y="213" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">recharging</tspan></text><polygon points="20,229 25,234 20,239 15,234" fill="none" stroke="#2a3340" stroke-width="1"/><text x="34" y="237" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#5b6373">Empty module</text><polygon points="20,253 25,258 20,263 15,258" fill="none" stroke="#2a3340" stroke-width="1"/><text x="34" y="261" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#5b6373">Empty module</text><polygon points="20,277 25,282 20,287 15,282" fill="none" stroke="#2a3340" stroke-width="1"/><text x="34" y="285" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#5b6373">Empty module</text></svg>"`;
|
|
4
|
+
|
|
5
|
+
exports[`matches the committed Ship T1 (only engine) snapshot: packed-entity-ship-t1-only-engine.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="286" viewBox="0 0 280 286"><rect x="0.5" y="0.5" width="279" height="285" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#f4c96b" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#f4c96b" text-anchor="middle">SH</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Ship T1 (Packed)</text><text x="14" y="62" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="11" font-weight="700" fill="#8f98a8" letter-spacing="1">HULL</text><text x="14" y="80" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="80" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="700" fill="#e6e8ec" text-anchor="end">25,000</text><line x1="14" x2="266" y1="86" y2="86" stroke="#2a3340" stroke-width="1"/><text x="14" y="102" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Capacity</text><text x="266" y="102" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="700" fill="#e6e8ec" text-anchor="end">1,000,000</text><line x1="14" x2="266" y1="108" y2="108" stroke="#2a3340" stroke-width="1"/><polygon points="20,125 25,130 20,135 15,130" fill="#2fd6d1"/><text x="34" y="133" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan font-weight="600" fill="#e6e8ec">Engine: </tspan><tspan fill="#8f98a8">generates </tspan><tspan fill="#f4c96b">598</tspan><tspan fill="#8f98a8"> thrust for</tspan></text><text x="34" y="147" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">travel while draining </tspan><tspan fill="#f4c96b">47</tspan><tspan fill="#8f98a8"> energy per</tspan></text><text x="34" y="161" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12"><tspan fill="#8f98a8">distance travelled</tspan></text><polygon points="20,177 25,182 20,187 15,182" fill="none" stroke="#2a3340" stroke-width="1"/><text x="34" y="185" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#5b6373">Empty module</text><polygon points="20,201 25,206 20,211 15,206" fill="none" stroke="#2a3340" stroke-width="1"/><text x="34" y="209" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#5b6373">Empty module</text><polygon points="20,225 25,230 20,235 15,230" fill="none" stroke="#2a3340" stroke-width="1"/><text x="34" y="233" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#5b6373">Empty module</text><polygon points="20,249 25,254 20,259 15,254" fill="none" stroke="#2a3340" stroke-width="1"/><text x="34" y="257" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#5b6373">Empty module</text></svg>"`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
2
|
+
|
|
3
|
+
exports[`matches the committed Iron snapshot: resource-iron.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="190" viewBox="0 0 280 190"><rect x="0.5" y="0.5" width="279" height="189" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#b5b9c2" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#b5b9c2" text-anchor="middle">26</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Iron</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Category</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">Metals</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">30,000</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="108" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">STR</text><text x="36" y="108" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Strength</text><text x="266" y="108" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="14" font-weight="700" fill="#5B9BD5" text-anchor="end">959</text><rect x="14" y="114" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><rect x="14" y="114" width="236" height="4" rx="2" ry="2" fill="#5B9BD5"/><text x="14" y="134" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">TOL</text><text x="36" y="134" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Tolerance</text><text x="266" y="134" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="14" font-weight="700" fill="#5B9BD5" text-anchor="end">340</text><rect x="14" y="140" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><rect x="14" y="140" width="83" height="4" rx="2" ry="2" fill="#5B9BD5"/><text x="14" y="160" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">DEN</text><text x="36" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Density</text><text x="266" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="14" font-weight="700" fill="#5B9BD5" text-anchor="end">59</text><rect x="14" y="166" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><rect x="14" y="166" width="237" height="4" rx="2" ry="2" fill="#5B9BD5"/></svg>"`;
|
|
4
|
+
|
|
5
|
+
exports[`matches the committed Helium snapshot: resource-helium.svg 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="190" viewBox="0 0 280 190"><rect x="0.5" y="0.5" width="279" height="189" rx="10" ry="10" fill="#11141a" stroke="#4ade80" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#6cb9ff" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#6cb9ff" text-anchor="middle">02</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Helium</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Category</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">Gas</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">2,000</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="108" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#7EC8E3">VOL</text><text x="36" y="108" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Volatility</text><text x="266" y="108" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="14" font-weight="700" fill="#7EC8E3" text-anchor="end">898</text><rect x="14" y="114" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><rect x="14" y="114" width="221" height="4" rx="2" ry="2" fill="#7EC8E3"/><text x="14" y="134" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#7EC8E3">REA</text><text x="36" y="134" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Reactivity</text><text x="266" y="134" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="14" font-weight="700" fill="#7EC8E3" text-anchor="end">728</text><rect x="14" y="140" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><rect x="14" y="140" width="179" height="4" rx="2" ry="2" fill="#7EC8E3"/><text x="14" y="160" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#7EC8E3">THM</text><text x="36" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Thermal</text><text x="266" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="14" font-weight="700" fill="#7EC8E3" text-anchor="end">399</text><rect x="14" y="166" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><rect x="14" y="166" width="98" height="4" rx="2" ry="2" fill="#7EC8E3"/></svg>"`;
|
|
6
|
+
|
|
7
|
+
exports[`renderResource ranges mode matches snapshot: resource-ranges 1`] = `"<svg xmlns="http://www.w3.org/2000/svg" width="280" height="190" viewBox="0 0 280 190"><rect x="0.5" y="0.5" width="279" height="189" rx="10" ry="10" fill="#11141a" stroke="#8b8b8b" stroke-width="1"/><polygon points="14.0,29.0 20.4,18.0 33.1,18.0 39.4,29.0 33.1,40.0 20.4,40.0" fill="none" stroke="#b5b9c2" stroke-width="1.5"/><text x="26.701700000000002" y="32" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="9" font-weight="700" fill="#b5b9c2" text-anchor="middle">26</text><text x="48" y="36" font-family=""Orbitron", "Orbitron Variable", system-ui, sans-serif" font-size="16" font-weight="700" fill="#e6e8ec">Iron</text><text x="14" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Category</text><text x="266" y="66" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">Metals</text><text x="14" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#8f98a8">Mass</text><text x="266" y="82" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="600" fill="#e6e8ec" text-anchor="end">30,000</text><line x1="14" x2="266" y1="96" y2="96" stroke="#1e242e" stroke-width="1"/><text x="14" y="108" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">STR</text><text x="36" y="108" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Strength</text><rect x="14" y="114" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><text x="14" y="134" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">TOL</text><text x="36" y="134" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Tolerance</text><rect x="14" y="140" width="252" height="4" rx="2" ry="2" fill="#1e242e"/><text x="14" y="160" font-family=""JetBrains Mono", "JetBrains Mono Variable", ui-monospace, monospace" font-size="10" font-weight="700" fill="#5B9BD5">DEN</text><text x="36" y="160" font-family=""Inter", "Inter Variable", system-ui, sans-serif" font-size="12" font-weight="400" fill="#e6e8ec">Density</text><rect x="14" y="166" width="252" height="4" rx="2" ry="2" fill="#1e242e"/></svg>"`;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import { bytesToBase64Url, base64UrlToBytes } from '../src/payload/base64url.ts'
|
|
3
|
+
import { InvalidPayloadError } from '../src/errors.ts'
|
|
4
|
+
|
|
5
|
+
test('round-trips arbitrary bytes', () => {
|
|
6
|
+
const inputs = [
|
|
7
|
+
new Uint8Array([0]),
|
|
8
|
+
new Uint8Array([255]),
|
|
9
|
+
new Uint8Array([0, 1, 2, 3, 4, 5]),
|
|
10
|
+
new Uint8Array(Array.from({ length: 256 }, (_, i) => i)),
|
|
11
|
+
]
|
|
12
|
+
for (const input of inputs) {
|
|
13
|
+
const encoded = bytesToBase64Url(input)
|
|
14
|
+
const decoded = base64UrlToBytes(encoded)
|
|
15
|
+
expect(decoded).toEqual(input)
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('produces only URL-safe characters — no +, /, =', () => {
|
|
20
|
+
const bytes = new Uint8Array(Array.from({ length: 256 }, (_, i) => i))
|
|
21
|
+
const encoded = bytesToBase64Url(bytes)
|
|
22
|
+
expect(encoded).toMatch(/^[A-Za-z0-9_-]+$/)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('rejects malformed base64url with InvalidPayloadError', () => {
|
|
26
|
+
expect(() => base64UrlToBytes('!!!not-base64!!!')).toThrow(InvalidPayloadError)
|
|
27
|
+
expect(() => base64UrlToBytes('has spaces')).toThrow(InvalidPayloadError)
|
|
28
|
+
expect(() => base64UrlToBytes('with+plus/slash')).toThrow(InvalidPayloadError)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('accepts known-good short string', () => {
|
|
32
|
+
expect(base64UrlToBytes('AAA')).toEqual(new Uint8Array([0, 0]))
|
|
33
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import { encodePayload, decodePayload } from '../src/payload/codec.ts'
|
|
3
|
+
import { InvalidPayloadError } from '../src/errors.ts'
|
|
4
|
+
import { FIXTURES } from './fixtures/cargo-items.ts'
|
|
5
|
+
|
|
6
|
+
test('round-trips every fixture exactly', () => {
|
|
7
|
+
for (const [name, item] of Object.entries(FIXTURES)) {
|
|
8
|
+
const encoded = encodePayload(item)
|
|
9
|
+
const decoded = decodePayload(encoded)
|
|
10
|
+
expect(
|
|
11
|
+
decoded.item_id.equals(item.item_id),
|
|
12
|
+
`${name} item_id`,
|
|
13
|
+
).toBe(true)
|
|
14
|
+
expect(
|
|
15
|
+
decoded.quantity.equals(item.quantity),
|
|
16
|
+
`${name} quantity`,
|
|
17
|
+
).toBe(true)
|
|
18
|
+
expect(
|
|
19
|
+
decoded.stats.equals(item.stats),
|
|
20
|
+
`${name} stats`,
|
|
21
|
+
).toBe(true)
|
|
22
|
+
expect(decoded.modules.length, `${name} modules length`).toBe(item.modules.length)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('encoded payload is URL-safe', () => {
|
|
27
|
+
for (const item of Object.values(FIXTURES)) {
|
|
28
|
+
const encoded = encodePayload(item)
|
|
29
|
+
expect(encoded).toMatch(/^[A-Za-z0-9_-]+$/)
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('decodePayload throws InvalidPayloadError on malformed input', () => {
|
|
34
|
+
expect(() => decodePayload('!!!')).toThrow(InvalidPayloadError)
|
|
35
|
+
expect(() => decodePayload('AAA')).toThrow(InvalidPayloadError)
|
|
36
|
+
expect(() => decodePayload('')).toThrow(InvalidPayloadError)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('payload sizes are within expected ranges', () => {
|
|
40
|
+
expect(encodePayload(FIXTURES.iron).length).toBeLessThan(30)
|
|
41
|
+
expect(encodePayload(FIXTURES.shipT1NoModules).length).toBeLessThan(30)
|
|
42
|
+
expect(encodePayload(FIXTURES.shipT1TwoModules).length).toBeLessThan(110)
|
|
43
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import { InvalidPayloadError, UnknownItemError, RenderError } from '../src/errors.ts'
|
|
3
|
+
|
|
4
|
+
test('InvalidPayloadError preserves the message and is an Error', () => {
|
|
5
|
+
const e = new InvalidPayloadError('bad base64')
|
|
6
|
+
expect(e).toBeInstanceOf(Error)
|
|
7
|
+
expect(e).toBeInstanceOf(InvalidPayloadError)
|
|
8
|
+
expect(e.message).toBe('bad base64')
|
|
9
|
+
expect(e.name).toBe('InvalidPayloadError')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('UnknownItemError carries the item id', () => {
|
|
13
|
+
const e = new UnknownItemError(9999)
|
|
14
|
+
expect(e).toBeInstanceOf(UnknownItemError)
|
|
15
|
+
expect(e.itemId).toBe(9999)
|
|
16
|
+
expect(e.message).toContain('9999')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('RenderError wraps a cause', () => {
|
|
20
|
+
const cause = new Error('inner')
|
|
21
|
+
const e = new RenderError('render failed', { cause })
|
|
22
|
+
expect(e).toBeInstanceOf(RenderError)
|
|
23
|
+
expect(e.cause).toBe(cause)
|
|
24
|
+
})
|