Help us shape the future of Go! Take the 2026 Go Developer Survey

worldchunk

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 16 Imported by: 0

README

Chunked world contract

world/chunks@1 keeps one complete compiled world in the root level and stores immutable render assets in independently fetched child KLD modules. It does not change compiled world versions 1–3, their bytes, or the 256-sector limit. Larger topology requires a separate versioned contract.

The root retains @world/main, authored contents, lighting, sector connections, shared albedo/material atlases and @world/chunks/catalog. The catalog contains global sector ownership, exact child SHA-256 and module byte size, packed mesh scalar size, decoded straight RGBA RNM image size, bounds and conservative candidate chunks for every sector. SDK 0.0.11 also stores BakedLights, the sorted unique union of authored source indexes from completed child prebakes. Hosts remove these sources from direct-light slots before any child is loaded. Every removed source must be steady, inside a physical component, and covered by baked descriptors throughout that component. Child metadata uses kartyWorldChunk, chunkID and geometrySha256; root metadata uses kartyWorldChunks. Child modules contain @world/chunks/mesh and, when enabled, the ordinary lightmap layout, completed prebake manifest and RNM QOI entries. Shared textures are referenced by their root material identity, without copies.

In the unreleased SDK 0.0.11 candidate, the catalog, mesh and shadow entries use fixed binary records. Earlier candidate JSON chunk payloads are rejected and must be rebuilt. TOML/YAML authoring and the established world, lightmap and level-envelope metadata formats retain their existing contracts.

world/chunk-ready@1 adds the compiler-authoritative @world/chunks/ready artifact (karty.world-chunk-ready@1, binary magic KCR1). It requires world/chunks@1; older SDK targets keep their existing semantic mesh path. Ready-enabled children contain final renderer streams without a duplicate semantic mesh entry. CompileReady packs already tessellated geometry offline into material batches, vertex/normal/UV streams, static tangent bases, RNM bindings, wave coordinates, stable surface IDs and semantic owner ranges. Liquid vertices remain authored rest positions; animation runs in the vertex shader. The catalog's MeshBytes retains its canonical 484 * triangle count reservation, using the final emitted triangle count; it does not become the Ready byte count.

For several chunks, call ReadySurfaces(meshes, document) once and pass its canonical table through ReadyOptions.Surfaces to every CompileReady call. ReadyOptions.Masked uses the world's canonical material order. A supplied table preserves its slot identities and must contain every source surface; missing or duplicate keys fail. Hosts retain that shared table across chunk residency changes, without remapping vertex arrays or growing material tables on reload. Nil Surfaces derives a local deterministic table for standalone use.

ReadyOptions.CleanupStatic optionally subtracts covered static faces from the final streams of one atomic streamed chunk. Only selected, co-resident owners in one unambiguous ordinary physical component participate. Only collidable solids act as occluders: noncolliding volumes can be entered. Packed solid facet halfspaces define a conservative inner volume; exact coplanar sector contact resolves same-facing solid duplicates. Opposing floor/wall contact faces on solids remain, preserving exterior views through backface-culled sector surfaces. Sector surfaces win same-facing duplicates, then lower authored solid indexes. This defines stable material ownership for previously ambiguous depth ties. Masked, liquid, animated and sky surfaces do not participate; actors never act as permanent occluders. Ambiguous scopes or unreliable numerical cuts retain their complete original surfaces. Positive gaps and nonresident occluders cannot create permanent holes.

Cleanup leaves the canonical semantic mesh and its digest unchanged. Full offline validation deterministically reconstructs the cuts and compares every output attribute. ReadyBatch.Sources indexes that derived triangle sequence, and the catalog reserves 484 * its length. New vertices interpolate the original UV, wave, band and RNM streams with their existing chart ownership. Fragmentation can increase triangle count, so builders enforce the configured budget after cleanup and repartition when possible; ErrReadyCapacity identifies format capacity limits. Hidden lightmap receivers and their bake allocation remain unchanged. Legacy output and non-streamed movable sector geometry use their existing path.

The asset pipeline proves source geometry and authored attributes before publishing a child and its catalog hash. Builders validate the semantic mesh and accepted RNM binding, then use DecodeReady/ValidateReady to check exact semantic-mesh digest, complete source coverage, packed attributes, material classifications, UV/basis bindings and displacement-expanded owner bounds. These complete offline proof APIs remain available and retain their checks. The MeshSHA256 header records build provenance; it does not require retaining or decoding the source mesh in the runtime artifact.

After verifying the complete child's exact catalog length and SHA-256, hosts call DecodeReadyArtifact with ReadyAdmission: parent material-slot count, sorted sector/solid owners, expected triangle count (MeshBytes / 484), lightmap presence and an optional already accepted canonical surface table. This checks bounded binary records and allocation counts, complete consumption, finite scalars, material/index/stream references, consistent per-triangle surface IDs, batch order/uniqueness, owner identity/range partitions and finite ordered owner bounds. It accepts compiler-authoritative geometry without repeating polygon coverage, triangulation, authored UV/normal reconstruction or vertex/bounds comparisons. Input descriptor values alone do not establish artifact integrity or producer correctness: the caller must perform the whole-child hash/size verification against its accepted parent first.

Runtime asset integrity is relative to the accepted root catalog; this does not introduce publisher signatures or claim arbitrary input was built correctly. The complete build proof belongs to the pipeline, while runtime structural and resource limits remain mandatory. Ready scalar data is bounded to 64 MiB, with the existing triangle, vertex, encoded-entry and child-module limits remaining in force. Image/layout dimensions and decoded resource bounds retain their own admission. This unpublished candidate changes no existing semantic mesh, catalog, shadow or compiled-world binary version.

Before instantiating a downloaded child, hosts call level.ValidatePassiveModule. It accepts only exact level.WrapModule output, including its bounded initial memory, three constant ABI functions and one validated data envelope. Extra imports, start functions, loops, memory growth, custom sections and noncanonical encodings are rejected without executing Wasm. Input remains bounded to 32 MiB. Hosts reserve the input plus the bounded canonical-module and data-construction buffers during this check. Legacy level execution retains its existing contract.

SolidOwners(document) validates a compiled world and returns the first sector with positive convex footprint intersection for each authored static solid. Boundary-only contact or overlapping bounding boxes cannot displace a later sector containing actual area. If no sector has positive footprint intersection, exterior trims retain their first conservative bounds owner. Explicit Options.SolidOwners overrides retain their existing validation and selection. Offline planners reuse the exact default Plan ownership policy without inferring it from wider physical chunks or duplicating geometry rules. The query does not change the document, and it returns nil when the world has no solids.

Plan grows connected groups deterministically in sector order through ordinary coincident reciprocal portals. It never grows across a transformed or one-way edge. Such an edge's endpoints can still share a chunk when an ordinary route connects them. Each proposal must fit the declared mesh scalar budget and the requested lightmap density, page capacity and padding. Defaults are 4 MiB mesh, 8 MiB encoded mesh, 256 sectors, and existing lightmap defaults. MaxSectors is a secondary limit. A single oversized sector fails with its identity; the planner never lowers density. Encoded mesh entries retain the 8 MiB level entry bound. Builders must additionally check the complete baked child module against the encoded budget and the existing 16 MiB envelope / 32 MiB module bounds. NoLightmap supports mesh-only levels without inventing a lighting recipe. Its planner prepares surfaces and physical-component junctions once, emits each sector and solid once, and tests growing groups with exact final scalar and binary byte counts. Liquid subdivision factors still come from the complete physical patch. Final meshes retain the standalone compiler's bytes and full semantic/coverage validation; preparation does not require the complete world's geometry to fit a single child mesh. This path performs no bake and creates no lightmap layout, image or recipe.

For chunks, Options.Lightmap.PageSize is the maximum page size. A configured 1024 maximum (also the default) first attempts a 512 page for each selected receiver group at the same density and padding. It retries 1024 only when those charts exceed page capacity. A configured 512 maximum remains a hard limit. The chosen layout defines the mesh's RNM UVs and exact LightmapBytes; the full geometry digest, global bindings, component lighting context and recipe are retained. Legacy worldlightmap.Compile and direct CompileReceivers keep fixed page sizes. worldlightmap.ErrPageCapacity also wraps ErrLayout; malformed geometry, options and recipes never trigger the larger-page retry.

Options.SectorGroups optionally preserves authored areas during build-time grouping. A nonnil list must assign every global sector an integer group ID in [0,256). The planner grows only through ordinary adjacency within the seed's group; disconnected areas or hard budget limits still produce separate chunks. Nil retains the original budget-only partitioning. Groups are producer inputs and do not add catalog, child or runtime fields. They affect mesh ownership, while visibility candidates and lighting transport still follow the complete topology and physical component across authored-area boundaries.

Candidate SDK 0.0.19 adds opt-in Options.EnclosureAware, enabled by the CLI for ordinary chunk builds. The planner first tries complete inferred spaces, keeps internal splits ahead of doorway crossings, and prefers wider shared openings when budgets force subdivision. Coincident reciprocal portals with identical floor/ceiling planes connect convex pieces of the same authored room/instance when both edges have no authored source edge. Other coplanar, full-height indoor openings merge only when their width is at least three quarters of the smaller cell's square-root area. Narrow openings, height changes, transformed portals and explicit sector-group boundaries remain cuts. This conservative heuristic is not a room detector or a cubemap-volume proof.

Options.MaxSpan optionally limits the X and Y extent of rendered geometry in metres. The CLI defaults to 48; [chunks] max_span = 32 selects a tighter cap. SDK zero disables the limit for compatibility. Limits must be finite and nonnegative (CLI authoring requires positive values). Span includes owned solids and applies to mesh-only growth and whole-chunk lightmap compaction as well as lightmapped plans. A single oversized sector fails with its identity and an instruction to subdivide geometry or use spatial render chunks. The cap never reduces lightmap density. Spatial tile sizes must fit the configured level limit; outdoor levels can raise it explicitly. The CLI also checks cropped terrain before baking.

Each accepted proposal still passes the same exact sector, mesh, encoded and lightmap limits. A complete neighboring enclosure that cannot fit is left for a later chunk instead of partially filling the current chunk. Large enclosures can span multiple chunks. PlanResult.Enclosures preserves their canonical lowest-sector identity across these budget splits and subsequent whole-chunk lightmap compaction. It is build-only metadata, independent of chunk IDs; no catalog or runtime probe ownership changes. Disabled options retain authored-order planning and a nil enclosure map. See the versioned policy decision.

Candidate SDK 0.0.12 adds Options.CompactLightmaps, an optional build policy used by environment variant cartridges. After ordinary greedy planning, it tries exact page merges of complete receiver groups within one ordinary physical component, ordered by occupied chart area. Each accepted merge retains the sector, decoded/encoded mesh, page, texel and complete mesh-validation bounds; the total decoded lightmap reservation cannot increase. Authored sector groups remain boundaries. Resulting sector/chunk indexes and visibility candidates are rebuilt deterministically. The default planner produces the same output.

The candidate accepts nonadjacent receiver sectors connected through intervening ordinary sectors assigned to other chunks. Both mesh and catalog validators traverse the complete physical component with buffers bounded by the validated world sector count. Every selected sector must belong to that component; transformed portals and disconnected spaces remain rejected. This widens receiver-group validation without changing wire fields. Produced environment cartridges require world/lightmaps-environment-variants@1, so older hosts reject the unsupported feature before mounting these resources. See the CLI's versioned environment-lightmap-variants-v1 decision for this producer policy.

Candidate sets are directed graph reachability, including transformed links. They are a conservative worst-case visibility superset, not geometric portal PVS pruning. A connected map's candidate set can include every chunk, but it is an optional prefetch hint and does not require those assets to remain resident. Required residency follows actual runtime portal traversal and aperture clipping. An open view can still expose every chunk at once, so this contract does not promise bounded residency for an open world. Future producer versions can introduce conservative aperture pruning. Candidate storage is bounded by the existing sector bound. A runtime retains the complete topology and expands actual portal paths with accumulated transforms and separate apertures; a chunk is fetched once but can appear in several render views.

Mesh schema karty.world-chunk-mesh@1 contains final float32 authored positions, primary/frame/secondary UVs, RNM UVs, wave UVs, uint32 triangle indices and per-triangle semantic/material bases and global owner identities. It uses a center fan after inserting all collinear physical-component junctions, so separately built chunks retain the same boundary vertices. Host preparation may pack existing triangles for its GPU, but must never triangulate polygons or tessellate loaded geometry. Winding uses the stored float32 positions, and fan triangles with exactly zero stored area are omitted. Complete receiver coverage is still validated. Bounds are exact minima/maxima of stored positions. DecodedMeshBytes counts 84 bytes per vertex, 4 per index and 220 fixed scalar bytes per triangle; it excludes the binary header/ownership lists, Go object padding and a host's GPU representation. Hosts must account for their upload representation separately. LightmapBytes is zero or exactly 3 times page width times page height times 4; RGBA16F GPU storage requires twice that image size in addition to CPU pixels.

Candidate SDK 0.0.12 retains finite upper sky masks between outdoor portal sectors with different ceiling heights, matching the ordinary renderer. Both plain and compiled-frame upper spans carry Sky=true and Chart=-1; physical lower spans and indoor lintels remain opaque receivers. Complete mesh validation requires the sky-mask coverage and correct flags, rejecting missing or mistagged upper spans. These render masks remain absent from lightmap transport and shadow casters, so existing layout and condition pixels retain their identities. The CLI complete-chunk cache revision 3 invalidates earlier mesh containers; pixel cache identities and released manifests remain unchanged. Hosts reserve both before decoding, rather than estimating from compressed QOI. The mesh also binds materials and authored projections with surface_sha256, using the public offline surface digest independently of its topology digest. Bound displaced liquids additionally hash the karty.world-chunk-liquid-tessellation@1 domain, that digest, and effective material/frequency/surface-amplitude inputs sorted by material. Runtime timing, opacity and shading-only wave controls do not change the rest mesh identity.

Every decoder checks the exact binary version, length, reserved zeros, scalar enums/flags, full document identity, complete owner lists, all final indices and attributes, triangle winding, bounds and complete receiver area coverage before publication. ValidateMeshBinding additionally checks every semantic chart and affine RNM coordinate against the child's layout. Catalog validation recomputes the conservative reachability sets and rejects omissions. Chunk identities never create new gameplay actor identities.

ValidateBakedSelection(catalog, chunkID, document, layout) binds a completed child recipe to exactly the parent's source union filtered to the child's ordinary physical component. A mere subset is rejected because removing a source without its coefficients would lose lighting. Recipe ordering remains part of the existing prebake digest; membership does not impose a different order. Transformed portals remain physical lighting boundaries. Mesh-only descriptors accept no lightmap layout.

Mesh validation also checks vertices against their authored receiver planes and domains. Supplied triangle edges cancel internally; their remaining directed boundary must cover every authored boundary interval once, including separate wall strips. Equal-area duplicate triangles, overlaps and holes are rejected without reconstructing or subdividing triangles. Authored projection bases, secondary weights and frame metadata are checked exactly; primary, secondary, frame and wave UVs are checked against their affine projections with bounded float32 packing/interpolation tolerance applied independently per coordinate. A large authored X never relaxes a precise Z plane. Unused attribute slots remain zero.

All array counts and the exact complete byte length are checked before typed slice allocation, using bounded integer arithmetic on native, 386 and Wasm. There is no JSON parsing or re-encoding for these payloads. On js/wasm, fixed record decoding and mesh validation periodically sleep for one millisecond to return control to JavaScript; native execution does not sleep. Actual Wasm tests check JavaScript timer progress; they do not measure graphics frame rate.

Binary records

Every integer and IEEE-754 float is little-endian. Hashes contain 32 raw SHA-256 bytes. Public schema strings are implied by the magic and version, rather than stored as strings. All payloads remain bounded to 8 MiB, and trailing bytes are rejected. Surface enums are 1=sector-floor, 2=sector-ceiling, 3=sector-wall, 4=solid-top, 5=solid-bottom, 6=solid-side; other values are invalid. Boolean words must be exactly zero or one. Mapping counts and coverage occupy uint32 words and are checked before conversion to their public uint8 fields. All floating-point attributes must be finite and pass their semantic checks.

The catalog has a 64-byte header:

Offset Type Value
0 4 bytes KCC2
4 uint16 version 2
6 uint16 header size 64
8 uint32 chunk count
12 uint32 global sector count
16 uint32 total candidate chunk IDs
20 uint32 baked source index count
24 32 bytes geometry SHA-256
56 uint64 reserved zero

All 120-byte chunk descriptors follow the header. Each stores ID, sector count, solid count and reserved zero as four uint32 words; child SHA-256 at offset 16; module size, decoded mesh bytes and decoded lightmap bytes as uint64 at offsets 48, 56 and 64; and six float64 bounds at offset 72. The remaining payload is, in order: every chunk's sector int32 list, every chunk's solid int32 list, the global sector-to-chunk uint32 list, then one candidate list per global sector. Each candidate list is a uint32 count followed by uint32 chunk IDs. The final array contains sorted unique int32 baked source indexes, bounded to 4,096 entries and to the root world's source count. Version-1 KCC1 catalogs are rejected and must be rebuilt; KCM1 meshes and KCS1 shadow proxies retain their version-1 bytes. The complete baked-index list is scanned before any catalog slice allocation, including its last record. Descriptor ownership totals and candidate totals must fit their public bounds and match the complete payload length before allocation.

The mesh has a 144-byte header:

Offset Type Value
0 4 bytes KCM1
4 uint16 version 1
6 uint16 header size 144
8 5 uint32 sector, solid, vertex, index, triangle counts
28 uint32 reserved zero
32 32 bytes geometry SHA-256
64 32 bytes surface SHA-256
96 6 float64 bounds

The body stores sector int32 IDs, solid int32 IDs, 84-byte vertex records, uint32 indices and 220-byte triangle records. A vertex contains 21 float32 values in this order: position (3), primary UVs (6), band UV (2), secondary UVs (6), lightmap UV (2), wave UV (2). A triangle stores fields in public struct order: sector/solid int32, surface uint32 enum, edge int32; normal/tangent/ bitangent (9 float32); material and mapping count uint32; weights (3 float32); three projection bases (18 float32); band material/coverage/repeatU/repeatV uint32 and basis (6 float32); secondary material uint32, strength float32, mapping count uint32 and weights (3 float32); sky/outdoor uint32 and chart int32. Each basis stores tangent followed by bitangent. Index and vertex counts must both equal three times the triangle count.

The shadow header is 80 bytes: KCS1, uint16 version 1, uint16 header size 80, uint32 triangle count, uint32 reserved zero, geometry SHA-256 at offset 16 and surface SHA-256 at offset 48. Each 68-byte triangle stores positions (9 float32), normal (3 float32), material uint32, sector/solid int32, surface uint32 enum and edge int32. Empty shadow arrays are valid when the world has no opaque caster geometry; mesh chunks remain nonempty.

Lightmap receiver algorithm 2 selects global sectors and solids while retaining the entire ordinary physical component for shadow and diffuse transport. Charts merge only through selected adjacent sectors. Lights in other physical spaces are excluded; a selected space without a local light stores covered black. Transformed portals are explicit lighting boundaries, without light transport through them. Chunk lightmaps preserve authored RNM bases across portal views. Volumes touching multiple physical spaces are rejected because authored XY overlap cannot establish their physical-space ownership.

Static frames, secondary materials, sky masks and material animations preserve their public semantics. Displaced horizontal upward liquid faces are tessellated offline with karty.world-chunk-liquid-tessellation@1. The two authored sine waves choose a barycentric subdivision factor from their frequency, amplitude and primary UV spans, targeting 0.005 metres interpolation error where the patch budget permits. The factor is capped at 32. A connected subtle-wave patch has a 256-triangle target; amplitude above 0.05 metres raises the target with amplitude and the square root of frequency, capped at 1024. Existing source triangles are always retained, even if their count already exceeds that target. The final chunk's 65536-triangle limit and all decoded/encoded budgets remain hard bounds.

The compiler plans the complete ordinary physical component's liquid patches before selecting chunk owners. Shared edges use one factor and canonical endpoint interpolation, so independently compiled neighboring chunks have matching boundary samples. Disconnected pools refine independently. Every material, secondary, band, wave and RNM UV coordinate is interpolated with the rest positions; semantic owners and differential bases remain unchanged. Hosts only pack these final triangles. They never run the tessellator. Validation checks authored rest elevations, affine wave coordinates, complete rest area and every affine RNM chart coordinate without generating geometry.

New chunked roots normally also contain @world/chunks/shadow, schema karty.world-chunk-shadow@1. This immutable asset holds the entire world's opaque authored rest caster geometry independently of render-chunk residency. It uses a corner fan without material seam junctions, center vertices or liquid subdivision, retaining the ordinary portal-opening profiles and static solid faces. Sky, liquid materials with opacity below one and gameplay actors are excluded. Wall-frame material bands retain the underlying wall/opening caster shape, matching the existing shadow path.

The proxy has at most 8192 triangles, each with final float32 positions, normal, material and global semantic owner. Compilation returns ErrShadowBudget above that bound. Builders may omit this optional asset only for that typed budget condition, preserving the larger render-chunk geometry bound. A host must reject requested shadows when the proxy is absent; missing proxy data never silently enables partial casters. DecodedShadowBytes counts 68 scalar bytes per triangle; hosts separately account for their owned object representation and GPU position/normal/index buffers. The entry remains bounded to 8 MiB before decoding, and the decoder checks the triangle record count before allocating owned records. It verifies source digests and the complete canonical authored polygon-corner sequence without creating a mesh. The surface digest binds the ordinary offline surface identity and sorted effective transparent-liquid material IDs. Older candidate roots without the entry remain valid with the shadow path disabled. A proxy does not extend shadow topology support: transformed/directed portal spaces and multiple ordinary components still need a separately versioned shadow contract.

Optional solid receiver ownership, version 1

Candidate SDK 0.0.12 adds build-only Options.SolidOwners. Nil retains the existing first-overlap policy. An explicit list must contain one valid sector index per static solid; each chosen sector must conservatively intersect that solid in XY and belong to its unambiguous ordinary physical component. Missing, out-of-range, nonintersecting and ambiguous assignments fail before planning. Geometry, density, page limits and chunk wire formats remain unchanged.

BalancedSolidOwners(document, lightmapOptions) supplies an optional deterministic policy for buildings with several overlapping roofs, cornices and decorations. It considers largest receiver chart sets first, then tries exact packing into eligible sectors ordered by occupied texels. Every single-sector layout must fit the requested page; inability to place a solid is an explicit page-capacity error. It never lowers density or moves geometry. The CLI enables this policy for environment lightmap variants so large decorative structures do not all consume the first observation sector's receiver page.

Within this opt-in policy, narrow grounded solids then prefer the first exact-fitting overlapping sector in authored order. Eligibility uses geometry and the current receiver floor: longest XY extent at least 2 units and four times the shortest, shortest extent at most 0.6, height at most 1.25, top at most 1 above that floor, and bottom reaching the floor or buried. IDs and material names have no effect. Other balanced owners remain unchanged. Complete owner validation still rejects disconnected or transformed physical membership; if the concentration cannot fit, the original balanced list is retained. This is a bounded candidate 0.0.12 build heuristic, without a wire or default Plan ownership change.

Spatial surface streaming, version 2

world/spatial-chunks@2 gates catalog schema karty.world-chunks@4 (KCC5). It requires chunks, Ready and fixed lighting. Existing KCC2/KCC3 catalogs retain all existing complete-owner, page-size and sector-count validation.

The new catalog keeps primary Chunks, SectorChunks and Candidates unchanged. Its separate Spatial list contains at most 4096 render leaves. A leaf retains its source face bindings, primary Parent, canonical XY Tile, conservative XYZ bounds, artifact hash/size and exact geometry/lighting reservations. Its local ID is its list index; StreamChunk exposes primary IDs followed by spatial IDs for bounded host scheduling without changing typed wire ownership. MaxDistance=0 imposes no extra distance cap. Builders must provide complete far coverage within residency budgets, rather than hiding unstreamed ocean.

Surfaces accounts for every discovered source face in exact semantic order. Each face is primary, spatial or terrain; Owner always names the original primary chunk. Spatial leaf bindings must name delegated faces of their Parent. Coverage validation clips each convex source polygon against its assigned tile rectangles, rejects overlapping source interiors, and proves complete area. Tile count, aggregate face references (65536), and intersection proof work (4 million comparisons) are bounded independently of the 256 primary sectors.

world-lightmaps@3 / algorithm 4 (KLM3) and world-chunk-mesh@3 (KCM3) carry the same explicit source-face selection and optional tile rectangle. Clipping happens before chart packing and final geometry emission. Source UV, wave phase, normal and material identities stay in authored coordinates. Density is never reduced implicitly. Selected atlases additionally allow square 32, 64, 128 and 256 pages. Explicit low-density far tiles are a quality policy; these small pages do not claim that lighting is uniform or discard directional RNM information. Exact uniform per-chart coefficients may use the compact fixed-lighting contract; varying charts retain the full atlas.

Every new primary requires CollisionBytes and a separately compiled @world/chunks/collision Ready stream from its original complete source owners. The reservation uses canonical 484 bytes per source triangle, independently of its render reservation. This retains collision when a collidable seabed or wall is delegated for rendering. Spatial children have no collision stream, fluid volume or actor probe ownership. The first implementation rejects empty render meshes; sky-only primaries can retain their sky geometry with an empty-chart 32-square lighting page.

Terrain-replaced floor ownership requires a root TerrainSHA256 fingerprint. ValidateSpatialTerrain proves exact exterior-sector ownership, world-compatible active terrain cells and the full encoded source fingerprint offline. Runtime admission compares immutable terrain-child lighting fingerprints with that root; it does not load full terrain to repeat the source proof.

Spatial water leaves share one positive LiquidEdgeStep, in world metres. Their clipping rectangles must lie on that global XY grid. The compiler inserts all grid crossings on every boundary, including coarse edges opposite several small leaves. Source heights and material/wave coordinates are evaluated from one authored plane and packed physical position. Interior rings and a centre fan preserve those boundary anchors; ordinary uniform triangle subdivision is not applied afterwards. A near/far split therefore retains the same animated boundary segments even when its interior meshes differ.

LiquidMaxSubdivisions is an explicit geometric quality policy. With a common edge grid, 1 retains only the outer fan; larger values allow up to five interior rings. Zero retains the normal near-detail policy. The edge step and interior policy are included in both selected layout and semantic mesh identities and are checked against the root leaf record. Their finite work/triangle bounds reject an excessively fine grid. A shared grid proves conformity, not an interpolation-error bound for arbitrary authored wave frequencies; builders must choose appropriate steps and validate the selected material visually.

The version-2 spatial contract permits larger loading units to retain up to 64 original geometry clips in LiquidTiles. The catalog and selected child carry the identical bounded list. Its complete, disjoint rectangular coverage is validated independently of the existing full-source ownership proof. The mesh compiler uses every original clip and subdivision policy before emitting the combined Ready buffers, so loading-unit size is independent of geometric detail. Ordinary released non-selected layouts, meshes and catalogs retain their bytes.

Physical-only GPU-cell ownership

PhysicalSchema (karty.world-chunks@5, binary KCC6) is the separately gated physics/probe catalog used by world/gpu-chunks@1. It preserves complete sector and solid ownership and the existing portal candidate graph. Descriptors require positive bounded collision and fixed-lighting metadata reservations, with zero render mesh and lightmap image bytes. They cannot carry old spatial render children. Existing KCC2, KCC3 and KCC5 contracts retain their original rules. The independently resident render cells live in format/worldgpuchunk.

Documentation

Overview

Package worldchunk defines build-generated render assets and conservative streaming visibility for one logical world. Geometry stays in authored space; a host may show one immutable asset through several transformed portal paths.

Index

Constants

View Source
const (
	Schema           = "karty.world-chunks@1"
	FixedSchema      = "karty.world-chunks@2"
	PhysicalSchema   = "karty.world-chunks@5"
	MeshSchema       = "karty.world-chunk-mesh@1"
	Feature          = cartridge.FeatureWorldChunksV1
	CatalogEntryName = "@world/chunks/catalog"
	MeshEntryName    = "@world/chunks/mesh"
	MetadataKey      = "kartyWorldChunks"
	ChunkMetadataKey = "kartyWorldChunk"
	MaxEncodedSize   = level.MaxEntrySize
	MaxEncodedBytes  = level.MaxEnvelopeSize * 2
	MaxVertices      = 196608
	MaxTriangles     = MaxVertices / 3
)
View Source
const (
	ReadySchema      = "karty.world-chunk-ready@1"
	ReadyEntryName   = "@world/chunks/ready"
	ReadyMetadataKey = "kartyWorldChunkReady"
	ReadyFeature     = cartridge.FeatureWorldChunkReadyV1
	ReadyStride      = 26
	MaxReadyBytes    = 64 << 20
)

ReadySchema identifies renderer-ready scalar streams, separate from the semantic mesh used by complete build-time source and lightmap validation.

View Source
const (
	ShadowSchema         = "karty.world-chunk-shadow@1"
	ShadowEntryName      = "@world/chunks/shadow"
	MaxShadowEncodedSize = MaxEncodedSize
	MaxShadowTriangles   = 8192
)
View Source
const (
	SpatialSchema      = "karty.world-chunks@4"
	SelectedMeshSchema = "karty.world-chunk-mesh@3"
	SpatialFeature     = "world/spatial-chunks@2"
	CollisionEntryName = "@world/chunks/collision"
	MaxSpatialChunks   = 4096
)

Variables

View Source
var ErrChunk = errors.New("world chunk is invalid")
View Source
var ErrReadyCapacity = fmt.Errorf("prepared geometry capacity exceeded: %w", ErrChunk)

ErrReadyCapacity identifies derived renderer geometry exceeding the existing triangle/scalar limits. Builders may repartition a multi-sector child.

View Source
var ErrShadowBudget = fmt.Errorf("opaque caster triangle budget: %w", ErrChunk)

ErrShadowBudget identifies a valid world whose complete opaque caster asset exceeds the supported bound. Producers may omit this optional root asset for render-only worlds; malformed source and other errors must still fail.

Functions

func BalancedSolidOwners added in v0.0.14

func BalancedSolidOwners(document world.Document, options worldlightmap.Options) ([]int, error)

BalancedSolidOwners is an opt-in build policy for decorative structures that overlap several receiver sectors. Largest chart sets are placed first, then assigned to the least occupied eligible sector whose exact receiver layout fits. Narrow low solids grounded at the receiver floor then prefer the first exact-fitting owner so perimeter details do not fragment adjacent pages. It never changes density, page limits, geometry or physical components. The returned complete list can be supplied as Options.SolidOwners. The default Plan ownership remains unchanged.

func DecodedMeshBytes

func DecodedMeshBytes(mesh Mesh) uint64

DecodedMeshBytes is the packed scalar array size, independent of Go padding: 21 float32 attributes per vertex, uint32 indices and 55 scalar words per triangle (including fixed identity/flags slots). It excludes the binary header and sector/solid ownership lists.

func DecodedShadowBytes

func DecodedShadowBytes(proxy ShadowProxy) uint64

DecodedShadowBytes counts 12 float32 coordinates and five fixed scalar identity words per triangle. Hosts account for their object and GPU storage separately, rather than estimating from the encoded payload size.

func EncodeCatalog

func EncodeCatalog(catalog Catalog, document *world.Document) ([]byte, error)

func EncodeMesh

func EncodeMesh(mesh Mesh, document *world.Document) ([]byte, error)

func EncodeReady added in v0.0.18

func EncodeReady(ready Ready) ([]byte, error)

EncodeReady writes bounded renderer streams. Builders check complete semantic association with DecodeReady/ValidateReady before publishing a catalog hash. Runtime uses DecodeReadyArtifact after whole-child integrity verification.

func EncodeShadowProxy

func EncodeShadowProxy(proxy ShadowProxy, document *world.Document) ([]byte, error)

func GeometryDigest

func GeometryDigest(document *world.Document) (string, error)

func ReadyBytes added in v0.0.18

func ReadyBytes(ready *Ready) uint64

func SolidOwners added in v0.1.0

func SolidOwners(document *world.Document) ([]int, error)

SolidOwners validates the compiled world and returns each static solid's first sector with positive footprint overlap, using the same ownership policy as Plan without overrides. If no positive area exists, exterior solids retain their first conservative bounds owner. This build-time query leaves the document unchanged and returns one entry per solid, or nil for no solids.

func ValidateBakedSelection

func ValidateBakedSelection(catalog *Catalog, chunkID int, document *world.Document, layout *worldlightmap.Layout) error

ValidateBakedSelection binds a child's source membership to its parent catalog. The recipe must contain exactly the parent union filtered to this ordinary physical component; ordering remains part of the prebake identity. A nil layout is valid only for a descriptor with no baked lighting. Compact spatial lighting retains its exact layout even though LightmapBytes is zero.

func ValidateCatalog

func ValidateCatalog(catalog *Catalog, document *world.Document) error

func ValidateMesh

func ValidateMesh(mesh *Mesh, document *world.Document) error

func ValidateMeshBinding

func ValidateMeshBinding(mesh *Mesh, layout *worldlightmap.Layout) error

ValidateMeshBinding checks every final RNM coordinate against its semantic chart. Geometry validation is separate and never regenerates triangles.

func ValidateReady added in v0.0.18

func ValidateReady(
	ready *Ready,
	mesh *Mesh,
	encodedMesh []byte,
	document *world.Document,
	layout *worldlightmap.Layout,
	options ReadyOptions,
) error

ValidateReady checks complete source coverage and exact packed values without constructing a second renderer representation. Inputs are read-only.

func ValidateShadowProxy

func ValidateShadowProxy(proxy *ShadowProxy, document *world.Document) error

ValidateShadowProxy checks each supplied triangle directly against its canonical authored polygon corners. It checks complete semantic coverage and winding without constructing a mesh or any new triangle/vertex arrays.

func ValidateSpatialTerrain added in v0.0.19

func ValidateSpatialTerrain(catalog *Catalog, terrain *worldterrain.Document, document *world.Document) error

ValidateSpatialTerrain is an offline source-coverage proof. Runtime admits immutable children by root artifact integrity and compares this fingerprint with each terrain lighting payload; it need not retain full terrain source.

func ValidateStreamSelection added in v0.0.19

func ValidateStreamSelection(catalog *Catalog, id int, layout *worldlightmap.Layout) error

ValidateStreamSelection binds selected face authority to an admitted root. It checks exact identities and rectangles without rediscovering geometry.

Types

type Band

type Band struct {
	Material uint32
	Coverage uint8
	RepeatU  bool
	RepeatV  bool
	Basis    Basis
}

type Basis

type Basis struct {
	Tangent   [3]float32
	Bitangent [3]float32
}

type Catalog

type Catalog struct {
	TerrainSHA256  string
	Schema         string
	GeometrySHA256 string
	Chunks         []Chunk
	SectorChunks   []int
	// Candidates is directed graph reachability, a worst-case visibility
	// superset. It is deduplicated by immutable chunk ID, not by portal path.
	Candidates [][]int
	// BakedLights is the sorted unique union of authored light indexes carried
	// by completed child prebakes. Hosts partition these sources before loading
	// children; they never consume runtime direct-light slots.
	BakedLights []int
	Spatial     []SpatialChunk
	Surfaces    []SurfaceOwnership
}

func DecodeCatalog

func DecodeCatalog(encoded []byte, document *world.Document) (Catalog, error)

func (*Catalog) StreamChunk added in v0.0.19

func (catalog *Catalog) StreamChunk(id int) (Chunk, bool)

func (*Catalog) StreamCount added in v0.0.19

func (catalog *Catalog) StreamCount() int

type Chunk

type Chunk struct {
	ID             int
	Sectors        []int
	Solids         []int
	ContentSHA256  string
	Size           uint64
	MeshBytes      uint64
	LightmapBytes  uint64
	LightingBytes  uint64
	TerrainBytes   uint64
	CollisionBytes uint64
	Bounds         [6]float64
}

type Mesh

type Mesh struct {
	Selection      *worldlightmap.SurfaceSelection
	Schema         string
	GeometrySHA256 string
	SurfaceSHA256  string
	Sectors        []int
	Solids         []int
	Vertices       []Vertex
	Indices        []uint32
	Triangles      []Triangle
	Bounds         [6]float64
}

func CompileMesh

func CompileMesh(document world.Document, sectors, solids []int, layout worldlightmap.Layout) (Mesh, error)

CompileMesh triangulates immutable authored receiver polygons offline. Every boundary vertex, including collinear junctions, gets its own triangle edge. The runtime reads final arrays and never constructs or tessellates a face.

func CompileSelectedMesh added in v0.1.0

func CompileSelectedMesh(document world.Document, sectors, solids []int, selection worldlightmap.SurfaceSelection) (Mesh, error)

CompileSelectedMesh clips explicit source surfaces offline without allocating lightmap charts or selecting a lighting density. All triangle charts are -1; CompileReady accepts the resulting mesh with a nil lightmap layout.

func DecodeMesh

func DecodeMesh(encoded []byte, document *world.Document) (Mesh, error)

type Options

type Options struct {
	Selection       *worldlightmap.SurfaceSelection
	MaxMeshBytes    uint64
	MaxEncodedBytes uint64
	MaxSectors      int
	// MaxSpan limits both horizontal extents of the rendered geometry in metres.
	// Zero disables this build-only limit; a single oversized sector must be
	// subdivided by the producer rather than silently exempted.
	MaxSpan float64
	// Lightmap.PageSize is a maximum: 1024 (or zero) first tries 512, then
	// retries 1024 only when the receiver charts exceed page capacity.
	Lightmap   worldlightmap.Options
	NoLightmap bool
	// EnclosureAware prefers complete inferred enclosures and wide internal
	// connections before crossing doorways. All resource limits still apply.
	// False retains the original authored-order growth policy.
	EnclosureAware bool
	// SectorGroups is an optional build-only authored-area preference. Nil keeps
	// budget-only grouping. Otherwise every global sector has an ID in [0,256).
	// Ordinary connectivity and hard budgets can still split an authored area.
	SectorGroups []int
	// SolidOwners optionally assigns every static solid to one overlapping
	// receiver sector. Nil preserves first-overlap ownership. It is build policy
	// only; complete bounds and ordinary-space validation remain mandatory.
	SolidOwners []int
	// CompactLightmaps optionally repacks complete valid receiver groups within
	// one ordinary physical component. It preserves all hard budgets and never
	// increases their total decoded lightmap cost. Nil/default policy is unchanged.
	CompactLightmaps bool
}

type PlanResult

type PlanResult struct {
	Chunks       []PlannedChunk
	SectorChunks []int
	Candidates   [][]int
	// Enclosures maps each sector to the lowest sector index in its inferred
	// enclosure. It is build-only metadata, independent of chunk budgets/IDs.
	// Nil means EnclosureAware was not requested.
	Enclosures []int
}

func Plan

func Plan(document world.Document, options Options) (PlanResult, error)

Plan grows connected chunks deterministically. EnclosureAware prefers whole inferred spaces; otherwise growth follows authored sector order. A budget failure never lowers density. An oversized single sector is an error. MaxEncodedBytes limits the mesh entry here; builders must also check the final child module including compressed lightmaps against that exact byte budget. Lightmap.PageSize is a maximum here: a 1024 maximum first tries a 512 page at identical density and padding, then retries 1024 only on page capacity.

type PlannedChunk

type PlannedChunk struct {
	ID              int
	Sectors, Solids []int
	Mesh            Mesh
	Layout          worldlightmap.Layout
	Bounds          [6]float64
	MeshBytes       uint64
	LightmapBytes   uint64
}

type Ready added in v0.0.18

type Ready struct {
	Schema     string
	MeshSHA256 string
	Surfaces   []ReadySurface
	Batches    []ReadyBatch
}

Ready is compiled with the level, not reconstructed by presentation. The associated semantic mesh is the build-time proof source. Runtime artifact admission checks structure after exact whole-child catalog integrity checks. Surface indexes refer to the provided level-wide table when compiled together.

func CompileReady added in v0.0.18

func CompileReady(
	mesh *Mesh,
	encodedMesh []byte,
	document *world.Document,
	layout *worldlightmap.Layout,
	options ReadyOptions,
) (Ready, error)

CompileReady groups and packs already tessellated source triangles at build time. Optional static cleanup cuts covered geometry while interpolating the source attributes; canonical source geometry and lighting remain unchanged.

func DecodeReady added in v0.0.18

func DecodeReady(
	encoded []byte,
	mesh *Mesh,
	encodedMesh []byte,
	document *world.Document,
	layout *worldlightmap.Layout,
	options ReadyOptions,
) (Ready, error)

DecodeReady proves renderer streams against an already validated semantic mesh and its accepted lightmap binding. Builders and offline cache acceptance use this complete source proof before publishing the whole-child catalog hash. Runtime compiled artifacts use DecodeReadyArtifact after integrity checking.

func DecodeReadyArtifact added in v0.0.18

func DecodeReadyArtifact(encoded []byte, admission ReadyAdmission) (Ready, error)

DecodeReadyArtifact decodes compiler-authoritative renderer data after whole artifact integrity verification. It checks binary/allocation limits, finite scalars and complete array/material/owner references. It does not decode a semantic mesh, reconstruct geometry, prove surface coverage, regenerate UVs or compare normals/bases against authored source. MeshSHA256 is build evidence; the verified whole-child catalog hash is the runtime artifact binding. Returned arrays are independently owned; inputs are read-only.

type ReadyAdmission added in v0.0.18

type ReadyAdmission struct {
	MaterialCount   int
	Sectors, Solids []int
	// Triangles is the catalog's canonical mesh-byte reservation divided by 484.
	Triangles int
	// Lightmap requires packed UV/basis streams on every non-sky batch. Image and
	// layout dimensions/format/decoded-byte limits remain their own boundary.
	Lightmap bool
	// Surfaces optionally requires the mount's already accepted canonical table.
	Surfaces []ReadySurface
}

ReadyAdmission binds compiled renderer streams to one accepted parent chunk. The asset pipeline proves geometry and authored attributes before publishing that parent's catalog. Callers must verify the complete child's exact catalog size and SHA-256 before using this structural admission API. This descriptor alone does not establish artifact authenticity or producer correctness.

type ReadyBatch added in v0.0.18

type ReadyBatch struct {
	Surface                           int
	Sky, Outdoor, StaticMaterial      bool
	Transparent, Invisible, Masked    bool
	Winding                           int8
	Vertices                          []float32
	Indices, SurfaceIDs, Sources      []uint32
	WaveUV, LightmapUV, LightmapBasis []float32
	MaterialBasis                     []float32
	Owners                            []ReadyOwner
}

type ReadyOptions added in v0.0.18

type ReadyOptions struct {
	// CleanupStatic derives visibility-safe static cuts at build time. It is for
	// atomic streamed chunks, whose selected owners cannot move independently.
	// Canonical Mesh stays unchanged; Ready Sources index the derived triangles.
	CleanupStatic bool
	Masked        []bool
	// Surfaces optionally fixes level-wide surface slot identities. Nil derives
	// a local deterministic table; a supplied table must contain every source key.
	Surfaces []ReadySurface
}

ReadyOptions selects build-time cleanup and material classification inputs. Masked uses the parent world's canonical material-slot order.

type ReadyOwner added in v0.0.18

type ReadyOwner struct {
	Sector, Solid int
	First, Count  int
	Bounds        [6]float64
}

type ReadySurface added in v0.0.18

type ReadySurface struct {
	Primary, Secondary, Band int
	SecondaryStrength        float32
	BandCoverage             uint8
	BandRepeatU, BandRepeatV bool
}

func ReadySurfaces added in v0.0.18

func ReadySurfaces(meshes []Mesh, document *world.Document) ([]ReadySurface, error)

ReadySurfaces derives a deterministic level-wide material surface table. Passing this table to every CompileReady call keeps streamed chunk vertex surface IDs stable without rewriting their scalar streams at runtime.

type Secondary

type Secondary struct {
	Material     uint32
	Strength     float32
	MappingCount uint8
	Weights      [3]float32
}

type ShadowProxy

type ShadowProxy struct {
	Schema         string
	GeometrySHA256 string
	SurfaceSHA256  string
	Triangles      []ShadowTriangle
}

ShadowProxy is one bounded root-owned caster asset, independent of render chunk residency. It contains authored opaque rest geometry, without material seam junctions, center vertices, displaced-liquid subdivision or actors.

func CompileShadowProxy

func CompileShadowProxy(document world.Document) (ShadowProxy, error)

CompileShadowProxy triangulates the complete opaque authored caster surfaces offline. Corner fans preserve legacy shadow semantics: static wall-frame UV bands do not change the underlying opening, sky has no caster, and a liquid material with opacity below one does not cast an opaque shadow.

func DecodeShadowProxy

func DecodeShadowProxy(encoded []byte, document *world.Document) (ShadowProxy, error)

type ShadowTriangle

type ShadowTriangle struct {
	Positions   [3][3]float32
	Normal      [3]float32
	Material    uint32
	Sector      int
	Solid       int
	Surface     string
	SurfaceEdge int
}

type SpatialChunk added in v0.0.19

type SpatialChunk struct {
	LiquidTiles           []worldlightmap.LiquidTile
	LiquidEdgeStep        float64
	LiquidMaxSubdivisions int
	Chunk
	Parent      int
	Tile        [4]float64
	Bindings    []worldlightmap.Binding
	MaxDistance float64
}

SpatialChunk is a render-only leaf. It shares source identity and physical context with Parent; its local ID never participates in sector ownership. MaxDistance zero means no additional distance cap beyond visibility/budgets.

type SurfaceOwnership added in v0.0.19

type SurfaceOwnership struct {
	Binding worldlightmap.Binding
	Kind    string
	Owner   int
}

SurfaceOwnership accounts for every global face, including sky/empty faces. Owner is the primary chunk index in every mode; spatial children with that Parent may carry the named source face. Terrain mode retains primary physics.

type Triangle

type Triangle struct {
	Sector          int
	Solid           int
	Surface         string
	SurfaceEdge     int
	Normal          [3]float32
	Tangent         [3]float32
	Bitangent       [3]float32
	Material        uint32
	MappingCount    uint8
	Weights         [3]float32
	ProjectionBases [3]Basis
	Band            Band
	Secondary       Secondary
	Sky             bool
	Outdoor         bool
	Chart           int
}

type Vertex

type Vertex struct {
	Position    [3]float32
	UV          [3][2]float32
	BandUV      [2]float32
	SecondaryUV [3][2]float32
	LightmapUV  [2]float32
	WaveUV      [2]float32
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL