Контракт модуля
00 / Compo 0.00 protocol
CONSUMES
Compo0.Canvas
Compo0.ProtectedZones[]
Scene.occupiedGeometry[]
Point.functionalRole
Point.visualRoleCandidate
Point.roleRigidity
Point.visualWeightBase
Point.visualWeightContextual?@fresh
Compo1.06.Grid? / gridCandidates[]?
StylePreset.noise
Seed
PROVIDES
NoiseField
NoisePoint[]
NoiseField.targetCount
NoiseField.actualCount
NoiseField.allowedAreaN
NoiseField.diagnostics
NoiseField.localScore
OWNS METRICS
noise.count_fit
noise.spacing_distribution
noise.field_match
noise.soft_intrusion_penalty
noise.local_neighbor_pressure
noise.local_score
DEFERRED INPUTS
global.balance_score
global.negative_space_score
global.hierarchy_score
global.eye_flow_score
typography.protectedZones
image_semantics.protectedZones
Граница ответственности: Compo 1.08 не владеет глобальным clutter, hierarchy, negative space или balance. Он вычисляет только локальные свойства микроточечного поля. Если более высокий модуль требует чистой пустоты, итоговая плотность может быть снижена до нуля даже при идеальном локальном score.
Единицы плотности
01 / исправленная математика
AN
allowed normalized area
Разрешённая площадь в нормализованных координатах. Для всего холста A_N=1.
ρN
points / normalized area
Количество точек на одну полную нормализованную площадь холста.
N
target count
Целое число микроточек после учёта разрешённой площади и detail scale.
W,H = canvas size in px
A_canvas_px = W * H
A_allowed_px = area(usableCanvas - hardProtectedZones)
A_allowed_N = A_allowed_px / A_canvas_px
// dimensionless, range 0..1
rhoN = requested point count per normalized full-canvas area
// unit: points / normalized-area-unit
N_target = round(rhoN * A_allowed_N * detailScale)
where:
detailScale = STYLE_PRESET or output-context multiplier
default detailScale = 1.0
EXAMPLE:
W=1080, H=1350
A_allowed_px = 1,166,400 px²
A_canvas_px = 1,458,000 px²
A_allowed_N = 0.80
rhoN = 75
detailScale = 1.0
N_target = round(75 * 0.80) = 60
Исправление v2: нельзя смешивать px² и normalized area. Плотность хранится либо как rhoN в points / normalized-area-unit, либо отдельно как pointsPerMP. Внутри одного расчёта единицы не смешиваются.
| Preset | rhoN | Назначение | Статус |
| quiet | 8–24 | единичные технические маркеры | STYLE PRESET |
| editorial | 20–60 | лёгкое микрополе | STYLE PRESET |
| technical | 45–120 | вычислительная / схемная среда | STYLE PRESET |
| dense_field | 100–260 | активная точечная текстура | STYLE PRESET |
Диапазоны — стартовые пресеты, а не универсальные законы. Они должны калиброваться на корпусе реальных постеров.
Поле вероятности
02 / target intensity field
MH
hard mask
0 = запрещено; 1 = разрешено.
MS
soft mask
0..1 — плавное ослабление около защищённых зон.
Z
zone weight
Локальный коэффициент активности из текущего preset/scenario.
G
style field
Полоса, градиент, кластер, grid-jitter или другой стилевой паттерн.
All field values are dimensionless in [0,1].
F_raw(x,y) = M_H(x,y) * M_S(x,y) * Z(x,y) * G(x,y)
F_norm(x,y) = F_raw(x,y) / integralAllowed(F_raw)
Expected local count in region R:
E[N_R] = N_target * integral_R(F_norm)
IMPORTANT:
F_norm defines WHERE points should appear.
rhoN / N_target defines HOW MANY points should appear.
Do not use rhoN directly as an acceptance probability.
Исправление v2: старая схема P_accept = clamp(rho_base × masks, 0,1) смешивала «количество точек» и «вероятность». Теперь количество и пространственное распределение разделены.
Генерация кандидатов
03 / deterministic sampling
Pure random
Допустим только как намеренный chaos preset.
p = RNG(seed)
no distance control
clumps expected
Poisson-like
Базовый режим для свободного микрошумового поля.
accept p iff
M_H(p)=1
and d(p,q) ≥ rMin(p,q)
for accepted q nearby
Grid jitter
Для technical preset. Позиции наследуют grid, но получают bounded deviation.
p = gridNode + jitter
|jx| ≤ Jx
|jy| ≤ Jy
Compo1.06 owns grid-fit
DEFAULT PIPELINE
1. Build hard masks.
2. Build soft masks.
3. Compute A_allowed_N.
4. Compute N_target from rhoN.
5. Build normalized field F_norm(x,y).
6. Initialize seeded PRNG.
7. Generate weighted candidate pool from F_norm.
8. Hard reject protected candidates.
9. Apply minimum-neighbor-distance filter.
10. Stop when N_target reached OR attempt budget exhausted.
11. Assign radius / opacity / visual role constraints.
12. Compute LOCAL metrics only.
13. Correct underfilled / overfilled zones.
14. Send proposal to global solver.
15. Freeze only after global acceptance.
Performance: neighbor queries should use spatial hashing / uniform grid. Full O(N²) pair checks are unnecessary for production.
Зоны запрета и мягкого отвода
04 / protected semantics
Hard mask:
M_H(p) ∈ {0,1}
if M_H(p)=0 → candidate REJECT
Soft exclusion around protected geometry:
d = signedDistance(p, expandedProtectedGeometry)
M_S(p) = smoothstep(0, softMarginShortN, dShortN)
Suggested INITIAL_HEURISTIC margins:
text / microcopy: 0.012..0.035 of short side
dominant geometry: 0.010..0.030 of short side
identity-critical image zones: DEFERRED to image-semantics owner
Подчинённый визуальный вес
05 / role constraint, not hierarchy ownership
r
radiusShortN
0.0012–0.0045 как стартовый STYLE/HEURISTIC диапазон.
α
opacity
0.25–0.72 — STYLE_PRESET, не закон.
WB
base weight
Берётся из Compo 1.01; здесь не пересчитывается.
WC
contextual weight
Использовать только при @fresh; иначе базовый вес.
referenceWeight = minEffectiveWeight(semanticPointsNearby)
noiseWeight =
Point.visualWeightContextual @fresh
else Point.visualWeightBase
roleWeightRatio = noiseWeight / max(referenceWeight, EPS)
INITIAL_HEURISTIC:
preferred roleWeightRatio ≤ 0.45
soft violation 0.45..0.70
above 0.70 → reduce radius/opacity OR reclassify visualRoleCandidate
This is a LOCAL role-consistency constraint.
It is NOT global.hierarchy_score.
Compo 1.08 не имеет права вычислять собственный вариант global.hierarchy_score. Он лишь проверяет, не перестал ли объект, заявленный как noise, быть микрошумом по собственным локальным ограничениям роли.
Интерактивная лаборатория
06 / seeded field
Локальный scoring
07 / owned metrics only
Count + field match
noise.count_fit =
1 - clamp(abs(N_actual-N_target)/max(1,N_target), 0, 1)
For K spatial bins:
expected_k = N_target * integral_bin_k(F_norm)
observed_k = count(points in bin_k)
field_error =
sum(abs(observed_k-expected_k)) /
max(1, 2*N_target)
noise.field_match = 1-clamp(field_error,0,1)
Spacing distribution
d_i = nearestNeighborDistance(point_i)
hard condition:
d_i ≥ minGap_i
cv = std(d_i) / max(mean(d_i), EPS)
spacing_distribution =
scoreAgainstPreset(cv, StylePreset.noise.spacingProfile)
// exact target depends on style
Soft intrusion
soft_intrusion_penalty =
mean(1 - M_S(point_i))
hard violations are NOT a score:
if any M_H(point_i)==0:
candidate invalid
Neighbor pressure
pressure_i =
sum_j kernel(d_ij / minGap_i)
for d_ij < pressureRadius
noise.local_neighbor_pressure =
clamp(mean(pressure_i),0,1)
noise.local_score =
w_count * noise.count_fit
+ w_field * noise.field_match
+ w_spacing * noise.spacing_distribution
- w_soft * noise.soft_intrusion_penalty
- w_press * noise.local_neighbor_pressure
Weights = ENGINE_DEFAULT or STYLE_PRESET.
ANTI-DOUBLE-COUNTING:
Global solver may consume noise.local_score OR selected component metrics.
It must not sum local_score + all of its components again.
Corrective pass: underfilled zone → add candidates where observed < expected; overfilled zone → remove lowest-contribution points; excessive pressure → remove points from densest neighbor cells; protected-zone violation → reject candidate, never compensate with score.
Context interactions
08 / override graph
| Owner | Может изменить | Что Compo 1.08 делает после override |
| Global negative space | rhoN, active zones, вплоть до 0 | перегенерирует target count и поле |
| Global hierarchy | допустимый visual-weight envelope | уменьшает radius/opacity или reclassifies candidate |
| Typography | hard/soft protected zones | пересобирает masks |
| Image semantics | лица, логотипы, товарные protected zones | пересобирает masks |
| Compo 1.06 grid | допустимые grid-jitter candidates | читает grid evidence, но не пересчитывает grid-fit |
| Global balance | zone activity map | может перераспределить шум, не считая его полноценной балансирующей массой |
OVERRIDE PRIORITY
1. protected semantic HARD constraints
2. global composition
3. global hierarchy / negative-space intent
4. local noise constraints
5. style preset
6. seeded random variation
Randomness never overrides 1..5.
Статус чисел
09 / provenance
| Параметр | Класс | Комментарий |
| area normalization, Euclidean distance, counts | DERIVED | Геометрия/арифметика. |
rhoN preset ranges | STYLE PRESET | Калибруется по визуальному языку. |
| minGap, soft margins, role weight ratios | INITIAL HEURISTIC | Стартовые инженерные ограничения. |
| balance / negative-space / hierarchy / eye-flow | DEFERRED INPUT | Приходят от владельцев глобальных метрик. |
Детерминированные тесты
10 / regression suite
T01 · Density units
A_allowed_N = 0.80
rhoN = 75
detailScale = 1
EXPECTED:
N_target = 60
T02 · Seed repeatability
same input
same seed
same preset
EXPECTED:
NoisePoint[] identical
max coordinate delta = 0
T03 · Hard mask
candidate p inside hard zone
EXPECTED:
p rejected
NOT scored
surviving hard violations = 0
T04 · Global override
localScore = 0.91
global negative-space intent = CLEAN
EXPECTED:
rhoN may become 0
local evidence remains unchanged
T05 · Role mismatch
roleWeightRatio = 0.82
EXPECTED:
reduce radius/opacity
OR visualRole reclassify
NO global hierarchy recomputation
T06 · Anti double count
global receives local_score
and component metrics
EXPECTED:
validator requires aggregate OR components
never both
T07 · Unit invariance
same aspect + same masks
1080×1350 vs 2160×2700
same rhoN, detailScale=1
EXPECTED:
same N_target
normalized distribution equivalent
T08 · Grid owner
sampling=grid_jitter
EXPECTED:
Compo1.06.grid_fit consumed
NOT redefined here
T09 · Attempt budget
N_target impossible under minGap
EXPECTED:
return underfilled diagnostic
no infinite loop
no hard-rule violation
DATA FOR LAYOUT ENGINE
11 / machine contract · v2
{
"document_id": "Compo 1.08",
"version": "2.0",
"module": "decorative_and_computational_point_noise",
"scope": "micro-point field generation only",
"finality": "LOCAL_PROPOSAL_ONLY",
"consumes": [
"Compo0.Canvas",
"Compo0.ProtectedZones[]",
"Scene.occupiedGeometry[]",
"Point.functionalRole",
"Point.visualRoleCandidate",
"Point.roleRigidity",
"Point.visualWeightBase",
"Point.visualWeightContextual?@fresh",
"Compo1.06.Grid?",
"Compo1.06.GridCandidate[]?",
"StylePreset.noise",
"Seed"
],
"provides": [
"NoiseField",
"NoisePoint[]",
"NoiseField.targetCount",
"NoiseField.actualCount",
"NoiseField.allowedAreaN",
"NoiseField.localScore",
"NoiseField.diagnostics"
],
"owns_metrics": [
"noise.count_fit",
"noise.spacing_distribution",
"noise.field_match",
"noise.soft_intrusion_penalty",
"noise.local_neighbor_pressure",
"noise.local_score"
],
"metric_groups": {
"noise.local_score": {
"components": [
"noise.count_fit",
"noise.spacing_distribution",
"noise.field_match",
"noise.soft_intrusion_penalty",
"noise.local_neighbor_pressure"
],
"aggregation_rule": "consume aggregate OR components, never both"
}
},
"density_model": {
"allowedAreaN": "A_allowed_px / (W*H)",
"rhoN_unit": "points_per_normalized_canvas_area",
"targetCount": "round(rhoN * allowedAreaN * detailScale)",
"detailScale": {"default":1.0,"source":"STYLE_PRESET"}
},
"style_density_presets_rhoN": {
"quiet": [8,24],
"editorial": [20,60],
"technical": [45,120],
"dense_field": [100,260]
},
"initial_heuristics": {
"radiusShortN": [0.0012,0.0045],
"softMarginShortN": [0.010,0.035],
"preferredNoiseToSemanticWeightRatioMax": 0.45,
"softNoiseToSemanticWeightRatioMax": 0.70,
"attemptBudgetMultiplier": [20,80]
},
"hard_constraints": [
"no surviving noise point inside hard protected zone",
"seeded repeatability for identical inputs",
"finite generation attempt budget",
"no local ownership of global metrics"
],
"soft_constraints": [
"minimum_neighbor_distance",
"target_count_fit",
"target_field_match",
"soft_zone_avoidance",
"noise_role_weight_consistency"
],
"deferred_inputs": [
"global.balance_score",
"global.negative_space_score",
"global.hierarchy_score",
"global.eye_flow_score",
"typography.protectedZones",
"image_semantics.protectedZones"
],
"forbidden_metric_ownership": [
"global.balance_score",
"global.negative_space_score",
"global.hierarchy_score",
"global.eye_flow_score",
"grid.fit_score",
"point.visualWeightBase",
"point.visualWeightContextual"
],
"pipeline": [
"build_masks",
"compute_allowed_area",
"compute_target_count",
"build_normalized_field",
"generate_seeded_candidates",
"hard_filter",
"neighbor_distance_filter",
"assign_visual_parameters",
"compute_owned_metrics",
"corrective_pass",
"request_deferred_global_context",
"apply_global_override",
"freeze_after_acceptance"
],
"recompute_when": [
"protected zones change",
"rhoN or detailScale changes",
"style noise field changes",
"grid-jitter source changes",
"semantic point effective weight changes materially",
"global solver changes active zones"
]
}
Финальный чек-лист
12 / validation
- Плотность имеет одну явную единицу измерения.
A_allowed_N вычисляется через реальную площадь, затем нормализуется.
- Количество точек отделено от пространственного field.
- Hard protected zone не превращается в штраф — кандидат просто недопустим.
- Random воспроизводим через seed.
- Neighbor search имеет ограниченный attempt budget.
- Grid-fit читается из Compo 1.06 и не пересчитывается.
- Visual weight читается из Compo 1.01 и не пересчитывается.
- Global hierarchy / balance / negative-space не принадлежат этому модулю.
- Local score не суммируется повторно вместе со всеми компонентами.
- Если global solver требует чистого пространства,
rhoN=0 допустим.
- Все негеометрические пороги имеют HEURISTIC или STYLE_PRESET статус.