As others have said. In order to create an address, you first start with a secp256k1 private key, from which the public key is derived. From the public key, you can then derive the corresponding address.
This means, that the private key must exist before the public key.
However, directly answering your initial question " generating public keys only" is technically possible, but you need to work with an initial keypair. From there, you can take just the public key component, and then similar to the way Merkalised Abstract Syntax tree's work in Taproot, tweak only the public key. This can be done by modifying the generator point on the Elliptic Curve. I've written a wallet client which does this. If anyone is interested, here is the client in action.
https://medium.com/@jamie.brian.gilchrist/my-new-wallet-client-txtailor-a-twist-on-cryptographic-key-tweaking-inspired-by-bitcoins-83233795feb1If anyone is interested, I'd be happy to explain more about exactly how this is achieved, but for those familiar with how taproot addresses are generated, will already conceptually understand what I'm doing anyway.