Skip to content

Consumer-owned extension

Icon Packs

Extend the icon set without changing Goshtoso's bundled components. The iconpack tool turns verified SVG sources into a typed Go package, a sprite, and the provenance files your application ships.

What stays under your control?

Own the output

The generated Go package, sprite, manifest, provenance, and licenses live with your application. The bundled Goshtoso icons remain unchanged.

Choose the source

Select exact names from an Arai Hu Assets release, or combine a GitHub tree, a remote SVG, and other packs through .iconpack.yaml.

Keep one rendering path

Generated helpers use the same accessibility, sizing, color, and same-origin sprite rules as Goshtoso's core Icon component.

Extension proof

A generated pack keeps the same icon contract

This site ships a small Bootstrap Icons package generated outside the bundled Heroicons set. It keeps the same label, decorative, sprite, and parent-color behavior used by Goshtoso icons.

View Bootstrap Icons source
Meaningful
Decorative

1. Generate from a verified Assets release

Use the archive digest and the release metadata digests published with that Assets release. Select assets by their literal catalog canonicalName; do not infer names from filenames.

Generate the consumer-owned package
go run github.com/araihu/goshtoso/cmd/iconpack@latest \
  -release-archive ./araihu-assets-v0.2.0.tar.gz \
  -archive-sha256 "$ASSETS_ARCHIVE_SHA256" \
  -release v0.2.0 \
  -catalog-sha256 "$CATALOG_SHA256" \
  -release-json-sha256 "$RELEASE_JSON_SHA256" \
  -checksums-sha256 "$CHECKSUMS_SHA256" \
  -name brand-developer-icons-tRPC \
  -name ui-hi-16-solid-check \
  -out ./internal/appicons \
  -package appicons \
  -const-prefix Icon \
  -sprite-url /assets/icons/appicons/sprite.svg

For a verified extracted release root, use -release-root instead of -release-archive. Keep the output parent present and let the generator publish the owned output directory atomically.

2. Define sources with .iconpack.yaml

This file belongs to Goshtoso. It does not discover or modify an existing muamba.yaml. Muamba runs as a Go library; the first trust records source bytes, and later runs verify them.

.iconpack.yaml
schemaVersion: 1
sources:
  - id: heroicons
    url: https://github.com/tailwindlabs/heroicons/tree/master/src
    packName: heroicons
    paths:
      - 16/solid/academic-cap.svg
    license: MIT
    licensePath: LICENSE
    licenseUrl: https://raw.githubusercontent.com/tailwindlabs/heroicons/master/LICENSE
  - id: bootstrap
    kind: file
    url: https://raw.githubusercontent.com/twbs/icons/v1.11.3/icons/alarm.svg
    path: alarm.svg
    license: MIT
    licensePath: LICENSE
    licenseUrl: https://raw.githubusercontent.com/twbs/icons/v1.11.3/LICENSE.md
First trust and generate
go run github.com/araihu/goshtoso/cmd/iconpack@latest \
	  -config ./.iconpack.yaml -trust \
	  -out ./internal/appicons -package appicons \
	  -const-prefix Icon -sprite-url /assets/icons/appicons/sprite.svg

The generated .iconpack.lock.yaml is the TOFU boundary. Remove -trust after the first run. The Muamba adapter declaration is built in memory, so no .iconpack.engine.yaml file is left in the consumer project. If paths is omitted, every SVG in the tree is locked and available; names use packName-path, such as heroicons-16-solid-academic-cap. Git trees without packName use the repository name; other sources use id-full-normalized-path. The same file supports multiple sources.

3. Keep compatibility manifests for migration

Existing JSON and YAML manifests remain supported for migration and for the checked-in Bootstrap fixture. New integrations should use .iconpack.yaml so source acquisition and lock verification stay in one place.

Generate from an existing hashed source manifest
go run github.com/araihu/goshtoso/cmd/iconpack@latest \
	-source-root ./vendor/bootstrap-icons \
	-source-manifest ./bootstrap-icons.goshtoso.json \
	-name bootstrap-icons-alarm \
	-out ./internal/bootstrapicons -package bootstrapicons \
	-const-prefix Icon -sprite-url /assets/icons/bootstrapicons/sprite.svg

This compatibility path still verifies explicit per-file SHA-256 values. It does not read or modify any Muamba manifest.

4. Serve the sprite and render the generated symbols

Serve the generated sprite at the same-origin URL passed to the generator. The generated Icon helper accepts a small config and delegates rendering to Goshtoso's core icon component.

Use the generated typed symbol
import (
    "github.com/araihu/goshtoso/components/icon"
    "example.com/myapp/internal/appicons"
)

// Route /assets/icons/appicons/sprite.svg to ./internal/appicons/sprite.svg.
templ ProviderIcon() {
    @appicons.Icon(appicons.Config{
        Symbol:    appicons.IconBrandDeveloperIconsTRPC,
        Size:      icon.SizeLG,
        Label:     "tRPC",
        RootClass: "text-primary",
    })
}

Literal catalog names

appicons.NameBrandDeveloperIconsTRPC represents brand-developer-icons-tRPC. Go identifiers are normalized only for language syntax.

Literal sprite symbols

appicons.IconBrandDeveloperIconsTRPC binds devicon-trpc exactly as published by the catalog; do not reconstruct the symbol from the Go name.

5. Resolve exact names from configuration

When configuration stores canonical names, resolve them through the generated Name type and Lookup. A missing name is a configuration error; do not silently substitute another glyph.

Resolve an exact canonical name
func IconForName(name appicons.Name) icon.Instance {
    glyph, ok := appicons.Lookup(name)
    if !ok {
        panic("icon is not in this generated pack")
    }
    return appicons.Icon(appicons.Config{
        Symbol: glyph.Symbol,
        Label:  string(glyph.CanonicalName),
    })
}

Generated files are the audit boundary

Keep these files with the application. Together they record the selected release, source bytes, symbols, output hashes, provenance, and licenses without reopening the source tree.

sprite.svg

Only the selected SVG symbols, with the catalog sprite symbols preserved literally.

icons_gen.go

Typed Name, Glyph, icon.Symbol constants, Lookup, Config, SpriteURL, and Icon.

manifest.json

Release, source kind, archive identity, selected assets, generated identifiers, and output hashes.

provenance.json + PROVENANCE/

Per-family source and license references copied from the verified release.

licenses/ + NOTICE

The notices required to redistribute the selected assets.

Runtime and update rules

  • Use a relative same-origin sprite URL. HTTPS pages must not depend on an HTTP sprite or cross-origin <use> behavior.
  • Give labelled icons a nonblank Label. Set Decorative: true on purely visual icons; the generated helper passes both decisions to core.
  • Do not recolor protected brand assets. Monochrome assets can inherit currentColor through your normal Goshtoso classes.
  • When updating, generate a new versioned output and sprite route, verify the new manifest, then switch the application import and route together. Retain the previous output as a rollback artifact until the deployment is confirmed.

The generated-consumer proof above uses the same core rendering path as Goshtoso's bundled icons; it does not modify the bundled sprite.