Write a full Roblox system that is highly modular and versatile for creating incredibly smooth and satisfying camera shake.
The system must be easy to use.

A simple and singular command could be:
CameraShakeModule:Shake(player, position, rotation, time, ease, intensity, smoothness, maxdistance, maxrotation)
player: the player instance
position: if the shaking involves position changing
rotation: if the shaking involving rotation changing
time: how long the shake lasts
ease: similar to how tween direction works, a string value of "InOut", "Out", "In", "OutIn", or "Linear"
intensity: how intense the shake is, effects shake speed
smoothness: similar to how lerp alpha works, 1 is instant, 0 has no progression
maxdistance: how far the camera can move from it's original position, this is a positive number and effects every axis, this is in world studs
maxrotation: how far the camera can rotate from it's original rotation, this is a positive number and effects every axis, this is in degrees

what each one does:
player: decides who the camera shake should go to, this is the player instance, this decides who's camera to shake, the module should only work when it's running on the client. This is a player instance.
position: if the shake changes the position, this makes it so shaking can happen only on position or only on rotation. This is a boolvalue.
rotation: if the shake changes the rotation, if position is true, then rotation tilts the camera based on where the camera is moving position wise, if left, then rotate to the left, if right, rotate to the right, if forward, rotate down, if back, rotate up. if position is false, then rotation should be normal and just have unpredictable rotation. This is a boolvalue.
time: how long the shake lasts, this effects how long the ease parameter goes on for. This is a number.
ease: very similar to how tweening works from roblox tweenservice, but doesn't use tweenservice, this has multiple values such as "InOut", "Out", "In", "OutIn", or "Linear". This is a string.
if "InOut" then the shake starts from nothing, to full, then slowly goes back to nothing
if "Out" then the shake starts full, then to nothing slowly
if "In" then the shake starts from nothing, to full, then instantly to nothing
if "OutIn" then the shake starts from full, then to nothing slowly, then back to full slowly, then instantly nothing
if "Linear" then the shake is always full
intensity: how aggressive the shake is, this changes the overall speed of the shake, higher is faster, lower is slower. This is a number.
smoothness: this is very similar to how lerp works in roblox, linear interpolation simplified in roblox, the alpha value is similar, 0 is no shake progression at all and simply doesn't cause any movement, 1 is instant movement and has no transition, these are max and minimum, they can go lower or higher, but lower or higher won't do anything. This is a number
maxdistance: this is how much the camera can move away from where it originally started shaking or where the player's camera is at, this effects every single axis in position and is a whole number, such as 5 or 7, the increment is in studs, so 0.5 is half a stud, the camera should never attempt to go past these values and smoothly moves away from it if it tries passing it. This is a number
maxrotation: exactly the same as maxdistance, however involving rotation, this is fully dependent on if the rotation parameter is true. This is a boolvalue.

A few full commands would be something like:
Soft, Slow, rocking, similar to inside a car on a smooth road.
CameraShakeModule:Shake(player, false, true, 6, "Linear", 1, 0.125, 0, 25)

Soft, fast, similar to holding a handheld camera
CameraShakeModule:Shake(player, true, true, 6, "Linear", 1.25, 0.2, 0.6, 30)

Hard, fast, similar to an earthquake
CameraShakeModule:Shake(player, true, true, 3, "Out", 2.15, 0.4, 0.8, 35)

Bizarre shake with high intensity but smooth
CameraShakeModule:Shake(player, true, true, "4", "Out", 3.75, 0.175, 1.5, 40)

Slightly rough, similar to driving offroad
CameraShakeModule:Shake(player, true, true, "10", "Linear", 2, 0.35, 1, 20)

This should be a full system, if required use sub modules.
This should be full and ready for publish to a full community.

Assume 100 Roblox game developers have been waiting for this module to come out, think of every single feature that could be implemented and might get use by even 1 of those people, and add it.
Don't limit yourself to the parameters I gave nor the single command I gave, include multiple commands and parameters past what I added that you believe would get use by even 1 person in a group of 100 people.

If you believe it could be of use, use this perlin noise module, if you don't have to, don't use it.
Only use it if you believe it would make the result prettier, better, and easier.
```
local module = {}

local function fade(t)
	return t * t * t * (t * (t * 6 - 15) + 10)
end

local function grad(hash, x, y, z)
	local h = hash % 16
	local u = h < 8 and x or y
	local v = h < 4 and y or (h == 12 or h == 14) and x or z
	return ((h % 2) == 0 and u or -u) + ((h % 3) == 0 and v or -v)
end

local function lerp(t, a, b)
	return a + t * (b - a)
end

-- Create a function to initialize the Perlin noise generator with a specific seed
function module.init(seed)
	module.p = {}
	math.randomseed(seed)  -- Initialize random number generator with the provided seed
	for i = 0, 255 do
		module.p[i] = math.random(0, 255)
	end
	for i = 0, 255 do
		local j = math.random(0, 255)
		module.p[i], module.p[j] = module.p[j], module.p[i]
	end
	for i = 0, 511 do
		module.p[i] = module.p[i % 256]
	end
end

-- Function to generate Perlin noise after initialization
function module.noise(x, y, z)
	local X = math.floor(x) % 256
	local Y = math.floor(y) % 256
	local Z = math.floor(z) % 256
	x = x - math.floor(x)
	y = y - math.floor(y)
	z = z - math.floor(z)
	local u = fade(x)
	local v = fade(y)
	local w = fade(z)
	local A = module.p[X] + Y
	local AA = module.p[A] + Z
	local AB = module.p[A + 1] + Z
	local B = module.p[X + 1] + Y
	local BA = module.p[B] + Z
	local BB = module.p[B + 1] + Z

	return lerp(w,
		lerp(v,
			lerp(u, grad(module.p[AA], x, y, z), grad(module.p[BA], x - 1, y, z)),
			lerp(u, grad(module.p[AB], x, y - 1, z), grad(module.p[BB], x - 1, y - 1, z))
		),
		lerp(v,
			lerp(u, grad(module.p[AA + 1], x, y, z - 1), grad(module.p[BA + 1], x - 1, y, z - 1)),
			lerp(u, grad(module.p[AB + 1], x, y - 1, z - 1), grad(module.p[BB + 1], x - 1, y - 1, z - 1))
		)
	)
end

return module
```

The perlin noise module would likely be a sub module inside of the camera shake module itself.
Good luck.